mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-06-16 05:55:20 +00:00
Changed indentation to 2 spaces for all files.
This commit is contained in:
parent
37bcbb7793
commit
d444c177df
180
Classes/BWApp.m
180
Classes/BWApp.m
@ -41,20 +41,20 @@
|
|||||||
#pragma mark static
|
#pragma mark static
|
||||||
|
|
||||||
+ (BWApp *)appFromDict:(NSDictionary *)dict {
|
+ (BWApp *)appFromDict:(NSDictionary *)dict {
|
||||||
BWApp *app = [[[[self class] alloc] init] autorelease];
|
BWApp *app = [[[[self class] alloc] init] autorelease];
|
||||||
|
|
||||||
// NSParameterAssert([dict isKindOfClass:[NSDictionary class]]);
|
// NSParameterAssert([dict isKindOfClass:[NSDictionary class]]);
|
||||||
if ([dict isKindOfClass:[NSDictionary class]]) {
|
if ([dict isKindOfClass:[NSDictionary class]]) {
|
||||||
app.name = [dict objectForKey:@"title"];
|
app.name = [dict objectForKey:@"title"];
|
||||||
app.version = [dict objectForKey:@"version"];
|
app.version = [dict objectForKey:@"version"];
|
||||||
app.shortVersion = [dict objectForKey:@"shortversion"];
|
app.shortVersion = [dict objectForKey:@"shortversion"];
|
||||||
[app setDateWithTimestamp:[[dict objectForKey:@"timestamp"] doubleValue]];
|
[app setDateWithTimestamp:[[dict objectForKey:@"timestamp"] doubleValue]];
|
||||||
app.size = [dict objectForKey:@"appsize"];
|
app.size = [dict objectForKey:@"appsize"];
|
||||||
app.notes = [dict objectForKey:@"notes"];
|
app.notes = [dict objectForKey:@"notes"];
|
||||||
app.mandatory = [dict objectForKey:@"mandatory"];
|
app.mandatory = [dict objectForKey:@"mandatory"];
|
||||||
}
|
}
|
||||||
|
|
||||||
return app;
|
return app;
|
||||||
}
|
}
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
@ -62,43 +62,43 @@
|
|||||||
#pragma mark NSObject
|
#pragma mark NSObject
|
||||||
|
|
||||||
- (void)dealloc {
|
- (void)dealloc {
|
||||||
[name_ release];
|
[name_ release];
|
||||||
[version_ release];
|
[version_ release];
|
||||||
[shortVersion_ release];
|
[shortVersion_ release];
|
||||||
[notes_ release];
|
[notes_ release];
|
||||||
[date_ release];
|
[date_ release];
|
||||||
[size_ release];
|
[size_ release];
|
||||||
[mandatory_ release];
|
[mandatory_ release];
|
||||||
|
|
||||||
[super dealloc];
|
[super dealloc];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (BOOL)isEqual:(id)other {
|
- (BOOL)isEqual:(id)other {
|
||||||
if (other == self)
|
if (other == self)
|
||||||
return YES;
|
return YES;
|
||||||
if (!other || ![other isKindOfClass:[self class]])
|
if (!other || ![other isKindOfClass:[self class]])
|
||||||
return NO;
|
return NO;
|
||||||
return [self isEqualToBWApp:other];
|
return [self isEqualToBWApp:other];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (BOOL)isEqualToBWApp:(BWApp *)anApp {
|
- (BOOL)isEqualToBWApp:(BWApp *)anApp {
|
||||||
if (self == anApp)
|
if (self == anApp)
|
||||||
return YES;
|
|
||||||
if (self.name != anApp.name && ![self.name isEqualToString:anApp.name])
|
|
||||||
return NO;
|
|
||||||
if (self.version != anApp.version && ![self.version isEqualToString:anApp.version])
|
|
||||||
return NO;
|
|
||||||
if (self.shortVersion != anApp.shortVersion && ![self.shortVersion isEqualToString:anApp.shortVersion])
|
|
||||||
return NO;
|
|
||||||
if (self.notes != anApp.notes && ![self.notes isEqualToString:anApp.notes])
|
|
||||||
return NO;
|
|
||||||
if (self.date != anApp.date && ![self.date isEqualToDate:anApp.date])
|
|
||||||
return NO;
|
|
||||||
if (self.size != anApp.size && ![self.size isEqualToNumber:anApp.size])
|
|
||||||
return NO;
|
|
||||||
if (self.mandatory != anApp.mandatory && ![self.mandatory isEqualToNumber:anApp.mandatory])
|
|
||||||
return NO;
|
|
||||||
return YES;
|
return YES;
|
||||||
|
if (self.name != anApp.name && ![self.name isEqualToString:anApp.name])
|
||||||
|
return NO;
|
||||||
|
if (self.version != anApp.version && ![self.version isEqualToString:anApp.version])
|
||||||
|
return NO;
|
||||||
|
if (self.shortVersion != anApp.shortVersion && ![self.shortVersion isEqualToString:anApp.shortVersion])
|
||||||
|
return NO;
|
||||||
|
if (self.notes != anApp.notes && ![self.notes isEqualToString:anApp.notes])
|
||||||
|
return NO;
|
||||||
|
if (self.date != anApp.date && ![self.date isEqualToDate:anApp.date])
|
||||||
|
return NO;
|
||||||
|
if (self.size != anApp.size && ![self.size isEqualToNumber:anApp.size])
|
||||||
|
return NO;
|
||||||
|
if (self.mandatory != anApp.mandatory && ![self.mandatory isEqualToNumber:anApp.mandatory])
|
||||||
|
return NO;
|
||||||
|
return YES;
|
||||||
}
|
}
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
@ -106,26 +106,26 @@
|
|||||||
#pragma mark NSCoder
|
#pragma mark NSCoder
|
||||||
|
|
||||||
- (void)encodeWithCoder:(NSCoder *)encoder {
|
- (void)encodeWithCoder:(NSCoder *)encoder {
|
||||||
[encoder encodeObject:self.name forKey:@"name"];
|
[encoder encodeObject:self.name forKey:@"name"];
|
||||||
[encoder encodeObject:self.version forKey:@"version"];
|
[encoder encodeObject:self.version forKey:@"version"];
|
||||||
[encoder encodeObject:self.shortVersion forKey:@"shortVersion"];
|
[encoder encodeObject:self.shortVersion forKey:@"shortVersion"];
|
||||||
[encoder encodeObject:self.notes forKey:@"notes"];
|
[encoder encodeObject:self.notes forKey:@"notes"];
|
||||||
[encoder encodeObject:self.date forKey:@"date"];
|
[encoder encodeObject:self.date forKey:@"date"];
|
||||||
[encoder encodeObject:self.size forKey:@"size"];
|
[encoder encodeObject:self.size forKey:@"size"];
|
||||||
[encoder encodeObject:self.mandatory forKey:@"mandatory"];
|
[encoder encodeObject:self.mandatory forKey:@"mandatory"];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (id)initWithCoder:(NSCoder *)decoder {
|
- (id)initWithCoder:(NSCoder *)decoder {
|
||||||
if ((self = [super init])) {
|
if ((self = [super init])) {
|
||||||
self.name = [decoder decodeObjectForKey:@"name"];
|
self.name = [decoder decodeObjectForKey:@"name"];
|
||||||
self.version = [decoder decodeObjectForKey:@"version"];
|
self.version = [decoder decodeObjectForKey:@"version"];
|
||||||
self.shortVersion = [decoder decodeObjectForKey:@"shortVersion"];
|
self.shortVersion = [decoder decodeObjectForKey:@"shortVersion"];
|
||||||
self.notes = [decoder decodeObjectForKey:@"notes"];
|
self.notes = [decoder decodeObjectForKey:@"notes"];
|
||||||
self.date = [decoder decodeObjectForKey:@"date"];
|
self.date = [decoder decodeObjectForKey:@"date"];
|
||||||
self.size = [decoder decodeObjectForKey:@"size"];
|
self.size = [decoder decodeObjectForKey:@"size"];
|
||||||
self.mandatory = [decoder decodeObjectForKey:@"mandatory"];
|
self.mandatory = [decoder decodeObjectForKey:@"mandatory"];
|
||||||
}
|
}
|
||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
@ -133,54 +133,54 @@
|
|||||||
#pragma mark Properties
|
#pragma mark Properties
|
||||||
|
|
||||||
- (NSString *)nameAndVersionString {
|
- (NSString *)nameAndVersionString {
|
||||||
NSString *appNameAndVersion = [NSString stringWithFormat:@"%@ %@", self.name, [self versionString]];
|
NSString *appNameAndVersion = [NSString stringWithFormat:@"%@ %@", self.name, [self versionString]];
|
||||||
return appNameAndVersion;
|
return appNameAndVersion;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (NSString *)versionString {
|
- (NSString *)versionString {
|
||||||
NSString *shortString = ([self.shortVersion respondsToSelector:@selector(length)] && [self.shortVersion length]) ? [NSString stringWithFormat:@"%@", self.shortVersion] : @"";
|
NSString *shortString = ([self.shortVersion respondsToSelector:@selector(length)] && [self.shortVersion length]) ? [NSString stringWithFormat:@"%@", self.shortVersion] : @"";
|
||||||
NSString *versionString = [shortString length] ? [NSString stringWithFormat:@" (%@)", self.version] : self.version;
|
NSString *versionString = [shortString length] ? [NSString stringWithFormat:@" (%@)", self.version] : self.version;
|
||||||
return [NSString stringWithFormat:@"%@ %@%@", BWHockeyLocalize(@"HockeyVersion"), shortString, versionString];
|
return [NSString stringWithFormat:@"%@ %@%@", BWHockeyLocalize(@"HockeyVersion"), shortString, versionString];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (NSString *)dateString {
|
- (NSString *)dateString {
|
||||||
NSDateFormatter *formatter = [[[NSDateFormatter alloc] init] autorelease];
|
NSDateFormatter *formatter = [[[NSDateFormatter alloc] init] autorelease];
|
||||||
[formatter setDateStyle:NSDateFormatterMediumStyle];
|
[formatter setDateStyle:NSDateFormatterMediumStyle];
|
||||||
|
|
||||||
return [formatter stringFromDate:self.date];
|
return [formatter stringFromDate:self.date];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (NSString *)sizeInMB {
|
- (NSString *)sizeInMB {
|
||||||
if ([size_ isKindOfClass: [NSNumber class]] && [size_ doubleValue] > 0) {
|
if ([size_ isKindOfClass: [NSNumber class]] && [size_ doubleValue] > 0) {
|
||||||
double appSizeInMB = [size_ doubleValue]/(1024*1024);
|
double appSizeInMB = [size_ doubleValue]/(1024*1024);
|
||||||
NSString *appSizeString = [NSString stringWithFormat:@"%.1f MB", appSizeInMB];
|
NSString *appSizeString = [NSString stringWithFormat:@"%.1f MB", appSizeInMB];
|
||||||
return appSizeString;
|
return appSizeString;
|
||||||
}
|
}
|
||||||
|
|
||||||
return @"0 MB";
|
return @"0 MB";
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)setDateWithTimestamp:(NSTimeInterval)timestamp {
|
- (void)setDateWithTimestamp:(NSTimeInterval)timestamp {
|
||||||
if (timestamp) {
|
if (timestamp) {
|
||||||
NSDate *appDate = [NSDate dateWithTimeIntervalSince1970:timestamp];
|
NSDate *appDate = [NSDate dateWithTimeIntervalSince1970:timestamp];
|
||||||
self.date = appDate;
|
self.date = appDate;
|
||||||
} else {
|
} else {
|
||||||
self.date = nil;
|
self.date = nil;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
- (NSString *)notesOrEmptyString {
|
- (NSString *)notesOrEmptyString {
|
||||||
if (self.notes) {
|
if (self.notes) {
|
||||||
return self.notes;
|
return self.notes;
|
||||||
}else {
|
}else {
|
||||||
return [NSString string];
|
return [NSString string];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// a valid app needs at least following properties: name, version, date
|
// a valid app needs at least following properties: name, version, date
|
||||||
- (BOOL)isValid {
|
- (BOOL)isValid {
|
||||||
BOOL valid = [self.name length] && [self.version length] && self.date;
|
BOOL valid = [self.name length] && [self.version length] && self.date;
|
||||||
return valid;
|
return valid;
|
||||||
}
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
@ -26,13 +26,13 @@
|
|||||||
#include <CommonCrypto/CommonDigest.h>
|
#include <CommonCrypto/CommonDigest.h>
|
||||||
|
|
||||||
NSBundle *hockeyBundle(void) {
|
NSBundle *hockeyBundle(void) {
|
||||||
static NSBundle* bundle = nil;
|
static NSBundle* bundle = nil;
|
||||||
if (!bundle) {
|
if (!bundle) {
|
||||||
NSString* path = [[[NSBundle mainBundle] resourcePath]
|
NSString* path = [[[NSBundle mainBundle] resourcePath]
|
||||||
stringByAppendingPathComponent:kHockeyBundleName];
|
stringByAppendingPathComponent:kHockeyBundleName];
|
||||||
bundle = [[NSBundle bundleWithPath:path] retain];
|
bundle = [[NSBundle bundleWithPath:path] retain];
|
||||||
}
|
}
|
||||||
return bundle;
|
return bundle;
|
||||||
}
|
}
|
||||||
|
|
||||||
NSString *BWmd5(NSString *str) {
|
NSString *BWmd5(NSString *str) {
|
||||||
@ -40,22 +40,22 @@ NSString *BWmd5(NSString *str) {
|
|||||||
unsigned char result[CC_MD5_DIGEST_LENGTH];
|
unsigned char result[CC_MD5_DIGEST_LENGTH];
|
||||||
CC_MD5( cStr, strlen(cStr), result );
|
CC_MD5( cStr, strlen(cStr), result );
|
||||||
return [NSString
|
return [NSString
|
||||||
stringWithFormat: @"%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X",
|
stringWithFormat: @"%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X",
|
||||||
result[0], result[1],
|
result[0], result[1],
|
||||||
result[2], result[3],
|
result[2], result[3],
|
||||||
result[4], result[5],
|
result[4], result[5],
|
||||||
result[6], result[7],
|
result[6], result[7],
|
||||||
result[8], result[9],
|
result[8], result[9],
|
||||||
result[10], result[11],
|
result[10], result[11],
|
||||||
result[12], result[13],
|
result[12], result[13],
|
||||||
result[14], result[15]
|
result[14], result[15]
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
NSString *BWHockeyLocalize(NSString *stringToken) {
|
NSString *BWHockeyLocalize(NSString *stringToken) {
|
||||||
if (hockeyBundle()) {
|
if (hockeyBundle()) {
|
||||||
return NSLocalizedStringFromTableInBundle(stringToken, @"Hockey", hockeyBundle(), @"");
|
return NSLocalizedStringFromTableInBundle(stringToken, @"Hockey", hockeyBundle(), @"");
|
||||||
} else {
|
} else {
|
||||||
return stringToken;
|
return stringToken;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -7,11 +7,11 @@
|
|||||||
//
|
//
|
||||||
|
|
||||||
#import <UIKit/UIKit.h>
|
#import <UIKit/UIKit.h>
|
||||||
|
|
||||||
@class BWHockeyManager;
|
@class BWHockeyManager;
|
||||||
|
|
||||||
|
|
||||||
@interface BWHockeySettingsViewController : UIViewController <UITableViewDelegate, UITableViewDataSource> {
|
@interface BWHockeySettingsViewController : UIViewController <UITableViewDelegate, UITableViewDataSource> {
|
||||||
BWHockeyManager *hockeyManager_;
|
BWHockeyManager *hockeyManager_;
|
||||||
}
|
}
|
||||||
|
|
||||||
@property (nonatomic, retain) BWHockeyManager *hockeyManager;
|
@property (nonatomic, retain) BWHockeyManager *hockeyManager;
|
||||||
|
@ -24,41 +24,41 @@
|
|||||||
#pragma mark Initialization
|
#pragma mark Initialization
|
||||||
|
|
||||||
- (id)init:(BWHockeyManager *)newHockeyManager {
|
- (id)init:(BWHockeyManager *)newHockeyManager {
|
||||||
if ((self = [super init])) {
|
if ((self = [super init])) {
|
||||||
self.hockeyManager = newHockeyManager;
|
self.hockeyManager = newHockeyManager;
|
||||||
self.title = BWHockeyLocalize(@"HockeySettingsTitle");
|
self.title = BWHockeyLocalize(@"HockeySettingsTitle");
|
||||||
|
|
||||||
CGRect frame = self.view.frame;
|
CGRect frame = self.view.frame;
|
||||||
frame.origin = CGPointZero;
|
frame.origin = CGPointZero;
|
||||||
|
|
||||||
UITableView *tableView_ = [[[UITableView alloc] initWithFrame:CGRectMake(0, self.view.frame.size.height - 260, self.view.frame.size.width, 260) style:UITableViewStyleGrouped] autorelease];
|
UITableView *tableView_ = [[[UITableView alloc] initWithFrame:CGRectMake(0, self.view.frame.size.height - 260, self.view.frame.size.width, 260) style:UITableViewStyleGrouped] autorelease];
|
||||||
tableView_.autoresizingMask = UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleRightMargin | UIViewAutoresizingFlexibleWidth;
|
tableView_.autoresizingMask = UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleRightMargin | UIViewAutoresizingFlexibleWidth;
|
||||||
|
|
||||||
BW_IF_3_2_OR_GREATER(
|
BW_IF_3_2_OR_GREATER(
|
||||||
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone) {
|
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone) {
|
||||||
self.view.backgroundColor = BW_RGBCOLOR(200, 202, 204);
|
self.view.backgroundColor = BW_RGBCOLOR(200, 202, 204);
|
||||||
tableView_.backgroundColor = BW_RGBCOLOR(200, 202, 204);
|
tableView_.backgroundColor = BW_RGBCOLOR(200, 202, 204);
|
||||||
} else {
|
} else {
|
||||||
tableView_.frame = frame;
|
tableView_.frame = frame;
|
||||||
tableView_.autoresizingMask = tableView_.autoresizingMask | UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleBottomMargin;
|
tableView_.autoresizingMask = tableView_.autoresizingMask | UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleBottomMargin;
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
BW_IF_PRE_3_2(
|
BW_IF_PRE_3_2(
|
||||||
self.navigationItem.rightBarButtonItem = [[[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemDone
|
self.navigationItem.rightBarButtonItem = [[[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemDone
|
||||||
target:self
|
target:self
|
||||||
action:@selector(dismissSettings)] autorelease];
|
action:@selector(dismissSettings)] autorelease];
|
||||||
tableView_.frame = frame;
|
tableView_.frame = frame;
|
||||||
tableView_.autoresizingMask = tableView_.autoresizingMask | UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleBottomMargin;
|
tableView_.autoresizingMask = tableView_.autoresizingMask | UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleBottomMargin;
|
||||||
)
|
)
|
||||||
|
|
||||||
tableView_.delegate = self;
|
tableView_.delegate = self;
|
||||||
tableView_.dataSource = self;
|
tableView_.dataSource = self;
|
||||||
tableView_.clipsToBounds = NO;
|
tableView_.clipsToBounds = NO;
|
||||||
|
|
||||||
[self.view addSubview:tableView_];
|
[self.view addSubview:tableView_];
|
||||||
|
|
||||||
}
|
}
|
||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (id)init {
|
- (id)init {
|
||||||
@ -69,165 +69,165 @@
|
|||||||
#pragma mark Table view data source
|
#pragma mark Table view data source
|
||||||
|
|
||||||
- (int)numberOfSections {
|
- (int)numberOfSections {
|
||||||
int numberOfSections = 1;
|
int numberOfSections = 1;
|
||||||
|
|
||||||
if ([self.hockeyManager isAllowUserToDisableSendData]) {
|
if ([self.hockeyManager isAllowUserToDisableSendData]) {
|
||||||
if ([self.hockeyManager shouldSendUserData]) numberOfSections++;
|
if ([self.hockeyManager shouldSendUserData]) numberOfSections++;
|
||||||
if ([self.hockeyManager shouldSendUsageTime]) numberOfSections++;
|
if ([self.hockeyManager shouldSendUsageTime]) numberOfSections++;
|
||||||
}
|
}
|
||||||
|
|
||||||
return numberOfSections;
|
return numberOfSections;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section {
|
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section {
|
||||||
if (section == [self numberOfSections] - 1) {
|
if (section == [self numberOfSections] - 1) {
|
||||||
return BWHockeyLocalize(@"HockeySectionCheckTitle");
|
return BWHockeyLocalize(@"HockeySectionCheckTitle");
|
||||||
} else {
|
} else {
|
||||||
return nil;
|
return nil;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
- (CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section {
|
- (CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section {
|
||||||
if (section < [self numberOfSections] - 1) {
|
if (section < [self numberOfSections] - 1) {
|
||||||
return 66;
|
return 66;
|
||||||
} else return 0;
|
} else return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
- (UIView *)tableView:(UITableView *)tableView viewForFooterInSection:(NSInteger)section {
|
- (UIView *)tableView:(UITableView *)tableView viewForFooterInSection:(NSInteger)section {
|
||||||
if ([self numberOfSections] > 1 && section < [self numberOfSections] - 1) {
|
if ([self numberOfSections] > 1 && section < [self numberOfSections] - 1) {
|
||||||
UILabel *footer = [[[UILabel alloc] initWithFrame:CGRectMake(0, 0, 285, 66)] autorelease];
|
UILabel *footer = [[[UILabel alloc] initWithFrame:CGRectMake(0, 0, 285, 66)] autorelease];
|
||||||
footer.backgroundColor = [UIColor clearColor];
|
footer.backgroundColor = [UIColor clearColor];
|
||||||
footer.numberOfLines = 3;
|
footer.numberOfLines = 3;
|
||||||
footer.textAlignment = UITextAlignmentCenter;
|
footer.textAlignment = UITextAlignmentCenter;
|
||||||
footer.adjustsFontSizeToFitWidth = YES;
|
footer.adjustsFontSizeToFitWidth = YES;
|
||||||
footer.textColor = [UIColor grayColor];
|
footer.textColor = [UIColor grayColor];
|
||||||
footer.font = [UIFont systemFontOfSize:13];
|
footer.font = [UIFont systemFontOfSize:13];
|
||||||
|
|
||||||
if (section == 0 && [self.hockeyManager isAllowUserToDisableSendData] && [self.hockeyManager shouldSendUserData]) {
|
if (section == 0 && [self.hockeyManager isAllowUserToDisableSendData] && [self.hockeyManager shouldSendUserData]) {
|
||||||
footer.text = BWHockeyLocalize(@"HockeySettingsUserDataDescription");
|
footer.text = BWHockeyLocalize(@"HockeySettingsUserDataDescription");
|
||||||
} else if ([self.hockeyManager isAllowUserToDisableSendData] && section < [self numberOfSections]) {
|
} else if ([self.hockeyManager isAllowUserToDisableSendData] && section < [self numberOfSections]) {
|
||||||
footer.text = BWHockeyLocalize(@"HockeySettingsUsageDataDescription");
|
footer.text = BWHockeyLocalize(@"HockeySettingsUsageDataDescription");
|
||||||
}
|
|
||||||
|
|
||||||
UIView* view = [[[UIView alloc] initWithFrame:CGRectMake(0, 0, 285, footer.frame.size.height + 6 + 11)] autorelease];
|
|
||||||
[view setBackgroundColor:[UIColor clearColor]];
|
|
||||||
|
|
||||||
CGRect frame = footer.frame;
|
|
||||||
frame.origin.y = 8;
|
|
||||||
frame.origin.x = 16;
|
|
||||||
frame.size.width = 285;
|
|
||||||
footer.frame = frame;
|
|
||||||
|
|
||||||
[view addSubview:footer];
|
|
||||||
[view sizeToFit];
|
|
||||||
|
|
||||||
return view;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil;
|
UIView* view = [[[UIView alloc] initWithFrame:CGRectMake(0, 0, 285, footer.frame.size.height + 6 + 11)] autorelease];
|
||||||
|
[view setBackgroundColor:[UIColor clearColor]];
|
||||||
|
|
||||||
|
CGRect frame = footer.frame;
|
||||||
|
frame.origin.y = 8;
|
||||||
|
frame.origin.x = 16;
|
||||||
|
frame.size.width = 285;
|
||||||
|
footer.frame = frame;
|
||||||
|
|
||||||
|
[view addSubview:footer];
|
||||||
|
[view sizeToFit];
|
||||||
|
|
||||||
|
return view;
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
|
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
|
||||||
// Return the number of sections.
|
// Return the number of sections.
|
||||||
return [self numberOfSections];
|
return [self numberOfSections];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
|
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
|
||||||
// Return the number of rows in the section.
|
// Return the number of rows in the section.
|
||||||
if (section == [self numberOfSections] - 1)
|
if (section == [self numberOfSections] - 1)
|
||||||
return 3;
|
return 3;
|
||||||
else
|
else
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
- (void)sendUserData:(UISwitch *)switcher {
|
- (void)sendUserData:(UISwitch *)switcher {
|
||||||
[self.hockeyManager setUserAllowsSendUserData:switcher.on];
|
[self.hockeyManager setUserAllowsSendUserData:switcher.on];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)sendUsageData:(UISwitch *)switcher {
|
- (void)sendUsageData:(UISwitch *)switcher {
|
||||||
[self.hockeyManager setUserAllowsSendUsageTime:switcher.on];
|
[self.hockeyManager setUserAllowsSendUsageTime:switcher.on];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Customize the appearance of table view cells.
|
// Customize the appearance of table view cells.
|
||||||
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
|
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
|
||||||
|
|
||||||
|
static NSString *CheckmarkCellIdentifier = @"CheckmarkCell";
|
||||||
|
static NSString *SwitchCellIdentifier = @"SwitchCell";
|
||||||
|
|
||||||
|
NSString *requiredIdentifier = nil;
|
||||||
|
UITableViewCellStyle cellStyle = UITableViewCellStyleSubtitle;
|
||||||
|
|
||||||
|
if ((NSInteger)indexPath.section == [self numberOfSections] - 1) {
|
||||||
|
cellStyle = UITableViewCellStyleDefault;
|
||||||
|
requiredIdentifier = CheckmarkCellIdentifier;
|
||||||
|
} else {
|
||||||
|
cellStyle = UITableViewCellStyleValue1;
|
||||||
|
requiredIdentifier = SwitchCellIdentifier;
|
||||||
|
}
|
||||||
|
|
||||||
|
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:requiredIdentifier];
|
||||||
|
if (cell == nil) {
|
||||||
|
cell = [[[UITableViewCell alloc] initWithStyle:cellStyle reuseIdentifier:requiredIdentifier] autorelease];
|
||||||
|
}
|
||||||
|
|
||||||
|
cell.accessoryType = UITableViewCellAccessoryNone;
|
||||||
|
cell.selectionStyle = UITableViewCellSelectionStyleNone;
|
||||||
|
|
||||||
|
// Configure the cell...
|
||||||
|
if ((NSInteger)indexPath.section == [self numberOfSections] - 1) {
|
||||||
|
cell.selectionStyle = UITableViewCellSelectionStyleBlue;
|
||||||
|
|
||||||
static NSString *CheckmarkCellIdentifier = @"CheckmarkCell";
|
// update check selection
|
||||||
static NSString *SwitchCellIdentifier = @"SwitchCell";
|
HockeyUpdateSetting hockeyAutoUpdateSetting = [[BWHockeyManager sharedHockeyManager] updateSetting];
|
||||||
|
if (indexPath.row == 0) {
|
||||||
NSString *requiredIdentifier = nil;
|
// on startup
|
||||||
UITableViewCellStyle cellStyle = UITableViewCellStyleSubtitle;
|
cell.textLabel.text = BWHockeyLocalize(@"HockeySectionCheckStartup");
|
||||||
|
if (hockeyAutoUpdateSetting == HockeyUpdateCheckStartup) {
|
||||||
if ((NSInteger)indexPath.section == [self numberOfSections] - 1) {
|
cell.accessoryType = UITableViewCellAccessoryCheckmark;
|
||||||
cellStyle = UITableViewCellStyleDefault;
|
}
|
||||||
requiredIdentifier = CheckmarkCellIdentifier;
|
} else if (indexPath.row == 1) {
|
||||||
|
// daily
|
||||||
|
cell.textLabel.text = BWHockeyLocalize(@"HockeySectionCheckDaily");
|
||||||
|
if (hockeyAutoUpdateSetting == HockeyUpdateCheckDaily) {
|
||||||
|
cell.accessoryType = UITableViewCellAccessoryCheckmark;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
cellStyle = UITableViewCellStyleValue1;
|
// manually
|
||||||
requiredIdentifier = SwitchCellIdentifier;
|
cell.textLabel.text = BWHockeyLocalize(@"HockeySectionCheckManually");
|
||||||
|
if (hockeyAutoUpdateSetting == HockeyUpdateCheckManually) {
|
||||||
|
cell.accessoryType = UITableViewCellAccessoryCheckmark;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
UISwitch *toggleSwitch = [[[UISwitch alloc] initWithFrame:CGRectZero] autorelease];
|
||||||
|
|
||||||
|
if (indexPath.section == 0 && [self.hockeyManager shouldSendUserData] && [self.hockeyManager isAllowUserToDisableSendData]) {
|
||||||
|
// send user data
|
||||||
|
cell.textLabel.text = BWHockeyLocalize(@"HockeySettingsUserData");
|
||||||
|
[toggleSwitch addTarget:self action:@selector(sendUserData:)
|
||||||
|
forControlEvents:UIControlEventValueChanged];
|
||||||
|
[toggleSwitch setOn:[self.hockeyManager doesUserAllowsSendUserData]];
|
||||||
|
|
||||||
|
} else if ([self.hockeyManager shouldSendUsageTime] && [self.hockeyManager isAllowUserToDisableSendData]) {
|
||||||
|
// send usage time
|
||||||
|
cell.textLabel.text = BWHockeyLocalize(@"HockeySettingsUsageData");
|
||||||
|
[toggleSwitch addTarget:self action:@selector(sendUsageData:)
|
||||||
|
forControlEvents:UIControlEventValueChanged];
|
||||||
|
[toggleSwitch setOn:[self.hockeyManager doesUserAllowsSendUsageTime]];
|
||||||
}
|
}
|
||||||
|
|
||||||
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:requiredIdentifier];
|
cell.accessoryView = toggleSwitch;
|
||||||
if (cell == nil) {
|
|
||||||
cell = [[[UITableViewCell alloc] initWithStyle:cellStyle reuseIdentifier:requiredIdentifier] autorelease];
|
|
||||||
}
|
|
||||||
|
|
||||||
cell.accessoryType = UITableViewCellAccessoryNone;
|
}
|
||||||
cell.selectionStyle = UITableViewCellSelectionStyleNone;
|
|
||||||
|
return cell;
|
||||||
// Configure the cell...
|
|
||||||
if ((NSInteger)indexPath.section == [self numberOfSections] - 1) {
|
|
||||||
cell.selectionStyle = UITableViewCellSelectionStyleBlue;
|
|
||||||
|
|
||||||
// update check selection
|
|
||||||
HockeyUpdateSetting hockeyAutoUpdateSetting = [[BWHockeyManager sharedHockeyManager] updateSetting];
|
|
||||||
if (indexPath.row == 0) {
|
|
||||||
// on startup
|
|
||||||
cell.textLabel.text = BWHockeyLocalize(@"HockeySectionCheckStartup");
|
|
||||||
if (hockeyAutoUpdateSetting == HockeyUpdateCheckStartup) {
|
|
||||||
cell.accessoryType = UITableViewCellAccessoryCheckmark;
|
|
||||||
}
|
|
||||||
} else if (indexPath.row == 1) {
|
|
||||||
// daily
|
|
||||||
cell.textLabel.text = BWHockeyLocalize(@"HockeySectionCheckDaily");
|
|
||||||
if (hockeyAutoUpdateSetting == HockeyUpdateCheckDaily) {
|
|
||||||
cell.accessoryType = UITableViewCellAccessoryCheckmark;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// manually
|
|
||||||
cell.textLabel.text = BWHockeyLocalize(@"HockeySectionCheckManually");
|
|
||||||
if (hockeyAutoUpdateSetting == HockeyUpdateCheckManually) {
|
|
||||||
cell.accessoryType = UITableViewCellAccessoryCheckmark;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
UISwitch *toggleSwitch = [[[UISwitch alloc] initWithFrame:CGRectZero] autorelease];
|
|
||||||
|
|
||||||
if (indexPath.section == 0 && [self.hockeyManager shouldSendUserData] && [self.hockeyManager isAllowUserToDisableSendData]) {
|
|
||||||
// send user data
|
|
||||||
cell.textLabel.text = BWHockeyLocalize(@"HockeySettingsUserData");
|
|
||||||
[toggleSwitch addTarget:self action:@selector(sendUserData:)
|
|
||||||
forControlEvents:UIControlEventValueChanged];
|
|
||||||
[toggleSwitch setOn:[self.hockeyManager doesUserAllowsSendUserData]];
|
|
||||||
|
|
||||||
} else if ([self.hockeyManager shouldSendUsageTime] && [self.hockeyManager isAllowUserToDisableSendData]) {
|
|
||||||
// send usage time
|
|
||||||
cell.textLabel.text = BWHockeyLocalize(@"HockeySettingsUsageData");
|
|
||||||
[toggleSwitch addTarget:self action:@selector(sendUsageData:)
|
|
||||||
forControlEvents:UIControlEventValueChanged];
|
|
||||||
[toggleSwitch setOn:[self.hockeyManager doesUserAllowsSendUsageTime]];
|
|
||||||
}
|
|
||||||
|
|
||||||
cell.accessoryView = toggleSwitch;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
return cell;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -235,21 +235,21 @@
|
|||||||
#pragma mark Table view delegate
|
#pragma mark Table view delegate
|
||||||
|
|
||||||
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
|
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
|
||||||
[tableView deselectRowAtIndexPath:indexPath animated:YES];
|
[tableView deselectRowAtIndexPath:indexPath animated:YES];
|
||||||
|
|
||||||
// update check interval selection
|
// update check interval selection
|
||||||
if (indexPath.row == 0) {
|
if (indexPath.row == 0) {
|
||||||
// on startup
|
// on startup
|
||||||
[BWHockeyManager sharedHockeyManager].updateSetting = HockeyUpdateCheckStartup;
|
[BWHockeyManager sharedHockeyManager].updateSetting = HockeyUpdateCheckStartup;
|
||||||
} else if (indexPath.row == 1) {
|
} else if (indexPath.row == 1) {
|
||||||
// daily
|
// daily
|
||||||
[BWHockeyManager sharedHockeyManager].updateSetting = HockeyUpdateCheckDaily;
|
[BWHockeyManager sharedHockeyManager].updateSetting = HockeyUpdateCheckDaily;
|
||||||
} else {
|
} else {
|
||||||
// manually
|
// manually
|
||||||
[BWHockeyManager sharedHockeyManager].updateSetting = HockeyUpdateCheckManually;
|
[BWHockeyManager sharedHockeyManager].updateSetting = HockeyUpdateCheckManually;
|
||||||
}
|
}
|
||||||
|
|
||||||
[tableView reloadData];
|
[tableView reloadData];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -257,20 +257,20 @@
|
|||||||
#pragma mark Memory management
|
#pragma mark Memory management
|
||||||
|
|
||||||
- (void)didReceiveMemoryWarning {
|
- (void)didReceiveMemoryWarning {
|
||||||
// Releases the view if it doesn't have a superview.
|
// Releases the view if it doesn't have a superview.
|
||||||
[super didReceiveMemoryWarning];
|
[super didReceiveMemoryWarning];
|
||||||
|
|
||||||
// Relinquish ownership any cached data, images, etc. that aren't in use.
|
// Relinquish ownership any cached data, images, etc. that aren't in use.
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)viewDidUnload {
|
- (void)viewDidUnload {
|
||||||
// Relinquish ownership of anything that can be recreated in viewDidLoad or on demand.
|
// Relinquish ownership of anything that can be recreated in viewDidLoad or on demand.
|
||||||
// For example: self.myOutlet = nil;
|
// For example: self.myOutlet = nil;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
- (void)dealloc {
|
- (void)dealloc {
|
||||||
[super dealloc];
|
[super dealloc];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -279,15 +279,15 @@
|
|||||||
#pragma mark Rotation
|
#pragma mark Rotation
|
||||||
|
|
||||||
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
|
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
|
||||||
BOOL shouldAutorotate;
|
BOOL shouldAutorotate;
|
||||||
|
|
||||||
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone) {
|
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone) {
|
||||||
shouldAutorotate = (interfaceOrientation == UIInterfaceOrientationPortrait);
|
shouldAutorotate = (interfaceOrientation == UIInterfaceOrientationPortrait);
|
||||||
} else {
|
} else {
|
||||||
shouldAutorotate = YES;
|
shouldAutorotate = YES;
|
||||||
}
|
}
|
||||||
|
|
||||||
return shouldAutorotate;
|
return shouldAutorotate;
|
||||||
}
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
@ -39,22 +39,22 @@ typedef enum {
|
|||||||
@class BWHockeyManager;
|
@class BWHockeyManager;
|
||||||
|
|
||||||
@interface BWHockeyViewController : UITableViewController <PSStoreButtonDelegate> {
|
@interface BWHockeyViewController : UITableViewController <PSStoreButtonDelegate> {
|
||||||
BWHockeyManager *hockeyManager_;
|
BWHockeyManager *hockeyManager_;
|
||||||
|
|
||||||
NSDictionary *cellLayout;
|
NSDictionary *cellLayout;
|
||||||
|
|
||||||
BOOL modal_;
|
BOOL modal_;
|
||||||
BOOL kvoRegistered_;
|
BOOL kvoRegistered_;
|
||||||
BOOL showAllVersions_;
|
BOOL showAllVersions_;
|
||||||
UIStatusBarStyle statusBarStyle_;
|
UIStatusBarStyle statusBarStyle_;
|
||||||
PSAppStoreHeader *appStoreHeader_;
|
PSAppStoreHeader *appStoreHeader_;
|
||||||
PSStoreButton *appStoreButton_;
|
PSStoreButton *appStoreButton_;
|
||||||
|
|
||||||
id popOverController_;
|
id popOverController_;
|
||||||
|
|
||||||
AppStoreButtonState appStoreButtonState_;
|
AppStoreButtonState appStoreButtonState_;
|
||||||
|
|
||||||
NSMutableArray *cells_;
|
NSMutableArray *cells_;
|
||||||
}
|
}
|
||||||
|
|
||||||
@property (nonatomic, retain) BWHockeyManager *hockeyManager;
|
@property (nonatomic, retain) BWHockeyManager *hockeyManager;
|
||||||
|
@ -56,174 +56,174 @@
|
|||||||
#pragma mark private
|
#pragma mark private
|
||||||
|
|
||||||
- (void)restoreStoreButtonStateAnimated_:(BOOL)animated {
|
- (void)restoreStoreButtonStateAnimated_:(BOOL)animated {
|
||||||
if ([self.hockeyManager isAppStoreEnvironment]) {
|
if ([self.hockeyManager isAppStoreEnvironment]) {
|
||||||
[self setAppStoreButtonState:AppStoreButtonStateOffline animated:animated];
|
[self setAppStoreButtonState:AppStoreButtonStateOffline animated:animated];
|
||||||
} else if ([self.hockeyManager isUpdateAvailable]) {
|
} else if ([self.hockeyManager isUpdateAvailable]) {
|
||||||
[self setAppStoreButtonState:AppStoreButtonStateUpdate animated:animated];
|
[self setAppStoreButtonState:AppStoreButtonStateUpdate animated:animated];
|
||||||
} else {
|
} else {
|
||||||
[self setAppStoreButtonState:AppStoreButtonStateCheck animated:animated];
|
[self setAppStoreButtonState:AppStoreButtonStateCheck animated:animated];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)updateAppStoreHeader_ {
|
- (void)updateAppStoreHeader_ {
|
||||||
BWApp *app = self.hockeyManager.app;
|
BWApp *app = self.hockeyManager.app;
|
||||||
appStoreHeader_.headerLabel = app.name;
|
appStoreHeader_.headerLabel = app.name;
|
||||||
appStoreHeader_.middleHeaderLabel = [app versionString];
|
appStoreHeader_.middleHeaderLabel = [app versionString];
|
||||||
NSDateFormatter *formatter = [[[NSDateFormatter alloc] init] autorelease];
|
NSDateFormatter *formatter = [[[NSDateFormatter alloc] init] autorelease];
|
||||||
[formatter setDateStyle:NSDateFormatterMediumStyle];
|
[formatter setDateStyle:NSDateFormatterMediumStyle];
|
||||||
NSMutableString *subHeaderString = [NSMutableString string];
|
NSMutableString *subHeaderString = [NSMutableString string];
|
||||||
if (app.date) {
|
if (app.date) {
|
||||||
[subHeaderString appendString:[formatter stringFromDate:app.date]];
|
[subHeaderString appendString:[formatter stringFromDate:app.date]];
|
||||||
|
}
|
||||||
|
if (app.size) {
|
||||||
|
if ([subHeaderString length]) {
|
||||||
|
[subHeaderString appendString:@" - "];
|
||||||
}
|
}
|
||||||
if (app.size) {
|
[subHeaderString appendString:app.sizeInMB];
|
||||||
if ([subHeaderString length]) {
|
}
|
||||||
[subHeaderString appendString:@" - "];
|
appStoreHeader_.subHeaderLabel = subHeaderString;
|
||||||
}
|
|
||||||
[subHeaderString appendString:app.sizeInMB];
|
|
||||||
}
|
|
||||||
appStoreHeader_.subHeaderLabel = subHeaderString;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)appDidBecomeActive_ {
|
- (void)appDidBecomeActive_ {
|
||||||
if (self.appStoreButtonState == AppStoreButtonStateInstalling) {
|
if (self.appStoreButtonState == AppStoreButtonStateInstalling) {
|
||||||
[self setAppStoreButtonState:AppStoreButtonStateUpdate animated:YES];
|
[self setAppStoreButtonState:AppStoreButtonStateUpdate animated:YES];
|
||||||
} else if (![self.hockeyManager isCheckInProgress]) {
|
} else if (![self.hockeyManager isCheckInProgress]) {
|
||||||
[self restoreStoreButtonStateAnimated_:YES];
|
[self restoreStoreButtonStateAnimated_:YES];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)openSettings:(id)sender {
|
- (void)openSettings:(id)sender {
|
||||||
BWHockeySettingsViewController *settings = [[[BWHockeySettingsViewController alloc] init] autorelease];
|
BWHockeySettingsViewController *settings = [[[BWHockeySettingsViewController alloc] init] autorelease];
|
||||||
|
|
||||||
Class popoverControllerClass = NSClassFromString(@"UIPopoverController");
|
Class popoverControllerClass = NSClassFromString(@"UIPopoverController");
|
||||||
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad && popoverControllerClass) {
|
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad && popoverControllerClass) {
|
||||||
if (popOverController_ == nil) {
|
if (popOverController_ == nil) {
|
||||||
popOverController_ = [[popoverControllerClass alloc] initWithContentViewController:settings];
|
popOverController_ = [[popoverControllerClass alloc] initWithContentViewController:settings];
|
||||||
}
|
|
||||||
if ([popOverController_ contentViewController].view.window) {
|
|
||||||
[popOverController_ dismissPopoverAnimated:YES];
|
|
||||||
}else {
|
|
||||||
[popOverController_ setPopoverContentSize: CGSizeMake(320, 440)];
|
|
||||||
[popOverController_ presentPopoverFromBarButtonItem:self.navigationItem.rightBarButtonItem
|
|
||||||
permittedArrowDirections:UIPopoverArrowDirectionUp animated:YES];
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
|
|
||||||
BW_IF_3_2_OR_GREATER(
|
|
||||||
settings.modalTransitionStyle = UIModalTransitionStylePartialCurl;
|
|
||||||
[self presentModalViewController:settings animated:YES];
|
|
||||||
)
|
|
||||||
BW_IF_PRE_3_2(
|
|
||||||
UINavigationController *navController = [[[UINavigationController alloc] initWithRootViewController:settings] autorelease];
|
|
||||||
navController.modalTransitionStyle = UIModalTransitionStyleCoverVertical;
|
|
||||||
[self presentModalViewController:navController animated:YES];
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
if ([popOverController_ contentViewController].view.window) {
|
||||||
|
[popOverController_ dismissPopoverAnimated:YES];
|
||||||
|
}else {
|
||||||
|
[popOverController_ setPopoverContentSize: CGSizeMake(320, 440)];
|
||||||
|
[popOverController_ presentPopoverFromBarButtonItem:self.navigationItem.rightBarButtonItem
|
||||||
|
permittedArrowDirections:UIPopoverArrowDirectionUp animated:YES];
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
|
||||||
|
BW_IF_3_2_OR_GREATER(
|
||||||
|
settings.modalTransitionStyle = UIModalTransitionStylePartialCurl;
|
||||||
|
[self presentModalViewController:settings animated:YES];
|
||||||
|
)
|
||||||
|
BW_IF_PRE_3_2(
|
||||||
|
UINavigationController *navController = [[[UINavigationController alloc] initWithRootViewController:settings] autorelease];
|
||||||
|
navController.modalTransitionStyle = UIModalTransitionStyleCoverVertical;
|
||||||
|
[self presentModalViewController:navController animated:YES];
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
- (UIImage *)addGlossToImage_:(UIImage *)image {
|
- (UIImage *)addGlossToImage_:(UIImage *)image {
|
||||||
BW_IF_IOS4_OR_GREATER(UIGraphicsBeginImageContextWithOptions(image.size, NO, 0.0);)
|
BW_IF_IOS4_OR_GREATER(UIGraphicsBeginImageContextWithOptions(image.size, NO, 0.0);)
|
||||||
BW_IF_PRE_IOS4(UIGraphicsBeginImageContext(image.size);)
|
BW_IF_PRE_IOS4(UIGraphicsBeginImageContext(image.size);)
|
||||||
|
|
||||||
[image drawAtPoint:CGPointZero];
|
[image drawAtPoint:CGPointZero];
|
||||||
UIImage *iconGradient = [UIImage bw_imageNamed:@"IconGradient.png" bundle:kHockeyBundleName];
|
UIImage *iconGradient = [UIImage bw_imageNamed:@"IconGradient.png" bundle:kHockeyBundleName];
|
||||||
[iconGradient drawInRect:CGRectMake(0, 0, image.size.width, image.size.height) blendMode:kCGBlendModeNormal alpha:0.5];
|
[iconGradient drawInRect:CGRectMake(0, 0, image.size.width, image.size.height) blendMode:kCGBlendModeNormal alpha:0.5];
|
||||||
|
|
||||||
UIImage *result = UIGraphicsGetImageFromCurrentImageContext();
|
UIImage *result = UIGraphicsGetImageFromCurrentImageContext();
|
||||||
UIGraphicsEndImageContext();
|
UIGraphicsEndImageContext();
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
#define kMinPreviousVersionButtonHeight 50
|
#define kMinPreviousVersionButtonHeight 50
|
||||||
- (void)realignPreviousVersionButton {
|
- (void)realignPreviousVersionButton {
|
||||||
|
|
||||||
// manually collect actual table height size
|
// manually collect actual table height size
|
||||||
NSUInteger tableViewContentHeight = 0;
|
NSUInteger tableViewContentHeight = 0;
|
||||||
for (int i=0; i < [self tableView:self.tableView numberOfRowsInSection:0]; i++) {
|
for (int i=0; i < [self tableView:self.tableView numberOfRowsInSection:0]; i++) {
|
||||||
tableViewContentHeight += [self tableView:self.tableView heightForRowAtIndexPath:[NSIndexPath indexPathForRow:i inSection:0]];
|
tableViewContentHeight += [self tableView:self.tableView heightForRowAtIndexPath:[NSIndexPath indexPathForRow:i inSection:0]];
|
||||||
}
|
}
|
||||||
tableViewContentHeight += self.tableView.tableHeaderView.frame.size.height;
|
tableViewContentHeight += self.tableView.tableHeaderView.frame.size.height;
|
||||||
|
|
||||||
NSUInteger footerViewSize = kMinPreviousVersionButtonHeight;
|
NSUInteger footerViewSize = kMinPreviousVersionButtonHeight;
|
||||||
NSUInteger frameHeight = self.view.frame.size.height;
|
NSUInteger frameHeight = self.view.frame.size.height;
|
||||||
if(tableViewContentHeight < frameHeight && (frameHeight - tableViewContentHeight > 100)) {
|
if(tableViewContentHeight < frameHeight && (frameHeight - tableViewContentHeight > 100)) {
|
||||||
footerViewSize = frameHeight - tableViewContentHeight;
|
footerViewSize = frameHeight - tableViewContentHeight;
|
||||||
}
|
}
|
||||||
|
|
||||||
// update footer view
|
// update footer view
|
||||||
if(self.tableView.tableFooterView) {
|
if(self.tableView.tableFooterView) {
|
||||||
CGRect frame = self.tableView.tableFooterView.frame;
|
CGRect frame = self.tableView.tableFooterView.frame;
|
||||||
frame.size.height = footerViewSize;
|
frame.size.height = footerViewSize;
|
||||||
self.tableView.tableFooterView.frame = frame;
|
self.tableView.tableFooterView.frame = frame;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)changePreviousVersionButtonBackground:(id)sender {
|
- (void)changePreviousVersionButtonBackground:(id)sender {
|
||||||
[(UIButton *)sender setBackgroundColor:BW_RGBCOLOR(183,183,183)];
|
[(UIButton *)sender setBackgroundColor:BW_RGBCOLOR(183,183,183)];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)changePreviousVersionButtonBackgroundHighlighted:(id)sender {
|
- (void)changePreviousVersionButtonBackgroundHighlighted:(id)sender {
|
||||||
[(UIButton *)sender setBackgroundColor:BW_RGBCOLOR(183,183,183)];
|
[(UIButton *)sender setBackgroundColor:BW_RGBCOLOR(183,183,183)];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)showHidePreviousVersionsButton {
|
- (void)showHidePreviousVersionsButton {
|
||||||
BOOL multipleVersionButtonNeeded = [self.hockeyManager.apps count] > 1 && !showAllVersions_;
|
BOOL multipleVersionButtonNeeded = [self.hockeyManager.apps count] > 1 && !showAllVersions_;
|
||||||
|
|
||||||
if(multipleVersionButtonNeeded) {
|
if(multipleVersionButtonNeeded) {
|
||||||
// align at the bottom if tableview is small
|
// align at the bottom if tableview is small
|
||||||
UIView *footerView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, self.view.frame.size.width, kMinPreviousVersionButtonHeight)];
|
UIView *footerView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, self.view.frame.size.width, kMinPreviousVersionButtonHeight)];
|
||||||
footerView.autoresizingMask = UIViewAutoresizingFlexibleWidth;
|
footerView.autoresizingMask = UIViewAutoresizingFlexibleWidth;
|
||||||
footerView.backgroundColor = BW_RGBCOLOR(200, 202, 204);
|
footerView.backgroundColor = BW_RGBCOLOR(200, 202, 204);
|
||||||
UIButton *footerButton = [UIButton buttonWithType:UIButtonTypeCustom];
|
UIButton *footerButton = [UIButton buttonWithType:UIButtonTypeCustom];
|
||||||
BW_IF_IOS4_OR_GREATER(
|
BW_IF_IOS4_OR_GREATER(
|
||||||
//footerButton.layer.shadowOffset = CGSizeMake(-2, 2);
|
//footerButton.layer.shadowOffset = CGSizeMake(-2, 2);
|
||||||
footerButton.layer.shadowColor = [[UIColor blackColor] CGColor];
|
footerButton.layer.shadowColor = [[UIColor blackColor] CGColor];
|
||||||
footerButton.layer.shadowRadius = 2.0f;
|
footerButton.layer.shadowRadius = 2.0f;
|
||||||
)
|
)
|
||||||
footerButton.titleLabel.font = [UIFont boldSystemFontOfSize:14];
|
footerButton.titleLabel.font = [UIFont boldSystemFontOfSize:14];
|
||||||
[footerButton setTitle:BWHockeyLocalize(@"HockeyShowPreviousVersions") forState:UIControlStateNormal];
|
[footerButton setTitle:BWHockeyLocalize(@"HockeyShowPreviousVersions") forState:UIControlStateNormal];
|
||||||
[footerButton setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
|
[footerButton setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
|
||||||
[footerButton setTitleColor:[UIColor whiteColor] forState:UIControlStateHighlighted];
|
[footerButton setTitleColor:[UIColor whiteColor] forState:UIControlStateHighlighted];
|
||||||
[footerButton setBackgroundImage:[UIImage bw_imageNamed:@"buttonHighlight.png" bundle:kHockeyBundleName] forState:UIControlStateHighlighted];
|
[footerButton setBackgroundImage:[UIImage bw_imageNamed:@"buttonHighlight.png" bundle:kHockeyBundleName] forState:UIControlStateHighlighted];
|
||||||
footerButton.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleTopMargin;
|
footerButton.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleTopMargin;
|
||||||
[footerButton addTarget:self action:@selector(showPreviousVersionAction) forControlEvents:UIControlEventTouchUpInside];
|
[footerButton addTarget:self action:@selector(showPreviousVersionAction) forControlEvents:UIControlEventTouchUpInside];
|
||||||
footerButton.frame = CGRectMake(0, kMinPreviousVersionButtonHeight-44, self.view.frame.size.width, 44);
|
footerButton.frame = CGRectMake(0, kMinPreviousVersionButtonHeight-44, self.view.frame.size.width, 44);
|
||||||
footerButton.backgroundColor = BW_RGBCOLOR(183,183,183);
|
footerButton.backgroundColor = BW_RGBCOLOR(183,183,183);
|
||||||
[footerView addSubview:footerButton];
|
[footerView addSubview:footerButton];
|
||||||
self.tableView.tableFooterView = footerView;
|
self.tableView.tableFooterView = footerView;
|
||||||
[self realignPreviousVersionButton];
|
[self realignPreviousVersionButton];
|
||||||
[footerView release];
|
[footerView release];
|
||||||
} else {
|
} else {
|
||||||
self.tableView.tableFooterView = nil;
|
self.tableView.tableFooterView = nil;
|
||||||
self.tableView.backgroundColor = BW_RGBCOLOR(200, 202, 204);
|
self.tableView.backgroundColor = BW_RGBCOLOR(200, 202, 204);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)configureWebCell:(PSWebTableViewCell *)cell forApp_:(BWApp *)app {
|
- (void)configureWebCell:(PSWebTableViewCell *)cell forApp_:(BWApp *)app {
|
||||||
// create web view for a version
|
// create web view for a version
|
||||||
NSString *installed = @"";
|
NSString *installed = @"";
|
||||||
if ([app.version isEqualToString:[self.hockeyManager currentAppVersion]]) {
|
if ([app.version isEqualToString:[self.hockeyManager currentAppVersion]]) {
|
||||||
installed = [NSString stringWithFormat:@"<span style=\"float:%@;text-shadow:rgba(255,255,255,0.6) 1px 1px 0px;\"><b>%@</b></span>", [app isEqual:self.hockeyManager.app] ? @"left" : @"right", BWHockeyLocalize(@"HockeyInstalled")];
|
installed = [NSString stringWithFormat:@"<span style=\"float:%@;text-shadow:rgba(255,255,255,0.6) 1px 1px 0px;\"><b>%@</b></span>", [app isEqual:self.hockeyManager.app] ? @"left" : @"right", BWHockeyLocalize(@"HockeyInstalled")];
|
||||||
}
|
}
|
||||||
|
|
||||||
if ([app isEqual:self.hockeyManager.app]) {
|
if ([app isEqual:self.hockeyManager.app]) {
|
||||||
if ([app.notes length] > 0) {
|
if ([app.notes length] > 0) {
|
||||||
installed = [NSString stringWithFormat:@"<p> %@</p>", installed];
|
installed = [NSString stringWithFormat:@"<p> %@</p>", installed];
|
||||||
cell.webViewContent = [NSString stringWithFormat:@"%@%@", installed, app.notes];
|
cell.webViewContent = [NSString stringWithFormat:@"%@%@", installed, app.notes];
|
||||||
} else {
|
|
||||||
cell.webViewContent = [NSString stringWithFormat:@"<div style=\"min-height:200px;vertical-align:middle;text-align:center;text-shadow:rgba(255,255,255,0.6) 1px 1px 0px;\">%@</div>", BWHockeyLocalize(@"HockeyNoReleaseNotesAvailable")];
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
cell.webViewContent = [NSString stringWithFormat:@"<p><b style=\"text-shadow:rgba(255,255,255,0.6) 1px 1px 0px;\">%@</b>%@<br/><small>%@</small></p><p>%@</p>", [app versionString], installed, [app dateString], [app notesOrEmptyString]];
|
cell.webViewContent = [NSString stringWithFormat:@"<div style=\"min-height:200px;vertical-align:middle;text-align:center;text-shadow:rgba(255,255,255,0.6) 1px 1px 0px;\">%@</div>", BWHockeyLocalize(@"HockeyNoReleaseNotesAvailable")];
|
||||||
}
|
}
|
||||||
cell.cellBackgroundColor = BW_RGBCOLOR(200, 202, 204);
|
} else {
|
||||||
|
cell.webViewContent = [NSString stringWithFormat:@"<p><b style=\"text-shadow:rgba(255,255,255,0.6) 1px 1px 0px;\">%@</b>%@<br/><small>%@</small></p><p>%@</p>", [app versionString], installed, [app dateString], [app notesOrEmptyString]];
|
||||||
[cell addWebView];
|
}
|
||||||
// hack
|
cell.cellBackgroundColor = BW_RGBCOLOR(200, 202, 204);
|
||||||
cell.textLabel.text = @"";
|
|
||||||
|
[cell addWebView];
|
||||||
[cell addObserver:self forKeyPath:@"webViewSize" options:0 context:nil];
|
// hack
|
||||||
|
cell.textLabel.text = @"";
|
||||||
|
|
||||||
|
[cell addObserver:self forKeyPath:@"webViewSize" options:0 context:nil];
|
||||||
}
|
}
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
@ -231,22 +231,22 @@
|
|||||||
#pragma mark NSObject
|
#pragma mark NSObject
|
||||||
|
|
||||||
- (id)init:(BWHockeyManager *)newHockeyManager modal:(BOOL)newModal {
|
- (id)init:(BWHockeyManager *)newHockeyManager modal:(BOOL)newModal {
|
||||||
if ((self = [super initWithStyle:UITableViewStylePlain])) {
|
if ((self = [super initWithStyle:UITableViewStylePlain])) {
|
||||||
self.hockeyManager = newHockeyManager;
|
self.hockeyManager = newHockeyManager;
|
||||||
self.modal = newModal;
|
self.modal = newModal;
|
||||||
self.title = BWHockeyLocalize(@"HockeyUpdateScreenTitle");
|
self.title = BWHockeyLocalize(@"HockeyUpdateScreenTitle");
|
||||||
|
|
||||||
if ([self.hockeyManager shouldShowUserSettings]) {
|
if ([self.hockeyManager shouldShowUserSettings]) {
|
||||||
self.navigationItem.rightBarButtonItem = [[[UIBarButtonItem alloc] initWithImage:[UIImage bw_imageNamed:@"gear.png" bundle:kHockeyBundleName]
|
self.navigationItem.rightBarButtonItem = [[[UIBarButtonItem alloc] initWithImage:[UIImage bw_imageNamed:@"gear.png" bundle:kHockeyBundleName]
|
||||||
style:UIBarButtonItemStyleBordered
|
style:UIBarButtonItemStyleBordered
|
||||||
target:self
|
target:self
|
||||||
action:@selector(openSettings:)] autorelease];
|
action:@selector(openSettings:)] autorelease];
|
||||||
}
|
|
||||||
|
|
||||||
cells_ = [[NSMutableArray alloc] initWithCapacity:5];
|
|
||||||
popOverController_ = nil;
|
|
||||||
}
|
}
|
||||||
return self;
|
|
||||||
|
cells_ = [[NSMutableArray alloc] initWithCapacity:5];
|
||||||
|
popOverController_ = nil;
|
||||||
|
}
|
||||||
|
return self;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (id)init {
|
- (id)init {
|
||||||
@ -254,12 +254,12 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
- (void)dealloc {
|
- (void)dealloc {
|
||||||
[self viewDidUnload];
|
[self viewDidUnload];
|
||||||
for (UITableViewCell *cell in cells_) {
|
for (UITableViewCell *cell in cells_) {
|
||||||
[cell removeObserver:self forKeyPath:@"webViewSize"];
|
[cell removeObserver:self forKeyPath:@"webViewSize"];
|
||||||
}
|
}
|
||||||
[cells_ release];
|
[cells_ release];
|
||||||
[super dealloc];
|
[super dealloc];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -268,30 +268,30 @@
|
|||||||
#pragma mark View lifecycle
|
#pragma mark View lifecycle
|
||||||
|
|
||||||
- (void)onAction:(id)sender {
|
- (void)onAction:(id)sender {
|
||||||
if (self.modal) {
|
if (self.modal) {
|
||||||
// Note that as of 5.0, parentViewController will no longer return the presenting view controller
|
// Note that as of 5.0, parentViewController will no longer return the presenting view controller
|
||||||
SEL presentingViewControllerSelector = NSSelectorFromString(@"presentingViewController");
|
SEL presentingViewControllerSelector = NSSelectorFromString(@"presentingViewController");
|
||||||
UIViewController *presentingViewController = nil;
|
UIViewController *presentingViewController = nil;
|
||||||
if ([self respondsToSelector:presentingViewControllerSelector]) {
|
if ([self respondsToSelector:presentingViewControllerSelector]) {
|
||||||
presentingViewController = [self performSelector:presentingViewControllerSelector];
|
presentingViewController = [self performSelector:presentingViewControllerSelector];
|
||||||
}
|
|
||||||
else {
|
|
||||||
presentingViewController = [self parentViewController];
|
|
||||||
}
|
|
||||||
|
|
||||||
// If there is no presenting view controller just remove view
|
|
||||||
if (presentingViewController) {
|
|
||||||
[presentingViewController dismissModalViewControllerAnimated:YES];
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
[self.navigationController.view removeFromSuperview];
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
[self.navigationController popViewControllerAnimated:YES];
|
presentingViewController = [self parentViewController];
|
||||||
}
|
}
|
||||||
|
|
||||||
[[UIApplication sharedApplication] setStatusBarStyle:statusBarStyle_];
|
// If there is no presenting view controller just remove view
|
||||||
|
if (presentingViewController) {
|
||||||
|
[presentingViewController dismissModalViewControllerAnimated:YES];
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
[self.navigationController.view removeFromSuperview];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
[self.navigationController popViewControllerAnimated:YES];
|
||||||
|
}
|
||||||
|
|
||||||
|
[[UIApplication sharedApplication] setStatusBarStyle:statusBarStyle_];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (CAGradientLayer *)backgroundLayer {
|
- (CAGradientLayer *)backgroundLayer {
|
||||||
@ -299,199 +299,199 @@
|
|||||||
UIColor *colorTwo = [UIColor colorWithHue:0.625 saturation:0.0 brightness:0.85 alpha:1.0];
|
UIColor *colorTwo = [UIColor colorWithHue:0.625 saturation:0.0 brightness:0.85 alpha:1.0];
|
||||||
UIColor *colorThree = [UIColor colorWithHue:0.625 saturation:0.0 brightness:0.7 alpha:1.0];
|
UIColor *colorThree = [UIColor colorWithHue:0.625 saturation:0.0 brightness:0.7 alpha:1.0];
|
||||||
UIColor *colorFour = [UIColor colorWithHue:0.625 saturation:0.0 brightness:0.4 alpha:1.0];
|
UIColor *colorFour = [UIColor colorWithHue:0.625 saturation:0.0 brightness:0.4 alpha:1.0];
|
||||||
|
|
||||||
NSArray *colors = [NSArray arrayWithObjects:(id)colorOne.CGColor, colorTwo.CGColor, colorThree.CGColor, colorFour.CGColor, nil];
|
NSArray *colors = [NSArray arrayWithObjects:(id)colorOne.CGColor, colorTwo.CGColor, colorThree.CGColor, colorFour.CGColor, nil];
|
||||||
|
|
||||||
NSNumber *stopOne = [NSNumber numberWithFloat:0.0];
|
NSNumber *stopOne = [NSNumber numberWithFloat:0.0];
|
||||||
NSNumber *stopTwo = [NSNumber numberWithFloat:0.02];
|
NSNumber *stopTwo = [NSNumber numberWithFloat:0.02];
|
||||||
NSNumber *stopThree = [NSNumber numberWithFloat:0.99];
|
NSNumber *stopThree = [NSNumber numberWithFloat:0.99];
|
||||||
NSNumber *stopFour = [NSNumber numberWithFloat:1.0];
|
NSNumber *stopFour = [NSNumber numberWithFloat:1.0];
|
||||||
|
|
||||||
NSArray *locations = [NSArray arrayWithObjects:stopOne, stopTwo, stopThree, stopFour, nil];
|
NSArray *locations = [NSArray arrayWithObjects:stopOne, stopTwo, stopThree, stopFour, nil];
|
||||||
|
|
||||||
CAGradientLayer *headerLayer = [CAGradientLayer layer];
|
CAGradientLayer *headerLayer = [CAGradientLayer layer];
|
||||||
//headerLayer.frame = CGRectMake(0.0, 0.0, 320.0, 77.0);
|
//headerLayer.frame = CGRectMake(0.0, 0.0, 320.0, 77.0);
|
||||||
headerLayer.colors = colors;
|
headerLayer.colors = colors;
|
||||||
headerLayer.locations = locations;
|
headerLayer.locations = locations;
|
||||||
|
|
||||||
return headerLayer;
|
return headerLayer;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)viewDidLoad {
|
- (void)viewDidLoad {
|
||||||
[super viewDidLoad];
|
[super viewDidLoad];
|
||||||
|
|
||||||
// add notifications only to loaded view
|
// add notifications only to loaded view
|
||||||
NSNotificationCenter *dnc = [NSNotificationCenter defaultCenter];
|
NSNotificationCenter *dnc = [NSNotificationCenter defaultCenter];
|
||||||
[dnc addObserver:self selector:@selector(appDidBecomeActive_) name:UIApplicationDidBecomeActiveNotification object:nil];
|
[dnc addObserver:self selector:@selector(appDidBecomeActive_) name:UIApplicationDidBecomeActiveNotification object:nil];
|
||||||
|
|
||||||
// hook into manager with kvo!
|
// hook into manager with kvo!
|
||||||
[self.hockeyManager addObserver:self forKeyPath:@"checkInProgress" options:0 context:nil];
|
[self.hockeyManager addObserver:self forKeyPath:@"checkInProgress" options:0 context:nil];
|
||||||
[self.hockeyManager addObserver:self forKeyPath:@"isUpdateURLOffline" options:0 context:nil];
|
[self.hockeyManager addObserver:self forKeyPath:@"isUpdateURLOffline" options:0 context:nil];
|
||||||
[self.hockeyManager addObserver:self forKeyPath:@"updateAvailable" options:0 context:nil];
|
[self.hockeyManager addObserver:self forKeyPath:@"updateAvailable" options:0 context:nil];
|
||||||
[self.hockeyManager addObserver:self forKeyPath:@"apps" options:0 context:nil];
|
[self.hockeyManager addObserver:self forKeyPath:@"apps" options:0 context:nil];
|
||||||
kvoRegistered_ = YES;
|
kvoRegistered_ = YES;
|
||||||
|
|
||||||
self.tableView.backgroundColor = BW_RGBCOLOR(200, 202, 204);
|
self.tableView.backgroundColor = BW_RGBCOLOR(200, 202, 204);
|
||||||
self.tableView.separatorStyle = UITableViewCellSeparatorStyleNone;
|
self.tableView.separatorStyle = UITableViewCellSeparatorStyleNone;
|
||||||
|
|
||||||
UIView *topView = [[[UIView alloc] initWithFrame:CGRectMake(0, -(600-kAppStoreViewHeight), self.view.frame.size.width, 600)] autorelease];
|
UIView *topView = [[[UIView alloc] initWithFrame:CGRectMake(0, -(600-kAppStoreViewHeight), self.view.frame.size.width, 600)] autorelease];
|
||||||
topView.autoresizingMask = UIViewAutoresizingFlexibleWidth;
|
topView.autoresizingMask = UIViewAutoresizingFlexibleWidth;
|
||||||
topView.backgroundColor = BW_RGBCOLOR(140, 141, 142);
|
topView.backgroundColor = BW_RGBCOLOR(140, 141, 142);
|
||||||
[self.tableView addSubview:topView];
|
[self.tableView addSubview:topView];
|
||||||
|
|
||||||
appStoreHeader_ = [[PSAppStoreHeader alloc] initWithFrame:CGRectMake(0, 0, self.view.frame.size.width, kAppStoreViewHeight)];
|
appStoreHeader_ = [[PSAppStoreHeader alloc] initWithFrame:CGRectMake(0, 0, self.view.frame.size.width, kAppStoreViewHeight)];
|
||||||
[self updateAppStoreHeader_];
|
[self updateAppStoreHeader_];
|
||||||
|
|
||||||
NSString *iconString = nil;
|
NSString *iconString = nil;
|
||||||
NSArray *icons = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleIconFiles"];
|
NSArray *icons = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleIconFiles"];
|
||||||
if (!icons) {
|
if (!icons) {
|
||||||
iconString = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleIconFile"];
|
iconString = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleIconFile"];
|
||||||
if (!iconString) {
|
if (!iconString) {
|
||||||
iconString = @"Icon.png";
|
iconString = @"Icon.png";
|
||||||
}
|
|
||||||
} else {
|
|
||||||
BOOL useHighResIcon = NO;
|
|
||||||
BW_IF_IOS4_OR_GREATER(if ([UIScreen mainScreen].scale == 2.0f) useHighResIcon = YES;)
|
|
||||||
|
|
||||||
for(NSString *icon in icons) {
|
|
||||||
iconString = icon;
|
|
||||||
UIImage *iconImage = [UIImage imageNamed:icon];
|
|
||||||
|
|
||||||
if (iconImage.size.height == 57 && !useHighResIcon) {
|
|
||||||
// found!
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (iconImage.size.height == 114 && useHighResIcon) {
|
|
||||||
// found!
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
BOOL addGloss = YES;
|
BOOL useHighResIcon = NO;
|
||||||
NSNumber *prerendered = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"UIPrerenderedIcon"];
|
BW_IF_IOS4_OR_GREATER(if ([UIScreen mainScreen].scale == 2.0f) useHighResIcon = YES;)
|
||||||
if (prerendered) {
|
|
||||||
addGloss = ![prerendered boolValue];
|
for(NSString *icon in icons) {
|
||||||
|
iconString = icon;
|
||||||
|
UIImage *iconImage = [UIImage imageNamed:icon];
|
||||||
|
|
||||||
|
if (iconImage.size.height == 57 && !useHighResIcon) {
|
||||||
|
// found!
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (iconImage.size.height == 114 && useHighResIcon) {
|
||||||
|
// found!
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
if (addGloss) {
|
|
||||||
appStoreHeader_.iconImage = [self addGlossToImage_:[UIImage imageNamed:iconString]];
|
BOOL addGloss = YES;
|
||||||
} else {
|
NSNumber *prerendered = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"UIPrerenderedIcon"];
|
||||||
appStoreHeader_.iconImage = [UIImage imageNamed:iconString];
|
if (prerendered) {
|
||||||
}
|
addGloss = ![prerendered boolValue];
|
||||||
|
}
|
||||||
self.tableView.tableHeaderView = appStoreHeader_;
|
|
||||||
|
if (addGloss) {
|
||||||
if (self.modal) {
|
appStoreHeader_.iconImage = [self addGlossToImage_:[UIImage imageNamed:iconString]];
|
||||||
self.navigationItem.leftBarButtonItem = [[[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemDone
|
} else {
|
||||||
target:self
|
appStoreHeader_.iconImage = [UIImage imageNamed:iconString];
|
||||||
action:@selector(onAction:)] autorelease];
|
}
|
||||||
}
|
|
||||||
|
self.tableView.tableHeaderView = appStoreHeader_;
|
||||||
PSStoreButton *storeButton = [[[PSStoreButton alloc] initWithPadding:CGPointMake(5, 40)] autorelease];
|
|
||||||
storeButton.autoresizingMask = UIViewAutoresizingFlexibleLeftMargin;
|
if (self.modal) {
|
||||||
storeButton.buttonDelegate = self;
|
self.navigationItem.leftBarButtonItem = [[[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemDone
|
||||||
[self.tableView.tableHeaderView addSubview:storeButton];
|
target:self
|
||||||
storeButton.buttonData = [PSStoreButtonData dataWithLabel:@"" colors:[PSStoreButton appStoreGrayColor] enabled:NO];
|
action:@selector(onAction:)] autorelease];
|
||||||
self.appStoreButtonState = AppStoreButtonStateCheck;
|
}
|
||||||
[storeButton alignToSuperview];
|
|
||||||
appStoreButton_ = [storeButton retain];
|
PSStoreButton *storeButton = [[[PSStoreButton alloc] initWithPadding:CGPointMake(5, 40)] autorelease];
|
||||||
|
storeButton.autoresizingMask = UIViewAutoresizingFlexibleLeftMargin;
|
||||||
|
storeButton.buttonDelegate = self;
|
||||||
|
[self.tableView.tableHeaderView addSubview:storeButton];
|
||||||
|
storeButton.buttonData = [PSStoreButtonData dataWithLabel:@"" colors:[PSStoreButton appStoreGrayColor] enabled:NO];
|
||||||
|
self.appStoreButtonState = AppStoreButtonStateCheck;
|
||||||
|
[storeButton alignToSuperview];
|
||||||
|
appStoreButton_ = [storeButton retain];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)viewWillAppear:(BOOL)animated {
|
- (void)viewWillAppear:(BOOL)animated {
|
||||||
if ([self.hockeyManager isAppStoreEnvironment])
|
if ([self.hockeyManager isAppStoreEnvironment])
|
||||||
self.appStoreButtonState = AppStoreButtonStateOffline;
|
self.appStoreButtonState = AppStoreButtonStateOffline;
|
||||||
self.hockeyManager.currentHockeyViewController = self;
|
self.hockeyManager.currentHockeyViewController = self;
|
||||||
[super viewWillAppear:animated];
|
[super viewWillAppear:animated];
|
||||||
statusBarStyle_ = [[UIApplication sharedApplication] statusBarStyle];
|
statusBarStyle_ = [[UIApplication sharedApplication] statusBarStyle];
|
||||||
[[UIApplication sharedApplication] setStatusBarStyle:(self.navigationController.navigationBar.barStyle == UIBarStyleDefault) ? UIStatusBarStyleDefault : UIStatusBarStyleBlackOpaque];
|
[[UIApplication sharedApplication] setStatusBarStyle:(self.navigationController.navigationBar.barStyle == UIBarStyleDefault) ? UIStatusBarStyleDefault : UIStatusBarStyleBlackOpaque];
|
||||||
[self redrawTableView];
|
[self redrawTableView];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)viewWillDisappear:(BOOL)animated {
|
- (void)viewWillDisappear:(BOOL)animated {
|
||||||
self.hockeyManager.currentHockeyViewController = nil;
|
self.hockeyManager.currentHockeyViewController = nil;
|
||||||
//if the popover is still visible, dismiss it
|
//if the popover is still visible, dismiss it
|
||||||
[popOverController_ dismissPopoverAnimated:YES];
|
[popOverController_ dismissPopoverAnimated:YES];
|
||||||
[super viewWillDisappear:animated];
|
[super viewWillDisappear:animated];
|
||||||
[[UIApplication sharedApplication] setStatusBarStyle:statusBarStyle_];
|
[[UIApplication sharedApplication] setStatusBarStyle:statusBarStyle_];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)redrawTableView {
|
- (void)redrawTableView {
|
||||||
[self restoreStoreButtonStateAnimated_:NO];
|
[self restoreStoreButtonStateAnimated_:NO];
|
||||||
[self updateAppStoreHeader_];
|
[self updateAppStoreHeader_];
|
||||||
|
|
||||||
// clean up and remove any pending overservers
|
// clean up and remove any pending overservers
|
||||||
for (UITableViewCell *cell in cells_) {
|
for (UITableViewCell *cell in cells_) {
|
||||||
[cell removeObserver:self forKeyPath:@"webViewSize"];
|
[cell removeObserver:self forKeyPath:@"webViewSize"];
|
||||||
}
|
}
|
||||||
[cells_ removeAllObjects];
|
[cells_ removeAllObjects];
|
||||||
|
|
||||||
int i = 0;
|
int i = 0;
|
||||||
BOOL breakAfterThisApp = NO;
|
BOOL breakAfterThisApp = NO;
|
||||||
for (BWApp *app in self.hockeyManager.apps) {
|
for (BWApp *app in self.hockeyManager.apps) {
|
||||||
i++;
|
i++;
|
||||||
|
|
||||||
// only show the newer version of the app by default, if we don't show all versions
|
// only show the newer version of the app by default, if we don't show all versions
|
||||||
if (!showAllVersions_) {
|
if (!showAllVersions_) {
|
||||||
if ([app.version isEqualToString:[self.hockeyManager currentAppVersion]]) {
|
if ([app.version isEqualToString:[self.hockeyManager currentAppVersion]]) {
|
||||||
if (i == 1) {
|
if (i == 1) {
|
||||||
breakAfterThisApp = YES;
|
breakAfterThisApp = YES;
|
||||||
} else {
|
} else {
|
||||||
break;
|
break;
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
PSWebTableViewCell *cell = [[[PSWebTableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:kWebCellIdentifier] autorelease];
|
|
||||||
[self configureWebCell:cell forApp_:app];
|
|
||||||
[cells_ addObject:cell];
|
|
||||||
|
|
||||||
if (breakAfterThisApp) break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[self.tableView reloadData];
|
PSWebTableViewCell *cell = [[[PSWebTableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:kWebCellIdentifier] autorelease];
|
||||||
[self showHidePreviousVersionsButton];
|
[self configureWebCell:cell forApp_:app];
|
||||||
|
[cells_ addObject:cell];
|
||||||
|
|
||||||
|
if (breakAfterThisApp) break;
|
||||||
|
}
|
||||||
|
|
||||||
|
[self.tableView reloadData];
|
||||||
|
[self showHidePreviousVersionsButton];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)showPreviousVersionAction {
|
- (void)showPreviousVersionAction {
|
||||||
showAllVersions_ = YES;
|
showAllVersions_ = YES;
|
||||||
BOOL showAllPending = NO;
|
BOOL showAllPending = NO;
|
||||||
|
|
||||||
for (BWApp *app in self.hockeyManager.apps) {
|
for (BWApp *app in self.hockeyManager.apps) {
|
||||||
if (!showAllPending) {
|
if (!showAllPending) {
|
||||||
if ([app.version isEqualToString:[self.hockeyManager currentAppVersion]]) {
|
if ([app.version isEqualToString:[self.hockeyManager currentAppVersion]]) {
|
||||||
showAllPending = YES;
|
showAllPending = YES;
|
||||||
if (app == self.hockeyManager.app) {
|
if (app == self.hockeyManager.app) {
|
||||||
continue; // skip this version already if it the latest version is the installed one
|
continue; // skip this version already if it the latest version is the installed one
|
||||||
}
|
|
||||||
} else {
|
|
||||||
continue; // skip already shown
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
PSWebTableViewCell *cell = [[[PSWebTableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:kWebCellIdentifier] autorelease];
|
continue; // skip already shown
|
||||||
[self configureWebCell:cell forApp_:app];
|
}
|
||||||
[cells_ addObject:cell];
|
|
||||||
}
|
}
|
||||||
[self.tableView reloadData];
|
|
||||||
[self showHidePreviousVersionsButton];
|
PSWebTableViewCell *cell = [[[PSWebTableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:kWebCellIdentifier] autorelease];
|
||||||
|
[self configureWebCell:cell forApp_:app];
|
||||||
|
[cells_ addObject:cell];
|
||||||
|
}
|
||||||
|
[self.tableView reloadData];
|
||||||
|
[self showHidePreviousVersionsButton];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)viewDidUnload {
|
- (void)viewDidUnload {
|
||||||
[appStoreHeader_ release]; appStoreHeader_ = nil;
|
[appStoreHeader_ release]; appStoreHeader_ = nil;
|
||||||
[popOverController_ release], popOverController_ = nil;
|
[popOverController_ release], popOverController_ = nil;
|
||||||
[[NSNotificationCenter defaultCenter] removeObserver:self];
|
[[NSNotificationCenter defaultCenter] removeObserver:self];
|
||||||
|
|
||||||
// test if KVO's are registered. if class is destroyed before it was shown(viewDidLoad) no KVOs are registered.
|
// test if KVO's are registered. if class is destroyed before it was shown(viewDidLoad) no KVOs are registered.
|
||||||
if (kvoRegistered_) {
|
if (kvoRegistered_) {
|
||||||
[self.hockeyManager removeObserver:self forKeyPath:@"checkInProgress"];
|
[self.hockeyManager removeObserver:self forKeyPath:@"checkInProgress"];
|
||||||
[self.hockeyManager removeObserver:self forKeyPath:@"isUpdateURLOffline"];
|
[self.hockeyManager removeObserver:self forKeyPath:@"isUpdateURLOffline"];
|
||||||
[self.hockeyManager removeObserver:self forKeyPath:@"updateAvailable"];
|
[self.hockeyManager removeObserver:self forKeyPath:@"updateAvailable"];
|
||||||
[self.hockeyManager removeObserver:self forKeyPath:@"apps"];
|
[self.hockeyManager removeObserver:self forKeyPath:@"apps"];
|
||||||
kvoRegistered_ = NO;
|
kvoRegistered_ = NO;
|
||||||
}
|
}
|
||||||
|
|
||||||
[super viewDidUnload];
|
[super viewDidUnload];
|
||||||
}
|
}
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
@ -499,32 +499,32 @@
|
|||||||
#pragma mark Table view data source
|
#pragma mark Table view data source
|
||||||
|
|
||||||
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
|
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
|
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
|
||||||
CGFloat rowHeight = 0;
|
CGFloat rowHeight = 0;
|
||||||
|
|
||||||
if ([cells_ count] > (NSUInteger)indexPath.row) {
|
if ([cells_ count] > (NSUInteger)indexPath.row) {
|
||||||
PSWebTableViewCell *cell = [cells_ objectAtIndex:indexPath.row];
|
PSWebTableViewCell *cell = [cells_ objectAtIndex:indexPath.row];
|
||||||
rowHeight = cell.webViewSize.height;
|
rowHeight = cell.webViewSize.height;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ([self.hockeyManager.apps count] > 1 && !showAllVersions_) {
|
if ([self.hockeyManager.apps count] > 1 && !showAllVersions_) {
|
||||||
self.tableView.backgroundColor = BW_RGBCOLOR(183, 183, 183);
|
self.tableView.backgroundColor = BW_RGBCOLOR(183, 183, 183);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (rowHeight == 0) {
|
if (rowHeight == 0) {
|
||||||
rowHeight = indexPath.row == 0 ? 250 : 44; // fill screen on startup
|
rowHeight = indexPath.row == 0 ? 250 : 44; // fill screen on startup
|
||||||
self.tableView.backgroundColor = BW_RGBCOLOR(200, 202, 204);
|
self.tableView.backgroundColor = BW_RGBCOLOR(200, 202, 204);
|
||||||
}
|
}
|
||||||
|
|
||||||
return rowHeight;
|
return rowHeight;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
|
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
|
||||||
NSInteger cellCount = [cells_ count];
|
NSInteger cellCount = [cells_ count];
|
||||||
return cellCount;
|
return cellCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
@ -535,32 +535,32 @@
|
|||||||
// only make changes if we are visible
|
// only make changes if we are visible
|
||||||
if(self.view.window) {
|
if(self.view.window) {
|
||||||
if ([keyPath isEqualToString:@"webViewSize"]) {
|
if ([keyPath isEqualToString:@"webViewSize"]) {
|
||||||
[self.tableView reloadData];
|
[self.tableView reloadData];
|
||||||
[self realignPreviousVersionButton];
|
[self realignPreviousVersionButton];
|
||||||
} else if ([keyPath isEqualToString:@"checkInProgress"]) {
|
} else if ([keyPath isEqualToString:@"checkInProgress"]) {
|
||||||
if (self.hockeyManager.isCheckInProgress) {
|
if (self.hockeyManager.isCheckInProgress) {
|
||||||
[self setAppStoreButtonState:AppStoreButtonStateSearching animated:YES];
|
[self setAppStoreButtonState:AppStoreButtonStateSearching animated:YES];
|
||||||
}else {
|
}else {
|
||||||
[self restoreStoreButtonStateAnimated_:YES];
|
[self restoreStoreButtonStateAnimated_:YES];
|
||||||
}
|
}
|
||||||
} else if ([keyPath isEqualToString:@"isUpdateURLOffline"]) {
|
} else if ([keyPath isEqualToString:@"isUpdateURLOffline"]) {
|
||||||
[self restoreStoreButtonStateAnimated_:YES];
|
[self restoreStoreButtonStateAnimated_:YES];
|
||||||
} else if ([keyPath isEqualToString:@"updateAvailable"]) {
|
} else if ([keyPath isEqualToString:@"updateAvailable"]) {
|
||||||
[self restoreStoreButtonStateAnimated_:YES];
|
[self restoreStoreButtonStateAnimated_:YES];
|
||||||
} else if ([keyPath isEqualToString:@"apps"]) {
|
} else if ([keyPath isEqualToString:@"apps"]) {
|
||||||
[self redrawTableView];
|
[self redrawTableView];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Customize the appearance of table view cells.
|
// Customize the appearance of table view cells.
|
||||||
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
|
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
|
||||||
if ([cells_ count] > (NSUInteger)indexPath.row) {
|
if ([cells_ count] > (NSUInteger)indexPath.row) {
|
||||||
return [cells_ objectAtIndex:indexPath.row];
|
return [cells_ objectAtIndex:indexPath.row];
|
||||||
} else {
|
} else {
|
||||||
BWHockeyLog(@"Warning: cells_ and indexPath do not match? forgot calling redrawTableView?");
|
BWHockeyLog(@"Warning: cells_ and indexPath do not match? forgot calling redrawTableView?");
|
||||||
}
|
}
|
||||||
return nil;
|
return nil;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -569,22 +569,22 @@
|
|||||||
#pragma mark Rotation
|
#pragma mark Rotation
|
||||||
|
|
||||||
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
|
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
|
||||||
BOOL shouldAutorotate;
|
BOOL shouldAutorotate;
|
||||||
|
|
||||||
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone) {
|
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone) {
|
||||||
shouldAutorotate = (interfaceOrientation == UIInterfaceOrientationLandscapeLeft ||
|
shouldAutorotate = (interfaceOrientation == UIInterfaceOrientationLandscapeLeft ||
|
||||||
interfaceOrientation == UIInterfaceOrientationLandscapeRight ||
|
interfaceOrientation == UIInterfaceOrientationLandscapeRight ||
|
||||||
interfaceOrientation == UIInterfaceOrientationPortrait);
|
interfaceOrientation == UIInterfaceOrientationPortrait);
|
||||||
} else {
|
} else {
|
||||||
shouldAutorotate = YES;
|
shouldAutorotate = YES;
|
||||||
}
|
}
|
||||||
|
|
||||||
return shouldAutorotate;
|
return shouldAutorotate;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation duration:(NSTimeInterval)duration {
|
- (void)willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation duration:(NSTimeInterval)duration {
|
||||||
// update all cells
|
// update all cells
|
||||||
[cells_ makeObjectsPerformSelector:@selector(addWebView)];
|
[cells_ makeObjectsPerformSelector:@selector(addWebView)];
|
||||||
}
|
}
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
@ -592,46 +592,46 @@
|
|||||||
#pragma mark PSAppStoreHeaderDelegate
|
#pragma mark PSAppStoreHeaderDelegate
|
||||||
|
|
||||||
- (void)setAppStoreButtonState:(AppStoreButtonState)anAppStoreButtonState {
|
- (void)setAppStoreButtonState:(AppStoreButtonState)anAppStoreButtonState {
|
||||||
[self setAppStoreButtonState:anAppStoreButtonState animated:NO];
|
[self setAppStoreButtonState:anAppStoreButtonState animated:NO];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)setAppStoreButtonState:(AppStoreButtonState)anAppStoreButtonState animated:(BOOL)animated {
|
- (void)setAppStoreButtonState:(AppStoreButtonState)anAppStoreButtonState animated:(BOOL)animated {
|
||||||
appStoreButtonState_ = anAppStoreButtonState;
|
appStoreButtonState_ = anAppStoreButtonState;
|
||||||
|
|
||||||
switch (anAppStoreButtonState) {
|
switch (anAppStoreButtonState) {
|
||||||
case AppStoreButtonStateOffline:
|
case AppStoreButtonStateOffline:
|
||||||
[appStoreButton_ setButtonData:[PSStoreButtonData dataWithLabel:BWHockeyLocalize(@"HockeyButtonOffline") colors:[PSStoreButton appStoreGrayColor] enabled:NO] animated:animated];
|
[appStoreButton_ setButtonData:[PSStoreButtonData dataWithLabel:BWHockeyLocalize(@"HockeyButtonOffline") colors:[PSStoreButton appStoreGrayColor] enabled:NO] animated:animated];
|
||||||
break;
|
break;
|
||||||
case AppStoreButtonStateCheck:
|
case AppStoreButtonStateCheck:
|
||||||
[appStoreButton_ setButtonData:[PSStoreButtonData dataWithLabel:BWHockeyLocalize(@"HockeyButtonCheck") colors:[PSStoreButton appStoreGreenColor] enabled:YES] animated:animated];
|
[appStoreButton_ setButtonData:[PSStoreButtonData dataWithLabel:BWHockeyLocalize(@"HockeyButtonCheck") colors:[PSStoreButton appStoreGreenColor] enabled:YES] animated:animated];
|
||||||
break;
|
break;
|
||||||
case AppStoreButtonStateSearching:
|
case AppStoreButtonStateSearching:
|
||||||
[appStoreButton_ setButtonData:[PSStoreButtonData dataWithLabel:BWHockeyLocalize(@"HockeyButtonSearching") colors:[PSStoreButton appStoreGrayColor] enabled:NO] animated:animated];
|
[appStoreButton_ setButtonData:[PSStoreButtonData dataWithLabel:BWHockeyLocalize(@"HockeyButtonSearching") colors:[PSStoreButton appStoreGrayColor] enabled:NO] animated:animated];
|
||||||
break;
|
break;
|
||||||
case AppStoreButtonStateUpdate:
|
case AppStoreButtonStateUpdate:
|
||||||
[appStoreButton_ setButtonData:[PSStoreButtonData dataWithLabel:BWHockeyLocalize(@"HockeyButtonUpdate") colors:[PSStoreButton appStoreBlueColor] enabled:YES] animated:animated];
|
[appStoreButton_ setButtonData:[PSStoreButtonData dataWithLabel:BWHockeyLocalize(@"HockeyButtonUpdate") colors:[PSStoreButton appStoreBlueColor] enabled:YES] animated:animated];
|
||||||
break;
|
break;
|
||||||
case AppStoreButtonStateInstalling:
|
case AppStoreButtonStateInstalling:
|
||||||
[appStoreButton_ setButtonData:[PSStoreButtonData dataWithLabel:BWHockeyLocalize(@"HockeyButtonInstalling") colors:[PSStoreButton appStoreGrayColor] enabled:NO] animated:animated];
|
[appStoreButton_ setButtonData:[PSStoreButtonData dataWithLabel:BWHockeyLocalize(@"HockeyButtonInstalling") colors:[PSStoreButton appStoreGrayColor] enabled:NO] animated:animated];
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)storeButtonFired:(PSStoreButton *)button {
|
- (void)storeButtonFired:(PSStoreButton *)button {
|
||||||
switch (appStoreButtonState_) {
|
switch (appStoreButtonState_) {
|
||||||
case AppStoreButtonStateCheck:
|
case AppStoreButtonStateCheck:
|
||||||
[self.hockeyManager checkForUpdateShowFeedback:YES];
|
[self.hockeyManager checkForUpdateShowFeedback:YES];
|
||||||
break;
|
break;
|
||||||
case AppStoreButtonStateUpdate:
|
case AppStoreButtonStateUpdate:
|
||||||
if ([self.hockeyManager initiateAppDownload]) {
|
if ([self.hockeyManager initiateAppDownload]) {
|
||||||
[self setAppStoreButtonState:AppStoreButtonStateInstalling animated:YES];
|
[self setAppStoreButtonState:AppStoreButtonStateInstalling animated:YES];
|
||||||
};
|
};
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
@ -57,61 +57,61 @@ typedef enum QuincyKitAlertType {
|
|||||||
} CrashAlertType;
|
} CrashAlertType;
|
||||||
|
|
||||||
typedef enum CrashReportStatus {
|
typedef enum CrashReportStatus {
|
||||||
// The status of the crash is queued, need to check later (HockeyApp)
|
// The status of the crash is queued, need to check later (HockeyApp)
|
||||||
CrashReportStatusQueued = -80,
|
CrashReportStatusQueued = -80,
|
||||||
|
|
||||||
// This app version is set to discontinued, no new crash reports accepted by the server
|
// This app version is set to discontinued, no new crash reports accepted by the server
|
||||||
CrashReportStatusFailureVersionDiscontinued = -30,
|
CrashReportStatusFailureVersionDiscontinued = -30,
|
||||||
|
|
||||||
// XML: Sender version string contains not allowed characters, only alphanumberical including space and . are allowed
|
// XML: Sender version string contains not allowed characters, only alphanumberical including space and . are allowed
|
||||||
CrashReportStatusFailureXMLSenderVersionNotAllowed = -21,
|
CrashReportStatusFailureXMLSenderVersionNotAllowed = -21,
|
||||||
|
|
||||||
// XML: Version string contains not allowed characters, only alphanumberical including space and . are allowed
|
// XML: Version string contains not allowed characters, only alphanumberical including space and . are allowed
|
||||||
CrashReportStatusFailureXMLVersionNotAllowed = -20,
|
CrashReportStatusFailureXMLVersionNotAllowed = -20,
|
||||||
|
|
||||||
// SQL for adding a symoblicate todo entry in the database failed
|
// SQL for adding a symoblicate todo entry in the database failed
|
||||||
CrashReportStatusFailureSQLAddSymbolicateTodo = -18,
|
CrashReportStatusFailureSQLAddSymbolicateTodo = -18,
|
||||||
|
|
||||||
// SQL for adding crash log in the database failed
|
// SQL for adding crash log in the database failed
|
||||||
CrashReportStatusFailureSQLAddCrashlog = -17,
|
CrashReportStatusFailureSQLAddCrashlog = -17,
|
||||||
|
|
||||||
// SQL for adding a new version in the database failed
|
// SQL for adding a new version in the database failed
|
||||||
CrashReportStatusFailureSQLAddVersion = -16,
|
CrashReportStatusFailureSQLAddVersion = -16,
|
||||||
|
|
||||||
// SQL for checking if the version is already added in the database failed
|
// SQL for checking if the version is already added in the database failed
|
||||||
CrashReportStatusFailureSQLCheckVersionExists = -15,
|
CrashReportStatusFailureSQLCheckVersionExists = -15,
|
||||||
|
|
||||||
// SQL for creating a new pattern for this bug and set amount of occurrances to 1 in the database failed
|
// SQL for creating a new pattern for this bug and set amount of occurrances to 1 in the database failed
|
||||||
CrashReportStatusFailureSQLAddPattern = -14,
|
CrashReportStatusFailureSQLAddPattern = -14,
|
||||||
|
|
||||||
// SQL for checking the status of the bugfix version in the database failed
|
// SQL for checking the status of the bugfix version in the database failed
|
||||||
CrashReportStatusFailureSQLCheckBugfixStatus = -13,
|
CrashReportStatusFailureSQLCheckBugfixStatus = -13,
|
||||||
|
|
||||||
// SQL for updating the occurances of this pattern in the database failed
|
// SQL for updating the occurances of this pattern in the database failed
|
||||||
CrashReportStatusFailureSQLUpdatePatternOccurances = -12,
|
CrashReportStatusFailureSQLUpdatePatternOccurances = -12,
|
||||||
|
|
||||||
// SQL for getting all the known bug patterns for the current app version in the database failed
|
// SQL for getting all the known bug patterns for the current app version in the database failed
|
||||||
CrashReportStatusFailureSQLFindKnownPatterns = -11,
|
CrashReportStatusFailureSQLFindKnownPatterns = -11,
|
||||||
|
|
||||||
// SQL for finding the bundle identifier in the database failed
|
// SQL for finding the bundle identifier in the database failed
|
||||||
CrashReportStatusFailureSQLSearchAppName = -10,
|
CrashReportStatusFailureSQLSearchAppName = -10,
|
||||||
|
|
||||||
// the post request didn't contain valid data
|
// the post request didn't contain valid data
|
||||||
CrashReportStatusFailureInvalidPostData = -3,
|
CrashReportStatusFailureInvalidPostData = -3,
|
||||||
|
|
||||||
// incoming data may not be added, because e.g. bundle identifier wasn't found
|
// incoming data may not be added, because e.g. bundle identifier wasn't found
|
||||||
CrashReportStatusFailureInvalidIncomingData = -2,
|
CrashReportStatusFailureInvalidIncomingData = -2,
|
||||||
|
|
||||||
// database cannot be accessed, check hostname, username, password and database name settings in config.php
|
// database cannot be accessed, check hostname, username, password and database name settings in config.php
|
||||||
CrashReportStatusFailureDatabaseNotAvailable = -1,
|
CrashReportStatusFailureDatabaseNotAvailable = -1,
|
||||||
|
|
||||||
CrashReportStatusUnknown = 0,
|
CrashReportStatusUnknown = 0,
|
||||||
|
|
||||||
CrashReportStatusAssigned = 1,
|
CrashReportStatusAssigned = 1,
|
||||||
|
|
||||||
CrashReportStatusSubmitted = 2,
|
CrashReportStatusSubmitted = 2,
|
||||||
|
|
||||||
CrashReportStatusAvailable = 3,
|
CrashReportStatusAvailable = 3,
|
||||||
} CrashReportStatus;
|
} CrashReportStatus;
|
||||||
|
|
||||||
// This protocol is used to send the image updates
|
// This protocol is used to send the image updates
|
||||||
@ -140,42 +140,42 @@ typedef enum CrashReportStatus {
|
|||||||
@end
|
@end
|
||||||
|
|
||||||
@interface BWQuincyManager : NSObject <NSXMLParserDelegate> {
|
@interface BWQuincyManager : NSObject <NSXMLParserDelegate> {
|
||||||
NSString *_submissionURL;
|
NSString *_submissionURL;
|
||||||
|
|
||||||
id <BWQuincyManagerDelegate> _delegate;
|
id <BWQuincyManagerDelegate> _delegate;
|
||||||
|
|
||||||
BOOL _showAlwaysButton;
|
BOOL _showAlwaysButton;
|
||||||
BOOL _feedbackActivated;
|
BOOL _feedbackActivated;
|
||||||
BOOL _autoSubmitCrashReport;
|
BOOL _autoSubmitCrashReport;
|
||||||
BOOL _autoSubmitDeviceUDID;
|
BOOL _autoSubmitDeviceUDID;
|
||||||
|
|
||||||
BOOL _didCrashInLastSession;
|
BOOL _didCrashInLastSession;
|
||||||
|
|
||||||
NSString *_appIdentifier;
|
NSString *_appIdentifier;
|
||||||
|
|
||||||
NSString *_feedbackRequestID;
|
NSString *_feedbackRequestID;
|
||||||
float _feedbackDelayInterval;
|
float _feedbackDelayInterval;
|
||||||
|
|
||||||
NSMutableString *_contentOfProperty;
|
NSMutableString *_contentOfProperty;
|
||||||
CrashReportStatus _serverResult;
|
CrashReportStatus _serverResult;
|
||||||
|
|
||||||
int _analyzerStarted;
|
int _analyzerStarted;
|
||||||
NSString *_crashesDir;
|
NSString *_crashesDir;
|
||||||
|
|
||||||
BOOL _crashIdenticalCurrentVersion;
|
BOOL _crashIdenticalCurrentVersion;
|
||||||
BOOL _crashReportActivated;
|
BOOL _crashReportActivated;
|
||||||
|
|
||||||
NSMutableArray *_crashFiles;
|
NSMutableArray *_crashFiles;
|
||||||
|
|
||||||
NSMutableData *_responseData;
|
NSMutableData *_responseData;
|
||||||
NSInteger _statusCode;
|
NSInteger _statusCode;
|
||||||
|
|
||||||
NSURLConnection *_urlConnection;
|
NSURLConnection *_urlConnection;
|
||||||
|
|
||||||
NSData *_crashData;
|
NSData *_crashData;
|
||||||
|
|
||||||
NSString *_languageStyle;
|
NSString *_languageStyle;
|
||||||
BOOL _sendingInProgress;
|
BOOL _sendingInProgress;
|
||||||
}
|
}
|
||||||
|
|
||||||
+ (BWQuincyManager *)sharedQuincyManager;
|
+ (BWQuincyManager *)sharedQuincyManager;
|
||||||
|
@ -36,22 +36,22 @@
|
|||||||
#include <inttypes.h> //needed for PRIx64 macro
|
#include <inttypes.h> //needed for PRIx64 macro
|
||||||
|
|
||||||
NSBundle *quincyBundle(void) {
|
NSBundle *quincyBundle(void) {
|
||||||
static NSBundle* bundle = nil;
|
static NSBundle* bundle = nil;
|
||||||
if (!bundle) {
|
if (!bundle) {
|
||||||
NSString* path = [[[NSBundle mainBundle] resourcePath]
|
NSString* path = [[[NSBundle mainBundle] resourcePath]
|
||||||
stringByAppendingPathComponent:kQuincyBundleName];
|
stringByAppendingPathComponent:kQuincyBundleName];
|
||||||
bundle = [[NSBundle bundleWithPath:path] retain];
|
bundle = [[NSBundle bundleWithPath:path] retain];
|
||||||
}
|
}
|
||||||
return bundle;
|
return bundle;
|
||||||
}
|
}
|
||||||
|
|
||||||
NSString *BWQuincyLocalize(NSString *stringToken) {
|
NSString *BWQuincyLocalize(NSString *stringToken) {
|
||||||
if ([BWQuincyManager sharedQuincyManager].languageStyle == nil)
|
if ([BWQuincyManager sharedQuincyManager].languageStyle == nil)
|
||||||
return NSLocalizedStringFromTableInBundle(stringToken, @"Quincy", quincyBundle(), @"");
|
return NSLocalizedStringFromTableInBundle(stringToken, @"Quincy", quincyBundle(), @"");
|
||||||
else {
|
else {
|
||||||
NSString *alternate = [NSString stringWithFormat:@"Quincy%@", [BWQuincyManager sharedQuincyManager].languageStyle];
|
NSString *alternate = [NSString stringWithFormat:@"Quincy%@", [BWQuincyManager sharedQuincyManager].languageStyle];
|
||||||
return NSLocalizedStringFromTableInBundle(stringToken, alternate, quincyBundle(), @"");
|
return NSLocalizedStringFromTableInBundle(stringToken, alternate, quincyBundle(), @"");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -93,15 +93,15 @@ NSString *BWQuincyLocalize(NSString *stringToken) {
|
|||||||
#if __IPHONE_OS_VERSION_MIN_REQUIRED >= 40000
|
#if __IPHONE_OS_VERSION_MIN_REQUIRED >= 40000
|
||||||
+(BWQuincyManager *)sharedQuincyManager
|
+(BWQuincyManager *)sharedQuincyManager
|
||||||
{
|
{
|
||||||
static BWQuincyManager *sharedInstance = nil;
|
static BWQuincyManager *sharedInstance = nil;
|
||||||
static dispatch_once_t pred;
|
static dispatch_once_t pred;
|
||||||
|
|
||||||
dispatch_once(&pred, ^{
|
dispatch_once(&pred, ^{
|
||||||
sharedInstance = [BWQuincyManager alloc];
|
sharedInstance = [BWQuincyManager alloc];
|
||||||
sharedInstance = [sharedInstance init];
|
sharedInstance = [sharedInstance init];
|
||||||
});
|
});
|
||||||
|
|
||||||
return sharedInstance;
|
return sharedInstance;
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
+ (BWQuincyManager *)sharedQuincyManager {
|
+ (BWQuincyManager *)sharedQuincyManager {
|
||||||
@ -116,24 +116,24 @@ NSString *BWQuincyLocalize(NSString *stringToken) {
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
- (id) init {
|
- (id) init {
|
||||||
if ((self = [super init])) {
|
if ((self = [super init])) {
|
||||||
_serverResult = CrashReportStatusUnknown;
|
_serverResult = CrashReportStatusUnknown;
|
||||||
_crashIdenticalCurrentVersion = YES;
|
_crashIdenticalCurrentVersion = YES;
|
||||||
_crashData = nil;
|
_crashData = nil;
|
||||||
_urlConnection = nil;
|
_urlConnection = nil;
|
||||||
_submissionURL = nil;
|
_submissionURL = nil;
|
||||||
_responseData = nil;
|
_responseData = nil;
|
||||||
_appIdentifier = nil;
|
_appIdentifier = nil;
|
||||||
_sendingInProgress = NO;
|
_sendingInProgress = NO;
|
||||||
_languageStyle = nil;
|
_languageStyle = nil;
|
||||||
_didCrashInLastSession = NO;
|
_didCrashInLastSession = NO;
|
||||||
|
|
||||||
self.delegate = nil;
|
self.delegate = nil;
|
||||||
self.feedbackActivated = NO;
|
self.feedbackActivated = NO;
|
||||||
self.showAlwaysButton = NO;
|
self.showAlwaysButton = NO;
|
||||||
self.autoSubmitCrashReport = NO;
|
self.autoSubmitCrashReport = NO;
|
||||||
self.autoSubmitDeviceUDID = NO;
|
self.autoSubmitDeviceUDID = NO;
|
||||||
|
|
||||||
NSString *testValue = [[NSUserDefaults standardUserDefaults] stringForKey:kQuincyKitAnalyzerStarted];
|
NSString *testValue = [[NSUserDefaults standardUserDefaults] stringForKey:kQuincyKitAnalyzerStarted];
|
||||||
if (testValue) {
|
if (testValue) {
|
||||||
_analyzerStarted = [[NSUserDefaults standardUserDefaults] integerForKey:kQuincyKitAnalyzerStarted];
|
_analyzerStarted = [[NSUserDefaults standardUserDefaults] integerForKey:kQuincyKitAnalyzerStarted];
|
||||||
@ -149,7 +149,7 @@ NSString *BWQuincyLocalize(NSString *stringToken) {
|
|||||||
_crashReportActivated = YES;
|
_crashReportActivated = YES;
|
||||||
[[NSUserDefaults standardUserDefaults] setValue:[NSNumber numberWithBool:YES] forKey:kQuincyKitActivated];
|
[[NSUserDefaults standardUserDefaults] setValue:[NSNumber numberWithBool:YES] forKey:kQuincyKitActivated];
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_crashReportActivated) {
|
if (_crashReportActivated) {
|
||||||
_crashFiles = [[NSMutableArray alloc] init];
|
_crashFiles = [[NSMutableArray alloc] init];
|
||||||
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES);
|
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES);
|
||||||
@ -163,52 +163,52 @@ NSString *BWQuincyLocalize(NSString *stringToken) {
|
|||||||
|
|
||||||
[fm createDirectoryAtPath:_crashesDir withIntermediateDirectories: YES attributes: attributes error: &theError];
|
[fm createDirectoryAtPath:_crashesDir withIntermediateDirectories: YES attributes: attributes error: &theError];
|
||||||
}
|
}
|
||||||
|
|
||||||
PLCrashReporter *crashReporter = [PLCrashReporter sharedReporter];
|
PLCrashReporter *crashReporter = [PLCrashReporter sharedReporter];
|
||||||
NSError *error = NULL;
|
NSError *error = NULL;
|
||||||
|
|
||||||
// Check if we previously crashed
|
// Check if we previously crashed
|
||||||
if ([crashReporter hasPendingCrashReport]) {
|
if ([crashReporter hasPendingCrashReport]) {
|
||||||
_didCrashInLastSession = YES;
|
_didCrashInLastSession = YES;
|
||||||
[self handleCrashReport];
|
[self handleCrashReport];
|
||||||
}
|
}
|
||||||
|
|
||||||
// Enable the Crash Reporter
|
// Enable the Crash Reporter
|
||||||
if (![crashReporter enableCrashReporterAndReturnError: &error])
|
if (![crashReporter enableCrashReporterAndReturnError: &error])
|
||||||
NSLog(@"Warning: Could not enable crash reporter: %@", error);
|
NSLog(@"Warning: Could not enable crash reporter: %@", error);
|
||||||
|
|
||||||
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(startManager) name:BWQuincyNetworkBecomeReachable object:nil];
|
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(startManager) name:BWQuincyNetworkBecomeReachable object:nil];
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!quincyBundle()) {
|
if (!quincyBundle()) {
|
||||||
NSLog(@"WARNING: Quincy.bundle is missing in the app bundle!");
|
NSLog(@"WARNING: Quincy.bundle is missing in the app bundle!");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
- (void) dealloc {
|
- (void) dealloc {
|
||||||
self.delegate = nil;
|
self.delegate = nil;
|
||||||
[[NSNotificationCenter defaultCenter] removeObserver:self name:BWQuincyNetworkBecomeReachable object:nil];
|
[[NSNotificationCenter defaultCenter] removeObserver:self name:BWQuincyNetworkBecomeReachable object:nil];
|
||||||
|
|
||||||
[_languageStyle release];
|
[_languageStyle release];
|
||||||
|
|
||||||
[_submissionURL release];
|
[_submissionURL release];
|
||||||
_submissionURL = nil;
|
_submissionURL = nil;
|
||||||
|
|
||||||
[_appIdentifier release];
|
[_appIdentifier release];
|
||||||
_appIdentifier = nil;
|
_appIdentifier = nil;
|
||||||
|
|
||||||
[_urlConnection cancel];
|
[_urlConnection cancel];
|
||||||
[_urlConnection release];
|
[_urlConnection release];
|
||||||
_urlConnection = nil;
|
_urlConnection = nil;
|
||||||
|
|
||||||
[_crashData release];
|
[_crashData release];
|
||||||
|
|
||||||
[_crashesDir release];
|
[_crashesDir release];
|
||||||
[_crashFiles release];
|
[_crashFiles release];
|
||||||
|
|
||||||
[super dealloc];
|
[super dealloc];
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -216,21 +216,21 @@ NSString *BWQuincyLocalize(NSString *stringToken) {
|
|||||||
#pragma mark -
|
#pragma mark -
|
||||||
#pragma mark setter
|
#pragma mark setter
|
||||||
- (void)setSubmissionURL:(NSString *)anSubmissionURL {
|
- (void)setSubmissionURL:(NSString *)anSubmissionURL {
|
||||||
if (_submissionURL != anSubmissionURL) {
|
if (_submissionURL != anSubmissionURL) {
|
||||||
[_submissionURL release];
|
[_submissionURL release];
|
||||||
_submissionURL = [anSubmissionURL copy];
|
_submissionURL = [anSubmissionURL copy];
|
||||||
}
|
}
|
||||||
|
|
||||||
[self performSelector:@selector(startManager) withObject:nil afterDelay:1.0f];
|
[self performSelector:@selector(startManager) withObject:nil afterDelay:1.0f];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)setAppIdentifier:(NSString *)anAppIdentifier {
|
- (void)setAppIdentifier:(NSString *)anAppIdentifier {
|
||||||
if (_appIdentifier != anAppIdentifier) {
|
if (_appIdentifier != anAppIdentifier) {
|
||||||
[_appIdentifier release];
|
[_appIdentifier release];
|
||||||
_appIdentifier = [anAppIdentifier copy];
|
_appIdentifier = [anAppIdentifier copy];
|
||||||
}
|
}
|
||||||
|
|
||||||
[self setSubmissionURL:@"https://rink.hockeyapp.net/"];
|
[self setSubmissionURL:@"https://rink.hockeyapp.net/"];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -238,65 +238,65 @@ NSString *BWQuincyLocalize(NSString *stringToken) {
|
|||||||
#pragma mark private methods
|
#pragma mark private methods
|
||||||
|
|
||||||
- (BOOL)autoSendCrashReports {
|
- (BOOL)autoSendCrashReports {
|
||||||
BOOL result = NO;
|
BOOL result = NO;
|
||||||
|
|
||||||
if (!self.autoSubmitCrashReport) {
|
if (!self.autoSubmitCrashReport) {
|
||||||
if (self.isShowingAlwaysButton && [[NSUserDefaults standardUserDefaults] boolForKey: kAutomaticallySendCrashReports]) {
|
if (self.isShowingAlwaysButton && [[NSUserDefaults standardUserDefaults] boolForKey: kAutomaticallySendCrashReports]) {
|
||||||
result = YES;
|
result = YES;
|
||||||
}
|
|
||||||
} else {
|
|
||||||
result = YES;
|
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
return result;
|
result = YES;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
// begin the startup process
|
// begin the startup process
|
||||||
- (void)startManager {
|
- (void)startManager {
|
||||||
if (!_sendingInProgress && [self hasPendingCrashReport]) {
|
if (!_sendingInProgress && [self hasPendingCrashReport]) {
|
||||||
_sendingInProgress = YES;
|
_sendingInProgress = YES;
|
||||||
if (!quincyBundle()) {
|
if (!quincyBundle()) {
|
||||||
NSLog(@"Quincy.bundle is missing, sending report automatically!");
|
NSLog(@"Quincy.bundle is missing, sending report automatically!");
|
||||||
[self _sendCrashReports];
|
[self _sendCrashReports];
|
||||||
} else if (!self.autoSubmitCrashReport && [self hasNonApprovedCrashReports]) {
|
} else if (!self.autoSubmitCrashReport && [self hasNonApprovedCrashReports]) {
|
||||||
|
|
||||||
if (self.delegate != nil && [self.delegate respondsToSelector:@selector(willShowSubmitCrashReportAlert)]) {
|
if (self.delegate != nil && [self.delegate respondsToSelector:@selector(willShowSubmitCrashReportAlert)]) {
|
||||||
[self.delegate willShowSubmitCrashReportAlert];
|
[self.delegate willShowSubmitCrashReportAlert];
|
||||||
}
|
}
|
||||||
|
|
||||||
NSString *appName = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleDisplayName"];
|
NSString *appName = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleDisplayName"];
|
||||||
|
|
||||||
UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:[NSString stringWithFormat:BWQuincyLocalize(@"CrashDataFoundTitle"), appName]
|
UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:[NSString stringWithFormat:BWQuincyLocalize(@"CrashDataFoundTitle"), appName]
|
||||||
message:[NSString stringWithFormat:BWQuincyLocalize(@"CrashDataFoundDescription"), appName]
|
message:[NSString stringWithFormat:BWQuincyLocalize(@"CrashDataFoundDescription"), appName]
|
||||||
delegate:self
|
delegate:self
|
||||||
cancelButtonTitle:BWQuincyLocalize(@"CrashDontSendReport")
|
cancelButtonTitle:BWQuincyLocalize(@"CrashDontSendReport")
|
||||||
otherButtonTitles:BWQuincyLocalize(@"CrashSendReport"), nil];
|
otherButtonTitles:BWQuincyLocalize(@"CrashSendReport"), nil];
|
||||||
|
|
||||||
if ([self isShowingAlwaysButton]) {
|
if ([self isShowingAlwaysButton]) {
|
||||||
[alertView addButtonWithTitle:BWQuincyLocalize(@"CrashSendReportAlways")];
|
[alertView addButtonWithTitle:BWQuincyLocalize(@"CrashSendReportAlways")];
|
||||||
}
|
}
|
||||||
|
|
||||||
[alertView setTag: QuincyKitAlertTypeSend];
|
[alertView setTag: QuincyKitAlertTypeSend];
|
||||||
[alertView show];
|
[alertView show];
|
||||||
[alertView release];
|
[alertView release];
|
||||||
} else {
|
} else {
|
||||||
[self _sendCrashReports];
|
[self _sendCrashReports];
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
- (BOOL)hasNonApprovedCrashReports {
|
- (BOOL)hasNonApprovedCrashReports {
|
||||||
NSDictionary *approvedCrashReports = [[NSUserDefaults standardUserDefaults] dictionaryForKey: kApprovedCrashReports];
|
NSDictionary *approvedCrashReports = [[NSUserDefaults standardUserDefaults] dictionaryForKey: kApprovedCrashReports];
|
||||||
|
|
||||||
if (!approvedCrashReports || [approvedCrashReports count] == 0) return YES;
|
if (!approvedCrashReports || [approvedCrashReports count] == 0) return YES;
|
||||||
|
|
||||||
for (NSUInteger i=0; i < [_crashFiles count]; i++) {
|
for (NSUInteger i=0; i < [_crashFiles count]; i++) {
|
||||||
NSString *filename = [_crashFiles objectAtIndex:i];
|
NSString *filename = [_crashFiles objectAtIndex:i];
|
||||||
|
|
||||||
if (![approvedCrashReports objectForKey:filename]) return YES;
|
|
||||||
}
|
|
||||||
|
|
||||||
return NO;
|
if (![approvedCrashReports objectForKey:filename]) return YES;
|
||||||
|
}
|
||||||
|
|
||||||
|
return NO;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (BOOL)hasPendingCrashReport {
|
- (BOOL)hasPendingCrashReport {
|
||||||
@ -305,8 +305,8 @@ NSString *BWQuincyLocalize(NSString *stringToken) {
|
|||||||
|
|
||||||
if ([_crashFiles count] == 0 && [fm fileExistsAtPath:_crashesDir]) {
|
if ([_crashFiles count] == 0 && [fm fileExistsAtPath:_crashesDir]) {
|
||||||
NSString *file = nil;
|
NSString *file = nil;
|
||||||
NSError *error = NULL;
|
NSError *error = NULL;
|
||||||
|
|
||||||
NSDirectoryEnumerator *dirEnum = [fm enumeratorAtPath: _crashesDir];
|
NSDirectoryEnumerator *dirEnum = [fm enumeratorAtPath: _crashesDir];
|
||||||
|
|
||||||
while ((file = [dirEnum nextObject])) {
|
while ((file = [dirEnum nextObject])) {
|
||||||
@ -330,31 +330,31 @@ NSString *BWQuincyLocalize(NSString *stringToken) {
|
|||||||
UIAlertView *alertView = nil;
|
UIAlertView *alertView = nil;
|
||||||
|
|
||||||
if (_serverResult >= CrashReportStatusAssigned &&
|
if (_serverResult >= CrashReportStatusAssigned &&
|
||||||
_crashIdenticalCurrentVersion &&
|
_crashIdenticalCurrentVersion &&
|
||||||
quincyBundle()) {
|
quincyBundle()) {
|
||||||
// show some feedback to the user about the crash status
|
// show some feedback to the user about the crash status
|
||||||
NSString *appName = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleDisplayName"];
|
NSString *appName = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleDisplayName"];
|
||||||
switch (_serverResult) {
|
switch (_serverResult) {
|
||||||
case CrashReportStatusAssigned:
|
case CrashReportStatusAssigned:
|
||||||
alertView = [[UIAlertView alloc] initWithTitle: [NSString stringWithFormat:BWQuincyLocalize(@"CrashResponseTitle"), appName ]
|
alertView = [[UIAlertView alloc] initWithTitle: [NSString stringWithFormat:BWQuincyLocalize(@"CrashResponseTitle"), appName ]
|
||||||
message: [NSString stringWithFormat:BWQuincyLocalize(@"CrashResponseNextRelease"), appName]
|
message: [NSString stringWithFormat:BWQuincyLocalize(@"CrashResponseNextRelease"), appName]
|
||||||
delegate: self
|
delegate: self
|
||||||
cancelButtonTitle: BWQuincyLocalize(@"CrashResponseTitleOK")
|
cancelButtonTitle: BWQuincyLocalize(@"CrashResponseTitleOK")
|
||||||
otherButtonTitles: nil];
|
otherButtonTitles: nil];
|
||||||
break;
|
break;
|
||||||
case CrashReportStatusSubmitted:
|
case CrashReportStatusSubmitted:
|
||||||
alertView = [[UIAlertView alloc] initWithTitle: [NSString stringWithFormat:BWQuincyLocalize(@"CrashResponseTitle"), appName ]
|
alertView = [[UIAlertView alloc] initWithTitle: [NSString stringWithFormat:BWQuincyLocalize(@"CrashResponseTitle"), appName ]
|
||||||
message: [NSString stringWithFormat:BWQuincyLocalize(@"CrashResponseWaitingApple"), appName]
|
message: [NSString stringWithFormat:BWQuincyLocalize(@"CrashResponseWaitingApple"), appName]
|
||||||
delegate: self
|
delegate: self
|
||||||
cancelButtonTitle: BWQuincyLocalize(@"CrashResponseTitleOK")
|
cancelButtonTitle: BWQuincyLocalize(@"CrashResponseTitleOK")
|
||||||
otherButtonTitles: nil];
|
otherButtonTitles: nil];
|
||||||
break;
|
break;
|
||||||
case CrashReportStatusAvailable:
|
case CrashReportStatusAvailable:
|
||||||
alertView = [[UIAlertView alloc] initWithTitle: [NSString stringWithFormat:BWQuincyLocalize(@"CrashResponseTitle"), appName ]
|
alertView = [[UIAlertView alloc] initWithTitle: [NSString stringWithFormat:BWQuincyLocalize(@"CrashResponseTitle"), appName ]
|
||||||
message: [NSString stringWithFormat:BWQuincyLocalize(@"CrashResponseAvailable"), appName]
|
message: [NSString stringWithFormat:BWQuincyLocalize(@"CrashResponseAvailable"), appName]
|
||||||
delegate: self
|
delegate: self
|
||||||
cancelButtonTitle: BWQuincyLocalize(@"CrashResponseTitleOK")
|
cancelButtonTitle: BWQuincyLocalize(@"CrashResponseTitleOK")
|
||||||
otherButtonTitles: nil];
|
otherButtonTitles: nil];
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
alertView = nil;
|
alertView = nil;
|
||||||
@ -377,7 +377,7 @@ NSString *BWQuincyLocalize(NSString *stringToken) {
|
|||||||
if ([alertView tag] == QuincyKitAlertTypeSend) {
|
if ([alertView tag] == QuincyKitAlertTypeSend) {
|
||||||
switch (buttonIndex) {
|
switch (buttonIndex) {
|
||||||
case 0:
|
case 0:
|
||||||
_sendingInProgress = NO;
|
_sendingInProgress = NO;
|
||||||
[self _cleanCrashReports];
|
[self _cleanCrashReports];
|
||||||
break;
|
break;
|
||||||
case 1:
|
case 1:
|
||||||
@ -404,7 +404,7 @@ NSString *BWQuincyLocalize(NSString *stringToken) {
|
|||||||
|
|
||||||
if ([elementName isEqualToString:@"result"]) {
|
if ([elementName isEqualToString:@"result"]) {
|
||||||
_contentOfProperty = [NSMutableString string];
|
_contentOfProperty = [NSMutableString string];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName {
|
- (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI qualifiedName:(NSString *)qName {
|
||||||
@ -412,12 +412,12 @@ NSString *BWQuincyLocalize(NSString *stringToken) {
|
|||||||
elementName = qName;
|
elementName = qName;
|
||||||
}
|
}
|
||||||
|
|
||||||
// open source implementation
|
// open source implementation
|
||||||
if ([elementName isEqualToString: @"result"]) {
|
if ([elementName isEqualToString: @"result"]) {
|
||||||
if ([_contentOfProperty intValue] > _serverResult) {
|
if ([_contentOfProperty intValue] > _serverResult) {
|
||||||
_serverResult = (CrashReportStatus)[_contentOfProperty intValue];
|
_serverResult = (CrashReportStatus)[_contentOfProperty intValue];
|
||||||
} else {
|
} else {
|
||||||
CrashReportStatus errorcode = (CrashReportStatus)[_contentOfProperty intValue];
|
CrashReportStatus errorcode = (CrashReportStatus)[_contentOfProperty intValue];
|
||||||
NSLog(@"CrashReporter ended in error code: %i", errorcode);
|
NSLog(@"CrashReporter ended in error code: %i", errorcode);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -458,18 +458,18 @@ NSString *BWQuincyLocalize(NSString *stringToken) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
- (void)_performSendingCrashReports {
|
- (void)_performSendingCrashReports {
|
||||||
NSMutableDictionary *approvedCrashReports = [NSMutableDictionary dictionaryWithDictionary:[[NSUserDefaults standardUserDefaults] dictionaryForKey: kApprovedCrashReports]];
|
NSMutableDictionary *approvedCrashReports = [NSMutableDictionary dictionaryWithDictionary:[[NSUserDefaults standardUserDefaults] dictionaryForKey: kApprovedCrashReports]];
|
||||||
|
|
||||||
NSFileManager *fm = [NSFileManager defaultManager];
|
NSFileManager *fm = [NSFileManager defaultManager];
|
||||||
NSError *error = NULL;
|
NSError *error = NULL;
|
||||||
|
|
||||||
NSString *userid = @"";
|
NSString *userid = @"";
|
||||||
NSString *contact = @"";
|
NSString *contact = @"";
|
||||||
NSString *description = @"";
|
NSString *description = @"";
|
||||||
|
|
||||||
if (self.autoSubmitDeviceUDID && [[NSBundle mainBundle] pathForResource:@"embedded" ofType:@"mobileprovision"]) {
|
if (self.autoSubmitDeviceUDID && [[NSBundle mainBundle] pathForResource:@"embedded" ofType:@"mobileprovision"]) {
|
||||||
userid = [self deviceIdentifier];
|
userid = [self deviceIdentifier];
|
||||||
} else if (self.delegate != nil && [self.delegate respondsToSelector:@selector(crashReportUserID)]) {
|
} else if (self.delegate != nil && [self.delegate respondsToSelector:@selector(crashReportUserID)]) {
|
||||||
userid = [self.delegate crashReportUserID] ?: @"";
|
userid = [self.delegate crashReportUserID] ?: @"";
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -481,9 +481,9 @@ NSString *BWQuincyLocalize(NSString *stringToken) {
|
|||||||
description = [self.delegate crashReportDescription] ?: @"";
|
description = [self.delegate crashReportDescription] ?: @"";
|
||||||
}
|
}
|
||||||
|
|
||||||
NSMutableString *crashes = nil;
|
NSMutableString *crashes = nil;
|
||||||
_crashIdenticalCurrentVersion = NO;
|
_crashIdenticalCurrentVersion = NO;
|
||||||
|
|
||||||
for (NSUInteger i=0; i < [_crashFiles count]; i++) {
|
for (NSUInteger i=0; i < [_crashFiles count]; i++) {
|
||||||
NSString *filename = [_crashesDir stringByAppendingPathComponent:[_crashFiles objectAtIndex:i]];
|
NSString *filename = [_crashesDir stringByAppendingPathComponent:[_crashFiles objectAtIndex:i]];
|
||||||
NSData *crashData = [NSData dataWithContentsOfFile:filename];
|
NSData *crashData = [NSData dataWithContentsOfFile:filename];
|
||||||
@ -491,87 +491,87 @@ NSString *BWQuincyLocalize(NSString *stringToken) {
|
|||||||
if ([crashData length] > 0) {
|
if ([crashData length] > 0) {
|
||||||
PLCrashReport *report = [[[PLCrashReport alloc] initWithData:crashData error:&error] autorelease];
|
PLCrashReport *report = [[[PLCrashReport alloc] initWithData:crashData error:&error] autorelease];
|
||||||
|
|
||||||
if (report == nil) {
|
if (report == nil) {
|
||||||
NSLog(@"Could not parse crash report");
|
NSLog(@"Could not parse crash report");
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
NSString *crashLogString = [PLCrashReportTextFormatter stringValueForCrashReport:report withTextFormat:PLCrashReportTextFormatiOS];
|
NSString *crashLogString = [PLCrashReportTextFormatter stringValueForCrashReport:report withTextFormat:PLCrashReportTextFormatiOS];
|
||||||
|
|
||||||
if ([report.applicationInfo.applicationVersion compare:[[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleVersion"]] == NSOrderedSame) {
|
if ([report.applicationInfo.applicationVersion compare:[[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleVersion"]] == NSOrderedSame) {
|
||||||
_crashIdenticalCurrentVersion = YES;
|
_crashIdenticalCurrentVersion = YES;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (crashes == nil) {
|
if (crashes == nil) {
|
||||||
crashes = [NSMutableString string];
|
crashes = [NSMutableString string];
|
||||||
}
|
}
|
||||||
|
|
||||||
[crashes appendFormat:@"<crash><applicationname>%s</applicationname><bundleidentifier>%@</bundleidentifier><systemversion>%@</systemversion><platform>%@</platform><senderversion>%@</senderversion><version>%@</version><log><![CDATA[%@]]></log><userid>%@</userid><contact>%@</contact><description><![CDATA[%@]]></description></crash>",
|
[crashes appendFormat:@"<crash><applicationname>%s</applicationname><bundleidentifier>%@</bundleidentifier><systemversion>%@</systemversion><platform>%@</platform><senderversion>%@</senderversion><version>%@</version><log><![CDATA[%@]]></log><userid>%@</userid><contact>%@</contact><description><![CDATA[%@]]></description></crash>",
|
||||||
[[[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleExecutable"] UTF8String],
|
[[[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleExecutable"] UTF8String],
|
||||||
report.applicationInfo.applicationIdentifier,
|
report.applicationInfo.applicationIdentifier,
|
||||||
report.systemInfo.operatingSystemVersion,
|
report.systemInfo.operatingSystemVersion,
|
||||||
[self _getDevicePlatform],
|
[self _getDevicePlatform],
|
||||||
[[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleVersion"],
|
[[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleVersion"],
|
||||||
report.applicationInfo.applicationVersion,
|
report.applicationInfo.applicationVersion,
|
||||||
[crashLogString stringByReplacingOccurrencesOfString:@"]]>" withString:@"]]" @"]]><![CDATA[" @">" options:NSLiteralSearch range:NSMakeRange(0,crashLogString.length)],
|
[crashLogString stringByReplacingOccurrencesOfString:@"]]>" withString:@"]]" @"]]><![CDATA[" @">" options:NSLiteralSearch range:NSMakeRange(0,crashLogString.length)],
|
||||||
userid,
|
userid,
|
||||||
contact,
|
contact,
|
||||||
[description stringByReplacingOccurrencesOfString:@"]]>" withString:@"]]" @"]]><![CDATA[" @">" options:NSLiteralSearch range:NSMakeRange(0,description.length)]];
|
[description stringByReplacingOccurrencesOfString:@"]]>" withString:@"]]" @"]]><![CDATA[" @">" options:NSLiteralSearch range:NSMakeRange(0,description.length)]];
|
||||||
|
|
||||||
|
|
||||||
// store this crash report as user approved, so if it fails it will retry automatically
|
// store this crash report as user approved, so if it fails it will retry automatically
|
||||||
[approvedCrashReports setObject:[NSNumber numberWithBool:YES] forKey:[_crashFiles objectAtIndex:i]];
|
[approvedCrashReports setObject:[NSNumber numberWithBool:YES] forKey:[_crashFiles objectAtIndex:i]];
|
||||||
} else {
|
} else {
|
||||||
// we cannot do anything with this report, so delete it
|
// we cannot do anything with this report, so delete it
|
||||||
[fm removeItemAtPath:filename error:&error];
|
[fm removeItemAtPath:filename error:&error];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[[NSUserDefaults standardUserDefaults] setObject:approvedCrashReports forKey:kApprovedCrashReports];
|
[[NSUserDefaults standardUserDefaults] setObject:approvedCrashReports forKey:kApprovedCrashReports];
|
||||||
[[NSUserDefaults standardUserDefaults] synchronize];
|
[[NSUserDefaults standardUserDefaults] synchronize];
|
||||||
|
|
||||||
if (crashes != nil) {
|
if (crashes != nil) {
|
||||||
[self _postXML:[NSString stringWithFormat:@"<crashes>%@</crashes>", crashes]
|
[self _postXML:[NSString stringWithFormat:@"<crashes>%@</crashes>", crashes]
|
||||||
toURL:[NSURL URLWithString:self.submissionURL]];
|
toURL:[NSURL URLWithString:self.submissionURL]];
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)_cleanCrashReports {
|
- (void)_cleanCrashReports {
|
||||||
NSError *error = NULL;
|
NSError *error = NULL;
|
||||||
|
|
||||||
NSFileManager *fm = [NSFileManager defaultManager];
|
NSFileManager *fm = [NSFileManager defaultManager];
|
||||||
|
|
||||||
for (NSUInteger i=0; i < [_crashFiles count]; i++) {
|
for (NSUInteger i=0; i < [_crashFiles count]; i++) {
|
||||||
[fm removeItemAtPath:[_crashesDir stringByAppendingPathComponent:[_crashFiles objectAtIndex:i]] error:&error];
|
[fm removeItemAtPath:[_crashesDir stringByAppendingPathComponent:[_crashFiles objectAtIndex:i]] error:&error];
|
||||||
}
|
}
|
||||||
[_crashFiles removeAllObjects];
|
[_crashFiles removeAllObjects];
|
||||||
|
|
||||||
[[NSUserDefaults standardUserDefaults] setObject:nil forKey:kApprovedCrashReports];
|
[[NSUserDefaults standardUserDefaults] setObject:nil forKey:kApprovedCrashReports];
|
||||||
[[NSUserDefaults standardUserDefaults] synchronize];
|
[[NSUserDefaults standardUserDefaults] synchronize];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)_sendCrashReports {
|
- (void)_sendCrashReports {
|
||||||
// send it to the next runloop
|
// send it to the next runloop
|
||||||
[self performSelector:@selector(_performSendingCrashReports) withObject:nil afterDelay:0.0f];
|
[self performSelector:@selector(_performSendingCrashReports) withObject:nil afterDelay:0.0f];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)_checkForFeedbackStatus {
|
- (void)_checkForFeedbackStatus {
|
||||||
NSMutableURLRequest *request = nil;
|
NSMutableURLRequest *request = nil;
|
||||||
|
|
||||||
request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:[NSString stringWithFormat:@"%@api/2/apps/%@/crashes/%@",
|
request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:[NSString stringWithFormat:@"%@api/2/apps/%@/crashes/%@",
|
||||||
self.submissionURL,
|
self.submissionURL,
|
||||||
[self.appIdentifier stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding],
|
[self.appIdentifier stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding],
|
||||||
_feedbackRequestID
|
_feedbackRequestID
|
||||||
]
|
]
|
||||||
]];
|
]];
|
||||||
|
|
||||||
[request setCachePolicy: NSURLRequestReloadIgnoringLocalCacheData];
|
[request setCachePolicy: NSURLRequestReloadIgnoringLocalCacheData];
|
||||||
[request setValue:@"Quincy/iOS" forHTTPHeaderField:@"User-Agent"];
|
[request setValue:@"Quincy/iOS" forHTTPHeaderField:@"User-Agent"];
|
||||||
[request setValue:@"gzip" forHTTPHeaderField:@"Accept-Encoding"];
|
[request setValue:@"gzip" forHTTPHeaderField:@"Accept-Encoding"];
|
||||||
[request setTimeoutInterval: 15];
|
[request setTimeoutInterval: 15];
|
||||||
[request setHTTPMethod:@"GET"];
|
[request setHTTPMethod:@"GET"];
|
||||||
|
|
||||||
_serverResult = CrashReportStatusUnknown;
|
_serverResult = CrashReportStatusUnknown;
|
||||||
_statusCode = 200;
|
_statusCode = 200;
|
||||||
|
|
||||||
@ -587,21 +587,21 @@ NSString *BWQuincyLocalize(NSString *stringToken) {
|
|||||||
|
|
||||||
- (void)_postXML:(NSString*)xml toURL:(NSURL*)url {
|
- (void)_postXML:(NSString*)xml toURL:(NSURL*)url {
|
||||||
NSMutableURLRequest *request = nil;
|
NSMutableURLRequest *request = nil;
|
||||||
NSString *boundary = @"----FOO";
|
NSString *boundary = @"----FOO";
|
||||||
|
|
||||||
if (self.appIdentifier) {
|
if (self.appIdentifier) {
|
||||||
request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:[NSString stringWithFormat:@"%@api/2/apps/%@/crashes",
|
request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:[NSString stringWithFormat:@"%@api/2/apps/%@/crashes",
|
||||||
self.submissionURL,
|
self.submissionURL,
|
||||||
[self.appIdentifier stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]
|
[self.appIdentifier stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]
|
||||||
]
|
]
|
||||||
]];
|
]];
|
||||||
} else {
|
} else {
|
||||||
request = [NSMutableURLRequest requestWithURL:url];
|
request = [NSMutableURLRequest requestWithURL:url];
|
||||||
}
|
}
|
||||||
|
|
||||||
[request setCachePolicy: NSURLRequestReloadIgnoringLocalCacheData];
|
[request setCachePolicy: NSURLRequestReloadIgnoringLocalCacheData];
|
||||||
[request setValue:@"Quincy/iOS" forHTTPHeaderField:@"User-Agent"];
|
[request setValue:@"Quincy/iOS" forHTTPHeaderField:@"User-Agent"];
|
||||||
[request setValue:@"gzip" forHTTPHeaderField:@"Accept-Encoding"];
|
[request setValue:@"gzip" forHTTPHeaderField:@"Accept-Encoding"];
|
||||||
[request setTimeoutInterval: 15];
|
[request setTimeoutInterval: 15];
|
||||||
[request setHTTPMethod:@"POST"];
|
[request setHTTPMethod:@"POST"];
|
||||||
NSString *contentType = [NSString stringWithFormat:@"multipart/form-data; boundary=%@", boundary];
|
NSString *contentType = [NSString stringWithFormat:@"multipart/form-data; boundary=%@", boundary];
|
||||||
@ -609,16 +609,16 @@ NSString *BWQuincyLocalize(NSString *stringToken) {
|
|||||||
|
|
||||||
NSMutableData *postBody = [NSMutableData data];
|
NSMutableData *postBody = [NSMutableData data];
|
||||||
[postBody appendData:[[NSString stringWithFormat:@"--%@\r\n", boundary] dataUsingEncoding:NSUTF8StringEncoding]];
|
[postBody appendData:[[NSString stringWithFormat:@"--%@\r\n", boundary] dataUsingEncoding:NSUTF8StringEncoding]];
|
||||||
if (self.appIdentifier) {
|
if (self.appIdentifier) {
|
||||||
[postBody appendData:[@"Content-Disposition: form-data; name=\"xml\"; filename=\"crash.xml\"\r\n" dataUsingEncoding:NSUTF8StringEncoding]];
|
[postBody appendData:[@"Content-Disposition: form-data; name=\"xml\"; filename=\"crash.xml\"\r\n" dataUsingEncoding:NSUTF8StringEncoding]];
|
||||||
[postBody appendData:[[NSString stringWithFormat:@"Content-Type: text/xml\r\n\r\n"] dataUsingEncoding:NSUTF8StringEncoding]];
|
[postBody appendData:[[NSString stringWithFormat:@"Content-Type: text/xml\r\n\r\n"] dataUsingEncoding:NSUTF8StringEncoding]];
|
||||||
} else {
|
} else {
|
||||||
[postBody appendData:[@"Content-Disposition: form-data; name=\"xmlstring\"\r\n\r\n" dataUsingEncoding:NSUTF8StringEncoding]];
|
[postBody appendData:[@"Content-Disposition: form-data; name=\"xmlstring\"\r\n\r\n" dataUsingEncoding:NSUTF8StringEncoding]];
|
||||||
}
|
}
|
||||||
[postBody appendData:[xml dataUsingEncoding:NSUTF8StringEncoding]];
|
[postBody appendData:[xml dataUsingEncoding:NSUTF8StringEncoding]];
|
||||||
[postBody appendData:[[NSString stringWithFormat:@"\r\n--%@--\r\n", boundary] dataUsingEncoding:NSUTF8StringEncoding]];
|
[postBody appendData:[[NSString stringWithFormat:@"\r\n--%@--\r\n", boundary] dataUsingEncoding:NSUTF8StringEncoding]];
|
||||||
|
|
||||||
[request setHTTPBody:postBody];
|
[request setHTTPBody:postBody];
|
||||||
|
|
||||||
_serverResult = CrashReportStatusUnknown;
|
_serverResult = CrashReportStatusUnknown;
|
||||||
_statusCode = 200;
|
_statusCode = 200;
|
||||||
@ -631,10 +631,10 @@ NSString *BWQuincyLocalize(NSString *stringToken) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
_urlConnection = [[NSURLConnection alloc] initWithRequest:request delegate:self];
|
_urlConnection = [[NSURLConnection alloc] initWithRequest:request delegate:self];
|
||||||
|
|
||||||
if (!_urlConnection) {
|
if (!_urlConnection) {
|
||||||
_sendingInProgress = NO;
|
_sendingInProgress = NO;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#pragma mark NSURLConnection Delegate
|
#pragma mark NSURLConnection Delegate
|
||||||
@ -652,70 +652,70 @@ NSString *BWQuincyLocalize(NSString *stringToken) {
|
|||||||
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
|
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
|
||||||
[_responseData release];
|
[_responseData release];
|
||||||
_responseData = nil;
|
_responseData = nil;
|
||||||
_urlConnection = nil;
|
_urlConnection = nil;
|
||||||
|
|
||||||
if (self.delegate != nil && [self.delegate respondsToSelector:@selector(connectionClosed)]) {
|
if (self.delegate != nil && [self.delegate respondsToSelector:@selector(connectionClosed)]) {
|
||||||
[self.delegate connectionClosed];
|
[self.delegate connectionClosed];
|
||||||
}
|
}
|
||||||
|
|
||||||
_sendingInProgress = NO;
|
_sendingInProgress = NO;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
|
- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
|
||||||
if (_statusCode >= 200 && _statusCode < 400) {
|
if (_statusCode >= 200 && _statusCode < 400) {
|
||||||
[self _cleanCrashReports];
|
[self _cleanCrashReports];
|
||||||
|
|
||||||
_feedbackRequestID = nil;
|
_feedbackRequestID = nil;
|
||||||
if (self.appIdentifier) {
|
if (self.appIdentifier) {
|
||||||
// HockeyApp uses PList XML format
|
// HockeyApp uses PList XML format
|
||||||
NSMutableDictionary *response = [NSPropertyListSerialization propertyListFromData:_responseData
|
NSMutableDictionary *response = [NSPropertyListSerialization propertyListFromData:_responseData
|
||||||
mutabilityOption:NSPropertyListMutableContainersAndLeaves
|
mutabilityOption:NSPropertyListMutableContainersAndLeaves
|
||||||
format:nil
|
format:nil
|
||||||
errorDescription:NULL];
|
errorDescription:NULL];
|
||||||
_serverResult = (CrashReportStatus)[[response objectForKey:@"status"] intValue];
|
_serverResult = (CrashReportStatus)[[response objectForKey:@"status"] intValue];
|
||||||
if ([response objectForKey:@"id"]) {
|
if ([response objectForKey:@"id"]) {
|
||||||
_feedbackRequestID = [[NSString alloc] initWithString:[response objectForKey:@"id"]];
|
_feedbackRequestID = [[NSString alloc] initWithString:[response objectForKey:@"id"]];
|
||||||
_feedbackDelayInterval = [[response objectForKey:@"delay"] floatValue];
|
_feedbackDelayInterval = [[response objectForKey:@"delay"] floatValue];
|
||||||
if (_feedbackDelayInterval > 0)
|
if (_feedbackDelayInterval > 0)
|
||||||
_feedbackDelayInterval *= 0.01;
|
_feedbackDelayInterval *= 0.01;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
NSXMLParser *parser = [[NSXMLParser alloc] initWithData:_responseData];
|
NSXMLParser *parser = [[NSXMLParser alloc] initWithData:_responseData];
|
||||||
// Set self as the delegate of the parser so that it will receive the parser delegate methods callbacks.
|
// Set self as the delegate of the parser so that it will receive the parser delegate methods callbacks.
|
||||||
[parser setDelegate:self];
|
[parser setDelegate:self];
|
||||||
// Depending on the XML document you're parsing, you may want to enable these features of NSXMLParser.
|
// Depending on the XML document you're parsing, you may want to enable these features of NSXMLParser.
|
||||||
[parser setShouldProcessNamespaces:NO];
|
[parser setShouldProcessNamespaces:NO];
|
||||||
[parser setShouldReportNamespacePrefixes:NO];
|
[parser setShouldReportNamespacePrefixes:NO];
|
||||||
[parser setShouldResolveExternalEntities:NO];
|
[parser setShouldResolveExternalEntities:NO];
|
||||||
|
|
||||||
[parser parse];
|
[parser parse];
|
||||||
|
|
||||||
[parser release];
|
[parser release];
|
||||||
}
|
}
|
||||||
|
|
||||||
if ([self isFeedbackActivated]) {
|
if ([self isFeedbackActivated]) {
|
||||||
// only proceed if the server did not report any problem
|
// only proceed if the server did not report any problem
|
||||||
if ((self.appIdentifier) && (_serverResult == CrashReportStatusQueued)) {
|
if ((self.appIdentifier) && (_serverResult == CrashReportStatusQueued)) {
|
||||||
// the report is still in the queue
|
// the report is still in the queue
|
||||||
if (_feedbackRequestID) {
|
if (_feedbackRequestID) {
|
||||||
[NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(_checkForFeedbackStatus) object:nil];
|
[NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(_checkForFeedbackStatus) object:nil];
|
||||||
[self performSelector:@selector(_checkForFeedbackStatus) withObject:nil afterDelay:_feedbackDelayInterval];
|
[self performSelector:@selector(_checkForFeedbackStatus) withObject:nil afterDelay:_feedbackDelayInterval];
|
||||||
}
|
|
||||||
} else {
|
|
||||||
[self showCrashStatusMessage];
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
[self showCrashStatusMessage];
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[_responseData release];
|
[_responseData release];
|
||||||
_responseData = nil;
|
_responseData = nil;
|
||||||
_urlConnection = nil;
|
_urlConnection = nil;
|
||||||
|
|
||||||
if (self.delegate != nil && [self.delegate respondsToSelector:@selector(connectionClosed)]) {
|
if (self.delegate != nil && [self.delegate respondsToSelector:@selector(connectionClosed)]) {
|
||||||
[self.delegate connectionClosed];
|
[self.delegate connectionClosed];
|
||||||
}
|
}
|
||||||
|
|
||||||
_sendingInProgress = NO;
|
_sendingInProgress = NO;
|
||||||
}
|
}
|
||||||
|
|
||||||
#pragma mark PLCrashReporter
|
#pragma mark PLCrashReporter
|
||||||
@ -727,22 +727,22 @@ NSString *BWQuincyLocalize(NSString *stringToken) {
|
|||||||
PLCrashReporter *crashReporter = [PLCrashReporter sharedReporter];
|
PLCrashReporter *crashReporter = [PLCrashReporter sharedReporter];
|
||||||
NSError *error = NULL;
|
NSError *error = NULL;
|
||||||
|
|
||||||
// check if the next call ran successfully the last time
|
// check if the next call ran successfully the last time
|
||||||
if (_analyzerStarted == 0) {
|
if (_analyzerStarted == 0) {
|
||||||
// mark the start of the routine
|
// mark the start of the routine
|
||||||
_analyzerStarted = 1;
|
_analyzerStarted = 1;
|
||||||
[[NSUserDefaults standardUserDefaults] setValue:[NSNumber numberWithInt:_analyzerStarted] forKey:kQuincyKitAnalyzerStarted];
|
[[NSUserDefaults standardUserDefaults] setValue:[NSNumber numberWithInt:_analyzerStarted] forKey:kQuincyKitAnalyzerStarted];
|
||||||
[[NSUserDefaults standardUserDefaults] synchronize];
|
[[NSUserDefaults standardUserDefaults] synchronize];
|
||||||
|
|
||||||
// Try loading the crash report
|
// Try loading the crash report
|
||||||
_crashData = [[NSData alloc] initWithData:[crashReporter loadPendingCrashReportDataAndReturnError: &error]];
|
_crashData = [[NSData alloc] initWithData:[crashReporter loadPendingCrashReportDataAndReturnError: &error]];
|
||||||
|
|
||||||
NSString *cacheFilename = [NSString stringWithFormat: @"%.0f", [NSDate timeIntervalSinceReferenceDate]];
|
NSString *cacheFilename = [NSString stringWithFormat: @"%.0f", [NSDate timeIntervalSinceReferenceDate]];
|
||||||
|
|
||||||
if (_crashData == nil) {
|
if (_crashData == nil) {
|
||||||
NSLog(@"Could not load crash report: %@", error);
|
NSLog(@"Could not load crash report: %@", error);
|
||||||
} else {
|
} else {
|
||||||
[_crashData writeToFile:[_crashesDir stringByAppendingPathComponent: cacheFilename] atomically:YES];
|
[_crashData writeToFile:[_crashesDir stringByAppendingPathComponent: cacheFilename] atomically:YES];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -750,8 +750,8 @@ NSString *BWQuincyLocalize(NSString *stringToken) {
|
|||||||
// mark the end of the routine
|
// mark the end of the routine
|
||||||
_analyzerStarted = 0;
|
_analyzerStarted = 0;
|
||||||
[[NSUserDefaults standardUserDefaults] setValue:[NSNumber numberWithInt:_analyzerStarted] forKey:kQuincyKitAnalyzerStarted];
|
[[NSUserDefaults standardUserDefaults] setValue:[NSNumber numberWithInt:_analyzerStarted] forKey:kQuincyKitAnalyzerStarted];
|
||||||
[[NSUserDefaults standardUserDefaults] synchronize];
|
[[NSUserDefaults standardUserDefaults] synchronize];
|
||||||
|
|
||||||
[crashReporter purgePendingCrashReport];
|
[crashReporter purgePendingCrashReport];
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -29,22 +29,22 @@
|
|||||||
@implementation NSString (HockeyAdditions)
|
@implementation NSString (HockeyAdditions)
|
||||||
|
|
||||||
- (NSString *)bw_URLEncodedString {
|
- (NSString *)bw_URLEncodedString {
|
||||||
NSString *result = (NSString *)CFURLCreateStringByAddingPercentEscapes(kCFAllocatorDefault,
|
NSString *result = (NSString *)CFURLCreateStringByAddingPercentEscapes(kCFAllocatorDefault,
|
||||||
(CFStringRef)self,
|
(CFStringRef)self,
|
||||||
NULL,
|
NULL,
|
||||||
CFSTR("!*'();:@&=+$,/?%#[]"),
|
CFSTR("!*'();:@&=+$,/?%#[]"),
|
||||||
kCFStringEncodingUTF8);
|
kCFStringEncodingUTF8);
|
||||||
[result autorelease];
|
[result autorelease];
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (NSString*)bw_URLDecodedString {
|
- (NSString*)bw_URLDecodedString {
|
||||||
NSString *result = (NSString *)CFURLCreateStringByReplacingPercentEscapesUsingEncoding(kCFAllocatorDefault,
|
NSString *result = (NSString *)CFURLCreateStringByReplacingPercentEscapesUsingEncoding(kCFAllocatorDefault,
|
||||||
(CFStringRef)self,
|
(CFStringRef)self,
|
||||||
CFSTR(""),
|
CFSTR(""),
|
||||||
kCFStringEncodingUTF8);
|
kCFStringEncodingUTF8);
|
||||||
[result autorelease];
|
[result autorelease];
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (NSComparisonResult)versionCompare:(NSString *)other
|
- (NSComparisonResult)versionCompare:(NSString *)other
|
||||||
|
@ -26,12 +26,12 @@
|
|||||||
#import <UIKit/UIKit.h>
|
#import <UIKit/UIKit.h>
|
||||||
|
|
||||||
@interface PSAppStoreHeader : UIView {
|
@interface PSAppStoreHeader : UIView {
|
||||||
NSString *headerLabel_;
|
NSString *headerLabel_;
|
||||||
NSString *middleHeaderLabel_;
|
NSString *middleHeaderLabel_;
|
||||||
NSString *subHeaderLabel;
|
NSString *subHeaderLabel;
|
||||||
UIImage *iconImage_;
|
UIImage *iconImage_;
|
||||||
|
|
||||||
UIImage *reflectedImage_;
|
UIImage *reflectedImage_;
|
||||||
}
|
}
|
||||||
|
|
||||||
@property (nonatomic, copy) NSString *headerLabel;
|
@property (nonatomic, copy) NSString *headerLabel;
|
||||||
|
@ -50,20 +50,20 @@
|
|||||||
#pragma mark NSObject
|
#pragma mark NSObject
|
||||||
|
|
||||||
- (id)initWithFrame:(CGRect)frame {
|
- (id)initWithFrame:(CGRect)frame {
|
||||||
if ((self = [super initWithFrame:frame])) {
|
if ((self = [super initWithFrame:frame])) {
|
||||||
self.autoresizingMask = UIViewAutoresizingFlexibleWidth;
|
self.autoresizingMask = UIViewAutoresizingFlexibleWidth;
|
||||||
self.backgroundColor = kLightGrayColor;
|
self.backgroundColor = kLightGrayColor;
|
||||||
}
|
}
|
||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)dealloc {
|
- (void)dealloc {
|
||||||
[headerLabel_ release];
|
[headerLabel_ release];
|
||||||
[middleHeaderLabel_ release];
|
[middleHeaderLabel_ release];
|
||||||
[subHeaderLabel release];
|
[subHeaderLabel release];
|
||||||
[iconImage_ release];
|
[iconImage_ release];
|
||||||
|
|
||||||
[super dealloc];
|
[super dealloc];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -72,56 +72,56 @@
|
|||||||
#pragma mark UIView
|
#pragma mark UIView
|
||||||
|
|
||||||
- (void)drawRect:(CGRect)rect {
|
- (void)drawRect:(CGRect)rect {
|
||||||
CGRect bounds = self.bounds;
|
CGRect bounds = self.bounds;
|
||||||
CGFloat globalWidth = self.frame.size.width;
|
CGFloat globalWidth = self.frame.size.width;
|
||||||
CGContextRef context = UIGraphicsGetCurrentContext();
|
CGContextRef context = UIGraphicsGetCurrentContext();
|
||||||
|
|
||||||
// draw the gradient
|
// draw the gradient
|
||||||
NSArray *colors = [NSArray arrayWithObjects:(id)kDarkGrayColor.CGColor, (id)kLightGrayColor.CGColor, nil];
|
NSArray *colors = [NSArray arrayWithObjects:(id)kDarkGrayColor.CGColor, (id)kLightGrayColor.CGColor, nil];
|
||||||
CGGradientRef gradient = CGGradientCreateWithColors(CGColorGetColorSpace((CGColorRef)[colors objectAtIndex:0]), (CFArrayRef)colors, (CGFloat[2]){0, 1});
|
CGGradientRef gradient = CGGradientCreateWithColors(CGColorGetColorSpace((CGColorRef)[colors objectAtIndex:0]), (CFArrayRef)colors, (CGFloat[2]){0, 1});
|
||||||
CGPoint top = CGPointMake(CGRectGetMidX(bounds), bounds.origin.y);
|
CGPoint top = CGPointMake(CGRectGetMidX(bounds), bounds.origin.y);
|
||||||
CGPoint bottom = CGPointMake(CGRectGetMidX(bounds), CGRectGetMaxY(bounds)-kReflectionHeight);
|
CGPoint bottom = CGPointMake(CGRectGetMidX(bounds), CGRectGetMaxY(bounds)-kReflectionHeight);
|
||||||
CGContextDrawLinearGradient(context, gradient, top, bottom, 0);
|
CGContextDrawLinearGradient(context, gradient, top, bottom, 0);
|
||||||
CGGradientRelease(gradient);
|
CGGradientRelease(gradient);
|
||||||
|
|
||||||
// draw header name
|
// draw header name
|
||||||
UIColor *mainTextColor = BW_RGBCOLOR(0,0,0);
|
UIColor *mainTextColor = BW_RGBCOLOR(0,0,0);
|
||||||
UIColor *secondaryTextColor = BW_RGBCOLOR(48,48,48);
|
UIColor *secondaryTextColor = BW_RGBCOLOR(48,48,48);
|
||||||
UIFont *mainFont = [UIFont boldSystemFontOfSize:20];
|
UIFont *mainFont = [UIFont boldSystemFontOfSize:20];
|
||||||
UIFont *secondaryFont = [UIFont boldSystemFontOfSize:12];
|
UIFont *secondaryFont = [UIFont boldSystemFontOfSize:12];
|
||||||
UIFont *smallFont = [UIFont systemFontOfSize:12];
|
UIFont *smallFont = [UIFont systemFontOfSize:12];
|
||||||
|
|
||||||
float myColorValues[] = {255, 255, 255, .6};
|
float myColorValues[] = {255, 255, 255, .6};
|
||||||
CGColorSpaceRef myColorSpace = CGColorSpaceCreateDeviceRGB();
|
CGColorSpaceRef myColorSpace = CGColorSpaceCreateDeviceRGB();
|
||||||
CGColorRef myColor = CGColorCreate(myColorSpace, myColorValues);
|
CGColorRef myColor = CGColorCreate(myColorSpace, myColorValues);
|
||||||
|
|
||||||
// icon
|
// icon
|
||||||
[iconImage_ drawAtPoint:CGPointMake(kImageMargin, kImageMargin)];
|
[iconImage_ drawAtPoint:CGPointMake(kImageMargin, kImageMargin)];
|
||||||
[reflectedImage_ drawAtPoint:CGPointMake(kImageMargin, kImageMargin+kImageHeight)];
|
[reflectedImage_ drawAtPoint:CGPointMake(kImageMargin, kImageMargin+kImageHeight)];
|
||||||
|
|
||||||
// shadows are a beast
|
// shadows are a beast
|
||||||
NSInteger shadowOffset = 2;
|
NSInteger shadowOffset = 2;
|
||||||
BW_IF_IOS4_OR_GREATER(if([[UIScreen mainScreen] scale] == 2) shadowOffset = 1;)
|
BW_IF_IOS4_OR_GREATER(if([[UIScreen mainScreen] scale] == 2) shadowOffset = 1;)
|
||||||
BW_IF_IOS5_OR_GREATER(shadowOffset = 1;) // iOS5 changes this - again!
|
BW_IF_IOS5_OR_GREATER(shadowOffset = 1;) // iOS5 changes this - again!
|
||||||
|
|
||||||
BW_IF_3_2_OR_GREATER(CGContextSetShadowWithColor(context, CGSizeMake(shadowOffset, shadowOffset), 0, myColor);)
|
BW_IF_3_2_OR_GREATER(CGContextSetShadowWithColor(context, CGSizeMake(shadowOffset, shadowOffset), 0, myColor);)
|
||||||
BW_IF_PRE_3_2(shadowOffset=1;CGContextSetShadowWithColor(context, CGSizeMake(shadowOffset, -shadowOffset), 0, myColor);)
|
BW_IF_PRE_3_2(shadowOffset=1;CGContextSetShadowWithColor(context, CGSizeMake(shadowOffset, -shadowOffset), 0, myColor);)
|
||||||
|
|
||||||
|
|
||||||
[mainTextColor set];
|
[mainTextColor set];
|
||||||
[headerLabel_ drawInRect:CGRectMake(kTextRow, kImageMargin, globalWidth-kTextRow, 20) withFont:mainFont lineBreakMode:UILineBreakModeTailTruncation];
|
[headerLabel_ drawInRect:CGRectMake(kTextRow, kImageMargin, globalWidth-kTextRow, 20) withFont:mainFont lineBreakMode:UILineBreakModeTailTruncation];
|
||||||
|
|
||||||
// middle
|
// middle
|
||||||
[secondaryTextColor set];
|
[secondaryTextColor set];
|
||||||
[middleHeaderLabel_ drawInRect:CGRectMake(kTextRow, kImageMargin + 25, globalWidth-kTextRow, 20) withFont:secondaryFont lineBreakMode:UILineBreakModeTailTruncation];
|
[middleHeaderLabel_ drawInRect:CGRectMake(kTextRow, kImageMargin + 25, globalWidth-kTextRow, 20) withFont:secondaryFont lineBreakMode:UILineBreakModeTailTruncation];
|
||||||
CGContextSetShadowWithColor(context, CGSizeZero, 0, nil);
|
CGContextSetShadowWithColor(context, CGSizeZero, 0, nil);
|
||||||
|
|
||||||
// sub
|
// sub
|
||||||
[secondaryTextColor set];
|
[secondaryTextColor set];
|
||||||
[subHeaderLabel drawAtPoint:CGPointMake(kTextRow, kImageMargin+kImageHeight-12) forWidth:globalWidth-kTextRow withFont:smallFont lineBreakMode:UILineBreakModeTailTruncation];
|
[subHeaderLabel drawAtPoint:CGPointMake(kTextRow, kImageMargin+kImageHeight-12) forWidth:globalWidth-kTextRow withFont:smallFont lineBreakMode:UILineBreakModeTailTruncation];
|
||||||
|
|
||||||
CGColorRelease(myColor);
|
CGColorRelease(myColor);
|
||||||
CGColorSpaceRelease(myColorSpace);
|
CGColorSpaceRelease(myColorSpace);
|
||||||
}
|
}
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
@ -129,45 +129,45 @@
|
|||||||
#pragma mark Properties
|
#pragma mark Properties
|
||||||
|
|
||||||
- (void)setHeaderLabel:(NSString *)anHeaderLabel {
|
- (void)setHeaderLabel:(NSString *)anHeaderLabel {
|
||||||
if (headerLabel_ != anHeaderLabel) {
|
if (headerLabel_ != anHeaderLabel) {
|
||||||
[headerLabel_ release];
|
[headerLabel_ release];
|
||||||
headerLabel_ = [anHeaderLabel copy];
|
headerLabel_ = [anHeaderLabel copy];
|
||||||
[self setNeedsDisplay];
|
[self setNeedsDisplay];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)setMiddleHeaderLabel:(NSString *)aMiddleHeaderLabel {
|
- (void)setMiddleHeaderLabel:(NSString *)aMiddleHeaderLabel {
|
||||||
if (middleHeaderLabel_ != aMiddleHeaderLabel) {
|
if (middleHeaderLabel_ != aMiddleHeaderLabel) {
|
||||||
[middleHeaderLabel_ release];
|
[middleHeaderLabel_ release];
|
||||||
middleHeaderLabel_ = [aMiddleHeaderLabel copy];
|
middleHeaderLabel_ = [aMiddleHeaderLabel copy];
|
||||||
[self setNeedsDisplay];
|
[self setNeedsDisplay];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)setSubHeaderLabel:(NSString *)aSubHeaderLabel {
|
- (void)setSubHeaderLabel:(NSString *)aSubHeaderLabel {
|
||||||
if (subHeaderLabel != aSubHeaderLabel) {
|
if (subHeaderLabel != aSubHeaderLabel) {
|
||||||
[subHeaderLabel release];
|
[subHeaderLabel release];
|
||||||
subHeaderLabel = [aSubHeaderLabel copy];
|
subHeaderLabel = [aSubHeaderLabel copy];
|
||||||
[self setNeedsDisplay];
|
[self setNeedsDisplay];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)setIconImage:(UIImage *)anIconImage {
|
- (void)setIconImage:(UIImage *)anIconImage {
|
||||||
if (iconImage_ != anIconImage) {
|
if (iconImage_ != anIconImage) {
|
||||||
[iconImage_ release];
|
[iconImage_ release];
|
||||||
|
|
||||||
// scale, make borders and reflection
|
// scale, make borders and reflection
|
||||||
iconImage_ = [anIconImage bw_imageToFitSize:CGSizeMake(kImageHeight, kImageHeight) honorScaleFactor:YES];
|
iconImage_ = [anIconImage bw_imageToFitSize:CGSizeMake(kImageHeight, kImageHeight) honorScaleFactor:YES];
|
||||||
iconImage_ = [[iconImage_ bw_roundedCornerImage:kImageBorderRadius borderSize:0.0] retain];
|
iconImage_ = [[iconImage_ bw_roundedCornerImage:kImageBorderRadius borderSize:0.0] retain];
|
||||||
|
|
||||||
// create reflected image
|
// create reflected image
|
||||||
[reflectedImage_ release];
|
[reflectedImage_ release];
|
||||||
reflectedImage_ = nil;
|
reflectedImage_ = nil;
|
||||||
if (anIconImage) {
|
if (anIconImage) {
|
||||||
reflectedImage_ = [[iconImage_ bw_reflectedImageWithHeight:kReflectionHeight fromAlpha:0.5 toAlpha:0.0] retain];
|
reflectedImage_ = [[iconImage_ bw_reflectedImageWithHeight:kReflectionHeight fromAlpha:0.5 toAlpha:0.0] retain];
|
||||||
}
|
|
||||||
[self setNeedsDisplay];
|
|
||||||
}
|
}
|
||||||
|
[self setNeedsDisplay];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
@ -28,10 +28,10 @@
|
|||||||
|
|
||||||
// defines a button action set (data container)
|
// defines a button action set (data container)
|
||||||
@interface PSStoreButtonData : NSObject {
|
@interface PSStoreButtonData : NSObject {
|
||||||
CGPoint customPadding_;
|
CGPoint customPadding_;
|
||||||
NSString *label_;
|
NSString *label_;
|
||||||
NSArray *colors_;
|
NSArray *colors_;
|
||||||
BOOL enabled_;
|
BOOL enabled_;
|
||||||
}
|
}
|
||||||
|
|
||||||
+ (id)dataWithLabel:(NSString*)aLabel colors:(NSArray*)aColors enabled:(BOOL)flag;
|
+ (id)dataWithLabel:(NSString*)aLabel colors:(NSArray*)aColors enabled:(BOOL)flag;
|
||||||
@ -52,11 +52,11 @@
|
|||||||
// Simulate the Paymeny-Button from the AppStore
|
// Simulate the Paymeny-Button from the AppStore
|
||||||
// The interface is flexible, so there is now fixed order
|
// The interface is flexible, so there is now fixed order
|
||||||
@interface PSStoreButton : UIButton {
|
@interface PSStoreButton : UIButton {
|
||||||
PSStoreButtonData *buttonData_;
|
PSStoreButtonData *buttonData_;
|
||||||
id<PSStoreButtonDelegate> buttonDelegate_;
|
id<PSStoreButtonDelegate> buttonDelegate_;
|
||||||
|
|
||||||
CAGradientLayer *gradient_;
|
CAGradientLayer *gradient_;
|
||||||
CGPoint customPadding_;
|
CGPoint customPadding_;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (id)initWithFrame:(CGRect)frame;
|
- (id)initWithFrame:(CGRect)frame;
|
||||||
|
@ -50,23 +50,23 @@
|
|||||||
#pragma mark NSObject
|
#pragma mark NSObject
|
||||||
|
|
||||||
- (id)initWithLabel:(NSString*)aLabel colors:(NSArray*)aColors enabled:(BOOL)flag {
|
- (id)initWithLabel:(NSString*)aLabel colors:(NSArray*)aColors enabled:(BOOL)flag {
|
||||||
if ((self = [super init])) {
|
if ((self = [super init])) {
|
||||||
self.label = aLabel;
|
self.label = aLabel;
|
||||||
self.colors = aColors;
|
self.colors = aColors;
|
||||||
self.enabled = flag;
|
self.enabled = flag;
|
||||||
}
|
}
|
||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
|
|
||||||
+ (id)dataWithLabel:(NSString*)aLabel colors:(NSArray*)aColors enabled:(BOOL)flag {
|
+ (id)dataWithLabel:(NSString*)aLabel colors:(NSArray*)aColors enabled:(BOOL)flag {
|
||||||
return [[[[self class] alloc] initWithLabel:aLabel colors:aColors enabled:flag] autorelease];
|
return [[[[self class] alloc] initWithLabel:aLabel colors:aColors enabled:flag] autorelease];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)dealloc {
|
- (void)dealloc {
|
||||||
[label_ release];
|
[label_ release];
|
||||||
[colors_ release];
|
[colors_ release];
|
||||||
|
|
||||||
[super dealloc];
|
[super dealloc];
|
||||||
}
|
}
|
||||||
@end
|
@end
|
||||||
|
|
||||||
@ -88,86 +88,86 @@
|
|||||||
#pragma mark private
|
#pragma mark private
|
||||||
|
|
||||||
- (void)touchedUpOutside:(id)sender {
|
- (void)touchedUpOutside:(id)sender {
|
||||||
PSLog(@"touched outside...");
|
PSLog(@"touched outside...");
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)buttonPressed:(id)sender {
|
- (void)buttonPressed:(id)sender {
|
||||||
PSLog(@"calling delegate:storeButtonFired for %@", sender);
|
PSLog(@"calling delegate:storeButtonFired for %@", sender);
|
||||||
[buttonDelegate_ storeButtonFired:self];
|
[buttonDelegate_ storeButtonFired:self];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)animationDidStop:(NSString *)animationID finished:(NSNumber *)finished context:(void *)context {
|
- (void)animationDidStop:(NSString *)animationID finished:(NSNumber *)finished context:(void *)context {
|
||||||
// show text again, but only if animation did finish (or else another animation is on the way)
|
// show text again, but only if animation did finish (or else another animation is on the way)
|
||||||
if ([finished boolValue]) {
|
if ([finished boolValue]) {
|
||||||
[self setTitle:self.buttonData.label forState:UIControlStateNormal];
|
[self setTitle:self.buttonData.label forState:UIControlStateNormal];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)updateButtonAnimated:(BOOL)animated {
|
- (void)updateButtonAnimated:(BOOL)animated {
|
||||||
|
if (animated) {
|
||||||
|
// hide text, then start animation
|
||||||
|
[self setTitle:@"" forState:UIControlStateNormal];
|
||||||
|
[UIView beginAnimations:@"storeButtonUpdate" context:nil];
|
||||||
|
[UIView setAnimationBeginsFromCurrentState:YES];
|
||||||
|
[UIView setAnimationDuration:kDefaultButtonAnimationTime];
|
||||||
|
[UIView setAnimationDelegate:self];
|
||||||
|
[UIView setAnimationDidStopSelector:@selector(animationDidStop:finished:context:)];
|
||||||
|
}else {
|
||||||
|
[self setTitle:self.buttonData.label forState:UIControlStateNormal];
|
||||||
|
}
|
||||||
|
|
||||||
|
self.enabled = self.buttonData.isEnabled;
|
||||||
|
gradient_.colors = self.buttonData.colors;
|
||||||
|
|
||||||
|
// show white or gray text, depending on the state
|
||||||
|
if (self.buttonData.isEnabled) {
|
||||||
|
[self setTitleShadowColor:[UIColor colorWithWhite:0.200 alpha:1.000] forState:UIControlStateNormal];
|
||||||
|
[self.titleLabel setShadowOffset:CGSizeMake(0.0, -0.6)];
|
||||||
|
[self setTitleColor:[UIColor colorWithWhite:1.0 alpha:1.000] forState:UIControlStateNormal];
|
||||||
|
}else {
|
||||||
|
[self.titleLabel setShadowOffset:CGSizeMake(0.0, 0.0)];
|
||||||
|
[self setTitleColor:PS_RGBCOLOR(148,150,151) forState:UIControlStateNormal];
|
||||||
|
}
|
||||||
|
|
||||||
|
// calculate optimal new size
|
||||||
|
CGSize sizeThatFits = [self sizeThatFits:CGSizeZero];
|
||||||
|
|
||||||
|
// move sublayer (can't be animated explcitely)
|
||||||
|
for (CALayer *aLayer in self.layer.sublayers) {
|
||||||
|
[CATransaction begin];
|
||||||
|
|
||||||
if (animated) {
|
if (animated) {
|
||||||
// hide text, then start animation
|
[CATransaction setAnimationDuration:kDefaultButtonAnimationTime];
|
||||||
[self setTitle:@"" forState:UIControlStateNormal];
|
[CATransaction setAnimationTimingFunction:[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut]];
|
||||||
[UIView beginAnimations:@"storeButtonUpdate" context:nil];
|
|
||||||
[UIView setAnimationBeginsFromCurrentState:YES];
|
|
||||||
[UIView setAnimationDuration:kDefaultButtonAnimationTime];
|
|
||||||
[UIView setAnimationDelegate:self];
|
|
||||||
[UIView setAnimationDidStopSelector:@selector(animationDidStop:finished:context:)];
|
|
||||||
}else {
|
}else {
|
||||||
[self setTitle:self.buttonData.label forState:UIControlStateNormal];
|
// frame is calculated and explicitely animated. so we absolutely need kCATransactionDisableActions
|
||||||
|
[CATransaction setValue:[NSNumber numberWithBool:YES] forKey:kCATransactionDisableActions];
|
||||||
}
|
}
|
||||||
|
|
||||||
self.enabled = self.buttonData.isEnabled;
|
CGRect newFrame = aLayer.frame;
|
||||||
gradient_.colors = self.buttonData.colors;
|
newFrame.size.width = sizeThatFits.width;
|
||||||
|
aLayer.frame = newFrame;
|
||||||
// show white or gray text, depending on the state
|
|
||||||
if (self.buttonData.isEnabled) {
|
[CATransaction commit];
|
||||||
[self setTitleShadowColor:[UIColor colorWithWhite:0.200 alpha:1.000] forState:UIControlStateNormal];
|
|
||||||
[self.titleLabel setShadowOffset:CGSizeMake(0.0, -0.6)];
|
|
||||||
[self setTitleColor:[UIColor colorWithWhite:1.0 alpha:1.000] forState:UIControlStateNormal];
|
|
||||||
}else {
|
|
||||||
[self.titleLabel setShadowOffset:CGSizeMake(0.0, 0.0)];
|
|
||||||
[self setTitleColor:PS_RGBCOLOR(148,150,151) forState:UIControlStateNormal];
|
|
||||||
}
|
|
||||||
|
|
||||||
// calculate optimal new size
|
|
||||||
CGSize sizeThatFits = [self sizeThatFits:CGSizeZero];
|
|
||||||
|
|
||||||
// move sublayer (can't be animated explcitely)
|
|
||||||
for (CALayer *aLayer in self.layer.sublayers) {
|
|
||||||
[CATransaction begin];
|
|
||||||
|
|
||||||
if (animated) {
|
|
||||||
[CATransaction setAnimationDuration:kDefaultButtonAnimationTime];
|
|
||||||
[CATransaction setAnimationTimingFunction:[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut]];
|
|
||||||
}else {
|
|
||||||
// frame is calculated and explicitely animated. so we absolutely need kCATransactionDisableActions
|
|
||||||
[CATransaction setValue:[NSNumber numberWithBool:YES] forKey:kCATransactionDisableActions];
|
|
||||||
}
|
|
||||||
|
|
||||||
CGRect newFrame = aLayer.frame;
|
|
||||||
newFrame.size.width = sizeThatFits.width;
|
|
||||||
aLayer.frame = newFrame;
|
|
||||||
|
|
||||||
[CATransaction commit];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// set outer frame changes
|
// set outer frame changes
|
||||||
self.titleEdgeInsets = UIEdgeInsetsMake(2.0, self.titleEdgeInsets.left, 0.0, 0.0);
|
self.titleEdgeInsets = UIEdgeInsetsMake(2.0, self.titleEdgeInsets.left, 0.0, 0.0);
|
||||||
[self alignToSuperview];
|
[self alignToSuperview];
|
||||||
|
|
||||||
if (animated) {
|
if (animated) {
|
||||||
[UIView commitAnimations];
|
[UIView commitAnimations];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)alignToSuperview {
|
- (void)alignToSuperview {
|
||||||
[self sizeToFit];
|
[self sizeToFit];
|
||||||
if (self.superview) {
|
if (self.superview) {
|
||||||
CGRect cr = self.frame;
|
CGRect cr = self.frame;
|
||||||
cr.origin.y = customPadding_.y;
|
cr.origin.y = customPadding_.y;
|
||||||
cr.origin.x = self.superview.frame.size.width - cr.size.width - customPadding_.x * 2;
|
cr.origin.x = self.superview.frame.size.width - cr.size.width - customPadding_.x * 2;
|
||||||
self.frame = cr;
|
self.frame = cr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
@ -175,55 +175,55 @@
|
|||||||
#pragma mark NSObject
|
#pragma mark NSObject
|
||||||
|
|
||||||
- (id)initWithFrame:(CGRect)frame {
|
- (id)initWithFrame:(CGRect)frame {
|
||||||
if ((self = [super initWithFrame:frame])) {
|
if ((self = [super initWithFrame:frame])) {
|
||||||
self.layer.needsDisplayOnBoundsChange = YES;
|
self.layer.needsDisplayOnBoundsChange = YES;
|
||||||
|
|
||||||
// setup title label
|
// setup title label
|
||||||
[self.titleLabel setFont:[UIFont boldSystemFontOfSize:13.0]];
|
[self.titleLabel setFont:[UIFont boldSystemFontOfSize:13.0]];
|
||||||
|
|
||||||
// register for touch events
|
// register for touch events
|
||||||
[self addTarget:self action:@selector(touchedUpOutside:) forControlEvents:UIControlEventTouchUpOutside];
|
[self addTarget:self action:@selector(touchedUpOutside:) forControlEvents:UIControlEventTouchUpOutside];
|
||||||
[self addTarget:self action:@selector(buttonPressed:) forControlEvents:UIControlEventTouchUpInside];
|
[self addTarget:self action:@selector(buttonPressed:) forControlEvents:UIControlEventTouchUpInside];
|
||||||
|
|
||||||
// border layers for more sex!
|
// border layers for more sex!
|
||||||
CAGradientLayer *bevelLayer = [CAGradientLayer layer];
|
CAGradientLayer *bevelLayer = [CAGradientLayer layer];
|
||||||
bevelLayer.colors = [NSArray arrayWithObjects:(id)[[UIColor colorWithWhite:0.4 alpha:1.0] CGColor], [[UIColor whiteColor] CGColor], nil];
|
bevelLayer.colors = [NSArray arrayWithObjects:(id)[[UIColor colorWithWhite:0.4 alpha:1.0] CGColor], [[UIColor whiteColor] CGColor], nil];
|
||||||
bevelLayer.frame = CGRectMake(0.0, 0.0, CGRectGetWidth(frame), CGRectGetHeight(frame));
|
bevelLayer.frame = CGRectMake(0.0, 0.0, CGRectGetWidth(frame), CGRectGetHeight(frame));
|
||||||
bevelLayer.cornerRadius = 2.5;
|
bevelLayer.cornerRadius = 2.5;
|
||||||
bevelLayer.needsDisplayOnBoundsChange = YES;
|
bevelLayer.needsDisplayOnBoundsChange = YES;
|
||||||
[self.layer addSublayer:bevelLayer];
|
[self.layer addSublayer:bevelLayer];
|
||||||
|
|
||||||
CAGradientLayer *topBorderLayer = [CAGradientLayer layer];
|
CAGradientLayer *topBorderLayer = [CAGradientLayer layer];
|
||||||
topBorderLayer.colors = [NSArray arrayWithObjects:(id)[[UIColor darkGrayColor] CGColor], [[UIColor lightGrayColor] CGColor], nil];
|
topBorderLayer.colors = [NSArray arrayWithObjects:(id)[[UIColor darkGrayColor] CGColor], [[UIColor lightGrayColor] CGColor], nil];
|
||||||
topBorderLayer.frame = CGRectMake(0.5, 0.5, CGRectGetWidth(frame) - 1.0, CGRectGetHeight(frame) - 1.0);
|
topBorderLayer.frame = CGRectMake(0.5, 0.5, CGRectGetWidth(frame) - 1.0, CGRectGetHeight(frame) - 1.0);
|
||||||
topBorderLayer.cornerRadius = 2.6;
|
topBorderLayer.cornerRadius = 2.6;
|
||||||
topBorderLayer.needsDisplayOnBoundsChange = YES;
|
topBorderLayer.needsDisplayOnBoundsChange = YES;
|
||||||
[self.layer addSublayer:topBorderLayer];
|
[self.layer addSublayer:topBorderLayer];
|
||||||
|
|
||||||
// main gradient layer
|
// main gradient layer
|
||||||
gradient_ = [[CAGradientLayer layer] retain];
|
gradient_ = [[CAGradientLayer layer] retain];
|
||||||
gradient_.locations = [NSArray arrayWithObjects:[NSNumber numberWithFloat:0.0], [NSNumber numberWithFloat:1.0], nil];//[NSNumber numberWithFloat:0.500], [NSNumber numberWithFloat:0.5001],
|
gradient_.locations = [NSArray arrayWithObjects:[NSNumber numberWithFloat:0.0], [NSNumber numberWithFloat:1.0], nil];//[NSNumber numberWithFloat:0.500], [NSNumber numberWithFloat:0.5001],
|
||||||
gradient_.frame = CGRectMake(0.75, 0.75, CGRectGetWidth(frame) - 1.5, CGRectGetHeight(frame) - 1.5);
|
gradient_.frame = CGRectMake(0.75, 0.75, CGRectGetWidth(frame) - 1.5, CGRectGetHeight(frame) - 1.5);
|
||||||
gradient_.cornerRadius = 2.5;
|
gradient_.cornerRadius = 2.5;
|
||||||
gradient_.needsDisplayOnBoundsChange = YES;
|
gradient_.needsDisplayOnBoundsChange = YES;
|
||||||
[self.layer addSublayer:gradient_];
|
[self.layer addSublayer:gradient_];
|
||||||
[self bringSubviewToFront:self.titleLabel];
|
[self bringSubviewToFront:self.titleLabel];
|
||||||
}
|
}
|
||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (id)initWithPadding:(CGPoint)padding {
|
- (id)initWithPadding:(CGPoint)padding {
|
||||||
if ((self = [self initWithFrame:CGRectMake(0, 0, 40, PS_MIN_HEIGHT)])) {
|
if ((self = [self initWithFrame:CGRectMake(0, 0, 40, PS_MIN_HEIGHT)])) {
|
||||||
customPadding_ = padding;
|
customPadding_ = padding;
|
||||||
}
|
}
|
||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)dealloc {
|
- (void)dealloc {
|
||||||
[buttonData_ release];
|
[buttonData_ release];
|
||||||
[gradient_ release];
|
[gradient_ release];
|
||||||
|
|
||||||
[super dealloc];
|
[super dealloc];
|
||||||
}
|
}
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
@ -231,25 +231,25 @@
|
|||||||
#pragma mark UIView
|
#pragma mark UIView
|
||||||
|
|
||||||
- (CGSize)sizeThatFits:(CGSize)size {
|
- (CGSize)sizeThatFits:(CGSize)size {
|
||||||
CGSize constr = (CGSize){.height = self.frame.size.height, .width = PS_MAX_WIDTH};
|
CGSize constr = (CGSize){.height = self.frame.size.height, .width = PS_MAX_WIDTH};
|
||||||
CGSize newSize = [self.buttonData.label sizeWithFont:self.titleLabel.font constrainedToSize:constr lineBreakMode:UILineBreakModeMiddleTruncation];
|
CGSize newSize = [self.buttonData.label sizeWithFont:self.titleLabel.font constrainedToSize:constr lineBreakMode:UILineBreakModeMiddleTruncation];
|
||||||
CGFloat newWidth = newSize.width + (PS_PADDING * 2);
|
CGFloat newWidth = newSize.width + (PS_PADDING * 2);
|
||||||
CGFloat newHeight = PS_MIN_HEIGHT > newSize.height ? PS_MIN_HEIGHT : newSize.height;
|
CGFloat newHeight = PS_MIN_HEIGHT > newSize.height ? PS_MIN_HEIGHT : newSize.height;
|
||||||
|
|
||||||
CGSize sizeThatFits = CGSizeMake(newWidth, newHeight);
|
CGSize sizeThatFits = CGSizeMake(newWidth, newHeight);
|
||||||
return sizeThatFits;
|
return sizeThatFits;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)setFrame:(CGRect)aRect {
|
- (void)setFrame:(CGRect)aRect {
|
||||||
[super setFrame:aRect];
|
[super setFrame:aRect];
|
||||||
|
|
||||||
// copy frame changes to sublayers (but watch out for NaN's)
|
// copy frame changes to sublayers (but watch out for NaN's)
|
||||||
for (CALayer *aLayer in self.layer.sublayers) {
|
for (CALayer *aLayer in self.layer.sublayers) {
|
||||||
CGRect rect = aLayer.frame;
|
CGRect rect = aLayer.frame;
|
||||||
rect.size.width = self.frame.size.width;
|
rect.size.width = self.frame.size.width;
|
||||||
rect.size.height = self.frame.size.height;
|
rect.size.height = self.frame.size.height;
|
||||||
aLayer.frame = rect;
|
aLayer.frame = rect;
|
||||||
[aLayer layoutIfNeeded];
|
[aLayer layoutIfNeeded];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -258,16 +258,16 @@
|
|||||||
#pragma mark Properties
|
#pragma mark Properties
|
||||||
|
|
||||||
- (void)setButtonData:(PSStoreButtonData *)aButtonData {
|
- (void)setButtonData:(PSStoreButtonData *)aButtonData {
|
||||||
[self setButtonData:aButtonData animated:NO];
|
[self setButtonData:aButtonData animated:NO];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)setButtonData:(PSStoreButtonData *)aButtonData animated:(BOOL)animated {
|
- (void)setButtonData:(PSStoreButtonData *)aButtonData animated:(BOOL)animated {
|
||||||
if (buttonData_ != aButtonData) {
|
if (buttonData_ != aButtonData) {
|
||||||
[buttonData_ release];
|
[buttonData_ release];
|
||||||
buttonData_ = [aButtonData retain];
|
buttonData_ = [aButtonData retain];
|
||||||
}
|
}
|
||||||
|
|
||||||
[self updateButtonAnimated:animated];
|
[self updateButtonAnimated:animated];
|
||||||
}
|
}
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
@ -275,21 +275,21 @@
|
|||||||
#pragma mark Static
|
#pragma mark Static
|
||||||
|
|
||||||
+ (NSArray *)appStoreGreenColor {
|
+ (NSArray *)appStoreGreenColor {
|
||||||
return [NSArray arrayWithObjects:(id)
|
return [NSArray arrayWithObjects:(id)
|
||||||
[UIColor colorWithRed:0.482 green:0.674 blue:0.406 alpha:1.000].CGColor,
|
[UIColor colorWithRed:0.482 green:0.674 blue:0.406 alpha:1.000].CGColor,
|
||||||
[UIColor colorWithRed:0.299 green:0.606 blue:0.163 alpha:1.000].CGColor, nil];
|
[UIColor colorWithRed:0.299 green:0.606 blue:0.163 alpha:1.000].CGColor, nil];
|
||||||
}
|
}
|
||||||
|
|
||||||
+ (NSArray *)appStoreBlueColor {
|
+ (NSArray *)appStoreBlueColor {
|
||||||
return [NSArray arrayWithObjects:(id)
|
return [NSArray arrayWithObjects:(id)
|
||||||
[UIColor colorWithRed:0.306 green:0.380 blue:0.547 alpha:1.000].CGColor,
|
[UIColor colorWithRed:0.306 green:0.380 blue:0.547 alpha:1.000].CGColor,
|
||||||
[UIColor colorWithRed:0.129 green:0.220 blue:0.452 alpha:1.000].CGColor, nil];
|
[UIColor colorWithRed:0.129 green:0.220 blue:0.452 alpha:1.000].CGColor, nil];
|
||||||
}
|
}
|
||||||
|
|
||||||
+ (NSArray *)appStoreGrayColor {
|
+ (NSArray *)appStoreGrayColor {
|
||||||
return [NSArray arrayWithObjects:(id)
|
return [NSArray arrayWithObjects:(id)
|
||||||
PS_RGBCOLOR(187,189,191).CGColor,
|
PS_RGBCOLOR(187,189,191).CGColor,
|
||||||
PS_RGBCOLOR(210,210,210).CGColor, nil];
|
PS_RGBCOLOR(210,210,210).CGColor, nil];
|
||||||
}
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
@ -27,11 +27,11 @@
|
|||||||
#import <UIKit/UIKit.h>
|
#import <UIKit/UIKit.h>
|
||||||
|
|
||||||
@interface PSWebTableViewCell : UITableViewCell <UIWebViewDelegate> {
|
@interface PSWebTableViewCell : UITableViewCell <UIWebViewDelegate> {
|
||||||
UIWebView *webView_;
|
UIWebView *webView_;
|
||||||
NSString *webViewContent_;
|
NSString *webViewContent_;
|
||||||
CGSize webViewSize_;
|
CGSize webViewSize_;
|
||||||
|
|
||||||
UIColor *cellBackgroundColor_;
|
UIColor *cellBackgroundColor_;
|
||||||
}
|
}
|
||||||
|
|
||||||
@property (nonatomic, retain) UIWebView *webView;
|
@property (nonatomic, retain) UIWebView *webView;
|
||||||
|
@ -53,7 +53,7 @@ body { font: 13px 'Helvetica Neue', Helvetica; word-wrap:break-word; padding:8px
|
|||||||
|
|
||||||
- (void)addWebView {
|
- (void)addWebView {
|
||||||
if(webViewContent_) {
|
if(webViewContent_) {
|
||||||
CGRect webViewRect = CGRectMake(0, 0, self.frame.size.width, self.frame.size.height);
|
CGRect webViewRect = CGRectMake(0, 0, self.frame.size.width, self.frame.size.height);
|
||||||
if(!webView_) {
|
if(!webView_) {
|
||||||
webView_ = [[[UIWebView alloc] initWithFrame:webViewRect] retain];
|
webView_ = [[[UIWebView alloc] initWithFrame:webViewRect] retain];
|
||||||
[self addSubview:webView_];
|
[self addSubview:webView_];
|
||||||
@ -61,37 +61,37 @@ body { font: 13px 'Helvetica Neue', Helvetica; word-wrap:break-word; padding:8px
|
|||||||
webView_.backgroundColor = self.cellBackgroundColor;
|
webView_.backgroundColor = self.cellBackgroundColor;
|
||||||
webView_.opaque = NO;
|
webView_.opaque = NO;
|
||||||
webView_.delegate = self;
|
webView_.delegate = self;
|
||||||
webView_.autoresizingMask = UIViewAutoresizingFlexibleWidth;
|
webView_.autoresizingMask = UIViewAutoresizingFlexibleWidth;
|
||||||
|
|
||||||
for(UIView* subView in webView_.subviews){
|
for(UIView* subView in webView_.subviews){
|
||||||
if([subView isKindOfClass:[UIScrollView class]]){
|
if([subView isKindOfClass:[UIScrollView class]]){
|
||||||
// disable scrolling
|
// disable scrolling
|
||||||
UIScrollView *sv = (UIScrollView *)subView;
|
UIScrollView *sv = (UIScrollView *)subView;
|
||||||
sv.scrollEnabled = NO;
|
sv.scrollEnabled = NO;
|
||||||
sv.bounces = NO;
|
sv.bounces = NO;
|
||||||
|
|
||||||
// hide shadow
|
// hide shadow
|
||||||
for (UIView* shadowView in [subView subviews]) {
|
for (UIView* shadowView in [subView subviews]) {
|
||||||
if ([shadowView isKindOfClass:[UIImageView class]]) {
|
if ([shadowView isKindOfClass:[UIImageView class]]) {
|
||||||
shadowView.hidden = YES;
|
shadowView.hidden = YES;
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
else
|
else
|
||||||
webView_.frame = webViewRect;
|
webView_.frame = webViewRect;
|
||||||
|
|
||||||
NSString *deviceWidth = UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad ? [NSString stringWithFormat:@"%d", CGRectGetWidth(self.bounds)] : @"device-width";
|
NSString *deviceWidth = UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad ? [NSString stringWithFormat:@"%d", CGRectGetWidth(self.bounds)] : @"device-width";
|
||||||
//BWHockeyLog(@"%@\n%@\%@", PSWebTableViewCellHtmlTemplate, deviceWidth, self.webViewContent);
|
//BWHockeyLog(@"%@\n%@\%@", PSWebTableViewCellHtmlTemplate, deviceWidth, self.webViewContent);
|
||||||
NSString *contentHtml = [NSString stringWithFormat:PSWebTableViewCellHtmlTemplate, deviceWidth, self.webViewContent];
|
NSString *contentHtml = [NSString stringWithFormat:PSWebTableViewCellHtmlTemplate, deviceWidth, self.webViewContent];
|
||||||
[webView_ loadHTMLString:contentHtml baseURL:nil];
|
[webView_ loadHTMLString:contentHtml baseURL:nil];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)showWebView {
|
- (void)showWebView {
|
||||||
webView_.hidden = NO;
|
webView_.hidden = NO;
|
||||||
self.textLabel.text = @"";
|
self.textLabel.text = @"";
|
||||||
[self setNeedsDisplay];
|
[self setNeedsDisplay];
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -109,13 +109,13 @@ body { font: 13px 'Helvetica Neue', Helvetica; word-wrap:break-word; padding:8px
|
|||||||
|
|
||||||
|
|
||||||
- (void)setWebViewContent:(NSString *)aWebViewContent {
|
- (void)setWebViewContent:(NSString *)aWebViewContent {
|
||||||
if (webViewContent_ != aWebViewContent) {
|
if (webViewContent_ != aWebViewContent) {
|
||||||
[webViewContent_ release];
|
[webViewContent_ release];
|
||||||
webViewContent_ = [aWebViewContent retain];
|
webViewContent_ = [aWebViewContent retain];
|
||||||
|
|
||||||
// add basic accessiblity (prevents "snarfed from ivar layout") logs
|
// add basic accessiblity (prevents "snarfed from ivar layout") logs
|
||||||
self.accessibilityLabel = aWebViewContent;
|
self.accessibilityLabel = aWebViewContent;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
@ -123,16 +123,16 @@ body { font: 13px 'Helvetica Neue', Helvetica; word-wrap:break-word; padding:8px
|
|||||||
#pragma mark NSObject
|
#pragma mark NSObject
|
||||||
|
|
||||||
- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier {
|
- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier {
|
||||||
if((self = [super initWithStyle:style reuseIdentifier:reuseIdentifier])) {
|
if((self = [super initWithStyle:style reuseIdentifier:reuseIdentifier])) {
|
||||||
self.cellBackgroundColor = [UIColor clearColor];
|
self.cellBackgroundColor = [UIColor clearColor];
|
||||||
}
|
}
|
||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)dealloc {
|
- (void)dealloc {
|
||||||
[self removeWebView];
|
[self removeWebView];
|
||||||
[webViewContent_ release];
|
[webViewContent_ release];
|
||||||
[super dealloc];
|
[super dealloc];
|
||||||
}
|
}
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
@ -140,12 +140,12 @@ body { font: 13px 'Helvetica Neue', Helvetica; word-wrap:break-word; padding:8px
|
|||||||
#pragma mark UIView
|
#pragma mark UIView
|
||||||
|
|
||||||
- (void)setFrame:(CGRect)aFrame {
|
- (void)setFrame:(CGRect)aFrame {
|
||||||
BOOL needChange = !CGRectEqualToRect(aFrame, self.frame);
|
BOOL needChange = !CGRectEqualToRect(aFrame, self.frame);
|
||||||
[super setFrame:aFrame];
|
[super setFrame:aFrame];
|
||||||
|
|
||||||
if (needChange) {
|
if (needChange) {
|
||||||
[self addWebView];
|
[self addWebView];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
@ -154,7 +154,7 @@ body { font: 13px 'Helvetica Neue', Helvetica; word-wrap:break-word; padding:8px
|
|||||||
|
|
||||||
- (void)prepareForReuse {
|
- (void)prepareForReuse {
|
||||||
[self removeWebView];
|
[self removeWebView];
|
||||||
self.webViewContent = nil;
|
self.webViewContent = nil;
|
||||||
[super prepareForReuse];
|
[super prepareForReuse];
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -165,25 +165,25 @@ body { font: 13px 'Helvetica Neue', Helvetica; word-wrap:break-word; padding:8px
|
|||||||
- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType {
|
- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType {
|
||||||
if(navigationType == UIWebViewNavigationTypeOther)
|
if(navigationType == UIWebViewNavigationTypeOther)
|
||||||
return YES;
|
return YES;
|
||||||
|
|
||||||
return NO;
|
return NO;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
- (void)webViewDidFinishLoad:(UIWebView *)webView {
|
- (void)webViewDidFinishLoad:(UIWebView *)webView {
|
||||||
if(webViewContent_)
|
if(webViewContent_)
|
||||||
[self showWebView];
|
[self showWebView];
|
||||||
|
|
||||||
CGRect frame = webView_.frame;
|
CGRect frame = webView_.frame;
|
||||||
frame.size.height = 1;
|
frame.size.height = 1;
|
||||||
webView_.frame = frame;
|
webView_.frame = frame;
|
||||||
CGSize fittingSize = [webView_ sizeThatFits:CGSizeZero];
|
CGSize fittingSize = [webView_ sizeThatFits:CGSizeZero];
|
||||||
frame.size = fittingSize;
|
frame.size = fittingSize;
|
||||||
webView_.frame = frame;
|
webView_.frame = frame;
|
||||||
|
|
||||||
// sizeThatFits is not reliable - use javascript for optimal height
|
// sizeThatFits is not reliable - use javascript for optimal height
|
||||||
NSString *output = [webView_ stringByEvaluatingJavaScriptFromString:@"document.body.scrollHeight;"];
|
NSString *output = [webView_ stringByEvaluatingJavaScriptFromString:@"document.body.scrollHeight;"];
|
||||||
self.webViewSize = CGSizeMake(fittingSize.width, [output integerValue]);
|
self.webViewSize = CGSizeMake(fittingSize.width, [output integerValue]);
|
||||||
}
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
@ -38,107 +38,107 @@ CGImageRef CreateGradientImage(int pixelsWide, int pixelsHigh, float fromAlpha,
|
|||||||
|
|
||||||
// Returns true if the image has an alpha layer
|
// Returns true if the image has an alpha layer
|
||||||
- (BOOL)hasAlpha {
|
- (BOOL)hasAlpha {
|
||||||
CGImageAlphaInfo alpha = CGImageGetAlphaInfo(self.CGImage);
|
CGImageAlphaInfo alpha = CGImageGetAlphaInfo(self.CGImage);
|
||||||
return (alpha == kCGImageAlphaFirst ||
|
return (alpha == kCGImageAlphaFirst ||
|
||||||
alpha == kCGImageAlphaLast ||
|
alpha == kCGImageAlphaLast ||
|
||||||
alpha == kCGImageAlphaPremultipliedFirst ||
|
alpha == kCGImageAlphaPremultipliedFirst ||
|
||||||
alpha == kCGImageAlphaPremultipliedLast);
|
alpha == kCGImageAlphaPremultipliedLast);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns a copy of the given image, adding an alpha channel if it doesn't already have one
|
// Returns a copy of the given image, adding an alpha channel if it doesn't already have one
|
||||||
- (UIImage *)imageWithAlpha {
|
- (UIImage *)imageWithAlpha {
|
||||||
if ([self hasAlpha]) {
|
if ([self hasAlpha]) {
|
||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
|
|
||||||
CGImageRef imageRef = self.CGImage;
|
CGImageRef imageRef = self.CGImage;
|
||||||
size_t width = CGImageGetWidth(imageRef) * self.scale;
|
size_t width = CGImageGetWidth(imageRef) * self.scale;
|
||||||
size_t height = CGImageGetHeight(imageRef) * self.scale;
|
size_t height = CGImageGetHeight(imageRef) * self.scale;
|
||||||
|
|
||||||
// The bitsPerComponent and bitmapInfo values are hard-coded to prevent an "unsupported parameter combination" error
|
// The bitsPerComponent and bitmapInfo values are hard-coded to prevent an "unsupported parameter combination" error
|
||||||
CGContextRef offscreenContext = CGBitmapContextCreate(NULL,
|
CGContextRef offscreenContext = CGBitmapContextCreate(NULL,
|
||||||
width,
|
width,
|
||||||
height,
|
height,
|
||||||
8,
|
8,
|
||||||
0,
|
0,
|
||||||
CGImageGetColorSpace(imageRef),
|
CGImageGetColorSpace(imageRef),
|
||||||
kCGBitmapByteOrderDefault | kCGImageAlphaPremultipliedFirst);
|
kCGBitmapByteOrderDefault | kCGImageAlphaPremultipliedFirst);
|
||||||
|
|
||||||
// Draw the image into the context and retrieve the new image, which will now have an alpha layer
|
// Draw the image into the context and retrieve the new image, which will now have an alpha layer
|
||||||
CGContextDrawImage(offscreenContext, CGRectMake(0, 0, width, height), imageRef);
|
CGContextDrawImage(offscreenContext, CGRectMake(0, 0, width, height), imageRef);
|
||||||
CGImageRef imageRefWithAlpha = CGBitmapContextCreateImage(offscreenContext);
|
CGImageRef imageRefWithAlpha = CGBitmapContextCreateImage(offscreenContext);
|
||||||
UIImage *imageWithAlpha = [UIImage imageWithCGImage:imageRefWithAlpha];
|
UIImage *imageWithAlpha = [UIImage imageWithCGImage:imageRefWithAlpha];
|
||||||
|
|
||||||
// Clean up
|
// Clean up
|
||||||
CGContextRelease(offscreenContext);
|
CGContextRelease(offscreenContext);
|
||||||
CGImageRelease(imageRefWithAlpha);
|
CGImageRelease(imageRefWithAlpha);
|
||||||
|
|
||||||
return imageWithAlpha;
|
return imageWithAlpha;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Creates a copy of this image with rounded corners
|
// Creates a copy of this image with rounded corners
|
||||||
// If borderSize is non-zero, a transparent border of the given size will also be added
|
// If borderSize is non-zero, a transparent border of the given size will also be added
|
||||||
// Original author: Björn Sållarp. Used with permission. See: http://blog.sallarp.com/iphone-uiimage-round-corners/
|
// Original author: Björn Sållarp. Used with permission. See: http://blog.sallarp.com/iphone-uiimage-round-corners/
|
||||||
- (UIImage *)bw_roundedCornerImage:(NSInteger)cornerSize borderSize:(NSInteger)borderSize {
|
- (UIImage *)bw_roundedCornerImage:(NSInteger)cornerSize borderSize:(NSInteger)borderSize {
|
||||||
// If the image does not have an alpha layer, add one
|
// If the image does not have an alpha layer, add one
|
||||||
|
|
||||||
UIImage *roundedImage = nil;
|
UIImage *roundedImage = nil;
|
||||||
#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 40000
|
#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 40000
|
||||||
BW_IF_IOS4_OR_GREATER(
|
BW_IF_IOS4_OR_GREATER(
|
||||||
UIGraphicsBeginImageContextWithOptions(self.size, NO, 0.0); // 0.0 for scale means "correct scale for device's main screen".
|
UIGraphicsBeginImageContextWithOptions(self.size, NO, 0.0); // 0.0 for scale means "correct scale for device's main screen".
|
||||||
CGImageRef sourceImg = CGImageCreateWithImageInRect([self CGImage], CGRectMake(0, 0, self.size.width * self.scale, self.size.height * self.scale)); // cropping happens here.
|
CGImageRef sourceImg = CGImageCreateWithImageInRect([self CGImage], CGRectMake(0, 0, self.size.width * self.scale, self.size.height * self.scale)); // cropping happens here.
|
||||||
|
|
||||||
// Create a clipping path with rounded corners
|
// Create a clipping path with rounded corners
|
||||||
CGContextRef context = UIGraphicsGetCurrentContext();
|
CGContextRef context = UIGraphicsGetCurrentContext();
|
||||||
CGContextBeginPath(context);
|
CGContextBeginPath(context);
|
||||||
[self addRoundedRectToPath:CGRectMake(borderSize, borderSize, self.size.width - borderSize * 2, self.size.height - borderSize * 2)
|
[self addRoundedRectToPath:CGRectMake(borderSize, borderSize, self.size.width - borderSize * 2, self.size.height - borderSize * 2)
|
||||||
context:context
|
context:context
|
||||||
ovalWidth:cornerSize
|
ovalWidth:cornerSize
|
||||||
ovalHeight:cornerSize];
|
ovalHeight:cornerSize];
|
||||||
CGContextClosePath(context);
|
CGContextClosePath(context);
|
||||||
CGContextClip(context);
|
CGContextClip(context);
|
||||||
|
|
||||||
roundedImage = [UIImage imageWithCGImage:sourceImg scale:0.0 orientation:self.imageOrientation]; // create cropped UIImage.
|
roundedImage = [UIImage imageWithCGImage:sourceImg scale:0.0 orientation:self.imageOrientation]; // create cropped UIImage.
|
||||||
[roundedImage drawInRect:CGRectMake(0, 0, self.size.width, self.size.height)]; // the actual scaling happens here, and orientation is taken care of automatically.
|
[roundedImage drawInRect:CGRectMake(0, 0, self.size.width, self.size.height)]; // the actual scaling happens here, and orientation is taken care of automatically.
|
||||||
CGImageRelease(sourceImg);
|
CGImageRelease(sourceImg);
|
||||||
roundedImage = UIGraphicsGetImageFromCurrentImageContext();
|
roundedImage = UIGraphicsGetImageFromCurrentImageContext();
|
||||||
UIGraphicsEndImageContext();
|
UIGraphicsEndImageContext();
|
||||||
)
|
)
|
||||||
#endif
|
#endif
|
||||||
if (!roundedImage) {
|
if (!roundedImage) {
|
||||||
// Try older method.
|
// Try older method.
|
||||||
UIImage *image = [self imageWithAlpha];
|
UIImage *image = [self imageWithAlpha];
|
||||||
|
|
||||||
// Build a context that's the same dimensions as the new size
|
// Build a context that's the same dimensions as the new size
|
||||||
CGContextRef context = CGBitmapContextCreate(NULL,
|
CGContextRef context = CGBitmapContextCreate(NULL,
|
||||||
image.size.width,
|
image.size.width,
|
||||||
image.size.height,
|
image.size.height,
|
||||||
CGImageGetBitsPerComponent(image.CGImage),
|
CGImageGetBitsPerComponent(image.CGImage),
|
||||||
0,
|
0,
|
||||||
CGImageGetColorSpace(image.CGImage),
|
CGImageGetColorSpace(image.CGImage),
|
||||||
CGImageGetBitmapInfo(image.CGImage));
|
CGImageGetBitmapInfo(image.CGImage));
|
||||||
|
|
||||||
// Create a clipping path with rounded corners
|
// Create a clipping path with rounded corners
|
||||||
CGContextBeginPath(context);
|
CGContextBeginPath(context);
|
||||||
[self addRoundedRectToPath:CGRectMake(borderSize, borderSize, image.size.width - borderSize * 2, image.size.height - borderSize * 2)
|
[self addRoundedRectToPath:CGRectMake(borderSize, borderSize, image.size.width - borderSize * 2, image.size.height - borderSize * 2)
|
||||||
context:context
|
context:context
|
||||||
ovalWidth:cornerSize
|
ovalWidth:cornerSize
|
||||||
ovalHeight:cornerSize];
|
ovalHeight:cornerSize];
|
||||||
CGContextClosePath(context);
|
CGContextClosePath(context);
|
||||||
CGContextClip(context);
|
CGContextClip(context);
|
||||||
|
|
||||||
// Draw the image to the context; the clipping path will make anything outside the rounded rect transparent
|
// Draw the image to the context; the clipping path will make anything outside the rounded rect transparent
|
||||||
CGContextDrawImage(context, CGRectMake(0, 0, image.size.width, image.size.height), image.CGImage);
|
CGContextDrawImage(context, CGRectMake(0, 0, image.size.width, image.size.height), image.CGImage);
|
||||||
|
|
||||||
// Create a CGImage from the context
|
// Create a CGImage from the context
|
||||||
CGImageRef clippedImage = CGBitmapContextCreateImage(context);
|
CGImageRef clippedImage = CGBitmapContextCreateImage(context);
|
||||||
CGContextRelease(context);
|
CGContextRelease(context);
|
||||||
|
|
||||||
// Create a UIImage from the CGImage
|
// Create a UIImage from the CGImage
|
||||||
roundedImage = [UIImage imageWithCGImage:clippedImage];
|
roundedImage = [UIImage imageWithCGImage:clippedImage];
|
||||||
CGImageRelease(clippedImage);
|
CGImageRelease(clippedImage);
|
||||||
}
|
}
|
||||||
return roundedImage;
|
return roundedImage;
|
||||||
}
|
}
|
||||||
|
|
||||||
#pragma mark -
|
#pragma mark -
|
||||||
@ -147,83 +147,83 @@ CGImageRef CreateGradientImage(int pixelsWide, int pixelsHigh, float fromAlpha,
|
|||||||
// Adds a rectangular path to the given context and rounds its corners by the given extents
|
// Adds a rectangular path to the given context and rounds its corners by the given extents
|
||||||
// Original author: Björn Sållarp. Used with permission. See: http://blog.sallarp.com/iphone-uiimage-round-corners/
|
// Original author: Björn Sållarp. Used with permission. See: http://blog.sallarp.com/iphone-uiimage-round-corners/
|
||||||
- (void)addRoundedRectToPath:(CGRect)rect context:(CGContextRef)context ovalWidth:(CGFloat)ovalWidth ovalHeight:(CGFloat)ovalHeight {
|
- (void)addRoundedRectToPath:(CGRect)rect context:(CGContextRef)context ovalWidth:(CGFloat)ovalWidth ovalHeight:(CGFloat)ovalHeight {
|
||||||
if (ovalWidth == 0 || ovalHeight == 0) {
|
if (ovalWidth == 0 || ovalHeight == 0) {
|
||||||
CGContextAddRect(context, rect);
|
CGContextAddRect(context, rect);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
CGContextSaveGState(context);
|
CGContextSaveGState(context);
|
||||||
CGContextTranslateCTM(context, CGRectGetMinX(rect), CGRectGetMinY(rect));
|
CGContextTranslateCTM(context, CGRectGetMinX(rect), CGRectGetMinY(rect));
|
||||||
CGContextScaleCTM(context, ovalWidth, ovalHeight);
|
CGContextScaleCTM(context, ovalWidth, ovalHeight);
|
||||||
CGFloat fw = CGRectGetWidth(rect) / ovalWidth;
|
CGFloat fw = CGRectGetWidth(rect) / ovalWidth;
|
||||||
CGFloat fh = CGRectGetHeight(rect) / ovalHeight;
|
CGFloat fh = CGRectGetHeight(rect) / ovalHeight;
|
||||||
CGContextMoveToPoint(context, fw, fh/2);
|
CGContextMoveToPoint(context, fw, fh/2);
|
||||||
CGContextAddArcToPoint(context, fw, fh, fw/2, fh, 1);
|
CGContextAddArcToPoint(context, fw, fh, fw/2, fh, 1);
|
||||||
CGContextAddArcToPoint(context, 0, fh, 0, fh/2, 1);
|
CGContextAddArcToPoint(context, 0, fh, 0, fh/2, 1);
|
||||||
CGContextAddArcToPoint(context, 0, 0, fw/2, 0, 1);
|
CGContextAddArcToPoint(context, 0, 0, fw/2, 0, 1);
|
||||||
CGContextAddArcToPoint(context, fw, 0, fw, fh/2, 1);
|
CGContextAddArcToPoint(context, fw, 0, fw, fh/2, 1);
|
||||||
CGContextClosePath(context);
|
CGContextClosePath(context);
|
||||||
CGContextRestoreGState(context);
|
CGContextRestoreGState(context);
|
||||||
}
|
}
|
||||||
|
|
||||||
- (UIImage *)bw_imageToFitSize:(CGSize)fitSize honorScaleFactor:(BOOL)honorScaleFactor
|
- (UIImage *)bw_imageToFitSize:(CGSize)fitSize honorScaleFactor:(BOOL)honorScaleFactor
|
||||||
{
|
{
|
||||||
float imageScaleFactor = 1.0;
|
float imageScaleFactor = 1.0;
|
||||||
#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 40000
|
#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 40000
|
||||||
if (honorScaleFactor) {
|
if (honorScaleFactor) {
|
||||||
if ([self respondsToSelector:@selector(scale)]) {
|
if ([self respondsToSelector:@selector(scale)]) {
|
||||||
imageScaleFactor = [self scale];
|
imageScaleFactor = [self scale];
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
float sourceWidth = [self size].width * imageScaleFactor;
|
float sourceWidth = [self size].width * imageScaleFactor;
|
||||||
float sourceHeight = [self size].height * imageScaleFactor;
|
float sourceHeight = [self size].height * imageScaleFactor;
|
||||||
float targetWidth = fitSize.width;
|
float targetWidth = fitSize.width;
|
||||||
float targetHeight = fitSize.height;
|
float targetHeight = fitSize.height;
|
||||||
|
|
||||||
// Calculate aspect ratios
|
// Calculate aspect ratios
|
||||||
float sourceRatio = sourceWidth / sourceHeight;
|
float sourceRatio = sourceWidth / sourceHeight;
|
||||||
float targetRatio = targetWidth / targetHeight;
|
float targetRatio = targetWidth / targetHeight;
|
||||||
|
|
||||||
// Determine what side of the source image to use for proportional scaling
|
// Determine what side of the source image to use for proportional scaling
|
||||||
BOOL scaleWidth = (sourceRatio <= targetRatio);
|
BOOL scaleWidth = (sourceRatio <= targetRatio);
|
||||||
// Deal with the case of just scaling proportionally to fit, without cropping
|
// Deal with the case of just scaling proportionally to fit, without cropping
|
||||||
scaleWidth = !scaleWidth;
|
scaleWidth = !scaleWidth;
|
||||||
|
|
||||||
// Proportionally scale source image
|
// Proportionally scale source image
|
||||||
float scalingFactor, scaledWidth, scaledHeight;
|
float scalingFactor, scaledWidth, scaledHeight;
|
||||||
if (scaleWidth) {
|
if (scaleWidth) {
|
||||||
scalingFactor = 1.0 / sourceRatio;
|
scalingFactor = 1.0 / sourceRatio;
|
||||||
scaledWidth = targetWidth;
|
scaledWidth = targetWidth;
|
||||||
scaledHeight = round(targetWidth * scalingFactor);
|
scaledHeight = round(targetWidth * scalingFactor);
|
||||||
} else {
|
} else {
|
||||||
scalingFactor = sourceRatio;
|
scalingFactor = sourceRatio;
|
||||||
scaledWidth = round(targetHeight * scalingFactor);
|
scaledWidth = round(targetHeight * scalingFactor);
|
||||||
scaledHeight = targetHeight;
|
scaledHeight = targetHeight;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Calculate compositing rectangles
|
// Calculate compositing rectangles
|
||||||
CGRect sourceRect, destRect;
|
CGRect sourceRect, destRect;
|
||||||
sourceRect = CGRectMake(0, 0, sourceWidth, sourceHeight);
|
sourceRect = CGRectMake(0, 0, sourceWidth, sourceHeight);
|
||||||
destRect = CGRectMake(0, 0, scaledWidth, scaledHeight);
|
destRect = CGRectMake(0, 0, scaledWidth, scaledHeight);
|
||||||
|
|
||||||
// Create appropriately modified image.
|
// Create appropriately modified image.
|
||||||
UIImage *image = nil;
|
UIImage *image = nil;
|
||||||
BW_IF_IOS4_OR_GREATER
|
BW_IF_IOS4_OR_GREATER
|
||||||
(
|
(
|
||||||
UIGraphicsBeginImageContextWithOptions(destRect.size, NO, honorScaleFactor ? 0.0 : 1.0); // 0.0 for scale means "correct scale for device's main screen".
|
UIGraphicsBeginImageContextWithOptions(destRect.size, NO, honorScaleFactor ? 0.0 : 1.0); // 0.0 for scale means "correct scale for device's main screen".
|
||||||
CGImageRef sourceImg = CGImageCreateWithImageInRect([self CGImage], sourceRect); // cropping happens here.
|
CGImageRef sourceImg = CGImageCreateWithImageInRect([self CGImage], sourceRect); // cropping happens here.
|
||||||
image = [UIImage imageWithCGImage:sourceImg scale:0.0 orientation:self.imageOrientation]; // create cropped UIImage.
|
image = [UIImage imageWithCGImage:sourceImg scale:0.0 orientation:self.imageOrientation]; // create cropped UIImage.
|
||||||
[image drawInRect:destRect]; // the actual scaling happens here, and orientation is taken care of automatically.
|
[image drawInRect:destRect]; // the actual scaling happens here, and orientation is taken care of automatically.
|
||||||
CGImageRelease(sourceImg);
|
CGImageRelease(sourceImg);
|
||||||
image = UIGraphicsGetImageFromCurrentImageContext();
|
image = UIGraphicsGetImageFromCurrentImageContext();
|
||||||
UIGraphicsEndImageContext();
|
UIGraphicsEndImageContext();
|
||||||
)
|
)
|
||||||
if (!image) {
|
if (!image) {
|
||||||
// Try older method.
|
// Try older method.
|
||||||
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
|
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
|
||||||
CGContextRef context = CGBitmapContextCreate(NULL, scaledWidth, scaledHeight, 8, (fitSize.width * 4),
|
CGContextRef context = CGBitmapContextCreate(NULL, scaledWidth, scaledHeight, 8, (fitSize.width * 4),
|
||||||
colorSpace, kCGImageAlphaPremultipliedLast);
|
colorSpace, kCGImageAlphaPremultipliedLast);
|
||||||
CGImageRef sourceImg = CGImageCreateWithImageInRect([self CGImage], sourceRect);
|
CGImageRef sourceImg = CGImageCreateWithImageInRect([self CGImage], sourceRect);
|
||||||
CGContextDrawImage(context, destRect, sourceImg);
|
CGContextDrawImage(context, destRect, sourceImg);
|
||||||
CGImageRelease(sourceImg);
|
CGImageRelease(sourceImg);
|
||||||
@ -233,105 +233,105 @@ CGImageRef CreateGradientImage(int pixelsWide, int pixelsHigh, float fromAlpha,
|
|||||||
image = [UIImage imageWithCGImage:finalImage];
|
image = [UIImage imageWithCGImage:finalImage];
|
||||||
CGImageRelease(finalImage);
|
CGImageRelease(finalImage);
|
||||||
}
|
}
|
||||||
|
|
||||||
return image;
|
return image;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
CGImageRef CreateGradientImage(int pixelsWide, int pixelsHigh, float fromAlpha, float toAlpha) {
|
CGImageRef CreateGradientImage(int pixelsWide, int pixelsHigh, float fromAlpha, float toAlpha) {
|
||||||
CGImageRef theCGImage = NULL;
|
CGImageRef theCGImage = NULL;
|
||||||
|
|
||||||
// gradient is always black-white and the mask must be in the gray colorspace
|
// gradient is always black-white and the mask must be in the gray colorspace
|
||||||
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceGray();
|
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceGray();
|
||||||
|
|
||||||
// create the bitmap context
|
// create the bitmap context
|
||||||
CGContextRef gradientBitmapContext = CGBitmapContextCreate(NULL, pixelsWide, pixelsHigh,
|
CGContextRef gradientBitmapContext = CGBitmapContextCreate(NULL, pixelsWide, pixelsHigh,
|
||||||
8, 0, colorSpace, kCGImageAlphaNone);
|
8, 0, colorSpace, kCGImageAlphaNone);
|
||||||
|
|
||||||
// define the start and end grayscale values (with the alpha, even though
|
// define the start and end grayscale values (with the alpha, even though
|
||||||
// our bitmap context doesn't support alpha the gradient requires it)
|
// our bitmap context doesn't support alpha the gradient requires it)
|
||||||
CGFloat colors[] = {toAlpha, 1.0, fromAlpha, 1.0};
|
CGFloat colors[] = {toAlpha, 1.0, fromAlpha, 1.0};
|
||||||
|
|
||||||
// create the CGGradient and then release the gray color space
|
// create the CGGradient and then release the gray color space
|
||||||
CGGradientRef grayScaleGradient = CGGradientCreateWithColorComponents(colorSpace, colors, NULL, 2);
|
CGGradientRef grayScaleGradient = CGGradientCreateWithColorComponents(colorSpace, colors, NULL, 2);
|
||||||
CGColorSpaceRelease(colorSpace);
|
CGColorSpaceRelease(colorSpace);
|
||||||
|
|
||||||
// create the start and end points for the gradient vector (straight down)
|
// create the start and end points for the gradient vector (straight down)
|
||||||
CGPoint gradientEndPoint = CGPointZero;
|
CGPoint gradientEndPoint = CGPointZero;
|
||||||
CGPoint gradientStartPoint = CGPointMake(0, pixelsHigh);
|
CGPoint gradientStartPoint = CGPointMake(0, pixelsHigh);
|
||||||
|
|
||||||
// draw the gradient into the gray bitmap context
|
// draw the gradient into the gray bitmap context
|
||||||
CGContextDrawLinearGradient(gradientBitmapContext, grayScaleGradient, gradientStartPoint,
|
CGContextDrawLinearGradient(gradientBitmapContext, grayScaleGradient, gradientStartPoint,
|
||||||
gradientEndPoint, kCGGradientDrawsAfterEndLocation);
|
gradientEndPoint, kCGGradientDrawsAfterEndLocation);
|
||||||
CGGradientRelease(grayScaleGradient);
|
CGGradientRelease(grayScaleGradient);
|
||||||
|
|
||||||
// convert the context into a CGImageRef and release the context
|
// convert the context into a CGImageRef and release the context
|
||||||
theCGImage = CGBitmapContextCreateImage(gradientBitmapContext);
|
theCGImage = CGBitmapContextCreateImage(gradientBitmapContext);
|
||||||
CGContextRelease(gradientBitmapContext);
|
CGContextRelease(gradientBitmapContext);
|
||||||
|
|
||||||
// return the imageref containing the gradient
|
// return the imageref containing the gradient
|
||||||
return theCGImage;
|
return theCGImage;
|
||||||
}
|
}
|
||||||
|
|
||||||
CGContextRef MyOpenBitmapContext(int pixelsWide, int pixelsHigh) {
|
CGContextRef MyOpenBitmapContext(int pixelsWide, int pixelsHigh) {
|
||||||
CGSize size = CGSizeMake(pixelsWide, pixelsHigh);
|
CGSize size = CGSizeMake(pixelsWide, pixelsHigh);
|
||||||
if (UIGraphicsBeginImageContextWithOptions != NULL) {
|
if (UIGraphicsBeginImageContextWithOptions != NULL) {
|
||||||
UIGraphicsBeginImageContextWithOptions(size, NO, 0.0);
|
UIGraphicsBeginImageContextWithOptions(size, NO, 0.0);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
UIGraphicsBeginImageContext(size);
|
UIGraphicsBeginImageContext(size);
|
||||||
}
|
}
|
||||||
|
|
||||||
return UIGraphicsGetCurrentContext();
|
return UIGraphicsGetCurrentContext();
|
||||||
}
|
}
|
||||||
|
|
||||||
- (UIImage *)bw_reflectedImageWithHeight:(NSUInteger)height fromAlpha:(float)fromAlpha toAlpha:(float)toAlpha {
|
- (UIImage *)bw_reflectedImageWithHeight:(NSUInteger)height fromAlpha:(float)fromAlpha toAlpha:(float)toAlpha {
|
||||||
if(height == 0)
|
if(height == 0)
|
||||||
return nil;
|
return nil;
|
||||||
|
|
||||||
// create a bitmap graphics context the size of the image
|
// create a bitmap graphics context the size of the image
|
||||||
CGContextRef mainViewContentContext = MyOpenBitmapContext(self.size.width, height);
|
CGContextRef mainViewContentContext = MyOpenBitmapContext(self.size.width, height);
|
||||||
|
|
||||||
// create a 2 bit CGImage containing a gradient that will be used for masking the
|
// create a 2 bit CGImage containing a gradient that will be used for masking the
|
||||||
// main view content to create the 'fade' of the reflection. The CGImageCreateWithMask
|
// main view content to create the 'fade' of the reflection. The CGImageCreateWithMask
|
||||||
// function will stretch the bitmap image as required, so we can create a 1 pixel wide gradient
|
// function will stretch the bitmap image as required, so we can create a 1 pixel wide gradient
|
||||||
CGImageRef gradientMaskImage = CreateGradientImage(1, height, fromAlpha, toAlpha);
|
CGImageRef gradientMaskImage = CreateGradientImage(1, height, fromAlpha, toAlpha);
|
||||||
|
|
||||||
// create an image by masking the bitmap of the mainView content with the gradient view
|
// create an image by masking the bitmap of the mainView content with the gradient view
|
||||||
// then release the pre-masked content bitmap and the gradient bitmap
|
// then release the pre-masked content bitmap and the gradient bitmap
|
||||||
CGContextClipToMask(mainViewContentContext, CGRectMake(0.0, 0.0, self.size.width, height), gradientMaskImage);
|
CGContextClipToMask(mainViewContentContext, CGRectMake(0.0, 0.0, self.size.width, height), gradientMaskImage);
|
||||||
CGImageRelease(gradientMaskImage);
|
CGImageRelease(gradientMaskImage);
|
||||||
|
|
||||||
// draw the image into the bitmap context
|
// draw the image into the bitmap context
|
||||||
CGContextDrawImage(mainViewContentContext, CGRectMake(0, 0, self.size.width, self.size.height), self.CGImage);
|
CGContextDrawImage(mainViewContentContext, CGRectMake(0, 0, self.size.width, self.size.height), self.CGImage);
|
||||||
|
|
||||||
// convert the finished reflection image to a UIImage
|
// convert the finished reflection image to a UIImage
|
||||||
UIImage *theImage = UIGraphicsGetImageFromCurrentImageContext(); // returns autoreleased
|
UIImage *theImage = UIGraphicsGetImageFromCurrentImageContext(); // returns autoreleased
|
||||||
UIGraphicsEndImageContext();
|
UIGraphicsEndImageContext();
|
||||||
|
|
||||||
return theImage;
|
return theImage;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (id)bw_initWithContentsOfResolutionIndependentFile:(NSString *)path {
|
- (id)bw_initWithContentsOfResolutionIndependentFile:(NSString *)path {
|
||||||
if ([UIScreen instancesRespondToSelector:@selector(scale)] && (int)[[UIScreen mainScreen] scale] == 2.0) {
|
if ([UIScreen instancesRespondToSelector:@selector(scale)] && (int)[[UIScreen mainScreen] scale] == 2.0) {
|
||||||
NSString *path2x = [[path stringByDeletingLastPathComponent]
|
NSString *path2x = [[path stringByDeletingLastPathComponent]
|
||||||
stringByAppendingPathComponent:[NSString stringWithFormat:@"%@@2x.%@",
|
stringByAppendingPathComponent:[NSString stringWithFormat:@"%@@2x.%@",
|
||||||
[[path lastPathComponent] stringByDeletingPathExtension],
|
[[path lastPathComponent] stringByDeletingPathExtension],
|
||||||
[path pathExtension]]];
|
[path pathExtension]]];
|
||||||
|
|
||||||
if ([[NSFileManager defaultManager] fileExistsAtPath:path2x]) {
|
|
||||||
return [self initWithContentsOfFile:path2x];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return [self initWithContentsOfFile:path];
|
if ([[NSFileManager defaultManager] fileExistsAtPath:path2x]) {
|
||||||
|
return [self initWithContentsOfFile:path2x];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return [self initWithContentsOfFile:path];
|
||||||
}
|
}
|
||||||
|
|
||||||
+ (UIImage*)bw_imageWithContentsOfResolutionIndependentFile:(NSString *)path {
|
+ (UIImage*)bw_imageWithContentsOfResolutionIndependentFile:(NSString *)path {
|
||||||
#ifndef __clang_analyzer__
|
#ifndef __clang_analyzer__
|
||||||
// clang alayzer in 4.2b3 thinks here's a leak, which is not the case.
|
// clang alayzer in 4.2b3 thinks here's a leak, which is not the case.
|
||||||
return [[[UIImage alloc] bw_initWithContentsOfResolutionIndependentFile:path] autorelease];
|
return [[[UIImage alloc] bw_initWithContentsOfResolutionIndependentFile:path] autorelease];
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user