From 1a71aa2ea5ab00f9ef310ad5981687de9e2369e9 Mon Sep 17 00:00:00 2001 From: Andreas Linde Date: Fri, 28 Sep 2012 12:30:19 +0200 Subject: [PATCH 001/176] Initial Feedback component - First implementation on feedback, not finished yet! - Move all components into their own subdirectory - Restructure common delegates into BITHockeyManagerDelegate - Restructure common component methods into new superclass (not finished yet) --- Classes/BITHockeyManager.h | 59 +- Classes/BITHockeyManager.m | 58 +- Classes/BITHockeyManagerDelegate.h | 104 ++- Classes/BITHockeyManagerPrivate.h | 37 ++ Classes/{ => CrashReports}/BITCrashManager.h | 28 +- Classes/{ => CrashReports}/BITCrashManager.m | 81 ++- .../BITCrashManagerDelegate.h | 23 - .../BITCrashManagerPrivate.h | 12 +- .../BITCrashReportTextFormatter.h | 0 .../BITCrashReportTextFormatter.m | 0 .../BITFeedbackComposeViewController.h | 37 ++ .../BITFeedbackComposeViewController.m | 202 ++++++ Classes/Feedback/BITFeedbackListViewCell.h | 48 ++ Classes/Feedback/BITFeedbackListViewCell.m | 161 +++++ .../Feedback/BITFeedbackListViewController.h | 38 ++ .../Feedback/BITFeedbackListViewController.m | 311 +++++++++ Classes/Feedback/BITFeedbackManager.h | 94 +++ Classes/Feedback/BITFeedbackManager.m | 626 ++++++++++++++++++ Classes/Feedback/BITFeedbackManagerPrivate.h | 56 ++ Classes/Feedback/BITFeedbackMessage.h | 54 ++ Classes/Feedback/BITFeedbackMessage.m | 86 +++ .../BITFeedbackUserDataViewController.h | 51 ++ .../BITFeedbackUserDataViewController.m | 255 +++++++ Classes/Helper/BITHockeyBaseManager.h | 29 + Classes/Helper/BITHockeyBaseManager.m | 192 ++++++ Classes/Helper/BITHockeyBaseManagerPrivate.h | 46 ++ Classes/Helper/BITHockeyBaseViewController.h | 17 + Classes/Helper/BITHockeyBaseViewController.m | 118 ++++ Classes/{ => Helper}/BITHockeyHelper.h | 2 + Classes/{ => Helper}/BITHockeyHelper.m | 84 +++ Classes/{ => Helper}/HockeySDKPrivate.h | 3 + Classes/{ => Helper}/HockeySDKPrivate.m | 3 +- Classes/{ => Helper}/PSAppStoreHeader.h | 0 Classes/{ => Helper}/PSAppStoreHeader.m | 0 Classes/{ => Helper}/PSStoreButton.h | 0 Classes/{ => Helper}/PSStoreButton.m | 0 Classes/{ => Helper}/PSWebTableViewCell.h | 0 Classes/{ => Helper}/PSWebTableViewCell.m | 0 Classes/HockeySDK.h | 36 + Classes/{ => Update}/BITAppVersionMetaInfo.h | 0 Classes/{ => Update}/BITAppVersionMetaInfo.m | 0 Classes/{ => Update}/BITUpdateManager.h | 0 Classes/{ => Update}/BITUpdateManager.m | 115 +--- .../{ => Update}/BITUpdateManagerDelegate.h | 0 .../{ => Update}/BITUpdateManagerPrivate.h | 2 +- .../{ => Update}/BITUpdateViewController.h | 0 .../{ => Update}/BITUpdateViewController.m | 0 .../BITUpdateViewControllerPrivate.h | 0 Resources/de.lproj/HockeySDK.strings | 86 +++ Resources/en.lproj/HockeySDK.strings | 84 +++ Resources/es.lproj/HockeySDK.strings | 84 +++ Resources/fr.lproj/HockeySDK.strings | 84 +++ Resources/it.lproj/HockeySDK.strings | 84 +++ Resources/ja.lproj/HockeySDK.strings | 84 +++ Resources/nl.lproj/HockeySDK.strings | 84 +++ Resources/pt-PT.lproj/HockeySDK.strings | 84 +++ Resources/pt.lproj/HockeySDK.strings | 84 +++ Resources/ru.lproj/HockeySDK.strings | 84 +++ Resources/sv.lproj/HockeySDK.strings | 84 +++ Resources/tr.lproj/HockeySDK.strings | 84 +++ Resources/zh_CN.lproj/HockeySDK.strings | 84 +++ Resources/zh_TW.lproj/HockeySDK.strings | 84 +++ Support/HockeySDK.xcodeproj/project.pbxproj | 602 +++++++++++------ 63 files changed, 4407 insertions(+), 441 deletions(-) create mode 100644 Classes/BITHockeyManagerPrivate.h rename Classes/{ => CrashReports}/BITCrashManager.h (93%) rename Classes/{ => CrashReports}/BITCrashManager.m (90%) rename Classes/{ => CrashReports}/BITCrashManagerDelegate.h (81%) rename Classes/{ => CrashReports}/BITCrashManagerPrivate.h (89%) rename Classes/{ => CrashReports}/BITCrashReportTextFormatter.h (100%) rename Classes/{ => CrashReports}/BITCrashReportTextFormatter.m (100%) create mode 100644 Classes/Feedback/BITFeedbackComposeViewController.h create mode 100644 Classes/Feedback/BITFeedbackComposeViewController.m create mode 100644 Classes/Feedback/BITFeedbackListViewCell.h create mode 100644 Classes/Feedback/BITFeedbackListViewCell.m create mode 100644 Classes/Feedback/BITFeedbackListViewController.h create mode 100644 Classes/Feedback/BITFeedbackListViewController.m create mode 100644 Classes/Feedback/BITFeedbackManager.h create mode 100644 Classes/Feedback/BITFeedbackManager.m create mode 100644 Classes/Feedback/BITFeedbackManagerPrivate.h create mode 100644 Classes/Feedback/BITFeedbackMessage.h create mode 100644 Classes/Feedback/BITFeedbackMessage.m create mode 100644 Classes/Feedback/BITFeedbackUserDataViewController.h create mode 100644 Classes/Feedback/BITFeedbackUserDataViewController.m create mode 100644 Classes/Helper/BITHockeyBaseManager.h create mode 100644 Classes/Helper/BITHockeyBaseManager.m create mode 100644 Classes/Helper/BITHockeyBaseManagerPrivate.h create mode 100644 Classes/Helper/BITHockeyBaseViewController.h create mode 100644 Classes/Helper/BITHockeyBaseViewController.m rename Classes/{ => Helper}/BITHockeyHelper.h (94%) rename Classes/{ => Helper}/BITHockeyHelper.m (82%) rename Classes/{ => Helper}/HockeySDKPrivate.h (96%) rename Classes/{ => Helper}/HockeySDKPrivate.m (99%) rename Classes/{ => Helper}/PSAppStoreHeader.h (100%) rename Classes/{ => Helper}/PSAppStoreHeader.m (100%) rename Classes/{ => Helper}/PSStoreButton.h (100%) rename Classes/{ => Helper}/PSStoreButton.m (100%) rename Classes/{ => Helper}/PSWebTableViewCell.h (100%) rename Classes/{ => Helper}/PSWebTableViewCell.m (100%) rename Classes/{ => Update}/BITAppVersionMetaInfo.h (100%) rename Classes/{ => Update}/BITAppVersionMetaInfo.m (100%) rename Classes/{ => Update}/BITUpdateManager.h (100%) rename Classes/{ => Update}/BITUpdateManager.m (89%) rename Classes/{ => Update}/BITUpdateManagerDelegate.h (100%) rename Classes/{ => Update}/BITUpdateManagerPrivate.h (98%) rename Classes/{ => Update}/BITUpdateViewController.h (100%) rename Classes/{ => Update}/BITUpdateViewController.m (100%) rename Classes/{ => Update}/BITUpdateViewControllerPrivate.h (100%) diff --git a/Classes/BITHockeyManager.h b/Classes/BITHockeyManager.h index 677e089a..0f26058e 100644 --- a/Classes/BITHockeyManager.h +++ b/Classes/BITHockeyManager.h @@ -34,9 +34,10 @@ @class BITCrashManager; @class BITUpdateManager; +@class BITFeedbackManager; /** - The HockeySDK manager. + The HockeySDK manager. Responsible for setup and management of all components This is the principal SDK class. It represents the entry point for the HockeySDK. The main promises of the class are initializing the SDK modules, providing access to global properties and to all modules. Initialization is divided into several distinct phases: @@ -45,7 +46,9 @@ 3. Start up all modules. Example: - [[BITHockeyManager sharedHockeyManager] configureWithIdentifier:@"" delegate:nil]; + [[BITHockeyManager sharedHockeyManager] + configureWithIdentifier:@"" + delegate:nil]; [[BITHockeyManager sharedHockeyManager] startManager]; @warning When also using the SDK for updating app versions (AdHoc or Enterprise) and collecting @@ -67,16 +70,7 @@ */ -@interface BITHockeyManager : NSObject { -@private - id _delegate; - NSString *_appIdentifier; - - BOOL _validAppIdentifier; - - BOOL _startManagerIsInvoked; -} - +@interface BITHockeyManager : NSObject #pragma mark - Public Methods @@ -99,7 +93,9 @@ implements the optional protocols `BITHockeyManagerDelegate`, `BITCrashManagerDelegate` or `BITUpdateManagerDelegate`. - [[BITHockeyManager sharedHockeyManager] configureWithIdentifier:@"" delegate:nil]; + [[BITHockeyManager sharedHockeyManager] + configureWithIdentifier:@"" + delegate:nil]; @see configureWithBetaIdentifier:liveIdentifier:delegate: @see startManager @@ -121,9 +117,10 @@ And also assign the class that implements the optional protocols `BITHockeyManagerDelegate`, `BITCrashManagerDelegate` or `BITUpdateManagerDelegate` - [[BITHockeyManager sharedHockeyManager] configureWithBetaIdentifier:@"" - liveIdentifier:@"" - delegate:nil]; + [[BITHockeyManager sharedHockeyManager] + configureWithBetaIdentifier:@"" + liveIdentifier:@"" + delegate:nil]; @see configureWithIdentifier:delegate: @see startManager @@ -161,7 +158,7 @@ By default this is set to the HockeyApp servers and there rarely should be a need to modify that. */ -@property (nonatomic, retain) NSString *updateURL; +@property (nonatomic, retain) NSString *serverURL; /** @@ -197,7 +194,7 @@ @see configureWithBetaIdentifier:liveIdentifier:delegate: @see startManager @see disableUpdateManager - @return The BITCrashManager instance initialized by BITUpdateManager + @return The BITUpdateManager instance initialized by BITHockeyManager */ @property (nonatomic, retain, readonly) BITUpdateManager *updateManager; @@ -216,6 +213,32 @@ @property (nonatomic, getter = isUpdateManagerDisabled) BOOL disableUpdateManager; +/** + Reference to the initialized BITFeedbackManager module + + @see configureWithIdentifier:delegate: + @see configureWithBetaIdentifier:liveIdentifier:delegate: + @see startManager + @see disableFeedbackManager + @return The BITFeedbackManager instance initialized by BITHockeyManager + */ +@property (nonatomic, retain, readonly) BITFeedbackManager *feedbackManager; + + +/** + Flag the determines wether the Feedback Manager should be disabled + + If this flag is enabled, then letting the user give feedback and + get responses will be turned off! + + Please note that the Feedback Manager will be initialized anyway! + + *Default*: _NO_ + @see feedbackManager + */ +@property (nonatomic, getter = isFeedbackManagerDisabled) BOOL disableFeedbackManager; + + ///----------------------------------------------------------------------------- /// @name Environment ///----------------------------------------------------------------------------- diff --git a/Classes/BITHockeyManager.m b/Classes/BITHockeyManager.m index a4f52df2..fd031bad 100644 --- a/Classes/BITHockeyManager.m +++ b/Classes/BITHockeyManager.m @@ -30,9 +30,11 @@ #import "HockeySDK.h" #import "HockeySDKPrivate.h" +#import "BITHockeyManagerPrivate.h" +#import "BITHockeyBaseManagerPrivate.h" #import "BITCrashManagerPrivate.h" #import "BITUpdateManagerPrivate.h" - +#import "BITFeedbackManagerPrivate.h" @interface BITHockeyManager () @@ -44,12 +46,14 @@ - (void)configureJMC; @end -@implementation BITHockeyManager - -@synthesize crashManager = _crashManager; -@synthesize updateManager = _updateManager; -@synthesize appStoreEnvironment = _appStoreEnvironment; +@implementation BITHockeyManager { + NSString *_appIdentifier; + + BOOL _validAppIdentifier; + + BOOL _startManagerIsInvoked; +} #pragma mark - Private Class Methods @@ -88,11 +92,12 @@ + (BITHockeyManager *)sharedHockeyManager { - (id) init { if ((self = [super init])) { - _updateURL = nil; + _serverURL = nil; _delegate = nil; _disableCrashManager = NO; _disableUpdateManager = NO; + _disableFeedbackManager = NO; _appStoreEnvironment = NO; _startManagerIsInvoked = NO; @@ -118,6 +123,7 @@ - (void)dealloc { [_crashManager release], _crashManager = nil; [_updateManager release], _updateManager = nil; + [_feedbackManager release], _feedbackManager = nil; _delegate = nil; @@ -164,8 +170,8 @@ - (void)startManager { // start CrashManager if (![self isCrashManagerDisabled]) { BITHockeyLog(@"INFO: Start CrashManager"); - if (_updateURL) { - [_crashManager setUpdateURL:_updateURL]; + if (_serverURL) { + [_crashManager setServerURL:_serverURL]; } [_crashManager startManager]; } @@ -177,11 +183,20 @@ - (void)startManager { #endif ) { BITHockeyLog(@"INFO: Start UpdateManager with small delay"); - if (_updateURL) { - [_updateManager setUpdateURL:_updateURL]; + if (_serverURL) { + [_updateManager setServerURL:_serverURL]; } [_updateManager performSelector:@selector(startManager) withObject:nil afterDelay:0.5f]; } + + // start FeedbackManager + if (![self isFeedbackManagerDisabled]) { + BITHockeyLog(@"INFO: Start FeedbackManager"); + if (_serverURL) { + [_feedbackManager setServerURL:_serverURL]; + } + [_feedbackManager performSelector:@selector(startManager) withObject:nil afterDelay:1.0f]; + } } @@ -202,15 +217,15 @@ - (void)setDisableUpdateManager:(BOOL)disableUpdateManager { } -- (void)setUpdateURL:(NSString *)anUpdateURL { +- (void)setServerURL:(NSString *)aServerURL { // ensure url ends with a trailing slash - if (![anUpdateURL hasSuffix:@"/"]) { - anUpdateURL = [NSString stringWithFormat:@"%@/", anUpdateURL]; + if (![aServerURL hasSuffix:@"/"]) { + aServerURL = [NSString stringWithFormat:@"%@/", aServerURL]; } - if (_updateURL != anUpdateURL) { - [_updateURL release]; - _updateURL = [anUpdateURL copy]; + if (_serverURL != aServerURL) { + [_serverURL release]; + _serverURL = [aServerURL copy]; } } @@ -219,8 +234,8 @@ - (void)setUpdateURL:(NSString *)anUpdateURL { - (BOOL)shouldUseLiveIdentifier { BOOL delegateResult = NO; - if ([_delegate respondsToSelector:@selector(shouldUseLiveIdentifier)]) { - delegateResult = [(NSObject *)_delegate shouldUseLiveIdentifier]; + if ([_delegate respondsToSelector:@selector(shouldUseLiveIdentifierForHockeyManager:)]) { + delegateResult = [(NSObject *)_delegate shouldUseLiveIdentifierForHockeyManager:self]; } return (delegateResult) || (_appStoreEnvironment); @@ -233,13 +248,16 @@ - (void)initializeModules { if (_validAppIdentifier) { BITHockeyLog(@"INFO: Setup CrashManager"); - _crashManager = [[BITCrashManager alloc] initWithAppIdentifier:_appIdentifier]; + _crashManager = [[BITCrashManager alloc] initWithAppIdentifier:_appIdentifier isAppStoreEnvironemt:_appStoreEnvironment]; _crashManager.delegate = _delegate; BITHockeyLog(@"INFO: Setup UpdateManager"); _updateManager = [[BITUpdateManager alloc] initWithAppIdentifier:_appIdentifier isAppStoreEnvironemt:_appStoreEnvironment]; _updateManager.delegate = _delegate; + BITHockeyLog(@"INFO: Setup FeedbackManager"); + _feedbackManager = [[BITFeedbackManager alloc] initWithAppIdentifier:_appIdentifier isAppStoreEnvironemt:_appStoreEnvironment]; + #if JIRA_MOBILE_CONNECT_SUPPORT_ENABLED // Only if JMC is part of the project if ([[self class] isJMCPresent]) { diff --git a/Classes/BITHockeyManagerDelegate.h b/Classes/BITHockeyManagerDelegate.h index e2fdb3b6..82d57219 100644 --- a/Classes/BITHockeyManagerDelegate.h +++ b/Classes/BITHockeyManagerDelegate.h @@ -29,6 +29,9 @@ #import +@class BITHockeyManager; +@class BITHockeyBaseManager; + /** The `BITHockeyManagerDelegate` formal protocol defines methods further configuring the behaviour of `BITHockeyManager`. @@ -38,6 +41,11 @@ @optional + +///----------------------------------------------------------------------------- +/// @name App Identifier usage +///----------------------------------------------------------------------------- + /** Implement to force the usage of the live identifier @@ -46,13 +54,105 @@ the App Store. Example: - - (BOOL)shouldUseLiveIdentifier { + - (BOOL)shouldUseLiveIdentifierForHockeyManager:(BITHockeyManager *)hockeyManager { #ifdef (CONFIGURATION_Release) return YES; #endif return NO; } */ -- (BOOL)shouldUseLiveIdentifier; +- (BOOL)shouldUseLiveIdentifierForHockeyManager:(BITHockeyManager *)hockeyManager; + + +///----------------------------------------------------------------------------- +/// @name UI presentation +///----------------------------------------------------------------------------- + + +// optional parent view controller for the feedback screen when invoked via the alert view, default is the root UIWindow instance +/** + Return a custom parent view controller for presenting modal sheets + + By default the SDK is using the root UIWindow instance to present any required + view controllers. Overwrite this if this doesn't result in a satisfying + behavior or if you want to define any other parent view controller. + + @param hockeyManager The `BITHockeyManager` HockeyManager instance invoking this delegate + @param componentManager The `BITHockeyBaseManager` component instance invoking this delegate + */ +- (UIViewController *)viewControllerForHockeyManager:(BITHockeyManager *)hockeyManager componentManager:(BITHockeyBaseManager *)componentManager; + + +///----------------------------------------------------------------------------- +/// @name Additional meta data +///----------------------------------------------------------------------------- + + +/** Return the userid that should used in the SDK components + + Right now this is only used by the `BITCrashMananger` to attach to a crash report. + + @param hockeyManager The `BITHockeyManager` HockeyManager instance invoking this delegate + @param componentManager The `BITHockeyBaseManager` component instance invoking this delegate + @see userNameForHockeyManager: + @see userEmailForHockeyManager: + @warning When returning a non nil value for the `BITCrashManager` component, crash reports + are not anonymous any more and the crash alerts will not show the word "anonymous"! + */ +- (NSString *)userIDForHockeyManager:(BITHockeyManager *)hockeyManager componentManager:(BITHockeyBaseManager *)componentManager; + + +/** Return the user name that should used in the SDK components + + Right now this is used by the `BITCrashMananger` to attach to a crash report. + `BITFeedbackManager` uses it too for assigning the user to a discussion thread. + + You can find out the component requesting the user name like this: + - (NSString *)userNameForHockeyManager:(BITHockeyManager *)hockeyManager componentManager:(BITHockeyBaseManager *)componentManager { + if (componentManager == hockeyManager.feedbackManager) { + return UserNameForFeedback; + } else if (componentManager == hockeyManager.crashManager) { + return UserNameForCrashReports; + } else { + return nil; + } + } + + + @param hockeyManager The `BITHockeyManager` HockeyManager instance invoking this delegate + @param componentManager The `BITHockeyBaseManager` component instance invoking this delegate + @see userIDForHockeyManager: + @see userEmailForHockeyManager: + @warning When returning a non nil value for the `BITCrashManager` component, crash reports + are not anonymous any more and the crash alerts will not show the word "anonymous"! + */ +- (NSString *)userNameForHockeyManager:(BITHockeyManager *)hockeyManager componentManager:(BITHockeyBaseManager *)componentManager; + + +/** Return the users email address that should used in the SDK components + + Right now this is used by the `BITCrashMananger` to attach to a crash report. + `BITFeedbackManager` uses it too for assigning the user to a discussion thread. + + You can find out the component requesting the user name like this: + - (NSString *)userNameForHockeyManager:(BITHockeyManager *)hockeyManager componentManager:(BITHockeyBaseManager *)componentManager { + if (componentManager == hockeyManager.feedbackManager) { + return UserNameForFeedback; + } else if (componentManager == hockeyManager.crashManager) { + return UserNameForCrashReports; + } else { + return nil; + } + } + + + @param hockeyManager The `BITHockeyManager` HockeyManager instance invoking this delegate + @param componentManager The `BITHockeyBaseManager` component instance invoking this delegate + @see userIDForHockeyManager: + @see userNameForHockeyManager: + @warning When returning a non nil value for the `BITCrashManager` component, crash reports + are not anonymous any more and the crash alerts will not show the word "anonymous"! + */ +- (NSString *)userEmailForHockeyManager:(BITHockeyManager *)hockeyManager componentManager:(BITHockeyBaseManager *)componentManager; @end diff --git a/Classes/BITHockeyManagerPrivate.h b/Classes/BITHockeyManagerPrivate.h new file mode 100644 index 00000000..92dd1566 --- /dev/null +++ b/Classes/BITHockeyManagerPrivate.h @@ -0,0 +1,37 @@ +/* + * Author: Andreas Linde + * + * Copyright (c) 2012 HockeyApp, Bit Stadium GmbH. + * All rights reserved. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#import + + +@interface BITHockeyManager () { +} + +@property (nonatomic, assign) id delegate; + +@end diff --git a/Classes/BITCrashManager.h b/Classes/CrashReports/BITCrashManager.h similarity index 93% rename from Classes/BITCrashManager.h rename to Classes/CrashReports/BITCrashManager.h index 9417bdcf..777bc711 100644 --- a/Classes/BITCrashManager.h +++ b/Classes/CrashReports/BITCrashManager.h @@ -30,6 +30,9 @@ #import +#import "BITHockeyBaseManager.h" + + // hockey crash manager status typedef enum { BITCrashManagerStatusDisabled = 0, @@ -73,30 +76,7 @@ static NSString *kBITCrashManagerStatus = @"BITCrashManagerStatus"; safe crash reporting: [Reliable Crash Reporting](http://goo.gl/WvTBR) */ -@interface BITCrashManager : NSObject { -@private - NSString *_appIdentifier; - - NSMutableDictionary *_approvedCrashReports; - - NSMutableArray *_crashFiles; - NSString *_crashesDir; - NSString *_settingsFile; - NSString *_analyzerInProgressFile; - NSFileManager *_fileManager; - - BOOL _crashIdenticalCurrentVersion; - - NSMutableData *_responseData; - NSInteger _statusCode; - - NSURLConnection *_urlConnection; - - BOOL _sendingInProgress; - BOOL _isSetup; - - NSUncaughtExceptionHandler *_exceptionHandler; -} +@interface BITCrashManager : BITHockeyBaseManager ///----------------------------------------------------------------------------- diff --git a/Classes/BITCrashManager.m b/Classes/CrashReports/BITCrashManager.m similarity index 90% rename from Classes/BITCrashManager.m rename to Classes/CrashReports/BITCrashManager.m index 3ce6d127..e16de73d 100644 --- a/Classes/BITCrashManager.m +++ b/Classes/CrashReports/BITCrashManager.m @@ -34,6 +34,8 @@ #import "HockeySDK.h" #import "HockeySDKPrivate.h" +#import "BITHockeyManagerPrivate.h" +#import "BITHockeyBaseManagerPrivate.h" #import "BITCrashManagerPrivate.h" #import "BITCrashReportTextFormatter.h" @@ -57,7 +59,27 @@ @interface BITCrashManager () @end -@implementation BITCrashManager +@implementation BITCrashManager { + NSMutableDictionary *_approvedCrashReports; + + NSMutableArray *_crashFiles; + NSString *_crashesDir; + NSString *_settingsFile; + NSString *_analyzerInProgressFile; + NSFileManager *_fileManager; + + BOOL _crashIdenticalCurrentVersion; + + NSMutableData *_responseData; + NSInteger _statusCode; + + NSURLConnection *_urlConnection; + + BOOL _sendingInProgress; + BOOL _isSetup; + + NSUncaughtExceptionHandler *_exceptionHandler; +} @synthesize delegate = _delegate; @synthesize crashManagerStatus = _crashManagerStatus; @@ -68,10 +90,9 @@ @implementation BITCrashManager @synthesize fileManager = _fileManager; -- (id)initWithAppIdentifier:(NSString *)appIdentifier { +- (id)init { if ((self = [super init])) { - _updateURL = BITHOCKEYSDK_URL; - _appIdentifier = appIdentifier; + self.serverURL = BITHOCKEYSDK_URL; _delegate = nil; _showAlwaysButton = NO; @@ -134,12 +155,6 @@ - (void) dealloc { _delegate = nil; [[NSNotificationCenter defaultCenter] removeObserver:self name:BITHockeyNetworkDidBecomeReachableNotification object:nil]; - [_updateURL release]; - _updateURL = nil; - - [_appIdentifier release]; - _appIdentifier = nil; - [_urlConnection cancel]; [_urlConnection release]; _urlConnection = nil; @@ -282,14 +297,26 @@ - (void) handleCrashReport { NSString *applicationLog = @""; NSString *errorString = nil; - if (self.delegate != nil && [self.delegate respondsToSelector:@selector(userNameForCrashManager:)]) { - username = [self.delegate userNameForCrashManager:self] ?: @""; + if ([BITHockeyManager sharedHockeyManager].delegate && + [[BITHockeyManager sharedHockeyManager].delegate respondsToSelector:@selector(userNameForHockeyManager:componentManager:)]) { + username = [[BITHockeyManager sharedHockeyManager].delegate + userNameForHockeyManager:[BITHockeyManager sharedHockeyManager] + componentManager:self]; + } + if ([BITHockeyManager sharedHockeyManager].delegate && + [[BITHockeyManager sharedHockeyManager].delegate respondsToSelector:@selector(userIDForHockeyManager:componentManager:)]) { + username = [[BITHockeyManager sharedHockeyManager].delegate + userIDForHockeyManager:[BITHockeyManager sharedHockeyManager] + componentManager:self]; } [metaDict setObject:username forKey:kBITCrashMetaUserName]; - if (self.delegate != nil && [self.delegate respondsToSelector:@selector(userEmailForCrashManager:)]) { - useremail = [self.delegate userEmailForCrashManager:self] ?: @""; - } + if ([BITHockeyManager sharedHockeyManager].delegate && + [[BITHockeyManager sharedHockeyManager].delegate respondsToSelector:@selector(userEmailForHockeyManager:componentManager:)]) { + useremail = [[BITHockeyManager sharedHockeyManager].delegate + userEmailForHockeyManager:[BITHockeyManager sharedHockeyManager] + componentManager:self]; + } [metaDict setObject:useremail forKey:kBITCrashMetaUserEmail]; if (self.delegate != nil && [self.delegate respondsToSelector:@selector(applicationLogForCrashManager:)]) { @@ -405,12 +432,24 @@ - (void)invokeDelayedProcessing { NSString *username = nil; NSString *useremail = nil; - if (self.delegate != nil && [self.delegate respondsToSelector:@selector(userNameForCrashManager:)]) { - username = [self.delegate userNameForCrashManager:self]; + if ([BITHockeyManager sharedHockeyManager].delegate && + [[BITHockeyManager sharedHockeyManager].delegate respondsToSelector:@selector(userNameForHockeyManager:componentManager:)]) { + username = [[BITHockeyManager sharedHockeyManager].delegate + userNameForHockeyManager:[BITHockeyManager sharedHockeyManager] + componentManager:self]; + } + if ([BITHockeyManager sharedHockeyManager].delegate && + [[BITHockeyManager sharedHockeyManager].delegate respondsToSelector:@selector(userIDForHockeyManager:componentManager:)]) { + username = [[BITHockeyManager sharedHockeyManager].delegate + userIDForHockeyManager:[BITHockeyManager sharedHockeyManager] + componentManager:self]; } - if (self.delegate != nil && [self.delegate respondsToSelector:@selector(userEmailForCrashManager:)]) { - useremail = [self.delegate userEmailForCrashManager:self]; + if ([BITHockeyManager sharedHockeyManager].delegate && + [[BITHockeyManager sharedHockeyManager].delegate respondsToSelector:@selector(userEmailForHockeyManager:componentManager:)]) { + useremail = [[BITHockeyManager sharedHockeyManager].delegate + userEmailForHockeyManager:[BITHockeyManager sharedHockeyManager] + componentManager:self]; } if (username || useremail) { @@ -641,8 +680,8 @@ - (void)postXML:(NSString*)xml { request = [NSMutableURLRequest requestWithURL: [NSURL URLWithString:[NSString stringWithFormat:@"%@api/2/apps/%@/crashes?sdk=%@&sdk_version=%@&feedbackEnabled=no", - _updateURL, - [_appIdentifier stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding], + self.serverURL, + [self encodedAppIdentifier], BITHOCKEY_NAME, BITHOCKEY_VERSION ] diff --git a/Classes/BITCrashManagerDelegate.h b/Classes/CrashReports/BITCrashManagerDelegate.h similarity index 81% rename from Classes/BITCrashManagerDelegate.h rename to Classes/CrashReports/BITCrashManagerDelegate.h index 724b4586..a2cada6f 100644 --- a/Classes/BITCrashManagerDelegate.h +++ b/Classes/CrashReports/BITCrashManagerDelegate.h @@ -54,29 +54,6 @@ -/** Return the user name or userid that should be send along each crash report - - @param crashManager The `BITCrashManager` instance invoking this delegate - @see applicationLogForCrashManager: - @see userEmailForCrashManager: - @warning When returning a non nil value, crash reports are not anonymous any - more and the alerts will not show the "anonymous" word! - */ --(NSString *)userNameForCrashManager:(BITCrashManager *)crashManager; - - - -/** Return the users email address that should be send along each crash report - - @param crashManager The `BITCrashManager` instance invoking this delegate - @see applicationLogForCrashManager: - @see userNameForCrashManager: - @warning When returning a non nil value, crash reports are not anonymous any - more and the alerts will not show the "anonymous" word! - */ --(NSString *)userEmailForCrashManager:(BITCrashManager *)crashManager; - - ///----------------------------------------------------------------------------- /// @name Alert ///----------------------------------------------------------------------------- diff --git a/Classes/BITCrashManagerPrivate.h b/Classes/CrashReports/BITCrashManagerPrivate.h similarity index 89% rename from Classes/BITCrashManagerPrivate.h rename to Classes/CrashReports/BITCrashManagerPrivate.h index 684c03dd..b3960c4f 100644 --- a/Classes/BITCrashManagerPrivate.h +++ b/Classes/CrashReports/BITCrashManagerPrivate.h @@ -34,11 +34,11 @@ @interface BITCrashManager () { } -// set the server URL -@property (nonatomic, retain) NSString *updateURL; - -- (id)initWithAppIdentifier:(NSString *)appIdentifier; - -- (void)startManager; +//// set the server URL +//@property (nonatomic, retain) NSString *serverURL; +// +//- (id)initWithAppIdentifier:(NSString *)appIdentifier; +// +//- (void)startManager; @end diff --git a/Classes/BITCrashReportTextFormatter.h b/Classes/CrashReports/BITCrashReportTextFormatter.h similarity index 100% rename from Classes/BITCrashReportTextFormatter.h rename to Classes/CrashReports/BITCrashReportTextFormatter.h diff --git a/Classes/BITCrashReportTextFormatter.m b/Classes/CrashReports/BITCrashReportTextFormatter.m similarity index 100% rename from Classes/BITCrashReportTextFormatter.m rename to Classes/CrashReports/BITCrashReportTextFormatter.m diff --git a/Classes/Feedback/BITFeedbackComposeViewController.h b/Classes/Feedback/BITFeedbackComposeViewController.h new file mode 100644 index 00000000..c8264d36 --- /dev/null +++ b/Classes/Feedback/BITFeedbackComposeViewController.h @@ -0,0 +1,37 @@ +/* + * Author: Andreas Linde + * + * Copyright (c) 2012 HockeyApp, Bit Stadium GmbH. + * All rights reserved. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + + +#import +#import "BITHockeyBaseViewController.h" + +@interface BITFeedbackComposeViewController : BITHockeyBaseViewController + +- (id)init; + +@end \ No newline at end of file diff --git a/Classes/Feedback/BITFeedbackComposeViewController.m b/Classes/Feedback/BITFeedbackComposeViewController.m new file mode 100644 index 00000000..e5f78202 --- /dev/null +++ b/Classes/Feedback/BITFeedbackComposeViewController.m @@ -0,0 +1,202 @@ +/* + * Author: Andreas Linde + * + * Copyright (c) 2012 HockeyApp, Bit Stadium GmbH. + * All rights reserved. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + + +#import "HockeySDK.h" +#import "HockeySDKPrivate.h" + +#import "BITFeedbackManagerPrivate.h" +#import "BITFeedbackComposeViewController.h" +#import "BITFeedbackUserDataViewController.h" + +#import "BITHockeyHelper.h" + + +@interface BITFeedbackComposeViewController () { + BOOL blockUserDataScreen; +} + +@property (nonatomic, assign) BITFeedbackManager *manager; +@property (nonatomic, retain) UITextView *textView; + +- (void)setUserDataAction; + +@end + + + +@implementation BITFeedbackComposeViewController + +- (id)init { + self = [super init]; + if (self) { + self.title = BITHockeyLocalizedString(@"HockeyFeedbackComposeTitle"); + blockUserDataScreen = NO; + _manager = [BITHockeyManager sharedHockeyManager].feedbackManager; + } + return self; +} + +- (void)viewDidLoad { + [super viewDidLoad]; + + self.view.backgroundColor = [UIColor whiteColor]; + + // Do any additional setup after loading the view. + self.navigationItem.leftBarButtonItem = [[[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemCancel + target:self + action:@selector(dismissAction:)] autorelease]; + + self.navigationItem.rightBarButtonItem = [[[UIBarButtonItem alloc] initWithTitle:BITHockeyLocalizedString(@"HockeyFeedbackComposeSend") + style:UIBarButtonItemStyleDone + target:self + action:@selector(sendAction:)] autorelease]; + + // message input textfield + CGRect frame = CGRectZero; + + if (UI_USER_INTERFACE_IDIOM() != UIUserInterfaceIdiomPad) { + frame = CGRectMake(0, 0, self.view.bounds.size.width, 200); + } else { + frame = CGRectMake(0, 0, self.view.bounds.size.width, self.view.bounds.size.height); + } + self.textView = [[[UITextView alloc] initWithFrame:frame] autorelease]; + self.textView.font = [UIFont systemFontOfSize:17]; + self.textView.delegate = self; + self.textView.backgroundColor = [UIColor whiteColor]; + self.textView.returnKeyType = UIReturnKeyDefault; + self.textView.autoresizingMask = UIViewAutoresizingFlexibleWidth; + [self.view addSubview:self.textView]; +} + +- (void)viewDidUnload { + [super viewDidUnload]; + // Release any retained subviews of the main view. +} + +- (void)viewWillAppear:(BOOL)animated { + self.manager.currentFeedbackComposeViewController = self; + + [super viewWillAppear:animated]; + + self.navigationItem.rightBarButtonItem.enabled = NO; +} + +- (void)viewDidAppear:(BOOL)animated { + [super viewDidAppear:animated]; + + if ([self.manager askManualUserDataAvailable] && + ([self.manager requireManualUserDataMissing] || + ![self.manager didAskUserData]) + ) { + if (!blockUserDataScreen) + [self setUserDataAction]; + } else { + [self.textView becomeFirstResponder]; + } +} + +- (void)viewWillDisappear:(BOOL)animated { + self.manager.currentFeedbackComposeViewController = nil; + + [super viewWillDisappear:animated]; +} + +- (void)viewDidDisappear:(BOOL)animated { + [super viewDidDisappear:animated]; +} + + +#pragma mark - Private methods + +- (void)setUserDataAction { + BITFeedbackUserDataViewController *userController = [[[BITFeedbackUserDataViewController alloc] initWithStyle:UITableViewStyleGrouped] autorelease]; + userController.delegate = self; + + UINavigationController *navController = [[[UINavigationController alloc] initWithRootViewController:userController] autorelease]; + + [self.navigationController presentModalViewController:navController animated:YES]; +} + +- (void)dismissAction:(id)sender { + [self dismissModalViewControllerAnimated:YES]; +} + +- (void)sendAction:(id)sender { + if ([self.textView isFirstResponder]) + [self.textView resignFirstResponder]; + + NSString *text = self.textView.text; + + [self.manager submitMessageWithText:text]; + + [self dismissModalViewControllerAnimated:YES]; +} + + +#pragma mark - CNSFeedbackUserDataDelegate + +- (void)userDataUpdateCancelled { + blockUserDataScreen = YES; + + if ([self.manager requireManualUserDataMissing]) { + if ([self.navigationController respondsToSelector:@selector(dismissViewControllerAnimated:completion:)]) { + [self.navigationController dismissViewControllerAnimated:YES + completion:^(void) { + [self dismissModalViewControllerAnimated:YES]; + }]; + } else { + [self dismissModalViewControllerAnimated:YES]; + [self performSelector:@selector(dismissAction:) withObject:nil afterDelay:0.4]; + } + } else { + [self.navigationController dismissModalViewControllerAnimated:YES]; + } +} + +- (void)userDataUpdateFinished { + [self.manager saveMessages]; + + [self.navigationController dismissModalViewControllerAnimated:YES]; +} + + +#pragma mark - UITextViewDelegate + +- (void)textViewDidChange:(UITextView *)textView { + NSUInteger newLength = [textView.text length]; + if (newLength == 0) { + self.navigationItem.rightBarButtonItem.enabled = NO; + } else { + self.navigationItem.rightBarButtonItem.enabled = YES; + } +} + + +@end + diff --git a/Classes/Feedback/BITFeedbackListViewCell.h b/Classes/Feedback/BITFeedbackListViewCell.h new file mode 100644 index 00000000..87f7c6ba --- /dev/null +++ b/Classes/Feedback/BITFeedbackListViewCell.h @@ -0,0 +1,48 @@ +/* + * Author: Andreas Linde + * + * Copyright (c) 2012 HockeyApp, Bit Stadium GmbH. + * All rights reserved. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + + +#import + +typedef enum { + BITFeedbackListViewCellStyleNormal = 0, // left aligned header style + BITFeedbackListViewCellStyleRepsonse = 1 // right aligned header style for dev responses +} BITFeedbackListViewCellStyle; + +@interface BITFeedbackListViewCell : UITableViewCell + +@property (nonatomic) BITFeedbackListViewCellStyle style; +@property (nonatomic) BOOL sent; + +@property (nonatomic, copy) NSDate *date; +@property (nonatomic, copy) NSString *name; +@property (nonatomic, copy) NSString *text; + ++ (CGFloat) heightForRowWithText:(NSString *)text tableViewWidth:(CGFloat)width; + +@end diff --git a/Classes/Feedback/BITFeedbackListViewCell.m b/Classes/Feedback/BITFeedbackListViewCell.m new file mode 100644 index 00000000..b32b5ad0 --- /dev/null +++ b/Classes/Feedback/BITFeedbackListViewCell.m @@ -0,0 +1,161 @@ +/* + * Author: Andreas Linde + * + * Copyright (c) 2012 HockeyApp, Bit Stadium GmbH. + * All rights reserved. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + + +#import "BITFeedbackListViewCell.h" + +#define FRAME_SIDE_BORDER 10 +#define FRAME_TOP_BORDER 5 +#define FRAME_BOTTOM_BORDER 5 + +#define LABEL_DATE_Y 0 +#define LABEL_DATE_HEIGHT 15 + +#define LABEL_NAME_Y 15 +#define LABEL_NAME_HEIGHT 15 + +#define LABEL_TEXT_Y 40 + +@interface BITFeedbackListViewCell () + +@property (nonatomic, retain) NSDateFormatter *dateFormatter; + +@property (nonatomic, retain) UILabel *labelDate; +@property (nonatomic, retain) UILabel *labelName; +@property (nonatomic, retain) UILabel *labelText; + +@end + + +@implementation BITFeedbackListViewCell + + +- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier { + self = [super initWithStyle:style reuseIdentifier:reuseIdentifier]; + if (self) { + // Initialization code + self.contentView.backgroundColor = [UIColor whiteColor]; + + _style = BITFeedbackListViewCellStyleNormal; + _sent = YES; + + _date = nil; + _name = nil; + _text = nil; + + self.dateFormatter = [[[NSDateFormatter alloc] init] autorelease]; + [self.dateFormatter setTimeStyle:NSDateFormatterNoStyle]; + [self.dateFormatter setDateStyle:NSDateFormatterMediumStyle]; + [self.dateFormatter setLocale:[NSLocale currentLocale]]; + [self.dateFormatter setDoesRelativeDateFormatting:YES]; + + self.labelDate = [[[UILabel alloc] init] autorelease]; + self.labelDate.font = [UIFont systemFontOfSize:12]; + + self.labelName = [[[UILabel alloc] init] autorelease]; + self.labelName.font = [UIFont systemFontOfSize:12]; + + self.labelText = [[[UILabel alloc] init] autorelease]; + self.labelText.font = [UIFont systemFontOfSize:14]; + self.labelText.numberOfLines = 0; + self.labelText.textAlignment = UITextAlignmentLeft; + } + return self; +} + +- (void)dealloc { + [_dateFormatter release], _dateFormatter = nil; + + [_labelDate release], _labelDate = nil; + [_labelName release], _labelName = nil; + [_labelText release], _labelText = nil; + + [_date release], _date = nil; + [_name release], _name = nil; + [_text release], _text = nil; + + [super dealloc]; +} + + +#pragma mark - Layout + ++ (CGFloat) heightForRowWithText:(NSString *)text tableViewWidth:(CGFloat)width { + CGFloat calculatedHeight = [text sizeWithFont:[UIFont systemFontOfSize:14] + constrainedToSize:CGSizeMake(width - (2 * FRAME_SIDE_BORDER), CGFLOAT_MAX)].height + LABEL_TEXT_Y + FRAME_BOTTOM_BORDER; + return calculatedHeight; +} + +- (void)layoutSubviews { + [super layoutSubviews]; + + NSString *dateString = [self.dateFormatter stringFromDate:self.date]; + [self.labelDate setText:dateString];// [self.date description]]; + [self.labelDate setFrame:CGRectMake(FRAME_SIDE_BORDER, FRAME_TOP_BORDER + LABEL_DATE_Y, self.frame.size.width - (2 * FRAME_SIDE_BORDER), LABEL_DATE_HEIGHT)]; + + [self.labelName setText:self.name]; + [self.labelName setFrame:CGRectMake(FRAME_SIDE_BORDER, FRAME_TOP_BORDER + LABEL_NAME_Y, self.frame.size.width - (2 * FRAME_SIDE_BORDER), LABEL_NAME_HEIGHT)]; + // header + if (_style == BITFeedbackListViewCellStyleNormal) { + self.contentView.backgroundColor = [UIColor whiteColor]; + self.labelDate.backgroundColor = [UIColor whiteColor]; + self.labelName.backgroundColor = [UIColor whiteColor]; + self.labelText.backgroundColor = [UIColor whiteColor]; + + self.labelDate.textAlignment = UITextAlignmentLeft; + self.labelName.textAlignment = UITextAlignmentLeft; + } else { + self.contentView.backgroundColor = [UIColor lightGrayColor]; + self.labelDate.backgroundColor = [UIColor lightGrayColor]; + self.labelName.backgroundColor = [UIColor lightGrayColor]; + self.labelText.backgroundColor = [UIColor lightGrayColor]; + + self.labelDate.textAlignment = UITextAlignmentRight; + self.labelName.textAlignment = UITextAlignmentRight; + } + + [self addSubview:self.labelDate]; + [self addSubview:self.labelName]; + + // text + [self.labelText setText:self.text]; + CGSize size = CGSizeMake(self.frame.size.width - (2 * FRAME_SIDE_BORDER), + [[self class] heightForRowWithText:self.text tableViewWidth:self.frame.size.width] - LABEL_TEXT_Y - FRAME_BOTTOM_BORDER); + + [self.labelText setFrame : CGRectMake(FRAME_SIDE_BORDER, LABEL_TEXT_Y, size.width, size.height)]; + if (self.sent) { + [self.labelText setTextColor:[UIColor darkTextColor]]; + } else { + [self.labelText setTextColor:[UIColor lightGrayColor]]; + } + + [self addSubview:self.labelText]; +} + + +@end diff --git a/Classes/Feedback/BITFeedbackListViewController.h b/Classes/Feedback/BITFeedbackListViewController.h new file mode 100644 index 00000000..9ed216bd --- /dev/null +++ b/Classes/Feedback/BITFeedbackListViewController.h @@ -0,0 +1,38 @@ +/* + * Author: Andreas Linde + * + * Copyright (c) 2012 HockeyApp, Bit Stadium GmbH. + * All rights reserved. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + + +#import + +#import "BITHockeyBaseViewController.h" + + +@interface BITFeedbackListViewController : BITHockeyBaseViewController { +} + +@end \ No newline at end of file diff --git a/Classes/Feedback/BITFeedbackListViewController.m b/Classes/Feedback/BITFeedbackListViewController.m new file mode 100644 index 00000000..e652d844 --- /dev/null +++ b/Classes/Feedback/BITFeedbackListViewController.m @@ -0,0 +1,311 @@ +/* + * Author: Andreas Linde + * + * Copyright (c) 2012 HockeyApp, Bit Stadium GmbH. + * All rights reserved. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + + +#import "HockeySDK.h" +#import "HockeySDKPrivate.h" + +#import "BITFeedbackManagerPrivate.h" +#import "BITFeedbackListViewController.h" +#import "BITFeedbackListViewCell.h" +#import "BITFeedbackComposeViewController.h" +#import "BITFeedbackUserDataViewController.h" +#import "BITFeedbackMessage.h" + +#import "BITHockeyHelper.h" + + +@interface BITFeedbackListViewController () +@property (nonatomic, assign) BITFeedbackManager *manager; +@property (nonatomic, retain) UITableView *tableView; + +@property (nonatomic, retain) NSDateFormatter *lastUpdateDateFormatter; +@end + +@implementation BITFeedbackListViewController + +- (id)init { + if ((self = [super init])) { + _manager = [BITHockeyManager sharedHockeyManager].feedbackManager; + + self.lastUpdateDateFormatter = [[[NSDateFormatter alloc] init] autorelease]; + [self.lastUpdateDateFormatter setDateStyle:NSDateFormatterShortStyle]; + [self.lastUpdateDateFormatter setTimeStyle:NSDateFormatterShortStyle]; + self.lastUpdateDateFormatter.locale = [NSLocale currentLocale]; + } + return self; +} + + +- (void)dealloc { + [_tableView release], _tableView = nil; + [_lastUpdateDateFormatter release]; _lastUpdateDateFormatter = nil; + + [super dealloc]; +} + + +#pragma mark - View lifecycle + +- (void)viewDidLoad { + [super viewDidLoad]; + + [[NSNotificationCenter defaultCenter] addObserver:self + selector:@selector(updateList) + name:BITHockeyFeedbackMessagesUpdated + object:nil]; + + self.title = BITHockeyLocalizedString(@"HockeyFeedbackListTitle"); + + self.tableView = [[[UITableView alloc] initWithFrame:self.view.bounds] autorelease]; + self.tableView.delegate = self; + self.tableView.dataSource = self; + self.tableView.separatorStyle = UITableViewCellSeparatorStyleNone; + [self.tableView setAutoresizingMask:UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth]; + [self.tableView setBackgroundColor:[UIColor colorWithRed:0.82 green:0.84 blue:0.84 alpha:1]]; + [self.tableView setSeparatorColor:[UIColor colorWithRed:0.79 green:0.79 blue:0.79 alpha:1]]; + [self.view addSubview:self.tableView]; + + self.navigationItem.rightBarButtonItem = [[[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemRefresh + target:self + action:@selector(reloadList)] autorelease]; + +} + +- (void)viewDidUnload { + [[NSNotificationCenter defaultCenter] removeObserver:self name:BITHockeyFeedbackMessagesUpdated object:nil]; + + [super viewDidUnload]; +} + +- (void)reloadList { + [self.manager updateMessagesList]; +} + +- (void)updateList { + CGSize contentSize = self.tableView.contentSize; + CGPoint contentOffset = self.tableView.contentOffset; + + [self.tableView reloadData]; + if (self.tableView.contentSize.height > contentSize.height) + [self.tableView setContentOffset:CGPointMake(contentOffset.x, self.tableView.contentSize.height - contentSize.height + contentOffset.y) animated:NO]; + + [self.tableView flashScrollIndicators]; +} + +- (void)viewWillAppear:(BOOL)animated { + self.manager.currentFeedbackListViewController = self; + + [super viewWillAppear:animated]; + + [self.tableView reloadData]; +} + +- (void)viewWillDisappear:(BOOL)animated { + self.manager.currentFeedbackListViewController = nil; + + [super viewWillDisappear:animated]; +} + + +#pragma mark - Private methods + +- (void)setUserDataAction:(id)sender { + BITFeedbackUserDataViewController *userController = [[[BITFeedbackUserDataViewController alloc] initWithStyle:UITableViewStyleGrouped] autorelease]; + userController.delegate = self; + + UINavigationController *navController = [[[UINavigationController alloc] initWithRootViewController:userController] autorelease]; + + [self.navigationController presentModalViewController:navController animated:YES]; +} + +- (void)newFeedbackAction:(id)sender { + BITFeedbackComposeViewController *composeController = [[[BITFeedbackComposeViewController alloc] init] autorelease]; + + UINavigationController *navController = [[[UINavigationController alloc] initWithRootViewController:composeController] autorelease]; + + [self.navigationController presentModalViewController:navController animated:YES]; +} + + +#pragma mark - BITFeedbackUserDataDelegate + +-(void)userDataUpdateCancelled { + [self.navigationController dismissModalViewControllerAnimated:YES]; +} + +-(void)userDataUpdateFinished { + [self.manager saveMessages]; + + [self.navigationController dismissModalViewControllerAnimated:YES]; +} + + +#pragma mark - Table view data source + +- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { + NSInteger rows = 2; + if ([self.manager isManualUserDataAvailable] || [self.manager didAskUserData]) + rows++; + + return rows; +} + +- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { + if (section == 0) { + return 2; + } else if (section == 2) { + return 1; + } else { + return [self.manager numberOfMessages]; + } +} + +- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { + static NSString *CellIdentifier = @"MessageCell"; + static NSString *LastUpdateIdentifier = @"LastUpdateCell"; + static NSString *ButtonIdentifier = @"ButtonCell"; + + if (indexPath.section == 0 && indexPath.row == 1) { + UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:LastUpdateIdentifier]; + + if (!cell) { + cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:LastUpdateIdentifier] autorelease]; + cell.textLabel.font = [UIFont systemFontOfSize:10]; + cell.accessoryType = UITableViewCellAccessoryNone; + cell.selectionStyle = UITableViewCellSelectionStyleNone; + cell.textLabel.textAlignment = UITextAlignmentCenter; + } + + cell.textLabel.text = [NSString stringWithFormat:BITHockeyLocalizedString(@"HockeyFeedbackListLastUpdated"), + [self.manager lastCheck] ? [self.lastUpdateDateFormatter stringFromDate:[self.manager lastCheck]] : BITHockeyLocalizedString(@"HockeyFeedbackListNeverUpdated")]; + + return cell; + } else if (indexPath.section == 0 || indexPath.section == 2) { + UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:ButtonIdentifier]; + + if (!cell) { + cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:ButtonIdentifier] autorelease]; + cell.textLabel.font = [UIFont systemFontOfSize:14]; + cell.textLabel.numberOfLines = 0; + cell.accessoryType = UITableViewCellAccessoryNone; + cell.selectionStyle = UITableViewCellSelectionStyleNone; + } + + UIButton *button = [UIButton buttonWithType:UIButtonTypeRoundedRect]; + [button setTitleColor:[UIColor blackColor] forState:UIControlStateNormal]; + [button setTitleShadowColor:[UIColor lightGrayColor] forState:UIControlStateNormal]; + if (indexPath.section == 0) { + if ([self.manager numberOfMessages] == 0) { + [button setTitle:BITHockeyLocalizedString(@"HockeyFeedbackListButonWriteFeedback") forState:UIControlStateNormal]; + } else { + [button setTitle:BITHockeyLocalizedString(@"HockeyFeedbackListButonWriteResponse") forState:UIControlStateNormal]; + } + [button addTarget:self action:@selector(newFeedbackAction:) forControlEvents:UIControlEventTouchUpInside]; + } else { + NSString *title = @""; + if ([self.manager requireUserName] == BITFeedbackUserDataElementRequired || + ([self.manager requireUserName] == BITFeedbackUserDataElementOptional && [self.manager userName] != nil) + ) { + title = [NSString stringWithFormat:BITHockeyLocalizedString(@"HockeyFeedbackListButonUserDataWithName"), [self.manager userName]]; + } else if ([self.manager requireUserEmail] == BITFeedbackUserDataElementRequired || + ([self.manager requireUserEmail] == BITFeedbackUserDataElementOptional && [self.manager userEmail] != nil) + ) { + title = [NSString stringWithFormat:BITHockeyLocalizedString(@"HockeyFeedbackListButonUserDataWithEmail"), [self.manager userEmail]]; + } else if ([self.manager requireUserName] == BITFeedbackUserDataElementOptional) { + title = BITHockeyLocalizedString(@"HockeyFeedbackListButonUserDataSetName"); + } else { + title = BITHockeyLocalizedString(@"HockeyFeedbackListButonUserDataSetEmail"); + } + [button setTitle:title forState:UIControlStateNormal]; + [button addTarget:self action:@selector(setUserDataAction:) forControlEvents:UIControlEventTouchUpInside]; + } + [button setFrame: CGRectMake( 10.0f, 12.0f, self.view.frame.size.width - 20.0f, 50.0f)]; + + [cell addSubview:button]; + + return cell; + } else { + BITFeedbackListViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier]; + + if (!cell) { + cell = [[[BITFeedbackListViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease]; + cell.accessoryType = UITableViewCellAccessoryNone; + cell.selectionStyle = UITableViewCellSelectionStyleNone; + } + + BITFeedbackMessage *message = [self.manager messageAtIndex:indexPath.row]; + cell.date = message.date; + + if (message.userMessage) { + cell.style = BITFeedbackListViewCellStyleNormal; + if ([self.manager requireUserName] == BITFeedbackUserDataElementRequired || + ([self.manager requireUserName] == BITFeedbackUserDataElementOptional && [self.manager userName] != nil) + ) { + cell.name = [self.manager userName]; + } else { + cell.name = BITHockeyLocalizedString(@"HockeyFeedbackListMessageUserNameNotSet"); + } + } else { + cell.style = BITFeedbackListViewCellStyleRepsonse; + if (message.name && [message.name length] > 0) { + cell.name = message.name; + } else { + cell.name = BITHockeyLocalizedString(@"HockeyFeedbackListmessageResponseNameNotSet"); + } + } + + if (message.text) { + cell.text = message.text; + } else { + cell.text = @""; + } + + return cell; + } +} + + +#pragma mark - Table view delegate + +- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath { + if (indexPath.section == 0 && indexPath.row == 1) { + return 28; + } + if (indexPath.section == 0 || indexPath.section == 2) { + return 74; + } + + BITFeedbackMessage *message = [self.manager messageAtIndex:indexPath.row]; + if (!message) return 44; + + // BITFeedbackListViewCell *cell = (BITFeedbackListViewCell *)[tableView cellForRowAtIndexPath:indexPath]; + return [BITFeedbackListViewCell heightForRowWithText:message.text tableViewWidth:self.view.frame.size.width]; +} + +@end diff --git a/Classes/Feedback/BITFeedbackManager.h b/Classes/Feedback/BITFeedbackManager.h new file mode 100644 index 00000000..81353108 --- /dev/null +++ b/Classes/Feedback/BITFeedbackManager.h @@ -0,0 +1,94 @@ +/* + * Author: Andreas Linde + * + * Copyright (c) 2012 HockeyApp, Bit Stadium GmbH. + * All rights reserved. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + + +#import + +#import "BITHockeyBaseManager.h" +#import "BITFeedbackListViewController.h" +#import "BITFeedbackComposeViewController.h" + + +typedef enum { + BITFeedbackUserDataElementDontShow = 0, // don't ask for this user data element at all + BITFeedbackUserDataElementOptional = 1, // the user may provide it, but does not have to + BITFeedbackUserDataElementRequired = 2 // the user has to provide this to continue +} BITFeedbackUserDataElement; + + +@class BITFeedbackMessage; +@protocol BITFeedbackManagerDelegate; + + +@interface BITFeedbackManager : BITHockeyBaseManager + +@property (nonatomic, retain) BITFeedbackListViewController *currentFeedbackListViewController; +@property (nonatomic, retain) BITFeedbackComposeViewController *currentFeedbackComposeViewController; +@property (nonatomic) BOOL didAskUserData; + +@property (nonatomic, retain) NSDate *lastCheck; + +@property (nonatomic, readwrite) BITFeedbackUserDataElement requireUserName; // default is BITFeedbackUserDataRequired +@property (nonatomic, readwrite) BITFeedbackUserDataElement requireUserEmail; // default is BITFeedbackUserDataRequired +@property (nonatomic, readwrite) BOOL showAlertOnIncomingMessages; // default is YES + +@property (nonatomic, copy) NSString *userName; +@property (nonatomic, copy) NSString *userEmail; + + +// convenience methode to create feedback view controller +- (BITFeedbackListViewController *)feedbackListViewController:(BOOL)modal; + +// load new messages from the server +- (void)updateMessagesList; + +// open feedback list view +- (void)showFeedbackListView; + +// open feedback compose view +- (void)showFeedbackComposeView; + +- (NSUInteger)numberOfMessages; +- (BITFeedbackMessage *)messageAtIndex:(NSUInteger)index; + +- (void)submitMessageWithText:(NSString *)text; +- (void)submitPendingMessages; + +// Returns YES if manual user data can be entered, required or optional +- (BOOL)askManualUserDataAvailable; + +// Returns YES if required user data is missing? +- (BOOL)requireManualUserDataMissing; + +// Returns YES if user data is available and can be edited +- (BOOL)isManualUserDataAvailable; + +// used in the user data screen +- (void)updateDidAskUserData; + +@end diff --git a/Classes/Feedback/BITFeedbackManager.m b/Classes/Feedback/BITFeedbackManager.m new file mode 100644 index 00000000..83d6d2c2 --- /dev/null +++ b/Classes/Feedback/BITFeedbackManager.m @@ -0,0 +1,626 @@ +/* + * Author: Andreas Linde + * + * Copyright (c) 2012 HockeyApp, Bit Stadium GmbH. + * All rights reserved. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + + +#import "HockeySDK.h" +#import "HockeySDKPrivate.h" + +#import "BITFeedbackManager.h" +#import "BITFeedbackManagerPrivate.h" +#import "BITHockeyBaseManagerPrivate.h" + +#import "BITHockeyManagerPrivate.h" + +#import "BITFeedbackMessage.h" +#import "BITHockeyHelper.h" + + +#define kBITFeedbackUserDataAsked @"HockeyFeedbackUserDataAsked" +#define kBITFeedbackDateOfLastCheck @"HockeyFeedbackDateOfLastCheck" +#define kBITFeedbackMessages @"HockeyFeedbackMessages" +#define kBITFeedbackToken @"HockeyFeedbackToken" +#define kBITFeedbackName @"HockeyFeedbackName" +#define kBITFeedbackEmail @"HockeyFeedbackEmail" + + +@implementation BITFeedbackManager { + NSFileManager *_fileManager; + NSString *_feedbackDir; + NSString *_settingsFile; +} + +#pragma mark - Initialization + +- (id)init { + if ((self = [super init])) { + _currentFeedbackListViewController = nil; + _currentFeedbackComposeViewController = nil; + _didAskUserData = NO; + + _requireUserName = BITFeedbackUserDataElementRequired; + _requireUserEmail = BITFeedbackUserDataElementRequired; + _showAlertOnIncomingMessages = YES; + + _networkRequestInProgress = NO; + _incomingMessagesAlertShowing = NO; + _lastCheck = nil; + _token = nil; + _feedbackList = nil; + + _fileManager = [[NSFileManager alloc] init]; + + // temporary directory for crashes grabbed from PLCrashReporter + NSArray *paths = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES); + _feedbackDir = [[[paths objectAtIndex:0] stringByAppendingPathComponent:BITHOCKEY_IDENTIFIER] retain]; + + if (![_fileManager fileExistsAtPath:_feedbackDir]) { + NSDictionary *attributes = [NSDictionary dictionaryWithObject: [NSNumber numberWithUnsignedLong: 0755] forKey: NSFilePosixPermissions]; + NSError *theError = NULL; + + [_fileManager createDirectoryAtPath:_feedbackDir withIntermediateDirectories: YES attributes: attributes error: &theError]; + } + + _settingsFile = [[_feedbackDir stringByAppendingPathComponent:BITHOCKEY_FEEDBACK_SETTINGS] retain]; + + + _userName = nil; + _userEmail = nil; + } + return self; +} + +- (void)dealloc { + [_currentFeedbackListViewController release], _currentFeedbackListViewController = nil; + [_currentFeedbackComposeViewController release], _currentFeedbackComposeViewController = nil; + + [_lastCheck release], _lastCheck = nil; + [_token release], _token = nil; + [_feedbackList release], _feedbackList = nil; + + [_userName release], _userName = nil; + [_userEmail release], _userEmail = nil; + + [_fileManager release], _fileManager = nil; + [_feedbackDir release], _feedbackDir = nil; + [_settingsFile release], _settingsFile = nil; + + [super dealloc]; +} + + +#pragma mark - Feedback Modal UI + +- (BITFeedbackListViewController *)feedbackListViewController:(BOOL)modal { + return [[[BITFeedbackListViewController alloc] initWithModalStyle:modal] autorelease]; +} + +- (void)showFeedbackListView { + if (_currentFeedbackListViewController) { + BITHockeyLog(@"INFO: update view already visible, aborting"); + return; + } + + [self showView:[self feedbackListViewController:YES]]; +} + +- (BITFeedbackComposeViewController *)feedbackComposeViewController:(BOOL)modal { + return [[[BITFeedbackComposeViewController alloc] initWithModalStyle:modal] autorelease]; +} + +- (void)showFeedbackComposeView { + if (_currentFeedbackComposeViewController) { + BITHockeyLog(@"INFO: update view already visible, aborting"); + return; + } + + [self showView:[self feedbackComposeViewController:YES]]; +} + + +#pragma mark - Manager Control + +- (void)startManager { + if ([self.feedbackList count] == 0) { + [self loadMessages]; + } + [self updateMessagesList]; +} + +- (void)updateMessagesList { + if (_networkRequestInProgress) return; + + if ([self nextPendingMessage]) { + [self submitPendingMessages]; + } else { + [self fetchMessageUpdates]; + } +} + +#pragma mark - Local Storage + +- (void)loadMessages { + NSString *errorString = nil; + NSPropertyListFormat format; + + BOOL userNameViaDelegate = NO; + BOOL userEmailViaDelegate = NO; + + if ([BITHockeyManager sharedHockeyManager].delegate && + [[BITHockeyManager sharedHockeyManager].delegate respondsToSelector:@selector(userNameForHockeyManager:componentManager:)]) { + userNameViaDelegate = YES; + self.userName = [[BITHockeyManager sharedHockeyManager].delegate + userNameForHockeyManager:[BITHockeyManager sharedHockeyManager] + componentManager:self]; + self.requireUserName = BITFeedbackUserDataElementDontShow; + self.requireUserEmail = BITFeedbackUserDataElementDontShow; + } + if ([BITHockeyManager sharedHockeyManager].delegate && + [[BITHockeyManager sharedHockeyManager].delegate respondsToSelector:@selector(userEmailForHockeyManager:componentManager:)]) { + userEmailViaDelegate = YES; + self.userEmail = [[BITHockeyManager sharedHockeyManager].delegate + userEmailForHockeyManager:[BITHockeyManager sharedHockeyManager] + componentManager:self]; + self.requireUserName = BITFeedbackUserDataElementDontShow; + self.requireUserEmail = BITFeedbackUserDataElementDontShow; + } + + if (![_fileManager fileExistsAtPath:_settingsFile]) + return; + + NSData *plist = [NSData dataWithContentsOfFile:_settingsFile]; + if (plist) { + NSDictionary *rootObj = (NSDictionary *)[NSPropertyListSerialization + propertyListFromData:plist + mutabilityOption:NSPropertyListMutableContainersAndLeaves + format:&format + errorDescription:&errorString]; + + if (!userNameViaDelegate) { + if ([rootObj objectForKey:kBITFeedbackName]) + self.userName = [rootObj objectForKey:kBITFeedbackName]; + } + + if (!userEmailViaDelegate) { + if ([rootObj objectForKey:kBITFeedbackEmail]) + self.userEmail = [rootObj objectForKey:kBITFeedbackEmail]; + } + + if ([rootObj objectForKey:kBITFeedbackUserDataAsked]) + self.didAskUserData = YES; + + if ([rootObj objectForKey:kBITFeedbackToken]) + self.token = [rootObj objectForKey:kBITFeedbackToken]; + + if ([rootObj objectForKey:kBITFeedbackName]) + self.userName = [rootObj objectForKey:kBITFeedbackName]; + + if ([rootObj objectForKey:kBITFeedbackEmail]) + self.userEmail = [rootObj objectForKey:kBITFeedbackEmail]; + + if ([rootObj objectForKey:kBITFeedbackDateOfLastCheck]) + self.lastCheck = [rootObj objectForKey:kBITFeedbackDateOfLastCheck]; + + if ([rootObj objectForKey:kBITFeedbackMessages]) { + self.feedbackList = [NSMutableArray arrayWithArray:[rootObj objectForKey:kBITFeedbackMessages]]; + + [self sortFeedbackList]; + + // inform the UI to update its data in case the list is already showing + [[NSNotificationCenter defaultCenter] postNotificationName:BITHockeyFeedbackMessagesUpdated object:nil]; + } else { + self.feedbackList = [NSMutableArray array]; + } + } else { + self.feedbackList = [NSMutableArray array]; + BITHockeyLog(@"ERROR: Reading settings. %@", errorString); + } + + if (!self.lastCheck) { + self.lastCheck = [NSDate distantPast]; + } +} + + +- (void)saveMessages { + [self sortFeedbackList]; + + NSString *errorString = nil; + + NSMutableDictionary *rootObj = [NSMutableDictionary dictionaryWithCapacity:2]; + + if (self.didAskUserData) + [rootObj setObject:[NSNumber numberWithBool:YES] forKey:kBITFeedbackUserDataAsked]; + + if (self.token) + [rootObj setObject:self.token forKey:kBITFeedbackToken]; + + if (self.userName) + [rootObj setObject:self.userName forKey:kBITFeedbackName]; + + if (self.userEmail) + [rootObj setObject:self.userEmail forKey:kBITFeedbackEmail]; + + [rootObj setObject:self.lastCheck forKey:kBITFeedbackDateOfLastCheck]; + + [rootObj setObject:self.feedbackList forKey:kBITFeedbackMessages]; + + NSData *plist = [NSPropertyListSerialization dataFromPropertyList:(id)rootObj + format:NSPropertyListBinaryFormat_v1_0 + errorDescription:&errorString]; + if (plist) { + [plist writeToFile:_settingsFile atomically:YES]; + } else { + BITHockeyLog(@"ERROR: Writing settings. %@", errorString); + } +} + + +- (void)updateDidAskUserData { + if (!self.didAskUserData) { + self.didAskUserData = YES; + + [self saveMessages]; + } +} + +#pragma mark - Messages + +- (void)sortFeedbackList { + [self.feedbackList sortUsingComparator:^(BITFeedbackMessage *obj1, BITFeedbackMessage *obj2) { + NSDate *date1 = [obj1 date]; + NSDate *date2 = [obj2 date]; + + // not send and send in progress messages on top, sorted by date + // read and unread on bottom, sorted by date + + if ([obj1 status] >= BITFeedbackMessageStatusSendInProgress && [obj2 status] < BITFeedbackMessageStatusSendInProgress) { + return NSOrderedAscending; + } else if ([obj1 status] < BITFeedbackMessageStatusSendInProgress && [obj2 status] >= BITFeedbackMessageStatusSendInProgress) { + return NSOrderedDescending; + } else { + return (NSInteger)[date2 compare:date1]; + } + }]; +} + +- (NSUInteger)numberOfMessages { + return [self.feedbackList count]; +} + +- (BITFeedbackMessage *)messageAtIndex:(NSUInteger)index { + if ([self.feedbackList count] > index) { + return [self.feedbackList objectAtIndex:index]; + } + + return nil; +} + +- (BITFeedbackMessage *)messageWithID:(NSNumber *)messageID { + __block BITFeedbackMessage *message = nil; + + [self.feedbackList enumerateObjectsUsingBlock:^(BITFeedbackMessage *objMessage, NSUInteger messagesIdx, BOOL *stop) { + if ([[objMessage id] isEqualToNumber:messageID]) { + message = objMessage; + *stop = YES; + } + }]; + + return message; +} + +- (BITFeedbackMessage *)sendInProgressMessage { + __block BITFeedbackMessage *message = nil; + + [self.feedbackList enumerateObjectsUsingBlock:^(BITFeedbackMessage *objMessage, NSUInteger messagesIdx, BOOL *stop) { + if ([objMessage status] == BITFeedbackMessageStatusSendInProgress) { + message = objMessage; + *stop = YES; + } + }]; + + return message; +} + +- (BITFeedbackMessage *)nextPendingMessage { + __block BITFeedbackMessage *message = nil; + + [self.feedbackList enumerateObjectsUsingBlock:^(BITFeedbackMessage *objMessage, NSUInteger messagesIdx, BOOL *stop) { + if ([objMessage status] == BITFeedbackMessageStatusSendPending) { + message = objMessage; + *stop = YES; + } + }]; + + return message; +} + + +#pragma mark - User + +- (BOOL)askManualUserDataAvailable { + if (self.requireUserName == BITFeedbackUserDataElementDontShow && + self.requireUserEmail == BITFeedbackUserDataElementDontShow) + return NO; + + return YES; +} + +- (BOOL)requireManualUserDataMissing { + if (self.requireUserName == BITFeedbackUserDataElementRequired && !self.userName) + return YES; + + if (self.requireUserEmail == BITFeedbackUserDataElementRequired && !self.userEmail) + return YES; + + return NO; +} + +- (BOOL)isManualUserDataAvailable { + if ((self.requireUserName != BITFeedbackUserDataElementDontShow && self.userName) || + (self.requireUserEmail != BITFeedbackUserDataElementDontShow && self.userEmail)) + return YES; + + return NO; +} + + +#pragma mark - Networking + +- (BOOL)updateMessageListFromResponse:(NSDictionary *)jsonDictionary { + NSDictionary *feedback = [jsonDictionary objectForKey:@"feedback"]; + NSString *token = [jsonDictionary objectForKey:@"token"]; + NSDictionary *feedbackObject = [jsonDictionary objectForKey:@"feedback"]; + if (feedback && token && feedbackObject) { + // update the thread token, which is not available until the 1st message was successfully sent + self.token = token; + + self.lastCheck = [NSDate date]; + + // add all new messages + NSArray *feedMessages = [feedbackObject objectForKey:@"messages"]; + + // get the message that was currently sent if available + __block BITFeedbackMessage *sendInProgressMessage = [self sendInProgressMessage]; + __block BOOL messagesUpdated = NO; + __block BOOL newResponseMessage = NO; + + [feedMessages enumerateObjectsUsingBlock:^(id objMessage, NSUInteger messagesIdx, BOOL *stop) { + NSNumber *messageID = [(NSDictionary *)objMessage objectForKey:@"id"]; + if (![self messageWithID:messageID]) { + // check if this is the message that was sent right now + if (sendInProgressMessage && [[sendInProgressMessage text] isEqualToString:[(NSDictionary *)objMessage objectForKey:@"text"]]) { + sendInProgressMessage.date = [self parseRFC3339Date:[(NSDictionary *)objMessage objectForKey:@"created_at"]]; + sendInProgressMessage.id = messageID; + sendInProgressMessage.status = BITFeedbackMessageStatusRead; + } else { + BITFeedbackMessage *message = [[[BITFeedbackMessage alloc] init] autorelease]; + message.text = [(NSDictionary *)objMessage objectForKey:@"text"]; + message.name = [(NSDictionary *)objMessage objectForKey:@"name"]; + message.email = [(NSDictionary *)objMessage objectForKey:@"email"]; + + message.date = [self parseRFC3339Date:[(NSDictionary *)objMessage objectForKey:@"created_at"]]; + message.id = [(NSDictionary *)objMessage objectForKey:@"id"]; + message.status = BITFeedbackMessageStatusUnread; + + [self.feedbackList addObject:message]; + + newResponseMessage = YES; + } + messagesUpdated = YES; + } + }]; + + // new data arrived, so save it + if (messagesUpdated) { + [self saveMessages]; + + // inform the UI to update its data in case the list is already showing + [[NSNotificationCenter defaultCenter] postNotificationName:BITHockeyFeedbackMessagesUpdated object:nil]; + } + + // we got a new incoming message, trigger user notification system + if (newResponseMessage) { + [[NSNotificationCenter defaultCenter] postNotificationName:BITHockeyFeedbackNewMessagesReceived object:nil]; + + if (self.showAlertOnIncomingMessages && !self.currentFeedbackListViewController && !self.currentFeedbackComposeViewController) { + UIAlertView *alertView = [[[UIAlertView alloc] initWithTitle:BITHockeyLocalizedString(@"HockeyFeedbackNewMessageTitle") + message:BITHockeyLocalizedString(@"HockeyFeedbackNewMessageText") + delegate:self + cancelButtonTitle:BITHockeyLocalizedString(@"HockeyFeedbackIgnore") + otherButtonTitles:BITHockeyLocalizedString(@"HockeyFeedbackShow"), nil + ] autorelease]; + [alertView setTag:0]; + [alertView show]; + _incomingMessagesAlertShowing = YES; + } + } + + return YES; + } + + // quit + return NO; +} + +- (void)sendNetworkRequestWithHTTPMethod:(NSString *)httpMethod withText:(NSString *)text completionHandler:(void (^)(NSError *err))completionHandler { + NSString *boundary = @"----FOO"; + + _networkRequestInProgress = YES; + + NSString *tokenParameter = @""; + if ([self token]) { + tokenParameter = [NSString stringWithFormat:@"/%@", [self token]]; + } + NSMutableString *parameter = [NSMutableString stringWithFormat:@"api/2/apps/%@/feedback%@", [self encodedAppIdentifier], tokenParameter]; + + [parameter appendFormat:@"?format=json&bundle_version=%@&sdk=%@&sdk_version=%@", + bit_URLEncodedString([[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleVersion"]), + BITHOCKEY_NAME, + BITHOCKEY_VERSION + ]; + + // build request & send + NSString *url = [NSString stringWithFormat:@"https://warmup.hockeyapp.net/%@", parameter]; + BITHockeyLog(@"INFO: sending api request to %@", url); + + NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:url] cachePolicy:1 timeoutInterval:10.0]; + [request setHTTPMethod:httpMethod]; + [request setValue:@"Hockey/iOS" forHTTPHeaderField:@"User-Agent"]; + [request setValue:@"gzip" forHTTPHeaderField:@"Accept-Encoding"]; + + if (text) { + NSString *contentType = [NSString stringWithFormat:@"multipart/form-data; boundary=%@", boundary]; + [request setValue:contentType forHTTPHeaderField:@"Content-type"]; + + NSMutableData *postBody = [NSMutableData data]; + + [postBody appendData:[self appendPostValue:@"Apple" forKey:@"oem"]]; + [postBody appendData:[self appendPostValue:[[UIDevice currentDevice] systemVersion] forKey:@"os_version"]]; + [postBody appendData:[self appendPostValue:[self getDevicePlatform] forKey:@"model"]]; + [postBody appendData:[self appendPostValue:[[[NSBundle mainBundle] preferredLocalizations] objectAtIndex:0] forKey:@"lang"]]; + [postBody appendData:[self appendPostValue:[[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleVersion"] forKey:@"bundle_version"]]; + [postBody appendData:[self appendPostValue:text forKey:@"text"]]; + + if (self.userName) { + [postBody appendData:[self appendPostValue:self.userName forKey:@"name"]]; + } + if (self.userEmail) { + [postBody appendData:[self appendPostValue:self.userEmail forKey:@"email"]]; + } + + [postBody appendData:[[NSString stringWithFormat:@"--%@--\r\n", boundary] dataUsingEncoding:NSUTF8StringEncoding]]; + + [request setHTTPBody:postBody]; + } + + [NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse *response, NSData *responseData, NSError *err) { + _networkRequestInProgress = NO; + + if (err) { + completionHandler(err); + } else { + if ([responseData length]) { + NSString *responseString = [[[NSString alloc] initWithBytes:[responseData bytes] length:[responseData length] encoding: NSUTF8StringEncoding] autorelease]; + BITHockeyLog(@"INFO: Received API response: %@", responseString); + + NSError *error = NULL; + + NSDictionary *feedDict = (NSDictionary *)bit_parseJSON(responseString, &error); + + // server returned empty response? + if (error) { + [self reportError:error]; + } else if (![feedDict count]) { + [self reportError:[NSError errorWithDomain:kBITFeedbackErrorDomain + code:BITFeedbackAPIServerReturnedEmptyResponse + userInfo:[NSDictionary dictionaryWithObjectsAndKeys:@"Server returned empty response.", NSLocalizedDescriptionKey, nil]]]; + } else { + BITHockeyLog(@"INFO: Received API response: %@", responseString); + NSString *status = [feedDict objectForKey:@"status"]; + if ([status compare:@"success"] != NSOrderedSame) { + [self reportError:[NSError errorWithDomain:kBITFeedbackErrorDomain + code:BITFeedbackAPIServerReturnedInvalidStatus + userInfo:[NSDictionary dictionaryWithObjectsAndKeys:@"Server returned invalid status.", NSLocalizedDescriptionKey, nil]]]; + } else { + [self updateMessageListFromResponse:feedDict]; + } + } + + completionHandler(err); + } + } + }]; +} + +- (void)fetchMessageUpdates { + if ([self.feedbackList count] == 0) { + return; + } + + [self sendNetworkRequestWithHTTPMethod:@"GET" + withText:nil + completionHandler:^(NSError *err){ + }]; +} + +- (void)submitPendingMessages { + BITFeedbackMessage *message = [self nextPendingMessage]; + + if (message) { + [message setStatus:BITFeedbackMessageStatusSendInProgress]; + if (self.userName) + [message setName:self.userName]; + if (self.userEmail) + [message setName:self.userEmail]; + + NSString *httpMethod = @"POST"; + if ([self token]) { + httpMethod = @"PUT"; + } + + [self sendNetworkRequestWithHTTPMethod:httpMethod + withText:[message text] + completionHandler:^(NSError *err){ + if (err) { + [message setStatus:BITFeedbackMessageStatusSendPending]; + + [self saveMessages]; + + // inform the UI to update its data in case the list is already showing + [[NSNotificationCenter defaultCenter] postNotificationName:BITHockeyFeedbackMessagesUpdated object:nil]; + + } + }]; + } +} + +- (void)submitMessageWithText:(NSString *)text { + BITFeedbackMessage *message = [[[BITFeedbackMessage alloc] init] autorelease]; + message.text = text; + [message setStatus:BITFeedbackMessageStatusSendPending]; + [message setUserMessage:YES]; + + [self.feedbackList addObject:message]; + + [self submitPendingMessages]; +} + + +#pragma mark - UIAlertViewDelegate + +// invoke the selected action from the actionsheet for a location element +- (void)alertView:(UIAlertView *)alertView didDismissWithButtonIndex:(NSInteger)buttonIndex { + + _incomingMessagesAlertShowing = NO; + if (buttonIndex == [alertView firstOtherButtonIndex]) { + // Show button has been clicked + [self showFeedbackListView]; + } +} + +@end diff --git a/Classes/Feedback/BITFeedbackManagerPrivate.h b/Classes/Feedback/BITFeedbackManagerPrivate.h new file mode 100644 index 00000000..510588ee --- /dev/null +++ b/Classes/Feedback/BITFeedbackManagerPrivate.h @@ -0,0 +1,56 @@ +/* + * Author: Andreas Linde + * Kent Sutherland + * + * Copyright (c) 2012 HockeyApp, Bit Stadium GmbH. + * Copyright (c) 2011 Andreas Linde & Kent Sutherland. + * All rights reserved. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#import + + +@interface BITFeedbackManager () { +} + + +@property (nonatomic, readwrite) BOOL incomingMessagesAlertShowing; +@property (nonatomic) BOOL networkRequestInProgress; + +@property (nonatomic, retain) NSString *token; +@property (nonatomic, retain) NSMutableArray *feedbackList; + + + +- (BITFeedbackMessage *)messageWithID:(NSNumber *)messageID; +- (BITFeedbackMessage *)sendInProgressMessage; +- (BITFeedbackMessage *)nextPendingMessage; + +- (void)saveMessages; + +- (void)fetchMessageUpdates; +- (BOOL)updateMessageListFromResponse:(NSDictionary *)jsonDictionary; + + +@end diff --git a/Classes/Feedback/BITFeedbackMessage.h b/Classes/Feedback/BITFeedbackMessage.h new file mode 100644 index 00000000..2dfc81bc --- /dev/null +++ b/Classes/Feedback/BITFeedbackMessage.h @@ -0,0 +1,54 @@ +/* + * Author: Andreas Linde + * + * Copyright (c) 2012 HockeyApp, Bit Stadium GmbH. + * All rights reserved. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + + +#import + +typedef enum { + // default and new messages from SDK per default + BITFeedbackMessageStatusSendPending = 0, + // sending of message is in progress + BITFeedbackMessageStatusSendInProgress = 1, + // new messages from server + BITFeedbackMessageStatusUnread = 2, + // messages from server once read and new local messages once successful send from SDK + BITFeedbackMessageStatusRead = 3 +} BITFeedbackMessageStatus; + +@interface BITFeedbackMessage : NSObject { +} + +@property (nonatomic, copy) NSString *text; +@property (nonatomic, copy) NSString *name; +@property (nonatomic, copy) NSString *email; +@property (nonatomic, copy) NSDate *date; +@property (nonatomic, copy) NSNumber *id; +@property (nonatomic) BITFeedbackMessageStatus status; +@property (nonatomic) BOOL userMessage; + +@end \ No newline at end of file diff --git a/Classes/Feedback/BITFeedbackMessage.m b/Classes/Feedback/BITFeedbackMessage.m new file mode 100644 index 00000000..85410c2c --- /dev/null +++ b/Classes/Feedback/BITFeedbackMessage.m @@ -0,0 +1,86 @@ +/* + * Author: Andreas Linde + * + * Copyright (c) 2012 HockeyApp, Bit Stadium GmbH. + * All rights reserved. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + + +#import "BITFeedbackMessage.h" + +@implementation BITFeedbackMessage + + +#pragma mark - NSObject + +- (id) init { + if ((self = [super init])) { + _text = nil; + _name = nil; + _email = nil; + _date = nil; + _id = [[NSNumber alloc] initWithInteger:0]; + _status = BITFeedbackMessageStatusSendPending; + _userMessage = NO; + } + return self; +} + +- (void)dealloc { + [_text release], _text = nil; + [_name release], _name = nil; + [_email release], _email = nil; + [_date release], _date = nil; + [_id release], _id = nil; + + [super dealloc]; +} + + +#pragma mark - NSCoder + +- (void)encodeWithCoder:(NSCoder *)encoder { + [encoder encodeObject:self.text forKey:@"text"]; + [encoder encodeObject:self.name forKey:@"name"]; + [encoder encodeObject:self.email forKey:@"email"]; + [encoder encodeObject:self.date forKey:@"date"]; + [encoder encodeObject:self.id forKey:@"id"]; + [encoder encodeInteger:self.status forKey:@"status"]; + [encoder encodeInteger:self.userMessage forKey:@"userMessage"]; +} + +- (id)initWithCoder:(NSCoder *)decoder { + if ((self = [super init])) { + self.text = [decoder decodeObjectForKey:@"text"]; + self.name = [decoder decodeObjectForKey:@"name"]; + self.email = [decoder decodeObjectForKey:@"email"]; + self.date = [decoder decodeObjectForKey:@"date"]; + self.id = [decoder decodeObjectForKey:@"id"]; + self.status = [decoder decodeIntegerForKey:@"status"]; + self.userMessage = [decoder decodeIntegerForKey:@"userMessage"]; + } + return self; +} + +@end \ No newline at end of file diff --git a/Classes/Feedback/BITFeedbackUserDataViewController.h b/Classes/Feedback/BITFeedbackUserDataViewController.h new file mode 100644 index 00000000..7a4795b8 --- /dev/null +++ b/Classes/Feedback/BITFeedbackUserDataViewController.h @@ -0,0 +1,51 @@ +/* + * Author: Andreas Linde + * + * Copyright (c) 2012 HockeyApp, Bit Stadium GmbH. + * All rights reserved. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + + +#import + +@protocol BITFeedbackUserDataDelegate; + +@interface BITFeedbackUserDataViewController : UITableViewController + +@property (nonatomic, assign) id delegate; + +@end + +/////////////////////////////////////////////////////////////////////////////////////////////////// +@protocol BITFeedbackUserDataDelegate + +@required + +// cancel action is invoked +- (void)userDataUpdateCancelled; + +// save action is invoked and all required data available +- (void)userDataUpdateFinished; + +@end \ No newline at end of file diff --git a/Classes/Feedback/BITFeedbackUserDataViewController.m b/Classes/Feedback/BITFeedbackUserDataViewController.m new file mode 100644 index 00000000..8fea23b8 --- /dev/null +++ b/Classes/Feedback/BITFeedbackUserDataViewController.m @@ -0,0 +1,255 @@ +/* + * Author: Andreas Linde + * + * Copyright (c) 2012 HockeyApp, Bit Stadium GmbH. + * All rights reserved. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + + +#import "HockeySDK.h" +#import "HockeySDKPrivate.h" + +#import "BITFeedbackUserDataViewController.h" + + +@interface BITFeedbackUserDataViewController () +@property (nonatomic, assign) BITFeedbackManager *manager; + +@property (nonatomic, copy) NSString *name; +@property (nonatomic, copy) NSString *email; +@end + + +@implementation BITFeedbackUserDataViewController + + +- (id)initWithStyle:(UITableViewStyle)style { + self = [super initWithStyle:style]; + if (self) { + self.title = BITHockeyLocalizedString(@"HockeyFeedbackUserDataTitle"); + + _delegate = nil; + + _manager = [BITHockeyManager sharedHockeyManager].feedbackManager; + _name = @""; + _email = @""; + } + return self; +} + +- (void)dealloc { + [_name release], _name = nil; + [_email release], _email = nil; + + [super dealloc]; +} + +- (void)viewDidLoad { + [super viewDidLoad]; + + [self.tableView setScrollEnabled:NO]; + + // Do any additional setup after loading the view. + self.navigationItem.leftBarButtonItem = [[[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemCancel + target:self + action:@selector(dismissAction:)] autorelease]; + + self.navigationItem.rightBarButtonItem = [[[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemSave + target:self + action:@selector(saveAction:)] autorelease]; +} + +- (void)viewDidUnload { + [super viewDidUnload]; + // Release any retained subviews of the main view. + // e.g. self.myOutlet = nil; +} + +- (void)viewWillAppear:(BOOL)animated { + [super viewWillAppear:animated]; + + if ([self.manager userName]) + self.name = [self.manager userName]; + + if ([self.manager userEmail]) + self.email = [self.manager userEmail]; + + [self.manager updateDidAskUserData]; + + self.navigationItem.rightBarButtonItem.enabled = [self allRequiredFieldsEntered]; +} + +- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation { + return (interfaceOrientation == UIInterfaceOrientationPortrait); +} + +#pragma mark - Private methods + +- (BOOL)allRequiredFieldsEntered { + if ([self.manager requireUserName] == BITFeedbackUserDataElementRequired && [self.name length] == 0) + return NO; + + if ([self.manager requireUserEmail] == BITFeedbackUserDataElementRequired && [self.email length] == 0) + return NO; + + return YES; +} + +- (void)userNameEntered:(id)sender { + self.name = [(UITextField *)sender text]; + + self.navigationItem.rightBarButtonItem.enabled = [self allRequiredFieldsEntered]; +} + +- (void)userEmailEntered:(id)sender { + self.email = [(UITextField *)sender text]; + + self.navigationItem.rightBarButtonItem.enabled = [self allRequiredFieldsEntered]; +} + +- (void)dismissAction:(id)sender { + [self.delegate userDataUpdateCancelled]; +} + +- (void)saveAction:(id)sender { + + if ([self.manager requireUserName]) { + [self.manager setUserName:self.name]; + } + + if ([self.manager requireUserEmail]) { + [self.manager setUserEmail:self.email]; + } + + [self.delegate userDataUpdateFinished]; +} + +#pragma mark - Table view data source + +- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { + return 1; +} + +- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { + NSInteger rows = 0; + + if ([self.manager requireUserName] != BITFeedbackUserDataElementDontShow) + rows ++; + + if ([self.manager requireUserEmail] != BITFeedbackUserDataElementDontShow) + rows ++; + + return rows; +} + +- (NSString *)tableView:(UITableView *)tableView titleForFooterInSection:(NSInteger)section { + if (section == 0) { + return BITHockeyLocalizedString(@"HockeyFeedbackUserDataDescription"); + } + + return nil; +} + +- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { + static NSString *CellIdentifier = @"InputCell"; + + UITableViewCell *cell = [self.tableView dequeueReusableCellWithIdentifier:CellIdentifier]; + if (cell == nil) { + cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease]; + + cell.accessoryType = UITableViewCellAccessoryNone; + cell.selectionStyle = UITableViewCellSelectionStyleNone; + cell.backgroundColor = [UIColor whiteColor]; + + UITextField *textField = [[[UITextField alloc] initWithFrame:CGRectMake(110, 10, 185, 30)] autorelease]; + textField.adjustsFontSizeToFitWidth = YES; + textField.textColor = [UIColor blackColor]; + textField.backgroundColor = [UIColor lightGrayColor]; + + if ([indexPath row] == 0 && [self.manager requireUserName] != BITFeedbackUserDataElementDontShow) { + textField.placeholder = BITHockeyLocalizedString(@"HockeyFeedbackUserDataNamePlaceHolder"); + textField.text = self.name; + + textField.keyboardType = UIKeyboardTypeDefault; + if ([self.manager requireUserEmail]) + textField.returnKeyType = UIReturnKeyNext; + else + textField.returnKeyType = UIReturnKeyDone; + [textField addTarget:self action:@selector(userNameEntered:) forControlEvents:UIControlEventEditingChanged]; + [textField becomeFirstResponder]; + } else { + textField.placeholder = BITHockeyLocalizedString(@"HockeyFeedbackUserDataEmailPlaceholder"); + textField.text = self.email; + + textField.keyboardType = UIKeyboardTypeEmailAddress; + textField.returnKeyType = UIReturnKeyDone; + [textField addTarget:self action:@selector(userEmailEntered:) forControlEvents:UIControlEventEditingChanged]; + if (![self.manager requireUserName]) + [textField becomeFirstResponder]; + } + + textField.backgroundColor = [UIColor whiteColor]; + textField.autocorrectionType = UITextAutocorrectionTypeNo; + textField.autocapitalizationType = UITextAutocapitalizationTypeNone; + textField.textAlignment = UITextAlignmentLeft; + textField.delegate = self; + textField.tag = indexPath.row; + + textField.clearButtonMode = UITextFieldViewModeWhileEditing; + [textField setEnabled: YES]; + + [cell addSubview:textField]; + } + + if ([indexPath row] == 0 && [self.manager requireUserName] != BITFeedbackUserDataElementDontShow) { + cell.textLabel.text = BITHockeyLocalizedString(@"HockeyFeedbackUserDataName"); + } else { + cell.textLabel.text = BITHockeyLocalizedString(@"HockeyFeedbackUserDataEmail"); + } + + return cell; +} + + +#pragma mark - UITextFieldDelegate + +- (BOOL)textFieldShouldReturn:(UITextField *)textField { + NSInteger nextTag = textField.tag + 1; + + UIResponder* nextResponder = [self.view viewWithTag:nextTag]; + if (nextResponder) { + [nextResponder becomeFirstResponder]; + } else { + if ([self allRequiredFieldsEntered]) { + if ([textField isFirstResponder]) + [textField resignFirstResponder]; + + [self saveAction:nil]; + } + } + return NO; +} + + +@end diff --git a/Classes/Helper/BITHockeyBaseManager.h b/Classes/Helper/BITHockeyBaseManager.h new file mode 100644 index 00000000..fd94e6f2 --- /dev/null +++ b/Classes/Helper/BITHockeyBaseManager.h @@ -0,0 +1,29 @@ +// +// CNSHockeyBaseManager.h +// HockeySDK +// +// Created by Andreas Linde on 04.06.12. +// Copyright (c) 2012 __MyCompanyName__. All rights reserved. +// + +#import +#import + + + +@interface BITHockeyBaseManager : NSObject + +///----------------------------------------------------------------------------- +/// @name Delegate +///----------------------------------------------------------------------------- + +/** + Sets the `BITUpdateManagerDelegate` delegate. + + When using `BITUpdateManager` to distribute updates of your beta or enterprise + application, it is _REQUIRED_ to set this delegate and implement + `[BITUpdateManagerDelegate customDeviceIdentifierForUpdateManager:]`! + */ +@property (nonatomic, assign) id delegate; + +@end diff --git a/Classes/Helper/BITHockeyBaseManager.m b/Classes/Helper/BITHockeyBaseManager.m new file mode 100644 index 00000000..b6b9aa5d --- /dev/null +++ b/Classes/Helper/BITHockeyBaseManager.m @@ -0,0 +1,192 @@ +// +// CNSHockeyBaseManager.m +// HockeySDK +// +// Created by Andreas Linde on 04.06.12. +// Copyright (c) 2012 __MyCompanyName__. All rights reserved. +// + +#import "HockeySDK.h" +#import "HockeySDKPrivate.h" + +#import "BITHockeyHelper.h" + +#import "BITHockeyBaseManager.h" +#import "BITHockeyBaseManagerPrivate.h" +#import "BITHockeyBaseViewController.h" + +#import "BITHockeyManagerPrivate.h" + +#import + + +@implementation BITHockeyBaseManager + + +- (id)init { + if ((self = [super init])) { + _isAppStoreEnvironment = NO; + _appIdentifier = nil; + + _navController = nil; + _barStyle = UIBarStyleDefault; + _modalPresentationStyle = UIModalPresentationFormSheet; + + _rfc3339Formatter = [[NSDateFormatter alloc] init]; + [_rfc3339Formatter setLocale:[[[NSLocale alloc] initWithLocaleIdentifier:@"en_US_POSIX"] autorelease]]; + [_rfc3339Formatter setDateFormat:@"yyyy-MM-dd'T'HH:mm:ss'Z'"]; + } + return self; +} + +- (id)initWithAppIdentifier:(NSString *)appIdentifier isAppStoreEnvironemt:(BOOL)isAppStoreEnvironment { + if ((self = [self init])) { + + self.appIdentifier = appIdentifier; + _isAppStoreEnvironment = isAppStoreEnvironment; + + } + return self; +} + + +- (void)dealloc { + [_appIdentifier release]; + + [_navController release], _navController = nil; + + [_rfc3339Formatter release], _rfc3339Formatter = nil; + + [super dealloc]; +} + + +#pragma mark - Private + +- (void)reportError:(NSError *)error { + BITHockeyLog(@"Error: %@", [error localizedDescription]); +} + +- (NSString *)encodedAppIdentifier { + return (_appIdentifier ? bit_URLEncodedString(_appIdentifier) : bit_URLEncodedString([[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleIdentifier"])); +} + +- (NSString *)getDevicePlatform { + size_t size; + sysctlbyname("hw.machine", NULL, &size, NULL, 0); + char *answer = (char*)malloc(size); + sysctlbyname("hw.machine", answer, &size, NULL, 0); + NSString *platform = [NSString stringWithCString:answer encoding: NSUTF8StringEncoding]; + free(answer); + return platform; +} + +- (UIWindow *)findVisibleWindow { + UIWindow *visibleWindow = nil; + + // if the rootViewController property (available >= iOS 4.0) of the main window is set, we present the modal view controller on top of the rootViewController + NSArray *windows = [[UIApplication sharedApplication] windows]; + for (UIWindow *window in windows) { + if (!window.hidden && !visibleWindow) { + visibleWindow = window; + } + if ([UIWindow instancesRespondToSelector:@selector(rootViewController)]) { + if ([window rootViewController]) { + visibleWindow = window; + BITHockeyLog(@"INFO: UIWindow with rootViewController found: %@", visibleWindow); + break; + } + } + } + + return visibleWindow; +} + +- (void)showView:(BITHockeyBaseViewController *)viewController { + UIViewController *parentViewController = nil; + + if ([[BITHockeyManager sharedHockeyManager].delegate respondsToSelector:@selector(viewControllerForHockeyManager:componentManager:)]) { + parentViewController = [[BITHockeyManager sharedHockeyManager].delegate viewControllerForHockeyManager:[BITHockeyManager sharedHockeyManager] componentManager:self]; + } + + UIWindow *visibleWindow = [self findVisibleWindow]; + + if (parentViewController == nil && [UIWindow instancesRespondToSelector:@selector(rootViewController)]) { + parentViewController = [visibleWindow rootViewController]; + } + + // use topmost modal view + while (parentViewController.modalViewController) { + parentViewController = parentViewController.modalViewController; + } + + // special addition to get rootViewController from three20 which has it's own controller handling + if (NSClassFromString(@"TTNavigator")) { + parentViewController = [[NSClassFromString(@"TTNavigator") performSelector:(NSSelectorFromString(@"navigator"))] visibleViewController]; + } + + if (_navController != nil) [_navController release], _navController = nil; + + _navController = [[UINavigationController alloc] initWithRootViewController:viewController]; + _navController.navigationBar.barStyle = _barStyle; + _navController.modalPresentationStyle = _modalPresentationStyle; + + if (parentViewController) { + if ([_navController respondsToSelector:@selector(setModalTransitionStyle:)]) { + _navController.modalTransitionStyle = UIModalTransitionStyleCoverVertical; + } + + // page sheet for the iPad + if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad && [_navController respondsToSelector:@selector(setModalPresentationStyle:)]) { + _navController.modalPresentationStyle = UIModalPresentationFormSheet; + } + + viewController.modalAnimated = YES; + + [parentViewController presentModalViewController:_navController animated:YES]; + } else { + // if not, we add a subview to the window. A bit hacky but should work in most circumstances. + // Also, we don't get a nice animation for free, but hey, this is for beta not production users ;) + BITHockeyLog(@"INFO: No rootViewController found, using UIWindow-approach: %@", visibleWindow); + viewController.modalAnimated = NO; + [visibleWindow addSubview:_navController.view]; + } +} + +#pragma mark - Manager Control + +- (void)startManager { +} + + +#pragma mark - Networking + +- (NSData *)appendPostValue:(NSString *)value forKey:(NSString *)key { + NSString *boundary = @"----FOO"; + + NSMutableData *postBody = [NSMutableData data]; + + [postBody appendData:[[NSString stringWithFormat:@"--%@\r\n", boundary] dataUsingEncoding:NSUTF8StringEncoding]]; + [postBody appendData:[[NSString stringWithFormat:@"Content-Disposition: form-data; name=\"%@\";\r\n", key] dataUsingEncoding:NSUTF8StringEncoding]]; + [postBody appendData:[[NSString stringWithFormat:@"Content-Type: text\r\n\r\n"] dataUsingEncoding:NSUTF8StringEncoding]]; + [postBody appendData:[value dataUsingEncoding:NSUTF8StringEncoding]]; + [postBody appendData:[@"\r\n" dataUsingEncoding:NSUTF8StringEncoding]]; + + return postBody; +} + + +#pragma mark - Helpers + +- (NSDate *)parseRFC3339Date:(NSString *)dateString { + NSDate *date = nil; + NSError *error = nil; + if (![_rfc3339Formatter getObjectValue:&date forString:dateString range:nil error:&error]) { + BITHockeyLog(@"INFO: Invalid date '%@' string: %@", dateString, error); + } + + return date; +} + + +@end diff --git a/Classes/Helper/BITHockeyBaseManagerPrivate.h b/Classes/Helper/BITHockeyBaseManagerPrivate.h new file mode 100644 index 00000000..d4696049 --- /dev/null +++ b/Classes/Helper/BITHockeyBaseManagerPrivate.h @@ -0,0 +1,46 @@ +// +// CNSHockeyBaseManager+Private.h +// HockeySDK +// +// Created by Andreas Linde on 04.06.12. +// Copyright (c) 2012 __MyCompanyName__. All rights reserved. +// + +#import +#import + +@class BITHockeyBaseManager; +@class BITHockeyBaseViewController; + +@interface BITHockeyBaseManager() { + UINavigationController *_navController; + UIBarStyle _barStyle; + UIModalPresentationStyle _modalPresentationStyle; + + NSDateFormatter *_rfc3339Formatter; + + BOOL _isAppStoreEnvironment; +} + +// set the server URL +@property (nonatomic, retain) NSString *serverURL; + +@property (nonatomic, retain) NSString *appIdentifier; + +- (id)initWithAppIdentifier:(NSString *)appIdentifier isAppStoreEnvironemt:(BOOL)isAppStoreEnvironment; + +- (void)startManager; + +- (void)reportError:(NSError *)error; +- (NSString *)encodedAppIdentifier; + +- (NSString *)getDevicePlatform; + +- (UIWindow *)findVisibleWindow; +- (void)showView:(BITHockeyBaseViewController *)viewController; + +- (NSData *)appendPostValue:(NSString *)value forKey:(NSString *)key; + +- (NSDate *)parseRFC3339Date:(NSString *)dateString; + +@end \ No newline at end of file diff --git a/Classes/Helper/BITHockeyBaseViewController.h b/Classes/Helper/BITHockeyBaseViewController.h new file mode 100644 index 00000000..5196ec95 --- /dev/null +++ b/Classes/Helper/BITHockeyBaseViewController.h @@ -0,0 +1,17 @@ +// +// CNSHockeyBaseViewController.h +// HockeySDK +// +// Created by Andreas Linde on 04.06.12. +// Copyright (c) 2012 __MyCompanyName__. All rights reserved. +// + +#import + +@interface BITHockeyBaseViewController : UIViewController + +@property (nonatomic, readwrite) BOOL modalAnimated; + +- (id)initWithModalStyle:(BOOL)modal; + +@end diff --git a/Classes/Helper/BITHockeyBaseViewController.m b/Classes/Helper/BITHockeyBaseViewController.m new file mode 100644 index 00000000..8e65ec3d --- /dev/null +++ b/Classes/Helper/BITHockeyBaseViewController.m @@ -0,0 +1,118 @@ +// +// CNSHockeyBaseViewController.m +// HockeySDK +// +// Created by Andreas Linde on 04.06.12. +// Copyright (c) 2012 __MyCompanyName__. All rights reserved. +// + +#import "BITHockeyBaseViewController.h" + +@interface BITHockeyBaseViewController () +@property (nonatomic) BOOL modal; +@property (nonatomic) UIStatusBarStyle statusBarStyle; +@end + +@implementation BITHockeyBaseViewController + +@synthesize modalAnimated = _modalAnimated; +@synthesize modal = _modal; +@synthesize statusBarStyle = _statusBarStyle; + + +- (id)init { + self = [super init]; + if (self) { + _modalAnimated = YES; + _modal = NO; + } + return self; +} + +- (id)initWithModalStyle:(BOOL)modal { + self = [self init]; + if (self) { + _modal = modal; + } + return self; +} + + +#pragma mark - View lifecycle + +- (void)onDismissModal:(id)sender { + if (self.modal) { + // Note that as of 5.0, parentViewController will no longer return the presenting view controller + SEL presentingViewControllerSelector = NSSelectorFromString(@"presentingViewController"); + UIViewController *presentingViewController = nil; + if ([self respondsToSelector:presentingViewControllerSelector]) { + presentingViewController = [self performSelector:presentingViewControllerSelector]; + } else { + presentingViewController = [self parentViewController]; + } + + // If there is no presenting view controller just remove view + if (presentingViewController && self.modalAnimated) { + [presentingViewController dismissModalViewControllerAnimated:YES]; + } else { + [self.navigationController.view removeFromSuperview]; + } + } else { + [self.navigationController popViewControllerAnimated:YES]; + } + + [[UIApplication sharedApplication] setStatusBarStyle:_statusBarStyle]; +} + +- (void)viewDidLoad { + [super viewDidLoad]; + + if (self.modal) { + self.navigationItem.leftBarButtonItem = [[[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemDone + target:self + action:@selector(onDismissModal:)] autorelease]; + } + + // Do any additional setup after loading the view. +} + +- (void)viewDidUnload { + [super viewDidUnload]; + // Release any retained subviews of the main view. +} + +- (void)viewWillAppear:(BOOL)animated { + [super viewWillAppear:animated]; + + _statusBarStyle = [[UIApplication sharedApplication] statusBarStyle]; + [[UIApplication sharedApplication] setStatusBarStyle:(self.navigationController.navigationBar.barStyle == UIBarStyleDefault) ? UIStatusBarStyleDefault : UIStatusBarStyleBlackOpaque]; +} + +- (void)viewWillDisappear:(BOOL)animated { + [super viewWillDisappear:animated]; + + [[UIApplication sharedApplication] setStatusBarStyle:_statusBarStyle]; +} + + +#pragma mark - Rotation + +- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation { + BOOL shouldAutorotate; + + if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone) { + shouldAutorotate = (interfaceOrientation == UIInterfaceOrientationLandscapeLeft || + interfaceOrientation == UIInterfaceOrientationLandscapeRight || + interfaceOrientation == UIInterfaceOrientationPortrait); + } else { + shouldAutorotate = YES; + } + + return shouldAutorotate; +} + + +#pragma mark - Modal presentation + + +@end diff --git a/Classes/BITHockeyHelper.h b/Classes/Helper/BITHockeyHelper.h similarity index 94% rename from Classes/BITHockeyHelper.h rename to Classes/Helper/BITHockeyHelper.h index a7b48cc3..3e7ceec8 100644 --- a/Classes/BITHockeyHelper.h +++ b/Classes/Helper/BITHockeyHelper.h @@ -33,6 +33,8 @@ NSString *bit_URLEncodedString(NSString *inputString); NSString *bit_URLDecodedString(NSString *inputString); NSComparisonResult bit_versionCompare(NSString *stringA, NSString *stringB); +id bit_parseJSON(NSString *inputString, NSError **error); +NSString *bit_encodeAppIdentifier(NSString *inputString); /* UIImage helpers */ UIImage *bit_roundedCornerImage(UIImage *inputImage, NSInteger cornerSize, NSInteger borderSize); diff --git a/Classes/BITHockeyHelper.m b/Classes/Helper/BITHockeyHelper.m similarity index 82% rename from Classes/BITHockeyHelper.m rename to Classes/Helper/BITHockeyHelper.m index 7f5c875f..4e7dfeda 100644 --- a/Classes/BITHockeyHelper.m +++ b/Classes/Helper/BITHockeyHelper.m @@ -28,6 +28,8 @@ #import "BITHockeyHelper.h" +#import "HockeySDK.h" + #pragma mark NSString helpers @@ -74,6 +76,88 @@ NSComparisonResult bit_versionCompare(NSString *stringA, NSString *stringB) { return result; } +// parse JSON depending on the available framework +id bit_parseJSON(NSString *inputString, NSError **error) { + error = nil; + + if (!inputString) + return nil; + + id feedResult = nil; + +#if BW_NATIVE_JSON_AVAILABLE + feedResult = [NSJSONSerialization JSONObjectWithData:[jsonString dataUsingEncoding:NSUTF8StringEncoding] options:kNilOptions error:&error]; +#else + id nsjsonClass = NSClassFromString(@"NSJSONSerialization"); + SEL nsjsonSelect = NSSelectorFromString(@"JSONObjectWithData:options:error:"); + SEL sbJSONSelector = NSSelectorFromString(@"JSONValue"); + SEL jsonKitSelector = NSSelectorFromString(@"objectFromJSONStringWithParseOptions:error:"); + SEL yajlSelector = NSSelectorFromString(@"yajl_JSONWithOptions:error:"); + + if (nsjsonClass && [nsjsonClass respondsToSelector:nsjsonSelect]) { + NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:[nsjsonClass methodSignatureForSelector:nsjsonSelect]]; + invocation.target = nsjsonClass; + invocation.selector = nsjsonSelect; + NSData *jsonData = [inputString dataUsingEncoding:NSUTF8StringEncoding]; + + if (!jsonData) + return nil; + + [invocation setArgument:&jsonData atIndex:2]; // arguments 0 and 1 are self and _cmd respectively, automatically set by NSInvocation + NSUInteger readOptions = kNilOptions; + [invocation setArgument:&readOptions atIndex:3]; + [invocation setArgument:&error atIndex:4]; + [invocation invoke]; + [invocation getReturnValue:&feedResult]; + } else if (jsonKitSelector && [inputString respondsToSelector:jsonKitSelector]) { + // first try JSONkit + NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:[inputString methodSignatureForSelector:jsonKitSelector]]; + invocation.target = inputString; + invocation.selector = jsonKitSelector; + int parseOptions = 0; + [invocation setArgument:&parseOptions atIndex:2]; // arguments 0 and 1 are self and _cmd respectively, automatically set by NSInvocation + [invocation setArgument:&error atIndex:3]; + [invocation invoke]; + [invocation getReturnValue:&feedResult]; + } else if (sbJSONSelector && [inputString respondsToSelector:sbJSONSelector]) { + // now try SBJson + NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:[inputString methodSignatureForSelector:sbJSONSelector]]; + invocation.target = inputString; + invocation.selector = sbJSONSelector; + [invocation invoke]; + [invocation getReturnValue:&feedResult]; + } else if (yajlSelector && [inputString respondsToSelector:yajlSelector]) { + NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:[inputString methodSignatureForSelector:yajlSelector]]; + invocation.target = inputString; + invocation.selector = yajlSelector; + + NSUInteger yajlParserOptions = 0; + [invocation setArgument:&yajlParserOptions atIndex:2]; // arguments 0 and 1 are self and _cmd respectively, automatically set by NSInvocation + [invocation setArgument:&error atIndex:3]; + + [invocation invoke]; + [invocation getReturnValue:&feedResult]; + } else { + if (error != NULL) + *error = [[NSError errorWithDomain:kBITHockeyErrorDomain + code:HockeyAPIClientMissingJSONLibrary + userInfo:[NSDictionary dictionaryWithObjectsAndKeys:@"You need a JSON Framework in your runtime for iOS4!", NSLocalizedDescriptionKey, nil]] retain]; + return nil; + } +#endif + + if (error != NULL) { + return nil; + } + + return feedResult; +} + +NSString *bit_encodeAppIdentifier(NSString *inputString) { + return (inputString ? bit_URLEncodedString(inputString) : bit_URLEncodedString([[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleIdentifier"])); +} + + #pragma mark UIImage private helpers diff --git a/Classes/HockeySDKPrivate.h b/Classes/Helper/HockeySDKPrivate.h similarity index 96% rename from Classes/HockeySDKPrivate.h rename to Classes/Helper/HockeySDKPrivate.h index fc3d8a30..75f638d2 100644 --- a/Classes/HockeySDKPrivate.h +++ b/Classes/Helper/HockeySDKPrivate.h @@ -39,6 +39,8 @@ #define BITHOCKEY_CRASH_SETTINGS @"BITCrashManager.plist" #define BITHOCKEY_CRASH_ANALYZER @"BITCrashManager.analyzer" +#define BITHOCKEY_FEEDBACK_SETTINGS @"BITFeedbackManager.plist" + #define kBITUpdateArrayOfLastCheck @"BITUpdateArrayOfLastCheck" #define kBITUpdateDateOfLastCheck @"BITUpdateDateOfLastCheck" #define kBITUpdateDateOfVersionInstallation @"BITUpdateDateOfVersionInstallation" @@ -61,6 +63,7 @@ NSBundle *BITHockeyBundle(void); NSString *BITHockeyLocalizedString(NSString *stringToken); NSString *BITHockeyMD5(NSString *str); +id BITHockeyParseJSON(NSString *str, NSError **error); // compatibility helper diff --git a/Classes/HockeySDKPrivate.m b/Classes/Helper/HockeySDKPrivate.m similarity index 99% rename from Classes/HockeySDKPrivate.m rename to Classes/Helper/HockeySDKPrivate.m index e223438e..fa879de6 100644 --- a/Classes/HockeySDKPrivate.m +++ b/Classes/Helper/HockeySDKPrivate.m @@ -27,6 +27,7 @@ * OTHER DEALINGS IN THE SOFTWARE. */ +#import "HockeySDK.h" #import "HockeySDKPrivate.h" #include @@ -66,4 +67,4 @@ result[12], result[13], result[14], result[15] ]; -} \ No newline at end of file +} diff --git a/Classes/PSAppStoreHeader.h b/Classes/Helper/PSAppStoreHeader.h similarity index 100% rename from Classes/PSAppStoreHeader.h rename to Classes/Helper/PSAppStoreHeader.h diff --git a/Classes/PSAppStoreHeader.m b/Classes/Helper/PSAppStoreHeader.m similarity index 100% rename from Classes/PSAppStoreHeader.m rename to Classes/Helper/PSAppStoreHeader.m diff --git a/Classes/PSStoreButton.h b/Classes/Helper/PSStoreButton.h similarity index 100% rename from Classes/PSStoreButton.h rename to Classes/Helper/PSStoreButton.h diff --git a/Classes/PSStoreButton.m b/Classes/Helper/PSStoreButton.m similarity index 100% rename from Classes/PSStoreButton.m rename to Classes/Helper/PSStoreButton.m diff --git a/Classes/PSWebTableViewCell.h b/Classes/Helper/PSWebTableViewCell.h similarity index 100% rename from Classes/PSWebTableViewCell.h rename to Classes/Helper/PSWebTableViewCell.h diff --git a/Classes/PSWebTableViewCell.m b/Classes/Helper/PSWebTableViewCell.m similarity index 100% rename from Classes/PSWebTableViewCell.m rename to Classes/Helper/PSWebTableViewCell.m diff --git a/Classes/HockeySDK.h b/Classes/HockeySDK.h index c2a78f7f..49cd8968 100644 --- a/Classes/HockeySDK.h +++ b/Classes/HockeySDK.h @@ -33,6 +33,8 @@ #import "BITHockeyManager.h" #import "BITHockeyManagerDelegate.h" +#import "BITHockeyBaseManager.h" + #import "BITCrashManager.h" #import "BITCrashManagerDelegate.h" @@ -40,10 +42,20 @@ #import "BITUpdateManagerDelegate.h" #import "BITUpdateViewController.h" +#import "BITFeedbackManager.h" +#import "BITFeedbackComposeViewController.h" +#import "BITFeedbackListViewController.h" + // Notification message which HockeyManager is listening to, to retry requesting updated from the server #define BITHockeyNetworkDidBecomeReachableNotification @"BITHockeyNetworkDidBecomeReachable" +// Notification message which tells that messages got updated or added +#define BITHockeyFeedbackMessagesUpdated @"BITHockeyFeedbackMessagesUpdated" + +// Notification message which tells that new messages arrived +#define BITHockeyFeedbackNewMessagesReceived @"BITHockeyFeedbackNewMessagesReceived" + // hockey api error domain typedef enum { @@ -69,4 +81,28 @@ typedef enum { static NSString *kBITUpdateErrorDomain = @"BITUpdaterErrorDomain"; +// Update App Versions + +// hockey api error domain +typedef enum { + BITFeedbackErrorUnknown, + BITFeedbackAPIServerReturnedInvalidStatus, + BITFeedbackAPIServerReturnedInvalidData, + BITFeedbackAPIServerReturnedEmptyResponse, + BITFeedbackAPIClientAuthorizationMissingSecret, + BITFeedbackAPIClientCannotCreateConnection +} BITFeedbackErrorReason; +static NSString *kBITFeedbackErrorDomain = @"BITFeedbackErrorDomain"; + + +// HockeySDK + +// hockey api error domain +typedef enum { + BITHockeyErrorUnknown, + HockeyAPIClientMissingJSONLibrary +} BITHockeyErrorReason; +static NSString *kBITHockeyErrorDomain = @"BITHockeyErrorDomain"; + + #endif diff --git a/Classes/BITAppVersionMetaInfo.h b/Classes/Update/BITAppVersionMetaInfo.h similarity index 100% rename from Classes/BITAppVersionMetaInfo.h rename to Classes/Update/BITAppVersionMetaInfo.h diff --git a/Classes/BITAppVersionMetaInfo.m b/Classes/Update/BITAppVersionMetaInfo.m similarity index 100% rename from Classes/BITAppVersionMetaInfo.m rename to Classes/Update/BITAppVersionMetaInfo.m diff --git a/Classes/BITUpdateManager.h b/Classes/Update/BITUpdateManager.h similarity index 100% rename from Classes/BITUpdateManager.h rename to Classes/Update/BITUpdateManager.h diff --git a/Classes/BITUpdateManager.m b/Classes/Update/BITUpdateManager.m similarity index 89% rename from Classes/BITUpdateManager.m rename to Classes/Update/BITUpdateManager.m index a9bd03a4..afd3a39b 100644 --- a/Classes/BITUpdateManager.m +++ b/Classes/Update/BITUpdateManager.m @@ -54,28 +54,6 @@ @implementation BITUpdateManager -@synthesize delegate = _delegate; - -@synthesize urlConnection = _urlConnection; -@synthesize checkInProgress = _checkInProgress; -@synthesize receivedData = _receivedData; -@synthesize alwaysShowUpdateReminder = _showUpdateReminder; -@synthesize checkForUpdateOnLaunch = _checkForUpdateOnLaunch; -@synthesize compareVersionType = _compareVersionType; -@synthesize lastCheck = _lastCheck; -@synthesize updateSetting = _updateSetting; -@synthesize appVersions = _appVersions; -@synthesize updateAvailable = _updateAvailable; -@synthesize usageStartTimestamp = _usageStartTimestamp; -@synthesize currentHockeyViewController = _currentHockeyViewController; -@synthesize showDirectInstallOption = _showDirectInstallOption; -@synthesize requireAuthorization = _requireAuthorization; -@synthesize authenticationSecret = _authenticationSecret; -@synthesize blockingView = _blockingView; -@synthesize checkForTracker = _checkForTracker; -@synthesize trackerConfig = _trackerConfig; -@synthesize barStyle = _barStyle; -@synthesize modalPresentationStyle = _modalPresentationStyle; #pragma mark - private @@ -354,7 +332,7 @@ - (id)initWithAppIdentifier:(NSString *)appIdentifier isAppStoreEnvironemt:(BOOL _appIdentifier = appIdentifier; _isAppStoreEnvironment = isAppStoreEnvironment; - _updateURL = BITHOCKEYSDK_URL; + _serverURL = BITHOCKEYSDK_URL; _delegate = nil; _expiryDate = nil; _checkInProgress = NO; @@ -422,8 +400,7 @@ - (void)dealloc { _delegate = nil; - [_updateURL release]; - _updateURL = nil; + [_serverURL release]; [_urlConnection cancel]; self.urlConnection = nil; @@ -607,83 +584,6 @@ - (void)showBlockingScreen:(NSString *)message image:(NSString *)image { } -#pragma mark - JSONParsing - -- (id)parseJSONResultString:(NSString *)jsonString { - NSError *error = nil; - id feedResult = nil; - - if (!jsonString) - return nil; - -#if BITHOCKEYSDK_NATIVE_JSON_AVAILABLE - feedResult = [NSJSONSerialization JSONObjectWithData:[jsonString dataUsingEncoding:NSUTF8StringEncoding] options:kNilOptions error:&error]; -#else - id nsjsonClass = NSClassFromString(@"NSJSONSerialization"); - SEL nsjsonSelect = NSSelectorFromString(@"JSONObjectWithData:options:error:"); - SEL sbJSONSelector = NSSelectorFromString(@"JSONValue"); - SEL jsonKitSelector = NSSelectorFromString(@"objectFromJSONStringWithParseOptions:error:"); - SEL yajlSelector = NSSelectorFromString(@"yajl_JSONWithOptions:error:"); - - if (nsjsonClass && [nsjsonClass respondsToSelector:nsjsonSelect]) { - NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:[nsjsonClass methodSignatureForSelector:nsjsonSelect]]; - invocation.target = nsjsonClass; - invocation.selector = nsjsonSelect; - NSData *jsonData = [jsonString dataUsingEncoding:NSUTF8StringEncoding]; - - if (!jsonData) - return nil; - - [invocation setArgument:&jsonData atIndex:2]; // arguments 0 and 1 are self and _cmd respectively, automatically set by NSInvocation - NSUInteger readOptions = kNilOptions; - [invocation setArgument:&readOptions atIndex:3]; - [invocation setArgument:&error atIndex:4]; - [invocation invoke]; - [invocation getReturnValue:&feedResult]; - } else if (jsonKitSelector && [jsonString respondsToSelector:jsonKitSelector]) { - // first try JSONkit - NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:[jsonString methodSignatureForSelector:jsonKitSelector]]; - invocation.target = jsonString; - invocation.selector = jsonKitSelector; - int parseOptions = 0; - [invocation setArgument:&parseOptions atIndex:2]; // arguments 0 and 1 are self and _cmd respectively, automatically set by NSInvocation - [invocation setArgument:&error atIndex:3]; - [invocation invoke]; - [invocation getReturnValue:&feedResult]; - } else if (sbJSONSelector && [jsonString respondsToSelector:sbJSONSelector]) { - // now try SBJson - NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:[jsonString methodSignatureForSelector:sbJSONSelector]]; - invocation.target = jsonString; - invocation.selector = sbJSONSelector; - [invocation invoke]; - [invocation getReturnValue:&feedResult]; - } else if (yajlSelector && [jsonString respondsToSelector:yajlSelector]) { - NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:[jsonString methodSignatureForSelector:yajlSelector]]; - invocation.target = jsonString; - invocation.selector = yajlSelector; - - NSUInteger yajlParserOptions = 0; - [invocation setArgument:&yajlParserOptions atIndex:2]; // arguments 0 and 1 are self and _cmd respectively, automatically set by NSInvocation - [invocation setArgument:&error atIndex:3]; - - [invocation invoke]; - [invocation getReturnValue:&feedResult]; - } else { - error = [NSError errorWithDomain:kBITUpdateErrorDomain - code:BITUpdateAPIServerReturnedEmptyResponse - userInfo:[NSDictionary dictionaryWithObjectsAndKeys:@"You need a JSON Framework in your runtime for iOS4!", NSLocalizedDescriptionKey, nil]]; - } -#endif - - if (error) { - [self reportError:error]; - return nil; - } - - return feedResult; -} - - #pragma mark - RequestComments - (BOOL)shouldCheckForUpdates { @@ -723,7 +623,7 @@ - (void)checkForAuthorization { ]; // build request & send - NSString *url = [NSString stringWithFormat:@"%@%@", _updateURL, parameter]; + NSString *url = [NSString stringWithFormat:@"%@%@", _serverURL, parameter]; BITHockeyLog(@"INFO: Sending api request to %@", url); NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:url] cachePolicy:1 timeoutInterval:10.0]; @@ -739,7 +639,7 @@ - (void)checkForAuthorization { if ([responseData length]) { NSString *responseString = [[[NSString alloc] initWithBytes:[responseData bytes] length:[responseData length] encoding: NSUTF8StringEncoding] autorelease]; - NSDictionary *feedDict = (NSDictionary *)[self parseJSONResultString:responseString]; + NSDictionary *feedDict = (NSDictionary *)bit_parseJSON(responseString, &error); // server returned empty response? if (![feedDict count]) { @@ -838,7 +738,7 @@ - (void)checkForUpdateShowFeedback:(BOOL)feedback { } // build request & send - NSString *url = [NSString stringWithFormat:@"%@%@", _updateURL, parameter]; + NSString *url = [NSString stringWithFormat:@"%@%@", _serverURL, parameter]; BITHockeyLog(@"INFO: Sending api request to %@", url); NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:url] cachePolicy:1 timeoutInterval:10.0]; @@ -874,7 +774,7 @@ - (BOOL)initiateAppDownload { extraParameter = [NSString stringWithFormat:@"&udid=%@", [self deviceIdentifier]]; } - NSString *hockeyAPIURL = [NSString stringWithFormat:@"%@api/2/apps/%@?format=plist%@", _updateURL, [self encodedAppIdentifier], extraParameter]; + NSString *hockeyAPIURL = [NSString stringWithFormat:@"%@api/2/apps/%@?format=plist%@", _serverURL, [self encodedAppIdentifier], extraParameter]; NSString *iOSUpdateURL = [NSString stringWithFormat:@"itms-services://?action=download-manifest&url=%@", bit_URLEncodedString(hockeyAPIURL)]; BITHockeyLog(@"INFO: API Server Call: %@, calling iOS with %@", hockeyAPIURL, iOSUpdateURL); @@ -995,7 +895,8 @@ - (void)connectionDidFinishLoading:(NSURLConnection *)connection { NSString *responseString = [[[NSString alloc] initWithBytes:[_receivedData bytes] length:[_receivedData length] encoding: NSUTF8StringEncoding] autorelease]; BITHockeyLog(@"INFO: Received API response: %@", responseString); - id json = [self parseJSONResultString:responseString]; + NSError *error = nil; + id json = bit_parseJSON(responseString, &error); self.trackerConfig = (([self checkForTracker] && [[json valueForKey:@"tracker"] isKindOfClass:[NSDictionary class]]) ? [json valueForKey:@"tracker"] : nil); if (!_isAppStoreEnvironment) { diff --git a/Classes/BITUpdateManagerDelegate.h b/Classes/Update/BITUpdateManagerDelegate.h similarity index 100% rename from Classes/BITUpdateManagerDelegate.h rename to Classes/Update/BITUpdateManagerDelegate.h diff --git a/Classes/BITUpdateManagerPrivate.h b/Classes/Update/BITUpdateManagerPrivate.h similarity index 98% rename from Classes/BITUpdateManagerPrivate.h rename to Classes/Update/BITUpdateManagerPrivate.h index 51726531..8ab3da34 100644 --- a/Classes/BITUpdateManagerPrivate.h +++ b/Classes/Update/BITUpdateManagerPrivate.h @@ -36,7 +36,7 @@ } // set the server URL -@property (nonatomic, retain) NSString *updateURL; +@property (nonatomic, retain) NSString *serverURL; // is an update available? @property (nonatomic, assign, getter=isUpdateAvailable) BOOL updateAvailable; diff --git a/Classes/BITUpdateViewController.h b/Classes/Update/BITUpdateViewController.h similarity index 100% rename from Classes/BITUpdateViewController.h rename to Classes/Update/BITUpdateViewController.h diff --git a/Classes/BITUpdateViewController.m b/Classes/Update/BITUpdateViewController.m similarity index 100% rename from Classes/BITUpdateViewController.m rename to Classes/Update/BITUpdateViewController.m diff --git a/Classes/BITUpdateViewControllerPrivate.h b/Classes/Update/BITUpdateViewControllerPrivate.h similarity index 100% rename from Classes/BITUpdateViewControllerPrivate.h rename to Classes/Update/BITUpdateViewControllerPrivate.h diff --git a/Resources/de.lproj/HockeySDK.strings b/Resources/de.lproj/HockeySDK.strings index df2e2e07..6d8382e0 100755 --- a/Resources/de.lproj/HockeySDK.strings +++ b/Resources/de.lproj/HockeySDK.strings @@ -107,3 +107,89 @@ /* Update Simulator Warning */ "UpdateSimulatorMessage" = "Hockey funktioniert nicht im Simulator."; + + + + +/* Feedback */ + + +/* New Message Alert */ + +/* Alert Title */ +"HockeyFeedbackNewMessageTitle" = "New Feedback Response"; + +/* Alert Text */ +"HockeyFeedbackNewMessageText" = "A new response to your feedback is available. Would you like to view it?"; + +/* Alert Ignore Button */ +"HockeyFeedbackIgnore" = "Ignore"; + +/* Alert Show Button */ +"HockeyFeedbackShow" = "Show"; + + +/* List View */ + +/* Title */ +"HockeyFeedbackListTitle" = "Feedback"; + +/* Last Updated */ +"HockeyFeedbackListLastUpdated" = "Last Updated: %@"; + +/* Never Updated */ +"HockeyFeedbackListNeverUpdated" = "Never"; + +/* Write Feedback Button Title */ +"HockeyFeedbackListButonWriteFeedback" = "Write Feedback"; + +/* Write Response Button Title */ +"HockeyFeedbackListButonWriteResponse" = "Write Response"; + +/* User Data Set Name Button Title */ +"HockeyFeedbackListButonUserDataSetName" = "Set Your Name"; + +/* User Data Set Email Button Title */ +"HockeyFeedbackListButonUserDataSetEmail" = "Set Your Email"; + +/* User Data With Name Button Title */ +"HockeyFeedbackListButonUserDataWithName" = "Name: %@"; + +/* User Data With Email Button Title */ +"HockeyFeedbackListButonUserDataWithEmail" = "Email: %@"; + +/* User Name In Message If Name Not Set */ +"HockeyFeedbackListMessageUserNameNotSet" = "You"; + +/* Name In Message From Server If Name Not Set */ +"HockeyFeedbackListmessageResponseNameNotSet" = "Response"; + + +/* Compose Message */ + +/* Title */ +"HockeyFeedbackComposeTitle" = "New Feedback"; + +/* Send button */ +"HockeyFeedbackComposeSend" = "Send"; + + +/* Set User Data */ + +/* Title */ +"HockeyFeedbackUserDataTitle" = "Who Are You"; + +/* Description On What Should Be Entered */ +"HockeyFeedbackUserDataDescription" = "Please let us know who you are before writing us your feedback."; + +/* Name Field */ +"HockeyFeedbackUserDataName" = "Name"; + +/* Name Placeholder */ +"HockeyFeedbackUserDataNamePlaceHolder" = "John Doe"; + +/* Email Field */ +"HockeyFeedbackUserDataEmail" = "Email"; + +/* Email Placeholder */ +"HockeyFeedbackUserDataEmailPlaceholder" = "example@email.com"; diff --git a/Resources/en.lproj/HockeySDK.strings b/Resources/en.lproj/HockeySDK.strings index e92f66fb..502a40ac 100755 --- a/Resources/en.lproj/HockeySDK.strings +++ b/Resources/en.lproj/HockeySDK.strings @@ -106,3 +106,87 @@ /* Update Simulator Warning */ "UpdateSimulatorMessage" = "Hockey Update does not work in the Simulator.\nThe itms-services:// url scheme is implemented but nonfunctional."; + + +/* Feedback */ + + +/* New Message Alert */ + +/* Alert Title */ +"HockeyFeedbackNewMessageTitle" = "New Feedback Response"; + +/* Alert Text */ +"HockeyFeedbackNewMessageText" = "A new response to your feedback is available. Would you like to view it?"; + +/* Alert Ignore Button */ +"HockeyFeedbackIgnore" = "Ignore"; + +/* Alert Show Button */ +"HockeyFeedbackShow" = "Show"; + + +/* List View */ + +/* Title */ +"HockeyFeedbackListTitle" = "Feedback"; + +/* Last Updated */ +"HockeyFeedbackListLastUpdated" = "Last Updated: %@"; + +/* Never Updated */ +"HockeyFeedbackListNeverUpdated" = "Never"; + +/* Write Feedback Button Title */ +"HockeyFeedbackListButonWriteFeedback" = "Write Feedback"; + +/* Write Response Button Title */ +"HockeyFeedbackListButonWriteResponse" = "Write Response"; + +/* User Data Set Name Button Title */ +"HockeyFeedbackListButonUserDataSetName" = "Set Your Name"; + +/* User Data Set Email Button Title */ +"HockeyFeedbackListButonUserDataSetEmail" = "Set Your Email"; + +/* User Data With Name Button Title */ +"HockeyFeedbackListButonUserDataWithName" = "Name: %@"; + +/* User Data With Email Button Title */ +"HockeyFeedbackListButonUserDataWithEmail" = "Email: %@"; + +/* User Name In Message If Name Not Set */ +"HockeyFeedbackListMessageUserNameNotSet" = "You"; + +/* Name In Message From Server If Name Not Set */ +"HockeyFeedbackListmessageResponseNameNotSet" = "Response"; + + +/* Compose Message */ + +/* Title */ +"HockeyFeedbackComposeTitle" = "New Feedback"; + +/* Send button */ +"HockeyFeedbackComposeSend" = "Send"; + + +/* Set User Data */ + +/* Title */ +"HockeyFeedbackUserDataTitle" = "Who Are You"; + +/* Description On What Should Be Entered */ +"HockeyFeedbackUserDataDescription" = "Please let us know who you are before writing us your feedback."; + +/* Name Field */ +"HockeyFeedbackUserDataName" = "Name"; + +/* Name Placeholder */ +"HockeyFeedbackUserDataNamePlaceHolder" = "John Doe"; + +/* Email Field */ +"HockeyFeedbackUserDataEmail" = "Email"; + +/* Email Placeholder */ +"HockeyFeedbackUserDataEmailPlaceholder" = "example@email.com"; diff --git a/Resources/es.lproj/HockeySDK.strings b/Resources/es.lproj/HockeySDK.strings index 85b1cf83..6d94259a 100755 --- a/Resources/es.lproj/HockeySDK.strings +++ b/Resources/es.lproj/HockeySDK.strings @@ -107,3 +107,87 @@ /* Update Simulator Warning */ "UpdateSimulatorMessage" = "Hockey Update does not work in the Simulator.\nThe itms-services:// url scheme is implemented but nonfunctional."; + + +/* Feedback */ + + +/* New Message Alert */ + +/* Alert Title */ +"HockeyFeedbackNewMessageTitle" = "New Feedback Response"; + +/* Alert Text */ +"HockeyFeedbackNewMessageText" = "A new response to your feedback is available. Would you like to view it?"; + +/* Alert Ignore Button */ +"HockeyFeedbackIgnore" = "Ignore"; + +/* Alert Show Button */ +"HockeyFeedbackShow" = "Show"; + + +/* List View */ + +/* Title */ +"HockeyFeedbackListTitle" = "Feedback"; + +/* Last Updated */ +"HockeyFeedbackListLastUpdated" = "Last Updated: %@"; + +/* Never Updated */ +"HockeyFeedbackListNeverUpdated" = "Never"; + +/* Write Feedback Button Title */ +"HockeyFeedbackListButonWriteFeedback" = "Write Feedback"; + +/* Write Response Button Title */ +"HockeyFeedbackListButonWriteResponse" = "Write Response"; + +/* User Data Set Name Button Title */ +"HockeyFeedbackListButonUserDataSetName" = "Set Your Name"; + +/* User Data Set Email Button Title */ +"HockeyFeedbackListButonUserDataSetEmail" = "Set Your Email"; + +/* User Data With Name Button Title */ +"HockeyFeedbackListButonUserDataWithName" = "Name: %@"; + +/* User Data With Email Button Title */ +"HockeyFeedbackListButonUserDataWithEmail" = "Email: %@"; + +/* User Name In Message If Name Not Set */ +"HockeyFeedbackListMessageUserNameNotSet" = "You"; + +/* Name In Message From Server If Name Not Set */ +"HockeyFeedbackListmessageResponseNameNotSet" = "Response"; + + +/* Compose Message */ + +/* Title */ +"HockeyFeedbackComposeTitle" = "New Feedback"; + +/* Send button */ +"HockeyFeedbackComposeSend" = "Send"; + + +/* Set User Data */ + +/* Title */ +"HockeyFeedbackUserDataTitle" = "Who Are You"; + +/* Description On What Should Be Entered */ +"HockeyFeedbackUserDataDescription" = "Please let us know who you are before writing us your feedback."; + +/* Name Field */ +"HockeyFeedbackUserDataName" = "Name"; + +/* Name Placeholder */ +"HockeyFeedbackUserDataNamePlaceHolder" = "John Doe"; + +/* Email Field */ +"HockeyFeedbackUserDataEmail" = "Email"; + +/* Email Placeholder */ +"HockeyFeedbackUserDataEmailPlaceholder" = "example@email.com"; diff --git a/Resources/fr.lproj/HockeySDK.strings b/Resources/fr.lproj/HockeySDK.strings index 59916552..be958900 100755 --- a/Resources/fr.lproj/HockeySDK.strings +++ b/Resources/fr.lproj/HockeySDK.strings @@ -107,3 +107,87 @@ /* Update Simulator Warning */ "UpdateSimulatorMessage" = "Hockey Update does not work in the Simulator.\nThe itms-services:// url scheme is implemented but nonfunctional."; + + +/* Feedback */ + + +/* New Message Alert */ + +/* Alert Title */ +"HockeyFeedbackNewMessageTitle" = "New Feedback Response"; + +/* Alert Text */ +"HockeyFeedbackNewMessageText" = "A new response to your feedback is available. Would you like to view it?"; + +/* Alert Ignore Button */ +"HockeyFeedbackIgnore" = "Ignore"; + +/* Alert Show Button */ +"HockeyFeedbackShow" = "Show"; + + +/* List View */ + +/* Title */ +"HockeyFeedbackListTitle" = "Feedback"; + +/* Last Updated */ +"HockeyFeedbackListLastUpdated" = "Last Updated: %@"; + +/* Never Updated */ +"HockeyFeedbackListNeverUpdated" = "Never"; + +/* Write Feedback Button Title */ +"HockeyFeedbackListButonWriteFeedback" = "Write Feedback"; + +/* Write Response Button Title */ +"HockeyFeedbackListButonWriteResponse" = "Write Response"; + +/* User Data Set Name Button Title */ +"HockeyFeedbackListButonUserDataSetName" = "Set Your Name"; + +/* User Data Set Email Button Title */ +"HockeyFeedbackListButonUserDataSetEmail" = "Set Your Email"; + +/* User Data With Name Button Title */ +"HockeyFeedbackListButonUserDataWithName" = "Name: %@"; + +/* User Data With Email Button Title */ +"HockeyFeedbackListButonUserDataWithEmail" = "Email: %@"; + +/* User Name In Message If Name Not Set */ +"HockeyFeedbackListMessageUserNameNotSet" = "You"; + +/* Name In Message From Server If Name Not Set */ +"HockeyFeedbackListmessageResponseNameNotSet" = "Response"; + + +/* Compose Message */ + +/* Title */ +"HockeyFeedbackComposeTitle" = "New Feedback"; + +/* Send button */ +"HockeyFeedbackComposeSend" = "Send"; + + +/* Set User Data */ + +/* Title */ +"HockeyFeedbackUserDataTitle" = "Who Are You"; + +/* Description On What Should Be Entered */ +"HockeyFeedbackUserDataDescription" = "Please let us know who you are before writing us your feedback."; + +/* Name Field */ +"HockeyFeedbackUserDataName" = "Name"; + +/* Name Placeholder */ +"HockeyFeedbackUserDataNamePlaceHolder" = "John Doe"; + +/* Email Field */ +"HockeyFeedbackUserDataEmail" = "Email"; + +/* Email Placeholder */ +"HockeyFeedbackUserDataEmailPlaceholder" = "example@email.com"; diff --git a/Resources/it.lproj/HockeySDK.strings b/Resources/it.lproj/HockeySDK.strings index c062763c..cd541f40 100755 --- a/Resources/it.lproj/HockeySDK.strings +++ b/Resources/it.lproj/HockeySDK.strings @@ -107,3 +107,87 @@ /* Update Simulator Warning */ "UpdateSimulatorMessage" = "Hockey Update does not work in the Simulator.\nThe itms-services:// url scheme is implemented but nonfunctional."; + + +/* Feedback */ + + +/* New Message Alert */ + +/* Alert Title */ +"HockeyFeedbackNewMessageTitle" = "New Feedback Response"; + +/* Alert Text */ +"HockeyFeedbackNewMessageText" = "A new response to your feedback is available. Would you like to view it?"; + +/* Alert Ignore Button */ +"HockeyFeedbackIgnore" = "Ignore"; + +/* Alert Show Button */ +"HockeyFeedbackShow" = "Show"; + + +/* List View */ + +/* Title */ +"HockeyFeedbackListTitle" = "Feedback"; + +/* Last Updated */ +"HockeyFeedbackListLastUpdated" = "Last Updated: %@"; + +/* Never Updated */ +"HockeyFeedbackListNeverUpdated" = "Never"; + +/* Write Feedback Button Title */ +"HockeyFeedbackListButonWriteFeedback" = "Write Feedback"; + +/* Write Response Button Title */ +"HockeyFeedbackListButonWriteResponse" = "Write Response"; + +/* User Data Set Name Button Title */ +"HockeyFeedbackListButonUserDataSetName" = "Set Your Name"; + +/* User Data Set Email Button Title */ +"HockeyFeedbackListButonUserDataSetEmail" = "Set Your Email"; + +/* User Data With Name Button Title */ +"HockeyFeedbackListButonUserDataWithName" = "Name: %@"; + +/* User Data With Email Button Title */ +"HockeyFeedbackListButonUserDataWithEmail" = "Email: %@"; + +/* User Name In Message If Name Not Set */ +"HockeyFeedbackListMessageUserNameNotSet" = "You"; + +/* Name In Message From Server If Name Not Set */ +"HockeyFeedbackListmessageResponseNameNotSet" = "Response"; + + +/* Compose Message */ + +/* Title */ +"HockeyFeedbackComposeTitle" = "New Feedback"; + +/* Send button */ +"HockeyFeedbackComposeSend" = "Send"; + + +/* Set User Data */ + +/* Title */ +"HockeyFeedbackUserDataTitle" = "Who Are You"; + +/* Description On What Should Be Entered */ +"HockeyFeedbackUserDataDescription" = "Please let us know who you are before writing us your feedback."; + +/* Name Field */ +"HockeyFeedbackUserDataName" = "Name"; + +/* Name Placeholder */ +"HockeyFeedbackUserDataNamePlaceHolder" = "John Doe"; + +/* Email Field */ +"HockeyFeedbackUserDataEmail" = "Email"; + +/* Email Placeholder */ +"HockeyFeedbackUserDataEmailPlaceholder" = "example@email.com"; diff --git a/Resources/ja.lproj/HockeySDK.strings b/Resources/ja.lproj/HockeySDK.strings index 73f00a43..32a595ba 100755 --- a/Resources/ja.lproj/HockeySDK.strings +++ b/Resources/ja.lproj/HockeySDK.strings @@ -107,3 +107,87 @@ /* Update Simulator Warning */ "UpdateSimulatorMessage" = "Hockey Update does not work in the Simulator.\nThe itms-services:// url scheme is implemented but nonfunctional."; + + +/* Feedback */ + + +/* New Message Alert */ + +/* Alert Title */ +"HockeyFeedbackNewMessageTitle" = "New Feedback Response"; + +/* Alert Text */ +"HockeyFeedbackNewMessageText" = "A new response to your feedback is available. Would you like to view it?"; + +/* Alert Ignore Button */ +"HockeyFeedbackIgnore" = "Ignore"; + +/* Alert Show Button */ +"HockeyFeedbackShow" = "Show"; + + +/* List View */ + +/* Title */ +"HockeyFeedbackListTitle" = "Feedback"; + +/* Last Updated */ +"HockeyFeedbackListLastUpdated" = "Last Updated: %@"; + +/* Never Updated */ +"HockeyFeedbackListNeverUpdated" = "Never"; + +/* Write Feedback Button Title */ +"HockeyFeedbackListButonWriteFeedback" = "Write Feedback"; + +/* Write Response Button Title */ +"HockeyFeedbackListButonWriteResponse" = "Write Response"; + +/* User Data Set Name Button Title */ +"HockeyFeedbackListButonUserDataSetName" = "Set Your Name"; + +/* User Data Set Email Button Title */ +"HockeyFeedbackListButonUserDataSetEmail" = "Set Your Email"; + +/* User Data With Name Button Title */ +"HockeyFeedbackListButonUserDataWithName" = "Name: %@"; + +/* User Data With Email Button Title */ +"HockeyFeedbackListButonUserDataWithEmail" = "Email: %@"; + +/* User Name In Message If Name Not Set */ +"HockeyFeedbackListMessageUserNameNotSet" = "You"; + +/* Name In Message From Server If Name Not Set */ +"HockeyFeedbackListmessageResponseNameNotSet" = "Response"; + + +/* Compose Message */ + +/* Title */ +"HockeyFeedbackComposeTitle" = "New Feedback"; + +/* Send button */ +"HockeyFeedbackComposeSend" = "Send"; + + +/* Set User Data */ + +/* Title */ +"HockeyFeedbackUserDataTitle" = "Who Are You"; + +/* Description On What Should Be Entered */ +"HockeyFeedbackUserDataDescription" = "Please let us know who you are before writing us your feedback."; + +/* Name Field */ +"HockeyFeedbackUserDataName" = "Name"; + +/* Name Placeholder */ +"HockeyFeedbackUserDataNamePlaceHolder" = "John Doe"; + +/* Email Field */ +"HockeyFeedbackUserDataEmail" = "Email"; + +/* Email Placeholder */ +"HockeyFeedbackUserDataEmailPlaceholder" = "example@email.com"; diff --git a/Resources/nl.lproj/HockeySDK.strings b/Resources/nl.lproj/HockeySDK.strings index 580e7ea1..5ab5b7a8 100755 --- a/Resources/nl.lproj/HockeySDK.strings +++ b/Resources/nl.lproj/HockeySDK.strings @@ -107,3 +107,87 @@ /* Update Simulator Warning */ "UpdateSimulatorMessage" = "Hockey Update does not work in the Simulator.\nThe itms-services:// url scheme is implemented but nonfunctional."; + + +/* Feedback */ + + +/* New Message Alert */ + +/* Alert Title */ +"HockeyFeedbackNewMessageTitle" = "New Feedback Response"; + +/* Alert Text */ +"HockeyFeedbackNewMessageText" = "A new response to your feedback is available. Would you like to view it?"; + +/* Alert Ignore Button */ +"HockeyFeedbackIgnore" = "Ignore"; + +/* Alert Show Button */ +"HockeyFeedbackShow" = "Show"; + + +/* List View */ + +/* Title */ +"HockeyFeedbackListTitle" = "Feedback"; + +/* Last Updated */ +"HockeyFeedbackListLastUpdated" = "Last Updated: %@"; + +/* Never Updated */ +"HockeyFeedbackListNeverUpdated" = "Never"; + +/* Write Feedback Button Title */ +"HockeyFeedbackListButonWriteFeedback" = "Write Feedback"; + +/* Write Response Button Title */ +"HockeyFeedbackListButonWriteResponse" = "Write Response"; + +/* User Data Set Name Button Title */ +"HockeyFeedbackListButonUserDataSetName" = "Set Your Name"; + +/* User Data Set Email Button Title */ +"HockeyFeedbackListButonUserDataSetEmail" = "Set Your Email"; + +/* User Data With Name Button Title */ +"HockeyFeedbackListButonUserDataWithName" = "Name: %@"; + +/* User Data With Email Button Title */ +"HockeyFeedbackListButonUserDataWithEmail" = "Email: %@"; + +/* User Name In Message If Name Not Set */ +"HockeyFeedbackListMessageUserNameNotSet" = "You"; + +/* Name In Message From Server If Name Not Set */ +"HockeyFeedbackListmessageResponseNameNotSet" = "Response"; + + +/* Compose Message */ + +/* Title */ +"HockeyFeedbackComposeTitle" = "New Feedback"; + +/* Send button */ +"HockeyFeedbackComposeSend" = "Send"; + + +/* Set User Data */ + +/* Title */ +"HockeyFeedbackUserDataTitle" = "Who Are You"; + +/* Description On What Should Be Entered */ +"HockeyFeedbackUserDataDescription" = "Please let us know who you are before writing us your feedback."; + +/* Name Field */ +"HockeyFeedbackUserDataName" = "Name"; + +/* Name Placeholder */ +"HockeyFeedbackUserDataNamePlaceHolder" = "John Doe"; + +/* Email Field */ +"HockeyFeedbackUserDataEmail" = "Email"; + +/* Email Placeholder */ +"HockeyFeedbackUserDataEmailPlaceholder" = "example@email.com"; diff --git a/Resources/pt-PT.lproj/HockeySDK.strings b/Resources/pt-PT.lproj/HockeySDK.strings index b06b687a..5115aa91 100755 --- a/Resources/pt-PT.lproj/HockeySDK.strings +++ b/Resources/pt-PT.lproj/HockeySDK.strings @@ -107,3 +107,87 @@ /* Update Simulator Warning */ "UpdateSimulatorMessage" = "Hockey Update does not work in the Simulator.\nThe itms-services:// url scheme is implemented but nonfunctional."; + + +/* Feedback */ + + +/* New Message Alert */ + +/* Alert Title */ +"HockeyFeedbackNewMessageTitle" = "New Feedback Response"; + +/* Alert Text */ +"HockeyFeedbackNewMessageText" = "A new response to your feedback is available. Would you like to view it?"; + +/* Alert Ignore Button */ +"HockeyFeedbackIgnore" = "Ignore"; + +/* Alert Show Button */ +"HockeyFeedbackShow" = "Show"; + + +/* List View */ + +/* Title */ +"HockeyFeedbackListTitle" = "Feedback"; + +/* Last Updated */ +"HockeyFeedbackListLastUpdated" = "Last Updated: %@"; + +/* Never Updated */ +"HockeyFeedbackListNeverUpdated" = "Never"; + +/* Write Feedback Button Title */ +"HockeyFeedbackListButonWriteFeedback" = "Write Feedback"; + +/* Write Response Button Title */ +"HockeyFeedbackListButonWriteResponse" = "Write Response"; + +/* User Data Set Name Button Title */ +"HockeyFeedbackListButonUserDataSetName" = "Set Your Name"; + +/* User Data Set Email Button Title */ +"HockeyFeedbackListButonUserDataSetEmail" = "Set Your Email"; + +/* User Data With Name Button Title */ +"HockeyFeedbackListButonUserDataWithName" = "Name: %@"; + +/* User Data With Email Button Title */ +"HockeyFeedbackListButonUserDataWithEmail" = "Email: %@"; + +/* User Name In Message If Name Not Set */ +"HockeyFeedbackListMessageUserNameNotSet" = "You"; + +/* Name In Message From Server If Name Not Set */ +"HockeyFeedbackListmessageResponseNameNotSet" = "Response"; + + +/* Compose Message */ + +/* Title */ +"HockeyFeedbackComposeTitle" = "New Feedback"; + +/* Send button */ +"HockeyFeedbackComposeSend" = "Send"; + + +/* Set User Data */ + +/* Title */ +"HockeyFeedbackUserDataTitle" = "Who Are You"; + +/* Description On What Should Be Entered */ +"HockeyFeedbackUserDataDescription" = "Please let us know who you are before writing us your feedback."; + +/* Name Field */ +"HockeyFeedbackUserDataName" = "Name"; + +/* Name Placeholder */ +"HockeyFeedbackUserDataNamePlaceHolder" = "John Doe"; + +/* Email Field */ +"HockeyFeedbackUserDataEmail" = "Email"; + +/* Email Placeholder */ +"HockeyFeedbackUserDataEmailPlaceholder" = "example@email.com"; diff --git a/Resources/pt.lproj/HockeySDK.strings b/Resources/pt.lproj/HockeySDK.strings index 5b83e735..38689eee 100755 --- a/Resources/pt.lproj/HockeySDK.strings +++ b/Resources/pt.lproj/HockeySDK.strings @@ -107,3 +107,87 @@ /* Update Simulator Warning */ "UpdateSimulatorMessage" = "Hockey Update não funciona no Simulador.\nA url itms-services:// é implementada mas não é funcional."; + + +/* Feedback */ + + +/* New Message Alert */ + +/* Alert Title */ +"HockeyFeedbackNewMessageTitle" = "New Feedback Response"; + +/* Alert Text */ +"HockeyFeedbackNewMessageText" = "A new response to your feedback is available. Would you like to view it?"; + +/* Alert Ignore Button */ +"HockeyFeedbackIgnore" = "Ignore"; + +/* Alert Show Button */ +"HockeyFeedbackShow" = "Show"; + + +/* List View */ + +/* Title */ +"HockeyFeedbackListTitle" = "Feedback"; + +/* Last Updated */ +"HockeyFeedbackListLastUpdated" = "Last Updated: %@"; + +/* Never Updated */ +"HockeyFeedbackListNeverUpdated" = "Never"; + +/* Write Feedback Button Title */ +"HockeyFeedbackListButonWriteFeedback" = "Write Feedback"; + +/* Write Response Button Title */ +"HockeyFeedbackListButonWriteResponse" = "Write Response"; + +/* User Data Set Name Button Title */ +"HockeyFeedbackListButonUserDataSetName" = "Set Your Name"; + +/* User Data Set Email Button Title */ +"HockeyFeedbackListButonUserDataSetEmail" = "Set Your Email"; + +/* User Data With Name Button Title */ +"HockeyFeedbackListButonUserDataWithName" = "Name: %@"; + +/* User Data With Email Button Title */ +"HockeyFeedbackListButonUserDataWithEmail" = "Email: %@"; + +/* User Name In Message If Name Not Set */ +"HockeyFeedbackListMessageUserNameNotSet" = "You"; + +/* Name In Message From Server If Name Not Set */ +"HockeyFeedbackListmessageResponseNameNotSet" = "Response"; + + +/* Compose Message */ + +/* Title */ +"HockeyFeedbackComposeTitle" = "New Feedback"; + +/* Send button */ +"HockeyFeedbackComposeSend" = "Send"; + + +/* Set User Data */ + +/* Title */ +"HockeyFeedbackUserDataTitle" = "Who Are You"; + +/* Description On What Should Be Entered */ +"HockeyFeedbackUserDataDescription" = "Please let us know who you are before writing us your feedback."; + +/* Name Field */ +"HockeyFeedbackUserDataName" = "Name"; + +/* Name Placeholder */ +"HockeyFeedbackUserDataNamePlaceHolder" = "John Doe"; + +/* Email Field */ +"HockeyFeedbackUserDataEmail" = "Email"; + +/* Email Placeholder */ +"HockeyFeedbackUserDataEmailPlaceholder" = "example@email.com"; diff --git a/Resources/ru.lproj/HockeySDK.strings b/Resources/ru.lproj/HockeySDK.strings index 7a9e54be..71407604 100755 --- a/Resources/ru.lproj/HockeySDK.strings +++ b/Resources/ru.lproj/HockeySDK.strings @@ -107,3 +107,87 @@ /* Update Simulator Warning */ "UpdateSimulatorMessage" = "Hockey Update does not work in the Simulator.\nThe itms-services:// url scheme is implemented but nonfunctional."; + + +/* Feedback */ + + +/* New Message Alert */ + +/* Alert Title */ +"HockeyFeedbackNewMessageTitle" = "New Feedback Response"; + +/* Alert Text */ +"HockeyFeedbackNewMessageText" = "A new response to your feedback is available. Would you like to view it?"; + +/* Alert Ignore Button */ +"HockeyFeedbackIgnore" = "Ignore"; + +/* Alert Show Button */ +"HockeyFeedbackShow" = "Show"; + + +/* List View */ + +/* Title */ +"HockeyFeedbackListTitle" = "Feedback"; + +/* Last Updated */ +"HockeyFeedbackListLastUpdated" = "Last Updated: %@"; + +/* Never Updated */ +"HockeyFeedbackListNeverUpdated" = "Never"; + +/* Write Feedback Button Title */ +"HockeyFeedbackListButonWriteFeedback" = "Write Feedback"; + +/* Write Response Button Title */ +"HockeyFeedbackListButonWriteResponse" = "Write Response"; + +/* User Data Set Name Button Title */ +"HockeyFeedbackListButonUserDataSetName" = "Set Your Name"; + +/* User Data Set Email Button Title */ +"HockeyFeedbackListButonUserDataSetEmail" = "Set Your Email"; + +/* User Data With Name Button Title */ +"HockeyFeedbackListButonUserDataWithName" = "Name: %@"; + +/* User Data With Email Button Title */ +"HockeyFeedbackListButonUserDataWithEmail" = "Email: %@"; + +/* User Name In Message If Name Not Set */ +"HockeyFeedbackListMessageUserNameNotSet" = "You"; + +/* Name In Message From Server If Name Not Set */ +"HockeyFeedbackListmessageResponseNameNotSet" = "Response"; + + +/* Compose Message */ + +/* Title */ +"HockeyFeedbackComposeTitle" = "New Feedback"; + +/* Send button */ +"HockeyFeedbackComposeSend" = "Send"; + + +/* Set User Data */ + +/* Title */ +"HockeyFeedbackUserDataTitle" = "Who Are You"; + +/* Description On What Should Be Entered */ +"HockeyFeedbackUserDataDescription" = "Please let us know who you are before writing us your feedback."; + +/* Name Field */ +"HockeyFeedbackUserDataName" = "Name"; + +/* Name Placeholder */ +"HockeyFeedbackUserDataNamePlaceHolder" = "John Doe"; + +/* Email Field */ +"HockeyFeedbackUserDataEmail" = "Email"; + +/* Email Placeholder */ +"HockeyFeedbackUserDataEmailPlaceholder" = "example@email.com"; diff --git a/Resources/sv.lproj/HockeySDK.strings b/Resources/sv.lproj/HockeySDK.strings index 0a42cb4f..659bed27 100755 --- a/Resources/sv.lproj/HockeySDK.strings +++ b/Resources/sv.lproj/HockeySDK.strings @@ -107,3 +107,87 @@ /* Update Simulator Warning */ "UpdateSimulatorMessage" = "Hockey Update fungerar inte i Simulatorn.\nitms-services:// url schemat är implementerat men fungerar ej."; + + +/* Feedback */ + + +/* New Message Alert */ + +/* Alert Title */ +"HockeyFeedbackNewMessageTitle" = "New Feedback Response"; + +/* Alert Text */ +"HockeyFeedbackNewMessageText" = "A new response to your feedback is available. Would you like to view it?"; + +/* Alert Ignore Button */ +"HockeyFeedbackIgnore" = "Ignore"; + +/* Alert Show Button */ +"HockeyFeedbackShow" = "Show"; + + +/* List View */ + +/* Title */ +"HockeyFeedbackListTitle" = "Feedback"; + +/* Last Updated */ +"HockeyFeedbackListLastUpdated" = "Last Updated: %@"; + +/* Never Updated */ +"HockeyFeedbackListNeverUpdated" = "Never"; + +/* Write Feedback Button Title */ +"HockeyFeedbackListButonWriteFeedback" = "Write Feedback"; + +/* Write Response Button Title */ +"HockeyFeedbackListButonWriteResponse" = "Write Response"; + +/* User Data Set Name Button Title */ +"HockeyFeedbackListButonUserDataSetName" = "Set Your Name"; + +/* User Data Set Email Button Title */ +"HockeyFeedbackListButonUserDataSetEmail" = "Set Your Email"; + +/* User Data With Name Button Title */ +"HockeyFeedbackListButonUserDataWithName" = "Name: %@"; + +/* User Data With Email Button Title */ +"HockeyFeedbackListButonUserDataWithEmail" = "Email: %@"; + +/* User Name In Message If Name Not Set */ +"HockeyFeedbackListMessageUserNameNotSet" = "You"; + +/* Name In Message From Server If Name Not Set */ +"HockeyFeedbackListmessageResponseNameNotSet" = "Response"; + + +/* Compose Message */ + +/* Title */ +"HockeyFeedbackComposeTitle" = "New Feedback"; + +/* Send button */ +"HockeyFeedbackComposeSend" = "Send"; + + +/* Set User Data */ + +/* Title */ +"HockeyFeedbackUserDataTitle" = "Who Are You"; + +/* Description On What Should Be Entered */ +"HockeyFeedbackUserDataDescription" = "Please let us know who you are before writing us your feedback."; + +/* Name Field */ +"HockeyFeedbackUserDataName" = "Name"; + +/* Name Placeholder */ +"HockeyFeedbackUserDataNamePlaceHolder" = "John Doe"; + +/* Email Field */ +"HockeyFeedbackUserDataEmail" = "Email"; + +/* Email Placeholder */ +"HockeyFeedbackUserDataEmailPlaceholder" = "example@email.com"; diff --git a/Resources/tr.lproj/HockeySDK.strings b/Resources/tr.lproj/HockeySDK.strings index 52e56d12..20755b8b 100644 --- a/Resources/tr.lproj/HockeySDK.strings +++ b/Resources/tr.lproj/HockeySDK.strings @@ -107,3 +107,87 @@ /* Update Simulator Warning */ "UpdateSimulatorMessage" = "Hockey Update does not work in the Simulator.\nThe itms-services:// url scheme is implemented but nonfunctional."; + + +/* Feedback */ + + +/* New Message Alert */ + +/* Alert Title */ +"HockeyFeedbackNewMessageTitle" = "New Feedback Response"; + +/* Alert Text */ +"HockeyFeedbackNewMessageText" = "A new response to your feedback is available. Would you like to view it?"; + +/* Alert Ignore Button */ +"HockeyFeedbackIgnore" = "Ignore"; + +/* Alert Show Button */ +"HockeyFeedbackShow" = "Show"; + + +/* List View */ + +/* Title */ +"HockeyFeedbackListTitle" = "Feedback"; + +/* Last Updated */ +"HockeyFeedbackListLastUpdated" = "Last Updated: %@"; + +/* Never Updated */ +"HockeyFeedbackListNeverUpdated" = "Never"; + +/* Write Feedback Button Title */ +"HockeyFeedbackListButonWriteFeedback" = "Write Feedback"; + +/* Write Response Button Title */ +"HockeyFeedbackListButonWriteResponse" = "Write Response"; + +/* User Data Set Name Button Title */ +"HockeyFeedbackListButonUserDataSetName" = "Set Your Name"; + +/* User Data Set Email Button Title */ +"HockeyFeedbackListButonUserDataSetEmail" = "Set Your Email"; + +/* User Data With Name Button Title */ +"HockeyFeedbackListButonUserDataWithName" = "Name: %@"; + +/* User Data With Email Button Title */ +"HockeyFeedbackListButonUserDataWithEmail" = "Email: %@"; + +/* User Name In Message If Name Not Set */ +"HockeyFeedbackListMessageUserNameNotSet" = "You"; + +/* Name In Message From Server If Name Not Set */ +"HockeyFeedbackListmessageResponseNameNotSet" = "Response"; + + +/* Compose Message */ + +/* Title */ +"HockeyFeedbackComposeTitle" = "New Feedback"; + +/* Send button */ +"HockeyFeedbackComposeSend" = "Send"; + + +/* Set User Data */ + +/* Title */ +"HockeyFeedbackUserDataTitle" = "Who Are You"; + +/* Description On What Should Be Entered */ +"HockeyFeedbackUserDataDescription" = "Please let us know who you are before writing us your feedback."; + +/* Name Field */ +"HockeyFeedbackUserDataName" = "Name"; + +/* Name Placeholder */ +"HockeyFeedbackUserDataNamePlaceHolder" = "John Doe"; + +/* Email Field */ +"HockeyFeedbackUserDataEmail" = "Email"; + +/* Email Placeholder */ +"HockeyFeedbackUserDataEmailPlaceholder" = "example@email.com"; diff --git a/Resources/zh_CN.lproj/HockeySDK.strings b/Resources/zh_CN.lproj/HockeySDK.strings index 69601d68..7d13604f 100644 --- a/Resources/zh_CN.lproj/HockeySDK.strings +++ b/Resources/zh_CN.lproj/HockeySDK.strings @@ -107,3 +107,87 @@ /* Update Simulator Warning */ "UpdateSimulatorMessage" = "Hockey Update does not work in the Simulator.\nThe itms-services:// url scheme is implemented but nonfunctional."; + + +/* Feedback */ + + +/* New Message Alert */ + +/* Alert Title */ +"HockeyFeedbackNewMessageTitle" = "New Feedback Response"; + +/* Alert Text */ +"HockeyFeedbackNewMessageText" = "A new response to your feedback is available. Would you like to view it?"; + +/* Alert Ignore Button */ +"HockeyFeedbackIgnore" = "Ignore"; + +/* Alert Show Button */ +"HockeyFeedbackShow" = "Show"; + + +/* List View */ + +/* Title */ +"HockeyFeedbackListTitle" = "Feedback"; + +/* Last Updated */ +"HockeyFeedbackListLastUpdated" = "Last Updated: %@"; + +/* Never Updated */ +"HockeyFeedbackListNeverUpdated" = "Never"; + +/* Write Feedback Button Title */ +"HockeyFeedbackListButonWriteFeedback" = "Write Feedback"; + +/* Write Response Button Title */ +"HockeyFeedbackListButonWriteResponse" = "Write Response"; + +/* User Data Set Name Button Title */ +"HockeyFeedbackListButonUserDataSetName" = "Set Your Name"; + +/* User Data Set Email Button Title */ +"HockeyFeedbackListButonUserDataSetEmail" = "Set Your Email"; + +/* User Data With Name Button Title */ +"HockeyFeedbackListButonUserDataWithName" = "Name: %@"; + +/* User Data With Email Button Title */ +"HockeyFeedbackListButonUserDataWithEmail" = "Email: %@"; + +/* User Name In Message If Name Not Set */ +"HockeyFeedbackListMessageUserNameNotSet" = "You"; + +/* Name In Message From Server If Name Not Set */ +"HockeyFeedbackListmessageResponseNameNotSet" = "Response"; + + +/* Compose Message */ + +/* Title */ +"HockeyFeedbackComposeTitle" = "New Feedback"; + +/* Send button */ +"HockeyFeedbackComposeSend" = "Send"; + + +/* Set User Data */ + +/* Title */ +"HockeyFeedbackUserDataTitle" = "Who Are You"; + +/* Description On What Should Be Entered */ +"HockeyFeedbackUserDataDescription" = "Please let us know who you are before writing us your feedback."; + +/* Name Field */ +"HockeyFeedbackUserDataName" = "Name"; + +/* Name Placeholder */ +"HockeyFeedbackUserDataNamePlaceHolder" = "John Doe"; + +/* Email Field */ +"HockeyFeedbackUserDataEmail" = "Email"; + +/* Email Placeholder */ +"HockeyFeedbackUserDataEmailPlaceholder" = "example@email.com"; diff --git a/Resources/zh_TW.lproj/HockeySDK.strings b/Resources/zh_TW.lproj/HockeySDK.strings index b6bfffda..32dc5623 100644 --- a/Resources/zh_TW.lproj/HockeySDK.strings +++ b/Resources/zh_TW.lproj/HockeySDK.strings @@ -107,3 +107,87 @@ /* Update Simulator Warning */ "UpdateSimulatorMessage" = "Hockey Update does not work in the Simulator.\nThe itms-services:// url scheme is implemented but nonfunctional."; + + +/* Feedback */ + + +/* New Message Alert */ + +/* Alert Title */ +"HockeyFeedbackNewMessageTitle" = "New Feedback Response"; + +/* Alert Text */ +"HockeyFeedbackNewMessageText" = "A new response to your feedback is available. Would you like to view it?"; + +/* Alert Ignore Button */ +"HockeyFeedbackIgnore" = "Ignore"; + +/* Alert Show Button */ +"HockeyFeedbackShow" = "Show"; + + +/* List View */ + +/* Title */ +"HockeyFeedbackListTitle" = "Feedback"; + +/* Last Updated */ +"HockeyFeedbackListLastUpdated" = "Last Updated: %@"; + +/* Never Updated */ +"HockeyFeedbackListNeverUpdated" = "Never"; + +/* Write Feedback Button Title */ +"HockeyFeedbackListButonWriteFeedback" = "Write Feedback"; + +/* Write Response Button Title */ +"HockeyFeedbackListButonWriteResponse" = "Write Response"; + +/* User Data Set Name Button Title */ +"HockeyFeedbackListButonUserDataSetName" = "Set Your Name"; + +/* User Data Set Email Button Title */ +"HockeyFeedbackListButonUserDataSetEmail" = "Set Your Email"; + +/* User Data With Name Button Title */ +"HockeyFeedbackListButonUserDataWithName" = "Name: %@"; + +/* User Data With Email Button Title */ +"HockeyFeedbackListButonUserDataWithEmail" = "Email: %@"; + +/* User Name In Message If Name Not Set */ +"HockeyFeedbackListMessageUserNameNotSet" = "You"; + +/* Name In Message From Server If Name Not Set */ +"HockeyFeedbackListmessageResponseNameNotSet" = "Response"; + + +/* Compose Message */ + +/* Title */ +"HockeyFeedbackComposeTitle" = "New Feedback"; + +/* Send button */ +"HockeyFeedbackComposeSend" = "Send"; + + +/* Set User Data */ + +/* Title */ +"HockeyFeedbackUserDataTitle" = "Who Are You"; + +/* Description On What Should Be Entered */ +"HockeyFeedbackUserDataDescription" = "Please let us know who you are before writing us your feedback."; + +/* Name Field */ +"HockeyFeedbackUserDataName" = "Name"; + +/* Name Placeholder */ +"HockeyFeedbackUserDataNamePlaceHolder" = "John Doe"; + +/* Email Field */ +"HockeyFeedbackUserDataEmail" = "Email"; + +/* Email Placeholder */ +"HockeyFeedbackUserDataEmailPlaceholder" = "example@email.com"; diff --git a/Support/HockeySDK.xcodeproj/project.pbxproj b/Support/HockeySDK.xcodeproj/project.pbxproj index 092f25e6..de3fadd9 100644 --- a/Support/HockeySDK.xcodeproj/project.pbxproj +++ b/Support/HockeySDK.xcodeproj/project.pbxproj @@ -21,62 +21,148 @@ /* End PBXAggregateTarget section */ /* Begin PBXBuildFile section */ - 1E01118115BB6311007002AC /* BITUpdateManagerPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E01118015BB62FE007002AC /* BITUpdateManagerPrivate.h */; }; - 1E01118215BB6314007002AC /* BITCrashManagerPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E01117E15BB6228007002AC /* BITCrashManagerPrivate.h */; }; - 1E01118D15BB83FB007002AC /* BITUpdateViewControllerPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E01118C15BB83F6007002AC /* BITUpdateViewControllerPrivate.h */; }; 1E27EF2515BB5033000AE995 /* HockeySDK.strings in Resources */ = {isa = PBXBuildFile; fileRef = 1E59555F15B6F80E00A03429 /* HockeySDK.strings */; }; - 1E40BCB515A3487500BD64D9 /* BITCrashManagerDelegate.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E40BCB415A3487500BD64D9 /* BITCrashManagerDelegate.h */; settings = {ATTRIBUTES = (); }; }; - 1E40BCB915A3494400BD64D9 /* BITCrashReportTextFormatter.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E40BCB715A3494400BD64D9 /* BITCrashReportTextFormatter.h */; }; - 1E40BCBA15A3494400BD64D9 /* BITCrashReportTextFormatter.m in Sources */ = {isa = PBXBuildFile; fileRef = 1E40BCB815A3494400BD64D9 /* BITCrashReportTextFormatter.m */; }; - 1E59545715B6C41300A03429 /* BITAppVersionMetaInfo.m in Sources */ = {isa = PBXBuildFile; fileRef = E41EB45A148D7BF50015DEDC /* BITAppVersionMetaInfo.m */; }; - 1E59545C15B6C41300A03429 /* BITCrashManager.m in Sources */ = {isa = PBXBuildFile; fileRef = E41EB464148D7BF50015DEDC /* BITCrashManager.m */; }; + 1E49A43A1612223B00463151 /* BITFeedbackComposeViewController.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E49A42D1612223B00463151 /* BITFeedbackComposeViewController.h */; }; + 1E49A43B1612223B00463151 /* BITFeedbackComposeViewController.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E49A42D1612223B00463151 /* BITFeedbackComposeViewController.h */; }; + 1E49A43C1612223B00463151 /* BITFeedbackComposeViewController.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E49A42D1612223B00463151 /* BITFeedbackComposeViewController.h */; }; + 1E49A43D1612223B00463151 /* BITFeedbackComposeViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 1E49A42E1612223B00463151 /* BITFeedbackComposeViewController.m */; }; + 1E49A43E1612223B00463151 /* BITFeedbackComposeViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 1E49A42E1612223B00463151 /* BITFeedbackComposeViewController.m */; }; + 1E49A43F1612223B00463151 /* BITFeedbackComposeViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 1E49A42E1612223B00463151 /* BITFeedbackComposeViewController.m */; }; + 1E49A4401612223B00463151 /* BITFeedbackListViewCell.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E49A42F1612223B00463151 /* BITFeedbackListViewCell.h */; }; + 1E49A4411612223B00463151 /* BITFeedbackListViewCell.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E49A42F1612223B00463151 /* BITFeedbackListViewCell.h */; }; + 1E49A4421612223B00463151 /* BITFeedbackListViewCell.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E49A42F1612223B00463151 /* BITFeedbackListViewCell.h */; }; + 1E49A4431612223B00463151 /* BITFeedbackListViewCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 1E49A4301612223B00463151 /* BITFeedbackListViewCell.m */; }; + 1E49A4441612223B00463151 /* BITFeedbackListViewCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 1E49A4301612223B00463151 /* BITFeedbackListViewCell.m */; }; + 1E49A4451612223B00463151 /* BITFeedbackListViewCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 1E49A4301612223B00463151 /* BITFeedbackListViewCell.m */; }; + 1E49A4461612223B00463151 /* BITFeedbackListViewController.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E49A4311612223B00463151 /* BITFeedbackListViewController.h */; }; + 1E49A4471612223B00463151 /* BITFeedbackListViewController.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E49A4311612223B00463151 /* BITFeedbackListViewController.h */; }; + 1E49A4481612223B00463151 /* BITFeedbackListViewController.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E49A4311612223B00463151 /* BITFeedbackListViewController.h */; }; + 1E49A4491612223B00463151 /* BITFeedbackListViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 1E49A4321612223B00463151 /* BITFeedbackListViewController.m */; }; + 1E49A44A1612223B00463151 /* BITFeedbackListViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 1E49A4321612223B00463151 /* BITFeedbackListViewController.m */; }; + 1E49A44B1612223B00463151 /* BITFeedbackListViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 1E49A4321612223B00463151 /* BITFeedbackListViewController.m */; }; + 1E49A44C1612223B00463151 /* BITFeedbackManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E49A4331612223B00463151 /* BITFeedbackManager.h */; }; + 1E49A44D1612223B00463151 /* BITFeedbackManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E49A4331612223B00463151 /* BITFeedbackManager.h */; }; + 1E49A44E1612223B00463151 /* BITFeedbackManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E49A4331612223B00463151 /* BITFeedbackManager.h */; }; + 1E49A44F1612223B00463151 /* BITFeedbackManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 1E49A4341612223B00463151 /* BITFeedbackManager.m */; }; + 1E49A4501612223B00463151 /* BITFeedbackManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 1E49A4341612223B00463151 /* BITFeedbackManager.m */; }; + 1E49A4511612223B00463151 /* BITFeedbackManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 1E49A4341612223B00463151 /* BITFeedbackManager.m */; }; + 1E49A4521612223B00463151 /* BITFeedbackManagerPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E49A4351612223B00463151 /* BITFeedbackManagerPrivate.h */; }; + 1E49A4531612223B00463151 /* BITFeedbackManagerPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E49A4351612223B00463151 /* BITFeedbackManagerPrivate.h */; }; + 1E49A4541612223B00463151 /* BITFeedbackManagerPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E49A4351612223B00463151 /* BITFeedbackManagerPrivate.h */; }; + 1E49A4551612223B00463151 /* BITFeedbackMessage.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E49A4361612223B00463151 /* BITFeedbackMessage.h */; }; + 1E49A4561612223B00463151 /* BITFeedbackMessage.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E49A4361612223B00463151 /* BITFeedbackMessage.h */; }; + 1E49A4571612223B00463151 /* BITFeedbackMessage.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E49A4361612223B00463151 /* BITFeedbackMessage.h */; }; + 1E49A4581612223B00463151 /* BITFeedbackMessage.m in Sources */ = {isa = PBXBuildFile; fileRef = 1E49A4371612223B00463151 /* BITFeedbackMessage.m */; }; + 1E49A4591612223B00463151 /* BITFeedbackMessage.m in Sources */ = {isa = PBXBuildFile; fileRef = 1E49A4371612223B00463151 /* BITFeedbackMessage.m */; }; + 1E49A45A1612223B00463151 /* BITFeedbackMessage.m in Sources */ = {isa = PBXBuildFile; fileRef = 1E49A4371612223B00463151 /* BITFeedbackMessage.m */; }; + 1E49A45B1612223B00463151 /* BITFeedbackUserDataViewController.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E49A4381612223B00463151 /* BITFeedbackUserDataViewController.h */; }; + 1E49A45C1612223B00463151 /* BITFeedbackUserDataViewController.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E49A4381612223B00463151 /* BITFeedbackUserDataViewController.h */; }; + 1E49A45D1612223B00463151 /* BITFeedbackUserDataViewController.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E49A4381612223B00463151 /* BITFeedbackUserDataViewController.h */; }; + 1E49A45E1612223B00463151 /* BITFeedbackUserDataViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 1E49A4391612223B00463151 /* BITFeedbackUserDataViewController.m */; }; + 1E49A45F1612223B00463151 /* BITFeedbackUserDataViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 1E49A4391612223B00463151 /* BITFeedbackUserDataViewController.m */; }; + 1E49A4601612223B00463151 /* BITFeedbackUserDataViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 1E49A4391612223B00463151 /* BITFeedbackUserDataViewController.m */; }; + 1E49A46B1612226D00463151 /* BITAppVersionMetaInfo.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E49A4621612226D00463151 /* BITAppVersionMetaInfo.h */; }; + 1E49A46C1612226D00463151 /* BITAppVersionMetaInfo.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E49A4621612226D00463151 /* BITAppVersionMetaInfo.h */; }; + 1E49A46D1612226D00463151 /* BITAppVersionMetaInfo.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E49A4621612226D00463151 /* BITAppVersionMetaInfo.h */; }; + 1E49A46E1612226D00463151 /* BITAppVersionMetaInfo.m in Sources */ = {isa = PBXBuildFile; fileRef = 1E49A4631612226D00463151 /* BITAppVersionMetaInfo.m */; }; + 1E49A46F1612226D00463151 /* BITAppVersionMetaInfo.m in Sources */ = {isa = PBXBuildFile; fileRef = 1E49A4631612226D00463151 /* BITAppVersionMetaInfo.m */; }; + 1E49A4701612226D00463151 /* BITAppVersionMetaInfo.m in Sources */ = {isa = PBXBuildFile; fileRef = 1E49A4631612226D00463151 /* BITAppVersionMetaInfo.m */; }; + 1E49A4711612226D00463151 /* BITUpdateManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E49A4641612226D00463151 /* BITUpdateManager.h */; }; + 1E49A4721612226D00463151 /* BITUpdateManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E49A4641612226D00463151 /* BITUpdateManager.h */; }; + 1E49A4731612226D00463151 /* BITUpdateManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E49A4641612226D00463151 /* BITUpdateManager.h */; }; + 1E49A4741612226D00463151 /* BITUpdateManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 1E49A4651612226D00463151 /* BITUpdateManager.m */; }; + 1E49A4751612226D00463151 /* BITUpdateManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 1E49A4651612226D00463151 /* BITUpdateManager.m */; }; + 1E49A4761612226D00463151 /* BITUpdateManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 1E49A4651612226D00463151 /* BITUpdateManager.m */; }; + 1E49A4771612226D00463151 /* BITUpdateManagerDelegate.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E49A4661612226D00463151 /* BITUpdateManagerDelegate.h */; }; + 1E49A4781612226D00463151 /* BITUpdateManagerDelegate.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E49A4661612226D00463151 /* BITUpdateManagerDelegate.h */; }; + 1E49A4791612226D00463151 /* BITUpdateManagerDelegate.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E49A4661612226D00463151 /* BITUpdateManagerDelegate.h */; }; + 1E49A47A1612226D00463151 /* BITUpdateManagerPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E49A4671612226D00463151 /* BITUpdateManagerPrivate.h */; }; + 1E49A47B1612226D00463151 /* BITUpdateManagerPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E49A4671612226D00463151 /* BITUpdateManagerPrivate.h */; }; + 1E49A47C1612226D00463151 /* BITUpdateManagerPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E49A4671612226D00463151 /* BITUpdateManagerPrivate.h */; }; + 1E49A47D1612226D00463151 /* BITUpdateViewController.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E49A4681612226D00463151 /* BITUpdateViewController.h */; }; + 1E49A47E1612226D00463151 /* BITUpdateViewController.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E49A4681612226D00463151 /* BITUpdateViewController.h */; }; + 1E49A47F1612226D00463151 /* BITUpdateViewController.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E49A4681612226D00463151 /* BITUpdateViewController.h */; }; + 1E49A4801612226D00463151 /* BITUpdateViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 1E49A4691612226D00463151 /* BITUpdateViewController.m */; }; + 1E49A4811612226D00463151 /* BITUpdateViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 1E49A4691612226D00463151 /* BITUpdateViewController.m */; }; + 1E49A4821612226D00463151 /* BITUpdateViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 1E49A4691612226D00463151 /* BITUpdateViewController.m */; }; + 1E49A4831612226D00463151 /* BITUpdateViewControllerPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E49A46A1612226D00463151 /* BITUpdateViewControllerPrivate.h */; }; + 1E49A4841612226D00463151 /* BITUpdateViewControllerPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E49A46A1612226D00463151 /* BITUpdateViewControllerPrivate.h */; }; + 1E49A4851612226D00463151 /* BITUpdateViewControllerPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E49A46A1612226D00463151 /* BITUpdateViewControllerPrivate.h */; }; + 1E49A48D1612228800463151 /* BITCrashManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E49A4871612228800463151 /* BITCrashManager.h */; }; + 1E49A48E1612228800463151 /* BITCrashManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E49A4871612228800463151 /* BITCrashManager.h */; }; + 1E49A48F1612228800463151 /* BITCrashManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E49A4871612228800463151 /* BITCrashManager.h */; }; + 1E49A4901612228800463151 /* BITCrashManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 1E49A4881612228800463151 /* BITCrashManager.m */; }; + 1E49A4911612228800463151 /* BITCrashManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 1E49A4881612228800463151 /* BITCrashManager.m */; }; + 1E49A4921612228800463151 /* BITCrashManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 1E49A4881612228800463151 /* BITCrashManager.m */; }; + 1E49A4931612228800463151 /* BITCrashManagerDelegate.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E49A4891612228800463151 /* BITCrashManagerDelegate.h */; }; + 1E49A4941612228800463151 /* BITCrashManagerDelegate.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E49A4891612228800463151 /* BITCrashManagerDelegate.h */; }; + 1E49A4951612228800463151 /* BITCrashManagerDelegate.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E49A4891612228800463151 /* BITCrashManagerDelegate.h */; }; + 1E49A4961612228800463151 /* BITCrashManagerPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E49A48A1612228800463151 /* BITCrashManagerPrivate.h */; }; + 1E49A4971612228800463151 /* BITCrashManagerPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E49A48A1612228800463151 /* BITCrashManagerPrivate.h */; }; + 1E49A4981612228800463151 /* BITCrashManagerPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E49A48A1612228800463151 /* BITCrashManagerPrivate.h */; }; + 1E49A4991612228800463151 /* BITCrashReportTextFormatter.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E49A48B1612228800463151 /* BITCrashReportTextFormatter.h */; }; + 1E49A49A1612228800463151 /* BITCrashReportTextFormatter.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E49A48B1612228800463151 /* BITCrashReportTextFormatter.h */; }; + 1E49A49B1612228800463151 /* BITCrashReportTextFormatter.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E49A48B1612228800463151 /* BITCrashReportTextFormatter.h */; }; + 1E49A49C1612228800463151 /* BITCrashReportTextFormatter.m in Sources */ = {isa = PBXBuildFile; fileRef = 1E49A48C1612228800463151 /* BITCrashReportTextFormatter.m */; }; + 1E49A49D1612228800463151 /* BITCrashReportTextFormatter.m in Sources */ = {isa = PBXBuildFile; fileRef = 1E49A48C1612228800463151 /* BITCrashReportTextFormatter.m */; }; + 1E49A49E1612228800463151 /* BITCrashReportTextFormatter.m in Sources */ = {isa = PBXBuildFile; fileRef = 1E49A48C1612228800463151 /* BITCrashReportTextFormatter.m */; }; + 1E49A4AD161222B900463151 /* BITHockeyBaseManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E49A4A0161222B900463151 /* BITHockeyBaseManager.h */; }; + 1E49A4AE161222B900463151 /* BITHockeyBaseManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E49A4A0161222B900463151 /* BITHockeyBaseManager.h */; }; + 1E49A4AF161222B900463151 /* BITHockeyBaseManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E49A4A0161222B900463151 /* BITHockeyBaseManager.h */; }; + 1E49A4B0161222B900463151 /* BITHockeyBaseManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 1E49A4A1161222B900463151 /* BITHockeyBaseManager.m */; }; + 1E49A4B1161222B900463151 /* BITHockeyBaseManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 1E49A4A1161222B900463151 /* BITHockeyBaseManager.m */; }; + 1E49A4B2161222B900463151 /* BITHockeyBaseManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 1E49A4A1161222B900463151 /* BITHockeyBaseManager.m */; }; + 1E49A4B3161222B900463151 /* BITHockeyBaseManagerPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E49A4A2161222B900463151 /* BITHockeyBaseManagerPrivate.h */; }; + 1E49A4B4161222B900463151 /* BITHockeyBaseManagerPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E49A4A2161222B900463151 /* BITHockeyBaseManagerPrivate.h */; }; + 1E49A4B5161222B900463151 /* BITHockeyBaseManagerPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E49A4A2161222B900463151 /* BITHockeyBaseManagerPrivate.h */; }; + 1E49A4B6161222B900463151 /* BITHockeyBaseViewController.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E49A4A3161222B900463151 /* BITHockeyBaseViewController.h */; }; + 1E49A4B7161222B900463151 /* BITHockeyBaseViewController.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E49A4A3161222B900463151 /* BITHockeyBaseViewController.h */; }; + 1E49A4B8161222B900463151 /* BITHockeyBaseViewController.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E49A4A3161222B900463151 /* BITHockeyBaseViewController.h */; }; + 1E49A4B9161222B900463151 /* BITHockeyBaseViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 1E49A4A4161222B900463151 /* BITHockeyBaseViewController.m */; }; + 1E49A4BA161222B900463151 /* BITHockeyBaseViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 1E49A4A4161222B900463151 /* BITHockeyBaseViewController.m */; }; + 1E49A4BB161222B900463151 /* BITHockeyBaseViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 1E49A4A4161222B900463151 /* BITHockeyBaseViewController.m */; }; + 1E49A4BC161222B900463151 /* BITHockeyHelper.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E49A4A5161222B900463151 /* BITHockeyHelper.h */; }; + 1E49A4BD161222B900463151 /* BITHockeyHelper.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E49A4A5161222B900463151 /* BITHockeyHelper.h */; }; + 1E49A4BE161222B900463151 /* BITHockeyHelper.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E49A4A5161222B900463151 /* BITHockeyHelper.h */; }; + 1E49A4BF161222B900463151 /* BITHockeyHelper.m in Sources */ = {isa = PBXBuildFile; fileRef = 1E49A4A6161222B900463151 /* BITHockeyHelper.m */; }; + 1E49A4C0161222B900463151 /* BITHockeyHelper.m in Sources */ = {isa = PBXBuildFile; fileRef = 1E49A4A6161222B900463151 /* BITHockeyHelper.m */; }; + 1E49A4C1161222B900463151 /* BITHockeyHelper.m in Sources */ = {isa = PBXBuildFile; fileRef = 1E49A4A6161222B900463151 /* BITHockeyHelper.m */; }; + 1E49A4C2161222B900463151 /* PSAppStoreHeader.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E49A4A7161222B900463151 /* PSAppStoreHeader.h */; }; + 1E49A4C3161222B900463151 /* PSAppStoreHeader.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E49A4A7161222B900463151 /* PSAppStoreHeader.h */; }; + 1E49A4C4161222B900463151 /* PSAppStoreHeader.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E49A4A7161222B900463151 /* PSAppStoreHeader.h */; }; + 1E49A4C5161222B900463151 /* PSAppStoreHeader.m in Sources */ = {isa = PBXBuildFile; fileRef = 1E49A4A8161222B900463151 /* PSAppStoreHeader.m */; }; + 1E49A4C6161222B900463151 /* PSAppStoreHeader.m in Sources */ = {isa = PBXBuildFile; fileRef = 1E49A4A8161222B900463151 /* PSAppStoreHeader.m */; }; + 1E49A4C7161222B900463151 /* PSAppStoreHeader.m in Sources */ = {isa = PBXBuildFile; fileRef = 1E49A4A8161222B900463151 /* PSAppStoreHeader.m */; }; + 1E49A4C8161222B900463151 /* PSStoreButton.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E49A4A9161222B900463151 /* PSStoreButton.h */; }; + 1E49A4C9161222B900463151 /* PSStoreButton.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E49A4A9161222B900463151 /* PSStoreButton.h */; }; + 1E49A4CA161222B900463151 /* PSStoreButton.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E49A4A9161222B900463151 /* PSStoreButton.h */; }; + 1E49A4CB161222B900463151 /* PSStoreButton.m in Sources */ = {isa = PBXBuildFile; fileRef = 1E49A4AA161222B900463151 /* PSStoreButton.m */; }; + 1E49A4CC161222B900463151 /* PSStoreButton.m in Sources */ = {isa = PBXBuildFile; fileRef = 1E49A4AA161222B900463151 /* PSStoreButton.m */; }; + 1E49A4CD161222B900463151 /* PSStoreButton.m in Sources */ = {isa = PBXBuildFile; fileRef = 1E49A4AA161222B900463151 /* PSStoreButton.m */; }; + 1E49A4CE161222B900463151 /* PSWebTableViewCell.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E49A4AB161222B900463151 /* PSWebTableViewCell.h */; }; + 1E49A4CF161222B900463151 /* PSWebTableViewCell.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E49A4AB161222B900463151 /* PSWebTableViewCell.h */; }; + 1E49A4D0161222B900463151 /* PSWebTableViewCell.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E49A4AB161222B900463151 /* PSWebTableViewCell.h */; }; + 1E49A4D1161222B900463151 /* PSWebTableViewCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 1E49A4AC161222B900463151 /* PSWebTableViewCell.m */; }; + 1E49A4D2161222B900463151 /* PSWebTableViewCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 1E49A4AC161222B900463151 /* PSWebTableViewCell.m */; }; + 1E49A4D3161222B900463151 /* PSWebTableViewCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 1E49A4AC161222B900463151 /* PSWebTableViewCell.m */; }; + 1E49A4D6161222D400463151 /* HockeySDKPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E49A4D4161222D400463151 /* HockeySDKPrivate.h */; }; + 1E49A4D7161222D400463151 /* HockeySDKPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E49A4D4161222D400463151 /* HockeySDKPrivate.h */; }; + 1E49A4D8161222D400463151 /* HockeySDKPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E49A4D4161222D400463151 /* HockeySDKPrivate.h */; }; + 1E49A4D9161222D400463151 /* HockeySDKPrivate.m in Sources */ = {isa = PBXBuildFile; fileRef = 1E49A4D5161222D400463151 /* HockeySDKPrivate.m */; }; + 1E49A4DA161222D400463151 /* HockeySDKPrivate.m in Sources */ = {isa = PBXBuildFile; fileRef = 1E49A4D5161222D400463151 /* HockeySDKPrivate.m */; }; + 1E49A4DB161222D400463151 /* HockeySDKPrivate.m in Sources */ = {isa = PBXBuildFile; fileRef = 1E49A4D5161222D400463151 /* HockeySDKPrivate.m */; }; 1E59545D15B6C41300A03429 /* BITHockeyManager.m in Sources */ = {isa = PBXBuildFile; fileRef = E41EB466148D7BF50015DEDC /* BITHockeyManager.m */; }; - 1E59545F15B6C41300A03429 /* PSAppStoreHeader.m in Sources */ = {isa = PBXBuildFile; fileRef = E41EB46A148D7BF50015DEDC /* PSAppStoreHeader.m */; }; - 1E59546015B6C41300A03429 /* PSStoreButton.m in Sources */ = {isa = PBXBuildFile; fileRef = E41EB46C148D7BF50015DEDC /* PSStoreButton.m */; }; - 1E59546115B6C41300A03429 /* PSWebTableViewCell.m in Sources */ = {isa = PBXBuildFile; fileRef = E41EB46E148D7BF50015DEDC /* PSWebTableViewCell.m */; }; - 1E59546315B6C41300A03429 /* BITCrashReportTextFormatter.m in Sources */ = {isa = PBXBuildFile; fileRef = 1E40BCB815A3494400BD64D9 /* BITCrashReportTextFormatter.m */; }; 1E59546615B6C41300A03429 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E400561D148D79B500EB22B9 /* Foundation.framework */; }; 1E59546715B6C41300A03429 /* CrashReporter.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E41EB48B148D7C4E0015DEDC /* CrashReporter.framework */; }; - 1E59546915B6C41300A03429 /* BITAppVersionMetaInfo.h in Headers */ = {isa = PBXBuildFile; fileRef = E41EB459148D7BF50015DEDC /* BITAppVersionMetaInfo.h */; }; - 1E59546B15B6C41300A03429 /* BITUpdateManager.h in Headers */ = {isa = PBXBuildFile; fileRef = E41EB45D148D7BF50015DEDC /* BITUpdateManager.h */; }; 1E59546E15B6C41300A03429 /* BITHockeyManager.h in Headers */ = {isa = PBXBuildFile; fileRef = E41EB465148D7BF50015DEDC /* BITHockeyManager.h */; }; - 1E59547015B6C41300A03429 /* PSAppStoreHeader.h in Headers */ = {isa = PBXBuildFile; fileRef = E41EB469148D7BF50015DEDC /* PSAppStoreHeader.h */; }; - 1E59547115B6C41300A03429 /* PSStoreButton.h in Headers */ = {isa = PBXBuildFile; fileRef = E41EB46B148D7BF50015DEDC /* PSStoreButton.h */; }; - 1E59547215B6C41300A03429 /* PSWebTableViewCell.h in Headers */ = {isa = PBXBuildFile; fileRef = E41EB46D148D7BF50015DEDC /* PSWebTableViewCell.h */; }; - 1E59547515B6C41300A03429 /* BITCrashManagerDelegate.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E40BCB415A3487500BD64D9 /* BITCrashManagerDelegate.h */; settings = {ATTRIBUTES = (); }; }; - 1E59547615B6C41300A03429 /* BITCrashReportTextFormatter.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E40BCB715A3494400BD64D9 /* BITCrashReportTextFormatter.h */; }; 1E59547815B6C41300A03429 /* HockeySDK.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E71509A15B5C76F004E88FF /* HockeySDK.h */; settings = {ATTRIBUTES = (); }; }; 1E59548315B6C4EF00A03429 /* HockeySDK.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E71509A15B5C76F004E88FF /* HockeySDK.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 1E59548415B6C4F300A03429 /* BITCrashManagerDelegate.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E40BCB415A3487500BD64D9 /* BITCrashManagerDelegate.h */; settings = {ATTRIBUTES = (Public, ); }; }; 1E59548515B6C4FB00A03429 /* BITHockeyManager.h in Headers */ = {isa = PBXBuildFile; fileRef = E41EB465148D7BF50015DEDC /* BITHockeyManager.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 1E59548715B6C51100A03429 /* BITCrashReportTextFormatter.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E40BCB715A3494400BD64D9 /* BITCrashReportTextFormatter.h */; }; - 1E5954B315B6E15300A03429 /* BITUpdateManager.h in Headers */ = {isa = PBXBuildFile; fileRef = E41EB45D148D7BF50015DEDC /* BITUpdateManager.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 1E5954B615B6E17700A03429 /* PSStoreButton.h in Headers */ = {isa = PBXBuildFile; fileRef = E41EB46B148D7BF50015DEDC /* PSStoreButton.h */; settings = {ATTRIBUTES = (); }; }; - 1E5954B815B6E19C00A03429 /* BITAppVersionMetaInfo.h in Headers */ = {isa = PBXBuildFile; fileRef = E41EB459148D7BF50015DEDC /* BITAppVersionMetaInfo.h */; settings = {ATTRIBUTES = (); }; }; - 1E5954CD15B6F24A00A03429 /* BITAppVersionMetaInfo.m in Sources */ = {isa = PBXBuildFile; fileRef = E41EB45A148D7BF50015DEDC /* BITAppVersionMetaInfo.m */; }; - 1E5954D215B6F24A00A03429 /* BITCrashManager.m in Sources */ = {isa = PBXBuildFile; fileRef = E41EB464148D7BF50015DEDC /* BITCrashManager.m */; }; 1E5954D315B6F24A00A03429 /* BITHockeyManager.m in Sources */ = {isa = PBXBuildFile; fileRef = E41EB466148D7BF50015DEDC /* BITHockeyManager.m */; }; - 1E5954D515B6F24A00A03429 /* PSAppStoreHeader.m in Sources */ = {isa = PBXBuildFile; fileRef = E41EB46A148D7BF50015DEDC /* PSAppStoreHeader.m */; }; - 1E5954D615B6F24A00A03429 /* PSStoreButton.m in Sources */ = {isa = PBXBuildFile; fileRef = E41EB46C148D7BF50015DEDC /* PSStoreButton.m */; }; - 1E5954D715B6F24A00A03429 /* PSWebTableViewCell.m in Sources */ = {isa = PBXBuildFile; fileRef = E41EB46E148D7BF50015DEDC /* PSWebTableViewCell.m */; }; - 1E5954D915B6F24A00A03429 /* BITCrashReportTextFormatter.m in Sources */ = {isa = PBXBuildFile; fileRef = 1E40BCB815A3494400BD64D9 /* BITCrashReportTextFormatter.m */; }; 1E5954DC15B6F24A00A03429 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E400561D148D79B500EB22B9 /* Foundation.framework */; }; 1E5954DD15B6F24A00A03429 /* CrashReporter.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E41EB48B148D7C4E0015DEDC /* CrashReporter.framework */; }; - 1E59558D15B6FDA500A03429 /* PSAppStoreHeader.h in Headers */ = {isa = PBXBuildFile; fileRef = E41EB469148D7BF50015DEDC /* PSAppStoreHeader.h */; }; - 1E59558E15B6FDA500A03429 /* PSStoreButton.h in Headers */ = {isa = PBXBuildFile; fileRef = E41EB46B148D7BF50015DEDC /* PSStoreButton.h */; }; - 1E59558F15B6FDA500A03429 /* PSWebTableViewCell.h in Headers */ = {isa = PBXBuildFile; fileRef = E41EB46D148D7BF50015DEDC /* PSWebTableViewCell.h */; }; - 1E59559215B6FDA500A03429 /* BITAppVersionMetaInfo.h in Headers */ = {isa = PBXBuildFile; fileRef = E41EB459148D7BF50015DEDC /* BITAppVersionMetaInfo.h */; }; - 1E59559415B6FDA500A03429 /* BITUpdateManager.h in Headers */ = {isa = PBXBuildFile; fileRef = E41EB45D148D7BF50015DEDC /* BITUpdateManager.h */; settings = {ATTRIBUTES = (); }; }; - 1E59559815B6FDA500A03429 /* BITCrashManagerDelegate.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E40BCB415A3487500BD64D9 /* BITCrashManagerDelegate.h */; settings = {ATTRIBUTES = (); }; }; - 1E59559915B6FDA500A03429 /* BITCrashReportTextFormatter.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E40BCB715A3494400BD64D9 /* BITCrashReportTextFormatter.h */; }; 1E59559A15B6FDA500A03429 /* BITHockeyManager.h in Headers */ = {isa = PBXBuildFile; fileRef = E41EB465148D7BF50015DEDC /* BITHockeyManager.h */; settings = {ATTRIBUTES = (); }; }; 1E59559B15B6FDA500A03429 /* HockeySDK.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E71509A15B5C76F004E88FF /* HockeySDK.h */; settings = {ATTRIBUTES = (); }; }; - 1E59559D15B70F4D00A03429 /* HockeySDKPrivate.m in Sources */ = {isa = PBXBuildFile; fileRef = 1E59559C15B70F4D00A03429 /* HockeySDKPrivate.m */; }; - 1E59559E15B70F4D00A03429 /* HockeySDKPrivate.m in Sources */ = {isa = PBXBuildFile; fileRef = 1E59559C15B70F4D00A03429 /* HockeySDKPrivate.m */; }; - 1E59559F15B70F4D00A03429 /* HockeySDKPrivate.m in Sources */ = {isa = PBXBuildFile; fileRef = 1E59559C15B70F4D00A03429 /* HockeySDKPrivate.m */; }; - 1E5955A115B70F6900A03429 /* HockeySDKPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E5955A015B70F6900A03429 /* HockeySDKPrivate.h */; }; - 1E5955A215B70F6900A03429 /* HockeySDKPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E5955A015B70F6900A03429 /* HockeySDKPrivate.h */; }; - 1E5955A315B70F6900A03429 /* HockeySDKPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E5955A015B70F6900A03429 /* HockeySDKPrivate.h */; }; 1E5955C615B71C8600A03429 /* authorize_denied.png in Resources */ = {isa = PBXBuildFile; fileRef = 1E5955BB15B71C8600A03429 /* authorize_denied.png */; }; 1E5955C715B71C8600A03429 /* authorize_denied@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 1E5955BC15B71C8600A03429 /* authorize_denied@2x.png */; }; 1E5955C815B71C8600A03429 /* authorize_request.png in Resources */ = {isa = PBXBuildFile; fileRef = 1E5955BD15B71C8600A03429 /* authorize_request.png */; }; @@ -86,51 +172,17 @@ 1E5955CC15B71C8600A03429 /* buttonHighlight@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 1E5955C115B71C8600A03429 /* buttonHighlight@2x.png */; }; 1E5955CF15B71C8600A03429 /* IconGradient.png in Resources */ = {isa = PBXBuildFile; fileRef = 1E5955C415B71C8600A03429 /* IconGradient.png */; }; 1E5955D015B71C8600A03429 /* IconGradient@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 1E5955C515B71C8600A03429 /* IconGradient@2x.png */; }; - 1E5955D215B72E5400A03429 /* BITCrashManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E5955D115B72E5300A03429 /* BITCrashManager.h */; }; - 1E5955D315B72E5400A03429 /* BITCrashManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E5955D115B72E5300A03429 /* BITCrashManager.h */; }; - 1E5955D415B72E5400A03429 /* BITCrashManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E5955D115B72E5300A03429 /* BITCrashManager.h */; }; - 1E5955D615B72ED500A03429 /* BITUpdateManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 1E5955D515B72ED500A03429 /* BITUpdateManager.m */; }; - 1E5955D715B72ED500A03429 /* BITUpdateManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 1E5955D515B72ED500A03429 /* BITUpdateManager.m */; }; - 1E5955D815B72ED500A03429 /* BITUpdateManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 1E5955D515B72ED500A03429 /* BITUpdateManager.m */; }; - 1E5955E315B751EE00A03429 /* BITUpdateViewController.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E5955E215B751ED00A03429 /* BITUpdateViewController.h */; }; - 1E5955E415B751EE00A03429 /* BITUpdateViewController.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E5955E215B751ED00A03429 /* BITUpdateViewController.h */; }; - 1E5955E515B751EE00A03429 /* BITUpdateViewController.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E5955E215B751ED00A03429 /* BITUpdateViewController.h */; }; - 1E5955E715B751FB00A03429 /* BITUpdateViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 1E5955E615B751FB00A03429 /* BITUpdateViewController.m */; }; - 1E5955E815B751FB00A03429 /* BITUpdateViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 1E5955E615B751FB00A03429 /* BITUpdateViewController.m */; }; - 1E5955E915B751FB00A03429 /* BITUpdateViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 1E5955E615B751FB00A03429 /* BITUpdateViewController.m */; }; - 1E5955EF15B7752300A03429 /* BITUpdateManagerDelegate.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E5955EE15B7752200A03429 /* BITUpdateManagerDelegate.h */; }; - 1E5955F015B7752300A03429 /* BITUpdateManagerDelegate.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E5955EE15B7752200A03429 /* BITUpdateManagerDelegate.h */; }; - 1E5955F115B7752300A03429 /* BITUpdateManagerDelegate.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E5955EE15B7752200A03429 /* BITUpdateManagerDelegate.h */; }; - 1E5955F315B77F5600A03429 /* PSAppStoreHeader.h in Headers */ = {isa = PBXBuildFile; fileRef = E41EB469148D7BF50015DEDC /* PSAppStoreHeader.h */; }; - 1E5955F415B77F5E00A03429 /* PSWebTableViewCell.h in Headers */ = {isa = PBXBuildFile; fileRef = E41EB46D148D7BF50015DEDC /* PSWebTableViewCell.h */; }; - 1E5955F615B77F6500A03429 /* HockeySDKPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E5955A015B70F6900A03429 /* HockeySDKPrivate.h */; }; - 1E5955F715B77F7600A03429 /* BITUpdateManagerDelegate.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E5955EE15B7752200A03429 /* BITUpdateManagerDelegate.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 1E5955F815B77F7C00A03429 /* BITUpdateViewController.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E5955E215B751ED00A03429 /* BITUpdateViewController.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 1E5955F915B77F8200A03429 /* BITCrashManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E5955D115B72E5300A03429 /* BITCrashManager.h */; settings = {ATTRIBUTES = (Public, ); }; }; 1E5955FB15B7877B00A03429 /* BITHockeyManagerDelegate.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E5955FA15B7877A00A03429 /* BITHockeyManagerDelegate.h */; }; 1E5955FC15B7877B00A03429 /* BITHockeyManagerDelegate.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E5955FA15B7877A00A03429 /* BITHockeyManagerDelegate.h */; }; 1E5955FD15B7877B00A03429 /* BITHockeyManagerDelegate.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E5955FA15B7877A00A03429 /* BITHockeyManagerDelegate.h */; }; 1E5955FE15B787D600A03429 /* BITHockeyManagerDelegate.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E5955FA15B7877A00A03429 /* BITHockeyManagerDelegate.h */; settings = {ATTRIBUTES = (Public, ); }; }; 1E71509B15B5C76F004E88FF /* HockeySDK.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E71509A15B5C76F004E88FF /* HockeySDK.h */; settings = {ATTRIBUTES = (); }; }; - 1EB6046D15EF6B3200F69880 /* BITHockeyHelper.h in Headers */ = {isa = PBXBuildFile; fileRef = 1EB6046B15EF6B3200F69880 /* BITHockeyHelper.h */; }; - 1EB6046E15EF6B3200F69880 /* BITHockeyHelper.h in Headers */ = {isa = PBXBuildFile; fileRef = 1EB6046B15EF6B3200F69880 /* BITHockeyHelper.h */; }; - 1EB6046F15EF6B3200F69880 /* BITHockeyHelper.h in Headers */ = {isa = PBXBuildFile; fileRef = 1EB6046B15EF6B3200F69880 /* BITHockeyHelper.h */; }; - 1EB6047015EF6B3200F69880 /* BITHockeyHelper.m in Sources */ = {isa = PBXBuildFile; fileRef = 1EB6046C15EF6B3200F69880 /* BITHockeyHelper.m */; }; - 1EB6047115EF6B3200F69880 /* BITHockeyHelper.m in Sources */ = {isa = PBXBuildFile; fileRef = 1EB6046C15EF6B3200F69880 /* BITHockeyHelper.m */; }; - 1EB6047215EF6B3200F69880 /* BITHockeyHelper.m in Sources */ = {isa = PBXBuildFile; fileRef = 1EB6046C15EF6B3200F69880 /* BITHockeyHelper.m */; }; + 1EC69F5E1615001500808FD9 /* BITHockeyManagerPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 1EC69F5D1615001500808FD9 /* BITHockeyManagerPrivate.h */; }; + 1EC69F5F1615001500808FD9 /* BITHockeyManagerPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 1EC69F5D1615001500808FD9 /* BITHockeyManagerPrivate.h */; }; + 1EC69F601615001500808FD9 /* BITHockeyManagerPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 1EC69F5D1615001500808FD9 /* BITHockeyManagerPrivate.h */; }; E400561E148D79B500EB22B9 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E400561D148D79B500EB22B9 /* Foundation.framework */; }; - E41EB471148D7BF50015DEDC /* BITAppVersionMetaInfo.h in Headers */ = {isa = PBXBuildFile; fileRef = E41EB459148D7BF50015DEDC /* BITAppVersionMetaInfo.h */; }; - E41EB472148D7BF50015DEDC /* BITAppVersionMetaInfo.m in Sources */ = {isa = PBXBuildFile; fileRef = E41EB45A148D7BF50015DEDC /* BITAppVersionMetaInfo.m */; }; - E41EB475148D7BF50015DEDC /* BITUpdateManager.h in Headers */ = {isa = PBXBuildFile; fileRef = E41EB45D148D7BF50015DEDC /* BITUpdateManager.h */; }; - E41EB47C148D7BF50015DEDC /* BITCrashManager.m in Sources */ = {isa = PBXBuildFile; fileRef = E41EB464148D7BF50015DEDC /* BITCrashManager.m */; }; E41EB47D148D7BF50015DEDC /* BITHockeyManager.h in Headers */ = {isa = PBXBuildFile; fileRef = E41EB465148D7BF50015DEDC /* BITHockeyManager.h */; }; E41EB47E148D7BF50015DEDC /* BITHockeyManager.m in Sources */ = {isa = PBXBuildFile; fileRef = E41EB466148D7BF50015DEDC /* BITHockeyManager.m */; }; - E41EB481148D7BF50015DEDC /* PSAppStoreHeader.h in Headers */ = {isa = PBXBuildFile; fileRef = E41EB469148D7BF50015DEDC /* PSAppStoreHeader.h */; }; - E41EB482148D7BF50015DEDC /* PSAppStoreHeader.m in Sources */ = {isa = PBXBuildFile; fileRef = E41EB46A148D7BF50015DEDC /* PSAppStoreHeader.m */; }; - E41EB483148D7BF50015DEDC /* PSStoreButton.h in Headers */ = {isa = PBXBuildFile; fileRef = E41EB46B148D7BF50015DEDC /* PSStoreButton.h */; }; - E41EB484148D7BF50015DEDC /* PSStoreButton.m in Sources */ = {isa = PBXBuildFile; fileRef = E41EB46C148D7BF50015DEDC /* PSStoreButton.m */; }; - E41EB485148D7BF50015DEDC /* PSWebTableViewCell.h in Headers */ = {isa = PBXBuildFile; fileRef = E41EB46D148D7BF50015DEDC /* PSWebTableViewCell.h */; }; - E41EB486148D7BF50015DEDC /* PSWebTableViewCell.m in Sources */ = {isa = PBXBuildFile; fileRef = E41EB46E148D7BF50015DEDC /* PSWebTableViewCell.m */; }; E41EB48C148D7C4E0015DEDC /* CrashReporter.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E41EB48B148D7C4E0015DEDC /* CrashReporter.framework */; }; /* End PBXBuildFile section */ @@ -166,12 +218,49 @@ /* End PBXContainerItemProxy section */ /* Begin PBXFileReference section */ - 1E01117E15BB6228007002AC /* BITCrashManagerPrivate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = BITCrashManagerPrivate.h; sourceTree = ""; }; - 1E01118015BB62FE007002AC /* BITUpdateManagerPrivate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = BITUpdateManagerPrivate.h; sourceTree = ""; }; - 1E01118C15BB83F6007002AC /* BITUpdateViewControllerPrivate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = BITUpdateViewControllerPrivate.h; sourceTree = ""; }; - 1E40BCB415A3487500BD64D9 /* BITCrashManagerDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BITCrashManagerDelegate.h; sourceTree = ""; }; - 1E40BCB715A3494400BD64D9 /* BITCrashReportTextFormatter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BITCrashReportTextFormatter.h; sourceTree = ""; }; - 1E40BCB815A3494400BD64D9 /* BITCrashReportTextFormatter.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = BITCrashReportTextFormatter.m; sourceTree = ""; }; + 1E49A42D1612223B00463151 /* BITFeedbackComposeViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BITFeedbackComposeViewController.h; sourceTree = ""; }; + 1E49A42E1612223B00463151 /* BITFeedbackComposeViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = BITFeedbackComposeViewController.m; sourceTree = ""; }; + 1E49A42F1612223B00463151 /* BITFeedbackListViewCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BITFeedbackListViewCell.h; sourceTree = ""; }; + 1E49A4301612223B00463151 /* BITFeedbackListViewCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = BITFeedbackListViewCell.m; sourceTree = ""; }; + 1E49A4311612223B00463151 /* BITFeedbackListViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BITFeedbackListViewController.h; sourceTree = ""; }; + 1E49A4321612223B00463151 /* BITFeedbackListViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = BITFeedbackListViewController.m; sourceTree = ""; }; + 1E49A4331612223B00463151 /* BITFeedbackManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BITFeedbackManager.h; sourceTree = ""; }; + 1E49A4341612223B00463151 /* BITFeedbackManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = BITFeedbackManager.m; sourceTree = ""; }; + 1E49A4351612223B00463151 /* BITFeedbackManagerPrivate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BITFeedbackManagerPrivate.h; sourceTree = ""; }; + 1E49A4361612223B00463151 /* BITFeedbackMessage.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BITFeedbackMessage.h; sourceTree = ""; }; + 1E49A4371612223B00463151 /* BITFeedbackMessage.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = BITFeedbackMessage.m; sourceTree = ""; }; + 1E49A4381612223B00463151 /* BITFeedbackUserDataViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BITFeedbackUserDataViewController.h; sourceTree = ""; }; + 1E49A4391612223B00463151 /* BITFeedbackUserDataViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = BITFeedbackUserDataViewController.m; sourceTree = ""; }; + 1E49A4621612226D00463151 /* BITAppVersionMetaInfo.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BITAppVersionMetaInfo.h; sourceTree = ""; }; + 1E49A4631612226D00463151 /* BITAppVersionMetaInfo.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = BITAppVersionMetaInfo.m; sourceTree = ""; }; + 1E49A4641612226D00463151 /* BITUpdateManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BITUpdateManager.h; sourceTree = ""; }; + 1E49A4651612226D00463151 /* BITUpdateManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = BITUpdateManager.m; sourceTree = ""; }; + 1E49A4661612226D00463151 /* BITUpdateManagerDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BITUpdateManagerDelegate.h; sourceTree = ""; }; + 1E49A4671612226D00463151 /* BITUpdateManagerPrivate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BITUpdateManagerPrivate.h; sourceTree = ""; }; + 1E49A4681612226D00463151 /* BITUpdateViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BITUpdateViewController.h; sourceTree = ""; }; + 1E49A4691612226D00463151 /* BITUpdateViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = BITUpdateViewController.m; sourceTree = ""; }; + 1E49A46A1612226D00463151 /* BITUpdateViewControllerPrivate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BITUpdateViewControllerPrivate.h; sourceTree = ""; }; + 1E49A4871612228800463151 /* BITCrashManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BITCrashManager.h; sourceTree = ""; }; + 1E49A4881612228800463151 /* BITCrashManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = BITCrashManager.m; sourceTree = ""; }; + 1E49A4891612228800463151 /* BITCrashManagerDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BITCrashManagerDelegate.h; sourceTree = ""; }; + 1E49A48A1612228800463151 /* BITCrashManagerPrivate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BITCrashManagerPrivate.h; sourceTree = ""; }; + 1E49A48B1612228800463151 /* BITCrashReportTextFormatter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BITCrashReportTextFormatter.h; sourceTree = ""; }; + 1E49A48C1612228800463151 /* BITCrashReportTextFormatter.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = BITCrashReportTextFormatter.m; sourceTree = ""; }; + 1E49A4A0161222B900463151 /* BITHockeyBaseManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BITHockeyBaseManager.h; sourceTree = ""; }; + 1E49A4A1161222B900463151 /* BITHockeyBaseManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = BITHockeyBaseManager.m; sourceTree = ""; }; + 1E49A4A2161222B900463151 /* BITHockeyBaseManagerPrivate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BITHockeyBaseManagerPrivate.h; sourceTree = ""; }; + 1E49A4A3161222B900463151 /* BITHockeyBaseViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BITHockeyBaseViewController.h; sourceTree = ""; }; + 1E49A4A4161222B900463151 /* BITHockeyBaseViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = BITHockeyBaseViewController.m; sourceTree = ""; }; + 1E49A4A5161222B900463151 /* BITHockeyHelper.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BITHockeyHelper.h; sourceTree = ""; }; + 1E49A4A6161222B900463151 /* BITHockeyHelper.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = BITHockeyHelper.m; sourceTree = ""; }; + 1E49A4A7161222B900463151 /* PSAppStoreHeader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PSAppStoreHeader.h; sourceTree = ""; }; + 1E49A4A8161222B900463151 /* PSAppStoreHeader.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PSAppStoreHeader.m; sourceTree = ""; }; + 1E49A4A9161222B900463151 /* PSStoreButton.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PSStoreButton.h; sourceTree = ""; }; + 1E49A4AA161222B900463151 /* PSStoreButton.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PSStoreButton.m; sourceTree = ""; }; + 1E49A4AB161222B900463151 /* PSWebTableViewCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PSWebTableViewCell.h; sourceTree = ""; }; + 1E49A4AC161222B900463151 /* PSWebTableViewCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PSWebTableViewCell.m; sourceTree = ""; }; + 1E49A4D4161222D400463151 /* HockeySDKPrivate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HockeySDKPrivate.h; sourceTree = ""; }; + 1E49A4D5161222D400463151 /* HockeySDKPrivate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HockeySDKPrivate.m; sourceTree = ""; }; 1E59544115B6C3DC00A03429 /* HockeySDK.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = HockeySDK.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 1E59547C15B6C41300A03429 /* libHockeySDK-iphonesimulator.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libHockeySDK-iphonesimulator.a"; sourceTree = BUILT_PRODUCTS_DIR; }; 1E5954F215B6F24A00A03429 /* libHockeySDK.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libHockeySDK.a; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -190,8 +279,6 @@ 1E59557615B6F85E00A03429 /* tr */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.strings; name = tr; path = tr.lproj/HockeySDK.strings; sourceTree = ""; }; 1E59557815B6F86600A03429 /* zh_CN */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.strings; name = zh_CN; path = zh_CN.lproj/HockeySDK.strings; sourceTree = ""; }; 1E59557A15B6F86E00A03429 /* zh_TW */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.strings; name = zh_TW; path = zh_TW.lproj/HockeySDK.strings; sourceTree = ""; }; - 1E59559C15B70F4D00A03429 /* HockeySDKPrivate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HockeySDKPrivate.m; sourceTree = ""; }; - 1E5955A015B70F6900A03429 /* HockeySDKPrivate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HockeySDKPrivate.h; sourceTree = ""; }; 1E5955BB15B71C8600A03429 /* authorize_denied.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = authorize_denied.png; sourceTree = ""; }; 1E5955BC15B71C8600A03429 /* authorize_denied@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "authorize_denied@2x.png"; sourceTree = ""; }; 1E5955BD15B71C8600A03429 /* authorize_request.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = authorize_request.png; sourceTree = ""; }; @@ -201,31 +288,15 @@ 1E5955C115B71C8600A03429 /* buttonHighlight@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "buttonHighlight@2x.png"; sourceTree = ""; }; 1E5955C415B71C8600A03429 /* IconGradient.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = IconGradient.png; sourceTree = ""; }; 1E5955C515B71C8600A03429 /* IconGradient@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "IconGradient@2x.png"; sourceTree = ""; }; - 1E5955D115B72E5300A03429 /* BITCrashManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BITCrashManager.h; sourceTree = ""; }; - 1E5955D515B72ED500A03429 /* BITUpdateManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; lineEnding = 0; path = BITUpdateManager.m; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.objc; }; - 1E5955E215B751ED00A03429 /* BITUpdateViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BITUpdateViewController.h; sourceTree = ""; }; - 1E5955E615B751FB00A03429 /* BITUpdateViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = BITUpdateViewController.m; sourceTree = ""; }; - 1E5955EE15B7752200A03429 /* BITUpdateManagerDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BITUpdateManagerDelegate.h; sourceTree = ""; }; 1E5955FA15B7877A00A03429 /* BITHockeyManagerDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BITHockeyManagerDelegate.h; sourceTree = ""; }; 1E66CA9115D4100500F35BED /* buildnumber.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = buildnumber.xcconfig; sourceTree = ""; }; 1E71509A15B5C76F004E88FF /* HockeySDK.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HockeySDK.h; sourceTree = ""; }; - 1EB6046B15EF6B3200F69880 /* BITHockeyHelper.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BITHockeyHelper.h; sourceTree = ""; }; - 1EB6046C15EF6B3200F69880 /* BITHockeyHelper.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = BITHockeyHelper.m; sourceTree = ""; }; + 1EC69F5D1615001500808FD9 /* BITHockeyManagerPrivate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BITHockeyManagerPrivate.h; sourceTree = ""; }; 1EDA60CF15C2C1450032D10B /* HockeySDK-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "HockeySDK-Info.plist"; sourceTree = ""; }; E400561A148D79B500EB22B9 /* libHockeySDK-iphoneos.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libHockeySDK-iphoneos.a"; sourceTree = BUILT_PRODUCTS_DIR; }; E400561D148D79B500EB22B9 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; - E41EB459148D7BF50015DEDC /* BITAppVersionMetaInfo.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BITAppVersionMetaInfo.h; sourceTree = ""; }; - E41EB45A148D7BF50015DEDC /* BITAppVersionMetaInfo.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = BITAppVersionMetaInfo.m; sourceTree = ""; }; - E41EB45D148D7BF50015DEDC /* BITUpdateManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; lineEnding = 0; path = BITUpdateManager.h; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.objcpp; }; - E41EB464148D7BF50015DEDC /* BITCrashManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; lineEnding = 0; path = BITCrashManager.m; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.objc; }; E41EB465148D7BF50015DEDC /* BITHockeyManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BITHockeyManager.h; sourceTree = ""; }; E41EB466148D7BF50015DEDC /* BITHockeyManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = BITHockeyManager.m; sourceTree = ""; }; - E41EB469148D7BF50015DEDC /* PSAppStoreHeader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PSAppStoreHeader.h; sourceTree = ""; }; - E41EB46A148D7BF50015DEDC /* PSAppStoreHeader.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PSAppStoreHeader.m; sourceTree = ""; }; - E41EB46B148D7BF50015DEDC /* PSStoreButton.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PSStoreButton.h; sourceTree = ""; }; - E41EB46C148D7BF50015DEDC /* PSStoreButton.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PSStoreButton.m; sourceTree = ""; }; - E41EB46D148D7BF50015DEDC /* PSWebTableViewCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PSWebTableViewCell.h; sourceTree = ""; }; - E41EB46E148D7BF50015DEDC /* PSWebTableViewCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PSWebTableViewCell.m; sourceTree = ""; }; E41EB48B148D7C4E0015DEDC /* CrashReporter.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CrashReporter.framework; path = ../Vendor/CrashReporter.framework; sourceTree = ""; }; E4E7335A148D7A5A00763A39 /* LICENSE.txt */ = {isa = PBXFileReference; lastKnownFileType = text; name = LICENSE.txt; path = ../LICENSE.txt; sourceTree = ""; }; E4E7335B148D7A5A00763A39 /* README.md */ = {isa = PBXFileReference; lastKnownFileType = text; name = README.md; path = ../README.md; sourceTree = ""; }; @@ -276,6 +347,77 @@ /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ + 1E49A42C1612223B00463151 /* Feedback */ = { + isa = PBXGroup; + children = ( + 1E49A4361612223B00463151 /* BITFeedbackMessage.h */, + 1E49A4371612223B00463151 /* BITFeedbackMessage.m */, + 1E49A42D1612223B00463151 /* BITFeedbackComposeViewController.h */, + 1E49A42E1612223B00463151 /* BITFeedbackComposeViewController.m */, + 1E49A4381612223B00463151 /* BITFeedbackUserDataViewController.h */, + 1E49A4391612223B00463151 /* BITFeedbackUserDataViewController.m */, + 1E49A42F1612223B00463151 /* BITFeedbackListViewCell.h */, + 1E49A4301612223B00463151 /* BITFeedbackListViewCell.m */, + 1E49A4311612223B00463151 /* BITFeedbackListViewController.h */, + 1E49A4321612223B00463151 /* BITFeedbackListViewController.m */, + 1E49A4331612223B00463151 /* BITFeedbackManager.h */, + 1E49A4341612223B00463151 /* BITFeedbackManager.m */, + 1E49A4351612223B00463151 /* BITFeedbackManagerPrivate.h */, + ); + path = Feedback; + sourceTree = ""; + }; + 1E49A4611612226D00463151 /* Update */ = { + isa = PBXGroup; + children = ( + 1E49A4621612226D00463151 /* BITAppVersionMetaInfo.h */, + 1E49A4631612226D00463151 /* BITAppVersionMetaInfo.m */, + 1E49A4641612226D00463151 /* BITUpdateManager.h */, + 1E49A4651612226D00463151 /* BITUpdateManager.m */, + 1E49A4661612226D00463151 /* BITUpdateManagerDelegate.h */, + 1E49A4671612226D00463151 /* BITUpdateManagerPrivate.h */, + 1E49A4681612226D00463151 /* BITUpdateViewController.h */, + 1E49A4691612226D00463151 /* BITUpdateViewController.m */, + 1E49A46A1612226D00463151 /* BITUpdateViewControllerPrivate.h */, + ); + path = Update; + sourceTree = ""; + }; + 1E49A4861612228800463151 /* CrashReports */ = { + isa = PBXGroup; + children = ( + 1E49A4871612228800463151 /* BITCrashManager.h */, + 1E49A4881612228800463151 /* BITCrashManager.m */, + 1E49A4891612228800463151 /* BITCrashManagerDelegate.h */, + 1E49A48A1612228800463151 /* BITCrashManagerPrivate.h */, + 1E49A48B1612228800463151 /* BITCrashReportTextFormatter.h */, + 1E49A48C1612228800463151 /* BITCrashReportTextFormatter.m */, + ); + path = CrashReports; + sourceTree = ""; + }; + 1E49A49F161222B900463151 /* Helper */ = { + isa = PBXGroup; + children = ( + 1E49A4D4161222D400463151 /* HockeySDKPrivate.h */, + 1E49A4D5161222D400463151 /* HockeySDKPrivate.m */, + 1E49A4A0161222B900463151 /* BITHockeyBaseManager.h */, + 1E49A4A1161222B900463151 /* BITHockeyBaseManager.m */, + 1E49A4A2161222B900463151 /* BITHockeyBaseManagerPrivate.h */, + 1E49A4A3161222B900463151 /* BITHockeyBaseViewController.h */, + 1E49A4A4161222B900463151 /* BITHockeyBaseViewController.m */, + 1E49A4A5161222B900463151 /* BITHockeyHelper.h */, + 1E49A4A6161222B900463151 /* BITHockeyHelper.m */, + 1E49A4A7161222B900463151 /* PSAppStoreHeader.h */, + 1E49A4A8161222B900463151 /* PSAppStoreHeader.m */, + 1E49A4A9161222B900463151 /* PSStoreButton.h */, + 1E49A4AA161222B900463151 /* PSStoreButton.m */, + 1E49A4AB161222B900463151 /* PSWebTableViewCell.h */, + 1E49A4AC161222B900463151 /* PSWebTableViewCell.m */, + ); + path = Helper; + sourceTree = ""; + }; 1E5955A415B71BDC00A03429 /* Images */ = { isa = PBXGroup; children = ( @@ -348,26 +490,13 @@ E41EB458148D7BF50015DEDC /* Classes */ = { isa = PBXGroup; children = ( - E41EB48A148D7C150015DEDC /* Helper */, - 1E5955A015B70F6900A03429 /* HockeySDKPrivate.h */, - 1E59559C15B70F4D00A03429 /* HockeySDKPrivate.m */, - E41EB459148D7BF50015DEDC /* BITAppVersionMetaInfo.h */, - E41EB45A148D7BF50015DEDC /* BITAppVersionMetaInfo.m */, - E41EB45D148D7BF50015DEDC /* BITUpdateManager.h */, - 1E01118015BB62FE007002AC /* BITUpdateManagerPrivate.h */, - 1E5955D515B72ED500A03429 /* BITUpdateManager.m */, - 1E5955EE15B7752200A03429 /* BITUpdateManagerDelegate.h */, - 1E5955E215B751ED00A03429 /* BITUpdateViewController.h */, - 1E01118C15BB83F6007002AC /* BITUpdateViewControllerPrivate.h */, - 1E5955E615B751FB00A03429 /* BITUpdateViewController.m */, - 1E5955D115B72E5300A03429 /* BITCrashManager.h */, - 1E01117E15BB6228007002AC /* BITCrashManagerPrivate.h */, - E41EB464148D7BF50015DEDC /* BITCrashManager.m */, - 1E40BCB415A3487500BD64D9 /* BITCrashManagerDelegate.h */, - 1E40BCB715A3494400BD64D9 /* BITCrashReportTextFormatter.h */, - 1E40BCB815A3494400BD64D9 /* BITCrashReportTextFormatter.m */, + 1E49A49F161222B900463151 /* Helper */, + 1E49A4861612228800463151 /* CrashReports */, + 1E49A42C1612223B00463151 /* Feedback */, + 1E49A4611612226D00463151 /* Update */, E41EB465148D7BF50015DEDC /* BITHockeyManager.h */, E41EB466148D7BF50015DEDC /* BITHockeyManager.m */, + 1EC69F5D1615001500808FD9 /* BITHockeyManagerPrivate.h */, 1E5955FA15B7877A00A03429 /* BITHockeyManagerDelegate.h */, 1E71509A15B5C76F004E88FF /* HockeySDK.h */, ); @@ -383,21 +512,6 @@ name = HockeySDK; sourceTree = ""; }; - E41EB48A148D7C150015DEDC /* Helper */ = { - isa = PBXGroup; - children = ( - E41EB469148D7BF50015DEDC /* PSAppStoreHeader.h */, - E41EB46A148D7BF50015DEDC /* PSAppStoreHeader.m */, - E41EB46B148D7BF50015DEDC /* PSStoreButton.h */, - E41EB46C148D7BF50015DEDC /* PSStoreButton.m */, - E41EB46D148D7BF50015DEDC /* PSWebTableViewCell.h */, - E41EB46E148D7BF50015DEDC /* PSWebTableViewCell.m */, - 1EB6046B15EF6B3200F69880 /* BITHockeyHelper.h */, - 1EB6046C15EF6B3200F69880 /* BITHockeyHelper.m */, - ); - name = Helper; - sourceTree = ""; - }; /* End PBXGroup section */ /* Begin PBXHeadersBuildPhase section */ @@ -408,20 +522,6 @@ 1E59548315B6C4EF00A03429 /* HockeySDK.h in Headers */, 1E59548515B6C4FB00A03429 /* BITHockeyManager.h in Headers */, 1E5955FE15B787D600A03429 /* BITHockeyManagerDelegate.h in Headers */, - 1E5955F915B77F8200A03429 /* BITCrashManager.h in Headers */, - 1E59548415B6C4F300A03429 /* BITCrashManagerDelegate.h in Headers */, - 1E5954B315B6E15300A03429 /* BITUpdateManager.h in Headers */, - 1E5955F715B77F7600A03429 /* BITUpdateManagerDelegate.h in Headers */, - 1E5955F815B77F7C00A03429 /* BITUpdateViewController.h in Headers */, - 1E5955F615B77F6500A03429 /* HockeySDKPrivate.h in Headers */, - 1E01118115BB6311007002AC /* BITUpdateManagerPrivate.h in Headers */, - 1E01118215BB6314007002AC /* BITCrashManagerPrivate.h in Headers */, - 1E01118D15BB83FB007002AC /* BITUpdateViewControllerPrivate.h in Headers */, - 1E5955F315B77F5600A03429 /* PSAppStoreHeader.h in Headers */, - 1E5954B615B6E17700A03429 /* PSStoreButton.h in Headers */, - 1E5955F415B77F5E00A03429 /* PSWebTableViewCell.h in Headers */, - 1E5954B815B6E19C00A03429 /* BITAppVersionMetaInfo.h in Headers */, - 1E59548715B6C51100A03429 /* BITCrashReportTextFormatter.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -430,20 +530,34 @@ buildActionMask = 2147483647; files = ( 1E59547815B6C41300A03429 /* HockeySDK.h in Headers */, - 1E59547515B6C41300A03429 /* BITCrashManagerDelegate.h in Headers */, - 1E59546915B6C41300A03429 /* BITAppVersionMetaInfo.h in Headers */, - 1E59546B15B6C41300A03429 /* BITUpdateManager.h in Headers */, 1E59546E15B6C41300A03429 /* BITHockeyManager.h in Headers */, - 1E59547015B6C41300A03429 /* PSAppStoreHeader.h in Headers */, - 1E59547115B6C41300A03429 /* PSStoreButton.h in Headers */, - 1E59547215B6C41300A03429 /* PSWebTableViewCell.h in Headers */, - 1E59547615B6C41300A03429 /* BITCrashReportTextFormatter.h in Headers */, - 1E5955A215B70F6900A03429 /* HockeySDKPrivate.h in Headers */, - 1E5955D315B72E5400A03429 /* BITCrashManager.h in Headers */, - 1E5955E415B751EE00A03429 /* BITUpdateViewController.h in Headers */, - 1E5955F015B7752300A03429 /* BITUpdateManagerDelegate.h in Headers */, 1E5955FC15B7877B00A03429 /* BITHockeyManagerDelegate.h in Headers */, - 1EB6046E15EF6B3200F69880 /* BITHockeyHelper.h in Headers */, + 1E49A43B1612223B00463151 /* BITFeedbackComposeViewController.h in Headers */, + 1E49A4411612223B00463151 /* BITFeedbackListViewCell.h in Headers */, + 1E49A4471612223B00463151 /* BITFeedbackListViewController.h in Headers */, + 1E49A44D1612223B00463151 /* BITFeedbackManager.h in Headers */, + 1E49A4531612223B00463151 /* BITFeedbackManagerPrivate.h in Headers */, + 1E49A4561612223B00463151 /* BITFeedbackMessage.h in Headers */, + 1E49A45C1612223B00463151 /* BITFeedbackUserDataViewController.h in Headers */, + 1E49A46C1612226D00463151 /* BITAppVersionMetaInfo.h in Headers */, + 1E49A4721612226D00463151 /* BITUpdateManager.h in Headers */, + 1E49A4781612226D00463151 /* BITUpdateManagerDelegate.h in Headers */, + 1E49A47B1612226D00463151 /* BITUpdateManagerPrivate.h in Headers */, + 1E49A47E1612226D00463151 /* BITUpdateViewController.h in Headers */, + 1E49A4841612226D00463151 /* BITUpdateViewControllerPrivate.h in Headers */, + 1E49A48E1612228800463151 /* BITCrashManager.h in Headers */, + 1E49A4941612228800463151 /* BITCrashManagerDelegate.h in Headers */, + 1E49A4971612228800463151 /* BITCrashManagerPrivate.h in Headers */, + 1E49A49A1612228800463151 /* BITCrashReportTextFormatter.h in Headers */, + 1E49A4AE161222B900463151 /* BITHockeyBaseManager.h in Headers */, + 1E49A4B4161222B900463151 /* BITHockeyBaseManagerPrivate.h in Headers */, + 1E49A4B7161222B900463151 /* BITHockeyBaseViewController.h in Headers */, + 1E49A4BD161222B900463151 /* BITHockeyHelper.h in Headers */, + 1E49A4C3161222B900463151 /* PSAppStoreHeader.h in Headers */, + 1E49A4C9161222B900463151 /* PSStoreButton.h in Headers */, + 1E49A4CF161222B900463151 /* PSWebTableViewCell.h in Headers */, + 1E49A4D7161222D400463151 /* HockeySDKPrivate.h in Headers */, + 1EC69F5F1615001500808FD9 /* BITHockeyManagerPrivate.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -452,20 +566,34 @@ buildActionMask = 2147483647; files = ( 1E59559A15B6FDA500A03429 /* BITHockeyManager.h in Headers */, - 1E59559815B6FDA500A03429 /* BITCrashManagerDelegate.h in Headers */, - 1E59559415B6FDA500A03429 /* BITUpdateManager.h in Headers */, - 1E59558D15B6FDA500A03429 /* PSAppStoreHeader.h in Headers */, - 1E59558E15B6FDA500A03429 /* PSStoreButton.h in Headers */, - 1E59558F15B6FDA500A03429 /* PSWebTableViewCell.h in Headers */, 1E59559B15B6FDA500A03429 /* HockeySDK.h in Headers */, - 1E59559215B6FDA500A03429 /* BITAppVersionMetaInfo.h in Headers */, - 1E59559915B6FDA500A03429 /* BITCrashReportTextFormatter.h in Headers */, - 1E5955A315B70F6900A03429 /* HockeySDKPrivate.h in Headers */, - 1E5955D415B72E5400A03429 /* BITCrashManager.h in Headers */, - 1E5955E515B751EE00A03429 /* BITUpdateViewController.h in Headers */, - 1E5955F115B7752300A03429 /* BITUpdateManagerDelegate.h in Headers */, 1E5955FD15B7877B00A03429 /* BITHockeyManagerDelegate.h in Headers */, - 1EB6046F15EF6B3200F69880 /* BITHockeyHelper.h in Headers */, + 1E49A43C1612223B00463151 /* BITFeedbackComposeViewController.h in Headers */, + 1E49A4421612223B00463151 /* BITFeedbackListViewCell.h in Headers */, + 1E49A4481612223B00463151 /* BITFeedbackListViewController.h in Headers */, + 1E49A44E1612223B00463151 /* BITFeedbackManager.h in Headers */, + 1E49A4541612223B00463151 /* BITFeedbackManagerPrivate.h in Headers */, + 1E49A4571612223B00463151 /* BITFeedbackMessage.h in Headers */, + 1E49A45D1612223B00463151 /* BITFeedbackUserDataViewController.h in Headers */, + 1E49A46D1612226D00463151 /* BITAppVersionMetaInfo.h in Headers */, + 1E49A4731612226D00463151 /* BITUpdateManager.h in Headers */, + 1E49A4791612226D00463151 /* BITUpdateManagerDelegate.h in Headers */, + 1E49A47C1612226D00463151 /* BITUpdateManagerPrivate.h in Headers */, + 1E49A47F1612226D00463151 /* BITUpdateViewController.h in Headers */, + 1E49A4851612226D00463151 /* BITUpdateViewControllerPrivate.h in Headers */, + 1E49A48F1612228800463151 /* BITCrashManager.h in Headers */, + 1E49A4951612228800463151 /* BITCrashManagerDelegate.h in Headers */, + 1E49A4981612228800463151 /* BITCrashManagerPrivate.h in Headers */, + 1E49A49B1612228800463151 /* BITCrashReportTextFormatter.h in Headers */, + 1E49A4AF161222B900463151 /* BITHockeyBaseManager.h in Headers */, + 1E49A4B5161222B900463151 /* BITHockeyBaseManagerPrivate.h in Headers */, + 1E49A4B8161222B900463151 /* BITHockeyBaseViewController.h in Headers */, + 1E49A4BE161222B900463151 /* BITHockeyHelper.h in Headers */, + 1E49A4C4161222B900463151 /* PSAppStoreHeader.h in Headers */, + 1E49A4CA161222B900463151 /* PSStoreButton.h in Headers */, + 1E49A4D0161222B900463151 /* PSWebTableViewCell.h in Headers */, + 1E49A4D8161222D400463151 /* HockeySDKPrivate.h in Headers */, + 1EC69F601615001500808FD9 /* BITHockeyManagerPrivate.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -474,20 +602,34 @@ buildActionMask = 2147483647; files = ( 1E71509B15B5C76F004E88FF /* HockeySDK.h in Headers */, - 1E40BCB515A3487500BD64D9 /* BITCrashManagerDelegate.h in Headers */, - E41EB471148D7BF50015DEDC /* BITAppVersionMetaInfo.h in Headers */, - E41EB475148D7BF50015DEDC /* BITUpdateManager.h in Headers */, E41EB47D148D7BF50015DEDC /* BITHockeyManager.h in Headers */, - E41EB481148D7BF50015DEDC /* PSAppStoreHeader.h in Headers */, - E41EB483148D7BF50015DEDC /* PSStoreButton.h in Headers */, - E41EB485148D7BF50015DEDC /* PSWebTableViewCell.h in Headers */, - 1E40BCB915A3494400BD64D9 /* BITCrashReportTextFormatter.h in Headers */, - 1E5955A115B70F6900A03429 /* HockeySDKPrivate.h in Headers */, - 1E5955D215B72E5400A03429 /* BITCrashManager.h in Headers */, - 1E5955E315B751EE00A03429 /* BITUpdateViewController.h in Headers */, - 1E5955EF15B7752300A03429 /* BITUpdateManagerDelegate.h in Headers */, 1E5955FB15B7877B00A03429 /* BITHockeyManagerDelegate.h in Headers */, - 1EB6046D15EF6B3200F69880 /* BITHockeyHelper.h in Headers */, + 1E49A43A1612223B00463151 /* BITFeedbackComposeViewController.h in Headers */, + 1E49A4401612223B00463151 /* BITFeedbackListViewCell.h in Headers */, + 1E49A4461612223B00463151 /* BITFeedbackListViewController.h in Headers */, + 1E49A44C1612223B00463151 /* BITFeedbackManager.h in Headers */, + 1E49A4521612223B00463151 /* BITFeedbackManagerPrivate.h in Headers */, + 1E49A4551612223B00463151 /* BITFeedbackMessage.h in Headers */, + 1E49A45B1612223B00463151 /* BITFeedbackUserDataViewController.h in Headers */, + 1E49A46B1612226D00463151 /* BITAppVersionMetaInfo.h in Headers */, + 1E49A4711612226D00463151 /* BITUpdateManager.h in Headers */, + 1E49A4771612226D00463151 /* BITUpdateManagerDelegate.h in Headers */, + 1E49A47A1612226D00463151 /* BITUpdateManagerPrivate.h in Headers */, + 1E49A47D1612226D00463151 /* BITUpdateViewController.h in Headers */, + 1E49A4831612226D00463151 /* BITUpdateViewControllerPrivate.h in Headers */, + 1E49A48D1612228800463151 /* BITCrashManager.h in Headers */, + 1E49A4931612228800463151 /* BITCrashManagerDelegate.h in Headers */, + 1E49A4961612228800463151 /* BITCrashManagerPrivate.h in Headers */, + 1E49A4991612228800463151 /* BITCrashReportTextFormatter.h in Headers */, + 1E49A4AD161222B900463151 /* BITHockeyBaseManager.h in Headers */, + 1E49A4B3161222B900463151 /* BITHockeyBaseManagerPrivate.h in Headers */, + 1E49A4B6161222B900463151 /* BITHockeyBaseViewController.h in Headers */, + 1E49A4BC161222B900463151 /* BITHockeyHelper.h in Headers */, + 1E49A4C2161222B900463151 /* PSAppStoreHeader.h in Headers */, + 1E49A4C8161222B900463151 /* PSStoreButton.h in Headers */, + 1E49A4CE161222B900463151 /* PSWebTableViewCell.h in Headers */, + 1E49A4D6161222D400463151 /* HockeySDKPrivate.h in Headers */, + 1EC69F5E1615001500808FD9 /* BITHockeyManagerPrivate.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -699,17 +841,25 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - 1E59545715B6C41300A03429 /* BITAppVersionMetaInfo.m in Sources */, - 1E59545C15B6C41300A03429 /* BITCrashManager.m in Sources */, 1E59545D15B6C41300A03429 /* BITHockeyManager.m in Sources */, - 1E59545F15B6C41300A03429 /* PSAppStoreHeader.m in Sources */, - 1E59546015B6C41300A03429 /* PSStoreButton.m in Sources */, - 1E59546115B6C41300A03429 /* PSWebTableViewCell.m in Sources */, - 1E59546315B6C41300A03429 /* BITCrashReportTextFormatter.m in Sources */, - 1E59559E15B70F4D00A03429 /* HockeySDKPrivate.m in Sources */, - 1E5955D715B72ED500A03429 /* BITUpdateManager.m in Sources */, - 1E5955E815B751FB00A03429 /* BITUpdateViewController.m in Sources */, - 1EB6047115EF6B3200F69880 /* BITHockeyHelper.m in Sources */, + 1E49A43E1612223B00463151 /* BITFeedbackComposeViewController.m in Sources */, + 1E49A4441612223B00463151 /* BITFeedbackListViewCell.m in Sources */, + 1E49A44A1612223B00463151 /* BITFeedbackListViewController.m in Sources */, + 1E49A4501612223B00463151 /* BITFeedbackManager.m in Sources */, + 1E49A4591612223B00463151 /* BITFeedbackMessage.m in Sources */, + 1E49A45F1612223B00463151 /* BITFeedbackUserDataViewController.m in Sources */, + 1E49A46F1612226D00463151 /* BITAppVersionMetaInfo.m in Sources */, + 1E49A4751612226D00463151 /* BITUpdateManager.m in Sources */, + 1E49A4811612226D00463151 /* BITUpdateViewController.m in Sources */, + 1E49A4911612228800463151 /* BITCrashManager.m in Sources */, + 1E49A49D1612228800463151 /* BITCrashReportTextFormatter.m in Sources */, + 1E49A4B1161222B900463151 /* BITHockeyBaseManager.m in Sources */, + 1E49A4BA161222B900463151 /* BITHockeyBaseViewController.m in Sources */, + 1E49A4C0161222B900463151 /* BITHockeyHelper.m in Sources */, + 1E49A4C6161222B900463151 /* PSAppStoreHeader.m in Sources */, + 1E49A4CC161222B900463151 /* PSStoreButton.m in Sources */, + 1E49A4D2161222B900463151 /* PSWebTableViewCell.m in Sources */, + 1E49A4DA161222D400463151 /* HockeySDKPrivate.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -717,17 +867,25 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - 1E5954CD15B6F24A00A03429 /* BITAppVersionMetaInfo.m in Sources */, - 1E5954D215B6F24A00A03429 /* BITCrashManager.m in Sources */, 1E5954D315B6F24A00A03429 /* BITHockeyManager.m in Sources */, - 1E5954D515B6F24A00A03429 /* PSAppStoreHeader.m in Sources */, - 1E5954D615B6F24A00A03429 /* PSStoreButton.m in Sources */, - 1E5954D715B6F24A00A03429 /* PSWebTableViewCell.m in Sources */, - 1E5954D915B6F24A00A03429 /* BITCrashReportTextFormatter.m in Sources */, - 1E59559F15B70F4D00A03429 /* HockeySDKPrivate.m in Sources */, - 1E5955D815B72ED500A03429 /* BITUpdateManager.m in Sources */, - 1E5955E915B751FB00A03429 /* BITUpdateViewController.m in Sources */, - 1EB6047215EF6B3200F69880 /* BITHockeyHelper.m in Sources */, + 1E49A43F1612223B00463151 /* BITFeedbackComposeViewController.m in Sources */, + 1E49A4451612223B00463151 /* BITFeedbackListViewCell.m in Sources */, + 1E49A44B1612223B00463151 /* BITFeedbackListViewController.m in Sources */, + 1E49A4511612223B00463151 /* BITFeedbackManager.m in Sources */, + 1E49A45A1612223B00463151 /* BITFeedbackMessage.m in Sources */, + 1E49A4601612223B00463151 /* BITFeedbackUserDataViewController.m in Sources */, + 1E49A4701612226D00463151 /* BITAppVersionMetaInfo.m in Sources */, + 1E49A4761612226D00463151 /* BITUpdateManager.m in Sources */, + 1E49A4821612226D00463151 /* BITUpdateViewController.m in Sources */, + 1E49A4921612228800463151 /* BITCrashManager.m in Sources */, + 1E49A49E1612228800463151 /* BITCrashReportTextFormatter.m in Sources */, + 1E49A4B2161222B900463151 /* BITHockeyBaseManager.m in Sources */, + 1E49A4BB161222B900463151 /* BITHockeyBaseViewController.m in Sources */, + 1E49A4C1161222B900463151 /* BITHockeyHelper.m in Sources */, + 1E49A4C7161222B900463151 /* PSAppStoreHeader.m in Sources */, + 1E49A4CD161222B900463151 /* PSStoreButton.m in Sources */, + 1E49A4D3161222B900463151 /* PSWebTableViewCell.m in Sources */, + 1E49A4DB161222D400463151 /* HockeySDKPrivate.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -742,17 +900,25 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - E41EB472148D7BF50015DEDC /* BITAppVersionMetaInfo.m in Sources */, - E41EB47C148D7BF50015DEDC /* BITCrashManager.m in Sources */, E41EB47E148D7BF50015DEDC /* BITHockeyManager.m in Sources */, - E41EB482148D7BF50015DEDC /* PSAppStoreHeader.m in Sources */, - E41EB484148D7BF50015DEDC /* PSStoreButton.m in Sources */, - E41EB486148D7BF50015DEDC /* PSWebTableViewCell.m in Sources */, - 1E40BCBA15A3494400BD64D9 /* BITCrashReportTextFormatter.m in Sources */, - 1E59559D15B70F4D00A03429 /* HockeySDKPrivate.m in Sources */, - 1E5955D615B72ED500A03429 /* BITUpdateManager.m in Sources */, - 1E5955E715B751FB00A03429 /* BITUpdateViewController.m in Sources */, - 1EB6047015EF6B3200F69880 /* BITHockeyHelper.m in Sources */, + 1E49A43D1612223B00463151 /* BITFeedbackComposeViewController.m in Sources */, + 1E49A4431612223B00463151 /* BITFeedbackListViewCell.m in Sources */, + 1E49A4491612223B00463151 /* BITFeedbackListViewController.m in Sources */, + 1E49A44F1612223B00463151 /* BITFeedbackManager.m in Sources */, + 1E49A4581612223B00463151 /* BITFeedbackMessage.m in Sources */, + 1E49A45E1612223B00463151 /* BITFeedbackUserDataViewController.m in Sources */, + 1E49A46E1612226D00463151 /* BITAppVersionMetaInfo.m in Sources */, + 1E49A4741612226D00463151 /* BITUpdateManager.m in Sources */, + 1E49A4801612226D00463151 /* BITUpdateViewController.m in Sources */, + 1E49A4901612228800463151 /* BITCrashManager.m in Sources */, + 1E49A49C1612228800463151 /* BITCrashReportTextFormatter.m in Sources */, + 1E49A4B0161222B900463151 /* BITHockeyBaseManager.m in Sources */, + 1E49A4B9161222B900463151 /* BITHockeyBaseViewController.m in Sources */, + 1E49A4BF161222B900463151 /* BITHockeyHelper.m in Sources */, + 1E49A4C5161222B900463151 /* PSAppStoreHeader.m in Sources */, + 1E49A4CB161222B900463151 /* PSStoreButton.m in Sources */, + 1E49A4D1161222B900463151 /* PSWebTableViewCell.m in Sources */, + 1E49A4D9161222D400463151 /* HockeySDKPrivate.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; From 61483d4437d63fa6f4fd0d97227a922ce803c0a4 Mon Sep 17 00:00:00 2001 From: Andreas Linde Date: Fri, 5 Oct 2012 13:35:14 +0200 Subject: [PATCH 002/176] Fix header --- Classes/BITHockeyManager.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Classes/BITHockeyManager.h b/Classes/BITHockeyManager.h index 0f26058e..bf425b84 100644 --- a/Classes/BITHockeyManager.h +++ b/Classes/BITHockeyManager.h @@ -27,11 +27,13 @@ * OTHER DEALINGS IN THE SOFTWARE. */ -#import "BITUpdateManager.h" +#import +#import @protocol BITHockeyManagerDelegate; +@class BITHockeyBaseManager; @class BITCrashManager; @class BITUpdateManager; @class BITFeedbackManager; From 218e25537809e4194f202717247e5d80d0334659 Mon Sep 17 00:00:00 2001 From: Andreas Linde Date: Fri, 5 Oct 2012 13:36:39 +0200 Subject: [PATCH 003/176] Save to archive, property list doesn't work anyway for custom objects --- Classes/Feedback/BITFeedbackManager.m | 122 +++++++++++++------------- Classes/Feedback/BITFeedbackMessage.m | 4 +- 2 files changed, 62 insertions(+), 64 deletions(-) diff --git a/Classes/Feedback/BITFeedbackManager.m b/Classes/Feedback/BITFeedbackManager.m index 83d6d2c2..57e1f329 100644 --- a/Classes/Feedback/BITFeedbackManager.m +++ b/Classes/Feedback/BITFeedbackManager.m @@ -70,7 +70,8 @@ - (id)init { _incomingMessagesAlertShowing = NO; _lastCheck = nil; _token = nil; - _feedbackList = nil; + + self.feedbackList = [NSMutableArray array]; _fileManager = [[NSFileManager alloc] init]; @@ -164,7 +165,7 @@ - (void)updateMessagesList { #pragma mark - Local Storage - (void)loadMessages { - NSString *errorString = nil; + NSError *error = nil; NSPropertyListFormat format; BOOL userNameViaDelegate = NO; @@ -191,55 +192,56 @@ - (void)loadMessages { if (![_fileManager fileExistsAtPath:_settingsFile]) return; - - NSData *plist = [NSData dataWithContentsOfFile:_settingsFile]; - if (plist) { - NSDictionary *rootObj = (NSDictionary *)[NSPropertyListSerialization - propertyListFromData:plist - mutabilityOption:NSPropertyListMutableContainersAndLeaves - format:&format - errorDescription:&errorString]; - - if (!userNameViaDelegate) { - if ([rootObj objectForKey:kBITFeedbackName]) - self.userName = [rootObj objectForKey:kBITFeedbackName]; - } - if (!userEmailViaDelegate) { - if ([rootObj objectForKey:kBITFeedbackEmail]) - self.userEmail = [rootObj objectForKey:kBITFeedbackEmail]; - } - - if ([rootObj objectForKey:kBITFeedbackUserDataAsked]) - self.didAskUserData = YES; + NSData *codedData = [[[NSData alloc] initWithContentsOfFile:_settingsFile] autorelease]; + if (codedData == nil) return; + + NSKeyedUnarchiver *unarchiver = nil; + + @try { + unarchiver = [[NSKeyedUnarchiver alloc] initForReadingWithData:codedData]; + } + @catch (NSException *exception) { + return; + } - if ([rootObj objectForKey:kBITFeedbackToken]) - self.token = [rootObj objectForKey:kBITFeedbackToken]; + if (!userNameViaDelegate) { + if ([unarchiver containsValueForKey:kBITFeedbackName]) + self.userName = [unarchiver decodeObjectForKey:kBITFeedbackName]; + } - if ([rootObj objectForKey:kBITFeedbackName]) - self.userName = [rootObj objectForKey:kBITFeedbackName]; - - if ([rootObj objectForKey:kBITFeedbackEmail]) - self.userEmail = [rootObj objectForKey:kBITFeedbackEmail]; + if (!userEmailViaDelegate) { + if ([unarchiver containsValueForKey:kBITFeedbackEmail]) + self.userEmail = [unarchiver decodeObjectForKey:kBITFeedbackEmail]; + } + + if ([unarchiver containsValueForKey:kBITFeedbackUserDataAsked]) + self.didAskUserData = YES; + + if ([unarchiver containsValueForKey:kBITFeedbackToken]) + self.token = [unarchiver decodeObjectForKey:kBITFeedbackToken]; + + if ([unarchiver containsValueForKey:kBITFeedbackName]) + self.userName = [unarchiver decodeObjectForKey:kBITFeedbackName]; + + if ([unarchiver containsValueForKey:kBITFeedbackEmail]) + self.userEmail = [unarchiver decodeObjectForKey:kBITFeedbackEmail]; + + if ([unarchiver containsValueForKey:kBITFeedbackDateOfLastCheck]) + self.lastCheck = [unarchiver decodeObjectForKey:kBITFeedbackDateOfLastCheck]; + + if ([unarchiver containsValueForKey:kBITFeedbackMessages]) { + [self.feedbackList setArray:[unarchiver decodeObjectForKey:kBITFeedbackMessages]]; - if ([rootObj objectForKey:kBITFeedbackDateOfLastCheck]) - self.lastCheck = [rootObj objectForKey:kBITFeedbackDateOfLastCheck]; + [self sortFeedbackList]; - if ([rootObj objectForKey:kBITFeedbackMessages]) { - self.feedbackList = [NSMutableArray arrayWithArray:[rootObj objectForKey:kBITFeedbackMessages]]; - - [self sortFeedbackList]; - - // inform the UI to update its data in case the list is already showing - [[NSNotificationCenter defaultCenter] postNotificationName:BITHockeyFeedbackMessagesUpdated object:nil]; - } else { - self.feedbackList = [NSMutableArray array]; - } - } else { - self.feedbackList = [NSMutableArray array]; - BITHockeyLog(@"ERROR: Reading settings. %@", errorString); + // inform the UI to update its data in case the list is already showing + [[NSNotificationCenter defaultCenter] postNotificationName:BITHockeyFeedbackMessagesUpdated object:nil]; } + [unarchiver finishDecoding]; + [unarchiver release]; + if (!self.lastCheck) { self.lastCheck = [NSDate distantPast]; } @@ -249,34 +251,30 @@ - (void)loadMessages { - (void)saveMessages { [self sortFeedbackList]; - NSString *errorString = nil; - - NSMutableDictionary *rootObj = [NSMutableDictionary dictionaryWithCapacity:2]; - + NSMutableData *data = [[NSMutableData alloc] init]; + NSKeyedArchiver *archiver = [[NSKeyedArchiver alloc] initForWritingWithMutableData:data]; + if (self.didAskUserData) - [rootObj setObject:[NSNumber numberWithBool:YES] forKey:kBITFeedbackUserDataAsked]; + [archiver encodeObject:[NSNumber numberWithBool:YES] forKey:kBITFeedbackUserDataAsked]; if (self.token) - [rootObj setObject:self.token forKey:kBITFeedbackToken]; + [archiver encodeObject:self.token forKey:kBITFeedbackToken]; if (self.userName) - [rootObj setObject:self.userName forKey:kBITFeedbackName]; + [archiver encodeObject:self.userName forKey:kBITFeedbackName]; if (self.userEmail) - [rootObj setObject:self.userEmail forKey:kBITFeedbackEmail]; + [archiver encodeObject:self.userEmail forKey:kBITFeedbackEmail]; - [rootObj setObject:self.lastCheck forKey:kBITFeedbackDateOfLastCheck]; + if (self.lastCheck) + [archiver encodeObject:self.lastCheck forKey:kBITFeedbackDateOfLastCheck]; - [rootObj setObject:self.feedbackList forKey:kBITFeedbackMessages]; + [archiver encodeObject:self.feedbackList forKey:kBITFeedbackMessages]; - NSData *plist = [NSPropertyListSerialization dataFromPropertyList:(id)rootObj - format:NSPropertyListBinaryFormat_v1_0 - errorDescription:&errorString]; - if (plist) { - [plist writeToFile:_settingsFile atomically:YES]; - } else { - BITHockeyLog(@"ERROR: Writing settings. %@", errorString); - } + [archiver finishEncoding]; + [data writeToFile:_settingsFile atomically:YES]; + [archiver release]; + [data release]; } diff --git a/Classes/Feedback/BITFeedbackMessage.m b/Classes/Feedback/BITFeedbackMessage.m index 85410c2c..e19044b7 100644 --- a/Classes/Feedback/BITFeedbackMessage.m +++ b/Classes/Feedback/BITFeedbackMessage.m @@ -67,7 +67,7 @@ - (void)encodeWithCoder:(NSCoder *)encoder { [encoder encodeObject:self.date forKey:@"date"]; [encoder encodeObject:self.id forKey:@"id"]; [encoder encodeInteger:self.status forKey:@"status"]; - [encoder encodeInteger:self.userMessage forKey:@"userMessage"]; + [encoder encodeBool:self.userMessage forKey:@"userMessage"]; } - (id)initWithCoder:(NSCoder *)decoder { @@ -78,7 +78,7 @@ - (id)initWithCoder:(NSCoder *)decoder { self.date = [decoder decodeObjectForKey:@"date"]; self.id = [decoder decodeObjectForKey:@"id"]; self.status = [decoder decodeIntegerForKey:@"status"]; - self.userMessage = [decoder decodeIntegerForKey:@"userMessage"]; + self.userMessage = [decoder decodeBoolForKey:@"userMessage"]; } return self; } From 3f12ce70ee0f6f95e2eaea7f80680474c965e651 Mon Sep 17 00:00:00 2001 From: Andreas Linde Date: Fri, 5 Oct 2012 15:25:04 +0200 Subject: [PATCH 004/176] Remove not needed vars --- Classes/Feedback/BITFeedbackManager.m | 3 --- 1 file changed, 3 deletions(-) diff --git a/Classes/Feedback/BITFeedbackManager.m b/Classes/Feedback/BITFeedbackManager.m index 57e1f329..817a1145 100644 --- a/Classes/Feedback/BITFeedbackManager.m +++ b/Classes/Feedback/BITFeedbackManager.m @@ -165,9 +165,6 @@ - (void)updateMessagesList { #pragma mark - Local Storage - (void)loadMessages { - NSError *error = nil; - NSPropertyListFormat format; - BOOL userNameViaDelegate = NO; BOOL userEmailViaDelegate = NO; From 4839afca9708e3cdfac43fa20a1d29ffaf841ebf Mon Sep 17 00:00:00 2001 From: Andreas Linde Date: Fri, 5 Oct 2012 15:26:00 +0200 Subject: [PATCH 005/176] Remove messages that got removed from the server When changing to API to only load new messages, we need to provide this info otherwise in the response --- Classes/Feedback/BITFeedbackManager.m | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/Classes/Feedback/BITFeedbackManager.m b/Classes/Feedback/BITFeedbackManager.m index 817a1145..5b0e6dc3 100644 --- a/Classes/Feedback/BITFeedbackManager.m +++ b/Classes/Feedback/BITFeedbackManager.m @@ -403,9 +403,12 @@ - (BOOL)updateMessageListFromResponse:(NSDictionary *)jsonDictionary { __block BITFeedbackMessage *sendInProgressMessage = [self sendInProgressMessage]; __block BOOL messagesUpdated = NO; __block BOOL newResponseMessage = NO; + __block NSMutableSet *returnedMessageIDs = [[[NSMutableSet alloc] init] autorelease]; [feedMessages enumerateObjectsUsingBlock:^(id objMessage, NSUInteger messagesIdx, BOOL *stop) { NSNumber *messageID = [(NSDictionary *)objMessage objectForKey:@"id"]; + [returnedMessageIDs addObject:messageID]; + if (![self messageWithID:messageID]) { // check if this is the message that was sent right now if (sendInProgressMessage && [[sendInProgressMessage text] isEqualToString:[(NSDictionary *)objMessage objectForKey:@"text"]]) { @@ -430,18 +433,27 @@ - (BOOL)updateMessageListFromResponse:(NSDictionary *)jsonDictionary { } }]; + // remove all messages that are removed on the server + NSMutableSet *removedMessageIDs = [[[NSMutableSet alloc] init] autorelease]; + [self.feedbackList enumerateObjectsUsingBlock:^(id objMessage, NSUInteger messagesIdx, BOOL *stop) { + if (![returnedMessageIDs member:[(BITFeedbackMessage *)objMessage id]]) { + [removedMessageIDs addObject:[(BITFeedbackMessage *)objMessage id]]; + } + }]; + + if ([removedMessageIDs count] > 0) { + [removedMessageIDs enumerateObjectsUsingBlock:^(id objID, BOOL *stop) { + [self.feedbackList removeObject:[self messageWithID:objID]]; + }]; + } + // new data arrived, so save it if (messagesUpdated) { [self saveMessages]; - - // inform the UI to update its data in case the list is already showing - [[NSNotificationCenter defaultCenter] postNotificationName:BITHockeyFeedbackMessagesUpdated object:nil]; } // we got a new incoming message, trigger user notification system if (newResponseMessage) { - [[NSNotificationCenter defaultCenter] postNotificationName:BITHockeyFeedbackNewMessagesReceived object:nil]; - if (self.showAlertOnIncomingMessages && !self.currentFeedbackListViewController && !self.currentFeedbackComposeViewController) { UIAlertView *alertView = [[[UIAlertView alloc] initWithTitle:BITHockeyLocalizedString(@"HockeyFeedbackNewMessageTitle") message:BITHockeyLocalizedString(@"HockeyFeedbackNewMessageText") From c8809ec038c9f851a6ba59ff854027e9344a04f3 Mon Sep 17 00:00:00 2001 From: Andreas Linde Date: Fri, 5 Oct 2012 15:26:50 +0200 Subject: [PATCH 006/176] Inform the UI wether we got new messages or nothing new --- Classes/Feedback/BITFeedbackManager.m | 9 +++++---- Classes/HockeySDK.h | 5 +---- 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/Classes/Feedback/BITFeedbackManager.m b/Classes/Feedback/BITFeedbackManager.m index 5b0e6dc3..d6023ac6 100644 --- a/Classes/Feedback/BITFeedbackManager.m +++ b/Classes/Feedback/BITFeedbackManager.m @@ -572,6 +572,8 @@ - (void)fetchMessageUpdates { [self sendNetworkRequestWithHTTPMethod:@"GET" withText:nil completionHandler:^(NSError *err){ + // inform the UI to update its data in case the list is already showing + [[NSNotificationCenter defaultCenter] postNotificationName:BITHockeyFeedbackMessagesUpdated object:nil]; }]; } @@ -597,11 +599,10 @@ - (void)submitPendingMessages { [message setStatus:BITFeedbackMessageStatusSendPending]; [self saveMessages]; - - // inform the UI to update its data in case the list is already showing - [[NSNotificationCenter defaultCenter] postNotificationName:BITHockeyFeedbackMessagesUpdated object:nil]; - } + + // inform the UI to update its data in case the list is already showing + [[NSNotificationCenter defaultCenter] postNotificationName:BITHockeyFeedbackMessagesUpdated object:nil]; }]; } } diff --git a/Classes/HockeySDK.h b/Classes/HockeySDK.h index 49cd8968..2503fcdf 100644 --- a/Classes/HockeySDK.h +++ b/Classes/HockeySDK.h @@ -50,12 +50,9 @@ // Notification message which HockeyManager is listening to, to retry requesting updated from the server #define BITHockeyNetworkDidBecomeReachableNotification @"BITHockeyNetworkDidBecomeReachable" -// Notification message which tells that messages got updated or added +// Notification message which tells that loading messages finished #define BITHockeyFeedbackMessagesUpdated @"BITHockeyFeedbackMessagesUpdated" -// Notification message which tells that new messages arrived -#define BITHockeyFeedbackNewMessagesReceived @"BITHockeyFeedbackNewMessagesReceived" - // hockey api error domain typedef enum { From 512db251aaa9d5e8f40ac9e0a5eabcaf3a747d2e Mon Sep 17 00:00:00 2001 From: Andreas Linde Date: Fri, 5 Oct 2012 21:48:01 +0200 Subject: [PATCH 007/176] More feedback improvements - Mark messages as archived that got deleted on the server - Send message even if the thread got deleted on the server, so create a new thread - Support Pull-To-Refresh in iOS6 - Update feedback and send pending message when the app gets into the foreground again - Always update user data via delegates before sending a new message, since those could have changed in the app --- Classes/BITHockeyManager.m | 8 + .../Feedback/BITFeedbackListViewController.m | 35 +-- Classes/Feedback/BITFeedbackManager.m | 214 +++++++++++++----- Classes/Feedback/BITFeedbackManagerPrivate.h | 10 +- Classes/Feedback/BITFeedbackMessage.h | 4 +- Classes/Helper/BITHockeyBaseViewController.h | 2 +- Classes/Helper/BITHockeyBaseViewController.m | 8 +- 7 files changed, 201 insertions(+), 80 deletions(-) diff --git a/Classes/BITHockeyManager.m b/Classes/BITHockeyManager.m index fd031bad..a5579e0c 100644 --- a/Classes/BITHockeyManager.m +++ b/Classes/BITHockeyManager.m @@ -217,6 +217,14 @@ - (void)setDisableUpdateManager:(BOOL)disableUpdateManager { } +- (void)setDisableFeedbackManager:(BOOL)disableFeedbackManager { + if (_feedbackManager) { + [_feedbackManager setDisableFeedbackManager:disableFeedbackManager]; + } + _disableFeedbackManager = disableFeedbackManager; +} + + - (void)setServerURL:(NSString *)aServerURL { // ensure url ends with a trailing slash if (![aServerURL hasSuffix:@"/"]) { diff --git a/Classes/Feedback/BITFeedbackListViewController.m b/Classes/Feedback/BITFeedbackListViewController.m index e652d844..04fd7a64 100644 --- a/Classes/Feedback/BITFeedbackListViewController.m +++ b/Classes/Feedback/BITFeedbackListViewController.m @@ -42,7 +42,6 @@ @interface BITFeedbackListViewController () @property (nonatomic, assign) BITFeedbackManager *manager; -@property (nonatomic, retain) UITableView *tableView; @property (nonatomic, retain) NSDateFormatter *lastUpdateDateFormatter; @end @@ -63,7 +62,8 @@ - (id)init { - (void)dealloc { - [_tableView release], _tableView = nil; + [[NSNotificationCenter defaultCenter] removeObserver:self name:BITHockeyFeedbackMessagesUpdated object:nil]; + [_lastUpdateDateFormatter release]; _lastUpdateDateFormatter = nil; [super dealloc]; @@ -82,28 +82,29 @@ - (void)viewDidLoad { self.title = BITHockeyLocalizedString(@"HockeyFeedbackListTitle"); - self.tableView = [[[UITableView alloc] initWithFrame:self.view.bounds] autorelease]; self.tableView.delegate = self; self.tableView.dataSource = self; self.tableView.separatorStyle = UITableViewCellSeparatorStyleNone; [self.tableView setAutoresizingMask:UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth]; [self.tableView setBackgroundColor:[UIColor colorWithRed:0.82 green:0.84 blue:0.84 alpha:1]]; [self.tableView setSeparatorColor:[UIColor colorWithRed:0.79 green:0.79 blue:0.79 alpha:1]]; - [self.view addSubview:self.tableView]; - - self.navigationItem.rightBarButtonItem = [[[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemRefresh - target:self - action:@selector(reloadList)] autorelease]; -} - -- (void)viewDidUnload { - [[NSNotificationCenter defaultCenter] removeObserver:self name:BITHockeyFeedbackMessagesUpdated object:nil]; - - [super viewDidUnload]; + id refreshClass = NSClassFromString(@"UIRefreshControl"); + if (refreshClass) { + self.refreshControl = [[[UIRefreshControl alloc] init] autorelease]; + [self.refreshControl addTarget:self action:@selector(reloadList) forControlEvents:UIControlEventValueChanged]; + } else { + self.navigationItem.rightBarButtonItem = [[[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemRefresh + target:self + action:@selector(reloadList)] autorelease]; + } } - (void)reloadList { + id refreshClass = NSClassFromString(@"UIRefreshControl"); + if (refreshClass) { + [self.refreshControl beginRefreshing]; + } [self.manager updateMessagesList]; } @@ -111,6 +112,11 @@ - (void)updateList { CGSize contentSize = self.tableView.contentSize; CGPoint contentOffset = self.tableView.contentOffset; + id refreshClass = NSClassFromString(@"UIRefreshControl"); + if (refreshClass) { + [self.refreshControl endRefreshing]; + } + [self.tableView reloadData]; if (self.tableView.contentSize.height > contentSize.height) [self.tableView setContentOffset:CGPointMake(contentOffset.x, self.tableView.contentSize.height - contentSize.height + contentOffset.y) animated:NO]; @@ -304,7 +310,6 @@ - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPa BITFeedbackMessage *message = [self.manager messageAtIndex:indexPath.row]; if (!message) return 44; - // BITFeedbackListViewCell *cell = (BITFeedbackListViewCell *)[tableView cellForRowAtIndexPath:indexPath]; return [BITFeedbackListViewCell heightForRowWithText:message.text tableViewWidth:self.view.frame.size.width]; } diff --git a/Classes/Feedback/BITFeedbackManager.m b/Classes/Feedback/BITFeedbackManager.m index d6023ac6..dd1a9f40 100644 --- a/Classes/Feedback/BITFeedbackManager.m +++ b/Classes/Feedback/BITFeedbackManager.m @@ -36,7 +36,6 @@ #import "BITHockeyManagerPrivate.h" -#import "BITFeedbackMessage.h" #import "BITHockeyHelper.h" @@ -52,6 +51,8 @@ @implementation BITFeedbackManager { NSFileManager *_fileManager; NSString *_feedbackDir; NSString *_settingsFile; + + BOOL _didSetupDidBecomeActiveNotifications; } #pragma mark - Initialization @@ -66,6 +67,8 @@ - (id)init { _requireUserEmail = BITFeedbackUserDataElementRequired; _showAlertOnIncomingMessages = YES; + _disableFeedbackManager = NO; + _didSetupDidBecomeActiveNotifications = NO; _networkRequestInProgress = NO; _incomingMessagesAlertShowing = NO; _lastCheck = nil; @@ -96,6 +99,10 @@ - (id)init { } - (void)dealloc { + [[NSNotificationCenter defaultCenter] removeObserver:self name:BITHockeyNetworkDidBecomeReachableNotification object:nil]; + + [[NSNotificationCenter defaultCenter] removeObserver:self name:UIApplicationDidBecomeActiveNotification object:nil]; + [_currentFeedbackListViewController release], _currentFeedbackListViewController = nil; [_currentFeedbackComposeViewController release], _currentFeedbackComposeViewController = nil; @@ -114,6 +121,27 @@ - (void)dealloc { } +- (void)didBecomeActiveActions { + if (![self isFeedbackManagerDisabled]) { + [self updateAppDefinedUserData]; + [self updateMessagesList]; + } +} + +- (void)setupDidBecomeActiveNotifications { + if (!_didSetupDidBecomeActiveNotifications) { + NSNotificationCenter *dnc = [NSNotificationCenter defaultCenter]; + [dnc addObserver:self selector:@selector(didBecomeActiveActions) name:UIApplicationDidBecomeActiveNotification object:nil]; + [dnc addObserver:self selector:@selector(didBecomeActiveActions) name:BITHockeyNetworkDidBecomeReachableNotification object:nil]; + _didSetupDidBecomeActiveNotifications = YES; + } +} + +- (void)cleanupDidBecomeActiveNotifications { + [[NSNotificationCenter defaultCenter] removeObserver:self name:BITHockeyNetworkDidBecomeReachableNotification object:nil]; + [[NSNotificationCenter defaultCenter] removeObserver:self name:UIApplicationDidBecomeActiveNotification object:nil]; +} + #pragma mark - Feedback Modal UI - (BITFeedbackListViewController *)feedbackListViewController:(BOOL)modal { @@ -148,20 +176,44 @@ - (void)showFeedbackComposeView { - (void)startManager { if ([self.feedbackList count] == 0) { [self loadMessages]; + } else { + [self updateAppDefinedUserData]; } [self updateMessagesList]; + + [self setupDidBecomeActiveNotifications]; } - (void)updateMessagesList { if (_networkRequestInProgress) return; - if ([self nextPendingMessage]) { + NSArray *pendingMessages = [self messagesWithStatus:BITFeedbackMessageStatusSendPending]; + if ([pendingMessages count] > 0) { [self submitPendingMessages]; } else { [self fetchMessageUpdates]; } } +- (void)updateAppDefinedUserData { + if ([BITHockeyManager sharedHockeyManager].delegate && + [[BITHockeyManager sharedHockeyManager].delegate respondsToSelector:@selector(userNameForHockeyManager:componentManager:)]) { + self.userName = [[BITHockeyManager sharedHockeyManager].delegate + userNameForHockeyManager:[BITHockeyManager sharedHockeyManager] + componentManager:self]; + self.requireUserName = BITFeedbackUserDataElementDontShow; + self.requireUserEmail = BITFeedbackUserDataElementDontShow; + } + if ([BITHockeyManager sharedHockeyManager].delegate && + [[BITHockeyManager sharedHockeyManager].delegate respondsToSelector:@selector(userEmailForHockeyManager:componentManager:)]) { + self.userEmail = [[BITHockeyManager sharedHockeyManager].delegate + userEmailForHockeyManager:[BITHockeyManager sharedHockeyManager] + componentManager:self]; + self.requireUserName = BITFeedbackUserDataElementDontShow; + self.requireUserEmail = BITFeedbackUserDataElementDontShow; + } +} + #pragma mark - Local Storage - (void)loadMessages { @@ -328,30 +380,24 @@ - (BITFeedbackMessage *)messageWithID:(NSNumber *)messageID { return message; } -- (BITFeedbackMessage *)sendInProgressMessage { - __block BITFeedbackMessage *message = nil; +- (NSArray *)messagesWithStatus:(BITFeedbackMessageStatus)status { + NSMutableArray *resultMessages = [[NSMutableArray alloc] initWithCapacity:[self.feedbackList count]]; [self.feedbackList enumerateObjectsUsingBlock:^(BITFeedbackMessage *objMessage, NSUInteger messagesIdx, BOOL *stop) { - if ([objMessage status] == BITFeedbackMessageStatusSendInProgress) { - message = objMessage; - *stop = YES; + if ([objMessage status] == status) { + [resultMessages addObject: objMessage]; } }]; - return message; + return [NSArray arrayWithArray:resultMessages];; } -- (BITFeedbackMessage *)nextPendingMessage { - __block BITFeedbackMessage *message = nil; - - [self.feedbackList enumerateObjectsUsingBlock:^(BITFeedbackMessage *objMessage, NSUInteger messagesIdx, BOOL *stop) { - if ([objMessage status] == BITFeedbackMessageStatusSendPending) { - message = objMessage; - *stop = YES; - } +- (void)markSendInProgressMessagesAsPending { + // make sure message that may have not been send successfully, get back into the right state to be send again + [self.feedbackList enumerateObjectsUsingBlock:^(id objMessage, NSUInteger messagesIdx, BOOL *stop) { + if ([(BITFeedbackMessage *)objMessage status] == BITFeedbackMessageStatusSendInProgress) + [(BITFeedbackMessage *)objMessage setStatus:BITFeedbackMessageStatusSendPending]; }]; - - return message; } @@ -386,7 +432,36 @@ - (BOOL)isManualUserDataAvailable { #pragma mark - Networking -- (BOOL)updateMessageListFromResponse:(NSDictionary *)jsonDictionary { +- (void)updateMessageListFromResponse:(NSDictionary *)jsonDictionary { + if (!jsonDictionary) { + // nil is used when the server returns 404, so we need to mark all existing threads as archives and delete the discussion token + + NSArray *messagesSendInProgress = [self messagesWithStatus:BITFeedbackMessageStatusSendInProgress]; + NSInteger pendingMessagesCount = [messagesSendInProgress count] + [[self messagesWithStatus:BITFeedbackMessageStatusSendPending] count]; + + [self markSendInProgressMessagesAsPending]; + + [self.feedbackList enumerateObjectsUsingBlock:^(id objMessage, NSUInteger messagesIdx, BOOL *stop) { + if ([(BITFeedbackMessage *)objMessage status] != BITFeedbackMessageStatusSendPending) + [(BITFeedbackMessage *)objMessage setStatus:BITFeedbackMessageStatusArchived]; + }]; + + if ([self token]) { + self.token = nil; + } + + NSInteger pendingMessagesCountAfterProcessing = [[self messagesWithStatus:BITFeedbackMessageStatusSendPending] count]; + + [self saveMessages]; + + // check if this request was successful and we have more messages pending and continue if positive + if (pendingMessagesCount > pendingMessagesCountAfterProcessing && pendingMessagesCountAfterProcessing > 0) { + [self performSelector:@selector(submitPendingMessages) withObject:nil afterDelay:0.1]; + } + + return; + } + NSDictionary *feedback = [jsonDictionary objectForKey:@"feedback"]; NSString *token = [jsonDictionary objectForKey:@"token"]; NSDictionary *feedbackObject = [jsonDictionary objectForKey:@"feedback"]; @@ -400,8 +475,10 @@ - (BOOL)updateMessageListFromResponse:(NSDictionary *)jsonDictionary { NSArray *feedMessages = [feedbackObject objectForKey:@"messages"]; // get the message that was currently sent if available - __block BITFeedbackMessage *sendInProgressMessage = [self sendInProgressMessage]; - __block BOOL messagesUpdated = NO; + NSArray *messagesSendInProgress = [self messagesWithStatus:BITFeedbackMessageStatusSendInProgress]; + + NSInteger pendingMessagesCount = [messagesSendInProgress count] + [[self messagesWithStatus:BITFeedbackMessageStatusSendPending] count]; + __block BOOL newResponseMessage = NO; __block NSMutableSet *returnedMessageIDs = [[[NSMutableSet alloc] init] autorelease]; @@ -409,12 +486,22 @@ - (BOOL)updateMessageListFromResponse:(NSDictionary *)jsonDictionary { NSNumber *messageID = [(NSDictionary *)objMessage objectForKey:@"id"]; [returnedMessageIDs addObject:messageID]; - if (![self messageWithID:messageID]) { - // check if this is the message that was sent right now - if (sendInProgressMessage && [[sendInProgressMessage text] isEqualToString:[(NSDictionary *)objMessage objectForKey:@"text"]]) { - sendInProgressMessage.date = [self parseRFC3339Date:[(NSDictionary *)objMessage objectForKey:@"created_at"]]; - sendInProgressMessage.id = messageID; - sendInProgressMessage.status = BITFeedbackMessageStatusRead; + BITFeedbackMessage *thisMessage = [self messageWithID:messageID]; + if (!thisMessage) { + // check if this is a message that was sent right now + __block BITFeedbackMessage *matchingSendInProgressMessage = nil; + + [messagesSendInProgress enumerateObjectsUsingBlock:^(id objSendInProgressMessage, NSUInteger messagesSendInProgressIdx, BOOL *stop) { + if ([[(NSDictionary *)objMessage objectForKey:@"text"] isEqualToString:[(BITFeedbackMessage *)objSendInProgressMessage text]]) { + matchingSendInProgressMessage = objSendInProgressMessage; + *stop = YES; + } + }]; + + if (matchingSendInProgressMessage) { + matchingSendInProgressMessage.date = [self parseRFC3339Date:[(NSDictionary *)objMessage objectForKey:@"created_at"]]; + matchingSendInProgressMessage.id = messageID; + matchingSendInProgressMessage.status = BITFeedbackMessageStatusRead; } else { BITFeedbackMessage *message = [[[BITFeedbackMessage alloc] init] autorelease]; message.text = [(NSDictionary *)objMessage objectForKey:@"text"]; @@ -429,28 +516,22 @@ - (BOOL)updateMessageListFromResponse:(NSDictionary *)jsonDictionary { newResponseMessage = YES; } - messagesUpdated = YES; + } else { + // TODO: update message } }]; + // TODO: implement todo defined above - // remove all messages that are removed on the server - NSMutableSet *removedMessageIDs = [[[NSMutableSet alloc] init] autorelease]; + [self markSendInProgressMessagesAsPending]; + + // mark all messages as archived that are removed on the server [self.feedbackList enumerateObjectsUsingBlock:^(id objMessage, NSUInteger messagesIdx, BOOL *stop) { - if (![returnedMessageIDs member:[(BITFeedbackMessage *)objMessage id]]) { - [removedMessageIDs addObject:[(BITFeedbackMessage *)objMessage id]]; + if (![returnedMessageIDs member:[(BITFeedbackMessage *)objMessage id]] && + [(BITFeedbackMessage *)objMessage status] != BITFeedbackMessageStatusSendPending + ) { + [(BITFeedbackMessage *)objMessage setStatus:BITFeedbackMessageStatusArchived]; } }]; - - if ([removedMessageIDs count] > 0) { - [removedMessageIDs enumerateObjectsUsingBlock:^(id objID, BOOL *stop) { - [self.feedbackList removeObject:[self messageWithID:objID]]; - }]; - } - - // new data arrived, so save it - if (messagesUpdated) { - [self saveMessages]; - } // we got a new incoming message, trigger user notification system if (newResponseMessage) { @@ -467,11 +548,20 @@ - (BOOL)updateMessageListFromResponse:(NSDictionary *)jsonDictionary { } } - return YES; + NSInteger pendingMessagesCountAfterProcessing = [[self messagesWithStatus:BITFeedbackMessageStatusSendPending] count]; + + // check if this request was successful and we have more messages pending and continue if positive + if (pendingMessagesCount > pendingMessagesCountAfterProcessing && pendingMessagesCountAfterProcessing > 0) { + [self performSelector:@selector(submitPendingMessages) withObject:nil afterDelay:0.1]; + } + + } else { + [self markSendInProgressMessagesAsPending]; } - // quit - return NO; + [self saveMessages]; + + return; } - (void)sendNetworkRequestWithHTTPMethod:(NSString *)httpMethod withText:(NSString *)text completionHandler:(void (^)(NSError *err))completionHandler { @@ -529,9 +619,14 @@ - (void)sendNetworkRequestWithHTTPMethod:(NSString *)httpMethod withText:(NSStri _networkRequestInProgress = NO; if (err) { + [self markSendInProgressMessagesAsPending]; completionHandler(err); } else { - if ([responseData length]) { + NSInteger statusCode = [(NSHTTPURLResponse *)response statusCode]; + if (statusCode == 404) { + // thread has been deleted, we archive it + [self updateMessageListFromResponse:nil]; + } else if ([responseData length]) { NSString *responseString = [[[NSString alloc] initWithBytes:[responseData bytes] length:[responseData length] encoding: NSUTF8StringEncoding] autorelease]; BITHockeyLog(@"INFO: Received API response: %@", responseString); @@ -557,9 +652,10 @@ - (void)sendNetworkRequestWithHTTPMethod:(NSString *)httpMethod withText:(NSStri [self updateMessageListFromResponse:feedDict]; } } - - completionHandler(err); } + + [self markSendInProgressMessagesAsPending]; + completionHandler(err); } }]; } @@ -578,14 +674,20 @@ - (void)fetchMessageUpdates { } - (void)submitPendingMessages { - BITFeedbackMessage *message = [self nextPendingMessage]; + // app defined user data may have changed, update it + [self updateAppDefinedUserData]; - if (message) { - [message setStatus:BITFeedbackMessageStatusSendInProgress]; + NSArray *pendingMessages = [self messagesWithStatus:BITFeedbackMessageStatusSendPending]; + + if ([pendingMessages count] > 0) { + // we send one message at a time + BITFeedbackMessage *messageToSend = [pendingMessages objectAtIndex:0]; + + [messageToSend setStatus:BITFeedbackMessageStatusSendInProgress]; if (self.userName) - [message setName:self.userName]; + [messageToSend setName:self.userName]; if (self.userEmail) - [message setName:self.userEmail]; + [messageToSend setName:self.userEmail]; NSString *httpMethod = @"POST"; if ([self token]) { @@ -593,10 +695,10 @@ - (void)submitPendingMessages { } [self sendNetworkRequestWithHTTPMethod:httpMethod - withText:[message text] + withText:[messageToSend text] completionHandler:^(NSError *err){ if (err) { - [message setStatus:BITFeedbackMessageStatusSendPending]; + [self markSendInProgressMessagesAsPending]; [self saveMessages]; } diff --git a/Classes/Feedback/BITFeedbackManagerPrivate.h b/Classes/Feedback/BITFeedbackManagerPrivate.h index 510588ee..520e5c38 100644 --- a/Classes/Feedback/BITFeedbackManagerPrivate.h +++ b/Classes/Feedback/BITFeedbackManagerPrivate.h @@ -29,6 +29,7 @@ */ #import +#import "BITFeedbackMessage.h" @interface BITFeedbackManager () { @@ -42,15 +43,18 @@ @property (nonatomic, retain) NSMutableArray *feedbackList; +// used by BITHockeyManager if disable status is changed +@property (nonatomic, getter = isFeedbackManagerDisabled) BOOL disableFeedbackManager; + - (BITFeedbackMessage *)messageWithID:(NSNumber *)messageID; -- (BITFeedbackMessage *)sendInProgressMessage; -- (BITFeedbackMessage *)nextPendingMessage; + +- (NSArray *)messagesWithStatus:(BITFeedbackMessageStatus)status; - (void)saveMessages; - (void)fetchMessageUpdates; -- (BOOL)updateMessageListFromResponse:(NSDictionary *)jsonDictionary; +- (void)updateMessageListFromResponse:(NSDictionary *)jsonDictionary; @end diff --git a/Classes/Feedback/BITFeedbackMessage.h b/Classes/Feedback/BITFeedbackMessage.h index 2dfc81bc..0263e40c 100644 --- a/Classes/Feedback/BITFeedbackMessage.h +++ b/Classes/Feedback/BITFeedbackMessage.h @@ -37,7 +37,9 @@ typedef enum { // new messages from server BITFeedbackMessageStatusUnread = 2, // messages from server once read and new local messages once successful send from SDK - BITFeedbackMessageStatusRead = 3 + BITFeedbackMessageStatusRead = 3, + // message is archived, happens if the thread is deleted from the server + BITFeedbackMessageStatusArchived = 4 } BITFeedbackMessageStatus; @interface BITFeedbackMessage : NSObject { diff --git a/Classes/Helper/BITHockeyBaseViewController.h b/Classes/Helper/BITHockeyBaseViewController.h index 5196ec95..ded912d3 100644 --- a/Classes/Helper/BITHockeyBaseViewController.h +++ b/Classes/Helper/BITHockeyBaseViewController.h @@ -8,7 +8,7 @@ #import -@interface BITHockeyBaseViewController : UIViewController +@interface BITHockeyBaseViewController : UITableViewController @property (nonatomic, readwrite) BOOL modalAnimated; diff --git a/Classes/Helper/BITHockeyBaseViewController.m b/Classes/Helper/BITHockeyBaseViewController.m index 8e65ec3d..48b38d28 100644 --- a/Classes/Helper/BITHockeyBaseViewController.m +++ b/Classes/Helper/BITHockeyBaseViewController.m @@ -8,16 +8,16 @@ #import "BITHockeyBaseViewController.h" + @interface BITHockeyBaseViewController () + @property (nonatomic) BOOL modal; @property (nonatomic) UIStatusBarStyle statusBarStyle; + @end -@implementation BITHockeyBaseViewController -@synthesize modalAnimated = _modalAnimated; -@synthesize modal = _modal; -@synthesize statusBarStyle = _statusBarStyle; +@implementation BITHockeyBaseViewController - (id)init { From aee8ad245c171f37a444ae649187fd0c6d41dc45 Mon Sep 17 00:00:00 2001 From: Andreas Linde Date: Fri, 5 Oct 2012 22:37:43 +0200 Subject: [PATCH 008/176] Move BITUpdateManager to subclass of BITHockeyBaseManager and adjust some more code styling --- Classes/Helper/BITHockeyBaseManager.h | 29 +++- Classes/Helper/BITHockeyBaseManager.m | 46 +++++- Classes/Helper/BITHockeyBaseManagerPrivate.h | 17 +-- Classes/Helper/BITHockeyBaseViewController.m | 28 ++-- Classes/Update/BITUpdateManager.h | 34 +---- Classes/Update/BITUpdateManager.m | 144 ++++-------------- Classes/Update/BITUpdateViewController.h | 19 +-- Classes/Update/BITUpdateViewController.m | 116 ++++---------- .../Update/BITUpdateViewControllerPrivate.h | 6 +- 9 files changed, 149 insertions(+), 290 deletions(-) diff --git a/Classes/Helper/BITHockeyBaseManager.h b/Classes/Helper/BITHockeyBaseManager.h index fd94e6f2..3e3340ee 100644 --- a/Classes/Helper/BITHockeyBaseManager.h +++ b/Classes/Helper/BITHockeyBaseManager.h @@ -14,16 +14,33 @@ @interface BITHockeyBaseManager : NSObject ///----------------------------------------------------------------------------- -/// @name Delegate +/// @name Modules ///----------------------------------------------------------------------------- + /** - Sets the `BITUpdateManagerDelegate` delegate. + Defines the server URL to send data to or request data from - When using `BITUpdateManager` to distribute updates of your beta or enterprise - application, it is _REQUIRED_ to set this delegate and implement - `[BITUpdateManagerDelegate customDeviceIdentifierForUpdateManager:]`! + By default this is set to the HockeyApp servers and there rarely should be a + need to modify that. + */ +@property (nonatomic, copy) NSString *serverURL; + + +///----------------------------------------------------------------------------- +/// @name User Interface +///----------------------------------------------------------------------------- + +/** + The UIBarStyle of the update user interface navigation bar. + */ +@property (nonatomic, assign) UIBarStyle barStyle; + +/** + The UIModalPresentationStyle for showing the update user interface when invoked + with the update alert. */ -@property (nonatomic, assign) id delegate; +@property (nonatomic, assign) UIModalPresentationStyle modalPresentationStyle; + @end diff --git a/Classes/Helper/BITHockeyBaseManager.m b/Classes/Helper/BITHockeyBaseManager.m index b6b9aa5d..868227dc 100644 --- a/Classes/Helper/BITHockeyBaseManager.m +++ b/Classes/Helper/BITHockeyBaseManager.m @@ -18,16 +18,25 @@ #import "BITHockeyManagerPrivate.h" #import +#import -@implementation BITHockeyBaseManager +@implementation BITHockeyBaseManager { + UINavigationController *_navController; + + NSDateFormatter *_rfc3339Formatter; + + NSString *_appIdentifier; + BOOL _isAppStoreEnvironment; +} - (id)init { if ((self = [super init])) { _isAppStoreEnvironment = NO; _appIdentifier = nil; - + _serverURL = BITHOCKEYSDK_URL; + _navController = nil; _barStyle = UIBarStyleDefault; _modalPresentationStyle = UIModalPresentationFormSheet; @@ -42,7 +51,7 @@ - (id)init { - (id)initWithAppIdentifier:(NSString *)appIdentifier isAppStoreEnvironemt:(BOOL)isAppStoreEnvironment { if ((self = [self init])) { - self.appIdentifier = appIdentifier; + _appIdentifier = appIdentifier; _isAppStoreEnvironment = isAppStoreEnvironment; } @@ -51,7 +60,7 @@ - (id)initWithAppIdentifier:(NSString *)appIdentifier isAppStoreEnvironemt:(BOOL - (void)dealloc { - [_appIdentifier release]; + [_serverURL release]; _serverURL = nil; [_navController release], _navController = nil; @@ -64,7 +73,11 @@ - (void)dealloc { #pragma mark - Private - (void)reportError:(NSError *)error { - BITHockeyLog(@"Error: %@", [error localizedDescription]); + BITHockeyLog(@"ERROR: %@", [error localizedDescription]); +} + +- (BOOL)isAppStoreEnvironment { + return _isAppStoreEnvironment; } - (NSString *)encodedAppIdentifier { @@ -81,6 +94,26 @@ - (NSString *)getDevicePlatform { return platform; } +- (NSString *)executableUUID { + const uint8_t *command = (const uint8_t *)(&_mh_execute_header + 1); + for (uint32_t idx = 0; idx < _mh_execute_header.ncmds; ++idx) { + const struct load_command *load_command = (const struct load_command *)command; + if (load_command->cmd == LC_UUID) { + const struct uuid_command *uuid_command = (const struct uuid_command *)command; + const uint8_t *uuid = uuid_command->uuid; + return [[NSString stringWithFormat:@"%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X", + uuid[0], uuid[1], uuid[2], uuid[3], + uuid[4], uuid[5], uuid[6], uuid[7], + uuid[8], uuid[9], uuid[10], uuid[11], + uuid[12], uuid[13], uuid[14], uuid[15]] + lowercaseString]; + } else { + command += load_command->cmdsize; + } + } + return nil; +} + - (UIWindow *)findVisibleWindow { UIWindow *visibleWindow = nil; @@ -122,7 +155,10 @@ - (void)showView:(BITHockeyBaseViewController *)viewController { // special addition to get rootViewController from three20 which has it's own controller handling if (NSClassFromString(@"TTNavigator")) { +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Warc-performSelector-leaks" parentViewController = [[NSClassFromString(@"TTNavigator") performSelector:(NSSelectorFromString(@"navigator"))] visibleViewController]; +#pragma clang diagnostic pop } if (_navController != nil) [_navController release], _navController = nil; diff --git a/Classes/Helper/BITHockeyBaseManagerPrivate.h b/Classes/Helper/BITHockeyBaseManagerPrivate.h index d4696049..c5028524 100644 --- a/Classes/Helper/BITHockeyBaseManagerPrivate.h +++ b/Classes/Helper/BITHockeyBaseManagerPrivate.h @@ -12,20 +12,7 @@ @class BITHockeyBaseManager; @class BITHockeyBaseViewController; -@interface BITHockeyBaseManager() { - UINavigationController *_navController; - UIBarStyle _barStyle; - UIModalPresentationStyle _modalPresentationStyle; - - NSDateFormatter *_rfc3339Formatter; - - BOOL _isAppStoreEnvironment; -} - -// set the server URL -@property (nonatomic, retain) NSString *serverURL; - -@property (nonatomic, retain) NSString *appIdentifier; +@interface BITHockeyBaseManager() - (id)initWithAppIdentifier:(NSString *)appIdentifier isAppStoreEnvironemt:(BOOL)isAppStoreEnvironment; @@ -33,8 +20,10 @@ - (void)reportError:(NSError *)error; - (NSString *)encodedAppIdentifier; +- (BOOL)isAppStoreEnvironment; - (NSString *)getDevicePlatform; +- (NSString *)executableUUID; - (UIWindow *)findVisibleWindow; - (void)showView:(BITHockeyBaseViewController *)viewController; diff --git a/Classes/Helper/BITHockeyBaseViewController.m b/Classes/Helper/BITHockeyBaseViewController.m index 48b38d28..630e8220 100644 --- a/Classes/Helper/BITHockeyBaseViewController.m +++ b/Classes/Helper/BITHockeyBaseViewController.m @@ -25,6 +25,15 @@ - (id)init { if (self) { _modalAnimated = YES; _modal = NO; + + //might be better in viewDidLoad, but to workaround rdar://12214613 and as it doesn't + //hurt, we do it here + if (self.modal) { + self.navigationItem.leftBarButtonItem = [[[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemDone + target:self + action:@selector(onDismissModal:)] autorelease]; + } + } return self; } @@ -46,7 +55,10 @@ - (void)onDismissModal:(id)sender { SEL presentingViewControllerSelector = NSSelectorFromString(@"presentingViewController"); UIViewController *presentingViewController = nil; if ([self respondsToSelector:presentingViewControllerSelector]) { +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Warc-performSelector-leaks" presentingViewController = [self performSelector:presentingViewControllerSelector]; +#pragma clang diagnostic pop } else { presentingViewController = [self parentViewController]; } @@ -64,22 +76,6 @@ - (void)onDismissModal:(id)sender { [[UIApplication sharedApplication] setStatusBarStyle:_statusBarStyle]; } -- (void)viewDidLoad { - [super viewDidLoad]; - - if (self.modal) { - self.navigationItem.leftBarButtonItem = [[[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemDone - target:self - action:@selector(onDismissModal:)] autorelease]; - } - - // Do any additional setup after loading the view. -} - -- (void)viewDidUnload { - [super viewDidUnload]; - // Release any retained subviews of the main view. -} - (void)viewWillAppear:(BOOL)animated { [super viewWillAppear:animated]; diff --git a/Classes/Update/BITUpdateManager.h b/Classes/Update/BITUpdateManager.h index ae402efc..656f8d07 100644 --- a/Classes/Update/BITUpdateManager.h +++ b/Classes/Update/BITUpdateManager.h @@ -30,6 +30,7 @@ #import +#import "BITHockeyBaseManager.h" typedef enum { @@ -78,26 +79,7 @@ typedef enum { */ -@interface BITUpdateManager : NSObject { -@private - NSString *_appIdentifier; - NSString *_currentAppVersion; - - UINavigationController *_navController; - BITUpdateViewController *_currentHockeyViewController; - - BOOL _dataFound; - BOOL _showFeedback; - BOOL _updateAlertShowing; - BOOL _lastCheckFailed; - BOOL _sendUsageData; - - BOOL _isAppStoreEnvironment; - - BOOL _didSetupDidBecomeActiveNotifications; - - NSString *_uuid; -} +@interface BITUpdateManager : BITHockeyBaseManager ///----------------------------------------------------------------------------- @@ -291,18 +273,6 @@ typedef enum { /// @name User Interface ///----------------------------------------------------------------------------- -/** - The UIBarStyle of the update user interface navigation bar. - */ -@property (nonatomic, assign) UIBarStyle barStyle; - - -/** - The UIModalPresentationStyle for showing the update user interface when invoked - with the update alert. - */ -@property (nonatomic, assign) UIModalPresentationStyle modalPresentationStyle; - /** Present the modal update user interface. diff --git a/Classes/Update/BITUpdateManager.m b/Classes/Update/BITUpdateManager.m index 394bb0fc..6f5ab5a8 100644 --- a/Classes/Update/BITUpdateManager.m +++ b/Classes/Update/BITUpdateManager.m @@ -30,11 +30,11 @@ #import #import -#import #import "HockeySDK.h" #import "HockeySDKPrivate.h" #import "BITHockeyHelper.h" +#import "BITHockeyBaseManagerPrivate.h" #import "BITUpdateManagerPrivate.h" #import "BITUpdateViewControllerPrivate.h" #import "BITAppVersionMetaInfo.h" @@ -52,7 +52,21 @@ #define BETA_UPDATE_APPSIZE @"appsize" -@implementation BITUpdateManager +@implementation BITUpdateManager { + NSString *_currentAppVersion; + + BITUpdateViewController *_currentHockeyViewController; + + BOOL _dataFound; + BOOL _showFeedback; + BOOL _updateAlertShowing; + BOOL _lastCheckFailed; + BOOL _sendUsageData; + + BOOL _didSetupDidBecomeActiveNotifications; + + NSString *_uuid; +} #pragma mark - private @@ -73,39 +87,6 @@ - (void)reportError:(NSError *)error { } } -- (NSString *)encodedAppIdentifier { - return (_appIdentifier ? bit_URLEncodedString(_appIdentifier) : bit_URLEncodedString([[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleIdentifier"])); -} - -- (NSString *)getDevicePlatform { - size_t size; - sysctlbyname("hw.machine", NULL, &size, NULL, 0); - char *answer = (char*)malloc(size); - sysctlbyname("hw.machine", answer, &size, NULL, 0); - NSString *platform = [NSString stringWithCString:answer encoding: NSUTF8StringEncoding]; - free(answer); - return platform; -} - -- (NSString *)executableUUID { - const uint8_t *command = (const uint8_t *)(&_mh_execute_header + 1); - for (uint32_t idx = 0; idx < _mh_execute_header.ncmds; ++idx) { - const struct load_command *load_command = (const struct load_command *)command; - if (load_command->cmd == LC_UUID) { - const struct uuid_command *uuid_command = (const struct uuid_command *)command; - const uint8_t *uuid = uuid_command->uuid; - return [[NSString stringWithFormat:@"%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X", - uuid[0], uuid[1], uuid[2], uuid[3], - uuid[4], uuid[5], uuid[6], uuid[7], - uuid[8], uuid[9], uuid[10], uuid[11], - uuid[12], uuid[13], uuid[14], uuid[15]] - lowercaseString]; - } else { - command += load_command->cmdsize; - } - } - return nil; -} - (void)didBecomeActiveActions { if (![self isUpdateManagerDisabled]) { @@ -136,7 +117,7 @@ - (void)cleanupDidBecomeActiveNotifications { #pragma mark - Expiry - (BOOL)expiryDateReached { - if (_isAppStoreEnvironment) return NO; + if ([self isAppStoreEnvironment]) return NO; if (_expiryDate) { NSDate *currentDate = [NSDate date]; @@ -328,11 +309,7 @@ - (UIWindow *)findVisibleWindow { #pragma mark - Init - (id)initWithAppIdentifier:(NSString *)appIdentifier isAppStoreEnvironemt:(BOOL)isAppStoreEnvironment { - if ((self = [super init])) { - _appIdentifier = appIdentifier; - _isAppStoreEnvironment = isAppStoreEnvironment; - - _serverURL = BITHOCKEYSDK_URL; + if ((self = [super initWithAppIdentifier:appIdentifier isAppStoreEnvironemt:isAppStoreEnvironment])) { _delegate = nil; _expiryDate = nil; _checkInProgress = NO; @@ -340,12 +317,11 @@ - (id)initWithAppIdentifier:(NSString *)appIdentifier isAppStoreEnvironemt:(BOOL _updateAvailable = NO; _lastCheckFailed = NO; _currentAppVersion = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleVersion"]; - _navController = nil; _blockingView = nil; _requireAuthorization = NO; _authenticationSecret = nil; _lastCheck = nil; - _uuid = [[self executableUUID] retain]; + _uuid = [[self executableUUID] copy]; _sendUsageData = YES; _disableUpdateManager = NO; _checkForTracker = NO; @@ -356,8 +332,6 @@ - (id)initWithAppIdentifier:(NSString *)appIdentifier isAppStoreEnvironemt:(BOOL self.alwaysShowUpdateReminder = YES; self.checkForUpdateOnLaunch = YES; self.compareVersionType = BITUpdateComparisonResultGreater; - self.barStyle = UIBarStyleDefault; - self.modalPresentationStyle = UIModalPresentationFormSheet; self.updateSetting = BITUpdateCheckStartup; if ([[NSUserDefaults standardUserDefaults] objectForKey:kBITUpdateDateOfLastCheck]) { @@ -400,15 +374,12 @@ - (void)dealloc { _delegate = nil; - [_serverURL release]; - [_urlConnection cancel]; self.urlConnection = nil; [_expiryDate release]; _expiryDate = nil; - [_navController release]; [_blockingView release]; [_currentHockeyViewController release]; [_appVersions release]; @@ -425,11 +396,11 @@ - (void)dealloc { #pragma mark - BetaUpdateUI - (BITUpdateViewController *)hockeyViewController:(BOOL)modal { - return [[[BITUpdateViewController alloc] init:self modal:modal] autorelease]; + return [[[BITUpdateViewController alloc] initWithModalStyle:modal] autorelease]; } - (void)showUpdateView { - if (_isAppStoreEnvironment) { + if ([self isAppStoreEnvironment]) { NSLog(@"[HockeySDK] This should not be called from an app store build!"); return; } @@ -439,63 +410,12 @@ - (void)showUpdateView { return; } - UIViewController *parentViewController = nil; - - if ([[self delegate] respondsToSelector:@selector(viewControllerForUpdateManager:)]) { - parentViewController = [_delegate viewControllerForUpdateManager:self]; - } - - UIWindow *visibleWindow = [self findVisibleWindow]; - - if (parentViewController == nil && [UIWindow instancesRespondToSelector:@selector(rootViewController)]) { - parentViewController = [visibleWindow rootViewController]; - } - - // use topmost modal view - while (parentViewController.modalViewController) { - parentViewController = parentViewController.modalViewController; - } - - // special addition to get rootViewController from three20 which has it's own controller handling - if (NSClassFromString(@"TTNavigator")) { -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Warc-performSelector-leaks" - parentViewController = [[NSClassFromString(@"TTNavigator") performSelector:(NSSelectorFromString(@"navigator"))] visibleViewController]; -#pragma clang diagnostic pop - } - - if (_navController != nil) [_navController release]; - - BITUpdateViewController *hockeyViewController = [self hockeyViewController:YES]; - _navController = [[UINavigationController alloc] initWithRootViewController:hockeyViewController]; - _navController.navigationBar.barStyle = _barStyle; - _navController.modalPresentationStyle = _modalPresentationStyle; - - if (parentViewController) { - if ([_navController respondsToSelector:@selector(setModalTransitionStyle:)]) { - _navController.modalTransitionStyle = UIModalTransitionStyleCoverVertical; - } - - // page sheet for the iPad - if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad && [_navController respondsToSelector:@selector(setModalPresentationStyle:)]) { - _navController.modalPresentationStyle = UIModalPresentationFormSheet; - } - - hockeyViewController.modalAnimated = YES; - - [parentViewController presentModalViewController:_navController animated:YES]; - } else { - // if not, we add a subview to the window. A bit hacky but should work in most circumstances. - // Also, we don't get a nice animation for free, but hey, this is for beta not production users ;) - NSLog(@"[HockeySDK] Warning: No rootViewController found and no view controller set via delegate, using UIWindow-approach: %@", visibleWindow); - hockeyViewController.modalAnimated = NO; - [visibleWindow addSubview:_navController.view]; - } + [self showView:[self hockeyViewController:YES]]; } - (void)showCheckForUpdateAlert { - if (_isAppStoreEnvironment) return; + if ([self isAppStoreEnvironment]) return; if ([self isUpdateManagerDisabled]) return; if (!_updateAlertShowing) { @@ -616,14 +536,14 @@ - (void)checkForAuthorization { [parameter appendFormat:@"?format=json&authorize=yes&app_version=%@&udid=%@&sdk=%@&sdk_version=%@&uuid=%@", bit_URLEncodedString([[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleVersion"]), - (_isAppStoreEnvironment ? @"appstore" : bit_URLEncodedString([self deviceIdentifier])), + ([self isAppStoreEnvironment] ? @"appstore" : bit_URLEncodedString([self deviceIdentifier])), BITHOCKEY_NAME, BITHOCKEY_VERSION, _uuid ]; // build request & send - NSString *url = [NSString stringWithFormat:@"%@%@", _serverURL, parameter]; + NSString *url = [NSString stringWithFormat:@"%@%@", self.serverURL, parameter]; BITHockeyLog(@"INFO: Sending api request to %@", url); NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:url] cachePolicy:1 timeoutInterval:10.0]; @@ -687,7 +607,7 @@ - (void)checkForAuthorization { } - (void)checkForUpdate { - if (!_isAppStoreEnvironment && ![self isUpdateManagerDisabled]) { + if (![self isAppStoreEnvironment] && ![self isUpdateManagerDisabled]) { if ([self expiryDateReached]) return; if (self.requireAuthorization) return; @@ -716,7 +636,7 @@ - (void)checkForUpdateShowFeedback:(BOOL)feedback { NSMutableString *parameter = [NSMutableString stringWithFormat:@"api/2/apps/%@?format=json&udid=%@&sdk=%@&sdk_version=%@&uuid=%@", bit_URLEncodedString([self encodedAppIdentifier]), - (_isAppStoreEnvironment ? @"appstore" : bit_URLEncodedString([self deviceIdentifier])), + ([self isAppStoreEnvironment] ? @"appstore" : bit_URLEncodedString([self deviceIdentifier])), BITHOCKEY_NAME, BITHOCKEY_VERSION, _uuid]; @@ -738,7 +658,7 @@ - (void)checkForUpdateShowFeedback:(BOOL)feedback { } // build request & send - NSString *url = [NSString stringWithFormat:@"%@%@", _serverURL, parameter]; + NSString *url = [NSString stringWithFormat:@"%@%@", self.serverURL, parameter]; BITHockeyLog(@"INFO: Sending api request to %@", url); NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:url] cachePolicy:1 timeoutInterval:10.0]; @@ -756,7 +676,7 @@ - (void)checkForUpdateShowFeedback:(BOOL)feedback { } - (BOOL)initiateAppDownload { - if (_isAppStoreEnvironment) return NO; + if ([self isAppStoreEnvironment]) return NO; if (!self.isUpdateAvailable) { BITHockeyLog(@"WARNING: No update available. Aborting."); @@ -774,7 +694,7 @@ - (BOOL)initiateAppDownload { extraParameter = [NSString stringWithFormat:@"&udid=%@", [self deviceIdentifier]]; } - NSString *hockeyAPIURL = [NSString stringWithFormat:@"%@api/2/apps/%@?format=plist%@", _serverURL, [self encodedAppIdentifier], extraParameter]; + NSString *hockeyAPIURL = [NSString stringWithFormat:@"%@api/2/apps/%@?format=plist%@", self.serverURL, [self encodedAppIdentifier], extraParameter]; NSString *iOSUpdateURL = [NSString stringWithFormat:@"itms-services://?action=download-manifest&url=%@", bit_URLEncodedString(hockeyAPIURL)]; BITHockeyLog(@"INFO: API Server Call: %@, calling iOS with %@", hockeyAPIURL, iOSUpdateURL); @@ -818,7 +738,7 @@ - (BOOL)appVersionIsAuthorized { // begin the startup process - (void)startManager { - if (!_isAppStoreEnvironment) { + if (![self isAppStoreEnvironment]) { if ([self isUpdateManagerDisabled]) return; BITHockeyLog(@"INFO: Start UpdateManager"); @@ -899,7 +819,7 @@ - (void)connectionDidFinishLoading:(NSURLConnection *)connection { id json = bit_parseJSON(responseString, &error); self.trackerConfig = (([self checkForTracker] && [[json valueForKey:@"tracker"] isKindOfClass:[NSDictionary class]]) ? [json valueForKey:@"tracker"] : nil); - if (!_isAppStoreEnvironment) { + if (![self isAppStoreEnvironment]) { NSArray *feedArray = (NSArray *)([self checkForTracker] ? [json valueForKey:@"versions"] : json); self.receivedData = nil; diff --git a/Classes/Update/BITUpdateViewController.h b/Classes/Update/BITUpdateViewController.h index 4ca81f11..cf131cc4 100644 --- a/Classes/Update/BITUpdateViewController.h +++ b/Classes/Update/BITUpdateViewController.h @@ -30,23 +30,12 @@ #import +#import "BITHockeyBaseViewController.h" + + @class PSStoreButton; @class PSAppStoreHeader; -@interface BITUpdateViewController : UITableViewController { -@private - BOOL _kvoRegistered; - BOOL _showAllVersions; - UIStatusBarStyle _statusBarStyle; - PSAppStoreHeader *_appStoreHeader; - PSStoreButton *_appStoreButton; - - id _popOverController; - - NSMutableArray *_cells; - - BOOL _isAppStoreEnvironment; -} - +@interface BITUpdateViewController : BITHockeyBaseViewController @end diff --git a/Classes/Update/BITUpdateViewController.m b/Classes/Update/BITUpdateViewController.m index 4a64ccee..2eea80e6 100644 --- a/Classes/Update/BITUpdateViewController.m +++ b/Classes/Update/BITUpdateViewController.m @@ -47,11 +47,19 @@ #define kAppStoreViewHeight 90 -@implementation BITUpdateViewController - -@synthesize appStoreButtonState = _appStoreButtonState; -@synthesize modal = _modal; -@synthesize modalAnimated = _modalAnimated; +@implementation BITUpdateViewController { + BOOL _kvoRegistered; + BOOL _showAllVersions; + UIStatusBarStyle _statusBarStyle; + PSAppStoreHeader *_appStoreHeader; + PSStoreButton *_appStoreButton; + + id _popOverController; + + NSMutableArray *_cells; + + BOOL _isAppStoreEnvironment; +} #pragma mark - Private @@ -198,75 +206,44 @@ - (void)configureWebCell:(PSWebTableViewCell *)cell forAppVersion:(BITAppVersion #pragma mark - Init -- (id)init:(BITUpdateManager *)newUpdateManager modal:(BOOL)newModal { +- (id)init { if ((self = [super initWithStyle:UITableViewStylePlain])) { - self.updateManager = newUpdateManager; - self.modal = newModal; - self.modalAnimated = YES; + _updateManager = [BITHockeyManager sharedHockeyManager].updateManager ; + _isAppStoreEnvironment = [BITHockeyManager sharedHockeyManager].isAppStoreEnvironment; + self.title = BITHockeyLocalizedString(@"UpdateScreenTitle"); - _isAppStoreEnvironment = [BITHockeyManager sharedHockeyManager].isAppStoreEnvironment; - _cells = [[NSMutableArray alloc] initWithCapacity:5]; _popOverController = nil; - - //might be better in viewDidLoad, but to workaround rdar://12214613 and as it doesn't - //hurt, we do it here - if (self.modal) { - self.navigationItem.leftBarButtonItem = [[[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemDone - target:self - action:@selector(onAction:)] autorelease]; - } } return self; } -- (id)init { - return [self init:[BITHockeyManager sharedHockeyManager].updateManager modal:NO]; -} - - (void)dealloc { - [self viewDidUnload]; + [_appStoreHeader release]; _appStoreHeader = nil; + [_popOverController release], _popOverController = nil; + [[NSNotificationCenter defaultCenter] removeObserver:self]; + + // test if KVO's are registered. if class is destroyed before it was shown(viewDidLoad) no KVOs are registered. + if (_kvoRegistered) { + [_updateManager removeObserver:self forKeyPath:@"checkInProgress"]; + [_updateManager removeObserver:self forKeyPath:@"isUpdateURLOffline"]; + [_updateManager removeObserver:self forKeyPath:@"updateAvailable"]; + [_updateManager removeObserver:self forKeyPath:@"apps"]; + _kvoRegistered = NO; + } + for (UITableViewCell *cell in _cells) { [cell removeObserver:self forKeyPath:@"webViewSize"]; } [_cells release]; + [super dealloc]; } #pragma mark - View lifecycle -- (void)onAction:(id)sender { - if (self.modal) { - // Note that as of 5.0, parentViewController will no longer return the presenting view controller - SEL presentingViewControllerSelector = NSSelectorFromString(@"presentingViewController"); - UIViewController *presentingViewController = nil; - if ([self respondsToSelector:presentingViewControllerSelector]) { -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Warc-performSelector-leaks" - presentingViewController = [self performSelector:presentingViewControllerSelector]; -#pragma clang diagnostic pop - } - else { - presentingViewController = [self parentViewController]; - } - - // If there is no presenting view controller just remove view - if (presentingViewController && self.modalAnimated) { - [presentingViewController dismissModalViewControllerAnimated:YES]; - } - else { - [self.navigationController.view removeFromSuperview]; - } - } - else { - [self.navigationController popViewControllerAnimated:YES]; - } - - [[UIApplication sharedApplication] setStatusBarStyle:_statusBarStyle]; -} - - (CAGradientLayer *)backgroundLayer { UIColor *colorOne = [UIColor colorWithWhite:0.9 alpha:1.0]; UIColor *colorTwo = [UIColor colorWithHue:0.625 saturation:0.0 brightness:0.85 alpha:1.0]; @@ -453,23 +430,6 @@ - (void)showPreviousVersionAction { [self showHidePreviousVersionsButton]; } -- (void)viewDidUnload { - [_appStoreHeader release]; _appStoreHeader = nil; - [_popOverController release], _popOverController = nil; - [[NSNotificationCenter defaultCenter] removeObserver:self]; - - // test if KVO's are registered. if class is destroyed before it was shown(viewDidLoad) no KVOs are registered. - if (_kvoRegistered) { - [_updateManager removeObserver:self forKeyPath:@"checkInProgress"]; - [_updateManager removeObserver:self forKeyPath:@"isUpdateURLOffline"]; - [_updateManager removeObserver:self forKeyPath:@"updateAvailable"]; - [_updateManager removeObserver:self forKeyPath:@"apps"]; - _kvoRegistered = NO; - } - - [super viewDidUnload]; -} - #pragma mark - Table view data source @@ -540,20 +500,6 @@ - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(N #pragma mark - Rotation -- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation { - BOOL shouldAutorotate; - - if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone) { - shouldAutorotate = (interfaceOrientation == UIInterfaceOrientationLandscapeLeft || - interfaceOrientation == UIInterfaceOrientationLandscapeRight || - interfaceOrientation == UIInterfaceOrientationPortrait); - } else { - shouldAutorotate = YES; - } - - return shouldAutorotate; -} - - (void)willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation duration:(NSTimeInterval)duration { // update all cells [_cells makeObjectsPerformSelector:@selector(addWebView)]; diff --git a/Classes/Update/BITUpdateViewControllerPrivate.h b/Classes/Update/BITUpdateViewControllerPrivate.h index 310d10c5..3ac39c89 100644 --- a/Classes/Update/BITUpdateViewControllerPrivate.h +++ b/Classes/Update/BITUpdateViewControllerPrivate.h @@ -47,13 +47,9 @@ typedef enum { @interface BITUpdateViewController() { } -@property (nonatomic, retain) BITUpdateManager *updateManager; +@property (nonatomic, assign) BITUpdateManager *updateManager; @property (nonatomic, readwrite) BOOL modal; -@property (nonatomic, readwrite) BOOL modalAnimated; @property (nonatomic, assign) AppStoreButtonState appStoreButtonState; -- (id)init:(BITUpdateManager *)newUpdateManager modal:(BOOL)newModal; -- (id)init; - @end From 798dd8b9b25eff9d36bf086c4c805d61dad9a731 Mon Sep 17 00:00:00 2001 From: Andreas Linde Date: Fri, 5 Oct 2012 22:45:15 +0200 Subject: [PATCH 009/176] Use the the assigned serverURL in FeedbackManager --- Classes/Feedback/BITFeedbackManager.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Classes/Feedback/BITFeedbackManager.m b/Classes/Feedback/BITFeedbackManager.m index dd1a9f40..a98e5c53 100644 --- a/Classes/Feedback/BITFeedbackManager.m +++ b/Classes/Feedback/BITFeedbackManager.m @@ -582,7 +582,7 @@ - (void)sendNetworkRequestWithHTTPMethod:(NSString *)httpMethod withText:(NSStri ]; // build request & send - NSString *url = [NSString stringWithFormat:@"https://warmup.hockeyapp.net/%@", parameter]; + NSString *url = [NSString stringWithFormat:@"%@%@", self.serverURL, parameter]; BITHockeyLog(@"INFO: sending api request to %@", url); NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:url] cachePolicy:1 timeoutInterval:10.0]; From b7cda2625f4ff17b0d58a517d048491369f08c55 Mon Sep 17 00:00:00 2001 From: Andreas Linde Date: Fri, 5 Oct 2012 23:04:55 +0200 Subject: [PATCH 010/176] Code cleanup --- Classes/Feedback/BITFeedbackManager.h | 49 ++++++------------- Classes/Feedback/BITFeedbackManager.m | 40 ++++++++------- Classes/Feedback/BITFeedbackManagerPrivate.h | 39 +++++++++++++-- .../BITFeedbackUserDataViewController.m | 2 +- Classes/Update/BITUpdateManagerPrivate.h | 7 --- 5 files changed, 71 insertions(+), 66 deletions(-) diff --git a/Classes/Feedback/BITFeedbackManager.h b/Classes/Feedback/BITFeedbackManager.h index 81353108..fed6ee87 100644 --- a/Classes/Feedback/BITFeedbackManager.h +++ b/Classes/Feedback/BITFeedbackManager.h @@ -42,53 +42,32 @@ typedef enum { @class BITFeedbackMessage; -@protocol BITFeedbackManagerDelegate; @interface BITFeedbackManager : BITHockeyBaseManager -@property (nonatomic, retain) BITFeedbackListViewController *currentFeedbackListViewController; -@property (nonatomic, retain) BITFeedbackComposeViewController *currentFeedbackComposeViewController; -@property (nonatomic) BOOL didAskUserData; - -@property (nonatomic, retain) NSDate *lastCheck; - @property (nonatomic, readwrite) BITFeedbackUserDataElement requireUserName; // default is BITFeedbackUserDataRequired @property (nonatomic, readwrite) BITFeedbackUserDataElement requireUserEmail; // default is BITFeedbackUserDataRequired @property (nonatomic, readwrite) BOOL showAlertOnIncomingMessages; // default is YES -@property (nonatomic, copy) NSString *userName; -@property (nonatomic, copy) NSString *userEmail; +///----------------------------------------------------------------------------- +/// @name User Interface +///----------------------------------------------------------------------------- -// convenience methode to create feedback view controller -- (BITFeedbackListViewController *)feedbackListViewController:(BOOL)modal; - -// load new messages from the server -- (void)updateMessagesList; - -// open feedback list view +/** + Present the modal feedback list user interface. + */ - (void)showFeedbackListView; -// open feedback compose view -- (void)showFeedbackComposeView; - -- (NSUInteger)numberOfMessages; -- (BITFeedbackMessage *)messageAtIndex:(NSUInteger)index; -- (void)submitMessageWithText:(NSString *)text; -- (void)submitPendingMessages; - -// Returns YES if manual user data can be entered, required or optional -- (BOOL)askManualUserDataAvailable; - -// Returns YES if required user data is missing? -- (BOOL)requireManualUserDataMissing; - -// Returns YES if user data is available and can be edited -- (BOOL)isManualUserDataAvailable; - -// used in the user data screen -- (void)updateDidAskUserData; +/** + Create an feedback list view + + @param modal Return a view ready for modal presentation with integrated navigation bar + @return BITFeedbackListViewController The update user interface view controller, + e.g. to push it onto a navigation stack. + */ +- (BITFeedbackListViewController *)feedbackListViewController:(BOOL)modal; @end diff --git a/Classes/Feedback/BITFeedbackManager.m b/Classes/Feedback/BITFeedbackManager.m index a98e5c53..6925943f 100644 --- a/Classes/Feedback/BITFeedbackManager.m +++ b/Classes/Feedback/BITFeedbackManager.m @@ -51,8 +51,10 @@ @implementation BITFeedbackManager { NSFileManager *_fileManager; NSString *_feedbackDir; NSString *_settingsFile; - + + BOOL _incomingMessagesAlertShowing; BOOL _didSetupDidBecomeActiveNotifications; + BOOL _networkRequestInProgress; } #pragma mark - Initialization @@ -174,7 +176,7 @@ - (void)showFeedbackComposeView { #pragma mark - Manager Control - (void)startManager { - if ([self.feedbackList count] == 0) { + if ([_feedbackList count] == 0) { [self loadMessages]; } else { [self updateAppDefinedUserData]; @@ -265,7 +267,7 @@ - (void)loadMessages { } if ([unarchiver containsValueForKey:kBITFeedbackUserDataAsked]) - self.didAskUserData = YES; + _didAskUserData = YES; if ([unarchiver containsValueForKey:kBITFeedbackToken]) self.token = [unarchiver decodeObjectForKey:kBITFeedbackToken]; @@ -303,7 +305,7 @@ - (void)saveMessages { NSMutableData *data = [[NSMutableData alloc] init]; NSKeyedArchiver *archiver = [[NSKeyedArchiver alloc] initForWritingWithMutableData:data]; - if (self.didAskUserData) + if (_didAskUserData) [archiver encodeObject:[NSNumber numberWithBool:YES] forKey:kBITFeedbackUserDataAsked]; if (self.token) @@ -328,8 +330,8 @@ - (void)saveMessages { - (void)updateDidAskUserData { - if (!self.didAskUserData) { - self.didAskUserData = YES; + if (!_didAskUserData) { + _didAskUserData = YES; [self saveMessages]; } @@ -338,7 +340,7 @@ - (void)updateDidAskUserData { #pragma mark - Messages - (void)sortFeedbackList { - [self.feedbackList sortUsingComparator:^(BITFeedbackMessage *obj1, BITFeedbackMessage *obj2) { + [_feedbackList sortUsingComparator:^(BITFeedbackMessage *obj1, BITFeedbackMessage *obj2) { NSDate *date1 = [obj1 date]; NSDate *date2 = [obj2 date]; @@ -356,12 +358,12 @@ - (void)sortFeedbackList { } - (NSUInteger)numberOfMessages { - return [self.feedbackList count]; + return [_feedbackList count]; } - (BITFeedbackMessage *)messageAtIndex:(NSUInteger)index { - if ([self.feedbackList count] > index) { - return [self.feedbackList objectAtIndex:index]; + if ([_feedbackList count] > index) { + return [_feedbackList objectAtIndex:index]; } return nil; @@ -370,7 +372,7 @@ - (BITFeedbackMessage *)messageAtIndex:(NSUInteger)index { - (BITFeedbackMessage *)messageWithID:(NSNumber *)messageID { __block BITFeedbackMessage *message = nil; - [self.feedbackList enumerateObjectsUsingBlock:^(BITFeedbackMessage *objMessage, NSUInteger messagesIdx, BOOL *stop) { + [_feedbackList enumerateObjectsUsingBlock:^(BITFeedbackMessage *objMessage, NSUInteger messagesIdx, BOOL *stop) { if ([[objMessage id] isEqualToNumber:messageID]) { message = objMessage; *stop = YES; @@ -381,9 +383,9 @@ - (BITFeedbackMessage *)messageWithID:(NSNumber *)messageID { } - (NSArray *)messagesWithStatus:(BITFeedbackMessageStatus)status { - NSMutableArray *resultMessages = [[NSMutableArray alloc] initWithCapacity:[self.feedbackList count]]; + NSMutableArray *resultMessages = [[NSMutableArray alloc] initWithCapacity:[_feedbackList count]]; - [self.feedbackList enumerateObjectsUsingBlock:^(BITFeedbackMessage *objMessage, NSUInteger messagesIdx, BOOL *stop) { + [_feedbackList enumerateObjectsUsingBlock:^(BITFeedbackMessage *objMessage, NSUInteger messagesIdx, BOOL *stop) { if ([objMessage status] == status) { [resultMessages addObject: objMessage]; } @@ -394,7 +396,7 @@ - (NSArray *)messagesWithStatus:(BITFeedbackMessageStatus)status { - (void)markSendInProgressMessagesAsPending { // make sure message that may have not been send successfully, get back into the right state to be send again - [self.feedbackList enumerateObjectsUsingBlock:^(id objMessage, NSUInteger messagesIdx, BOOL *stop) { + [_feedbackList enumerateObjectsUsingBlock:^(id objMessage, NSUInteger messagesIdx, BOOL *stop) { if ([(BITFeedbackMessage *)objMessage status] == BITFeedbackMessageStatusSendInProgress) [(BITFeedbackMessage *)objMessage setStatus:BITFeedbackMessageStatusSendPending]; }]; @@ -441,7 +443,7 @@ - (void)updateMessageListFromResponse:(NSDictionary *)jsonDictionary { [self markSendInProgressMessagesAsPending]; - [self.feedbackList enumerateObjectsUsingBlock:^(id objMessage, NSUInteger messagesIdx, BOOL *stop) { + [_feedbackList enumerateObjectsUsingBlock:^(id objMessage, NSUInteger messagesIdx, BOOL *stop) { if ([(BITFeedbackMessage *)objMessage status] != BITFeedbackMessageStatusSendPending) [(BITFeedbackMessage *)objMessage setStatus:BITFeedbackMessageStatusArchived]; }]; @@ -512,7 +514,7 @@ - (void)updateMessageListFromResponse:(NSDictionary *)jsonDictionary { message.id = [(NSDictionary *)objMessage objectForKey:@"id"]; message.status = BITFeedbackMessageStatusUnread; - [self.feedbackList addObject:message]; + [_feedbackList addObject:message]; newResponseMessage = YES; } @@ -525,7 +527,7 @@ - (void)updateMessageListFromResponse:(NSDictionary *)jsonDictionary { [self markSendInProgressMessagesAsPending]; // mark all messages as archived that are removed on the server - [self.feedbackList enumerateObjectsUsingBlock:^(id objMessage, NSUInteger messagesIdx, BOOL *stop) { + [_feedbackList enumerateObjectsUsingBlock:^(id objMessage, NSUInteger messagesIdx, BOOL *stop) { if (![returnedMessageIDs member:[(BITFeedbackMessage *)objMessage id]] && [(BITFeedbackMessage *)objMessage status] != BITFeedbackMessageStatusSendPending ) { @@ -661,7 +663,7 @@ - (void)sendNetworkRequestWithHTTPMethod:(NSString *)httpMethod withText:(NSStri } - (void)fetchMessageUpdates { - if ([self.feedbackList count] == 0) { + if ([_feedbackList count] == 0) { return; } @@ -715,7 +717,7 @@ - (void)submitMessageWithText:(NSString *)text { [message setStatus:BITFeedbackMessageStatusSendPending]; [message setUserMessage:YES]; - [self.feedbackList addObject:message]; + [_feedbackList addObject:message]; [self submitPendingMessages]; } diff --git a/Classes/Feedback/BITFeedbackManagerPrivate.h b/Classes/Feedback/BITFeedbackManagerPrivate.h index 520e5c38..9b9908d0 100644 --- a/Classes/Feedback/BITFeedbackManagerPrivate.h +++ b/Classes/Feedback/BITFeedbackManagerPrivate.h @@ -36,16 +36,47 @@ } -@property (nonatomic, readwrite) BOOL incomingMessagesAlertShowing; -@property (nonatomic) BOOL networkRequestInProgress; - -@property (nonatomic, retain) NSString *token; @property (nonatomic, retain) NSMutableArray *feedbackList; +@property (nonatomic, retain) NSString *token; // used by BITHockeyManager if disable status is changed @property (nonatomic, getter = isFeedbackManagerDisabled) BOOL disableFeedbackManager; +@property (nonatomic, retain) BITFeedbackListViewController *currentFeedbackListViewController; +@property (nonatomic, retain) BITFeedbackComposeViewController *currentFeedbackComposeViewController; +@property (nonatomic) BOOL didAskUserData; + +@property (nonatomic, retain) NSDate *lastCheck; + +@property (nonatomic, copy) NSString *userName; +@property (nonatomic, copy) NSString *userEmail; + + +// load new messages from the server +- (void)updateMessagesList; + +// open feedback compose view +- (void)showFeedbackComposeView; + +- (NSUInteger)numberOfMessages; +- (BITFeedbackMessage *)messageAtIndex:(NSUInteger)index; + +- (void)submitMessageWithText:(NSString *)text; +- (void)submitPendingMessages; + +// Returns YES if manual user data can be entered, required or optional +- (BOOL)askManualUserDataAvailable; + +// Returns YES if required user data is missing? +- (BOOL)requireManualUserDataMissing; + +// Returns YES if user data is available and can be edited +- (BOOL)isManualUserDataAvailable; + +// used in the user data screen +- (void)updateDidAskUserData; + - (BITFeedbackMessage *)messageWithID:(NSNumber *)messageID; diff --git a/Classes/Feedback/BITFeedbackUserDataViewController.m b/Classes/Feedback/BITFeedbackUserDataViewController.m index 8fea23b8..637c310b 100644 --- a/Classes/Feedback/BITFeedbackUserDataViewController.m +++ b/Classes/Feedback/BITFeedbackUserDataViewController.m @@ -31,7 +31,7 @@ #import "HockeySDKPrivate.h" #import "BITFeedbackUserDataViewController.h" - +#import "BITFeedbackManagerPrivate.h" @interface BITFeedbackUserDataViewController () @property (nonatomic, assign) BITFeedbackManager *manager; diff --git a/Classes/Update/BITUpdateManagerPrivate.h b/Classes/Update/BITUpdateManagerPrivate.h index 8ab3da34..67abbe92 100644 --- a/Classes/Update/BITUpdateManagerPrivate.h +++ b/Classes/Update/BITUpdateManagerPrivate.h @@ -35,9 +35,6 @@ @interface BITUpdateManager () { } -// set the server URL -@property (nonatomic, retain) NSString *serverURL; - // is an update available? @property (nonatomic, assign, getter=isUpdateAvailable) BOOL updateAvailable; @@ -67,10 +64,6 @@ // used by BITHockeyManager if disable status is changed @property (nonatomic, getter = isUpdateManagerDisabled) BOOL disableUpdateManager; -- (id)initWithAppIdentifier:(NSString *)appIdentifier isAppStoreEnvironemt:(BOOL)isAppStoreEnvironment; - -- (void)startManager; - // checks for update, informs the user (error, no update found, etc) - (void)checkForUpdateShowFeedback:(BOOL)feedback; From 4d8ed6b408fbf5f4d96dae71f6aaf2a68abdc357 Mon Sep 17 00:00:00 2001 From: Andreas Linde Date: Fri, 5 Oct 2012 23:21:46 +0200 Subject: [PATCH 011/176] Some more minor cleanup --- Classes/CrashReports/BITCrashManager.m | 2 -- Classes/Update/BITUpdateManager.m | 4 ++-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/Classes/CrashReports/BITCrashManager.m b/Classes/CrashReports/BITCrashManager.m index 54ad7742..e55cfab1 100644 --- a/Classes/CrashReports/BITCrashManager.m +++ b/Classes/CrashReports/BITCrashManager.m @@ -89,8 +89,6 @@ @implementation BITCrashManager { - (id)init { if ((self = [super init])) { - self.serverURL = BITHOCKEYSDK_URL; - _delegate = nil; _showAlwaysButton = NO; _isSetup = NO; diff --git a/Classes/Update/BITUpdateManager.m b/Classes/Update/BITUpdateManager.m index 6f5ab5a8..67bf42c1 100644 --- a/Classes/Update/BITUpdateManager.m +++ b/Classes/Update/BITUpdateManager.m @@ -308,8 +308,8 @@ - (UIWindow *)findVisibleWindow { #pragma mark - Init -- (id)initWithAppIdentifier:(NSString *)appIdentifier isAppStoreEnvironemt:(BOOL)isAppStoreEnvironment { - if ((self = [super initWithAppIdentifier:appIdentifier isAppStoreEnvironemt:isAppStoreEnvironment])) { +- (id)init { + if ((self = [super init])) { _delegate = nil; _expiryDate = nil; _checkInProgress = NO; From 478f26a7f62cced82496d15ad6156a98cbccf22d Mon Sep 17 00:00:00 2001 From: Andreas Linde Date: Sat, 6 Oct 2012 01:43:39 +0200 Subject: [PATCH 012/176] Fixes for iPad and Message composer presentation --- Classes/Feedback/BITFeedbackComposeViewController.h | 2 +- Classes/Feedback/BITFeedbackComposeViewController.m | 5 ----- Classes/Feedback/BITFeedbackListViewController.m | 1 + 3 files changed, 2 insertions(+), 6 deletions(-) diff --git a/Classes/Feedback/BITFeedbackComposeViewController.h b/Classes/Feedback/BITFeedbackComposeViewController.h index c8264d36..078a26aa 100644 --- a/Classes/Feedback/BITFeedbackComposeViewController.h +++ b/Classes/Feedback/BITFeedbackComposeViewController.h @@ -30,7 +30,7 @@ #import #import "BITHockeyBaseViewController.h" -@interface BITFeedbackComposeViewController : BITHockeyBaseViewController +@interface BITFeedbackComposeViewController : UIViewController - (id)init; diff --git a/Classes/Feedback/BITFeedbackComposeViewController.m b/Classes/Feedback/BITFeedbackComposeViewController.m index e5f78202..33c91f30 100644 --- a/Classes/Feedback/BITFeedbackComposeViewController.m +++ b/Classes/Feedback/BITFeedbackComposeViewController.m @@ -94,11 +94,6 @@ - (void)viewDidLoad { [self.view addSubview:self.textView]; } -- (void)viewDidUnload { - [super viewDidUnload]; - // Release any retained subviews of the main view. -} - - (void)viewWillAppear:(BOOL)animated { self.manager.currentFeedbackComposeViewController = self; diff --git a/Classes/Feedback/BITFeedbackListViewController.m b/Classes/Feedback/BITFeedbackListViewController.m index 04fd7a64..1c9f2a04 100644 --- a/Classes/Feedback/BITFeedbackListViewController.m +++ b/Classes/Feedback/BITFeedbackListViewController.m @@ -154,6 +154,7 @@ - (void)newFeedbackAction:(id)sender { BITFeedbackComposeViewController *composeController = [[[BITFeedbackComposeViewController alloc] init] autorelease]; UINavigationController *navController = [[[UINavigationController alloc] initWithRootViewController:composeController] autorelease]; + navController.modalPresentationStyle = UIModalPresentationFormSheet; [self.navigationController presentModalViewController:navController animated:YES]; } From b9d5b19b3cf353cd6c6bc0cfccae2f1ded43e04e Mon Sep 17 00:00:00 2001 From: Andreas Linde Date: Sat, 6 Oct 2012 21:39:27 +0200 Subject: [PATCH 013/176] Remove unused feature to modally show feedback compose view directly Also has the problem, that we would need to copy the modal view code in there, since it can be a subclass from BITBaseViewController right now, since that is a subclass of UITableViewController to get the iOS6 pull to refresh feature --- Classes/Feedback/BITFeedbackManager.m | 13 ------------- Classes/Feedback/BITFeedbackManagerPrivate.h | 3 --- 2 files changed, 16 deletions(-) diff --git a/Classes/Feedback/BITFeedbackManager.m b/Classes/Feedback/BITFeedbackManager.m index 6925943f..a3fed49f 100644 --- a/Classes/Feedback/BITFeedbackManager.m +++ b/Classes/Feedback/BITFeedbackManager.m @@ -159,19 +159,6 @@ - (void)showFeedbackListView { [self showView:[self feedbackListViewController:YES]]; } -- (BITFeedbackComposeViewController *)feedbackComposeViewController:(BOOL)modal { - return [[[BITFeedbackComposeViewController alloc] initWithModalStyle:modal] autorelease]; -} - -- (void)showFeedbackComposeView { - if (_currentFeedbackComposeViewController) { - BITHockeyLog(@"INFO: update view already visible, aborting"); - return; - } - - [self showView:[self feedbackComposeViewController:YES]]; -} - #pragma mark - Manager Control diff --git a/Classes/Feedback/BITFeedbackManagerPrivate.h b/Classes/Feedback/BITFeedbackManagerPrivate.h index 9b9908d0..c789549c 100644 --- a/Classes/Feedback/BITFeedbackManagerPrivate.h +++ b/Classes/Feedback/BITFeedbackManagerPrivate.h @@ -56,9 +56,6 @@ // load new messages from the server - (void)updateMessagesList; -// open feedback compose view -- (void)showFeedbackComposeView; - - (NSUInteger)numberOfMessages; - (BITFeedbackMessage *)messageAtIndex:(NSUInteger)index; From 46157510044003dfacc4a82f89b3d7fdfaf16cba Mon Sep 17 00:00:00 2001 From: Andreas Linde Date: Sun, 7 Oct 2012 01:51:43 +0200 Subject: [PATCH 014/176] Feedback UI polish --- Classes/Feedback/BITFeedbackListViewCell.h | 10 +- Classes/Feedback/BITFeedbackListViewCell.m | 101 +++++++++--------- .../Feedback/BITFeedbackListViewController.m | 95 ++++++++++++++-- Classes/Helper/HockeySDKPrivate.h | 2 + Classes/Update/BITUpdateViewController.m | 1 - Resources/de.lproj/HockeySDK.strings | 8 +- Resources/en.lproj/HockeySDK.strings | 8 +- Resources/es.lproj/HockeySDK.strings | 8 +- Resources/fr.lproj/HockeySDK.strings | 8 +- Resources/it.lproj/HockeySDK.strings | 8 +- Resources/ja.lproj/HockeySDK.strings | 8 +- Resources/nl.lproj/HockeySDK.strings | 8 +- Resources/pt-PT.lproj/HockeySDK.strings | 8 +- Resources/pt.lproj/HockeySDK.strings | 8 +- Resources/ru.lproj/HockeySDK.strings | 8 +- Resources/sv.lproj/HockeySDK.strings | 8 +- Resources/tr.lproj/HockeySDK.strings | 8 +- Resources/zh_CN.lproj/HockeySDK.strings | 8 +- Resources/zh_TW.lproj/HockeySDK.strings | 8 +- 19 files changed, 203 insertions(+), 118 deletions(-) diff --git a/Classes/Feedback/BITFeedbackListViewCell.h b/Classes/Feedback/BITFeedbackListViewCell.h index 87f7c6ba..daf09b4c 100644 --- a/Classes/Feedback/BITFeedbackListViewCell.h +++ b/Classes/Feedback/BITFeedbackListViewCell.h @@ -30,13 +30,19 @@ #import typedef enum { - BITFeedbackListViewCellStyleNormal = 0, // left aligned header style - BITFeedbackListViewCellStyleRepsonse = 1 // right aligned header style for dev responses + BITFeedbackListViewCellStyleNormal = 0, // right aligned header style + BITFeedbackListViewCellStyleRepsonse = 1 // left aligned header style for dev responses } BITFeedbackListViewCellStyle; +typedef enum { + BITFeedbackListViewCellBackgroundStyleNormal = 0, + BITFeedbackListViewCellBackgroundStyleAlternate = 1 +} BITFeedbackListViewCellBackgroundStyle; + @interface BITFeedbackListViewCell : UITableViewCell @property (nonatomic) BITFeedbackListViewCellStyle style; +@property (nonatomic) BITFeedbackListViewCellBackgroundStyle backgroundStyle; @property (nonatomic) BOOL sent; @property (nonatomic, copy) NSDate *date; diff --git a/Classes/Feedback/BITFeedbackListViewCell.m b/Classes/Feedback/BITFeedbackListViewCell.m index b32b5ad0..325fdf50 100644 --- a/Classes/Feedback/BITFeedbackListViewCell.m +++ b/Classes/Feedback/BITFeedbackListViewCell.m @@ -28,25 +28,34 @@ #import "BITFeedbackListViewCell.h" +#import "HockeySDKPrivate.h" + +#define BACKGROUNDCOLOR_DEFAULT BIT_RGBCOLOR(245, 245, 245) +#define BACKGROUNDCOLOR_ALTERNATE BIT_RGBCOLOR(235, 235, 235) + +#define TEXTCOLOR_TITLE BIT_RGBCOLOR(75, 75, 75) + +#define TEXTCOLOR_DEFAULT BIT_RGBCOLOR(25, 25, 25) +#define TEXTCOLOR_PENDING BIT_RGBCOLOR(75, 75, 75) + +#define TITLE_FONTSIZE 12 +#define TEXT_FONTSIZE 15 #define FRAME_SIDE_BORDER 10 -#define FRAME_TOP_BORDER 5 +#define FRAME_TOP_BORDER 8 #define FRAME_BOTTOM_BORDER 5 +#define FRAME_LEFT_RESPONSE_BORDER 20 -#define LABEL_DATE_Y 0 -#define LABEL_DATE_HEIGHT 15 - -#define LABEL_NAME_Y 15 -#define LABEL_NAME_HEIGHT 15 +#define LABEL_TITLE_Y 3 +#define LABEL_TITLE_HEIGHT 15 -#define LABEL_TEXT_Y 40 +#define LABEL_TEXT_Y 25 @interface BITFeedbackListViewCell () @property (nonatomic, retain) NSDateFormatter *dateFormatter; -@property (nonatomic, retain) UILabel *labelDate; -@property (nonatomic, retain) UILabel *labelName; +@property (nonatomic, retain) UILabel *labelTitle; @property (nonatomic, retain) UILabel *labelText; @end @@ -59,9 +68,8 @@ - (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reus self = [super initWithStyle:style reuseIdentifier:reuseIdentifier]; if (self) { // Initialization code - self.contentView.backgroundColor = [UIColor whiteColor]; - _style = BITFeedbackListViewCellStyleNormal; + _backgroundStyle = BITFeedbackListViewCellBackgroundStyleNormal; _sent = YES; _date = nil; @@ -74,14 +82,11 @@ - (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reus [self.dateFormatter setLocale:[NSLocale currentLocale]]; [self.dateFormatter setDoesRelativeDateFormatting:YES]; - self.labelDate = [[[UILabel alloc] init] autorelease]; - self.labelDate.font = [UIFont systemFontOfSize:12]; - - self.labelName = [[[UILabel alloc] init] autorelease]; - self.labelName.font = [UIFont systemFontOfSize:12]; + self.labelTitle = [[[UILabel alloc] init] autorelease]; + self.labelTitle.font = [UIFont systemFontOfSize:TITLE_FONTSIZE]; self.labelText = [[[UILabel alloc] init] autorelease]; - self.labelText.font = [UIFont systemFontOfSize:14]; + self.labelText.font = [UIFont systemFontOfSize:TEXT_FONTSIZE]; self.labelText.numberOfLines = 0; self.labelText.textAlignment = UITextAlignmentLeft; } @@ -91,8 +96,7 @@ - (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reus - (void)dealloc { [_dateFormatter release], _dateFormatter = nil; - [_labelDate release], _labelDate = nil; - [_labelName release], _labelName = nil; + [_labelTitle release], _labelTitle = nil; [_labelText release], _labelText = nil; [_date release], _date = nil; @@ -106,53 +110,52 @@ - (void)dealloc { #pragma mark - Layout + (CGFloat) heightForRowWithText:(NSString *)text tableViewWidth:(CGFloat)width { - CGFloat calculatedHeight = [text sizeWithFont:[UIFont systemFontOfSize:14] - constrainedToSize:CGSizeMake(width - (2 * FRAME_SIDE_BORDER), CGFLOAT_MAX)].height + LABEL_TEXT_Y + FRAME_BOTTOM_BORDER; + CGFloat calculatedHeight = [text sizeWithFont:[UIFont systemFontOfSize:TEXT_FONTSIZE] + constrainedToSize:CGSizeMake(width - (2 * FRAME_SIDE_BORDER), CGFLOAT_MAX)].height + FRAME_TOP_BORDER + LABEL_TEXT_Y + FRAME_BOTTOM_BORDER; return calculatedHeight; } - (void)layoutSubviews { [super layoutSubviews]; - - NSString *dateString = [self.dateFormatter stringFromDate:self.date]; - [self.labelDate setText:dateString];// [self.date description]]; - [self.labelDate setFrame:CGRectMake(FRAME_SIDE_BORDER, FRAME_TOP_BORDER + LABEL_DATE_Y, self.frame.size.width - (2 * FRAME_SIDE_BORDER), LABEL_DATE_HEIGHT)]; - [self.labelName setText:self.name]; - [self.labelName setFrame:CGRectMake(FRAME_SIDE_BORDER, FRAME_TOP_BORDER + LABEL_NAME_Y, self.frame.size.width - (2 * FRAME_SIDE_BORDER), LABEL_NAME_HEIGHT)]; + // colors + if (_backgroundStyle == BITFeedbackListViewCellBackgroundStyleNormal) { + self.contentView.backgroundColor = BACKGROUNDCOLOR_DEFAULT; + self.labelTitle.backgroundColor = BACKGROUNDCOLOR_DEFAULT; + self.labelText.backgroundColor = BACKGROUNDCOLOR_DEFAULT; + } else { + self.contentView.backgroundColor = BACKGROUNDCOLOR_ALTERNATE; + self.labelTitle.backgroundColor = BACKGROUNDCOLOR_ALTERNATE; + self.labelText.backgroundColor = BACKGROUNDCOLOR_ALTERNATE; + } + self.labelTitle.textColor = TEXTCOLOR_TITLE; + if (self.sent) { + [self.labelText setTextColor:TEXTCOLOR_DEFAULT]; + } else { + [self.labelText setTextColor:TEXTCOLOR_PENDING]; + } + // header - if (_style == BITFeedbackListViewCellStyleNormal) { - self.contentView.backgroundColor = [UIColor whiteColor]; - self.labelDate.backgroundColor = [UIColor whiteColor]; - self.labelName.backgroundColor = [UIColor whiteColor]; - self.labelText.backgroundColor = [UIColor whiteColor]; + NSString *dateString = [self.dateFormatter stringFromDate:self.date]; + [self.labelTitle setText:dateString];// [self.date description]]; + [self.labelTitle setFrame:CGRectMake(FRAME_SIDE_BORDER, FRAME_TOP_BORDER + LABEL_TITLE_Y, self.frame.size.width - (2 * FRAME_SIDE_BORDER), LABEL_TITLE_HEIGHT)]; - self.labelDate.textAlignment = UITextAlignmentLeft; - self.labelName.textAlignment = UITextAlignmentLeft; + if (_style == BITFeedbackListViewCellStyleNormal) { + self.labelTitle.textAlignment = UITextAlignmentRight; + self.labelText.textAlignment = UITextAlignmentRight; } else { - self.contentView.backgroundColor = [UIColor lightGrayColor]; - self.labelDate.backgroundColor = [UIColor lightGrayColor]; - self.labelName.backgroundColor = [UIColor lightGrayColor]; - self.labelText.backgroundColor = [UIColor lightGrayColor]; - - self.labelDate.textAlignment = UITextAlignmentRight; - self.labelName.textAlignment = UITextAlignmentRight; + self.labelTitle.textAlignment = UITextAlignmentLeft; + self.labelText.textAlignment = UITextAlignmentLeft; } - [self addSubview:self.labelDate]; - [self addSubview:self.labelName]; + [self addSubview:self.labelTitle]; // text [self.labelText setText:self.text]; CGSize size = CGSizeMake(self.frame.size.width - (2 * FRAME_SIDE_BORDER), [[self class] heightForRowWithText:self.text tableViewWidth:self.frame.size.width] - LABEL_TEXT_Y - FRAME_BOTTOM_BORDER); - [self.labelText setFrame : CGRectMake(FRAME_SIDE_BORDER, LABEL_TEXT_Y, size.width, size.height)]; - if (self.sent) { - [self.labelText setTextColor:[UIColor darkTextColor]]; - } else { - [self.labelText setTextColor:[UIColor lightGrayColor]]; - } + [self.labelText setFrame:CGRectMake(FRAME_SIDE_BORDER, LABEL_TEXT_Y, size.width, size.height)]; [self addSubview:self.labelText]; } diff --git a/Classes/Feedback/BITFeedbackListViewController.m b/Classes/Feedback/BITFeedbackListViewController.m index 1c9f2a04..1ccd8942 100644 --- a/Classes/Feedback/BITFeedbackListViewController.m +++ b/Classes/Feedback/BITFeedbackListViewController.m @@ -38,8 +38,19 @@ #import "BITFeedbackMessage.h" #import "BITHockeyHelper.h" +#import +#define DEFAULT_BACKGROUNDCOLOR BIT_RGBCOLOR(245, 245, 245) +#define DEFAULT_TEXTCOLOR BIT_RGBCOLOR(75, 75, 75) +#define BUTTON_BACKGROUNDCOLOR BIT_RGBCOLOR(225, 225, 225) +#define BUTTON_BORDERCOLOR BIT_RGBCOLOR(175, 175, 175) +#define BUTTON_TEXTCOLOR BIT_RGBCOLOR(58, 58, 58) +#define BUTTON_TEXTCOLOR_SHADOW BIT_RGBCOLOR(175, 175, 175) +#define BORDER_COLOR1 BIT_RGBCOLOR(215, 215, 215) +#define BORDER_COLOR2 BIT_RGBCOLOR(221, 221, 221) +#define BORDER_COLOR3 BIT_RGBCOLOR(255, 255, 255) + @interface BITFeedbackListViewController () @property (nonatomic, assign) BITFeedbackManager *manager; @@ -88,7 +99,9 @@ - (void)viewDidLoad { [self.tableView setAutoresizingMask:UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth]; [self.tableView setBackgroundColor:[UIColor colorWithRed:0.82 green:0.84 blue:0.84 alpha:1]]; [self.tableView setSeparatorColor:[UIColor colorWithRed:0.79 green:0.79 blue:0.79 alpha:1]]; - + + self.view.backgroundColor = DEFAULT_BACKGROUNDCOLOR; + id refreshClass = NSClassFromString(@"UIRefreshControl"); if (refreshClass) { self.refreshControl = [[[UIRefreshControl alloc] init] autorelease]; @@ -185,7 +198,7 @@ - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { if (section == 0) { - return 2; + return 1; } else if (section == 2) { return 1; } else { @@ -204,6 +217,7 @@ - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(N if (!cell) { cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:LastUpdateIdentifier] autorelease]; cell.textLabel.font = [UIFont systemFontOfSize:10]; + cell.textLabel.textColor = DEFAULT_TEXTCOLOR; cell.accessoryType = UITableViewCellAccessoryNone; cell.selectionStyle = UITableViewCellSelectionStyleNone; cell.textLabel.textAlignment = UITextAlignmentCenter; @@ -214,6 +228,8 @@ - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(N return cell; } else if (indexPath.section == 0 || indexPath.section == 2) { + CGFloat topGap = 0.0f; + UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:ButtonIdentifier]; if (!cell) { @@ -224,9 +240,16 @@ - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(N cell.selectionStyle = UITableViewCellSelectionStyleNone; } - UIButton *button = [UIButton buttonWithType:UIButtonTypeRoundedRect]; - [button setTitleColor:[UIColor blackColor] forState:UIControlStateNormal]; - [button setTitleShadowColor:[UIColor lightGrayColor] forState:UIControlStateNormal]; + UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom]; + [button.layer setMasksToBounds:YES]; + [button.layer setCornerRadius:10.0f]; + [button.layer setBorderWidth:1]; + [button.layer setBackgroundColor:BUTTON_BACKGROUNDCOLOR.CGColor]; + [button.layer setBorderColor:BUTTON_BORDERCOLOR.CGColor]; + [button.layer setShadowOffset:CGSizeMake(-1, -1)]; + [[button titleLabel] setFont:[UIFont boldSystemFontOfSize:14.0]]; + [button setTitleColor:BUTTON_TEXTCOLOR forState:UIControlStateNormal]; + [button setTitleShadowColor:BUTTON_TEXTCOLOR_SHADOW forState:UIControlStateNormal]; if (indexPath.section == 0) { if ([self.manager numberOfMessages] == 0) { [button setTitle:BITHockeyLocalizedString(@"HockeyFeedbackListButonWriteFeedback") forState:UIControlStateNormal]; @@ -235,6 +258,7 @@ - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(N } [button addTarget:self action:@selector(newFeedbackAction:) forControlEvents:UIControlEventTouchUpInside]; } else { + topGap = 6.0f; NSString *title = @""; if ([self.manager requireUserName] == BITFeedbackUserDataElementRequired || ([self.manager requireUserName] == BITFeedbackUserDataElementOptional && [self.manager userName] != nil) @@ -252,10 +276,40 @@ - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(N [button setTitle:title forState:UIControlStateNormal]; [button addTarget:self action:@selector(setUserDataAction:) forControlEvents:UIControlEventTouchUpInside]; } - [button setFrame: CGRectMake( 10.0f, 12.0f, self.view.frame.size.width - 20.0f, 50.0f)]; + [button setFrame: CGRectMake( 10.0f, topGap + 12.0f, self.view.frame.size.width - 20.0f, 42.0f)]; [cell addSubview:button]; + if (indexPath.section == 0) { + UILabel *statusLabel = [[[UILabel alloc] initWithFrame:CGRectMake(0, 59, self.view.frame.size.width, 28)] autorelease]; + + statusLabel.font = [UIFont systemFontOfSize:10]; + statusLabel.textColor = DEFAULT_TEXTCOLOR; + statusLabel.textAlignment = UITextAlignmentCenter; + statusLabel.backgroundColor = DEFAULT_BACKGROUNDCOLOR; + statusLabel.autoresizingMask = UIViewAutoresizingFlexibleWidth; + + statusLabel.text = [NSString stringWithFormat:BITHockeyLocalizedString(@"HockeyFeedbackListLastUpdated"), + [self.manager lastCheck] ? [self.lastUpdateDateFormatter stringFromDate:[self.manager lastCheck]] : BITHockeyLocalizedString(@"HockeyFeedbackListNeverUpdated")]; + + [cell addSubview:statusLabel]; + } else { + UIView *lineView1 = [[[UIView alloc] initWithFrame:CGRectMake(0, 0, cell.contentView.bounds.size.width, 1)] autorelease]; + lineView1.backgroundColor = BORDER_COLOR1; + lineView1.autoresizingMask = UIViewAutoresizingFlexibleWidth; + [cell addSubview:lineView1]; + + UIView *lineView2 = [[[UIView alloc] initWithFrame:CGRectMake(0, 1, cell.contentView.bounds.size.width, 1)] autorelease]; + lineView2.backgroundColor = BORDER_COLOR2; + lineView2.autoresizingMask = UIViewAutoresizingFlexibleWidth; + [cell addSubview:lineView2]; + + UIView *lineView3 = [[[UIView alloc] initWithFrame:CGRectMake(0, 2, cell.contentView.bounds.size.width, 1)] autorelease]; + lineView3.backgroundColor = BORDER_COLOR3; + lineView3.autoresizingMask = UIViewAutoresizingFlexibleWidth; + [cell addSubview:lineView3]; + } + return cell; } else { BITFeedbackListViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier]; @@ -266,6 +320,12 @@ - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(N cell.selectionStyle = UITableViewCellSelectionStyleNone; } + if (indexPath.row == 0 || indexPath.row % 2 == 0) { + cell.backgroundStyle = BITFeedbackListViewCellBackgroundStyleAlternate; + } else { + cell.backgroundStyle = BITFeedbackListViewCellBackgroundStyleNormal; + } + BITFeedbackMessage *message = [self.manager messageAtIndex:indexPath.row]; cell.date = message.date; @@ -292,7 +352,22 @@ - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(N } else { cell.text = @""; } + + UIView *lineView1 = [[[UIView alloc] initWithFrame:CGRectMake(0, 0, cell.contentView.bounds.size.width, 1)] autorelease]; + lineView1.backgroundColor = BORDER_COLOR1; + lineView1.autoresizingMask = UIViewAutoresizingFlexibleWidth; + [cell addSubview:lineView1]; + + UIView *lineView2 = [[[UIView alloc] initWithFrame:CGRectMake(0, 1, cell.contentView.bounds.size.width, 1)] autorelease]; + lineView2.backgroundColor = BORDER_COLOR2; + lineView2.autoresizingMask = UIViewAutoresizingFlexibleWidth; + [cell addSubview:lineView2]; + UIView *lineView3 = [[[UIView alloc] initWithFrame:CGRectMake(0, 2, cell.contentView.bounds.size.width, 1)] autorelease]; + lineView3.backgroundColor = BORDER_COLOR3; + lineView3.autoresizingMask = UIViewAutoresizingFlexibleWidth; + [cell addSubview:lineView3]; + return cell; } } @@ -301,11 +376,11 @@ - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(N #pragma mark - Table view delegate - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath { - if (indexPath.section == 0 && indexPath.row == 1) { - return 28; + if (indexPath.section == 0 ) { + return 87; } - if (indexPath.section == 0 || indexPath.section == 2) { - return 74; + if (indexPath.section == 2) { + return 75; } BITFeedbackMessage *message = [self.manager messageAtIndex:indexPath.row]; diff --git a/Classes/Helper/HockeySDKPrivate.h b/Classes/Helper/HockeySDKPrivate.h index 75f638d2..3b426027 100644 --- a/Classes/Helper/HockeySDKPrivate.h +++ b/Classes/Helper/HockeySDKPrivate.h @@ -60,6 +60,8 @@ #define BITHockeyLog(fmt, ...) do { if([BITHockeyManager sharedHockeyManager].isDebugLogEnabled && ![BITHockeyManager sharedHockeyManager].isAppStoreEnvironment) { NSLog((@"[HockeySDK] %s/%d " fmt), __PRETTY_FUNCTION__, __LINE__, ##__VA_ARGS__); }} while(0) +#define BIT_RGBCOLOR(r,g,b) [UIColor colorWithRed:(r)/255.0 green:(g)/255.0 blue:(b)/255.0 alpha:1] + NSBundle *BITHockeyBundle(void); NSString *BITHockeyLocalizedString(NSString *stringToken); NSString *BITHockeyMD5(NSString *str); diff --git a/Classes/Update/BITUpdateViewController.m b/Classes/Update/BITUpdateViewController.m index 2eea80e6..cdf715c0 100644 --- a/Classes/Update/BITUpdateViewController.m +++ b/Classes/Update/BITUpdateViewController.m @@ -42,7 +42,6 @@ #import "BITUpdateViewControllerPrivate.h" -#define BIT_RGBCOLOR(r,g,b) [UIColor colorWithRed:(r)/255.0 green:(g)/255.0 blue:(b)/255.0 alpha:1] #define kWebCellIdentifier @"PSWebTableViewCell" #define kAppStoreViewHeight 90 diff --git a/Resources/de.lproj/HockeySDK.strings b/Resources/de.lproj/HockeySDK.strings index 6d8382e0..8544e1ac 100755 --- a/Resources/de.lproj/HockeySDK.strings +++ b/Resources/de.lproj/HockeySDK.strings @@ -140,11 +140,11 @@ /* Never Updated */ "HockeyFeedbackListNeverUpdated" = "Never"; -/* Write Feedback Button Title */ -"HockeyFeedbackListButonWriteFeedback" = "Write Feedback"; +/* Provide Feedback Button Title */ +"HockeyFeedbackListButonWriteFeedback" = "Provide Feedback"; -/* Write Response Button Title */ -"HockeyFeedbackListButonWriteResponse" = "Write Response"; +/* Add a Response Button Title */ +"HockeyFeedbackListButonWriteResponse" = "Add a Response"; /* User Data Set Name Button Title */ "HockeyFeedbackListButonUserDataSetName" = "Set Your Name"; diff --git a/Resources/en.lproj/HockeySDK.strings b/Resources/en.lproj/HockeySDK.strings index 502a40ac..16b5278f 100755 --- a/Resources/en.lproj/HockeySDK.strings +++ b/Resources/en.lproj/HockeySDK.strings @@ -137,11 +137,11 @@ /* Never Updated */ "HockeyFeedbackListNeverUpdated" = "Never"; -/* Write Feedback Button Title */ -"HockeyFeedbackListButonWriteFeedback" = "Write Feedback"; +/* Provide Feedback Button Title */ +"HockeyFeedbackListButonWriteFeedback" = "Provide Feedback"; -/* Write Response Button Title */ -"HockeyFeedbackListButonWriteResponse" = "Write Response"; +/* Add a Response Button Title */ +"HockeyFeedbackListButonWriteResponse" = "Add a Response"; /* User Data Set Name Button Title */ "HockeyFeedbackListButonUserDataSetName" = "Set Your Name"; diff --git a/Resources/es.lproj/HockeySDK.strings b/Resources/es.lproj/HockeySDK.strings index 6d94259a..a1707823 100755 --- a/Resources/es.lproj/HockeySDK.strings +++ b/Resources/es.lproj/HockeySDK.strings @@ -138,11 +138,11 @@ /* Never Updated */ "HockeyFeedbackListNeverUpdated" = "Never"; -/* Write Feedback Button Title */ -"HockeyFeedbackListButonWriteFeedback" = "Write Feedback"; +/* Provide Feedback Button Title */ +"HockeyFeedbackListButonWriteFeedback" = "Provide Feedback"; -/* Write Response Button Title */ -"HockeyFeedbackListButonWriteResponse" = "Write Response"; +/* Add a Response Button Title */ +"HockeyFeedbackListButonWriteResponse" = "Add a Response"; /* User Data Set Name Button Title */ "HockeyFeedbackListButonUserDataSetName" = "Set Your Name"; diff --git a/Resources/fr.lproj/HockeySDK.strings b/Resources/fr.lproj/HockeySDK.strings index be958900..c33d8265 100755 --- a/Resources/fr.lproj/HockeySDK.strings +++ b/Resources/fr.lproj/HockeySDK.strings @@ -138,11 +138,11 @@ /* Never Updated */ "HockeyFeedbackListNeverUpdated" = "Never"; -/* Write Feedback Button Title */ -"HockeyFeedbackListButonWriteFeedback" = "Write Feedback"; +/* Provide Feedback Button Title */ +"HockeyFeedbackListButonWriteFeedback" = "Provide Feedback"; -/* Write Response Button Title */ -"HockeyFeedbackListButonWriteResponse" = "Write Response"; +/* Add a Response Button Title */ +"HockeyFeedbackListButonWriteResponse" = "Add a Response"; /* User Data Set Name Button Title */ "HockeyFeedbackListButonUserDataSetName" = "Set Your Name"; diff --git a/Resources/it.lproj/HockeySDK.strings b/Resources/it.lproj/HockeySDK.strings index cd541f40..38ad4f9b 100755 --- a/Resources/it.lproj/HockeySDK.strings +++ b/Resources/it.lproj/HockeySDK.strings @@ -138,11 +138,11 @@ /* Never Updated */ "HockeyFeedbackListNeverUpdated" = "Never"; -/* Write Feedback Button Title */ -"HockeyFeedbackListButonWriteFeedback" = "Write Feedback"; +/* Provide Feedback Button Title */ +"HockeyFeedbackListButonWriteFeedback" = "Provide Feedback"; -/* Write Response Button Title */ -"HockeyFeedbackListButonWriteResponse" = "Write Response"; +/* Add a Response Button Title */ +"HockeyFeedbackListButonWriteResponse" = "Add a Response"; /* User Data Set Name Button Title */ "HockeyFeedbackListButonUserDataSetName" = "Set Your Name"; diff --git a/Resources/ja.lproj/HockeySDK.strings b/Resources/ja.lproj/HockeySDK.strings index 32a595ba..727c74d0 100755 --- a/Resources/ja.lproj/HockeySDK.strings +++ b/Resources/ja.lproj/HockeySDK.strings @@ -138,11 +138,11 @@ /* Never Updated */ "HockeyFeedbackListNeverUpdated" = "Never"; -/* Write Feedback Button Title */ -"HockeyFeedbackListButonWriteFeedback" = "Write Feedback"; +/* Provide Feedback Button Title */ +"HockeyFeedbackListButonWriteFeedback" = "Provide Feedback"; -/* Write Response Button Title */ -"HockeyFeedbackListButonWriteResponse" = "Write Response"; +/* Add a Response Button Title */ +"HockeyFeedbackListButonWriteResponse" = "Add a Response"; /* User Data Set Name Button Title */ "HockeyFeedbackListButonUserDataSetName" = "Set Your Name"; diff --git a/Resources/nl.lproj/HockeySDK.strings b/Resources/nl.lproj/HockeySDK.strings index 5ab5b7a8..18db296c 100755 --- a/Resources/nl.lproj/HockeySDK.strings +++ b/Resources/nl.lproj/HockeySDK.strings @@ -138,11 +138,11 @@ /* Never Updated */ "HockeyFeedbackListNeverUpdated" = "Never"; -/* Write Feedback Button Title */ -"HockeyFeedbackListButonWriteFeedback" = "Write Feedback"; +/* Provide Feedback Button Title */ +"HockeyFeedbackListButonWriteFeedback" = "Provide Feedback"; -/* Write Response Button Title */ -"HockeyFeedbackListButonWriteResponse" = "Write Response"; +/* Add a Response Button Title */ +"HockeyFeedbackListButonWriteResponse" = "Add a Response"; /* User Data Set Name Button Title */ "HockeyFeedbackListButonUserDataSetName" = "Set Your Name"; diff --git a/Resources/pt-PT.lproj/HockeySDK.strings b/Resources/pt-PT.lproj/HockeySDK.strings index 5115aa91..a58a2e0d 100755 --- a/Resources/pt-PT.lproj/HockeySDK.strings +++ b/Resources/pt-PT.lproj/HockeySDK.strings @@ -138,11 +138,11 @@ /* Never Updated */ "HockeyFeedbackListNeverUpdated" = "Never"; -/* Write Feedback Button Title */ -"HockeyFeedbackListButonWriteFeedback" = "Write Feedback"; +/* Provide Feedback Button Title */ +"HockeyFeedbackListButonWriteFeedback" = "Provide Feedback"; -/* Write Response Button Title */ -"HockeyFeedbackListButonWriteResponse" = "Write Response"; +/* Add a Response Button Title */ +"HockeyFeedbackListButonWriteResponse" = "Add a Response"; /* User Data Set Name Button Title */ "HockeyFeedbackListButonUserDataSetName" = "Set Your Name"; diff --git a/Resources/pt.lproj/HockeySDK.strings b/Resources/pt.lproj/HockeySDK.strings index 38689eee..2e71290b 100755 --- a/Resources/pt.lproj/HockeySDK.strings +++ b/Resources/pt.lproj/HockeySDK.strings @@ -138,11 +138,11 @@ /* Never Updated */ "HockeyFeedbackListNeverUpdated" = "Never"; -/* Write Feedback Button Title */ -"HockeyFeedbackListButonWriteFeedback" = "Write Feedback"; +/* Provide Feedback Button Title */ +"HockeyFeedbackListButonWriteFeedback" = "Provide Feedback"; -/* Write Response Button Title */ -"HockeyFeedbackListButonWriteResponse" = "Write Response"; +/* Add a Response Button Title */ +"HockeyFeedbackListButonWriteResponse" = "Add a Response"; /* User Data Set Name Button Title */ "HockeyFeedbackListButonUserDataSetName" = "Set Your Name"; diff --git a/Resources/ru.lproj/HockeySDK.strings b/Resources/ru.lproj/HockeySDK.strings index 71407604..516e0127 100755 --- a/Resources/ru.lproj/HockeySDK.strings +++ b/Resources/ru.lproj/HockeySDK.strings @@ -138,11 +138,11 @@ /* Never Updated */ "HockeyFeedbackListNeverUpdated" = "Never"; -/* Write Feedback Button Title */ -"HockeyFeedbackListButonWriteFeedback" = "Write Feedback"; +/* Provide Feedback Button Title */ +"HockeyFeedbackListButonWriteFeedback" = "Provide Feedback"; -/* Write Response Button Title */ -"HockeyFeedbackListButonWriteResponse" = "Write Response"; +/* Add a Response Button Title */ +"HockeyFeedbackListButonWriteResponse" = "Add a Response"; /* User Data Set Name Button Title */ "HockeyFeedbackListButonUserDataSetName" = "Set Your Name"; diff --git a/Resources/sv.lproj/HockeySDK.strings b/Resources/sv.lproj/HockeySDK.strings index 659bed27..e4d07bde 100755 --- a/Resources/sv.lproj/HockeySDK.strings +++ b/Resources/sv.lproj/HockeySDK.strings @@ -138,11 +138,11 @@ /* Never Updated */ "HockeyFeedbackListNeverUpdated" = "Never"; -/* Write Feedback Button Title */ -"HockeyFeedbackListButonWriteFeedback" = "Write Feedback"; +/* Provide Feedback Button Title */ +"HockeyFeedbackListButonWriteFeedback" = "Provide Feedback"; -/* Write Response Button Title */ -"HockeyFeedbackListButonWriteResponse" = "Write Response"; +/* Add a Response Button Title */ +"HockeyFeedbackListButonWriteResponse" = "Add a Response"; /* User Data Set Name Button Title */ "HockeyFeedbackListButonUserDataSetName" = "Set Your Name"; diff --git a/Resources/tr.lproj/HockeySDK.strings b/Resources/tr.lproj/HockeySDK.strings index 20755b8b..356e66a6 100644 --- a/Resources/tr.lproj/HockeySDK.strings +++ b/Resources/tr.lproj/HockeySDK.strings @@ -138,11 +138,11 @@ /* Never Updated */ "HockeyFeedbackListNeverUpdated" = "Never"; -/* Write Feedback Button Title */ -"HockeyFeedbackListButonWriteFeedback" = "Write Feedback"; +/* Provide Feedback Button Title */ +"HockeyFeedbackListButonWriteFeedback" = "Provide Feedback"; -/* Write Response Button Title */ -"HockeyFeedbackListButonWriteResponse" = "Write Response"; +/* Add a Response Button Title */ +"HockeyFeedbackListButonWriteResponse" = "Add a Response"; /* User Data Set Name Button Title */ "HockeyFeedbackListButonUserDataSetName" = "Set Your Name"; diff --git a/Resources/zh_CN.lproj/HockeySDK.strings b/Resources/zh_CN.lproj/HockeySDK.strings index 7d13604f..6edb4c7c 100644 --- a/Resources/zh_CN.lproj/HockeySDK.strings +++ b/Resources/zh_CN.lproj/HockeySDK.strings @@ -138,11 +138,11 @@ /* Never Updated */ "HockeyFeedbackListNeverUpdated" = "Never"; -/* Write Feedback Button Title */ -"HockeyFeedbackListButonWriteFeedback" = "Write Feedback"; +/* Provide Feedback Button Title */ +"HockeyFeedbackListButonWriteFeedback" = "Provide Feedback"; -/* Write Response Button Title */ -"HockeyFeedbackListButonWriteResponse" = "Write Response"; +/* Add a Response Button Title */ +"HockeyFeedbackListButonWriteResponse" = "Add a Response"; /* User Data Set Name Button Title */ "HockeyFeedbackListButonUserDataSetName" = "Set Your Name"; diff --git a/Resources/zh_TW.lproj/HockeySDK.strings b/Resources/zh_TW.lproj/HockeySDK.strings index 32dc5623..8dde94bb 100644 --- a/Resources/zh_TW.lproj/HockeySDK.strings +++ b/Resources/zh_TW.lproj/HockeySDK.strings @@ -138,11 +138,11 @@ /* Never Updated */ "HockeyFeedbackListNeverUpdated" = "Never"; -/* Write Feedback Button Title */ -"HockeyFeedbackListButonWriteFeedback" = "Write Feedback"; +/* Provide Feedback Button Title */ +"HockeyFeedbackListButonWriteFeedback" = "Provide Feedback"; -/* Write Response Button Title */ -"HockeyFeedbackListButonWriteResponse" = "Write Response"; +/* Add a Response Button Title */ +"HockeyFeedbackListButonWriteResponse" = "Add a Response"; /* User Data Set Name Button Title */ "HockeyFeedbackListButonUserDataSetName" = "Set Your Name"; From 1b7d073998d65aca734fbdead50ee0de07fd70ca Mon Sep 17 00:00:00 2001 From: Andreas Linde Date: Sun, 7 Oct 2012 02:06:18 +0200 Subject: [PATCH 015/176] Fix requiring recursive header search due to subdirectory structure of modules --- Classes/CrashReports/BITCrashManager.h | 2 +- .../BITFeedbackComposeViewController.h | 1 - .../Feedback/BITFeedbackListViewController.h | 2 +- Classes/Feedback/BITFeedbackManager.h | 2 +- Classes/HockeySDK.h | 18 +++++++++--------- Classes/Update/BITUpdateManager.h | 2 +- Classes/Update/BITUpdateViewController.h | 2 +- 7 files changed, 14 insertions(+), 15 deletions(-) diff --git a/Classes/CrashReports/BITCrashManager.h b/Classes/CrashReports/BITCrashManager.h index 777bc711..1f4d955f 100644 --- a/Classes/CrashReports/BITCrashManager.h +++ b/Classes/CrashReports/BITCrashManager.h @@ -30,7 +30,7 @@ #import -#import "BITHockeyBaseManager.h" +#import "../Helper/BITHockeyBaseManager.h" // hockey crash manager status diff --git a/Classes/Feedback/BITFeedbackComposeViewController.h b/Classes/Feedback/BITFeedbackComposeViewController.h index 078a26aa..217db38b 100644 --- a/Classes/Feedback/BITFeedbackComposeViewController.h +++ b/Classes/Feedback/BITFeedbackComposeViewController.h @@ -28,7 +28,6 @@ #import -#import "BITHockeyBaseViewController.h" @interface BITFeedbackComposeViewController : UIViewController diff --git a/Classes/Feedback/BITFeedbackListViewController.h b/Classes/Feedback/BITFeedbackListViewController.h index 9ed216bd..a63addd7 100644 --- a/Classes/Feedback/BITFeedbackListViewController.h +++ b/Classes/Feedback/BITFeedbackListViewController.h @@ -29,7 +29,7 @@ #import -#import "BITHockeyBaseViewController.h" +#import "../Helper/BITHockeyBaseViewController.h" @interface BITFeedbackListViewController : BITHockeyBaseViewController { diff --git a/Classes/Feedback/BITFeedbackManager.h b/Classes/Feedback/BITFeedbackManager.h index fed6ee87..adfe8d3e 100644 --- a/Classes/Feedback/BITFeedbackManager.h +++ b/Classes/Feedback/BITFeedbackManager.h @@ -29,7 +29,7 @@ #import -#import "BITHockeyBaseManager.h" +#import "../Helper/BITHockeyBaseManager.h" #import "BITFeedbackListViewController.h" #import "BITFeedbackComposeViewController.h" diff --git a/Classes/HockeySDK.h b/Classes/HockeySDK.h index 2503fcdf..5215fdbb 100644 --- a/Classes/HockeySDK.h +++ b/Classes/HockeySDK.h @@ -33,18 +33,18 @@ #import "BITHockeyManager.h" #import "BITHockeyManagerDelegate.h" -#import "BITHockeyBaseManager.h" +#import "Helper/BITHockeyBaseManager.h" -#import "BITCrashManager.h" -#import "BITCrashManagerDelegate.h" +#import "CrashReports/BITCrashManager.h" +#import "CrashReports/BITCrashManagerDelegate.h" -#import "BITUpdateManager.h" -#import "BITUpdateManagerDelegate.h" -#import "BITUpdateViewController.h" +#import "Update/BITUpdateManager.h" +#import "Update/BITUpdateManagerDelegate.h" +#import "Update/BITUpdateViewController.h" -#import "BITFeedbackManager.h" -#import "BITFeedbackComposeViewController.h" -#import "BITFeedbackListViewController.h" +#import "Feedback/BITFeedbackManager.h" +#import "Feedback/BITFeedbackComposeViewController.h" +#import "Feedback/BITFeedbackListViewController.h" // Notification message which HockeyManager is listening to, to retry requesting updated from the server diff --git a/Classes/Update/BITUpdateManager.h b/Classes/Update/BITUpdateManager.h index 656f8d07..7355569d 100644 --- a/Classes/Update/BITUpdateManager.h +++ b/Classes/Update/BITUpdateManager.h @@ -30,7 +30,7 @@ #import -#import "BITHockeyBaseManager.h" +#import "../Helper/BITHockeyBaseManager.h" typedef enum { diff --git a/Classes/Update/BITUpdateViewController.h b/Classes/Update/BITUpdateViewController.h index cf131cc4..4f03a0d1 100644 --- a/Classes/Update/BITUpdateViewController.h +++ b/Classes/Update/BITUpdateViewController.h @@ -30,7 +30,7 @@ #import -#import "BITHockeyBaseViewController.h" +#import "../Helper/BITHockeyBaseViewController.h" @class PSStoreButton; From 4911af849c78ecfe8078745687ef900e2e263e50 Mon Sep 17 00:00:00 2001 From: Andreas Linde Date: Sun, 7 Oct 2012 13:14:09 +0200 Subject: [PATCH 016/176] Improve Feedbacklist updates and sending of new messages - Update feedback list reloading actions depending on loading status - Reload feedback list from network if last request is older than 30 seconds when appearing - Queue submitting message if there is another network request already in progress --- .../Feedback/BITFeedbackListViewController.m | 39 ++++++++++++++----- Classes/Feedback/BITFeedbackManager.h | 7 ++++ Classes/Feedback/BITFeedbackManager.m | 24 +++++++++--- Classes/Feedback/BITFeedbackManagerPrivate.h | 3 ++ Classes/HockeySDK.h | 3 -- 5 files changed, 59 insertions(+), 17 deletions(-) diff --git a/Classes/Feedback/BITFeedbackListViewController.m b/Classes/Feedback/BITFeedbackListViewController.m index 1ccd8942..8a586149 100644 --- a/Classes/Feedback/BITFeedbackListViewController.m +++ b/Classes/Feedback/BITFeedbackListViewController.m @@ -73,7 +73,8 @@ - (id)init { - (void)dealloc { - [[NSNotificationCenter defaultCenter] removeObserver:self name:BITHockeyFeedbackMessagesUpdated object:nil]; + [[NSNotificationCenter defaultCenter] removeObserver:self name:BITHockeyFeedbackMessagesLoadingStarted object:nil]; + [[NSNotificationCenter defaultCenter] removeObserver:self name:BITHockeyFeedbackMessagesLoadingFinished object:nil]; [_lastUpdateDateFormatter release]; _lastUpdateDateFormatter = nil; @@ -85,10 +86,15 @@ - (void)dealloc { - (void)viewDidLoad { [super viewDidLoad]; - + + [[NSNotificationCenter defaultCenter] addObserver:self + selector:@selector(startLoadingIndicator) + name:BITHockeyFeedbackMessagesLoadingStarted + object:nil]; + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(updateList) - name:BITHockeyFeedbackMessagesUpdated + name:BITHockeyFeedbackMessagesLoadingFinished object:nil]; self.title = BITHockeyLocalizedString(@"HockeyFeedbackListTitle"); @@ -113,11 +119,27 @@ - (void)viewDidLoad { } } -- (void)reloadList { +- (void)startLoadingIndicator { id refreshClass = NSClassFromString(@"UIRefreshControl"); if (refreshClass) { [self.refreshControl beginRefreshing]; + } else { + self.navigationItem.rightBarButtonItem.enabled = NO; } +} + +- (void)stopLoadingIndicator { + id refreshClass = NSClassFromString(@"UIRefreshControl"); + if (refreshClass) { + [self.refreshControl endRefreshing]; + } else { + self.navigationItem.rightBarButtonItem.enabled = YES; + } +} + +- (void)reloadList { + [self startLoadingIndicator]; + [self.manager updateMessagesList]; } @@ -125,10 +147,7 @@ - (void)updateList { CGSize contentSize = self.tableView.contentSize; CGPoint contentOffset = self.tableView.contentOffset; - id refreshClass = NSClassFromString(@"UIRefreshControl"); - if (refreshClass) { - [self.refreshControl endRefreshing]; - } + [self stopLoadingIndicator]; [self.tableView reloadData]; if (self.tableView.contentSize.height > contentSize.height) @@ -140,9 +159,11 @@ - (void)updateList { - (void)viewWillAppear:(BOOL)animated { self.manager.currentFeedbackListViewController = self; - [super viewWillAppear:animated]; + [self.manager updateMessagesListIfRequired]; [self.tableView reloadData]; + + [super viewWillAppear:animated]; } - (void)viewWillDisappear:(BOOL)animated { diff --git a/Classes/Feedback/BITFeedbackManager.h b/Classes/Feedback/BITFeedbackManager.h index adfe8d3e..4e1bb6c8 100644 --- a/Classes/Feedback/BITFeedbackManager.h +++ b/Classes/Feedback/BITFeedbackManager.h @@ -34,6 +34,13 @@ #import "BITFeedbackComposeViewController.h" +// Notification message which tells that loading messages finished +#define BITHockeyFeedbackMessagesLoadingStarted @"BITHockeyFeedbackMessagesLoadingStarted" + +// Notification message which tells that loading messages finished +#define BITHockeyFeedbackMessagesLoadingFinished @"BITHockeyFeedbackMessagesLoadingFinished" + + typedef enum { BITFeedbackUserDataElementDontShow = 0, // don't ask for this user data element at all BITFeedbackUserDataElementOptional = 1, // the user may provide it, but does not have to diff --git a/Classes/Feedback/BITFeedbackManager.m b/Classes/Feedback/BITFeedbackManager.m index a3fed49f..9e338335 100644 --- a/Classes/Feedback/BITFeedbackManager.m +++ b/Classes/Feedback/BITFeedbackManager.m @@ -75,7 +75,7 @@ - (id)init { _incomingMessagesAlertShowing = NO; _lastCheck = nil; _token = nil; - + self.feedbackList = [NSMutableArray array]; _fileManager = [[NSFileManager alloc] init]; @@ -184,6 +184,13 @@ - (void)updateMessagesList { } } +- (void)updateMessagesListIfRequired { + double now = [[NSDate date] timeIntervalSince1970]; + if ((now - [_lastCheck timeIntervalSince1970] > 30)) { + [self updateMessagesList]; + } +} + - (void)updateAppDefinedUserData { if ([BITHockeyManager sharedHockeyManager].delegate && [[BITHockeyManager sharedHockeyManager].delegate respondsToSelector:@selector(userNameForHockeyManager:componentManager:)]) { @@ -274,7 +281,7 @@ - (void)loadMessages { [self sortFeedbackList]; // inform the UI to update its data in case the list is already showing - [[NSNotificationCenter defaultCenter] postNotificationName:BITHockeyFeedbackMessagesUpdated object:nil]; + [[NSNotificationCenter defaultCenter] postNotificationName:BITHockeyFeedbackMessagesLoadingFinished object:nil]; } [unarchiver finishDecoding]; @@ -557,7 +564,9 @@ - (void)sendNetworkRequestWithHTTPMethod:(NSString *)httpMethod withText:(NSStri NSString *boundary = @"----FOO"; _networkRequestInProgress = YES; - + // inform the UI to update its data in case the list is already showing + [[NSNotificationCenter defaultCenter] postNotificationName:BITHockeyFeedbackMessagesLoadingStarted object:nil]; + NSString *tokenParameter = @""; if ([self token]) { tokenParameter = [NSString stringWithFormat:@"/%@", [self token]]; @@ -658,11 +667,16 @@ - (void)fetchMessageUpdates { withText:nil completionHandler:^(NSError *err){ // inform the UI to update its data in case the list is already showing - [[NSNotificationCenter defaultCenter] postNotificationName:BITHockeyFeedbackMessagesUpdated object:nil]; + [[NSNotificationCenter defaultCenter] postNotificationName:BITHockeyFeedbackMessagesLoadingFinished object:nil]; }]; } - (void)submitPendingMessages { + if (_networkRequestInProgress) { + [self performSelector:@selector(submitPendingMessages) withObject:nil afterDelay:2.0f]; + return; + } + // app defined user data may have changed, update it [self updateAppDefinedUserData]; @@ -693,7 +707,7 @@ - (void)submitPendingMessages { } // inform the UI to update its data in case the list is already showing - [[NSNotificationCenter defaultCenter] postNotificationName:BITHockeyFeedbackMessagesUpdated object:nil]; + [[NSNotificationCenter defaultCenter] postNotificationName:BITHockeyFeedbackMessagesLoadingFinished object:nil]; }]; } } diff --git a/Classes/Feedback/BITFeedbackManagerPrivate.h b/Classes/Feedback/BITFeedbackManagerPrivate.h index c789549c..0e04657d 100644 --- a/Classes/Feedback/BITFeedbackManagerPrivate.h +++ b/Classes/Feedback/BITFeedbackManagerPrivate.h @@ -56,6 +56,9 @@ // load new messages from the server - (void)updateMessagesList; +// load new messages from the server if the last request is too long ago +- (void)updateMessagesListIfRequired; + - (NSUInteger)numberOfMessages; - (BITFeedbackMessage *)messageAtIndex:(NSUInteger)index; diff --git a/Classes/HockeySDK.h b/Classes/HockeySDK.h index 5215fdbb..5c9cc218 100644 --- a/Classes/HockeySDK.h +++ b/Classes/HockeySDK.h @@ -50,9 +50,6 @@ // Notification message which HockeyManager is listening to, to retry requesting updated from the server #define BITHockeyNetworkDidBecomeReachableNotification @"BITHockeyNetworkDidBecomeReachable" -// Notification message which tells that loading messages finished -#define BITHockeyFeedbackMessagesUpdated @"BITHockeyFeedbackMessagesUpdated" - // hockey api error domain typedef enum { From 98ce579f40f792f0ce82c3a851afc5d4214fa34e Mon Sep 17 00:00:00 2001 From: Andreas Linde Date: Sun, 7 Oct 2012 13:58:24 +0200 Subject: [PATCH 017/176] Make subdirectory structure build when used as sub project --- Classes/HockeySDK.h | 2 - Support/HockeySDK.xcodeproj/project.pbxproj | 46 +++++++++++++-------- 2 files changed, 28 insertions(+), 20 deletions(-) diff --git a/Classes/HockeySDK.h b/Classes/HockeySDK.h index 5c9cc218..96a13ef1 100644 --- a/Classes/HockeySDK.h +++ b/Classes/HockeySDK.h @@ -33,8 +33,6 @@ #import "BITHockeyManager.h" #import "BITHockeyManagerDelegate.h" -#import "Helper/BITHockeyBaseManager.h" - #import "CrashReports/BITCrashManager.h" #import "CrashReports/BITCrashManagerDelegate.h" diff --git a/Support/HockeySDK.xcodeproj/project.pbxproj b/Support/HockeySDK.xcodeproj/project.pbxproj index de3fadd9..26b04297 100644 --- a/Support/HockeySDK.xcodeproj/project.pbxproj +++ b/Support/HockeySDK.xcodeproj/project.pbxproj @@ -42,7 +42,7 @@ 1E49A44B1612223B00463151 /* BITFeedbackListViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 1E49A4321612223B00463151 /* BITFeedbackListViewController.m */; }; 1E49A44C1612223B00463151 /* BITFeedbackManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E49A4331612223B00463151 /* BITFeedbackManager.h */; }; 1E49A44D1612223B00463151 /* BITFeedbackManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E49A4331612223B00463151 /* BITFeedbackManager.h */; }; - 1E49A44E1612223B00463151 /* BITFeedbackManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E49A4331612223B00463151 /* BITFeedbackManager.h */; }; + 1E49A44E1612223B00463151 /* BITFeedbackManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E49A4331612223B00463151 /* BITFeedbackManager.h */; settings = {ATTRIBUTES = (Public, ); }; }; 1E49A44F1612223B00463151 /* BITFeedbackManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 1E49A4341612223B00463151 /* BITFeedbackManager.m */; }; 1E49A4501612223B00463151 /* BITFeedbackManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 1E49A4341612223B00463151 /* BITFeedbackManager.m */; }; 1E49A4511612223B00463151 /* BITFeedbackManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 1E49A4341612223B00463151 /* BITFeedbackManager.m */; }; @@ -69,13 +69,13 @@ 1E49A4701612226D00463151 /* BITAppVersionMetaInfo.m in Sources */ = {isa = PBXBuildFile; fileRef = 1E49A4631612226D00463151 /* BITAppVersionMetaInfo.m */; }; 1E49A4711612226D00463151 /* BITUpdateManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E49A4641612226D00463151 /* BITUpdateManager.h */; }; 1E49A4721612226D00463151 /* BITUpdateManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E49A4641612226D00463151 /* BITUpdateManager.h */; }; - 1E49A4731612226D00463151 /* BITUpdateManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E49A4641612226D00463151 /* BITUpdateManager.h */; }; + 1E49A4731612226D00463151 /* BITUpdateManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E49A4641612226D00463151 /* BITUpdateManager.h */; settings = {ATTRIBUTES = (Public, ); }; }; 1E49A4741612226D00463151 /* BITUpdateManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 1E49A4651612226D00463151 /* BITUpdateManager.m */; }; 1E49A4751612226D00463151 /* BITUpdateManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 1E49A4651612226D00463151 /* BITUpdateManager.m */; }; 1E49A4761612226D00463151 /* BITUpdateManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 1E49A4651612226D00463151 /* BITUpdateManager.m */; }; 1E49A4771612226D00463151 /* BITUpdateManagerDelegate.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E49A4661612226D00463151 /* BITUpdateManagerDelegate.h */; }; 1E49A4781612226D00463151 /* BITUpdateManagerDelegate.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E49A4661612226D00463151 /* BITUpdateManagerDelegate.h */; }; - 1E49A4791612226D00463151 /* BITUpdateManagerDelegate.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E49A4661612226D00463151 /* BITUpdateManagerDelegate.h */; }; + 1E49A4791612226D00463151 /* BITUpdateManagerDelegate.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E49A4661612226D00463151 /* BITUpdateManagerDelegate.h */; settings = {ATTRIBUTES = (Public, ); }; }; 1E49A47A1612226D00463151 /* BITUpdateManagerPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E49A4671612226D00463151 /* BITUpdateManagerPrivate.h */; }; 1E49A47B1612226D00463151 /* BITUpdateManagerPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E49A4671612226D00463151 /* BITUpdateManagerPrivate.h */; }; 1E49A47C1612226D00463151 /* BITUpdateManagerPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E49A4671612226D00463151 /* BITUpdateManagerPrivate.h */; }; @@ -90,13 +90,13 @@ 1E49A4851612226D00463151 /* BITUpdateViewControllerPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E49A46A1612226D00463151 /* BITUpdateViewControllerPrivate.h */; }; 1E49A48D1612228800463151 /* BITCrashManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E49A4871612228800463151 /* BITCrashManager.h */; }; 1E49A48E1612228800463151 /* BITCrashManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E49A4871612228800463151 /* BITCrashManager.h */; }; - 1E49A48F1612228800463151 /* BITCrashManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E49A4871612228800463151 /* BITCrashManager.h */; }; + 1E49A48F1612228800463151 /* BITCrashManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E49A4871612228800463151 /* BITCrashManager.h */; settings = {ATTRIBUTES = (Public, ); }; }; 1E49A4901612228800463151 /* BITCrashManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 1E49A4881612228800463151 /* BITCrashManager.m */; }; 1E49A4911612228800463151 /* BITCrashManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 1E49A4881612228800463151 /* BITCrashManager.m */; }; 1E49A4921612228800463151 /* BITCrashManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 1E49A4881612228800463151 /* BITCrashManager.m */; }; 1E49A4931612228800463151 /* BITCrashManagerDelegate.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E49A4891612228800463151 /* BITCrashManagerDelegate.h */; }; 1E49A4941612228800463151 /* BITCrashManagerDelegate.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E49A4891612228800463151 /* BITCrashManagerDelegate.h */; }; - 1E49A4951612228800463151 /* BITCrashManagerDelegate.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E49A4891612228800463151 /* BITCrashManagerDelegate.h */; }; + 1E49A4951612228800463151 /* BITCrashManagerDelegate.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E49A4891612228800463151 /* BITCrashManagerDelegate.h */; settings = {ATTRIBUTES = (Public, ); }; }; 1E49A4961612228800463151 /* BITCrashManagerPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E49A48A1612228800463151 /* BITCrashManagerPrivate.h */; }; 1E49A4971612228800463151 /* BITCrashManagerPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E49A48A1612228800463151 /* BITCrashManagerPrivate.h */; }; 1E49A4981612228800463151 /* BITCrashManagerPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E49A48A1612228800463151 /* BITCrashManagerPrivate.h */; }; @@ -151,18 +151,24 @@ 1E49A4D9161222D400463151 /* HockeySDKPrivate.m in Sources */ = {isa = PBXBuildFile; fileRef = 1E49A4D5161222D400463151 /* HockeySDKPrivate.m */; }; 1E49A4DA161222D400463151 /* HockeySDKPrivate.m in Sources */ = {isa = PBXBuildFile; fileRef = 1E49A4D5161222D400463151 /* HockeySDKPrivate.m */; }; 1E49A4DB161222D400463151 /* HockeySDKPrivate.m in Sources */ = {isa = PBXBuildFile; fileRef = 1E49A4D5161222D400463151 /* HockeySDKPrivate.m */; }; + 1E4F61D51621A3620033EFC5 /* BITCrashManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E49A4871612228800463151 /* BITCrashManager.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 1E4F61D71621A3660033EFC5 /* BITCrashManagerDelegate.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E49A4891612228800463151 /* BITCrashManagerDelegate.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 1E4F61DC1621A3830033EFC5 /* BITFeedbackManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E49A4331612223B00463151 /* BITFeedbackManager.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 1E4F61DD1621A39B0033EFC5 /* BITUpdateManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E49A4641612226D00463151 /* BITUpdateManager.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 1E4F61DE1621A39E0033EFC5 /* BITUpdateManagerDelegate.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E49A4661612226D00463151 /* BITUpdateManagerDelegate.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 1E4F61DF1621A3CA0033EFC5 /* BITHockeyManager.h in Headers */ = {isa = PBXBuildFile; fileRef = E41EB465148D7BF50015DEDC /* BITHockeyManager.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 1E4F61E01621A3CD0033EFC5 /* BITHockeyManagerDelegate.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E5955FA15B7877A00A03429 /* BITHockeyManagerDelegate.h */; settings = {ATTRIBUTES = (Public, ); }; }; 1E59545D15B6C41300A03429 /* BITHockeyManager.m in Sources */ = {isa = PBXBuildFile; fileRef = E41EB466148D7BF50015DEDC /* BITHockeyManager.m */; }; 1E59546615B6C41300A03429 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E400561D148D79B500EB22B9 /* Foundation.framework */; }; 1E59546715B6C41300A03429 /* CrashReporter.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E41EB48B148D7C4E0015DEDC /* CrashReporter.framework */; }; 1E59546E15B6C41300A03429 /* BITHockeyManager.h in Headers */ = {isa = PBXBuildFile; fileRef = E41EB465148D7BF50015DEDC /* BITHockeyManager.h */; }; 1E59547815B6C41300A03429 /* HockeySDK.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E71509A15B5C76F004E88FF /* HockeySDK.h */; settings = {ATTRIBUTES = (); }; }; 1E59548315B6C4EF00A03429 /* HockeySDK.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E71509A15B5C76F004E88FF /* HockeySDK.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 1E59548515B6C4FB00A03429 /* BITHockeyManager.h in Headers */ = {isa = PBXBuildFile; fileRef = E41EB465148D7BF50015DEDC /* BITHockeyManager.h */; settings = {ATTRIBUTES = (Public, ); }; }; 1E5954D315B6F24A00A03429 /* BITHockeyManager.m in Sources */ = {isa = PBXBuildFile; fileRef = E41EB466148D7BF50015DEDC /* BITHockeyManager.m */; }; 1E5954DC15B6F24A00A03429 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E400561D148D79B500EB22B9 /* Foundation.framework */; }; 1E5954DD15B6F24A00A03429 /* CrashReporter.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E41EB48B148D7C4E0015DEDC /* CrashReporter.framework */; }; - 1E59559A15B6FDA500A03429 /* BITHockeyManager.h in Headers */ = {isa = PBXBuildFile; fileRef = E41EB465148D7BF50015DEDC /* BITHockeyManager.h */; settings = {ATTRIBUTES = (); }; }; - 1E59559B15B6FDA500A03429 /* HockeySDK.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E71509A15B5C76F004E88FF /* HockeySDK.h */; settings = {ATTRIBUTES = (); }; }; + 1E59559A15B6FDA500A03429 /* BITHockeyManager.h in Headers */ = {isa = PBXBuildFile; fileRef = E41EB465148D7BF50015DEDC /* BITHockeyManager.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 1E59559B15B6FDA500A03429 /* HockeySDK.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E71509A15B5C76F004E88FF /* HockeySDK.h */; settings = {ATTRIBUTES = (Public, ); }; }; 1E5955C615B71C8600A03429 /* authorize_denied.png in Resources */ = {isa = PBXBuildFile; fileRef = 1E5955BB15B71C8600A03429 /* authorize_denied.png */; }; 1E5955C715B71C8600A03429 /* authorize_denied@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 1E5955BC15B71C8600A03429 /* authorize_denied@2x.png */; }; 1E5955C815B71C8600A03429 /* authorize_request.png in Resources */ = {isa = PBXBuildFile; fileRef = 1E5955BD15B71C8600A03429 /* authorize_request.png */; }; @@ -174,8 +180,7 @@ 1E5955D015B71C8600A03429 /* IconGradient@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 1E5955C515B71C8600A03429 /* IconGradient@2x.png */; }; 1E5955FB15B7877B00A03429 /* BITHockeyManagerDelegate.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E5955FA15B7877A00A03429 /* BITHockeyManagerDelegate.h */; }; 1E5955FC15B7877B00A03429 /* BITHockeyManagerDelegate.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E5955FA15B7877A00A03429 /* BITHockeyManagerDelegate.h */; }; - 1E5955FD15B7877B00A03429 /* BITHockeyManagerDelegate.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E5955FA15B7877A00A03429 /* BITHockeyManagerDelegate.h */; }; - 1E5955FE15B787D600A03429 /* BITHockeyManagerDelegate.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E5955FA15B7877A00A03429 /* BITHockeyManagerDelegate.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 1E5955FD15B7877B00A03429 /* BITHockeyManagerDelegate.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E5955FA15B7877A00A03429 /* BITHockeyManagerDelegate.h */; settings = {ATTRIBUTES = (Public, ); }; }; 1E71509B15B5C76F004E88FF /* HockeySDK.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E71509A15B5C76F004E88FF /* HockeySDK.h */; settings = {ATTRIBUTES = (); }; }; 1EC69F5E1615001500808FD9 /* BITHockeyManagerPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 1EC69F5D1615001500808FD9 /* BITHockeyManagerPrivate.h */; }; 1EC69F5F1615001500808FD9 /* BITHockeyManagerPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 1EC69F5D1615001500808FD9 /* BITHockeyManagerPrivate.h */; }; @@ -520,8 +525,13 @@ buildActionMask = 2147483647; files = ( 1E59548315B6C4EF00A03429 /* HockeySDK.h in Headers */, - 1E59548515B6C4FB00A03429 /* BITHockeyManager.h in Headers */, - 1E5955FE15B787D600A03429 /* BITHockeyManagerDelegate.h in Headers */, + 1E4F61DF1621A3CA0033EFC5 /* BITHockeyManager.h in Headers */, + 1E4F61E01621A3CD0033EFC5 /* BITHockeyManagerDelegate.h in Headers */, + 1E4F61DD1621A39B0033EFC5 /* BITUpdateManager.h in Headers */, + 1E4F61DE1621A39E0033EFC5 /* BITUpdateManagerDelegate.h in Headers */, + 1E4F61D51621A3620033EFC5 /* BITCrashManager.h in Headers */, + 1E4F61D71621A3660033EFC5 /* BITCrashManagerDelegate.h in Headers */, + 1E4F61DC1621A3830033EFC5 /* BITFeedbackManager.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -565,24 +575,24 @@ isa = PBXHeadersBuildPhase; buildActionMask = 2147483647; files = ( - 1E59559A15B6FDA500A03429 /* BITHockeyManager.h in Headers */, 1E59559B15B6FDA500A03429 /* HockeySDK.h in Headers */, + 1E59559A15B6FDA500A03429 /* BITHockeyManager.h in Headers */, 1E5955FD15B7877B00A03429 /* BITHockeyManagerDelegate.h in Headers */, + 1E49A48F1612228800463151 /* BITCrashManager.h in Headers */, + 1E49A4951612228800463151 /* BITCrashManagerDelegate.h in Headers */, + 1E49A4731612226D00463151 /* BITUpdateManager.h in Headers */, + 1E49A4791612226D00463151 /* BITUpdateManagerDelegate.h in Headers */, + 1E49A44E1612223B00463151 /* BITFeedbackManager.h in Headers */, 1E49A43C1612223B00463151 /* BITFeedbackComposeViewController.h in Headers */, 1E49A4421612223B00463151 /* BITFeedbackListViewCell.h in Headers */, 1E49A4481612223B00463151 /* BITFeedbackListViewController.h in Headers */, - 1E49A44E1612223B00463151 /* BITFeedbackManager.h in Headers */, 1E49A4541612223B00463151 /* BITFeedbackManagerPrivate.h in Headers */, 1E49A4571612223B00463151 /* BITFeedbackMessage.h in Headers */, 1E49A45D1612223B00463151 /* BITFeedbackUserDataViewController.h in Headers */, 1E49A46D1612226D00463151 /* BITAppVersionMetaInfo.h in Headers */, - 1E49A4731612226D00463151 /* BITUpdateManager.h in Headers */, - 1E49A4791612226D00463151 /* BITUpdateManagerDelegate.h in Headers */, 1E49A47C1612226D00463151 /* BITUpdateManagerPrivate.h in Headers */, 1E49A47F1612226D00463151 /* BITUpdateViewController.h in Headers */, 1E49A4851612226D00463151 /* BITUpdateViewControllerPrivate.h in Headers */, - 1E49A48F1612228800463151 /* BITCrashManager.h in Headers */, - 1E49A4951612228800463151 /* BITCrashManagerDelegate.h in Headers */, 1E49A4981612228800463151 /* BITCrashManagerPrivate.h in Headers */, 1E49A49B1612228800463151 /* BITCrashReportTextFormatter.h in Headers */, 1E49A4AF161222B900463151 /* BITHockeyBaseManager.h in Headers */, From d3ece9f2b1b39ef7e265b125fe4eb68854b7777e Mon Sep 17 00:00:00 2001 From: Andreas Linde Date: Sun, 7 Oct 2012 14:29:55 +0200 Subject: [PATCH 018/176] Set info.plist on project level to include it also in the bundle target This way we can identify the SDK version by parsing the info.plist in the resource bundle --- Support/HockeySDK.xcodeproj/project.pbxproj | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Support/HockeySDK.xcodeproj/project.pbxproj b/Support/HockeySDK.xcodeproj/project.pbxproj index 26b04297..bb8a4917 100644 --- a/Support/HockeySDK.xcodeproj/project.pbxproj +++ b/Support/HockeySDK.xcodeproj/project.pbxproj @@ -1009,7 +1009,6 @@ "$(inherited)", "\"$(SRCROOT)/../Vendor\"", ); - INFOPLIST_FILE = "../Resources/HockeySDK-Info.plist"; INSTALL_PATH = "$(HOME)/Library/Frameworks"; MACOSX_DEPLOYMENT_TARGET = 10.5; ONLY_ACTIVE_ARCH = NO; @@ -1043,7 +1042,6 @@ "$(inherited)", "\"$(SRCROOT)/../Vendor\"", ); - INFOPLIST_FILE = "../Resources/HockeySDK-Info.plist"; INSTALL_PATH = "$(HOME)/Library/Frameworks"; MACOSX_DEPLOYMENT_TARGET = 10.5; PRODUCT_NAME = "$(TARGET_NAME)"; @@ -1179,6 +1177,7 @@ GCC_WARN_STRICT_SELECTOR_MATCH = YES; GCC_WARN_UNDECLARED_SELECTOR = YES; GCC_WARN_UNUSED_VARIABLE = YES; + INFOPLIST_FILE = "../Resources/HockeySDK-Info.plist"; IPHONEOS_DEPLOYMENT_TARGET = 4.0; MACOSX_DEPLOYMENT_TARGET = 10.5; RUN_CLANG_STATIC_ANALYZER = YES; @@ -1207,6 +1206,7 @@ GCC_WARN_STRICT_SELECTOR_MATCH = YES; GCC_WARN_UNDECLARED_SELECTOR = YES; GCC_WARN_UNUSED_VARIABLE = YES; + INFOPLIST_FILE = "../Resources/HockeySDK-Info.plist"; IPHONEOS_DEPLOYMENT_TARGET = 4.0; MACOSX_DEPLOYMENT_TARGET = 10.5; RUN_CLANG_STATIC_ANALYZER = YES; From 9b8f51fe5fbc3b5995e1bdefbee20a2c364a1740 Mon Sep 17 00:00:00 2001 From: Andreas Linde Date: Sun, 7 Oct 2012 21:49:47 +0200 Subject: [PATCH 019/176] Restructure project targets and binary distribution target - Use one common static lib target - create embeddedFramework as binary distribution including docset in one zip - Add HockeySDK.xcconfig for easier build setting setup - Move everything into a single directory, too many problems making binary and subproject work without requing recursive header search paths - Documentation update pending --- .gitignore | 3 +- Classes/{Update => }/BITAppVersionMetaInfo.h | 0 Classes/{Update => }/BITAppVersionMetaInfo.m | 0 Classes/{CrashReports => }/BITCrashManager.h | 2 +- Classes/{CrashReports => }/BITCrashManager.m | 0 .../BITCrashManagerDelegate.h | 0 .../BITCrashManagerPrivate.h | 0 .../BITCrashReportTextFormatter.h | 0 .../BITCrashReportTextFormatter.m | 0 .../BITFeedbackComposeViewController.h | 0 .../BITFeedbackComposeViewController.m | 0 .../{Feedback => }/BITFeedbackListViewCell.h | 0 .../{Feedback => }/BITFeedbackListViewCell.m | 0 .../BITFeedbackListViewController.h | 2 +- .../BITFeedbackListViewController.m | 0 Classes/{Feedback => }/BITFeedbackManager.h | 2 +- Classes/{Feedback => }/BITFeedbackManager.m | 0 .../BITFeedbackManagerPrivate.h | 0 Classes/{Feedback => }/BITFeedbackMessage.h | 0 Classes/{Feedback => }/BITFeedbackMessage.m | 0 .../BITFeedbackUserDataViewController.h | 0 .../BITFeedbackUserDataViewController.m | 0 Classes/{Helper => }/BITHockeyBaseManager.h | 0 Classes/{Helper => }/BITHockeyBaseManager.m | 0 .../BITHockeyBaseManagerPrivate.h | 0 .../BITHockeyBaseViewController.h | 0 .../BITHockeyBaseViewController.m | 0 Classes/{Helper => }/BITHockeyHelper.h | 0 Classes/{Helper => }/BITHockeyHelper.m | 0 Classes/{Update => }/BITUpdateManager.h | 2 +- Classes/{Update => }/BITUpdateManager.m | 0 .../{Update => }/BITUpdateManagerDelegate.h | 0 .../{Update => }/BITUpdateManagerPrivate.h | 0 .../{Update => }/BITUpdateViewController.h | 2 +- .../{Update => }/BITUpdateViewController.m | 0 .../BITUpdateViewControllerPrivate.h | 0 Classes/HockeySDK.h | 16 +- Classes/{Helper => }/HockeySDKPrivate.h | 0 Classes/{Helper => }/HockeySDKPrivate.m | 0 Classes/{Helper => }/PSAppStoreHeader.h | 0 Classes/{Helper => }/PSAppStoreHeader.m | 0 Classes/{Helper => }/PSStoreButton.h | 0 Classes/{Helper => }/PSStoreButton.m | 0 Classes/{Helper => }/PSWebTableViewCell.h | 0 Classes/{Helper => }/PSWebTableViewCell.m | 0 LICENSE.txt => LICENSE | 0 Support/HockeySDK.xcconfig | 2 + Support/HockeySDK.xcodeproj/project.pbxproj | 726 +++--------------- Support/buildnumber.xcconfig | 2 + 49 files changed, 137 insertions(+), 622 deletions(-) rename Classes/{Update => }/BITAppVersionMetaInfo.h (100%) rename Classes/{Update => }/BITAppVersionMetaInfo.m (100%) rename Classes/{CrashReports => }/BITCrashManager.h (99%) rename Classes/{CrashReports => }/BITCrashManager.m (100%) rename Classes/{CrashReports => }/BITCrashManagerDelegate.h (100%) rename Classes/{CrashReports => }/BITCrashManagerPrivate.h (100%) rename Classes/{CrashReports => }/BITCrashReportTextFormatter.h (100%) rename Classes/{CrashReports => }/BITCrashReportTextFormatter.m (100%) rename Classes/{Feedback => }/BITFeedbackComposeViewController.h (100%) rename Classes/{Feedback => }/BITFeedbackComposeViewController.m (100%) rename Classes/{Feedback => }/BITFeedbackListViewCell.h (100%) rename Classes/{Feedback => }/BITFeedbackListViewCell.m (100%) rename Classes/{Feedback => }/BITFeedbackListViewController.h (96%) rename Classes/{Feedback => }/BITFeedbackListViewController.m (100%) rename Classes/{Feedback => }/BITFeedbackManager.h (98%) rename Classes/{Feedback => }/BITFeedbackManager.m (100%) rename Classes/{Feedback => }/BITFeedbackManagerPrivate.h (100%) rename Classes/{Feedback => }/BITFeedbackMessage.h (100%) rename Classes/{Feedback => }/BITFeedbackMessage.m (100%) rename Classes/{Feedback => }/BITFeedbackUserDataViewController.h (100%) rename Classes/{Feedback => }/BITFeedbackUserDataViewController.m (100%) rename Classes/{Helper => }/BITHockeyBaseManager.h (100%) rename Classes/{Helper => }/BITHockeyBaseManager.m (100%) rename Classes/{Helper => }/BITHockeyBaseManagerPrivate.h (100%) rename Classes/{Helper => }/BITHockeyBaseViewController.h (100%) rename Classes/{Helper => }/BITHockeyBaseViewController.m (100%) rename Classes/{Helper => }/BITHockeyHelper.h (100%) rename Classes/{Helper => }/BITHockeyHelper.m (100%) rename Classes/{Update => }/BITUpdateManager.h (99%) rename Classes/{Update => }/BITUpdateManager.m (100%) rename Classes/{Update => }/BITUpdateManagerDelegate.h (100%) rename Classes/{Update => }/BITUpdateManagerPrivate.h (100%) rename Classes/{Update => }/BITUpdateViewController.h (96%) rename Classes/{Update => }/BITUpdateViewController.m (100%) rename Classes/{Update => }/BITUpdateViewControllerPrivate.h (100%) rename Classes/{Helper => }/HockeySDKPrivate.h (100%) rename Classes/{Helper => }/HockeySDKPrivate.m (100%) rename Classes/{Helper => }/PSAppStoreHeader.h (100%) rename Classes/{Helper => }/PSAppStoreHeader.m (100%) rename Classes/{Helper => }/PSStoreButton.h (100%) rename Classes/{Helper => }/PSStoreButton.m (100%) rename Classes/{Helper => }/PSWebTableViewCell.h (100%) rename Classes/{Helper => }/PSWebTableViewCell.m (100%) rename LICENSE.txt => LICENSE (100%) create mode 100644 Support/HockeySDK.xcconfig diff --git a/.gitignore b/.gitignore index a8579baa..d0f3b76e 100644 --- a/.gitignore +++ b/.gitignore @@ -19,4 +19,5 @@ profile *~.nib profile -documentation/ \ No newline at end of file +documentation/ +Products/ \ No newline at end of file diff --git a/Classes/Update/BITAppVersionMetaInfo.h b/Classes/BITAppVersionMetaInfo.h similarity index 100% rename from Classes/Update/BITAppVersionMetaInfo.h rename to Classes/BITAppVersionMetaInfo.h diff --git a/Classes/Update/BITAppVersionMetaInfo.m b/Classes/BITAppVersionMetaInfo.m similarity index 100% rename from Classes/Update/BITAppVersionMetaInfo.m rename to Classes/BITAppVersionMetaInfo.m diff --git a/Classes/CrashReports/BITCrashManager.h b/Classes/BITCrashManager.h similarity index 99% rename from Classes/CrashReports/BITCrashManager.h rename to Classes/BITCrashManager.h index 1f4d955f..777bc711 100644 --- a/Classes/CrashReports/BITCrashManager.h +++ b/Classes/BITCrashManager.h @@ -30,7 +30,7 @@ #import -#import "../Helper/BITHockeyBaseManager.h" +#import "BITHockeyBaseManager.h" // hockey crash manager status diff --git a/Classes/CrashReports/BITCrashManager.m b/Classes/BITCrashManager.m similarity index 100% rename from Classes/CrashReports/BITCrashManager.m rename to Classes/BITCrashManager.m diff --git a/Classes/CrashReports/BITCrashManagerDelegate.h b/Classes/BITCrashManagerDelegate.h similarity index 100% rename from Classes/CrashReports/BITCrashManagerDelegate.h rename to Classes/BITCrashManagerDelegate.h diff --git a/Classes/CrashReports/BITCrashManagerPrivate.h b/Classes/BITCrashManagerPrivate.h similarity index 100% rename from Classes/CrashReports/BITCrashManagerPrivate.h rename to Classes/BITCrashManagerPrivate.h diff --git a/Classes/CrashReports/BITCrashReportTextFormatter.h b/Classes/BITCrashReportTextFormatter.h similarity index 100% rename from Classes/CrashReports/BITCrashReportTextFormatter.h rename to Classes/BITCrashReportTextFormatter.h diff --git a/Classes/CrashReports/BITCrashReportTextFormatter.m b/Classes/BITCrashReportTextFormatter.m similarity index 100% rename from Classes/CrashReports/BITCrashReportTextFormatter.m rename to Classes/BITCrashReportTextFormatter.m diff --git a/Classes/Feedback/BITFeedbackComposeViewController.h b/Classes/BITFeedbackComposeViewController.h similarity index 100% rename from Classes/Feedback/BITFeedbackComposeViewController.h rename to Classes/BITFeedbackComposeViewController.h diff --git a/Classes/Feedback/BITFeedbackComposeViewController.m b/Classes/BITFeedbackComposeViewController.m similarity index 100% rename from Classes/Feedback/BITFeedbackComposeViewController.m rename to Classes/BITFeedbackComposeViewController.m diff --git a/Classes/Feedback/BITFeedbackListViewCell.h b/Classes/BITFeedbackListViewCell.h similarity index 100% rename from Classes/Feedback/BITFeedbackListViewCell.h rename to Classes/BITFeedbackListViewCell.h diff --git a/Classes/Feedback/BITFeedbackListViewCell.m b/Classes/BITFeedbackListViewCell.m similarity index 100% rename from Classes/Feedback/BITFeedbackListViewCell.m rename to Classes/BITFeedbackListViewCell.m diff --git a/Classes/Feedback/BITFeedbackListViewController.h b/Classes/BITFeedbackListViewController.h similarity index 96% rename from Classes/Feedback/BITFeedbackListViewController.h rename to Classes/BITFeedbackListViewController.h index a63addd7..9ed216bd 100644 --- a/Classes/Feedback/BITFeedbackListViewController.h +++ b/Classes/BITFeedbackListViewController.h @@ -29,7 +29,7 @@ #import -#import "../Helper/BITHockeyBaseViewController.h" +#import "BITHockeyBaseViewController.h" @interface BITFeedbackListViewController : BITHockeyBaseViewController { diff --git a/Classes/Feedback/BITFeedbackListViewController.m b/Classes/BITFeedbackListViewController.m similarity index 100% rename from Classes/Feedback/BITFeedbackListViewController.m rename to Classes/BITFeedbackListViewController.m diff --git a/Classes/Feedback/BITFeedbackManager.h b/Classes/BITFeedbackManager.h similarity index 98% rename from Classes/Feedback/BITFeedbackManager.h rename to Classes/BITFeedbackManager.h index 4e1bb6c8..318ce91a 100644 --- a/Classes/Feedback/BITFeedbackManager.h +++ b/Classes/BITFeedbackManager.h @@ -29,7 +29,7 @@ #import -#import "../Helper/BITHockeyBaseManager.h" +#import "BITHockeyBaseManager.h" #import "BITFeedbackListViewController.h" #import "BITFeedbackComposeViewController.h" diff --git a/Classes/Feedback/BITFeedbackManager.m b/Classes/BITFeedbackManager.m similarity index 100% rename from Classes/Feedback/BITFeedbackManager.m rename to Classes/BITFeedbackManager.m diff --git a/Classes/Feedback/BITFeedbackManagerPrivate.h b/Classes/BITFeedbackManagerPrivate.h similarity index 100% rename from Classes/Feedback/BITFeedbackManagerPrivate.h rename to Classes/BITFeedbackManagerPrivate.h diff --git a/Classes/Feedback/BITFeedbackMessage.h b/Classes/BITFeedbackMessage.h similarity index 100% rename from Classes/Feedback/BITFeedbackMessage.h rename to Classes/BITFeedbackMessage.h diff --git a/Classes/Feedback/BITFeedbackMessage.m b/Classes/BITFeedbackMessage.m similarity index 100% rename from Classes/Feedback/BITFeedbackMessage.m rename to Classes/BITFeedbackMessage.m diff --git a/Classes/Feedback/BITFeedbackUserDataViewController.h b/Classes/BITFeedbackUserDataViewController.h similarity index 100% rename from Classes/Feedback/BITFeedbackUserDataViewController.h rename to Classes/BITFeedbackUserDataViewController.h diff --git a/Classes/Feedback/BITFeedbackUserDataViewController.m b/Classes/BITFeedbackUserDataViewController.m similarity index 100% rename from Classes/Feedback/BITFeedbackUserDataViewController.m rename to Classes/BITFeedbackUserDataViewController.m diff --git a/Classes/Helper/BITHockeyBaseManager.h b/Classes/BITHockeyBaseManager.h similarity index 100% rename from Classes/Helper/BITHockeyBaseManager.h rename to Classes/BITHockeyBaseManager.h diff --git a/Classes/Helper/BITHockeyBaseManager.m b/Classes/BITHockeyBaseManager.m similarity index 100% rename from Classes/Helper/BITHockeyBaseManager.m rename to Classes/BITHockeyBaseManager.m diff --git a/Classes/Helper/BITHockeyBaseManagerPrivate.h b/Classes/BITHockeyBaseManagerPrivate.h similarity index 100% rename from Classes/Helper/BITHockeyBaseManagerPrivate.h rename to Classes/BITHockeyBaseManagerPrivate.h diff --git a/Classes/Helper/BITHockeyBaseViewController.h b/Classes/BITHockeyBaseViewController.h similarity index 100% rename from Classes/Helper/BITHockeyBaseViewController.h rename to Classes/BITHockeyBaseViewController.h diff --git a/Classes/Helper/BITHockeyBaseViewController.m b/Classes/BITHockeyBaseViewController.m similarity index 100% rename from Classes/Helper/BITHockeyBaseViewController.m rename to Classes/BITHockeyBaseViewController.m diff --git a/Classes/Helper/BITHockeyHelper.h b/Classes/BITHockeyHelper.h similarity index 100% rename from Classes/Helper/BITHockeyHelper.h rename to Classes/BITHockeyHelper.h diff --git a/Classes/Helper/BITHockeyHelper.m b/Classes/BITHockeyHelper.m similarity index 100% rename from Classes/Helper/BITHockeyHelper.m rename to Classes/BITHockeyHelper.m diff --git a/Classes/Update/BITUpdateManager.h b/Classes/BITUpdateManager.h similarity index 99% rename from Classes/Update/BITUpdateManager.h rename to Classes/BITUpdateManager.h index 7355569d..656f8d07 100644 --- a/Classes/Update/BITUpdateManager.h +++ b/Classes/BITUpdateManager.h @@ -30,7 +30,7 @@ #import -#import "../Helper/BITHockeyBaseManager.h" +#import "BITHockeyBaseManager.h" typedef enum { diff --git a/Classes/Update/BITUpdateManager.m b/Classes/BITUpdateManager.m similarity index 100% rename from Classes/Update/BITUpdateManager.m rename to Classes/BITUpdateManager.m diff --git a/Classes/Update/BITUpdateManagerDelegate.h b/Classes/BITUpdateManagerDelegate.h similarity index 100% rename from Classes/Update/BITUpdateManagerDelegate.h rename to Classes/BITUpdateManagerDelegate.h diff --git a/Classes/Update/BITUpdateManagerPrivate.h b/Classes/BITUpdateManagerPrivate.h similarity index 100% rename from Classes/Update/BITUpdateManagerPrivate.h rename to Classes/BITUpdateManagerPrivate.h diff --git a/Classes/Update/BITUpdateViewController.h b/Classes/BITUpdateViewController.h similarity index 96% rename from Classes/Update/BITUpdateViewController.h rename to Classes/BITUpdateViewController.h index 4f03a0d1..cf131cc4 100644 --- a/Classes/Update/BITUpdateViewController.h +++ b/Classes/BITUpdateViewController.h @@ -30,7 +30,7 @@ #import -#import "../Helper/BITHockeyBaseViewController.h" +#import "BITHockeyBaseViewController.h" @class PSStoreButton; diff --git a/Classes/Update/BITUpdateViewController.m b/Classes/BITUpdateViewController.m similarity index 100% rename from Classes/Update/BITUpdateViewController.m rename to Classes/BITUpdateViewController.m diff --git a/Classes/Update/BITUpdateViewControllerPrivate.h b/Classes/BITUpdateViewControllerPrivate.h similarity index 100% rename from Classes/Update/BITUpdateViewControllerPrivate.h rename to Classes/BITUpdateViewControllerPrivate.h diff --git a/Classes/HockeySDK.h b/Classes/HockeySDK.h index 96a13ef1..a377574b 100644 --- a/Classes/HockeySDK.h +++ b/Classes/HockeySDK.h @@ -33,16 +33,16 @@ #import "BITHockeyManager.h" #import "BITHockeyManagerDelegate.h" -#import "CrashReports/BITCrashManager.h" -#import "CrashReports/BITCrashManagerDelegate.h" +#import "BITCrashManager.h" +#import "BITCrashManagerDelegate.h" -#import "Update/BITUpdateManager.h" -#import "Update/BITUpdateManagerDelegate.h" -#import "Update/BITUpdateViewController.h" +#import "BITUpdateManager.h" +#import "BITUpdateManagerDelegate.h" +#import "BITUpdateViewController.h" -#import "Feedback/BITFeedbackManager.h" -#import "Feedback/BITFeedbackComposeViewController.h" -#import "Feedback/BITFeedbackListViewController.h" +#import "BITFeedbackManager.h" +#import "BITFeedbackComposeViewController.h" +#import "BITFeedbackListViewController.h" // Notification message which HockeyManager is listening to, to retry requesting updated from the server diff --git a/Classes/Helper/HockeySDKPrivate.h b/Classes/HockeySDKPrivate.h similarity index 100% rename from Classes/Helper/HockeySDKPrivate.h rename to Classes/HockeySDKPrivate.h diff --git a/Classes/Helper/HockeySDKPrivate.m b/Classes/HockeySDKPrivate.m similarity index 100% rename from Classes/Helper/HockeySDKPrivate.m rename to Classes/HockeySDKPrivate.m diff --git a/Classes/Helper/PSAppStoreHeader.h b/Classes/PSAppStoreHeader.h similarity index 100% rename from Classes/Helper/PSAppStoreHeader.h rename to Classes/PSAppStoreHeader.h diff --git a/Classes/Helper/PSAppStoreHeader.m b/Classes/PSAppStoreHeader.m similarity index 100% rename from Classes/Helper/PSAppStoreHeader.m rename to Classes/PSAppStoreHeader.m diff --git a/Classes/Helper/PSStoreButton.h b/Classes/PSStoreButton.h similarity index 100% rename from Classes/Helper/PSStoreButton.h rename to Classes/PSStoreButton.h diff --git a/Classes/Helper/PSStoreButton.m b/Classes/PSStoreButton.m similarity index 100% rename from Classes/Helper/PSStoreButton.m rename to Classes/PSStoreButton.m diff --git a/Classes/Helper/PSWebTableViewCell.h b/Classes/PSWebTableViewCell.h similarity index 100% rename from Classes/Helper/PSWebTableViewCell.h rename to Classes/PSWebTableViewCell.h diff --git a/Classes/Helper/PSWebTableViewCell.m b/Classes/PSWebTableViewCell.m similarity index 100% rename from Classes/Helper/PSWebTableViewCell.m rename to Classes/PSWebTableViewCell.m diff --git a/LICENSE.txt b/LICENSE similarity index 100% rename from LICENSE.txt rename to LICENSE diff --git a/Support/HockeySDK.xcconfig b/Support/HockeySDK.xcconfig new file mode 100644 index 00000000..7edd7646 --- /dev/null +++ b/Support/HockeySDK.xcconfig @@ -0,0 +1,2 @@ +OTHER_LDFLAGS=$(inherited) -ObjC -framework CoreGraphics -framework Foundation -framework QuartzCore -framework SystemConfiguration -weak_framework AdSupport -weak_framework UIKit +APPLEDOC_DOCSET_NAME=HockeySDK-iOS \ No newline at end of file diff --git a/Support/HockeySDK.xcodeproj/project.pbxproj b/Support/HockeySDK.xcodeproj/project.pbxproj index bb8a4917..623902c1 100644 --- a/Support/HockeySDK.xcodeproj/project.pbxproj +++ b/Support/HockeySDK.xcodeproj/project.pbxproj @@ -7,6 +7,18 @@ objects = { /* Begin PBXAggregateTarget section */ + 1E4F61E91621AD970033EFC5 /* HockeySDK Framework */ = { + isa = PBXAggregateTarget; + buildConfigurationList = 1E4F61EA1621AD970033EFC5 /* Build configuration list for PBXAggregateTarget "HockeySDK Framework" */; + buildPhases = ( + 1E4F61ED1621ADE70033EFC5 /* Build universal embedded framework */, + ); + dependencies = ( + 1E754E431621F6290070AB92 /* PBXTargetDependency */, + ); + name = "HockeySDK Framework"; + productName = "HockeySDK Framework"; + }; 1E8E66AD15BC3D7700632A2E /* HockeySDK Documentation */ = { isa = PBXAggregateTarget; buildConfigurationList = 1E8E66B015BC3D7700632A2E /* Build configuration list for PBXAggregateTarget "HockeySDK Documentation" */; @@ -22,148 +34,43 @@ /* Begin PBXBuildFile section */ 1E27EF2515BB5033000AE995 /* HockeySDK.strings in Resources */ = {isa = PBXBuildFile; fileRef = 1E59555F15B6F80E00A03429 /* HockeySDK.strings */; }; - 1E49A43A1612223B00463151 /* BITFeedbackComposeViewController.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E49A42D1612223B00463151 /* BITFeedbackComposeViewController.h */; }; - 1E49A43B1612223B00463151 /* BITFeedbackComposeViewController.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E49A42D1612223B00463151 /* BITFeedbackComposeViewController.h */; }; 1E49A43C1612223B00463151 /* BITFeedbackComposeViewController.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E49A42D1612223B00463151 /* BITFeedbackComposeViewController.h */; }; - 1E49A43D1612223B00463151 /* BITFeedbackComposeViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 1E49A42E1612223B00463151 /* BITFeedbackComposeViewController.m */; }; - 1E49A43E1612223B00463151 /* BITFeedbackComposeViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 1E49A42E1612223B00463151 /* BITFeedbackComposeViewController.m */; }; 1E49A43F1612223B00463151 /* BITFeedbackComposeViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 1E49A42E1612223B00463151 /* BITFeedbackComposeViewController.m */; }; - 1E49A4401612223B00463151 /* BITFeedbackListViewCell.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E49A42F1612223B00463151 /* BITFeedbackListViewCell.h */; }; - 1E49A4411612223B00463151 /* BITFeedbackListViewCell.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E49A42F1612223B00463151 /* BITFeedbackListViewCell.h */; }; 1E49A4421612223B00463151 /* BITFeedbackListViewCell.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E49A42F1612223B00463151 /* BITFeedbackListViewCell.h */; }; - 1E49A4431612223B00463151 /* BITFeedbackListViewCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 1E49A4301612223B00463151 /* BITFeedbackListViewCell.m */; }; - 1E49A4441612223B00463151 /* BITFeedbackListViewCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 1E49A4301612223B00463151 /* BITFeedbackListViewCell.m */; }; 1E49A4451612223B00463151 /* BITFeedbackListViewCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 1E49A4301612223B00463151 /* BITFeedbackListViewCell.m */; }; - 1E49A4461612223B00463151 /* BITFeedbackListViewController.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E49A4311612223B00463151 /* BITFeedbackListViewController.h */; }; - 1E49A4471612223B00463151 /* BITFeedbackListViewController.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E49A4311612223B00463151 /* BITFeedbackListViewController.h */; }; 1E49A4481612223B00463151 /* BITFeedbackListViewController.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E49A4311612223B00463151 /* BITFeedbackListViewController.h */; }; - 1E49A4491612223B00463151 /* BITFeedbackListViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 1E49A4321612223B00463151 /* BITFeedbackListViewController.m */; }; - 1E49A44A1612223B00463151 /* BITFeedbackListViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 1E49A4321612223B00463151 /* BITFeedbackListViewController.m */; }; 1E49A44B1612223B00463151 /* BITFeedbackListViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 1E49A4321612223B00463151 /* BITFeedbackListViewController.m */; }; - 1E49A44C1612223B00463151 /* BITFeedbackManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E49A4331612223B00463151 /* BITFeedbackManager.h */; }; - 1E49A44D1612223B00463151 /* BITFeedbackManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E49A4331612223B00463151 /* BITFeedbackManager.h */; }; 1E49A44E1612223B00463151 /* BITFeedbackManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E49A4331612223B00463151 /* BITFeedbackManager.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 1E49A44F1612223B00463151 /* BITFeedbackManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 1E49A4341612223B00463151 /* BITFeedbackManager.m */; }; - 1E49A4501612223B00463151 /* BITFeedbackManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 1E49A4341612223B00463151 /* BITFeedbackManager.m */; }; 1E49A4511612223B00463151 /* BITFeedbackManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 1E49A4341612223B00463151 /* BITFeedbackManager.m */; }; - 1E49A4521612223B00463151 /* BITFeedbackManagerPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E49A4351612223B00463151 /* BITFeedbackManagerPrivate.h */; }; - 1E49A4531612223B00463151 /* BITFeedbackManagerPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E49A4351612223B00463151 /* BITFeedbackManagerPrivate.h */; }; 1E49A4541612223B00463151 /* BITFeedbackManagerPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E49A4351612223B00463151 /* BITFeedbackManagerPrivate.h */; }; - 1E49A4551612223B00463151 /* BITFeedbackMessage.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E49A4361612223B00463151 /* BITFeedbackMessage.h */; }; - 1E49A4561612223B00463151 /* BITFeedbackMessage.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E49A4361612223B00463151 /* BITFeedbackMessage.h */; }; 1E49A4571612223B00463151 /* BITFeedbackMessage.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E49A4361612223B00463151 /* BITFeedbackMessage.h */; }; - 1E49A4581612223B00463151 /* BITFeedbackMessage.m in Sources */ = {isa = PBXBuildFile; fileRef = 1E49A4371612223B00463151 /* BITFeedbackMessage.m */; }; - 1E49A4591612223B00463151 /* BITFeedbackMessage.m in Sources */ = {isa = PBXBuildFile; fileRef = 1E49A4371612223B00463151 /* BITFeedbackMessage.m */; }; 1E49A45A1612223B00463151 /* BITFeedbackMessage.m in Sources */ = {isa = PBXBuildFile; fileRef = 1E49A4371612223B00463151 /* BITFeedbackMessage.m */; }; - 1E49A45B1612223B00463151 /* BITFeedbackUserDataViewController.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E49A4381612223B00463151 /* BITFeedbackUserDataViewController.h */; }; - 1E49A45C1612223B00463151 /* BITFeedbackUserDataViewController.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E49A4381612223B00463151 /* BITFeedbackUserDataViewController.h */; }; 1E49A45D1612223B00463151 /* BITFeedbackUserDataViewController.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E49A4381612223B00463151 /* BITFeedbackUserDataViewController.h */; }; - 1E49A45E1612223B00463151 /* BITFeedbackUserDataViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 1E49A4391612223B00463151 /* BITFeedbackUserDataViewController.m */; }; - 1E49A45F1612223B00463151 /* BITFeedbackUserDataViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 1E49A4391612223B00463151 /* BITFeedbackUserDataViewController.m */; }; 1E49A4601612223B00463151 /* BITFeedbackUserDataViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 1E49A4391612223B00463151 /* BITFeedbackUserDataViewController.m */; }; - 1E49A46B1612226D00463151 /* BITAppVersionMetaInfo.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E49A4621612226D00463151 /* BITAppVersionMetaInfo.h */; }; - 1E49A46C1612226D00463151 /* BITAppVersionMetaInfo.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E49A4621612226D00463151 /* BITAppVersionMetaInfo.h */; }; 1E49A46D1612226D00463151 /* BITAppVersionMetaInfo.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E49A4621612226D00463151 /* BITAppVersionMetaInfo.h */; }; - 1E49A46E1612226D00463151 /* BITAppVersionMetaInfo.m in Sources */ = {isa = PBXBuildFile; fileRef = 1E49A4631612226D00463151 /* BITAppVersionMetaInfo.m */; }; - 1E49A46F1612226D00463151 /* BITAppVersionMetaInfo.m in Sources */ = {isa = PBXBuildFile; fileRef = 1E49A4631612226D00463151 /* BITAppVersionMetaInfo.m */; }; 1E49A4701612226D00463151 /* BITAppVersionMetaInfo.m in Sources */ = {isa = PBXBuildFile; fileRef = 1E49A4631612226D00463151 /* BITAppVersionMetaInfo.m */; }; - 1E49A4711612226D00463151 /* BITUpdateManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E49A4641612226D00463151 /* BITUpdateManager.h */; }; - 1E49A4721612226D00463151 /* BITUpdateManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E49A4641612226D00463151 /* BITUpdateManager.h */; }; 1E49A4731612226D00463151 /* BITUpdateManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E49A4641612226D00463151 /* BITUpdateManager.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 1E49A4741612226D00463151 /* BITUpdateManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 1E49A4651612226D00463151 /* BITUpdateManager.m */; }; - 1E49A4751612226D00463151 /* BITUpdateManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 1E49A4651612226D00463151 /* BITUpdateManager.m */; }; 1E49A4761612226D00463151 /* BITUpdateManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 1E49A4651612226D00463151 /* BITUpdateManager.m */; }; - 1E49A4771612226D00463151 /* BITUpdateManagerDelegate.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E49A4661612226D00463151 /* BITUpdateManagerDelegate.h */; }; - 1E49A4781612226D00463151 /* BITUpdateManagerDelegate.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E49A4661612226D00463151 /* BITUpdateManagerDelegate.h */; }; 1E49A4791612226D00463151 /* BITUpdateManagerDelegate.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E49A4661612226D00463151 /* BITUpdateManagerDelegate.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 1E49A47A1612226D00463151 /* BITUpdateManagerPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E49A4671612226D00463151 /* BITUpdateManagerPrivate.h */; }; - 1E49A47B1612226D00463151 /* BITUpdateManagerPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E49A4671612226D00463151 /* BITUpdateManagerPrivate.h */; }; 1E49A47C1612226D00463151 /* BITUpdateManagerPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E49A4671612226D00463151 /* BITUpdateManagerPrivate.h */; }; - 1E49A47D1612226D00463151 /* BITUpdateViewController.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E49A4681612226D00463151 /* BITUpdateViewController.h */; }; - 1E49A47E1612226D00463151 /* BITUpdateViewController.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E49A4681612226D00463151 /* BITUpdateViewController.h */; }; 1E49A47F1612226D00463151 /* BITUpdateViewController.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E49A4681612226D00463151 /* BITUpdateViewController.h */; }; - 1E49A4801612226D00463151 /* BITUpdateViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 1E49A4691612226D00463151 /* BITUpdateViewController.m */; }; - 1E49A4811612226D00463151 /* BITUpdateViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 1E49A4691612226D00463151 /* BITUpdateViewController.m */; }; 1E49A4821612226D00463151 /* BITUpdateViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 1E49A4691612226D00463151 /* BITUpdateViewController.m */; }; - 1E49A4831612226D00463151 /* BITUpdateViewControllerPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E49A46A1612226D00463151 /* BITUpdateViewControllerPrivate.h */; }; - 1E49A4841612226D00463151 /* BITUpdateViewControllerPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E49A46A1612226D00463151 /* BITUpdateViewControllerPrivate.h */; }; 1E49A4851612226D00463151 /* BITUpdateViewControllerPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E49A46A1612226D00463151 /* BITUpdateViewControllerPrivate.h */; }; - 1E49A48D1612228800463151 /* BITCrashManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E49A4871612228800463151 /* BITCrashManager.h */; }; - 1E49A48E1612228800463151 /* BITCrashManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E49A4871612228800463151 /* BITCrashManager.h */; }; - 1E49A48F1612228800463151 /* BITCrashManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E49A4871612228800463151 /* BITCrashManager.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 1E49A4901612228800463151 /* BITCrashManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 1E49A4881612228800463151 /* BITCrashManager.m */; }; - 1E49A4911612228800463151 /* BITCrashManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 1E49A4881612228800463151 /* BITCrashManager.m */; }; - 1E49A4921612228800463151 /* BITCrashManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 1E49A4881612228800463151 /* BITCrashManager.m */; }; - 1E49A4931612228800463151 /* BITCrashManagerDelegate.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E49A4891612228800463151 /* BITCrashManagerDelegate.h */; }; - 1E49A4941612228800463151 /* BITCrashManagerDelegate.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E49A4891612228800463151 /* BITCrashManagerDelegate.h */; }; - 1E49A4951612228800463151 /* BITCrashManagerDelegate.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E49A4891612228800463151 /* BITCrashManagerDelegate.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 1E49A4961612228800463151 /* BITCrashManagerPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E49A48A1612228800463151 /* BITCrashManagerPrivate.h */; }; - 1E49A4971612228800463151 /* BITCrashManagerPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E49A48A1612228800463151 /* BITCrashManagerPrivate.h */; }; - 1E49A4981612228800463151 /* BITCrashManagerPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E49A48A1612228800463151 /* BITCrashManagerPrivate.h */; }; - 1E49A4991612228800463151 /* BITCrashReportTextFormatter.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E49A48B1612228800463151 /* BITCrashReportTextFormatter.h */; }; - 1E49A49A1612228800463151 /* BITCrashReportTextFormatter.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E49A48B1612228800463151 /* BITCrashReportTextFormatter.h */; }; - 1E49A49B1612228800463151 /* BITCrashReportTextFormatter.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E49A48B1612228800463151 /* BITCrashReportTextFormatter.h */; }; - 1E49A49C1612228800463151 /* BITCrashReportTextFormatter.m in Sources */ = {isa = PBXBuildFile; fileRef = 1E49A48C1612228800463151 /* BITCrashReportTextFormatter.m */; }; - 1E49A49D1612228800463151 /* BITCrashReportTextFormatter.m in Sources */ = {isa = PBXBuildFile; fileRef = 1E49A48C1612228800463151 /* BITCrashReportTextFormatter.m */; }; - 1E49A49E1612228800463151 /* BITCrashReportTextFormatter.m in Sources */ = {isa = PBXBuildFile; fileRef = 1E49A48C1612228800463151 /* BITCrashReportTextFormatter.m */; }; - 1E49A4AD161222B900463151 /* BITHockeyBaseManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E49A4A0161222B900463151 /* BITHockeyBaseManager.h */; }; - 1E49A4AE161222B900463151 /* BITHockeyBaseManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E49A4A0161222B900463151 /* BITHockeyBaseManager.h */; }; 1E49A4AF161222B900463151 /* BITHockeyBaseManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E49A4A0161222B900463151 /* BITHockeyBaseManager.h */; }; - 1E49A4B0161222B900463151 /* BITHockeyBaseManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 1E49A4A1161222B900463151 /* BITHockeyBaseManager.m */; }; - 1E49A4B1161222B900463151 /* BITHockeyBaseManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 1E49A4A1161222B900463151 /* BITHockeyBaseManager.m */; }; 1E49A4B2161222B900463151 /* BITHockeyBaseManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 1E49A4A1161222B900463151 /* BITHockeyBaseManager.m */; }; - 1E49A4B3161222B900463151 /* BITHockeyBaseManagerPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E49A4A2161222B900463151 /* BITHockeyBaseManagerPrivate.h */; }; - 1E49A4B4161222B900463151 /* BITHockeyBaseManagerPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E49A4A2161222B900463151 /* BITHockeyBaseManagerPrivate.h */; }; 1E49A4B5161222B900463151 /* BITHockeyBaseManagerPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E49A4A2161222B900463151 /* BITHockeyBaseManagerPrivate.h */; }; - 1E49A4B6161222B900463151 /* BITHockeyBaseViewController.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E49A4A3161222B900463151 /* BITHockeyBaseViewController.h */; }; - 1E49A4B7161222B900463151 /* BITHockeyBaseViewController.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E49A4A3161222B900463151 /* BITHockeyBaseViewController.h */; }; 1E49A4B8161222B900463151 /* BITHockeyBaseViewController.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E49A4A3161222B900463151 /* BITHockeyBaseViewController.h */; }; - 1E49A4B9161222B900463151 /* BITHockeyBaseViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 1E49A4A4161222B900463151 /* BITHockeyBaseViewController.m */; }; - 1E49A4BA161222B900463151 /* BITHockeyBaseViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 1E49A4A4161222B900463151 /* BITHockeyBaseViewController.m */; }; 1E49A4BB161222B900463151 /* BITHockeyBaseViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 1E49A4A4161222B900463151 /* BITHockeyBaseViewController.m */; }; - 1E49A4BC161222B900463151 /* BITHockeyHelper.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E49A4A5161222B900463151 /* BITHockeyHelper.h */; }; - 1E49A4BD161222B900463151 /* BITHockeyHelper.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E49A4A5161222B900463151 /* BITHockeyHelper.h */; }; 1E49A4BE161222B900463151 /* BITHockeyHelper.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E49A4A5161222B900463151 /* BITHockeyHelper.h */; }; - 1E49A4BF161222B900463151 /* BITHockeyHelper.m in Sources */ = {isa = PBXBuildFile; fileRef = 1E49A4A6161222B900463151 /* BITHockeyHelper.m */; }; - 1E49A4C0161222B900463151 /* BITHockeyHelper.m in Sources */ = {isa = PBXBuildFile; fileRef = 1E49A4A6161222B900463151 /* BITHockeyHelper.m */; }; 1E49A4C1161222B900463151 /* BITHockeyHelper.m in Sources */ = {isa = PBXBuildFile; fileRef = 1E49A4A6161222B900463151 /* BITHockeyHelper.m */; }; - 1E49A4C2161222B900463151 /* PSAppStoreHeader.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E49A4A7161222B900463151 /* PSAppStoreHeader.h */; }; - 1E49A4C3161222B900463151 /* PSAppStoreHeader.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E49A4A7161222B900463151 /* PSAppStoreHeader.h */; }; 1E49A4C4161222B900463151 /* PSAppStoreHeader.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E49A4A7161222B900463151 /* PSAppStoreHeader.h */; }; - 1E49A4C5161222B900463151 /* PSAppStoreHeader.m in Sources */ = {isa = PBXBuildFile; fileRef = 1E49A4A8161222B900463151 /* PSAppStoreHeader.m */; }; - 1E49A4C6161222B900463151 /* PSAppStoreHeader.m in Sources */ = {isa = PBXBuildFile; fileRef = 1E49A4A8161222B900463151 /* PSAppStoreHeader.m */; }; 1E49A4C7161222B900463151 /* PSAppStoreHeader.m in Sources */ = {isa = PBXBuildFile; fileRef = 1E49A4A8161222B900463151 /* PSAppStoreHeader.m */; }; - 1E49A4C8161222B900463151 /* PSStoreButton.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E49A4A9161222B900463151 /* PSStoreButton.h */; }; - 1E49A4C9161222B900463151 /* PSStoreButton.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E49A4A9161222B900463151 /* PSStoreButton.h */; }; 1E49A4CA161222B900463151 /* PSStoreButton.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E49A4A9161222B900463151 /* PSStoreButton.h */; }; - 1E49A4CB161222B900463151 /* PSStoreButton.m in Sources */ = {isa = PBXBuildFile; fileRef = 1E49A4AA161222B900463151 /* PSStoreButton.m */; }; - 1E49A4CC161222B900463151 /* PSStoreButton.m in Sources */ = {isa = PBXBuildFile; fileRef = 1E49A4AA161222B900463151 /* PSStoreButton.m */; }; 1E49A4CD161222B900463151 /* PSStoreButton.m in Sources */ = {isa = PBXBuildFile; fileRef = 1E49A4AA161222B900463151 /* PSStoreButton.m */; }; - 1E49A4CE161222B900463151 /* PSWebTableViewCell.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E49A4AB161222B900463151 /* PSWebTableViewCell.h */; }; - 1E49A4CF161222B900463151 /* PSWebTableViewCell.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E49A4AB161222B900463151 /* PSWebTableViewCell.h */; }; 1E49A4D0161222B900463151 /* PSWebTableViewCell.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E49A4AB161222B900463151 /* PSWebTableViewCell.h */; }; - 1E49A4D1161222B900463151 /* PSWebTableViewCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 1E49A4AC161222B900463151 /* PSWebTableViewCell.m */; }; - 1E49A4D2161222B900463151 /* PSWebTableViewCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 1E49A4AC161222B900463151 /* PSWebTableViewCell.m */; }; 1E49A4D3161222B900463151 /* PSWebTableViewCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 1E49A4AC161222B900463151 /* PSWebTableViewCell.m */; }; - 1E49A4D6161222D400463151 /* HockeySDKPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E49A4D4161222D400463151 /* HockeySDKPrivate.h */; }; - 1E49A4D7161222D400463151 /* HockeySDKPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E49A4D4161222D400463151 /* HockeySDKPrivate.h */; }; 1E49A4D8161222D400463151 /* HockeySDKPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E49A4D4161222D400463151 /* HockeySDKPrivate.h */; }; - 1E49A4D9161222D400463151 /* HockeySDKPrivate.m in Sources */ = {isa = PBXBuildFile; fileRef = 1E49A4D5161222D400463151 /* HockeySDKPrivate.m */; }; - 1E49A4DA161222D400463151 /* HockeySDKPrivate.m in Sources */ = {isa = PBXBuildFile; fileRef = 1E49A4D5161222D400463151 /* HockeySDKPrivate.m */; }; 1E49A4DB161222D400463151 /* HockeySDKPrivate.m in Sources */ = {isa = PBXBuildFile; fileRef = 1E49A4D5161222D400463151 /* HockeySDKPrivate.m */; }; - 1E4F61D51621A3620033EFC5 /* BITCrashManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E49A4871612228800463151 /* BITCrashManager.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 1E4F61D71621A3660033EFC5 /* BITCrashManagerDelegate.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E49A4891612228800463151 /* BITCrashManagerDelegate.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 1E4F61DC1621A3830033EFC5 /* BITFeedbackManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E49A4331612223B00463151 /* BITFeedbackManager.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 1E4F61DD1621A39B0033EFC5 /* BITUpdateManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E49A4641612226D00463151 /* BITUpdateManager.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 1E4F61DE1621A39E0033EFC5 /* BITUpdateManagerDelegate.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E49A4661612226D00463151 /* BITUpdateManagerDelegate.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 1E4F61DF1621A3CA0033EFC5 /* BITHockeyManager.h in Headers */ = {isa = PBXBuildFile; fileRef = E41EB465148D7BF50015DEDC /* BITHockeyManager.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 1E4F61E01621A3CD0033EFC5 /* BITHockeyManagerDelegate.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E5955FA15B7877A00A03429 /* BITHockeyManagerDelegate.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 1E59545D15B6C41300A03429 /* BITHockeyManager.m in Sources */ = {isa = PBXBuildFile; fileRef = E41EB466148D7BF50015DEDC /* BITHockeyManager.m */; }; - 1E59546615B6C41300A03429 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E400561D148D79B500EB22B9 /* Foundation.framework */; }; - 1E59546715B6C41300A03429 /* CrashReporter.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E41EB48B148D7C4E0015DEDC /* CrashReporter.framework */; }; - 1E59546E15B6C41300A03429 /* BITHockeyManager.h in Headers */ = {isa = PBXBuildFile; fileRef = E41EB465148D7BF50015DEDC /* BITHockeyManager.h */; }; - 1E59547815B6C41300A03429 /* HockeySDK.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E71509A15B5C76F004E88FF /* HockeySDK.h */; settings = {ATTRIBUTES = (); }; }; - 1E59548315B6C4EF00A03429 /* HockeySDK.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E71509A15B5C76F004E88FF /* HockeySDK.h */; settings = {ATTRIBUTES = (Public, ); }; }; 1E5954D315B6F24A00A03429 /* BITHockeyManager.m in Sources */ = {isa = PBXBuildFile; fileRef = E41EB466148D7BF50015DEDC /* BITHockeyManager.m */; }; 1E5954DC15B6F24A00A03429 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E400561D148D79B500EB22B9 /* Foundation.framework */; }; 1E5954DD15B6F24A00A03429 /* CrashReporter.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E41EB48B148D7C4E0015DEDC /* CrashReporter.framework */; }; @@ -178,47 +85,30 @@ 1E5955CC15B71C8600A03429 /* buttonHighlight@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 1E5955C115B71C8600A03429 /* buttonHighlight@2x.png */; }; 1E5955CF15B71C8600A03429 /* IconGradient.png in Resources */ = {isa = PBXBuildFile; fileRef = 1E5955C415B71C8600A03429 /* IconGradient.png */; }; 1E5955D015B71C8600A03429 /* IconGradient@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 1E5955C515B71C8600A03429 /* IconGradient@2x.png */; }; - 1E5955FB15B7877B00A03429 /* BITHockeyManagerDelegate.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E5955FA15B7877A00A03429 /* BITHockeyManagerDelegate.h */; }; - 1E5955FC15B7877B00A03429 /* BITHockeyManagerDelegate.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E5955FA15B7877A00A03429 /* BITHockeyManagerDelegate.h */; }; 1E5955FD15B7877B00A03429 /* BITHockeyManagerDelegate.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E5955FA15B7877A00A03429 /* BITHockeyManagerDelegate.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 1E71509B15B5C76F004E88FF /* HockeySDK.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E71509A15B5C76F004E88FF /* HockeySDK.h */; settings = {ATTRIBUTES = (); }; }; - 1EC69F5E1615001500808FD9 /* BITHockeyManagerPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 1EC69F5D1615001500808FD9 /* BITHockeyManagerPrivate.h */; }; - 1EC69F5F1615001500808FD9 /* BITHockeyManagerPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 1EC69F5D1615001500808FD9 /* BITHockeyManagerPrivate.h */; }; + 1E754E5C1621FBB70070AB92 /* BITCrashManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E754E561621FBB70070AB92 /* BITCrashManager.h */; }; + 1E754E5D1621FBB70070AB92 /* BITCrashManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 1E754E571621FBB70070AB92 /* BITCrashManager.m */; }; + 1E754E5E1621FBB70070AB92 /* BITCrashManagerDelegate.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E754E581621FBB70070AB92 /* BITCrashManagerDelegate.h */; }; + 1E754E5F1621FBB70070AB92 /* BITCrashManagerPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E754E591621FBB70070AB92 /* BITCrashManagerPrivate.h */; }; + 1E754E601621FBB70070AB92 /* BITCrashReportTextFormatter.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E754E5A1621FBB70070AB92 /* BITCrashReportTextFormatter.h */; }; + 1E754E611621FBB70070AB92 /* BITCrashReportTextFormatter.m in Sources */ = {isa = PBXBuildFile; fileRef = 1E754E5B1621FBB70070AB92 /* BITCrashReportTextFormatter.m */; }; 1EC69F601615001500808FD9 /* BITHockeyManagerPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 1EC69F5D1615001500808FD9 /* BITHockeyManagerPrivate.h */; }; - E400561E148D79B500EB22B9 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E400561D148D79B500EB22B9 /* Foundation.framework */; }; - E41EB47D148D7BF50015DEDC /* BITHockeyManager.h in Headers */ = {isa = PBXBuildFile; fileRef = E41EB465148D7BF50015DEDC /* BITHockeyManager.h */; }; - E41EB47E148D7BF50015DEDC /* BITHockeyManager.m in Sources */ = {isa = PBXBuildFile; fileRef = E41EB466148D7BF50015DEDC /* BITHockeyManager.m */; }; - E41EB48C148D7C4E0015DEDC /* CrashReporter.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E41EB48B148D7C4E0015DEDC /* CrashReporter.framework */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ - 1E59547D15B6C47900A03429 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = E4005611148D79B500EB22B9 /* Project object */; - proxyType = 1; - remoteGlobalIDString = E4005619148D79B500EB22B9; - remoteInfo = "HockeySDK-Device"; - }; - 1E59549315B6CBBE00A03429 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = E4005611148D79B500EB22B9 /* Project object */; - proxyType = 1; - remoteGlobalIDString = 1E59545515B6C41300A03429; - remoteInfo = "HockeySDK-Simulator"; - }; - 1E59554815B6F6F600A03429 /* PBXContainerItemProxy */ = { + 1E59557D15B6F97100A03429 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = E4005611148D79B500EB22B9 /* Project object */; proxyType = 1; remoteGlobalIDString = 1E59550915B6F45800A03429; - remoteInfo = HockeySDKBundle; + remoteInfo = HockeySDKResources; }; - 1E59557D15B6F97100A03429 /* PBXContainerItemProxy */ = { + 1E754E421621F6290070AB92 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = E4005611148D79B500EB22B9 /* Project object */; proxyType = 1; - remoteGlobalIDString = 1E59550915B6F45800A03429; - remoteInfo = HockeySDKResources; + remoteGlobalIDString = 1E8E66AD15BC3D7700632A2E; + remoteInfo = "HockeySDK Documentation"; }; /* End PBXContainerItemProxy section */ @@ -245,12 +135,6 @@ 1E49A4681612226D00463151 /* BITUpdateViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BITUpdateViewController.h; sourceTree = ""; }; 1E49A4691612226D00463151 /* BITUpdateViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = BITUpdateViewController.m; sourceTree = ""; }; 1E49A46A1612226D00463151 /* BITUpdateViewControllerPrivate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BITUpdateViewControllerPrivate.h; sourceTree = ""; }; - 1E49A4871612228800463151 /* BITCrashManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BITCrashManager.h; sourceTree = ""; }; - 1E49A4881612228800463151 /* BITCrashManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = BITCrashManager.m; sourceTree = ""; }; - 1E49A4891612228800463151 /* BITCrashManagerDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BITCrashManagerDelegate.h; sourceTree = ""; }; - 1E49A48A1612228800463151 /* BITCrashManagerPrivate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BITCrashManagerPrivate.h; sourceTree = ""; }; - 1E49A48B1612228800463151 /* BITCrashReportTextFormatter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BITCrashReportTextFormatter.h; sourceTree = ""; }; - 1E49A48C1612228800463151 /* BITCrashReportTextFormatter.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = BITCrashReportTextFormatter.m; sourceTree = ""; }; 1E49A4A0161222B900463151 /* BITHockeyBaseManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BITHockeyBaseManager.h; sourceTree = ""; }; 1E49A4A1161222B900463151 /* BITHockeyBaseManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = BITHockeyBaseManager.m; sourceTree = ""; }; 1E49A4A2161222B900463151 /* BITHockeyBaseManagerPrivate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BITHockeyBaseManagerPrivate.h; sourceTree = ""; }; @@ -266,8 +150,6 @@ 1E49A4AC161222B900463151 /* PSWebTableViewCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PSWebTableViewCell.m; sourceTree = ""; }; 1E49A4D4161222D400463151 /* HockeySDKPrivate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HockeySDKPrivate.h; sourceTree = ""; }; 1E49A4D5161222D400463151 /* HockeySDKPrivate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HockeySDKPrivate.m; sourceTree = ""; }; - 1E59544115B6C3DC00A03429 /* HockeySDK.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = HockeySDK.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - 1E59547C15B6C41300A03429 /* libHockeySDK-iphonesimulator.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libHockeySDK-iphonesimulator.a"; sourceTree = BUILT_PRODUCTS_DIR; }; 1E5954F215B6F24A00A03429 /* libHockeySDK.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libHockeySDK.a; sourceTree = BUILT_PRODUCTS_DIR; }; 1E59550A15B6F45800A03429 /* HockeySDKResources.bundle */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = HockeySDKResources.bundle; sourceTree = BUILT_PRODUCTS_DIR; }; 1E59556015B6F80E00A03429 /* de */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.strings; name = de; path = de.lproj/HockeySDK.strings; sourceTree = ""; }; @@ -296,9 +178,15 @@ 1E5955FA15B7877A00A03429 /* BITHockeyManagerDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BITHockeyManagerDelegate.h; sourceTree = ""; }; 1E66CA9115D4100500F35BED /* buildnumber.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = buildnumber.xcconfig; sourceTree = ""; }; 1E71509A15B5C76F004E88FF /* HockeySDK.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HockeySDK.h; sourceTree = ""; }; + 1E754DC61621BC170070AB92 /* HockeySDK.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = HockeySDK.xcconfig; sourceTree = ""; }; + 1E754E561621FBB70070AB92 /* BITCrashManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BITCrashManager.h; sourceTree = ""; }; + 1E754E571621FBB70070AB92 /* BITCrashManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = BITCrashManager.m; sourceTree = ""; }; + 1E754E581621FBB70070AB92 /* BITCrashManagerDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BITCrashManagerDelegate.h; sourceTree = ""; }; + 1E754E591621FBB70070AB92 /* BITCrashManagerPrivate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BITCrashManagerPrivate.h; sourceTree = ""; }; + 1E754E5A1621FBB70070AB92 /* BITCrashReportTextFormatter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BITCrashReportTextFormatter.h; sourceTree = ""; }; + 1E754E5B1621FBB70070AB92 /* BITCrashReportTextFormatter.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = BITCrashReportTextFormatter.m; sourceTree = ""; }; 1EC69F5D1615001500808FD9 /* BITHockeyManagerPrivate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BITHockeyManagerPrivate.h; sourceTree = ""; }; 1EDA60CF15C2C1450032D10B /* HockeySDK-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "HockeySDK-Info.plist"; sourceTree = ""; }; - E400561A148D79B500EB22B9 /* libHockeySDK-iphoneos.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libHockeySDK-iphoneos.a"; sourceTree = BUILT_PRODUCTS_DIR; }; E400561D148D79B500EB22B9 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; E41EB465148D7BF50015DEDC /* BITHockeyManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BITHockeyManager.h; sourceTree = ""; }; E41EB466148D7BF50015DEDC /* BITHockeyManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = BITHockeyManager.m; sourceTree = ""; }; @@ -308,22 +196,6 @@ /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ - 1E59543D15B6C3DC00A03429 /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 1E59546515B6C41300A03429 /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - 1E59546615B6C41300A03429 /* Foundation.framework in Frameworks */, - 1E59546715B6C41300A03429 /* CrashReporter.framework in Frameworks */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; 1E5954DB15B6F24A00A03429 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; @@ -340,68 +212,35 @@ ); runOnlyForDeploymentPostprocessing = 0; }; - E4005617148D79B500EB22B9 /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - E400561E148D79B500EB22B9 /* Foundation.framework in Frameworks */, - E41EB48C148D7C4E0015DEDC /* CrashReporter.framework in Frameworks */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ - 1E49A42C1612223B00463151 /* Feedback */ = { - isa = PBXGroup; - children = ( - 1E49A4361612223B00463151 /* BITFeedbackMessage.h */, - 1E49A4371612223B00463151 /* BITFeedbackMessage.m */, - 1E49A42D1612223B00463151 /* BITFeedbackComposeViewController.h */, - 1E49A42E1612223B00463151 /* BITFeedbackComposeViewController.m */, - 1E49A4381612223B00463151 /* BITFeedbackUserDataViewController.h */, - 1E49A4391612223B00463151 /* BITFeedbackUserDataViewController.m */, - 1E49A42F1612223B00463151 /* BITFeedbackListViewCell.h */, - 1E49A4301612223B00463151 /* BITFeedbackListViewCell.m */, - 1E49A4311612223B00463151 /* BITFeedbackListViewController.h */, - 1E49A4321612223B00463151 /* BITFeedbackListViewController.m */, - 1E49A4331612223B00463151 /* BITFeedbackManager.h */, - 1E49A4341612223B00463151 /* BITFeedbackManager.m */, - 1E49A4351612223B00463151 /* BITFeedbackManagerPrivate.h */, - ); - path = Feedback; - sourceTree = ""; - }; - 1E49A4611612226D00463151 /* Update */ = { + 1E5955A415B71BDC00A03429 /* Images */ = { isa = PBXGroup; children = ( - 1E49A4621612226D00463151 /* BITAppVersionMetaInfo.h */, - 1E49A4631612226D00463151 /* BITAppVersionMetaInfo.m */, - 1E49A4641612226D00463151 /* BITUpdateManager.h */, - 1E49A4651612226D00463151 /* BITUpdateManager.m */, - 1E49A4661612226D00463151 /* BITUpdateManagerDelegate.h */, - 1E49A4671612226D00463151 /* BITUpdateManagerPrivate.h */, - 1E49A4681612226D00463151 /* BITUpdateViewController.h */, - 1E49A4691612226D00463151 /* BITUpdateViewController.m */, - 1E49A46A1612226D00463151 /* BITUpdateViewControllerPrivate.h */, + 1E5955BB15B71C8600A03429 /* authorize_denied.png */, + 1E5955BC15B71C8600A03429 /* authorize_denied@2x.png */, + 1E5955BD15B71C8600A03429 /* authorize_request.png */, + 1E5955BE15B71C8600A03429 /* authorize_request@2x.png */, + 1E5955BF15B71C8600A03429 /* bg.png */, + 1E5955C015B71C8600A03429 /* buttonHighlight.png */, + 1E5955C115B71C8600A03429 /* buttonHighlight@2x.png */, + 1E5955C415B71C8600A03429 /* IconGradient.png */, + 1E5955C515B71C8600A03429 /* IconGradient@2x.png */, ); - path = Update; + name = Images; sourceTree = ""; }; - 1E49A4861612228800463151 /* CrashReports */ = { + 1E66CA8F15D40FF600F35BED /* Support */ = { isa = PBXGroup; children = ( - 1E49A4871612228800463151 /* BITCrashManager.h */, - 1E49A4881612228800463151 /* BITCrashManager.m */, - 1E49A4891612228800463151 /* BITCrashManagerDelegate.h */, - 1E49A48A1612228800463151 /* BITCrashManagerPrivate.h */, - 1E49A48B1612228800463151 /* BITCrashReportTextFormatter.h */, - 1E49A48C1612228800463151 /* BITCrashReportTextFormatter.m */, + 1E754DC61621BC170070AB92 /* HockeySDK.xcconfig */, + 1E66CA9115D4100500F35BED /* buildnumber.xcconfig */, ); - path = CrashReports; + name = Support; sourceTree = ""; }; - 1E49A49F161222B900463151 /* Helper */ = { + 1E754E441621F95E0070AB92 /* Helper */ = { isa = PBXGroup; children = ( 1E49A4D4161222D400463151 /* HockeySDKPrivate.h */, @@ -420,31 +259,56 @@ 1E49A4AB161222B900463151 /* PSWebTableViewCell.h */, 1E49A4AC161222B900463151 /* PSWebTableViewCell.m */, ); - path = Helper; + name = Helper; sourceTree = ""; }; - 1E5955A415B71BDC00A03429 /* Images */ = { + 1E754E461621FA9A0070AB92 /* Feedback */ = { isa = PBXGroup; children = ( - 1E5955BB15B71C8600A03429 /* authorize_denied.png */, - 1E5955BC15B71C8600A03429 /* authorize_denied@2x.png */, - 1E5955BD15B71C8600A03429 /* authorize_request.png */, - 1E5955BE15B71C8600A03429 /* authorize_request@2x.png */, - 1E5955BF15B71C8600A03429 /* bg.png */, - 1E5955C015B71C8600A03429 /* buttonHighlight.png */, - 1E5955C115B71C8600A03429 /* buttonHighlight@2x.png */, - 1E5955C415B71C8600A03429 /* IconGradient.png */, - 1E5955C515B71C8600A03429 /* IconGradient@2x.png */, + 1E49A4361612223B00463151 /* BITFeedbackMessage.h */, + 1E49A4371612223B00463151 /* BITFeedbackMessage.m */, + 1E49A42D1612223B00463151 /* BITFeedbackComposeViewController.h */, + 1E49A42E1612223B00463151 /* BITFeedbackComposeViewController.m */, + 1E49A4381612223B00463151 /* BITFeedbackUserDataViewController.h */, + 1E49A4391612223B00463151 /* BITFeedbackUserDataViewController.m */, + 1E49A42F1612223B00463151 /* BITFeedbackListViewCell.h */, + 1E49A4301612223B00463151 /* BITFeedbackListViewCell.m */, + 1E49A4311612223B00463151 /* BITFeedbackListViewController.h */, + 1E49A4321612223B00463151 /* BITFeedbackListViewController.m */, + 1E49A4331612223B00463151 /* BITFeedbackManager.h */, + 1E49A4341612223B00463151 /* BITFeedbackManager.m */, + 1E49A4351612223B00463151 /* BITFeedbackManagerPrivate.h */, ); - name = Images; + name = Feedback; sourceTree = ""; }; - 1E66CA8F15D40FF600F35BED /* Support */ = { + 1E754E471621FAD00070AB92 /* Update */ = { isa = PBXGroup; children = ( - 1E66CA9115D4100500F35BED /* buildnumber.xcconfig */, + 1E49A4621612226D00463151 /* BITAppVersionMetaInfo.h */, + 1E49A4631612226D00463151 /* BITAppVersionMetaInfo.m */, + 1E49A4641612226D00463151 /* BITUpdateManager.h */, + 1E49A4651612226D00463151 /* BITUpdateManager.m */, + 1E49A4661612226D00463151 /* BITUpdateManagerDelegate.h */, + 1E49A4671612226D00463151 /* BITUpdateManagerPrivate.h */, + 1E49A4681612226D00463151 /* BITUpdateViewController.h */, + 1E49A4691612226D00463151 /* BITUpdateViewController.m */, + 1E49A46A1612226D00463151 /* BITUpdateViewControllerPrivate.h */, ); - name = Support; + name = Update; + sourceTree = ""; + }; + 1E754E551621FBAF0070AB92 /* CrashReports */ = { + isa = PBXGroup; + children = ( + 1E754E561621FBB70070AB92 /* BITCrashManager.h */, + 1E754E571621FBB70070AB92 /* BITCrashManager.m */, + 1E754E581621FBB70070AB92 /* BITCrashManagerDelegate.h */, + 1E754E591621FBB70070AB92 /* BITCrashManagerPrivate.h */, + 1E754E5A1621FBB70070AB92 /* BITCrashReportTextFormatter.h */, + 1E754E5B1621FBB70070AB92 /* BITCrashReportTextFormatter.m */, + ); + name = CrashReports; sourceTree = ""; }; E400560F148D79B500EB22B9 = { @@ -463,9 +327,6 @@ E400561B148D79B500EB22B9 /* Products */ = { isa = PBXGroup; children = ( - E400561A148D79B500EB22B9 /* libHockeySDK-iphoneos.a */, - 1E59544115B6C3DC00A03429 /* HockeySDK.framework */, - 1E59547C15B6C41300A03429 /* libHockeySDK-iphonesimulator.a */, 1E5954F215B6F24A00A03429 /* libHockeySDK.a */, 1E59550A15B6F45800A03429 /* HockeySDKResources.bundle */, ); @@ -495,10 +356,10 @@ E41EB458148D7BF50015DEDC /* Classes */ = { isa = PBXGroup; children = ( - 1E49A49F161222B900463151 /* Helper */, - 1E49A4861612228800463151 /* CrashReports */, - 1E49A42C1612223B00463151 /* Feedback */, - 1E49A4611612226D00463151 /* Update */, + 1E754E441621F95E0070AB92 /* Helper */, + 1E754E551621FBAF0070AB92 /* CrashReports */, + 1E754E461621FA9A0070AB92 /* Feedback */, + 1E754E471621FAD00070AB92 /* Update */, E41EB465148D7BF50015DEDC /* BITHockeyManager.h */, E41EB466148D7BF50015DEDC /* BITHockeyManager.m */, 1EC69F5D1615001500808FD9 /* BITHockeyManagerPrivate.h */, @@ -520,57 +381,6 @@ /* End PBXGroup section */ /* Begin PBXHeadersBuildPhase section */ - 1E59543E15B6C3DC00A03429 /* Headers */ = { - isa = PBXHeadersBuildPhase; - buildActionMask = 2147483647; - files = ( - 1E59548315B6C4EF00A03429 /* HockeySDK.h in Headers */, - 1E4F61DF1621A3CA0033EFC5 /* BITHockeyManager.h in Headers */, - 1E4F61E01621A3CD0033EFC5 /* BITHockeyManagerDelegate.h in Headers */, - 1E4F61DD1621A39B0033EFC5 /* BITUpdateManager.h in Headers */, - 1E4F61DE1621A39E0033EFC5 /* BITUpdateManagerDelegate.h in Headers */, - 1E4F61D51621A3620033EFC5 /* BITCrashManager.h in Headers */, - 1E4F61D71621A3660033EFC5 /* BITCrashManagerDelegate.h in Headers */, - 1E4F61DC1621A3830033EFC5 /* BITFeedbackManager.h in Headers */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 1E59546815B6C41300A03429 /* Headers */ = { - isa = PBXHeadersBuildPhase; - buildActionMask = 2147483647; - files = ( - 1E59547815B6C41300A03429 /* HockeySDK.h in Headers */, - 1E59546E15B6C41300A03429 /* BITHockeyManager.h in Headers */, - 1E5955FC15B7877B00A03429 /* BITHockeyManagerDelegate.h in Headers */, - 1E49A43B1612223B00463151 /* BITFeedbackComposeViewController.h in Headers */, - 1E49A4411612223B00463151 /* BITFeedbackListViewCell.h in Headers */, - 1E49A4471612223B00463151 /* BITFeedbackListViewController.h in Headers */, - 1E49A44D1612223B00463151 /* BITFeedbackManager.h in Headers */, - 1E49A4531612223B00463151 /* BITFeedbackManagerPrivate.h in Headers */, - 1E49A4561612223B00463151 /* BITFeedbackMessage.h in Headers */, - 1E49A45C1612223B00463151 /* BITFeedbackUserDataViewController.h in Headers */, - 1E49A46C1612226D00463151 /* BITAppVersionMetaInfo.h in Headers */, - 1E49A4721612226D00463151 /* BITUpdateManager.h in Headers */, - 1E49A4781612226D00463151 /* BITUpdateManagerDelegate.h in Headers */, - 1E49A47B1612226D00463151 /* BITUpdateManagerPrivate.h in Headers */, - 1E49A47E1612226D00463151 /* BITUpdateViewController.h in Headers */, - 1E49A4841612226D00463151 /* BITUpdateViewControllerPrivate.h in Headers */, - 1E49A48E1612228800463151 /* BITCrashManager.h in Headers */, - 1E49A4941612228800463151 /* BITCrashManagerDelegate.h in Headers */, - 1E49A4971612228800463151 /* BITCrashManagerPrivate.h in Headers */, - 1E49A49A1612228800463151 /* BITCrashReportTextFormatter.h in Headers */, - 1E49A4AE161222B900463151 /* BITHockeyBaseManager.h in Headers */, - 1E49A4B4161222B900463151 /* BITHockeyBaseManagerPrivate.h in Headers */, - 1E49A4B7161222B900463151 /* BITHockeyBaseViewController.h in Headers */, - 1E49A4BD161222B900463151 /* BITHockeyHelper.h in Headers */, - 1E49A4C3161222B900463151 /* PSAppStoreHeader.h in Headers */, - 1E49A4C9161222B900463151 /* PSStoreButton.h in Headers */, - 1E49A4CF161222B900463151 /* PSWebTableViewCell.h in Headers */, - 1E49A4D7161222D400463151 /* HockeySDKPrivate.h in Headers */, - 1EC69F5F1615001500808FD9 /* BITHockeyManagerPrivate.h in Headers */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; 1E59558B15B6FD8800A03429 /* Headers */ = { isa = PBXHeadersBuildPhase; buildActionMask = 2147483647; @@ -578,8 +388,6 @@ 1E59559B15B6FDA500A03429 /* HockeySDK.h in Headers */, 1E59559A15B6FDA500A03429 /* BITHockeyManager.h in Headers */, 1E5955FD15B7877B00A03429 /* BITHockeyManagerDelegate.h in Headers */, - 1E49A48F1612228800463151 /* BITCrashManager.h in Headers */, - 1E49A4951612228800463151 /* BITCrashManagerDelegate.h in Headers */, 1E49A4731612226D00463151 /* BITUpdateManager.h in Headers */, 1E49A4791612226D00463151 /* BITUpdateManagerDelegate.h in Headers */, 1E49A44E1612223B00463151 /* BITFeedbackManager.h in Headers */, @@ -593,8 +401,6 @@ 1E49A47C1612226D00463151 /* BITUpdateManagerPrivate.h in Headers */, 1E49A47F1612226D00463151 /* BITUpdateViewController.h in Headers */, 1E49A4851612226D00463151 /* BITUpdateViewControllerPrivate.h in Headers */, - 1E49A4981612228800463151 /* BITCrashManagerPrivate.h in Headers */, - 1E49A49B1612228800463151 /* BITCrashReportTextFormatter.h in Headers */, 1E49A4AF161222B900463151 /* BITHockeyBaseManager.h in Headers */, 1E49A4B5161222B900463151 /* BITHockeyBaseManagerPrivate.h in Headers */, 1E49A4B8161222B900463151 /* BITHockeyBaseViewController.h in Headers */, @@ -604,90 +410,19 @@ 1E49A4D0161222B900463151 /* PSWebTableViewCell.h in Headers */, 1E49A4D8161222D400463151 /* HockeySDKPrivate.h in Headers */, 1EC69F601615001500808FD9 /* BITHockeyManagerPrivate.h in Headers */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - E4005618148D79B500EB22B9 /* Headers */ = { - isa = PBXHeadersBuildPhase; - buildActionMask = 2147483647; - files = ( - 1E71509B15B5C76F004E88FF /* HockeySDK.h in Headers */, - E41EB47D148D7BF50015DEDC /* BITHockeyManager.h in Headers */, - 1E5955FB15B7877B00A03429 /* BITHockeyManagerDelegate.h in Headers */, - 1E49A43A1612223B00463151 /* BITFeedbackComposeViewController.h in Headers */, - 1E49A4401612223B00463151 /* BITFeedbackListViewCell.h in Headers */, - 1E49A4461612223B00463151 /* BITFeedbackListViewController.h in Headers */, - 1E49A44C1612223B00463151 /* BITFeedbackManager.h in Headers */, - 1E49A4521612223B00463151 /* BITFeedbackManagerPrivate.h in Headers */, - 1E49A4551612223B00463151 /* BITFeedbackMessage.h in Headers */, - 1E49A45B1612223B00463151 /* BITFeedbackUserDataViewController.h in Headers */, - 1E49A46B1612226D00463151 /* BITAppVersionMetaInfo.h in Headers */, - 1E49A4711612226D00463151 /* BITUpdateManager.h in Headers */, - 1E49A4771612226D00463151 /* BITUpdateManagerDelegate.h in Headers */, - 1E49A47A1612226D00463151 /* BITUpdateManagerPrivate.h in Headers */, - 1E49A47D1612226D00463151 /* BITUpdateViewController.h in Headers */, - 1E49A4831612226D00463151 /* BITUpdateViewControllerPrivate.h in Headers */, - 1E49A48D1612228800463151 /* BITCrashManager.h in Headers */, - 1E49A4931612228800463151 /* BITCrashManagerDelegate.h in Headers */, - 1E49A4961612228800463151 /* BITCrashManagerPrivate.h in Headers */, - 1E49A4991612228800463151 /* BITCrashReportTextFormatter.h in Headers */, - 1E49A4AD161222B900463151 /* BITHockeyBaseManager.h in Headers */, - 1E49A4B3161222B900463151 /* BITHockeyBaseManagerPrivate.h in Headers */, - 1E49A4B6161222B900463151 /* BITHockeyBaseViewController.h in Headers */, - 1E49A4BC161222B900463151 /* BITHockeyHelper.h in Headers */, - 1E49A4C2161222B900463151 /* PSAppStoreHeader.h in Headers */, - 1E49A4C8161222B900463151 /* PSStoreButton.h in Headers */, - 1E49A4CE161222B900463151 /* PSWebTableViewCell.h in Headers */, - 1E49A4D6161222D400463151 /* HockeySDKPrivate.h in Headers */, - 1EC69F5E1615001500808FD9 /* BITHockeyManagerPrivate.h in Headers */, + 1E754E5C1621FBB70070AB92 /* BITCrashManager.h in Headers */, + 1E754E5E1621FBB70070AB92 /* BITCrashManagerDelegate.h in Headers */, + 1E754E5F1621FBB70070AB92 /* BITCrashManagerPrivate.h in Headers */, + 1E754E601621FBB70070AB92 /* BITCrashReportTextFormatter.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXHeadersBuildPhase section */ /* Begin PBXNativeTarget section */ - 1E59544015B6C3DC00A03429 /* HockeySDK */ = { + 1E5954CB15B6F24A00A03429 /* HockeySDK */ = { isa = PBXNativeTarget; - buildConfigurationList = 1E59545215B6C3DC00A03429 /* Build configuration list for PBXNativeTarget "HockeySDK" */; - buildPhases = ( - 1E59543E15B6C3DC00A03429 /* Headers */, - 1E59543F15B6C3DC00A03429 /* Resources */, - 1E59543C15B6C3DC00A03429 /* Sources */, - 1E59543D15B6C3DC00A03429 /* Frameworks */, - 1E59549D15B6D39500A03429 /* Lipo Binary */, - ); - buildRules = ( - ); - dependencies = ( - 1E59547E15B6C47900A03429 /* PBXTargetDependency */, - 1E59549415B6CBBE00A03429 /* PBXTargetDependency */, - 1E59554915B6F6F600A03429 /* PBXTargetDependency */, - ); - name = HockeySDK; - productName = HockeySDK; - productReference = 1E59544115B6C3DC00A03429 /* HockeySDK.framework */; - productType = "com.apple.product-type.framework"; - }; - 1E59545515B6C41300A03429 /* HockeySDK-Simulator */ = { - isa = PBXNativeTarget; - buildConfigurationList = 1E59547915B6C41300A03429 /* Build configuration list for PBXNativeTarget "HockeySDK-Simulator" */; - buildPhases = ( - 1E59545615B6C41300A03429 /* Sources */, - 1E59546515B6C41300A03429 /* Frameworks */, - 1E59546815B6C41300A03429 /* Headers */, - ); - buildRules = ( - ); - dependencies = ( - ); - name = "HockeySDK-Simulator"; - productName = HockeySDK; - productReference = 1E59547C15B6C41300A03429 /* libHockeySDK-iphonesimulator.a */; - productType = "com.apple.product-type.library.static"; - }; - 1E5954CB15B6F24A00A03429 /* HockeySDKLib */ = { - isa = PBXNativeTarget; - buildConfigurationList = 1E5954EF15B6F24A00A03429 /* Build configuration list for PBXNativeTarget "HockeySDKLib" */; + buildConfigurationList = 1E5954EF15B6F24A00A03429 /* Build configuration list for PBXNativeTarget "HockeySDK" */; buildPhases = ( 1E5954CC15B6F24A00A03429 /* Sources */, 1E5954DB15B6F24A00A03429 /* Frameworks */, @@ -698,7 +433,7 @@ dependencies = ( 1E59557E15B6F97100A03429 /* PBXTargetDependency */, ); - name = HockeySDKLib; + name = HockeySDK; productName = HockeySDK; productReference = 1E5954F215B6F24A00A03429 /* libHockeySDK.a */; productType = "com.apple.product-type.library.static"; @@ -720,23 +455,6 @@ productReference = 1E59550A15B6F45800A03429 /* HockeySDKResources.bundle */; productType = "com.apple.product-type.bundle"; }; - E4005619148D79B500EB22B9 /* HockeySDK-Device */ = { - isa = PBXNativeTarget; - buildConfigurationList = E400563E148D79B500EB22B9 /* Build configuration list for PBXNativeTarget "HockeySDK-Device" */; - buildPhases = ( - E4005616148D79B500EB22B9 /* Sources */, - E4005617148D79B500EB22B9 /* Frameworks */, - E4005618148D79B500EB22B9 /* Headers */, - ); - buildRules = ( - ); - dependencies = ( - ); - name = "HockeySDK-Device"; - productName = HockeySDK; - productReference = E400561A148D79B500EB22B9 /* libHockeySDK-iphoneos.a */; - productType = "com.apple.product-type.library.static"; - }; /* End PBXNativeTarget section */ /* Begin PBXProject section */ @@ -772,24 +490,15 @@ projectDirPath = ""; projectRoot = ""; targets = ( - 1E59544015B6C3DC00A03429 /* HockeySDK */, - E4005619148D79B500EB22B9 /* HockeySDK-Device */, - 1E59545515B6C41300A03429 /* HockeySDK-Simulator */, - 1E5954CB15B6F24A00A03429 /* HockeySDKLib */, + 1E5954CB15B6F24A00A03429 /* HockeySDK */, 1E59550915B6F45800A03429 /* HockeySDKResources */, 1E8E66AD15BC3D7700632A2E /* HockeySDK Documentation */, + 1E4F61E91621AD970033EFC5 /* HockeySDK Framework */, ); }; /* End PBXProject section */ /* Begin PBXResourcesBuildPhase section */ - 1E59543F15B6C3DC00A03429 /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; 1E59550815B6F45800A03429 /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; @@ -810,19 +519,19 @@ /* End PBXResourcesBuildPhase section */ /* Begin PBXShellScriptBuildPhase section */ - 1E59549D15B6D39500A03429 /* Lipo Binary */ = { + 1E4F61ED1621ADE70033EFC5 /* Build universal embedded framework */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( ); inputPaths = ( ); - name = "Lipo Binary"; + name = "Build universal embedded framework"; outputPaths = ( ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "FRAMEWORK=\"${BUILT_PRODUCTS_DIR}/${PRODUCT_NAME}.framework\"\n\nlipo \\\n\"${BUILD_DIR}/${CONFIGURATION}-iphoneos/libHockeySDK-iphoneos.a\" \\\n\"${BUILD_DIR}/${CONFIGURATION}-iphonesimulator/libHockeySDK-iphonesimulator.a\" \\\n-create -output \"${FRAMEWORK}/Versions/Current/${PRODUCT_NAME}\"\n\n# Combine the CrashReporter static library into a new Hockey static library file if they are not already present and copy the public headers too\nif [ -z $(otool -L \"${FRAMEWORK}/Versions/Current/${PRODUCT_NAME}\" | grep 'libCrashReporter') ]\nthen\nlibtool -static -o \"${FRAMEWORK}/Versions/Current/${PRODUCT_NAME}\" \"${FRAMEWORK}/Versions/Current/${PRODUCT_NAME}\" \"${SRCROOT}/../Vendor/CrashReporter.framework/Versions/A/CrashReporter\"\ncp -r \\\n\"${SRCROOT}/../Vendor/CrashReporter.framework/Versions/A/Headers/\" \\\n\"${FRAMEWORK}/Versions/Current/Headers/\"\nfi\n\n# Add the Resource bundle\n#if [ -e \"${FRAMEWORK}/Versions/Current/Resources/HockeySDKResources.bundle\" ];\n#then\n#rm -r \"${FRAMEWORK}/Versions/Current/Resources/HockeySDKResources.bundle\"\n#fi\n#\n#cp -r \\\n#\"${BUILD_DIR}/${CONFIGURATION}-iphoneos/HockeySDKResources.bundle\" \\\n#\"${FRAMEWORK}/Versions/Current/Resources/HockeySDKResources.bundle\"\n\n# Strip debugging symbols\n#strip -S \"${FRAMEWORK}/Versions/Current/${PRODUCT_NAME}\"\n\ncd \"${FRAMEWORK}\" && ln -sf \"Versions/Current/${PRODUCT_NAME}\" ./\n"; + shellScript = "# Sets the target folders and the final framework product.\nFMK_NAME=HockeySDK\nFMK_VERSION=A\nFMK_RESOURCE_BUNDLE=HockeySDKResources\n\n# Documentation\nDOCSET_NAME=\"de.bitstadium.${APPLEDOC_DOCSET_NAME}-${VERSION_STRING}\"\n\n# Install dir will be the final output to the framework.\n# The following line create it in the root folder of the current project.\nPRODUCTS_DIR=${SRCROOT}/../Products\nTEMP_DIR=${PRODUCTS_DIR}/Temp\nINSTALL_DIR=${TEMP_DIR}/${FMK_NAME}.framework\n\n# Working dir will be deleted after the framework creation.\nWRK_DIR=build\nDEVICE_DIR=${WRK_DIR}/Release-iphoneos\nSIMULATOR_DIR=${WRK_DIR}/Release-iphonesimulator\nHEADERS_DIR=${WRK_DIR}/Release-iphoneos/usr/local/include\n\n# Building both architectures.\nxcodebuild -project \"HockeySDK.xcodeproj\" -configuration \"Release\" -target \"${FMK_NAME}\" -sdk iphoneos\nxcodebuild -project \"HockeySDK.xcodeproj\" -configuration \"Release\" -target \"${FMK_NAME}\" -sdk iphonesimulator\n\n# Cleaning the oldest.\nif [ -d \"${TEMP_DIR}\" ]\nthen\nrm -rf \"${TEMP_DIR}\"\nfi\n\n# Creates and renews the final product folder.\nmkdir -p \"${INSTALL_DIR}\"\nmkdir -p \"${INSTALL_DIR}/Versions\"\nmkdir -p \"${INSTALL_DIR}/Versions/${FMK_VERSION}\"\nmkdir -p \"${INSTALL_DIR}/Versions/${FMK_VERSION}/Resources\"\nmkdir -p \"${INSTALL_DIR}/Versions/${FMK_VERSION}/Headers\"\n\n# Creates the internal links.\n# It MUST uses relative path, otherwise will not work when the folder is copied/moved.\nln -s \"${FMK_VERSION}\" \"${INSTALL_DIR}/Versions/Current\"\nln -s \"Versions/Current/Headers\" \"${INSTALL_DIR}/Headers\"\nln -s \"Versions/Current/Resources\" \"${INSTALL_DIR}/Resources\"\nln -s \"Versions/Current/${FMK_NAME}\" \"${INSTALL_DIR}/${FMK_NAME}\"\n\n# Copies the headers and resources files to the final product folder.\ncp -R \"${HEADERS_DIR}/\" \"${INSTALL_DIR}/Versions/${FMK_VERSION}/Headers/\"\ncp -R \"${DEVICE_DIR}/${FMK_RESOURCE_BUNDLE}.bundle\" \"${INSTALL_DIR}/Versions/${FMK_VERSION}/Resources/\"\ncp -f \"${SRCROOT}/${FMK_NAME}.xcconfig\" \"${INSTALL_DIR}/Versions/${FMK_VERSION}/Resources/\"\n\n# Uses the Lipo Tool to merge both binary files (i386 + armv6/armv7) into one Universal final product.\nlipo -create \"${DEVICE_DIR}/lib${FMK_NAME}.a\" \"${SIMULATOR_DIR}/lib${FMK_NAME}.a\" -output \"${INSTALL_DIR}/Versions/${FMK_VERSION}/${FMK_NAME}\"\n\n# Combine the CrashReporter static library into a new Hockey static library file if they are not already present and copy the public headers too\nif [ -z $(otool -L \"${INSTALL_DIR}/Versions/${FMK_VERSION}/${FMK_NAME}\" | grep 'libCrashReporter') ]\nthen\nlibtool -static -o \"${INSTALL_DIR}/Versions/${FMK_VERSION}/${FMK_NAME}\" \"${INSTALL_DIR}/Versions/${FMK_VERSION}/${FMK_NAME}\" \"${SRCROOT}/../Vendor/CrashReporter.framework/Versions/A/CrashReporter\"\ncp -r \\\n\"${SRCROOT}/../Vendor/CrashReporter.framework/Versions/A/Headers/\" \\\n\"${INSTALL_DIR}/Versions/${FMK_VERSION}/Headers/\"\nfi\n\nrm -r \"${WRK_DIR}\"\n\n# build embeddedframework folder and move framework into it\nmkdir \"${INSTALL_DIR}/../${FMK_NAME}.embeddedframework\"\nmv \"${INSTALL_DIR}\" \"${INSTALL_DIR}/../${FMK_NAME}.embeddedframework/${FMK_NAME}.framework\"\n\n# link Resources\nNEW_INSTALL_DIR=${TEMP_DIR}/${FMK_NAME}.embeddedframework\nmkdir \"${NEW_INSTALL_DIR}/Resources\"\nln -s \"../${FMK_NAME}.framework/Resources/${FMK_RESOURCE_BUNDLE}.bundle\" \"${NEW_INSTALL_DIR}/Resources/${FMK_RESOURCE_BUNDLE}.bundle\"\nln -s \"../${FMK_NAME}.framework/Resources/${FMK_NAME}.xcconfig\" \"${NEW_INSTALL_DIR}/Resources/${FMK_NAME}.xcconfig\"\n\n# copy license, changelog, documentation\ncp -f \"${SRCROOT}/../Docs/Changelog-template.md\" \"${TEMP_DIR}/CHANGELOG\"\ncp -f \"${SRCROOT}/../LICENSE\" \"${TEMP_DIR}\"\nmkdir \"${TEMP_DIR}/${DOCSET_NAME}.docset\"\ncp -R \"${SRCROOT}/../documentation/docset/Contents\" \"${TEMP_DIR}/${DOCSET_NAME}.docset\"\n\n# build zip\ncd \"${PRODUCTS_DIR}\"\nrm -f \"${FMK_NAME}-iOS-${VERSION_STRING}.zip\"\ncd \"${TEMP_DIR}\"\nzip -yr \"../${FMK_NAME}-iOS-${VERSION_STRING}.zip\" \"./${FMK_NAME}.embeddedframework\" \"./CHANGELOG\" \"./LICENSE\" \"./${DOCSET_NAME}.docset\" -x \\*/.*\n"; }; 1E8E66B215BC3D8200632A2E /* ShellScript */ = { isa = PBXShellScriptBuildPhase; @@ -835,44 +544,11 @@ ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "\nAPPLEDOC_DOCSET_NAME=\"HockeySDK-iOS\"\n\n/usr/local/bin/appledoc \\\n --output \"${SOURCE_ROOT}/../documentation\" \\\n --ignore Vendor \\\n --ignore .m \\\n --create-html \\\n --create-docset \\\n --install-docset \\\n --keep-intermediate-file \\\n --project-name \"$APPLEDOC_DOCSET_NAME ${VERSION_STRING}\" \\\n -v \"${VERSION_STRING}\" \\\n --project-company \"BitStadium GmbH\" \\\n --company-id \"de.bitstadium\" \\\n --docset-bundle-name \"$APPLEDOC_DOCSET_NAME ${VERSION_STRING}\" \\\n --docset-feed-name \"$APPLEDOC_DOCSET_NAME\" \\\n --docset-platform-family \"iphoneos\" \\\n --index-desc \"${SOURCE_ROOT}/../docs/index.md\" \\\n --include \"${SOURCE_ROOT}/../docs/\" \\\n --merge-categories \\\n --no-repeat-first-par \\\n --warn-undocumented-object \\\n --warn-undocumented-member \\\n --warn-empty-description \\\n --warn-unknown-directive \\\n --warn-invalid-crossref \\\n --warn-missing-arg \\\n --logformat xcode \\\n --exit-threshold 2 \\\n \"${SOURCE_ROOT}/../\" \\\n"; + shellScript = "DOCSETNAME=\"de.bitstadium.${APPLEDOC_DOCSET_NAME}-${VERSION_STRING}\"\n\n/usr/local/bin/appledoc \\\n --output \"${SOURCE_ROOT}/../documentation\" \\\n --ignore Vendor \\\n --ignore .m \\\n --create-html \\\n --create-docset \\\n --install-docset \\\n --keep-intermediate-files \\\n --project-name \"${APPLEDOC_DOCSET_NAME} ${VERSION_STRING}\" \\\n --project-version \"${VERSION_STRING}\" \\\n --project-company \"BitStadium GmbH\" \\\n --company-id \"de.bitstadium\" \\\n --docset-bundle-name \"${APPLEDOC_DOCSET_NAME} ${VERSION_STRING}\" \\\n --docset-feed-name \"${APPLEDOC_DOCSET_NAME}\" \\\n --docset-platform-family \"iphoneos\" \\\n --index-desc \"${SOURCE_ROOT}/../docs/index.md\" \\\n --include \"${SOURCE_ROOT}/../docs/\" \\\n --merge-categories \\\n --no-repeat-first-par \\\n --warn-undocumented-object \\\n --warn-undocumented-member \\\n --warn-empty-description \\\n --warn-unknown-directive \\\n --warn-invalid-crossref \\\n --warn-missing-arg \\\n --logformat xcode \\\n --exit-threshold 2 \\\n \"${SOURCE_ROOT}/../\" \\\n"; }; /* End PBXShellScriptBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ - 1E59543C15B6C3DC00A03429 /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 1E59545615B6C41300A03429 /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 1E59545D15B6C41300A03429 /* BITHockeyManager.m in Sources */, - 1E49A43E1612223B00463151 /* BITFeedbackComposeViewController.m in Sources */, - 1E49A4441612223B00463151 /* BITFeedbackListViewCell.m in Sources */, - 1E49A44A1612223B00463151 /* BITFeedbackListViewController.m in Sources */, - 1E49A4501612223B00463151 /* BITFeedbackManager.m in Sources */, - 1E49A4591612223B00463151 /* BITFeedbackMessage.m in Sources */, - 1E49A45F1612223B00463151 /* BITFeedbackUserDataViewController.m in Sources */, - 1E49A46F1612226D00463151 /* BITAppVersionMetaInfo.m in Sources */, - 1E49A4751612226D00463151 /* BITUpdateManager.m in Sources */, - 1E49A4811612226D00463151 /* BITUpdateViewController.m in Sources */, - 1E49A4911612228800463151 /* BITCrashManager.m in Sources */, - 1E49A49D1612228800463151 /* BITCrashReportTextFormatter.m in Sources */, - 1E49A4B1161222B900463151 /* BITHockeyBaseManager.m in Sources */, - 1E49A4BA161222B900463151 /* BITHockeyBaseViewController.m in Sources */, - 1E49A4C0161222B900463151 /* BITHockeyHelper.m in Sources */, - 1E49A4C6161222B900463151 /* PSAppStoreHeader.m in Sources */, - 1E49A4CC161222B900463151 /* PSStoreButton.m in Sources */, - 1E49A4D2161222B900463151 /* PSWebTableViewCell.m in Sources */, - 1E49A4DA161222D400463151 /* HockeySDKPrivate.m in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; 1E5954CC15B6F24A00A03429 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; @@ -887,8 +563,6 @@ 1E49A4701612226D00463151 /* BITAppVersionMetaInfo.m in Sources */, 1E49A4761612226D00463151 /* BITUpdateManager.m in Sources */, 1E49A4821612226D00463151 /* BITUpdateViewController.m in Sources */, - 1E49A4921612228800463151 /* BITCrashManager.m in Sources */, - 1E49A49E1612228800463151 /* BITCrashReportTextFormatter.m in Sources */, 1E49A4B2161222B900463151 /* BITHockeyBaseManager.m in Sources */, 1E49A4BB161222B900463151 /* BITHockeyBaseViewController.m in Sources */, 1E49A4C1161222B900463151 /* BITHockeyHelper.m in Sources */, @@ -896,6 +570,8 @@ 1E49A4CD161222B900463151 /* PSStoreButton.m in Sources */, 1E49A4D3161222B900463151 /* PSWebTableViewCell.m in Sources */, 1E49A4DB161222D400463151 /* HockeySDKPrivate.m in Sources */, + 1E754E5D1621FBB70070AB92 /* BITCrashManager.m in Sources */, + 1E754E611621FBB70070AB92 /* BITCrashReportTextFormatter.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -906,55 +582,19 @@ ); runOnlyForDeploymentPostprocessing = 0; }; - E4005616148D79B500EB22B9 /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - E41EB47E148D7BF50015DEDC /* BITHockeyManager.m in Sources */, - 1E49A43D1612223B00463151 /* BITFeedbackComposeViewController.m in Sources */, - 1E49A4431612223B00463151 /* BITFeedbackListViewCell.m in Sources */, - 1E49A4491612223B00463151 /* BITFeedbackListViewController.m in Sources */, - 1E49A44F1612223B00463151 /* BITFeedbackManager.m in Sources */, - 1E49A4581612223B00463151 /* BITFeedbackMessage.m in Sources */, - 1E49A45E1612223B00463151 /* BITFeedbackUserDataViewController.m in Sources */, - 1E49A46E1612226D00463151 /* BITAppVersionMetaInfo.m in Sources */, - 1E49A4741612226D00463151 /* BITUpdateManager.m in Sources */, - 1E49A4801612226D00463151 /* BITUpdateViewController.m in Sources */, - 1E49A4901612228800463151 /* BITCrashManager.m in Sources */, - 1E49A49C1612228800463151 /* BITCrashReportTextFormatter.m in Sources */, - 1E49A4B0161222B900463151 /* BITHockeyBaseManager.m in Sources */, - 1E49A4B9161222B900463151 /* BITHockeyBaseViewController.m in Sources */, - 1E49A4BF161222B900463151 /* BITHockeyHelper.m in Sources */, - 1E49A4C5161222B900463151 /* PSAppStoreHeader.m in Sources */, - 1E49A4CB161222B900463151 /* PSStoreButton.m in Sources */, - 1E49A4D1161222B900463151 /* PSWebTableViewCell.m in Sources */, - 1E49A4D9161222D400463151 /* HockeySDKPrivate.m in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; /* End PBXSourcesBuildPhase section */ /* Begin PBXTargetDependency section */ - 1E59547E15B6C47900A03429 /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - target = E4005619148D79B500EB22B9 /* HockeySDK-Device */; - targetProxy = 1E59547D15B6C47900A03429 /* PBXContainerItemProxy */; - }; - 1E59549415B6CBBE00A03429 /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - target = 1E59545515B6C41300A03429 /* HockeySDK-Simulator */; - targetProxy = 1E59549315B6CBBE00A03429 /* PBXContainerItemProxy */; - }; - 1E59554915B6F6F600A03429 /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - target = 1E59550915B6F45800A03429 /* HockeySDKResources */; - targetProxy = 1E59554815B6F6F600A03429 /* PBXContainerItemProxy */; - }; 1E59557E15B6F97100A03429 /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = 1E59550915B6F45800A03429 /* HockeySDKResources */; targetProxy = 1E59557D15B6F97100A03429 /* PBXContainerItemProxy */; }; + 1E754E431621F6290070AB92 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 1E8E66AD15BC3D7700632A2E /* HockeySDK Documentation */; + targetProxy = 1E754E421621F6290070AB92 /* PBXContainerItemProxy */; + }; /* End PBXTargetDependency section */ /* Begin PBXVariantGroup section */ @@ -982,99 +622,17 @@ /* End PBXVariantGroup section */ /* Begin XCBuildConfiguration section */ - 1E59545315B6C3DC00A03429 /* Debug */ = { + 1E4F61EB1621AD970033EFC5 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { - ARCHS = "$(ARCHS_STANDARD_32_BIT)"; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; - CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - COMBINE_HIDPI_IMAGES = YES; - DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 1; - FRAMEWORK_SEARCH_PATHS = ( - "$(inherited)", - "\"$(SRCROOT)/../Vendor\"", - ); - FRAMEWORK_VERSION = A; - GCC_ENABLE_OBJC_EXCEPTIONS = YES; - GCC_PRECOMPILE_PREFIX_HEADER = YES; - GCC_PREFIX_HEADER = "HockeySDK/HockeySDK-Prefix.pch"; - GCC_PREPROCESSOR_DEFINITIONS = ( - "DEBUG=1", - "$(inherited)", - ); - GCC_WARN_64_TO_32_BIT_CONVERSION = YES; - GCC_WARN_UNINITIALIZED_AUTOS = YES; - HEADER_SEARCH_PATHS = ( - "$(inherited)", - "\"$(SRCROOT)/../Vendor\"", - ); - INSTALL_PATH = "$(HOME)/Library/Frameworks"; - MACOSX_DEPLOYMENT_TARGET = 10.5; - ONLY_ACTIVE_ARCH = NO; - PRODUCT_NAME = "$(TARGET_NAME)"; - SDKROOT = macosx; - WRAPPER_EXTENSION = framework; + PRODUCT_NAME = HockeySDK.framework; }; name = Debug; }; - 1E59545415B6C3DC00A03429 /* Release */ = { + 1E4F61EC1621AD970033EFC5 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { - ARCHS = "$(ARCHS_STANDARD_32_BIT)"; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; - CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - COMBINE_HIDPI_IMAGES = YES; - DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; - DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 1; - FRAMEWORK_SEARCH_PATHS = ( - "$(inherited)", - "\"$(SRCROOT)/../Vendor\"", - ); - FRAMEWORK_VERSION = A; - GCC_ENABLE_OBJC_EXCEPTIONS = YES; - GCC_PRECOMPILE_PREFIX_HEADER = YES; - GCC_PREFIX_HEADER = "HockeySDK/HockeySDK-Prefix.pch"; - GCC_WARN_64_TO_32_BIT_CONVERSION = YES; - GCC_WARN_UNINITIALIZED_AUTOS = YES; - HEADER_SEARCH_PATHS = ( - "$(inherited)", - "\"$(SRCROOT)/../Vendor\"", - ); - INSTALL_PATH = "$(HOME)/Library/Frameworks"; - MACOSX_DEPLOYMENT_TARGET = 10.5; - PRODUCT_NAME = "$(TARGET_NAME)"; - SDKROOT = macosx; - WRAPPER_EXTENSION = framework; - }; - name = Release; - }; - 1E59547A15B6C41300A03429 /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - DSTROOT = /tmp/HockeySDK.dst; - FRAMEWORK_SEARCH_PATHS = ( - "$(inherited)", - "\"$(SRCROOT)/../Vendor\"", - ); - PRODUCT_NAME = "HockeySDK${EFFECTIVE_PLATFORM_NAME}"; - SDKROOT = iphonesimulator; - SKIP_INSTALL = YES; - }; - name = Debug; - }; - 1E59547B15B6C41300A03429 /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - DSTROOT = /tmp/HockeySDK.dst; - FRAMEWORK_SEARCH_PATHS = ( - "$(inherited)", - "\"$(SRCROOT)/../Vendor\"", - ); - PRODUCT_NAME = "HockeySDK${EFFECTIVE_PLATFORM_NAME}"; - SDKROOT = iphonesimulator; - SKIP_INSTALL = YES; + PRODUCT_NAME = HockeySDK.framework; }; name = Release; }; @@ -1216,58 +774,19 @@ }; name = Release; }; - E400563F148D79B500EB22B9 /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - DSTROOT = /tmp/HockeySDK.dst; - FRAMEWORK_SEARCH_PATHS = ( - "$(inherited)", - "\"$(SRCROOT)/../Vendor\"", - ); - GCC_THUMB_SUPPORT = NO; - PRODUCT_NAME = "HockeySDK${EFFECTIVE_PLATFORM_NAME}"; - SKIP_INSTALL = YES; - TARGETED_DEVICE_FAMILY = "1,2"; - }; - name = Debug; - }; - E4005640148D79B500EB22B9 /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - DSTROOT = /tmp/HockeySDK.dst; - FRAMEWORK_SEARCH_PATHS = ( - "$(inherited)", - "\"$(SRCROOT)/../Vendor\"", - ); - GCC_THUMB_SUPPORT = NO; - PRODUCT_NAME = "HockeySDK${EFFECTIVE_PLATFORM_NAME}"; - SKIP_INSTALL = YES; - TARGETED_DEVICE_FAMILY = "1,2"; - }; - name = Release; - }; /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ - 1E59545215B6C3DC00A03429 /* Build configuration list for PBXNativeTarget "HockeySDK" */ = { + 1E4F61EA1621AD970033EFC5 /* Build configuration list for PBXAggregateTarget "HockeySDK Framework" */ = { isa = XCConfigurationList; buildConfigurations = ( - 1E59545315B6C3DC00A03429 /* Debug */, - 1E59545415B6C3DC00A03429 /* Release */, + 1E4F61EB1621AD970033EFC5 /* Debug */, + 1E4F61EC1621AD970033EFC5 /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; - 1E59547915B6C41300A03429 /* Build configuration list for PBXNativeTarget "HockeySDK-Simulator" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 1E59547A15B6C41300A03429 /* Debug */, - 1E59547B15B6C41300A03429 /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - 1E5954EF15B6F24A00A03429 /* Build configuration list for PBXNativeTarget "HockeySDKLib" */ = { + 1E5954EF15B6F24A00A03429 /* Build configuration list for PBXNativeTarget "HockeySDK" */ = { isa = XCConfigurationList; buildConfigurations = ( 1E5954F015B6F24A00A03429 /* Debug */, @@ -1303,15 +822,6 @@ defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; - E400563E148D79B500EB22B9 /* Build configuration list for PBXNativeTarget "HockeySDK-Device" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - E400563F148D79B500EB22B9 /* Debug */, - E4005640148D79B500EB22B9 /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; /* End XCConfigurationList section */ }; rootObject = E4005611148D79B500EB22B9 /* Project object */; diff --git a/Support/buildnumber.xcconfig b/Support/buildnumber.xcconfig index e96a9178..118a3f3b 100644 --- a/Support/buildnumber.xcconfig +++ b/Support/buildnumber.xcconfig @@ -1,3 +1,5 @@ +#include "HockeySDK.xcconfig" + BUILD_NUMBER = 6 VERSION_STRING = 2.5.4b1 GCC_PREPROCESSOR_DEFINITIONS = $(inherited) BITHOCKEY_VERSION="@\"2.5.4b1\"" From 00af2aafb0b4b8f76c44df9e200c0d23bfa4fcfb Mon Sep 17 00:00:00 2001 From: Andreas Linde Date: Sun, 7 Oct 2012 22:40:15 +0200 Subject: [PATCH 020/176] Add missing public headers --- Support/HockeySDK.xcodeproj/project.pbxproj | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Support/HockeySDK.xcodeproj/project.pbxproj b/Support/HockeySDK.xcodeproj/project.pbxproj index 623902c1..fe13265d 100644 --- a/Support/HockeySDK.xcodeproj/project.pbxproj +++ b/Support/HockeySDK.xcodeproj/project.pbxproj @@ -38,7 +38,7 @@ 1E49A43F1612223B00463151 /* BITFeedbackComposeViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 1E49A42E1612223B00463151 /* BITFeedbackComposeViewController.m */; }; 1E49A4421612223B00463151 /* BITFeedbackListViewCell.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E49A42F1612223B00463151 /* BITFeedbackListViewCell.h */; }; 1E49A4451612223B00463151 /* BITFeedbackListViewCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 1E49A4301612223B00463151 /* BITFeedbackListViewCell.m */; }; - 1E49A4481612223B00463151 /* BITFeedbackListViewController.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E49A4311612223B00463151 /* BITFeedbackListViewController.h */; }; + 1E49A4481612223B00463151 /* BITFeedbackListViewController.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E49A4311612223B00463151 /* BITFeedbackListViewController.h */; settings = {ATTRIBUTES = (Public, ); }; }; 1E49A44B1612223B00463151 /* BITFeedbackListViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 1E49A4321612223B00463151 /* BITFeedbackListViewController.m */; }; 1E49A44E1612223B00463151 /* BITFeedbackManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E49A4331612223B00463151 /* BITFeedbackManager.h */; settings = {ATTRIBUTES = (Public, ); }; }; 1E49A4511612223B00463151 /* BITFeedbackManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 1E49A4341612223B00463151 /* BITFeedbackManager.m */; }; @@ -53,7 +53,7 @@ 1E49A4761612226D00463151 /* BITUpdateManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 1E49A4651612226D00463151 /* BITUpdateManager.m */; }; 1E49A4791612226D00463151 /* BITUpdateManagerDelegate.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E49A4661612226D00463151 /* BITUpdateManagerDelegate.h */; settings = {ATTRIBUTES = (Public, ); }; }; 1E49A47C1612226D00463151 /* BITUpdateManagerPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E49A4671612226D00463151 /* BITUpdateManagerPrivate.h */; }; - 1E49A47F1612226D00463151 /* BITUpdateViewController.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E49A4681612226D00463151 /* BITUpdateViewController.h */; }; + 1E49A47F1612226D00463151 /* BITUpdateViewController.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E49A4681612226D00463151 /* BITUpdateViewController.h */; settings = {ATTRIBUTES = (Public, ); }; }; 1E49A4821612226D00463151 /* BITUpdateViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 1E49A4691612226D00463151 /* BITUpdateViewController.m */; }; 1E49A4851612226D00463151 /* BITUpdateViewControllerPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E49A46A1612226D00463151 /* BITUpdateViewControllerPrivate.h */; }; 1E49A4AF161222B900463151 /* BITHockeyBaseManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E49A4A0161222B900463151 /* BITHockeyBaseManager.h */; }; @@ -391,15 +391,15 @@ 1E49A4731612226D00463151 /* BITUpdateManager.h in Headers */, 1E49A4791612226D00463151 /* BITUpdateManagerDelegate.h in Headers */, 1E49A44E1612223B00463151 /* BITFeedbackManager.h in Headers */, + 1E49A4481612223B00463151 /* BITFeedbackListViewController.h in Headers */, + 1E49A47F1612226D00463151 /* BITUpdateViewController.h in Headers */, 1E49A43C1612223B00463151 /* BITFeedbackComposeViewController.h in Headers */, 1E49A4421612223B00463151 /* BITFeedbackListViewCell.h in Headers */, - 1E49A4481612223B00463151 /* BITFeedbackListViewController.h in Headers */, 1E49A4541612223B00463151 /* BITFeedbackManagerPrivate.h in Headers */, 1E49A4571612223B00463151 /* BITFeedbackMessage.h in Headers */, 1E49A45D1612223B00463151 /* BITFeedbackUserDataViewController.h in Headers */, 1E49A46D1612226D00463151 /* BITAppVersionMetaInfo.h in Headers */, 1E49A47C1612226D00463151 /* BITUpdateManagerPrivate.h in Headers */, - 1E49A47F1612226D00463151 /* BITUpdateViewController.h in Headers */, 1E49A4851612226D00463151 /* BITUpdateViewControllerPrivate.h in Headers */, 1E49A4AF161222B900463151 /* BITHockeyBaseManager.h in Headers */, 1E49A4B5161222B900463151 /* BITHockeyBaseManagerPrivate.h in Headers */, From c3c17e88f9fb95b78d2b539117160add8bf29719 Mon Sep 17 00:00:00 2001 From: Andreas Linde Date: Sun, 7 Oct 2012 22:43:58 +0200 Subject: [PATCH 021/176] Remove license and readme file from Xcode project, not needed there. --- Support/HockeySDK.xcodeproj/project.pbxproj | 4 ---- 1 file changed, 4 deletions(-) diff --git a/Support/HockeySDK.xcodeproj/project.pbxproj b/Support/HockeySDK.xcodeproj/project.pbxproj index fe13265d..dbe6163b 100644 --- a/Support/HockeySDK.xcodeproj/project.pbxproj +++ b/Support/HockeySDK.xcodeproj/project.pbxproj @@ -191,8 +191,6 @@ E41EB465148D7BF50015DEDC /* BITHockeyManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BITHockeyManager.h; sourceTree = ""; }; E41EB466148D7BF50015DEDC /* BITHockeyManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = BITHockeyManager.m; sourceTree = ""; }; E41EB48B148D7C4E0015DEDC /* CrashReporter.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CrashReporter.framework; path = ../Vendor/CrashReporter.framework; sourceTree = ""; }; - E4E7335A148D7A5A00763A39 /* LICENSE.txt */ = {isa = PBXFileReference; lastKnownFileType = text; name = LICENSE.txt; path = ../LICENSE.txt; sourceTree = ""; }; - E4E7335B148D7A5A00763A39 /* README.md */ = {isa = PBXFileReference; lastKnownFileType = text; name = README.md; path = ../README.md; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -319,8 +317,6 @@ E4005648148D7A3000EB22B9 /* Resources */, 1E66CA8F15D40FF600F35BED /* Support */, E400561B148D79B500EB22B9 /* Products */, - E4E7335A148D7A5A00763A39 /* LICENSE.txt */, - E4E7335B148D7A5A00763A39 /* README.md */, ); sourceTree = ""; }; From 36be3708f24ec02c16339d575392974b3e4db88d Mon Sep 17 00:00:00 2001 From: Andreas Linde Date: Tue, 9 Oct 2012 22:57:27 +0200 Subject: [PATCH 022/176] Some more xcconfig optimizations - Renamed some vars to be more descriptive - Added CONFIGURATION preprocessor --- Support/HockeySDK.xcconfig | 3 ++- Support/HockeySDK.xcodeproj/project.pbxproj | 4 ++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/Support/HockeySDK.xcconfig b/Support/HockeySDK.xcconfig index 7edd7646..b29ea326 100644 --- a/Support/HockeySDK.xcconfig +++ b/Support/HockeySDK.xcconfig @@ -1,2 +1,3 @@ OTHER_LDFLAGS=$(inherited) -ObjC -framework CoreGraphics -framework Foundation -framework QuartzCore -framework SystemConfiguration -weak_framework AdSupport -weak_framework UIKit -APPLEDOC_DOCSET_NAME=HockeySDK-iOS \ No newline at end of file +HOCKEYSDK_DOCSET_NAME=HockeySDK-iOS +GCC_PREPROCESSOR_DEFINITIONS=$(inherited) CONFIGURATION_$(CONFIGURATION) \ No newline at end of file diff --git a/Support/HockeySDK.xcodeproj/project.pbxproj b/Support/HockeySDK.xcodeproj/project.pbxproj index dbe6163b..d28dc30f 100644 --- a/Support/HockeySDK.xcodeproj/project.pbxproj +++ b/Support/HockeySDK.xcodeproj/project.pbxproj @@ -527,7 +527,7 @@ ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "# Sets the target folders and the final framework product.\nFMK_NAME=HockeySDK\nFMK_VERSION=A\nFMK_RESOURCE_BUNDLE=HockeySDKResources\n\n# Documentation\nDOCSET_NAME=\"de.bitstadium.${APPLEDOC_DOCSET_NAME}-${VERSION_STRING}\"\n\n# Install dir will be the final output to the framework.\n# The following line create it in the root folder of the current project.\nPRODUCTS_DIR=${SRCROOT}/../Products\nTEMP_DIR=${PRODUCTS_DIR}/Temp\nINSTALL_DIR=${TEMP_DIR}/${FMK_NAME}.framework\n\n# Working dir will be deleted after the framework creation.\nWRK_DIR=build\nDEVICE_DIR=${WRK_DIR}/Release-iphoneos\nSIMULATOR_DIR=${WRK_DIR}/Release-iphonesimulator\nHEADERS_DIR=${WRK_DIR}/Release-iphoneos/usr/local/include\n\n# Building both architectures.\nxcodebuild -project \"HockeySDK.xcodeproj\" -configuration \"Release\" -target \"${FMK_NAME}\" -sdk iphoneos\nxcodebuild -project \"HockeySDK.xcodeproj\" -configuration \"Release\" -target \"${FMK_NAME}\" -sdk iphonesimulator\n\n# Cleaning the oldest.\nif [ -d \"${TEMP_DIR}\" ]\nthen\nrm -rf \"${TEMP_DIR}\"\nfi\n\n# Creates and renews the final product folder.\nmkdir -p \"${INSTALL_DIR}\"\nmkdir -p \"${INSTALL_DIR}/Versions\"\nmkdir -p \"${INSTALL_DIR}/Versions/${FMK_VERSION}\"\nmkdir -p \"${INSTALL_DIR}/Versions/${FMK_VERSION}/Resources\"\nmkdir -p \"${INSTALL_DIR}/Versions/${FMK_VERSION}/Headers\"\n\n# Creates the internal links.\n# It MUST uses relative path, otherwise will not work when the folder is copied/moved.\nln -s \"${FMK_VERSION}\" \"${INSTALL_DIR}/Versions/Current\"\nln -s \"Versions/Current/Headers\" \"${INSTALL_DIR}/Headers\"\nln -s \"Versions/Current/Resources\" \"${INSTALL_DIR}/Resources\"\nln -s \"Versions/Current/${FMK_NAME}\" \"${INSTALL_DIR}/${FMK_NAME}\"\n\n# Copies the headers and resources files to the final product folder.\ncp -R \"${HEADERS_DIR}/\" \"${INSTALL_DIR}/Versions/${FMK_VERSION}/Headers/\"\ncp -R \"${DEVICE_DIR}/${FMK_RESOURCE_BUNDLE}.bundle\" \"${INSTALL_DIR}/Versions/${FMK_VERSION}/Resources/\"\ncp -f \"${SRCROOT}/${FMK_NAME}.xcconfig\" \"${INSTALL_DIR}/Versions/${FMK_VERSION}/Resources/\"\n\n# Uses the Lipo Tool to merge both binary files (i386 + armv6/armv7) into one Universal final product.\nlipo -create \"${DEVICE_DIR}/lib${FMK_NAME}.a\" \"${SIMULATOR_DIR}/lib${FMK_NAME}.a\" -output \"${INSTALL_DIR}/Versions/${FMK_VERSION}/${FMK_NAME}\"\n\n# Combine the CrashReporter static library into a new Hockey static library file if they are not already present and copy the public headers too\nif [ -z $(otool -L \"${INSTALL_DIR}/Versions/${FMK_VERSION}/${FMK_NAME}\" | grep 'libCrashReporter') ]\nthen\nlibtool -static -o \"${INSTALL_DIR}/Versions/${FMK_VERSION}/${FMK_NAME}\" \"${INSTALL_DIR}/Versions/${FMK_VERSION}/${FMK_NAME}\" \"${SRCROOT}/../Vendor/CrashReporter.framework/Versions/A/CrashReporter\"\ncp -r \\\n\"${SRCROOT}/../Vendor/CrashReporter.framework/Versions/A/Headers/\" \\\n\"${INSTALL_DIR}/Versions/${FMK_VERSION}/Headers/\"\nfi\n\nrm -r \"${WRK_DIR}\"\n\n# build embeddedframework folder and move framework into it\nmkdir \"${INSTALL_DIR}/../${FMK_NAME}.embeddedframework\"\nmv \"${INSTALL_DIR}\" \"${INSTALL_DIR}/../${FMK_NAME}.embeddedframework/${FMK_NAME}.framework\"\n\n# link Resources\nNEW_INSTALL_DIR=${TEMP_DIR}/${FMK_NAME}.embeddedframework\nmkdir \"${NEW_INSTALL_DIR}/Resources\"\nln -s \"../${FMK_NAME}.framework/Resources/${FMK_RESOURCE_BUNDLE}.bundle\" \"${NEW_INSTALL_DIR}/Resources/${FMK_RESOURCE_BUNDLE}.bundle\"\nln -s \"../${FMK_NAME}.framework/Resources/${FMK_NAME}.xcconfig\" \"${NEW_INSTALL_DIR}/Resources/${FMK_NAME}.xcconfig\"\n\n# copy license, changelog, documentation\ncp -f \"${SRCROOT}/../Docs/Changelog-template.md\" \"${TEMP_DIR}/CHANGELOG\"\ncp -f \"${SRCROOT}/../LICENSE\" \"${TEMP_DIR}\"\nmkdir \"${TEMP_DIR}/${DOCSET_NAME}.docset\"\ncp -R \"${SRCROOT}/../documentation/docset/Contents\" \"${TEMP_DIR}/${DOCSET_NAME}.docset\"\n\n# build zip\ncd \"${PRODUCTS_DIR}\"\nrm -f \"${FMK_NAME}-iOS-${VERSION_STRING}.zip\"\ncd \"${TEMP_DIR}\"\nzip -yr \"../${FMK_NAME}-iOS-${VERSION_STRING}.zip\" \"./${FMK_NAME}.embeddedframework\" \"./CHANGELOG\" \"./LICENSE\" \"./${DOCSET_NAME}.docset\" -x \\*/.*\n"; + shellScript = "# Sets the target folders and the final framework product.\nFMK_NAME=HockeySDK\nFMK_VERSION=A\nFMK_RESOURCE_BUNDLE=HockeySDKResources\n\n# Documentation\nHOCKEYSDK_DOCSET_VERSION_NAME=\"de.bitstadium.${HOCKEYSDK_DOCSET_NAME}-${VERSION_STRING}\"\n\n# Install dir will be the final output to the framework.\n# The following line create it in the root folder of the current project.\nPRODUCTS_DIR=${SRCROOT}/../Products\nTEMP_DIR=${PRODUCTS_DIR}/Temp\nINSTALL_DIR=${TEMP_DIR}/${FMK_NAME}.framework\n\n# Working dir will be deleted after the framework creation.\nWRK_DIR=build\nDEVICE_DIR=${WRK_DIR}/Release-iphoneos\nSIMULATOR_DIR=${WRK_DIR}/Release-iphonesimulator\nHEADERS_DIR=${WRK_DIR}/Release-iphoneos/usr/local/include\n\n# Building both architectures.\nxcodebuild -project \"HockeySDK.xcodeproj\" -configuration \"Release\" -target \"${FMK_NAME}\" -sdk iphoneos\nxcodebuild -project \"HockeySDK.xcodeproj\" -configuration \"Release\" -target \"${FMK_NAME}\" -sdk iphonesimulator\n\n# Cleaning the oldest.\nif [ -d \"${TEMP_DIR}\" ]\nthen\nrm -rf \"${TEMP_DIR}\"\nfi\n\n# Creates and renews the final product folder.\nmkdir -p \"${INSTALL_DIR}\"\nmkdir -p \"${INSTALL_DIR}/Versions\"\nmkdir -p \"${INSTALL_DIR}/Versions/${FMK_VERSION}\"\nmkdir -p \"${INSTALL_DIR}/Versions/${FMK_VERSION}/Resources\"\nmkdir -p \"${INSTALL_DIR}/Versions/${FMK_VERSION}/Headers\"\n\n# Creates the internal links.\n# It MUST uses relative path, otherwise will not work when the folder is copied/moved.\nln -s \"${FMK_VERSION}\" \"${INSTALL_DIR}/Versions/Current\"\nln -s \"Versions/Current/Headers\" \"${INSTALL_DIR}/Headers\"\nln -s \"Versions/Current/Resources\" \"${INSTALL_DIR}/Resources\"\nln -s \"Versions/Current/${FMK_NAME}\" \"${INSTALL_DIR}/${FMK_NAME}\"\n\n# Copies the headers and resources files to the final product folder.\ncp -R \"${HEADERS_DIR}/\" \"${INSTALL_DIR}/Versions/${FMK_VERSION}/Headers/\"\ncp -R \"${DEVICE_DIR}/${FMK_RESOURCE_BUNDLE}.bundle\" \"${INSTALL_DIR}/Versions/${FMK_VERSION}/Resources/\"\ncp -f \"${SRCROOT}/${FMK_NAME}.xcconfig\" \"${INSTALL_DIR}/Versions/${FMK_VERSION}/Resources/\"\n\n# Uses the Lipo Tool to merge both binary files (i386 + armv6/armv7) into one Universal final product.\nlipo -create \"${DEVICE_DIR}/lib${FMK_NAME}.a\" \"${SIMULATOR_DIR}/lib${FMK_NAME}.a\" -output \"${INSTALL_DIR}/Versions/${FMK_VERSION}/${FMK_NAME}\"\n\n# Combine the CrashReporter static library into a new Hockey static library file if they are not already present and copy the public headers too\nif [ -z $(otool -L \"${INSTALL_DIR}/Versions/${FMK_VERSION}/${FMK_NAME}\" | grep 'libCrashReporter') ]\nthen\nlibtool -static -o \"${INSTALL_DIR}/Versions/${FMK_VERSION}/${FMK_NAME}\" \"${INSTALL_DIR}/Versions/${FMK_VERSION}/${FMK_NAME}\" \"${SRCROOT}/../Vendor/CrashReporter.framework/Versions/A/CrashReporter\"\ncp -r \\\n\"${SRCROOT}/../Vendor/CrashReporter.framework/Versions/A/Headers/\" \\\n\"${INSTALL_DIR}/Versions/${FMK_VERSION}/Headers/\"\nfi\n\nrm -r \"${WRK_DIR}\"\n\n# build embeddedframework folder and move framework into it\nmkdir \"${INSTALL_DIR}/../${FMK_NAME}.embeddedframework\"\nmv \"${INSTALL_DIR}\" \"${INSTALL_DIR}/../${FMK_NAME}.embeddedframework/${FMK_NAME}.framework\"\n\n# link Resources\nNEW_INSTALL_DIR=${TEMP_DIR}/${FMK_NAME}.embeddedframework\nmkdir \"${NEW_INSTALL_DIR}/Resources\"\nln -s \"../${FMK_NAME}.framework/Resources/${FMK_RESOURCE_BUNDLE}.bundle\" \"${NEW_INSTALL_DIR}/Resources/${FMK_RESOURCE_BUNDLE}.bundle\"\nln -s \"../${FMK_NAME}.framework/Resources/${FMK_NAME}.xcconfig\" \"${NEW_INSTALL_DIR}/Resources/${FMK_NAME}.xcconfig\"\n\n# copy license, changelog, documentation\ncp -f \"${SRCROOT}/../Docs/Changelog-template.md\" \"${TEMP_DIR}/CHANGELOG\"\ncp -f \"${SRCROOT}/../LICENSE\" \"${TEMP_DIR}\"\nmkdir \"${TEMP_DIR}/${HOCKEYSDK_DOCSET_VERSION_NAME}.docset\"\ncp -R \"${SRCROOT}/../documentation/docset/Contents\" \"${TEMP_DIR}/${HOCKEYSDK_DOCSET_VERSION_NAME}.docset\"\n\n# build zip\ncd \"${PRODUCTS_DIR}\"\nrm -f \"${FMK_NAME}-iOS-${VERSION_STRING}.zip\"\ncd \"${TEMP_DIR}\"\nzip -yr \"../${FMK_NAME}-iOS-${VERSION_STRING}.zip\" \"./${FMK_NAME}.embeddedframework\" \"./CHANGELOG\" \"./LICENSE\" \"./${HOCKEYSDK_DOCSET_VERSION_NAME}.docset\" -x \\*/.*\n"; }; 1E8E66B215BC3D8200632A2E /* ShellScript */ = { isa = PBXShellScriptBuildPhase; @@ -540,7 +540,7 @@ ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "DOCSETNAME=\"de.bitstadium.${APPLEDOC_DOCSET_NAME}-${VERSION_STRING}\"\n\n/usr/local/bin/appledoc \\\n --output \"${SOURCE_ROOT}/../documentation\" \\\n --ignore Vendor \\\n --ignore .m \\\n --create-html \\\n --create-docset \\\n --install-docset \\\n --keep-intermediate-files \\\n --project-name \"${APPLEDOC_DOCSET_NAME} ${VERSION_STRING}\" \\\n --project-version \"${VERSION_STRING}\" \\\n --project-company \"BitStadium GmbH\" \\\n --company-id \"de.bitstadium\" \\\n --docset-bundle-name \"${APPLEDOC_DOCSET_NAME} ${VERSION_STRING}\" \\\n --docset-feed-name \"${APPLEDOC_DOCSET_NAME}\" \\\n --docset-platform-family \"iphoneos\" \\\n --index-desc \"${SOURCE_ROOT}/../docs/index.md\" \\\n --include \"${SOURCE_ROOT}/../docs/\" \\\n --merge-categories \\\n --no-repeat-first-par \\\n --warn-undocumented-object \\\n --warn-undocumented-member \\\n --warn-empty-description \\\n --warn-unknown-directive \\\n --warn-invalid-crossref \\\n --warn-missing-arg \\\n --logformat xcode \\\n --exit-threshold 2 \\\n \"${SOURCE_ROOT}/../\" \\\n"; + shellScript = "/usr/local/bin/appledoc \\\n --output \"${SOURCE_ROOT}/../documentation\" \\\n --ignore Vendor \\\n --ignore .m \\\n --create-html \\\n --create-docset \\\n --install-docset \\\n --keep-intermediate-files \\\n --project-name \"${HOCKEYSDK_DOCSET_NAME} ${VERSION_STRING}\" \\\n --project-version \"${VERSION_STRING}\" \\\n --project-company \"BitStadium GmbH\" \\\n --company-id \"de.bitstadium\" \\\n --docset-bundle-name \"${HOCKEYSDK_DOCSET_NAME} ${VERSION_STRING}\" \\\n --docset-feed-name \"${HOCKEYSDK_DOCSET_NAME}\" \\\n --docset-platform-family \"iphoneos\" \\\n --index-desc \"${SOURCE_ROOT}/../docs/index.md\" \\\n --include \"${SOURCE_ROOT}/../docs/\" \\\n --merge-categories \\\n --no-repeat-first-par \\\n --warn-undocumented-object \\\n --warn-undocumented-member \\\n --warn-empty-description \\\n --warn-unknown-directive \\\n --warn-invalid-crossref \\\n --warn-missing-arg \\\n --logformat xcode \\\n --exit-threshold 2 \\\n \"${SOURCE_ROOT}/../\" \\\n"; }; /* End PBXShellScriptBuildPhase section */ From f34d458d95d1aff69abdfe92ed8682261b941b2e Mon Sep 17 00:00:00 2001 From: Andreas Linde Date: Thu, 11 Oct 2012 16:56:02 +0200 Subject: [PATCH 023/176] Fix iOS6 reloading activity with no messages present to never stop --- Classes/BITFeedbackManager.m | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Classes/BITFeedbackManager.m b/Classes/BITFeedbackManager.m index 9e338335..6ab8bdfb 100644 --- a/Classes/BITFeedbackManager.m +++ b/Classes/BITFeedbackManager.m @@ -660,6 +660,9 @@ - (void)sendNetworkRequestWithHTTPMethod:(NSString *)httpMethod withText:(NSStri - (void)fetchMessageUpdates { if ([_feedbackList count] == 0) { + // inform the UI to update its data in case the list is already showing + [[NSNotificationCenter defaultCenter] postNotificationName:BITHockeyFeedbackMessagesLoadingFinished object:nil]; + return; } From 1887ee7501b005e9225ebfd9a6d814490d765aa3 Mon Sep 17 00:00:00 2001 From: Andreas Linde Date: Fri, 12 Oct 2012 16:56:17 +0200 Subject: [PATCH 024/176] Also use old delegates in CrashManager for username and email if present, but mark them as deprecated --- Classes/BITCrashManager.m | 93 +++++++++++++++--------------- Classes/BITCrashManagerDelegate.h | 26 +++++++++ Classes/BITHockeyManagerDelegate.h | 12 ++-- 3 files changed, 78 insertions(+), 53 deletions(-) diff --git a/Classes/BITCrashManager.m b/Classes/BITCrashManager.m index e55cfab1..f4141ebd 100644 --- a/Classes/BITCrashManager.m +++ b/Classes/BITCrashManager.m @@ -264,6 +264,46 @@ - (NSString *)getDevicePlatform { } +- (NSString *)userNameForCrashReport { + NSString *username = @""; + + if (self.delegate && [self.delegate respondsToSelector:@selector(userNameForCrashManager:)]) { + BITHockeyLog(@"DEPRECATED: Please user BITHockeyManagerDelegate's userNameForHockeyManager:componentManager: or userIDForHockeyManager:componentManager: instead."); + username = [self.delegate userNameForCrashManager:self]; + } + if ([BITHockeyManager sharedHockeyManager].delegate && + [[BITHockeyManager sharedHockeyManager].delegate respondsToSelector:@selector(userNameForHockeyManager:componentManager:)]) { + username = [[BITHockeyManager sharedHockeyManager].delegate + userNameForHockeyManager:[BITHockeyManager sharedHockeyManager] + componentManager:self]; + } + if ([BITHockeyManager sharedHockeyManager].delegate && + [[BITHockeyManager sharedHockeyManager].delegate respondsToSelector:@selector(userIDForHockeyManager:componentManager:)]) { + username = [[BITHockeyManager sharedHockeyManager].delegate + userIDForHockeyManager:[BITHockeyManager sharedHockeyManager] + componentManager:self]; + } + + return username; +} + +- (NSString *)userEmailForCrashReport { + NSString *useremail = @""; + + if (self.delegate && [self.delegate respondsToSelector:@selector(userEmailForCrashManager:)]) { + BITHockeyLog(@"DEPRECATED: Please user BITHockeyManagerDelegate's userEmailForHockeyManager:componentManager: instead."); + useremail = [self.delegate userEmailForCrashManager:self]; + } + if ([BITHockeyManager sharedHockeyManager].delegate && + [[BITHockeyManager sharedHockeyManager].delegate respondsToSelector:@selector(userEmailForHockeyManager:componentManager:)]) { + useremail = [[BITHockeyManager sharedHockeyManager].delegate + userEmailForHockeyManager:[BITHockeyManager sharedHockeyManager] + componentManager:self]; + } + + return useremail; +} + #pragma mark - PLCrashReporter // Called to handle a pending crash report. @@ -292,32 +332,11 @@ - (void) handleCrashReport { // write the meta file NSMutableDictionary *metaDict = [NSMutableDictionary dictionaryWithCapacity:4]; - NSString *username = @""; - NSString *useremail = @""; NSString *applicationLog = @""; NSString *errorString = nil; - if ([BITHockeyManager sharedHockeyManager].delegate && - [[BITHockeyManager sharedHockeyManager].delegate respondsToSelector:@selector(userNameForHockeyManager:componentManager:)]) { - username = [[BITHockeyManager sharedHockeyManager].delegate - userNameForHockeyManager:[BITHockeyManager sharedHockeyManager] - componentManager:self]; - } - if ([BITHockeyManager sharedHockeyManager].delegate && - [[BITHockeyManager sharedHockeyManager].delegate respondsToSelector:@selector(userIDForHockeyManager:componentManager:)]) { - username = [[BITHockeyManager sharedHockeyManager].delegate - userIDForHockeyManager:[BITHockeyManager sharedHockeyManager] - componentManager:self]; - } - [metaDict setObject:username forKey:kBITCrashMetaUserName]; - - if ([BITHockeyManager sharedHockeyManager].delegate && - [[BITHockeyManager sharedHockeyManager].delegate respondsToSelector:@selector(userEmailForHockeyManager:componentManager:)]) { - useremail = [[BITHockeyManager sharedHockeyManager].delegate - userEmailForHockeyManager:[BITHockeyManager sharedHockeyManager] - componentManager:self]; - } - [metaDict setObject:useremail forKey:kBITCrashMetaUserEmail]; + [metaDict setObject:[self userNameForCrashReport] forKey:kBITCrashMetaUserName]; + [metaDict setObject:[self userEmailForCrashReport] forKey:kBITCrashMetaUserEmail]; if (self.delegate != nil && [self.delegate respondsToSelector:@selector(applicationLogForCrashManager:)]) { applicationLog = [self.delegate applicationLogForCrashManager:self] ?: @""; @@ -429,30 +448,10 @@ - (void)invokeDelayedProcessing { NSString *alertDescription = [NSString stringWithFormat:BITHockeyLocalizedString(@"CrashDataFoundAnonymousDescription"), appName]; // the crash report is not anynomous any more if username or useremail are not nil - NSString *username = nil; - NSString *useremail = nil; - - if ([BITHockeyManager sharedHockeyManager].delegate && - [[BITHockeyManager sharedHockeyManager].delegate respondsToSelector:@selector(userNameForHockeyManager:componentManager:)]) { - username = [[BITHockeyManager sharedHockeyManager].delegate - userNameForHockeyManager:[BITHockeyManager sharedHockeyManager] - componentManager:self]; - } - if ([BITHockeyManager sharedHockeyManager].delegate && - [[BITHockeyManager sharedHockeyManager].delegate respondsToSelector:@selector(userIDForHockeyManager:componentManager:)]) { - username = [[BITHockeyManager sharedHockeyManager].delegate - userIDForHockeyManager:[BITHockeyManager sharedHockeyManager] - componentManager:self]; - } - - if ([BITHockeyManager sharedHockeyManager].delegate && - [[BITHockeyManager sharedHockeyManager].delegate respondsToSelector:@selector(userEmailForHockeyManager:componentManager:)]) { - useremail = [[BITHockeyManager sharedHockeyManager].delegate - userEmailForHockeyManager:[BITHockeyManager sharedHockeyManager] - componentManager:self]; - } - - if (username || useremail) { + NSString *username = [self userNameForCrashReport]; + NSString *useremail = [self userEmailForCrashReport]; + + if ((username && [username length] > 0) || (useremail && [useremail length] > 0)) { alertDescription = [NSString stringWithFormat:BITHockeyLocalizedString(@"CrashDataFoundDescription"), appName]; } diff --git a/Classes/BITCrashManagerDelegate.h b/Classes/BITCrashManagerDelegate.h index a2cada6f..243f4299 100644 --- a/Classes/BITCrashManagerDelegate.h +++ b/Classes/BITCrashManagerDelegate.h @@ -54,6 +54,32 @@ +/** Return the user name or userid that should be send along each crash report + + @param crashManager The `BITCrashManager` instance invoking this delegate + @see applicationLogForCrashManager: + @see userEmailForCrashManager: + @deprecated Please use `BITHockeyManagerDelegate userNameForHockeyManager:componentManager:` instead + @warning When returning a non nil value, crash reports are not anonymous any + more and the alerts will not show the "anonymous" word! + */ +-(NSString *)userNameForCrashManager:(BITCrashManager *)crashManager; + + + +/** Return the users email address that should be send along each crash report + + @param crashManager The `BITCrashManager` instance invoking this delegate + @see applicationLogForCrashManager: + @see userNameForCrashManager: + @deprecated Please use `BITHockeyManagerDelegate userEmailForHockeyManager:componentManager:` instead + @warning When returning a non nil value, crash reports are not anonymous any + more and the alerts will not show the "anonymous" word! + */ +-(NSString *)userEmailForCrashManager:(BITCrashManager *)crashManager; + + + ///----------------------------------------------------------------------------- /// @name Alert ///----------------------------------------------------------------------------- diff --git a/Classes/BITHockeyManagerDelegate.h b/Classes/BITHockeyManagerDelegate.h index 82d57219..032ca103 100644 --- a/Classes/BITHockeyManagerDelegate.h +++ b/Classes/BITHockeyManagerDelegate.h @@ -94,8 +94,8 @@ @param hockeyManager The `BITHockeyManager` HockeyManager instance invoking this delegate @param componentManager The `BITHockeyBaseManager` component instance invoking this delegate - @see userNameForHockeyManager: - @see userEmailForHockeyManager: + @see userNameForHockeyManager:componentManager: + @see userEmailForHockeyManager:componentManager: @warning When returning a non nil value for the `BITCrashManager` component, crash reports are not anonymous any more and the crash alerts will not show the word "anonymous"! */ @@ -121,8 +121,8 @@ @param hockeyManager The `BITHockeyManager` HockeyManager instance invoking this delegate @param componentManager The `BITHockeyBaseManager` component instance invoking this delegate - @see userIDForHockeyManager: - @see userEmailForHockeyManager: + @see userIDForHockeyManager:componentManager: + @see userEmailForHockeyManager:componentManager: @warning When returning a non nil value for the `BITCrashManager` component, crash reports are not anonymous any more and the crash alerts will not show the word "anonymous"! */ @@ -148,8 +148,8 @@ @param hockeyManager The `BITHockeyManager` HockeyManager instance invoking this delegate @param componentManager The `BITHockeyBaseManager` component instance invoking this delegate - @see userIDForHockeyManager: - @see userNameForHockeyManager: + @see userIDForHockeyManager:componentManager: + @see userNameForHockeyManager:componentManager: @warning When returning a non nil value for the `BITCrashManager` component, crash reports are not anonymous any more and the crash alerts will not show the word "anonymous"! */ From be048007593f6e8b24521a8aea0a128cfb3d98b8 Mon Sep 17 00:00:00 2001 From: Andreas Linde Date: Fri, 12 Oct 2012 18:14:22 +0200 Subject: [PATCH 025/176] Various feedback related bug fixes --- Classes/BITFeedbackListViewCell.m | 7 ++++++- Classes/BITFeedbackListViewController.m | 2 +- Classes/BITFeedbackManager.m | 9 ++------- Resources/de.lproj/HockeySDK.strings | 3 +++ Resources/en.lproj/HockeySDK.strings | 3 +++ Resources/es.lproj/HockeySDK.strings | 3 +++ Resources/fr.lproj/HockeySDK.strings | 3 +++ Resources/it.lproj/HockeySDK.strings | 3 +++ Resources/ja.lproj/HockeySDK.strings | 3 +++ Resources/nl.lproj/HockeySDK.strings | 3 +++ Resources/pt-PT.lproj/HockeySDK.strings | 3 +++ Resources/pt.lproj/HockeySDK.strings | 3 +++ Resources/ru.lproj/HockeySDK.strings | 3 +++ Resources/sv.lproj/HockeySDK.strings | 3 +++ Resources/tr.lproj/HockeySDK.strings | 3 +++ Resources/zh_CN.lproj/HockeySDK.strings | 3 +++ Resources/zh_TW.lproj/HockeySDK.strings | 3 +++ 17 files changed, 51 insertions(+), 9 deletions(-) diff --git a/Classes/BITFeedbackListViewCell.m b/Classes/BITFeedbackListViewCell.m index 325fdf50..e8a5115d 100644 --- a/Classes/BITFeedbackListViewCell.m +++ b/Classes/BITFeedbackListViewCell.m @@ -136,7 +136,12 @@ - (void)layoutSubviews { } // header - NSString *dateString = [self.dateFormatter stringFromDate:self.date]; + NSString *dateString; + if (self.date) { + dateString = [self.dateFormatter stringFromDate:self.date]; + } else { + dateString = BITHockeyLocalizedString(@"Pending"); + } [self.labelTitle setText:dateString];// [self.date description]]; [self.labelTitle setFrame:CGRectMake(FRAME_SIDE_BORDER, FRAME_TOP_BORDER + LABEL_TITLE_Y, self.frame.size.width - (2 * FRAME_SIDE_BORDER), LABEL_TITLE_HEIGHT)]; diff --git a/Classes/BITFeedbackListViewController.m b/Classes/BITFeedbackListViewController.m index 8a586149..c422a07d 100644 --- a/Classes/BITFeedbackListViewController.m +++ b/Classes/BITFeedbackListViewController.m @@ -150,7 +150,7 @@ - (void)updateList { [self stopLoadingIndicator]; [self.tableView reloadData]; - if (self.tableView.contentSize.height > contentSize.height) + if (contentSize.height > 0 && self.tableView.contentSize.height > contentSize.height) [self.tableView setContentOffset:CGPointMake(contentOffset.x, self.tableView.contentSize.height - contentSize.height + contentOffset.y) animated:NO]; [self.tableView flashScrollIndicators]; diff --git a/Classes/BITFeedbackManager.m b/Classes/BITFeedbackManager.m index 6ab8bdfb..42e85545 100644 --- a/Classes/BITFeedbackManager.m +++ b/Classes/BITFeedbackManager.m @@ -266,12 +266,6 @@ - (void)loadMessages { if ([unarchiver containsValueForKey:kBITFeedbackToken]) self.token = [unarchiver decodeObjectForKey:kBITFeedbackToken]; - if ([unarchiver containsValueForKey:kBITFeedbackName]) - self.userName = [unarchiver decodeObjectForKey:kBITFeedbackName]; - - if ([unarchiver containsValueForKey:kBITFeedbackEmail]) - self.userEmail = [unarchiver decodeObjectForKey:kBITFeedbackEmail]; - if ([unarchiver containsValueForKey:kBITFeedbackDateOfLastCheck]) self.lastCheck = [unarchiver decodeObjectForKey:kBITFeedbackDateOfLastCheck]; @@ -617,6 +611,7 @@ - (void)sendNetworkRequestWithHTTPMethod:(NSString *)httpMethod withText:(NSStri _networkRequestInProgress = NO; if (err) { + [self reportError:err]; [self markSendInProgressMessagesAsPending]; completionHandler(err); } else { @@ -693,7 +688,7 @@ - (void)submitPendingMessages { if (self.userName) [messageToSend setName:self.userName]; if (self.userEmail) - [messageToSend setName:self.userEmail]; + [messageToSend setEmail:self.userEmail]; NSString *httpMethod = @"POST"; if ([self token]) { diff --git a/Resources/de.lproj/HockeySDK.strings b/Resources/de.lproj/HockeySDK.strings index 8544e1ac..50ce218c 100755 --- a/Resources/de.lproj/HockeySDK.strings +++ b/Resources/de.lproj/HockeySDK.strings @@ -164,6 +164,9 @@ /* Name In Message From Server If Name Not Set */ "HockeyFeedbackListmessageResponseNameNotSet" = "Response"; +/* Message pending to be send */ +"HockeyFeedbackListMessagePending" = "Pending"; + /* Compose Message */ diff --git a/Resources/en.lproj/HockeySDK.strings b/Resources/en.lproj/HockeySDK.strings index 16b5278f..34263a69 100755 --- a/Resources/en.lproj/HockeySDK.strings +++ b/Resources/en.lproj/HockeySDK.strings @@ -161,6 +161,9 @@ /* Name In Message From Server If Name Not Set */ "HockeyFeedbackListmessageResponseNameNotSet" = "Response"; +/* Message pending to be send */ +"HockeyFeedbackListMessagePending" = "Pending"; + /* Compose Message */ diff --git a/Resources/es.lproj/HockeySDK.strings b/Resources/es.lproj/HockeySDK.strings index a1707823..ab166f20 100755 --- a/Resources/es.lproj/HockeySDK.strings +++ b/Resources/es.lproj/HockeySDK.strings @@ -162,6 +162,9 @@ /* Name In Message From Server If Name Not Set */ "HockeyFeedbackListmessageResponseNameNotSet" = "Response"; +/* Message pending to be send */ +"HockeyFeedbackListMessagePending" = "Pending"; + /* Compose Message */ diff --git a/Resources/fr.lproj/HockeySDK.strings b/Resources/fr.lproj/HockeySDK.strings index c33d8265..76d685d2 100755 --- a/Resources/fr.lproj/HockeySDK.strings +++ b/Resources/fr.lproj/HockeySDK.strings @@ -162,6 +162,9 @@ /* Name In Message From Server If Name Not Set */ "HockeyFeedbackListmessageResponseNameNotSet" = "Response"; +/* Message pending to be send */ +"HockeyFeedbackListMessagePending" = "Pending"; + /* Compose Message */ diff --git a/Resources/it.lproj/HockeySDK.strings b/Resources/it.lproj/HockeySDK.strings index 38ad4f9b..54319358 100755 --- a/Resources/it.lproj/HockeySDK.strings +++ b/Resources/it.lproj/HockeySDK.strings @@ -162,6 +162,9 @@ /* Name In Message From Server If Name Not Set */ "HockeyFeedbackListmessageResponseNameNotSet" = "Response"; +/* Message pending to be send */ +"HockeyFeedbackListMessagePending" = "Pending"; + /* Compose Message */ diff --git a/Resources/ja.lproj/HockeySDK.strings b/Resources/ja.lproj/HockeySDK.strings index 727c74d0..5c57b5a4 100755 --- a/Resources/ja.lproj/HockeySDK.strings +++ b/Resources/ja.lproj/HockeySDK.strings @@ -162,6 +162,9 @@ /* Name In Message From Server If Name Not Set */ "HockeyFeedbackListmessageResponseNameNotSet" = "Response"; +/* Message pending to be send */ +"HockeyFeedbackListMessagePending" = "Pending"; + /* Compose Message */ diff --git a/Resources/nl.lproj/HockeySDK.strings b/Resources/nl.lproj/HockeySDK.strings index 18db296c..827eed53 100755 --- a/Resources/nl.lproj/HockeySDK.strings +++ b/Resources/nl.lproj/HockeySDK.strings @@ -162,6 +162,9 @@ /* Name In Message From Server If Name Not Set */ "HockeyFeedbackListmessageResponseNameNotSet" = "Response"; +/* Message pending to be send */ +"HockeyFeedbackListMessagePending" = "Pending"; + /* Compose Message */ diff --git a/Resources/pt-PT.lproj/HockeySDK.strings b/Resources/pt-PT.lproj/HockeySDK.strings index a58a2e0d..e36f78cb 100755 --- a/Resources/pt-PT.lproj/HockeySDK.strings +++ b/Resources/pt-PT.lproj/HockeySDK.strings @@ -162,6 +162,9 @@ /* Name In Message From Server If Name Not Set */ "HockeyFeedbackListmessageResponseNameNotSet" = "Response"; +/* Message pending to be send */ +"HockeyFeedbackListMessagePending" = "Pending"; + /* Compose Message */ diff --git a/Resources/pt.lproj/HockeySDK.strings b/Resources/pt.lproj/HockeySDK.strings index 2e71290b..3b7ffb94 100755 --- a/Resources/pt.lproj/HockeySDK.strings +++ b/Resources/pt.lproj/HockeySDK.strings @@ -162,6 +162,9 @@ /* Name In Message From Server If Name Not Set */ "HockeyFeedbackListmessageResponseNameNotSet" = "Response"; +/* Message pending to be send */ +"HockeyFeedbackListMessagePending" = "Pending"; + /* Compose Message */ diff --git a/Resources/ru.lproj/HockeySDK.strings b/Resources/ru.lproj/HockeySDK.strings index 516e0127..5dc296e0 100755 --- a/Resources/ru.lproj/HockeySDK.strings +++ b/Resources/ru.lproj/HockeySDK.strings @@ -162,6 +162,9 @@ /* Name In Message From Server If Name Not Set */ "HockeyFeedbackListmessageResponseNameNotSet" = "Response"; +/* Message pending to be send */ +"HockeyFeedbackListMessagePending" = "Pending"; + /* Compose Message */ diff --git a/Resources/sv.lproj/HockeySDK.strings b/Resources/sv.lproj/HockeySDK.strings index e4d07bde..ec760115 100755 --- a/Resources/sv.lproj/HockeySDK.strings +++ b/Resources/sv.lproj/HockeySDK.strings @@ -162,6 +162,9 @@ /* Name In Message From Server If Name Not Set */ "HockeyFeedbackListmessageResponseNameNotSet" = "Response"; +/* Message pending to be send */ +"HockeyFeedbackListMessagePending" = "Pending"; + /* Compose Message */ diff --git a/Resources/tr.lproj/HockeySDK.strings b/Resources/tr.lproj/HockeySDK.strings index 356e66a6..cd06bebb 100644 --- a/Resources/tr.lproj/HockeySDK.strings +++ b/Resources/tr.lproj/HockeySDK.strings @@ -162,6 +162,9 @@ /* Name In Message From Server If Name Not Set */ "HockeyFeedbackListmessageResponseNameNotSet" = "Response"; +/* Message pending to be send */ +"HockeyFeedbackListMessagePending" = "Pending"; + /* Compose Message */ diff --git a/Resources/zh_CN.lproj/HockeySDK.strings b/Resources/zh_CN.lproj/HockeySDK.strings index 6edb4c7c..8f5ebe2e 100644 --- a/Resources/zh_CN.lproj/HockeySDK.strings +++ b/Resources/zh_CN.lproj/HockeySDK.strings @@ -162,6 +162,9 @@ /* Name In Message From Server If Name Not Set */ "HockeyFeedbackListmessageResponseNameNotSet" = "Response"; +/* Message pending to be send */ +"HockeyFeedbackListMessagePending" = "Pending"; + /* Compose Message */ diff --git a/Resources/zh_TW.lproj/HockeySDK.strings b/Resources/zh_TW.lproj/HockeySDK.strings index 8dde94bb..1312b3c9 100644 --- a/Resources/zh_TW.lproj/HockeySDK.strings +++ b/Resources/zh_TW.lproj/HockeySDK.strings @@ -162,6 +162,9 @@ /* Name In Message From Server If Name Not Set */ "HockeyFeedbackListmessageResponseNameNotSet" = "Response"; +/* Message pending to be send */ +"HockeyFeedbackListMessagePending" = "Pending"; + /* Compose Message */ From f8cb400a928c49c7b868aabb200c23adedb54b09 Mon Sep 17 00:00:00 2001 From: Andreas Linde Date: Mon, 15 Oct 2012 00:03:08 +0200 Subject: [PATCH 026/176] Improve documentation --- Classes/BITCrashManager.h | 14 +++++++------- Classes/BITHockeyManager.h | 9 +++++++++ Classes/BITUpdateManager.h | 3 +++ 3 files changed, 19 insertions(+), 7 deletions(-) diff --git a/Classes/BITCrashManager.h b/Classes/BITCrashManager.h index 777bc711..d6361d96 100644 --- a/Classes/BITCrashManager.h +++ b/Classes/BITCrashManager.h @@ -59,11 +59,11 @@ static NSString *kBITCrashManagerStatus = @"BITCrashManagerStatus"; additional textual log information via `BITCrashManagerDelegate` protocol and a way to detect startup crashes so you can adjust your startup process to get these crash reports too and delay your app initialization. - Crashes are send the next time the app starts. If `autoSubmitCrashReport` is enabled, crashes will be send - without any user interaction, otherwise an alert will appear allowing the users to decide wether they want - to send the report or not. This module is not sending the reports right when the crash happens deliberately, - because if is not safe to implement such a mechanism while being async-safe (any Objective-C code is _NOT_ - async-safe!) and not causing more danger like a deadlock of the device, than helping. We found that users + Crashes are send the next time the app starts. If `crashManagerStatus` is set to `BITCrashManagerStatusAutoSend`, + crashes will be send without any user interaction, otherwise an alert will appear allowing the users to decide + wether they want to send the report or not. This module is not sending the reports right when the crash happens + deliberately, because if is not safe to implement such a mechanism while being async-safe (any Objective-C code + is _NOT_ async-safe!) and not causing more danger like a deadlock of the device, than helping. We found that users do start the app again because most don't know what happened, and you will get by far most of the reports. Sending the reports on startup is done asynchronously (non-blocking). This is the only safe way to ensure @@ -127,8 +127,8 @@ static NSString *kBITCrashManagerStatus = @"BITCrashManagerStatus"; If enabled the crash reporting alert will also present an "Always" option, so the user doesn't have to approve every single crash over and over again. - If `autoSubmitCrashReport` is enabled, this property has no effect, since no - alert will be presented. + If If `crashManagerStatus` is set to `BITCrashManagerStatusAutoSend`, this property + has no effect, since no alert will be presented. @warning This will cause the dialog not to show the alert description text landscape mode! @see crashManagerStatus diff --git a/Classes/BITHockeyManager.h b/Classes/BITHockeyManager.h index bf425b84..86f3d4d8 100644 --- a/Classes/BITHockeyManager.h +++ b/Classes/BITHockeyManager.h @@ -124,6 +124,15 @@ liveIdentifier:@"" delegate:nil]; + We recommend using one app entry on HockeyApp for your beta versions and another one for + your live versions. The reason is that you will have way more beta versions than live + versions, but on the other side get way more crash reports on the live version. Separating + them into two different app entries makes it easier to work with the data. In addition + you will likely end up having the same version number for a beta and live version which + would mix different data into the same version. Also the live version does not require + you to upload any IPA files, uploading only the dSYM package for crash reporting is + just fine. + @see configureWithIdentifier:delegate: @see startManager @see BITHockeyManagerDelegate diff --git a/Classes/BITUpdateManager.h b/Classes/BITUpdateManager.h index 656f8d07..2554d243 100644 --- a/Classes/BITUpdateManager.h +++ b/Classes/BITUpdateManager.h @@ -62,6 +62,9 @@ typedef enum { This modul handles version updates, presents update and version information in a App Store like user interface, collects usage information and provides additional authorization options when using Ad-Hoc provisioning profiles. + This module automatically disables itself when running in an App Store build by default! If you integrate the + Atlassian JMC client this module is used to automatically configure JMC, but will not do anything else. + To use this module, it is important to implement set the `delegate` property and implement `[BITUpdateManagerDelegate customDeviceIdentifierForUpdateManager:]`. From b47cbf78c88d1a1556e295f0ec39a6bf2199ee86 Mon Sep 17 00:00:00 2001 From: Andreas Linde Date: Mon, 15 Oct 2012 00:03:25 +0200 Subject: [PATCH 027/176] Fix modal views not having a done button --- Classes/BITHockeyBaseViewController.m | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/Classes/BITHockeyBaseViewController.m b/Classes/BITHockeyBaseViewController.m index 630e8220..98e80ccf 100644 --- a/Classes/BITHockeyBaseViewController.m +++ b/Classes/BITHockeyBaseViewController.m @@ -25,15 +25,6 @@ - (id)init { if (self) { _modalAnimated = YES; _modal = NO; - - //might be better in viewDidLoad, but to workaround rdar://12214613 and as it doesn't - //hurt, we do it here - if (self.modal) { - self.navigationItem.leftBarButtonItem = [[[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemDone - target:self - action:@selector(onDismissModal:)] autorelease]; - } - } return self; } @@ -42,6 +33,14 @@ - (id)initWithModalStyle:(BOOL)modal { self = [self init]; if (self) { _modal = modal; + + //might be better in viewDidLoad, but to workaround rdar://12214613 and as it doesn't + //hurt, we do it here + if (self.modal) { + self.navigationItem.leftBarButtonItem = [[[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemDone + target:self + action:@selector(onDismissModal:)] autorelease]; + } } return self; } From 8c013f7884ad09a58ab1509ac675bc26da799864 Mon Sep 17 00:00:00 2001 From: Andreas Linde Date: Mon, 15 Oct 2012 00:03:52 +0200 Subject: [PATCH 028/176] Fix buttons in feedback view showing artifacts of the other button --- Classes/BITFeedbackListViewController.m | 28 ++++++++++++++++++------- 1 file changed, 20 insertions(+), 8 deletions(-) diff --git a/Classes/BITFeedbackListViewController.m b/Classes/BITFeedbackListViewController.m index c422a07d..ec38bf51 100644 --- a/Classes/BITFeedbackListViewController.m +++ b/Classes/BITFeedbackListViewController.m @@ -230,7 +230,8 @@ - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { static NSString *CellIdentifier = @"MessageCell"; static NSString *LastUpdateIdentifier = @"LastUpdateCell"; - static NSString *ButtonIdentifier = @"ButtonCell"; + static NSString *ButtonTopIdentifier = @"ButtonTopCell"; + static NSString *ButtonBottomIdentifier = @"ButtonBottomCell"; if (indexPath.section == 0 && indexPath.row == 1) { UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:LastUpdateIdentifier]; @@ -251,15 +252,26 @@ - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(N } else if (indexPath.section == 0 || indexPath.section == 2) { CGFloat topGap = 0.0f; - UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:ButtonIdentifier]; + UITableViewCell *cell = nil; - if (!cell) { - cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:ButtonIdentifier] autorelease]; - cell.textLabel.font = [UIFont systemFontOfSize:14]; - cell.textLabel.numberOfLines = 0; - cell.accessoryType = UITableViewCellAccessoryNone; - cell.selectionStyle = UITableViewCellSelectionStyleNone; + if (indexPath.section == 0) { + cell = [tableView dequeueReusableCellWithIdentifier:ButtonTopIdentifier]; + + if (!cell) { + cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:ButtonTopIdentifier] autorelease]; + } + } else { + cell = [tableView dequeueReusableCellWithIdentifier:ButtonBottomIdentifier]; + + if (!cell) { + cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:ButtonBottomIdentifier] autorelease]; + } } + cell.textLabel.font = [UIFont systemFontOfSize:14]; + cell.textLabel.numberOfLines = 0; + cell.accessoryType = UITableViewCellAccessoryNone; + cell.selectionStyle = UITableViewCellSelectionStyleNone; + UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom]; [button.layer setMasksToBounds:YES]; From c8c1ad8e104c31dd5dc7e67f4376e0ec05b3858f Mon Sep 17 00:00:00 2001 From: Andreas Linde Date: Mon, 15 Oct 2012 00:04:54 +0200 Subject: [PATCH 029/176] Improve some feedback texts --- Resources/de.lproj/HockeySDK.strings | 4 ++-- Resources/en.lproj/HockeySDK.strings | 4 ++-- Resources/es.lproj/HockeySDK.strings | 4 ++-- Resources/fr.lproj/HockeySDK.strings | 4 ++-- Resources/it.lproj/HockeySDK.strings | 4 ++-- Resources/ja.lproj/HockeySDK.strings | 4 ++-- Resources/nl.lproj/HockeySDK.strings | 4 ++-- Resources/pt-PT.lproj/HockeySDK.strings | 4 ++-- Resources/pt.lproj/HockeySDK.strings | 4 ++-- Resources/ru.lproj/HockeySDK.strings | 4 ++-- Resources/sv.lproj/HockeySDK.strings | 4 ++-- Resources/tr.lproj/HockeySDK.strings | 4 ++-- Resources/zh_CN.lproj/HockeySDK.strings | 4 ++-- Resources/zh_TW.lproj/HockeySDK.strings | 4 ++-- 14 files changed, 28 insertions(+), 28 deletions(-) diff --git a/Resources/de.lproj/HockeySDK.strings b/Resources/de.lproj/HockeySDK.strings index 50ce218c..b81619c8 100755 --- a/Resources/de.lproj/HockeySDK.strings +++ b/Resources/de.lproj/HockeySDK.strings @@ -180,10 +180,10 @@ /* Set User Data */ /* Title */ -"HockeyFeedbackUserDataTitle" = "Who Are You"; +"HockeyFeedbackUserDataTitle" = "My Info"; /* Description On What Should Be Entered */ -"HockeyFeedbackUserDataDescription" = "Please let us know who you are before writing us your feedback."; +"HockeyFeedbackUserDataDescription" = "Please provide your information before writing your feedback."; /* Name Field */ "HockeyFeedbackUserDataName" = "Name"; diff --git a/Resources/en.lproj/HockeySDK.strings b/Resources/en.lproj/HockeySDK.strings index 34263a69..334e6192 100755 --- a/Resources/en.lproj/HockeySDK.strings +++ b/Resources/en.lproj/HockeySDK.strings @@ -177,10 +177,10 @@ /* Set User Data */ /* Title */ -"HockeyFeedbackUserDataTitle" = "Who Are You"; +"HockeyFeedbackUserDataTitle" = "My Info"; /* Description On What Should Be Entered */ -"HockeyFeedbackUserDataDescription" = "Please let us know who you are before writing us your feedback."; +"HockeyFeedbackUserDataDescription" = "Please provide your information before writing your feedback."; /* Name Field */ "HockeyFeedbackUserDataName" = "Name"; diff --git a/Resources/es.lproj/HockeySDK.strings b/Resources/es.lproj/HockeySDK.strings index ab166f20..c39ad438 100755 --- a/Resources/es.lproj/HockeySDK.strings +++ b/Resources/es.lproj/HockeySDK.strings @@ -178,10 +178,10 @@ /* Set User Data */ /* Title */ -"HockeyFeedbackUserDataTitle" = "Who Are You"; +"HockeyFeedbackUserDataTitle" = "My Info"; /* Description On What Should Be Entered */ -"HockeyFeedbackUserDataDescription" = "Please let us know who you are before writing us your feedback."; +"HockeyFeedbackUserDataDescription" = "Please provide your information before writing your feedback."; /* Name Field */ "HockeyFeedbackUserDataName" = "Name"; diff --git a/Resources/fr.lproj/HockeySDK.strings b/Resources/fr.lproj/HockeySDK.strings index 76d685d2..df6c1451 100755 --- a/Resources/fr.lproj/HockeySDK.strings +++ b/Resources/fr.lproj/HockeySDK.strings @@ -178,10 +178,10 @@ /* Set User Data */ /* Title */ -"HockeyFeedbackUserDataTitle" = "Who Are You"; +"HockeyFeedbackUserDataTitle" = "My Info"; /* Description On What Should Be Entered */ -"HockeyFeedbackUserDataDescription" = "Please let us know who you are before writing us your feedback."; +"HockeyFeedbackUserDataDescription" = "Please provide your information before writing your feedback."; /* Name Field */ "HockeyFeedbackUserDataName" = "Name"; diff --git a/Resources/it.lproj/HockeySDK.strings b/Resources/it.lproj/HockeySDK.strings index 54319358..80828c94 100755 --- a/Resources/it.lproj/HockeySDK.strings +++ b/Resources/it.lproj/HockeySDK.strings @@ -178,10 +178,10 @@ /* Set User Data */ /* Title */ -"HockeyFeedbackUserDataTitle" = "Who Are You"; +"HockeyFeedbackUserDataTitle" = "My Info"; /* Description On What Should Be Entered */ -"HockeyFeedbackUserDataDescription" = "Please let us know who you are before writing us your feedback."; +"HockeyFeedbackUserDataDescription" = "Please provide your information before writing your feedback."; /* Name Field */ "HockeyFeedbackUserDataName" = "Name"; diff --git a/Resources/ja.lproj/HockeySDK.strings b/Resources/ja.lproj/HockeySDK.strings index 5c57b5a4..63f8b86f 100755 --- a/Resources/ja.lproj/HockeySDK.strings +++ b/Resources/ja.lproj/HockeySDK.strings @@ -178,10 +178,10 @@ /* Set User Data */ /* Title */ -"HockeyFeedbackUserDataTitle" = "Who Are You"; +"HockeyFeedbackUserDataTitle" = "My Info"; /* Description On What Should Be Entered */ -"HockeyFeedbackUserDataDescription" = "Please let us know who you are before writing us your feedback."; +"HockeyFeedbackUserDataDescription" = "Please provide your information before writing your feedback."; /* Name Field */ "HockeyFeedbackUserDataName" = "Name"; diff --git a/Resources/nl.lproj/HockeySDK.strings b/Resources/nl.lproj/HockeySDK.strings index 827eed53..1dfdfe0f 100755 --- a/Resources/nl.lproj/HockeySDK.strings +++ b/Resources/nl.lproj/HockeySDK.strings @@ -178,10 +178,10 @@ /* Set User Data */ /* Title */ -"HockeyFeedbackUserDataTitle" = "Who Are You"; +"HockeyFeedbackUserDataTitle" = "My Info"; /* Description On What Should Be Entered */ -"HockeyFeedbackUserDataDescription" = "Please let us know who you are before writing us your feedback."; +"HockeyFeedbackUserDataDescription" = "Please provide your information before writing your feedback."; /* Name Field */ "HockeyFeedbackUserDataName" = "Name"; diff --git a/Resources/pt-PT.lproj/HockeySDK.strings b/Resources/pt-PT.lproj/HockeySDK.strings index e36f78cb..298f9980 100755 --- a/Resources/pt-PT.lproj/HockeySDK.strings +++ b/Resources/pt-PT.lproj/HockeySDK.strings @@ -178,10 +178,10 @@ /* Set User Data */ /* Title */ -"HockeyFeedbackUserDataTitle" = "Who Are You"; +"HockeyFeedbackUserDataTitle" = "My Info"; /* Description On What Should Be Entered */ -"HockeyFeedbackUserDataDescription" = "Please let us know who you are before writing us your feedback."; +"HockeyFeedbackUserDataDescription" = "Please provide your information before writing your feedback."; /* Name Field */ "HockeyFeedbackUserDataName" = "Name"; diff --git a/Resources/pt.lproj/HockeySDK.strings b/Resources/pt.lproj/HockeySDK.strings index 3b7ffb94..a0525521 100755 --- a/Resources/pt.lproj/HockeySDK.strings +++ b/Resources/pt.lproj/HockeySDK.strings @@ -178,10 +178,10 @@ /* Set User Data */ /* Title */ -"HockeyFeedbackUserDataTitle" = "Who Are You"; +"HockeyFeedbackUserDataTitle" = "My Info"; /* Description On What Should Be Entered */ -"HockeyFeedbackUserDataDescription" = "Please let us know who you are before writing us your feedback."; +"HockeyFeedbackUserDataDescription" = "Please provide your information before writing your feedback."; /* Name Field */ "HockeyFeedbackUserDataName" = "Name"; diff --git a/Resources/ru.lproj/HockeySDK.strings b/Resources/ru.lproj/HockeySDK.strings index 5dc296e0..f15bc9c4 100755 --- a/Resources/ru.lproj/HockeySDK.strings +++ b/Resources/ru.lproj/HockeySDK.strings @@ -178,10 +178,10 @@ /* Set User Data */ /* Title */ -"HockeyFeedbackUserDataTitle" = "Who Are You"; +"HockeyFeedbackUserDataTitle" = "My Info"; /* Description On What Should Be Entered */ -"HockeyFeedbackUserDataDescription" = "Please let us know who you are before writing us your feedback."; +"HockeyFeedbackUserDataDescription" = "Please provide your information before writing your feedback."; /* Name Field */ "HockeyFeedbackUserDataName" = "Name"; diff --git a/Resources/sv.lproj/HockeySDK.strings b/Resources/sv.lproj/HockeySDK.strings index ec760115..e42c6b98 100755 --- a/Resources/sv.lproj/HockeySDK.strings +++ b/Resources/sv.lproj/HockeySDK.strings @@ -178,10 +178,10 @@ /* Set User Data */ /* Title */ -"HockeyFeedbackUserDataTitle" = "Who Are You"; +"HockeyFeedbackUserDataTitle" = "My Info"; /* Description On What Should Be Entered */ -"HockeyFeedbackUserDataDescription" = "Please let us know who you are before writing us your feedback."; +"HockeyFeedbackUserDataDescription" = "Please provide your information before writing your feedback."; /* Name Field */ "HockeyFeedbackUserDataName" = "Name"; diff --git a/Resources/tr.lproj/HockeySDK.strings b/Resources/tr.lproj/HockeySDK.strings index cd06bebb..6898b29a 100644 --- a/Resources/tr.lproj/HockeySDK.strings +++ b/Resources/tr.lproj/HockeySDK.strings @@ -178,10 +178,10 @@ /* Set User Data */ /* Title */ -"HockeyFeedbackUserDataTitle" = "Who Are You"; +"HockeyFeedbackUserDataTitle" = "My Info"; /* Description On What Should Be Entered */ -"HockeyFeedbackUserDataDescription" = "Please let us know who you are before writing us your feedback."; +"HockeyFeedbackUserDataDescription" = "Please provide your information before writing your feedback."; /* Name Field */ "HockeyFeedbackUserDataName" = "Name"; diff --git a/Resources/zh_CN.lproj/HockeySDK.strings b/Resources/zh_CN.lproj/HockeySDK.strings index 8f5ebe2e..c1dd8dce 100644 --- a/Resources/zh_CN.lproj/HockeySDK.strings +++ b/Resources/zh_CN.lproj/HockeySDK.strings @@ -178,10 +178,10 @@ /* Set User Data */ /* Title */ -"HockeyFeedbackUserDataTitle" = "Who Are You"; +"HockeyFeedbackUserDataTitle" = "My Info"; /* Description On What Should Be Entered */ -"HockeyFeedbackUserDataDescription" = "Please let us know who you are before writing us your feedback."; +"HockeyFeedbackUserDataDescription" = "Please provide your information before writing your feedback."; /* Name Field */ "HockeyFeedbackUserDataName" = "Name"; diff --git a/Resources/zh_TW.lproj/HockeySDK.strings b/Resources/zh_TW.lproj/HockeySDK.strings index 1312b3c9..865c3fe9 100644 --- a/Resources/zh_TW.lproj/HockeySDK.strings +++ b/Resources/zh_TW.lproj/HockeySDK.strings @@ -178,10 +178,10 @@ /* Set User Data */ /* Title */ -"HockeyFeedbackUserDataTitle" = "Who Are You"; +"HockeyFeedbackUserDataTitle" = "My Info"; /* Description On What Should Be Entered */ -"HockeyFeedbackUserDataDescription" = "Please let us know who you are before writing us your feedback."; +"HockeyFeedbackUserDataDescription" = "Please provide your information before writing your feedback."; /* Name Field */ "HockeyFeedbackUserDataName" = "Name"; From d884936029fcd2c82d487e9e3fa74c493799737e Mon Sep 17 00:00:00 2001 From: Andreas Linde Date: Mon, 15 Oct 2012 00:06:54 +0200 Subject: [PATCH 030/176] Improve feedback handling - Messages deleted on the server will be internally marked as being archived - Pre-send a token for each new message for easier identification and detection of double sending --- Classes/BITFeedbackManager.m | 80 ++++++++++++++++++++++++++++++------ Classes/BITFeedbackMessage.h | 11 +++-- Classes/BITFeedbackMessage.m | 4 ++ 3 files changed, 78 insertions(+), 17 deletions(-) diff --git a/Classes/BITFeedbackManager.m b/Classes/BITFeedbackManager.m index 42e85545..a5c8898b 100644 --- a/Classes/BITFeedbackManager.m +++ b/Classes/BITFeedbackManager.m @@ -45,6 +45,7 @@ #define kBITFeedbackToken @"HockeyFeedbackToken" #define kBITFeedbackName @"HockeyFeedbackName" #define kBITFeedbackEmail @"HockeyFeedbackEmail" +#define kBITFeedbackLastMessageID @"HockeyFeedbackLastMessageID" @implementation BITFeedbackManager { @@ -144,6 +145,20 @@ - (void)cleanupDidBecomeActiveNotifications { [[NSNotificationCenter defaultCenter] removeObserver:self name:UIApplicationDidBecomeActiveNotification object:nil]; } +#pragma mark - Private methods + +- (NSString *)uuidString { + CFUUIDRef theToken = CFUUIDCreate(NULL); + CFStringRef stringUUID = CFUUIDCreateString(NULL, theToken); + CFRelease(theToken); + + return [(NSString *)stringUUID autorelease]; +} + +- (NSString *)uuidAsLowerCaseAndShortened { + return [[[self uuidString] lowercaseString] stringByReplacingOccurrencesOfString:@"-" withString:@""]; +} + #pragma mark - Feedback Modal UI - (BITFeedbackListViewController *)feedbackListViewController:(BOOL)modal { @@ -332,13 +347,18 @@ - (void)sortFeedbackList { NSDate *date1 = [obj1 date]; NSDate *date2 = [obj2 date]; - // not send and send in progress messages on top, sorted by date + // not send, in conflict and send in progress messages on top, sorted by date // read and unread on bottom, sorted by date + // archived on the very bottom if ([obj1 status] >= BITFeedbackMessageStatusSendInProgress && [obj2 status] < BITFeedbackMessageStatusSendInProgress) { return NSOrderedAscending; } else if ([obj1 status] < BITFeedbackMessageStatusSendInProgress && [obj2 status] >= BITFeedbackMessageStatusSendInProgress) { return NSOrderedDescending; + } else if ([obj1 status] == BITFeedbackMessageStatusArchived && [obj2 status] < BITFeedbackMessageStatusArchived) { + return NSOrderedDescending; + } else if ([obj1 status] < BITFeedbackMessageStatusArchived && [obj2 status] == BITFeedbackMessageStatusArchived) { + return NSOrderedAscending; } else { return (NSInteger)[date2 compare:date1]; } @@ -390,6 +410,14 @@ - (void)markSendInProgressMessagesAsPending { }]; } +- (void)markSendInProgressMessagesAsInConflict { + // make sure message that may have not been send successfully, get back into the right state to be send again + [_feedbackList enumerateObjectsUsingBlock:^(id objMessage, NSUInteger messagesIdx, BOOL *stop) { + if ([(BITFeedbackMessage *)objMessage status] == BITFeedbackMessageStatusSendInProgress) + [(BITFeedbackMessage *)objMessage setStatus:BITFeedbackMessageStatusInConflict]; + }]; +} + #pragma mark - User @@ -479,19 +507,21 @@ - (void)updateMessageListFromResponse:(NSDictionary *)jsonDictionary { BITFeedbackMessage *thisMessage = [self messageWithID:messageID]; if (!thisMessage) { // check if this is a message that was sent right now - __block BITFeedbackMessage *matchingSendInProgressMessage = nil; + __block BITFeedbackMessage *matchingSendInProgressOrInConflictMessage = nil; + + // TODO: match messages in state conflict [messagesSendInProgress enumerateObjectsUsingBlock:^(id objSendInProgressMessage, NSUInteger messagesSendInProgressIdx, BOOL *stop) { - if ([[(NSDictionary *)objMessage objectForKey:@"text"] isEqualToString:[(BITFeedbackMessage *)objSendInProgressMessage text]]) { - matchingSendInProgressMessage = objSendInProgressMessage; + if ([[(NSDictionary *)objMessage objectForKey:@"token"] isEqualToString:[(BITFeedbackMessage *)objSendInProgressMessage token]]) { + matchingSendInProgressOrInConflictMessage = objSendInProgressMessage; *stop = YES; } }]; - if (matchingSendInProgressMessage) { - matchingSendInProgressMessage.date = [self parseRFC3339Date:[(NSDictionary *)objMessage objectForKey:@"created_at"]]; - matchingSendInProgressMessage.id = messageID; - matchingSendInProgressMessage.status = BITFeedbackMessageStatusRead; + if (matchingSendInProgressOrInConflictMessage) { + matchingSendInProgressOrInConflictMessage.date = [self parseRFC3339Date:[(NSDictionary *)objMessage objectForKey:@"created_at"]]; + matchingSendInProgressOrInConflictMessage.id = messageID; + matchingSendInProgressOrInConflictMessage.status = BITFeedbackMessageStatusRead; } else { BITFeedbackMessage *message = [[[BITFeedbackMessage alloc] init] autorelease]; message.text = [(NSDictionary *)objMessage objectForKey:@"text"]; @@ -554,7 +584,7 @@ - (void)updateMessageListFromResponse:(NSDictionary *)jsonDictionary { return; } -- (void)sendNetworkRequestWithHTTPMethod:(NSString *)httpMethod withText:(NSString *)text completionHandler:(void (^)(NSError *err))completionHandler { +- (void)sendNetworkRequestWithHTTPMethod:(NSString *)httpMethod withMessage:(BITFeedbackMessage *)message completionHandler:(void (^)(NSError *err))completionHandler { NSString *boundary = @"----FOO"; _networkRequestInProgress = YES; @@ -582,7 +612,7 @@ - (void)sendNetworkRequestWithHTTPMethod:(NSString *)httpMethod withText:(NSStri [request setValue:@"Hockey/iOS" forHTTPHeaderField:@"User-Agent"]; [request setValue:@"gzip" forHTTPHeaderField:@"Accept-Encoding"]; - if (text) { + if (message) { NSString *contentType = [NSString stringWithFormat:@"multipart/form-data; boundary=%@", boundary]; [request setValue:contentType forHTTPHeaderField:@"Content-type"]; @@ -593,7 +623,8 @@ - (void)sendNetworkRequestWithHTTPMethod:(NSString *)httpMethod withText:(NSStri [postBody appendData:[self appendPostValue:[self getDevicePlatform] forKey:@"model"]]; [postBody appendData:[self appendPostValue:[[[NSBundle mainBundle] preferredLocalizations] objectAtIndex:0] forKey:@"lang"]]; [postBody appendData:[self appendPostValue:[[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleVersion"] forKey:@"bundle_version"]]; - [postBody appendData:[self appendPostValue:text forKey:@"text"]]; + [postBody appendData:[self appendPostValue:[message text] forKey:@"text"]]; + [postBody appendData:[self appendPostValue:[message token] forKey:@"message_token"]]; if (self.userName) { [postBody appendData:[self appendPostValue:self.userName forKey:@"name"]]; @@ -619,6 +650,28 @@ - (void)sendNetworkRequestWithHTTPMethod:(NSString *)httpMethod withText:(NSStri if (statusCode == 404) { // thread has been deleted, we archive it [self updateMessageListFromResponse:nil]; + } else if (statusCode == 409) { + // we submitted a message that is already on the server, mark it as being in conflict and resolve it with another fetch + + if (!self.token) { + // set the token to the first message token, since this is identical + __block NSString *token = nil; + + [_feedbackList enumerateObjectsUsingBlock:^(id objMessage, NSUInteger messagesIdx, BOOL *stop) { + if ([(BITFeedbackMessage *)objMessage status] == BITFeedbackMessageStatusSendInProgress) { + token = [(BITFeedbackMessage *)objMessage token]; + *stop = YES; + } + }]; + + if (token) { + self.token = token; + } + } + + [self markSendInProgressMessagesAsInConflict]; + [self saveMessages]; + [self performSelector:@selector(fetchMessageUpdates) withObject:nil afterDelay:0.2]; } else if ([responseData length]) { NSString *responseString = [[[NSString alloc] initWithBytes:[responseData bytes] length:[responseData length] encoding: NSUTF8StringEncoding] autorelease]; BITHockeyLog(@"INFO: Received API response: %@", responseString); @@ -662,7 +715,7 @@ - (void)fetchMessageUpdates { } [self sendNetworkRequestWithHTTPMethod:@"GET" - withText:nil + withMessage:nil completionHandler:^(NSError *err){ // inform the UI to update its data in case the list is already showing [[NSNotificationCenter defaultCenter] postNotificationName:BITHockeyFeedbackMessagesLoadingFinished object:nil]; @@ -696,7 +749,7 @@ - (void)submitPendingMessages { } [self sendNetworkRequestWithHTTPMethod:httpMethod - withText:[messageToSend text] + withMessage:messageToSend completionHandler:^(NSError *err){ if (err) { [self markSendInProgressMessagesAsPending]; @@ -714,6 +767,7 @@ - (void)submitMessageWithText:(NSString *)text { BITFeedbackMessage *message = [[[BITFeedbackMessage alloc] init] autorelease]; message.text = text; [message setStatus:BITFeedbackMessageStatusSendPending]; + [message setToken:[self uuidAsLowerCaseAndShortened]]; [message setUserMessage:YES]; [_feedbackList addObject:message]; diff --git a/Classes/BITFeedbackMessage.h b/Classes/BITFeedbackMessage.h index 0263e40c..4f8a5d9f 100644 --- a/Classes/BITFeedbackMessage.h +++ b/Classes/BITFeedbackMessage.h @@ -32,14 +32,16 @@ typedef enum { // default and new messages from SDK per default BITFeedbackMessageStatusSendPending = 0, + // message is in conflict, happens if the message is already stored on the server and tried sending it again + BITFeedbackMessageStatusInConflict = 1, // sending of message is in progress - BITFeedbackMessageStatusSendInProgress = 1, + BITFeedbackMessageStatusSendInProgress = 2, // new messages from server - BITFeedbackMessageStatusUnread = 2, + BITFeedbackMessageStatusUnread = 3, // messages from server once read and new local messages once successful send from SDK - BITFeedbackMessageStatusRead = 3, + BITFeedbackMessageStatusRead = 4, // message is archived, happens if the thread is deleted from the server - BITFeedbackMessageStatusArchived = 4 + BITFeedbackMessageStatusArchived = 5 } BITFeedbackMessageStatus; @interface BITFeedbackMessage : NSObject { @@ -50,6 +52,7 @@ typedef enum { @property (nonatomic, copy) NSString *email; @property (nonatomic, copy) NSDate *date; @property (nonatomic, copy) NSNumber *id; +@property (nonatomic, copy) NSString *token; @property (nonatomic) BITFeedbackMessageStatus status; @property (nonatomic) BOOL userMessage; diff --git a/Classes/BITFeedbackMessage.m b/Classes/BITFeedbackMessage.m index e19044b7..10870279 100644 --- a/Classes/BITFeedbackMessage.m +++ b/Classes/BITFeedbackMessage.m @@ -40,6 +40,7 @@ - (id) init { _name = nil; _email = nil; _date = nil; + _token = nil; _id = [[NSNumber alloc] initWithInteger:0]; _status = BITFeedbackMessageStatusSendPending; _userMessage = NO; @@ -53,6 +54,7 @@ - (void)dealloc { [_email release], _email = nil; [_date release], _date = nil; [_id release], _id = nil; + [_token release], _token = nil; [super dealloc]; } @@ -68,6 +70,7 @@ - (void)encodeWithCoder:(NSCoder *)encoder { [encoder encodeObject:self.id forKey:@"id"]; [encoder encodeInteger:self.status forKey:@"status"]; [encoder encodeBool:self.userMessage forKey:@"userMessage"]; + [encoder encodeObject:self.token forKey:@"token"]; } - (id)initWithCoder:(NSCoder *)decoder { @@ -79,6 +82,7 @@ - (id)initWithCoder:(NSCoder *)decoder { self.id = [decoder decodeObjectForKey:@"id"]; self.status = [decoder decodeIntegerForKey:@"status"]; self.userMessage = [decoder decodeBoolForKey:@"userMessage"]; + self.token = [decoder decodeObjectForKey:@"token"]; } return self; } From 8e7c08b4dba0560c1a2836333bda58a554ba8a1f Mon Sep 17 00:00:00 2001 From: Andreas Linde Date: Mon, 15 Oct 2012 00:41:43 +0200 Subject: [PATCH 031/176] Fix date handling to correctly use UTC date time format --- Classes/BITHockeyBaseManager.m | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/Classes/BITHockeyBaseManager.m b/Classes/BITHockeyBaseManager.m index 868227dc..a1345f31 100644 --- a/Classes/BITHockeyBaseManager.m +++ b/Classes/BITHockeyBaseManager.m @@ -41,9 +41,11 @@ - (id)init { _barStyle = UIBarStyleDefault; _modalPresentationStyle = UIModalPresentationFormSheet; + NSLocale *enUSPOSIXLocale = [[[NSLocale alloc] initWithLocaleIdentifier:@"en_US_POSIX"] autorelease]; _rfc3339Formatter = [[NSDateFormatter alloc] init]; - [_rfc3339Formatter setLocale:[[[NSLocale alloc] initWithLocaleIdentifier:@"en_US_POSIX"] autorelease]]; - [_rfc3339Formatter setDateFormat:@"yyyy-MM-dd'T'HH:mm:ss'Z'"]; + [_rfc3339Formatter setLocale:enUSPOSIXLocale]; + [_rfc3339Formatter setDateFormat:@"yyyy'-'MM'-'dd'T'HH':'mm':'ss'Z'"]; + [_rfc3339Formatter setTimeZone:[NSTimeZone timeZoneForSecondsFromGMT:0]]; } return self; } From 4de48051a8833154bc4de95178b7a8cd9585ec2b Mon Sep 17 00:00:00 2001 From: Andreas Linde Date: Mon, 15 Oct 2012 00:47:10 +0200 Subject: [PATCH 032/176] Add latest local stored message id to each request, so we get only get newer messages back from the server --- Classes/BITFeedbackManager.m | 37 +++++++++++++++++++++++------------- 1 file changed, 24 insertions(+), 13 deletions(-) diff --git a/Classes/BITFeedbackManager.m b/Classes/BITFeedbackManager.m index a5c8898b..ba7e53c0 100644 --- a/Classes/BITFeedbackManager.m +++ b/Classes/BITFeedbackManager.m @@ -402,6 +402,19 @@ - (NSArray *)messagesWithStatus:(BITFeedbackMessageStatus)status { return [NSArray arrayWithArray:resultMessages];; } +- (BITFeedbackMessage *)lastMessageHavingID { + __block BITFeedbackMessage *message = nil; + + [_feedbackList enumerateObjectsUsingBlock:^(BITFeedbackMessage *objMessage, NSUInteger messagesIdx, BOOL *stop) { + if ([[objMessage id] integerValue] != 0) { + message = objMessage; + *stop = YES; + } + }]; + + return message; +} + - (void)markSendInProgressMessagesAsPending { // make sure message that may have not been send successfully, get back into the right state to be send again [_feedbackList enumerateObjectsUsingBlock:^(id objMessage, NSUInteger messagesIdx, BOOL *stop) { @@ -537,22 +550,13 @@ - (void)updateMessageListFromResponse:(NSDictionary *)jsonDictionary { newResponseMessage = YES; } } else { - // TODO: update message + // we should never get any messages back that are already stored locally, + // since we add the last_message_id to the request } }]; - // TODO: implement todo defined above [self markSendInProgressMessagesAsPending]; - // mark all messages as archived that are removed on the server - [_feedbackList enumerateObjectsUsingBlock:^(id objMessage, NSUInteger messagesIdx, BOOL *stop) { - if (![returnedMessageIDs member:[(BITFeedbackMessage *)objMessage id]] && - [(BITFeedbackMessage *)objMessage status] != BITFeedbackMessageStatusSendPending - ) { - [(BITFeedbackMessage *)objMessage setStatus:BITFeedbackMessageStatusArchived]; - } - }]; - // we got a new incoming message, trigger user notification system if (newResponseMessage) { if (self.showAlertOnIncomingMessages && !self.currentFeedbackListViewController && !self.currentFeedbackComposeViewController) { @@ -597,10 +601,17 @@ - (void)sendNetworkRequestWithHTTPMethod:(NSString *)httpMethod withMessage:(BIT } NSMutableString *parameter = [NSMutableString stringWithFormat:@"api/2/apps/%@/feedback%@", [self encodedAppIdentifier], tokenParameter]; - [parameter appendFormat:@"?format=json&bundle_version=%@&sdk=%@&sdk_version=%@", + NSString *lastMessageID = @""; + BITFeedbackMessage *lastMessageHavingID = [self lastMessageHavingID]; + if (lastMessageHavingID) { + lastMessageID = [NSString stringWithFormat:@"&last_message_id=%i", [[lastMessageHavingID id] integerValue]]; + } + + [parameter appendFormat:@"?format=json&bundle_version=%@&sdk=%@&sdk_version=%@%@", bit_URLEncodedString([[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleVersion"]), BITHOCKEY_NAME, - BITHOCKEY_VERSION + BITHOCKEY_VERSION, + lastMessageID ]; // build request & send From 003de59f3d9f6c152b5b6db95df7184a45abedf2 Mon Sep 17 00:00:00 2001 From: Andreas Linde Date: Mon, 15 Oct 2012 00:47:50 +0200 Subject: [PATCH 033/176] If an email field is entered, validate the string and only allow addresses that look correct --- Classes/BITFeedbackUserDataViewController.m | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/Classes/BITFeedbackUserDataViewController.m b/Classes/BITFeedbackUserDataViewController.m index 637c310b..dae06618 100644 --- a/Classes/BITFeedbackUserDataViewController.m +++ b/Classes/BITFeedbackUserDataViewController.m @@ -106,6 +106,20 @@ - (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interface #pragma mark - Private methods +- (BOOL)validateEmail { + NSString *emailRegex = + @"(?:[a-z0-9!#$%\\&'*+/=?\\^_`{|}~-]+(?:\\.[a-z0-9!#$%\\&'*+/=?\\^_`{|}" + @"~-]+)*|\"(?:[\\x01-\\x08\\x0b\\x0c\\x0e-\\x1f\\x21\\x23-\\x5b\\x5d-\\" + @"x7f]|\\\\[\\x01-\\x09\\x0b\\x0c\\x0e-\\x7f])*\")@(?:(?:[a-z0-9](?:[a-" + @"z0-9-]*[a-z0-9])?\\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?|\\[(?:(?:25[0-5" + @"]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-" + @"9][0-9]?|[a-z0-9-]*[a-z0-9]:(?:[\\x01-\\x08\\x0b\\x0c\\x0e-\\x1f\\x21" + @"-\\x5a\\x53-\\x7f]|\\\\[\\x01-\\x09\\x0b\\x0c\\x0e-\\x7f])+)\\])"; + NSPredicate *emailTest = [NSPredicate predicateWithFormat:@"SELF MATCHES %@", emailRegex]; + + return [emailTest evaluateWithObject:self.email]; +} + - (BOOL)allRequiredFieldsEntered { if ([self.manager requireUserName] == BITFeedbackUserDataElementRequired && [self.name length] == 0) return NO; @@ -113,6 +127,9 @@ - (BOOL)allRequiredFieldsEntered { if ([self.manager requireUserEmail] == BITFeedbackUserDataElementRequired && [self.email length] == 0) return NO; + if ([self.email length] > 0 && ![self validateEmail]) + return NO; + return YES; } From 90bab2fc4bb365086d74f6ed5dc5af013b98fea1 Mon Sep 17 00:00:00 2001 From: Andreas Linde Date: Mon, 15 Oct 2012 00:48:47 +0200 Subject: [PATCH 034/176] Bump version to 3.0.0a1 --- Support/buildnumber.xcconfig | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Support/buildnumber.xcconfig b/Support/buildnumber.xcconfig index 118a3f3b..119cd859 100644 --- a/Support/buildnumber.xcconfig +++ b/Support/buildnumber.xcconfig @@ -1,5 +1,5 @@ #include "HockeySDK.xcconfig" -BUILD_NUMBER = 6 -VERSION_STRING = 2.5.4b1 -GCC_PREPROCESSOR_DEFINITIONS = $(inherited) BITHOCKEY_VERSION="@\"2.5.4b1\"" +BUILD_NUMBER = 10 +VERSION_STRING = 3.0.0a1 +GCC_PREPROCESSOR_DEFINITIONS = $(inherited) BITHOCKEY_VERSION="@\"3.0.0a1\"" From 343b8b0abbbda0f5fea95547a69f4590e16dbf2b Mon Sep 17 00:00:00 2001 From: Andreas Linde Date: Mon, 15 Oct 2012 01:11:29 +0200 Subject: [PATCH 035/176] Fix Feedback list repositioning problem in iOS6 when using pull to refresh and new messages coming in --- Classes/BITFeedbackListViewController.m | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/Classes/BITFeedbackListViewController.m b/Classes/BITFeedbackListViewController.m index ec38bf51..3f972251 100644 --- a/Classes/BITFeedbackListViewController.m +++ b/Classes/BITFeedbackListViewController.m @@ -137,6 +137,14 @@ - (void)stopLoadingIndicator { } } +- (BOOL)isRefreshingWithNewControl { + id refreshClass = NSClassFromString(@"UIRefreshControl"); + if (refreshClass) { + return [self.refreshControl isRefreshing]; + } + return NO; +} + - (void)reloadList { [self startLoadingIndicator]; @@ -147,12 +155,12 @@ - (void)updateList { CGSize contentSize = self.tableView.contentSize; CGPoint contentOffset = self.tableView.contentOffset; - [self stopLoadingIndicator]; - [self.tableView reloadData]; - if (contentSize.height > 0 && self.tableView.contentSize.height > contentSize.height) + if (contentSize.height > 0 && self.tableView.contentSize.height > contentSize.height && ![self isRefreshingWithNewControl]) [self.tableView setContentOffset:CGPointMake(contentOffset.x, self.tableView.contentSize.height - contentSize.height + contentOffset.y) animated:NO]; + [self stopLoadingIndicator]; + [self.tableView flashScrollIndicators]; } From f4b685ef47bd6eca8b590d3bb408486c26cd8ac5 Mon Sep 17 00:00:00 2001 From: Andreas Linde Date: Mon, 15 Oct 2012 01:22:13 +0200 Subject: [PATCH 036/176] If the message is from the same day, show the time instead of the date --- Classes/BITFeedbackListViewCell.m | 29 ++++++++++++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) diff --git a/Classes/BITFeedbackListViewCell.m b/Classes/BITFeedbackListViewCell.m index e8a5115d..89346bbd 100644 --- a/Classes/BITFeedbackListViewCell.m +++ b/Classes/BITFeedbackListViewCell.m @@ -54,6 +54,7 @@ @interface BITFeedbackListViewCell () @property (nonatomic, retain) NSDateFormatter *dateFormatter; +@property (nonatomic, retain) NSDateFormatter *timeFormatter; @property (nonatomic, retain) UILabel *labelTitle; @property (nonatomic, retain) UILabel *labelText; @@ -82,6 +83,12 @@ - (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reus [self.dateFormatter setLocale:[NSLocale currentLocale]]; [self.dateFormatter setDoesRelativeDateFormatting:YES]; + self.timeFormatter = [[[NSDateFormatter alloc] init] autorelease]; + [self.timeFormatter setTimeStyle:NSDateFormatterShortStyle]; + [self.timeFormatter setDateStyle:NSDateFormatterNoStyle]; + [self.timeFormatter setLocale:[NSLocale currentLocale]]; + [self.timeFormatter setDoesRelativeDateFormatting:YES]; + self.labelTitle = [[[UILabel alloc] init] autorelease]; self.labelTitle.font = [UIFont systemFontOfSize:TITLE_FONTSIZE]; @@ -95,6 +102,7 @@ - (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reus - (void)dealloc { [_dateFormatter release], _dateFormatter = nil; + [_timeFormatter release], _timeFormatter = nil; [_labelTitle release], _labelTitle = nil; [_labelText release], _labelText = nil; @@ -107,6 +115,21 @@ - (void)dealloc { } +#pragma mark - Private + +- (BOOL)isSameDayWithDate1:(NSDate*)date1 date2:(NSDate*)date2 { + NSCalendar* calendar = [NSCalendar currentCalendar]; + + unsigned unitFlags = NSYearCalendarUnit | NSMonthCalendarUnit | NSDayCalendarUnit; + NSDateComponents *dateComponent1 = [calendar components:unitFlags fromDate:date1]; + NSDateComponents *dateComponent2 = [calendar components:unitFlags fromDate:date2]; + + return ([dateComponent1 day] == [dateComponent2 day] && + [dateComponent1 month] == [dateComponent2 month] && + [dateComponent1 year] == [dateComponent2 year]); +} + + #pragma mark - Layout + (CGFloat) heightForRowWithText:(NSString *)text tableViewWidth:(CGFloat)width { @@ -138,7 +161,11 @@ - (void)layoutSubviews { // header NSString *dateString; if (self.date) { - dateString = [self.dateFormatter stringFromDate:self.date]; + if ([self isSameDayWithDate1:[NSDate date] date2:self.date]) { + dateString = [self.timeFormatter stringFromDate:self.date]; + } else { + dateString = [self.dateFormatter stringFromDate:self.date]; + } } else { dateString = BITHockeyLocalizedString(@"Pending"); } From 7fdf39148f261acfe56ae8ef1f7cc656846cfdd6 Mon Sep 17 00:00:00 2001 From: Andreas Linde Date: Mon, 15 Oct 2012 13:33:57 +0200 Subject: [PATCH 037/176] Use NSLog if non App Store environment for deprecated messages --- Classes/BITCrashManager.m | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/Classes/BITCrashManager.m b/Classes/BITCrashManager.m index f4141ebd..a9574c87 100644 --- a/Classes/BITCrashManager.m +++ b/Classes/BITCrashManager.m @@ -268,7 +268,8 @@ - (NSString *)userNameForCrashReport { NSString *username = @""; if (self.delegate && [self.delegate respondsToSelector:@selector(userNameForCrashManager:)]) { - BITHockeyLog(@"DEPRECATED: Please user BITHockeyManagerDelegate's userNameForHockeyManager:componentManager: or userIDForHockeyManager:componentManager: instead."); + if (!self.isAppStoreEnvironment) + NSLog(@"[HockeySDK] DEPRECATED: Please use BITHockeyManagerDelegate's userNameForHockeyManager:componentManager: or userIDForHockeyManager:componentManager: instead."); username = [self.delegate userNameForCrashManager:self]; } if ([BITHockeyManager sharedHockeyManager].delegate && @@ -291,7 +292,8 @@ - (NSString *)userEmailForCrashReport { NSString *useremail = @""; if (self.delegate && [self.delegate respondsToSelector:@selector(userEmailForCrashManager:)]) { - BITHockeyLog(@"DEPRECATED: Please user BITHockeyManagerDelegate's userEmailForHockeyManager:componentManager: instead."); + if (!self.isAppStoreEnvironment) + NSLog(@"[HockeySDK] DEPRECATED: Please use BITHockeyManagerDelegate's userEmailForHockeyManager:componentManager: instead."); useremail = [self.delegate userEmailForCrashManager:self]; } if ([BITHockeyManager sharedHockeyManager].delegate && From 389f2ab8761063be9dac0ef81a57460fc30a2372 Mon Sep 17 00:00:00 2001 From: Andreas Linde Date: Mon, 15 Oct 2012 15:23:33 +0200 Subject: [PATCH 038/176] Change the default of Feedback username and email to optional instead of required --- Classes/BITFeedbackManager.h | 4 ++-- Classes/BITFeedbackManager.m | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Classes/BITFeedbackManager.h b/Classes/BITFeedbackManager.h index 318ce91a..c571cce8 100644 --- a/Classes/BITFeedbackManager.h +++ b/Classes/BITFeedbackManager.h @@ -53,8 +53,8 @@ typedef enum { @interface BITFeedbackManager : BITHockeyBaseManager -@property (nonatomic, readwrite) BITFeedbackUserDataElement requireUserName; // default is BITFeedbackUserDataRequired -@property (nonatomic, readwrite) BITFeedbackUserDataElement requireUserEmail; // default is BITFeedbackUserDataRequired +@property (nonatomic, readwrite) BITFeedbackUserDataElement requireUserName; // default is BITFeedbackUserDataElementOptional +@property (nonatomic, readwrite) BITFeedbackUserDataElement requireUserEmail; // default is BITFeedbackUserDataElementOptional @property (nonatomic, readwrite) BOOL showAlertOnIncomingMessages; // default is YES ///----------------------------------------------------------------------------- diff --git a/Classes/BITFeedbackManager.m b/Classes/BITFeedbackManager.m index ba7e53c0..ea730df4 100644 --- a/Classes/BITFeedbackManager.m +++ b/Classes/BITFeedbackManager.m @@ -66,8 +66,8 @@ - (id)init { _currentFeedbackComposeViewController = nil; _didAskUserData = NO; - _requireUserName = BITFeedbackUserDataElementRequired; - _requireUserEmail = BITFeedbackUserDataElementRequired; + _requireUserName = BITFeedbackUserDataElementOptional; + _requireUserEmail = BITFeedbackUserDataElementOptional; _showAlertOnIncomingMessages = YES; _disableFeedbackManager = NO; From 669d03d6037340a137012272681f3b5a30c499fd Mon Sep 17 00:00:00 2001 From: Andreas Linde Date: Mon, 15 Oct 2012 15:25:01 +0200 Subject: [PATCH 039/176] Don't show a new feedback alert message, if the newest message on the server is from the same users email This can happen, if the user responds to the email directly instead of using the in-app feedback --- Classes/BITFeedbackManager.m | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/Classes/BITFeedbackManager.m b/Classes/BITFeedbackManager.m index ea730df4..cf75359a 100644 --- a/Classes/BITFeedbackManager.m +++ b/Classes/BITFeedbackManager.m @@ -510,7 +510,7 @@ - (void)updateMessageListFromResponse:(NSDictionary *)jsonDictionary { NSInteger pendingMessagesCount = [messagesSendInProgress count] + [[self messagesWithStatus:BITFeedbackMessageStatusSendPending] count]; - __block BOOL newResponseMessage = NO; + __block BOOL newMessage = NO; __block NSMutableSet *returnedMessageIDs = [[[NSMutableSet alloc] init] autorelease]; [feedMessages enumerateObjectsUsingBlock:^(id objMessage, NSUInteger messagesIdx, BOOL *stop) { @@ -547,7 +547,7 @@ - (void)updateMessageListFromResponse:(NSDictionary *)jsonDictionary { [_feedbackList addObject:message]; - newResponseMessage = YES; + newMessage = YES; } } else { // we should never get any messages back that are already stored locally, @@ -558,8 +558,17 @@ - (void)updateMessageListFromResponse:(NSDictionary *)jsonDictionary { [self markSendInProgressMessagesAsPending]; // we got a new incoming message, trigger user notification system - if (newResponseMessage) { - if (self.showAlertOnIncomingMessages && !self.currentFeedbackListViewController && !self.currentFeedbackComposeViewController) { + if (newMessage) { + // check if the latest message is from the users own email address, then don't show an alert since he answered using his own email + BOOL latestMessageFromUser = NO; + + [self sortFeedbackList]; + + BITFeedbackMessage *latestMessage = [self lastMessageHavingID]; + if (self.userEmail && [latestMessage.email compare:self.userEmail] == NSOrderedSame) + latestMessageFromUser = YES; + + if (!latestMessageFromUser && self.showAlertOnIncomingMessages && !self.currentFeedbackListViewController && !self.currentFeedbackComposeViewController) { UIAlertView *alertView = [[[UIAlertView alloc] initWithTitle:BITHockeyLocalizedString(@"HockeyFeedbackNewMessageTitle") message:BITHockeyLocalizedString(@"HockeyFeedbackNewMessageText") delegate:self From 147b5ec621032a1a010bfca980f66c8180a719d5 Mon Sep 17 00:00:00 2001 From: Andreas Linde Date: Mon, 15 Oct 2012 19:32:15 +0200 Subject: [PATCH 040/176] Add support for deleting single or all messages --- Classes/BITFeedbackListViewCell.m | 11 ++- Classes/BITFeedbackListViewController.h | 2 +- Classes/BITFeedbackListViewController.m | 99 ++++++++++++++++++++----- Classes/BITFeedbackManager.m | 46 ++++++++++-- Classes/BITFeedbackManagerPrivate.h | 4 + Resources/de.lproj/HockeySDK.strings | 17 ++++- Resources/en.lproj/HockeySDK.strings | 17 ++++- Resources/es.lproj/HockeySDK.strings | 17 ++++- Resources/fr.lproj/HockeySDK.strings | 17 ++++- Resources/it.lproj/HockeySDK.strings | 17 ++++- Resources/ja.lproj/HockeySDK.strings | 17 ++++- Resources/nl.lproj/HockeySDK.strings | 17 ++++- Resources/pt-PT.lproj/HockeySDK.strings | 17 ++++- Resources/pt.lproj/HockeySDK.strings | 17 ++++- Resources/ru.lproj/HockeySDK.strings | 17 ++++- Resources/sv.lproj/HockeySDK.strings | 17 ++++- Resources/tr.lproj/HockeySDK.strings | 17 ++++- Resources/zh_CN.lproj/HockeySDK.strings | 17 ++++- Resources/zh_TW.lproj/HockeySDK.strings | 17 ++++- 19 files changed, 358 insertions(+), 42 deletions(-) diff --git a/Classes/BITFeedbackListViewCell.m b/Classes/BITFeedbackListViewCell.m index 89346bbd..12f5062e 100644 --- a/Classes/BITFeedbackListViewCell.m +++ b/Classes/BITFeedbackListViewCell.m @@ -139,14 +139,16 @@ + (CGFloat) heightForRowWithText:(NSString *)text tableViewWidth:(CGFloat)width } - (void)layoutSubviews { - [super layoutSubviews]; - + UIView *accessoryViewBackground = [[[UIView alloc] initWithFrame:CGRectMake(0, 2, self.frame.size.width * 2, self.frame.size.height - 2)] autorelease]; + // colors if (_backgroundStyle == BITFeedbackListViewCellBackgroundStyleNormal) { + accessoryViewBackground.backgroundColor = BACKGROUNDCOLOR_DEFAULT; self.contentView.backgroundColor = BACKGROUNDCOLOR_DEFAULT; self.labelTitle.backgroundColor = BACKGROUNDCOLOR_DEFAULT; self.labelText.backgroundColor = BACKGROUNDCOLOR_DEFAULT; } else { + accessoryViewBackground.backgroundColor = BACKGROUNDCOLOR_ALTERNATE; self.contentView.backgroundColor = BACKGROUNDCOLOR_ALTERNATE; self.labelTitle.backgroundColor = BACKGROUNDCOLOR_ALTERNATE; self.labelText.backgroundColor = BACKGROUNDCOLOR_ALTERNATE; @@ -158,6 +160,9 @@ - (void)layoutSubviews { [self.labelText setTextColor:TEXTCOLOR_PENDING]; } + // background for deletion accessory view + [self addSubview:accessoryViewBackground]; + // header NSString *dateString; if (self.date) { @@ -190,6 +195,8 @@ - (void)layoutSubviews { [self.labelText setFrame:CGRectMake(FRAME_SIDE_BORDER, LABEL_TEXT_Y, size.width, size.height)]; [self addSubview:self.labelText]; + + [super layoutSubviews]; } diff --git a/Classes/BITFeedbackListViewController.h b/Classes/BITFeedbackListViewController.h index 9ed216bd..c77a4808 100644 --- a/Classes/BITFeedbackListViewController.h +++ b/Classes/BITFeedbackListViewController.h @@ -32,7 +32,7 @@ #import "BITHockeyBaseViewController.h" -@interface BITFeedbackListViewController : BITHockeyBaseViewController { +@interface BITFeedbackListViewController : BITHockeyBaseViewController { } @end \ No newline at end of file diff --git a/Classes/BITFeedbackListViewController.m b/Classes/BITFeedbackListViewController.m index 3f972251..209dbcb3 100644 --- a/Classes/BITFeedbackListViewController.m +++ b/Classes/BITFeedbackListViewController.m @@ -43,9 +43,12 @@ #define DEFAULT_BACKGROUNDCOLOR BIT_RGBCOLOR(245, 245, 245) #define DEFAULT_TEXTCOLOR BIT_RGBCOLOR(75, 75, 75) +#define BUTTON_DELETE_BACKGROUNDCOLOR BIT_RGBCOLOR(225, 0, 0) #define BUTTON_BACKGROUNDCOLOR BIT_RGBCOLOR(225, 225, 225) #define BUTTON_BORDERCOLOR BIT_RGBCOLOR(175, 175, 175) +#define BUTTON_DELETE_TEXTCOLOR BIT_RGBCOLOR(240, 240, 240) #define BUTTON_TEXTCOLOR BIT_RGBCOLOR(58, 58, 58) +#define BUTTON_DELETE_TEXTCOLOR_SHADOW BIT_RGBCOLOR(175, 175, 175) #define BUTTON_TEXTCOLOR_SHADOW BIT_RGBCOLOR(175, 175, 175) #define BORDER_COLOR1 BIT_RGBCOLOR(215, 215, 215) #define BORDER_COLOR2 BIT_RGBCOLOR(221, 221, 221) @@ -201,6 +204,23 @@ - (void)newFeedbackAction:(id)sender { [self.navigationController presentModalViewController:navController animated:YES]; } +- (void)deleteAllMessages { + [_manager deleteAllMessages]; + [self.tableView reloadData]; +} + +- (void)deleteAllMessagesAction:(id)sender { + UIActionSheet *deleteAction = [[UIActionSheet alloc] initWithTitle:BITHockeyLocalizedString(@"HockeyFeedbackListDeleteAllTitle") + delegate:self + cancelButtonTitle:BITHockeyLocalizedString(@"HockeyFeedbackListDeleteAllCancel") + destructiveButtonTitle:BITHockeyLocalizedString(@"HockeyFeedbackListDeleteAllDelete") + otherButtonTitles:nil + ]; + [deleteAction setActionSheetStyle:UIActionSheetStyleBlackTranslucent]; + [deleteAction showInView:self.view]; + [deleteAction release]; +} + #pragma mark - BITFeedbackUserDataDelegate @@ -222,16 +242,17 @@ - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { if ([self.manager isManualUserDataAvailable] || [self.manager didAskUserData]) rows++; + if ([self.manager numberOfMessages] > 0) + rows++; + return rows; } - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { - if (section == 0) { - return 1; - } else if (section == 2) { - return 1; - } else { + if (section == 1) { return [self.manager numberOfMessages]; + } else { + return 1; } } @@ -240,6 +261,7 @@ - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(N static NSString *LastUpdateIdentifier = @"LastUpdateCell"; static NSString *ButtonTopIdentifier = @"ButtonTopCell"; static NSString *ButtonBottomIdentifier = @"ButtonBottomCell"; + static NSString *ButtonDeleteIdentifier = @"ButtonDeleteCell"; if (indexPath.section == 0 && indexPath.row == 1) { UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:LastUpdateIdentifier]; @@ -257,30 +279,33 @@ - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(N [self.manager lastCheck] ? [self.lastUpdateDateFormatter stringFromDate:[self.manager lastCheck]] : BITHockeyLocalizedString(@"HockeyFeedbackListNeverUpdated")]; return cell; - } else if (indexPath.section == 0 || indexPath.section == 2) { + } else if (indexPath.section == 0 || indexPath.section == 2 || indexPath.section == 3) { CGFloat topGap = 0.0f; UITableViewCell *cell = nil; - if (indexPath.section == 0) { - cell = [tableView dequeueReusableCellWithIdentifier:ButtonTopIdentifier]; + NSString *identifier = nil; - if (!cell) { - cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:ButtonTopIdentifier] autorelease]; - } + if (indexPath.section == 0) { + identifier = ButtonTopIdentifier; + } else if (indexPath.section == 2) { + identifier = ButtonBottomIdentifier; } else { - cell = [tableView dequeueReusableCellWithIdentifier:ButtonBottomIdentifier]; - - if (!cell) { - cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:ButtonBottomIdentifier] autorelease]; - } + identifier = ButtonDeleteIdentifier; + } + + cell = [tableView dequeueReusableCellWithIdentifier:identifier]; + + if (!cell) { + cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:identifier] autorelease]; } + cell.textLabel.font = [UIFont systemFontOfSize:14]; cell.textLabel.numberOfLines = 0; cell.accessoryType = UITableViewCellAccessoryNone; cell.selectionStyle = UITableViewCellSelectionStyleNone; - + // button UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom]; [button.layer setMasksToBounds:YES]; [button.layer setCornerRadius:10.0f]; @@ -298,7 +323,7 @@ - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(N [button setTitle:BITHockeyLocalizedString(@"HockeyFeedbackListButonWriteResponse") forState:UIControlStateNormal]; } [button addTarget:self action:@selector(newFeedbackAction:) forControlEvents:UIControlEventTouchUpInside]; - } else { + } else if (indexPath.section == 2) { topGap = 6.0f; NSString *title = @""; if ([self.manager requireUserName] == BITFeedbackUserDataElementRequired || @@ -316,11 +341,19 @@ - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(N } [button setTitle:title forState:UIControlStateNormal]; [button addTarget:self action:@selector(setUserDataAction:) forControlEvents:UIControlEventTouchUpInside]; + } else { + [button.layer setBackgroundColor:BUTTON_DELETE_BACKGROUNDCOLOR.CGColor]; + [button setTitleColor:BUTTON_DELETE_TEXTCOLOR forState:UIControlStateNormal]; + [button setTitleShadowColor:BUTTON_DELETE_TEXTCOLOR_SHADOW forState:UIControlStateNormal]; + + [button setTitle:BITHockeyLocalizedString(@"HockeyFeedbackListButonDeleteAllMessages") forState:UIControlStateNormal]; + [button addTarget:self action:@selector(deleteAllMessagesAction:) forControlEvents:UIControlEventTouchUpInside]; } [button setFrame: CGRectMake( 10.0f, topGap + 12.0f, self.view.frame.size.width - 20.0f, 42.0f)]; [cell addSubview:button]; + // status label or shadow lines if (indexPath.section == 0) { UILabel *statusLabel = [[[UILabel alloc] initWithFrame:CGRectMake(0, 59, self.view.frame.size.width, 28)] autorelease]; @@ -334,7 +367,7 @@ - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(N [self.manager lastCheck] ? [self.lastUpdateDateFormatter stringFromDate:[self.manager lastCheck]] : BITHockeyLocalizedString(@"HockeyFeedbackListNeverUpdated")]; [cell addSubview:statusLabel]; - } else { + } else if (indexPath.section == 2) { UIView *lineView1 = [[[UIView alloc] initWithFrame:CGRectMake(0, 0, cell.contentView.bounds.size.width, 1)] autorelease]; lineView1.backgroundColor = BORDER_COLOR1; lineView1.autoresizingMask = UIViewAutoresizingFlexibleWidth; @@ -384,7 +417,7 @@ - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(N if (message.name && [message.name length] > 0) { cell.name = message.name; } else { - cell.name = BITHockeyLocalizedString(@"HockeyFeedbackListmessageResponseNameNotSet"); + cell.name = BITHockeyLocalizedString(@"HockeyFeedbackListMessageResponseNameNotSet"); } } @@ -414,6 +447,22 @@ - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(N } +- (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath { + if (indexPath.section == 1) + return YES; + + return NO; +} + +- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath { + if (editingStyle == UITableViewCellEditingStyleDelete) { + if ([_manager deleteMessageAtIndex:indexPath.row]) { + [tableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationAutomatic]; + } + } +} + + #pragma mark - Table view delegate - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath { @@ -430,4 +479,14 @@ - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPa return [BITFeedbackListViewCell heightForRowWithText:message.text tableViewWidth:self.view.frame.size.width]; } + + +#pragma mark - UIActionSheetDelegate + +- (void)actionSheet:(UIActionSheet *)actionSheet didDismissWithButtonIndex:(NSInteger)buttonIndex { + if (buttonIndex == [actionSheet destructiveButtonIndex]) { + [self deleteAllMessages]; + } +} + @end diff --git a/Classes/BITFeedbackManager.m b/Classes/BITFeedbackManager.m index cf75359a..355b0b69 100644 --- a/Classes/BITFeedbackManager.m +++ b/Classes/BITFeedbackManager.m @@ -76,6 +76,7 @@ - (id)init { _incomingMessagesAlertShowing = NO; _lastCheck = nil; _token = nil; + _lastMessageID = nil; self.feedbackList = [NSMutableArray array]; @@ -111,6 +112,7 @@ - (void)dealloc { [_lastCheck release], _lastCheck = nil; [_token release], _token = nil; + [_lastMessageID release], _lastMessageID = nil; [_feedbackList release], _feedbackList = nil; [_userName release], _userName = nil; @@ -284,6 +286,9 @@ - (void)loadMessages { if ([unarchiver containsValueForKey:kBITFeedbackDateOfLastCheck]) self.lastCheck = [unarchiver decodeObjectForKey:kBITFeedbackDateOfLastCheck]; + if ([unarchiver containsValueForKey:kBITFeedbackLastMessageID]) + self.lastMessageID = [unarchiver decodeObjectForKey:kBITFeedbackLastMessageID]; + if ([unarchiver containsValueForKey:kBITFeedbackMessages]) { [self.feedbackList setArray:[unarchiver decodeObjectForKey:kBITFeedbackMessages]]; @@ -323,6 +328,9 @@ - (void)saveMessages { if (self.lastCheck) [archiver encodeObject:self.lastCheck forKey:kBITFeedbackDateOfLastCheck]; + if (self.lastMessageID) + [archiver encodeObject:self.lastMessageID forKey:kBITFeedbackLastMessageID]; + [archiver encodeObject:self.feedbackList forKey:kBITFeedbackMessages]; [archiver finishEncoding]; @@ -431,6 +439,31 @@ - (void)markSendInProgressMessagesAsInConflict { }]; } +- (void)updateLastMessageID { + BITFeedbackMessage *lastMessageHavingID = [self lastMessageHavingID]; + if (lastMessageHavingID) { + if (!self.lastMessageID || [self.lastMessageID compare:[lastMessageHavingID id]] != NSOrderedSame) + self.lastMessageID = [lastMessageHavingID id]; + } +} + +- (BOOL)deleteMessageAtIndex:(NSUInteger)index { + if (_feedbackList && [_feedbackList count] > index && [_feedbackList objectAtIndex:index]) { + [_feedbackList removeObjectAtIndex:index]; + + [self saveMessages]; + return YES; + } + + return NO; +} + +- (void)deleteAllMessages { + [_feedbackList removeAllObjects]; + + [self saveMessages]; +} + #pragma mark - User @@ -563,7 +596,8 @@ - (void)updateMessageListFromResponse:(NSDictionary *)jsonDictionary { BOOL latestMessageFromUser = NO; [self sortFeedbackList]; - + [self updateLastMessageID]; + BITFeedbackMessage *latestMessage = [self lastMessageHavingID]; if (self.userEmail && [latestMessage.email compare:self.userEmail] == NSOrderedSame) latestMessageFromUser = YES; @@ -611,9 +645,11 @@ - (void)sendNetworkRequestWithHTTPMethod:(NSString *)httpMethod withMessage:(BIT NSMutableString *parameter = [NSMutableString stringWithFormat:@"api/2/apps/%@/feedback%@", [self encodedAppIdentifier], tokenParameter]; NSString *lastMessageID = @""; - BITFeedbackMessage *lastMessageHavingID = [self lastMessageHavingID]; - if (lastMessageHavingID) { - lastMessageID = [NSString stringWithFormat:@"&last_message_id=%i", [[lastMessageHavingID id] integerValue]]; + if (!self.lastMessageID) { + [self updateLastMessageID]; + } + if (self.lastMessageID) { + lastMessageID = [NSString stringWithFormat:@"&last_message_id=%i", [self.lastMessageID integerValue]]; } [parameter appendFormat:@"?format=json&bundle_version=%@&sdk=%@&sdk_version=%@%@", @@ -727,7 +763,7 @@ - (void)sendNetworkRequestWithHTTPMethod:(NSString *)httpMethod withMessage:(BIT } - (void)fetchMessageUpdates { - if ([_feedbackList count] == 0) { + if ([_feedbackList count] == 0 && !self.token) { // inform the UI to update its data in case the list is already showing [[NSNotificationCenter defaultCenter] postNotificationName:BITHockeyFeedbackMessagesLoadingFinished object:nil]; diff --git a/Classes/BITFeedbackManagerPrivate.h b/Classes/BITFeedbackManagerPrivate.h index 0e04657d..a907dc48 100644 --- a/Classes/BITFeedbackManagerPrivate.h +++ b/Classes/BITFeedbackManagerPrivate.h @@ -49,6 +49,8 @@ @property (nonatomic, retain) NSDate *lastCheck; +@property (nonatomic, retain) NSNumber *lastMessageID; + @property (nonatomic, copy) NSString *userName; @property (nonatomic, copy) NSString *userEmail; @@ -87,5 +89,7 @@ - (void)fetchMessageUpdates; - (void)updateMessageListFromResponse:(NSDictionary *)jsonDictionary; +- (BOOL)deleteMessageAtIndex:(NSUInteger)index; +- (void)deleteAllMessages; @end diff --git a/Resources/de.lproj/HockeySDK.strings b/Resources/de.lproj/HockeySDK.strings index b81619c8..f1704fed 100755 --- a/Resources/de.lproj/HockeySDK.strings +++ b/Resources/de.lproj/HockeySDK.strings @@ -158,16 +158,31 @@ /* User Data With Email Button Title */ "HockeyFeedbackListButonUserDataWithEmail" = "Email: %@"; +/* Button title for deleting all local messages*/ +"HockeyFeedbackListButonDeleteAllMessages" = "Delete All Messages"; + /* User Name In Message If Name Not Set */ "HockeyFeedbackListMessageUserNameNotSet" = "You"; /* Name In Message From Server If Name Not Set */ -"HockeyFeedbackListmessageResponseNameNotSet" = "Response"; +"HockeyFeedbackListMessageResponseNameNotSet" = "Response"; /* Message pending to be send */ "HockeyFeedbackListMessagePending" = "Pending"; +/* Delete All Messages Action Sheet */ + +/* Title for the Action Sheet */ +"HockeyFeedbackListDeleteAllTitle" = "This will delete all messages on this device."; + +/* Button Title to perform delete action */ +"HockeyFeedbackListDeleteAllDelete" = "Delete"; + +/* Button Title to cancel delete action */ +"HockeyFeedbackListDeleteAllCancel" = "Cancel"; + + /* Compose Message */ /* Title */ diff --git a/Resources/en.lproj/HockeySDK.strings b/Resources/en.lproj/HockeySDK.strings index 334e6192..301a4b13 100755 --- a/Resources/en.lproj/HockeySDK.strings +++ b/Resources/en.lproj/HockeySDK.strings @@ -155,16 +155,31 @@ /* User Data With Email Button Title */ "HockeyFeedbackListButonUserDataWithEmail" = "Email: %@"; +/* Button title for deleting all local messages*/ +"HockeyFeedbackListButonDeleteAllMessages" = "Delete All Messages"; + /* User Name In Message If Name Not Set */ "HockeyFeedbackListMessageUserNameNotSet" = "You"; /* Name In Message From Server If Name Not Set */ -"HockeyFeedbackListmessageResponseNameNotSet" = "Response"; +"HockeyFeedbackListMessageResponseNameNotSet" = "Response"; /* Message pending to be send */ "HockeyFeedbackListMessagePending" = "Pending"; +/* Delete All Messages Action Sheet */ + +/* Title for the Action Sheet */ +"HockeyFeedbackListDeleteAllTitle" = "This will delete all messages on this device."; + +/* Button Title to perform delete action */ +"HockeyFeedbackListDeleteAllDelete" = "Delete"; + +/* Button Title to cancel delete action */ +"HockeyFeedbackListDeleteAllCancel" = "Cancel"; + + /* Compose Message */ /* Title */ diff --git a/Resources/es.lproj/HockeySDK.strings b/Resources/es.lproj/HockeySDK.strings index c39ad438..f71d05b4 100755 --- a/Resources/es.lproj/HockeySDK.strings +++ b/Resources/es.lproj/HockeySDK.strings @@ -156,16 +156,31 @@ /* User Data With Email Button Title */ "HockeyFeedbackListButonUserDataWithEmail" = "Email: %@"; +/* Button title for deleting all local messages*/ +"HockeyFeedbackListButonDeleteAllMessages" = "Delete All Messages"; + /* User Name In Message If Name Not Set */ "HockeyFeedbackListMessageUserNameNotSet" = "You"; /* Name In Message From Server If Name Not Set */ -"HockeyFeedbackListmessageResponseNameNotSet" = "Response"; +"HockeyFeedbackListMessageResponseNameNotSet" = "Response"; /* Message pending to be send */ "HockeyFeedbackListMessagePending" = "Pending"; +/* Delete All Messages Action Sheet */ + +/* Title for the Action Sheet */ +"HockeyFeedbackListDeleteAllTitle" = "This will delete all messages on this device."; + +/* Button Title to perform delete action */ +"HockeyFeedbackListDeleteAllDelete" = "Delete"; + +/* Button Title to cancel delete action */ +"HockeyFeedbackListDeleteAllCancel" = "Cancel"; + + /* Compose Message */ /* Title */ diff --git a/Resources/fr.lproj/HockeySDK.strings b/Resources/fr.lproj/HockeySDK.strings index df6c1451..82b14982 100755 --- a/Resources/fr.lproj/HockeySDK.strings +++ b/Resources/fr.lproj/HockeySDK.strings @@ -156,16 +156,31 @@ /* User Data With Email Button Title */ "HockeyFeedbackListButonUserDataWithEmail" = "Email: %@"; +/* Button title for deleting all local messages*/ +"HockeyFeedbackListButonDeleteAllMessages" = "Delete All Messages"; + /* User Name In Message If Name Not Set */ "HockeyFeedbackListMessageUserNameNotSet" = "You"; /* Name In Message From Server If Name Not Set */ -"HockeyFeedbackListmessageResponseNameNotSet" = "Response"; +"HockeyFeedbackListMessageResponseNameNotSet" = "Response"; /* Message pending to be send */ "HockeyFeedbackListMessagePending" = "Pending"; +/* Delete All Messages Action Sheet */ + +/* Title for the Action Sheet */ +"HockeyFeedbackListDeleteAllTitle" = "This will delete all messages on this device."; + +/* Button Title to perform delete action */ +"HockeyFeedbackListDeleteAllDelete" = "Delete"; + +/* Button Title to cancel delete action */ +"HockeyFeedbackListDeleteAllCancel" = "Cancel"; + + /* Compose Message */ /* Title */ diff --git a/Resources/it.lproj/HockeySDK.strings b/Resources/it.lproj/HockeySDK.strings index 80828c94..b31c94e6 100755 --- a/Resources/it.lproj/HockeySDK.strings +++ b/Resources/it.lproj/HockeySDK.strings @@ -156,16 +156,31 @@ /* User Data With Email Button Title */ "HockeyFeedbackListButonUserDataWithEmail" = "Email: %@"; +/* Button title for deleting all local messages*/ +"HockeyFeedbackListButonDeleteAllMessages" = "Delete All Messages"; + /* User Name In Message If Name Not Set */ "HockeyFeedbackListMessageUserNameNotSet" = "You"; /* Name In Message From Server If Name Not Set */ -"HockeyFeedbackListmessageResponseNameNotSet" = "Response"; +"HockeyFeedbackListMessageResponseNameNotSet" = "Response"; /* Message pending to be send */ "HockeyFeedbackListMessagePending" = "Pending"; +/* Delete All Messages Action Sheet */ + +/* Title for the Action Sheet */ +"HockeyFeedbackListDeleteAllTitle" = "This will delete all messages on this device."; + +/* Button Title to perform delete action */ +"HockeyFeedbackListDeleteAllDelete" = "Delete"; + +/* Button Title to cancel delete action */ +"HockeyFeedbackListDeleteAllCancel" = "Cancel"; + + /* Compose Message */ /* Title */ diff --git a/Resources/ja.lproj/HockeySDK.strings b/Resources/ja.lproj/HockeySDK.strings index 63f8b86f..0d6a5fd7 100755 --- a/Resources/ja.lproj/HockeySDK.strings +++ b/Resources/ja.lproj/HockeySDK.strings @@ -156,16 +156,31 @@ /* User Data With Email Button Title */ "HockeyFeedbackListButonUserDataWithEmail" = "Email: %@"; +/* Button title for deleting all local messages*/ +"HockeyFeedbackListButonDeleteAllMessages" = "Delete All Messages"; + /* User Name In Message If Name Not Set */ "HockeyFeedbackListMessageUserNameNotSet" = "You"; /* Name In Message From Server If Name Not Set */ -"HockeyFeedbackListmessageResponseNameNotSet" = "Response"; +"HockeyFeedbackListMessageResponseNameNotSet" = "Response"; /* Message pending to be send */ "HockeyFeedbackListMessagePending" = "Pending"; +/* Delete All Messages Action Sheet */ + +/* Title for the Action Sheet */ +"HockeyFeedbackListDeleteAllTitle" = "This will delete all messages on this device."; + +/* Button Title to perform delete action */ +"HockeyFeedbackListDeleteAllDelete" = "Delete"; + +/* Button Title to cancel delete action */ +"HockeyFeedbackListDeleteAllCancel" = "Cancel"; + + /* Compose Message */ /* Title */ diff --git a/Resources/nl.lproj/HockeySDK.strings b/Resources/nl.lproj/HockeySDK.strings index 1dfdfe0f..27d3f6c6 100755 --- a/Resources/nl.lproj/HockeySDK.strings +++ b/Resources/nl.lproj/HockeySDK.strings @@ -156,16 +156,31 @@ /* User Data With Email Button Title */ "HockeyFeedbackListButonUserDataWithEmail" = "Email: %@"; +/* Button title for deleting all local messages*/ +"HockeyFeedbackListButonDeleteAllMessages" = "Delete All Messages"; + /* User Name In Message If Name Not Set */ "HockeyFeedbackListMessageUserNameNotSet" = "You"; /* Name In Message From Server If Name Not Set */ -"HockeyFeedbackListmessageResponseNameNotSet" = "Response"; +"HockeyFeedbackListMessageResponseNameNotSet" = "Response"; /* Message pending to be send */ "HockeyFeedbackListMessagePending" = "Pending"; +/* Delete All Messages Action Sheet */ + +/* Title for the Action Sheet */ +"HockeyFeedbackListDeleteAllTitle" = "This will delete all messages on this device."; + +/* Button Title to perform delete action */ +"HockeyFeedbackListDeleteAllDelete" = "Delete"; + +/* Button Title to cancel delete action */ +"HockeyFeedbackListDeleteAllCancel" = "Cancel"; + + /* Compose Message */ /* Title */ diff --git a/Resources/pt-PT.lproj/HockeySDK.strings b/Resources/pt-PT.lproj/HockeySDK.strings index 298f9980..0c4d4892 100755 --- a/Resources/pt-PT.lproj/HockeySDK.strings +++ b/Resources/pt-PT.lproj/HockeySDK.strings @@ -156,16 +156,31 @@ /* User Data With Email Button Title */ "HockeyFeedbackListButonUserDataWithEmail" = "Email: %@"; +/* Button title for deleting all local messages*/ +"HockeyFeedbackListButonDeleteAllMessages" = "Delete All Messages"; + /* User Name In Message If Name Not Set */ "HockeyFeedbackListMessageUserNameNotSet" = "You"; /* Name In Message From Server If Name Not Set */ -"HockeyFeedbackListmessageResponseNameNotSet" = "Response"; +"HockeyFeedbackListMessageResponseNameNotSet" = "Response"; /* Message pending to be send */ "HockeyFeedbackListMessagePending" = "Pending"; +/* Delete All Messages Action Sheet */ + +/* Title for the Action Sheet */ +"HockeyFeedbackListDeleteAllTitle" = "This will delete all messages on this device."; + +/* Button Title to perform delete action */ +"HockeyFeedbackListDeleteAllDelete" = "Delete"; + +/* Button Title to cancel delete action */ +"HockeyFeedbackListDeleteAllCancel" = "Cancel"; + + /* Compose Message */ /* Title */ diff --git a/Resources/pt.lproj/HockeySDK.strings b/Resources/pt.lproj/HockeySDK.strings index a0525521..c6d926c9 100755 --- a/Resources/pt.lproj/HockeySDK.strings +++ b/Resources/pt.lproj/HockeySDK.strings @@ -156,16 +156,31 @@ /* User Data With Email Button Title */ "HockeyFeedbackListButonUserDataWithEmail" = "Email: %@"; +/* Button title for deleting all local messages*/ +"HockeyFeedbackListButonDeleteAllMessages" = "Delete All Messages"; + /* User Name In Message If Name Not Set */ "HockeyFeedbackListMessageUserNameNotSet" = "You"; /* Name In Message From Server If Name Not Set */ -"HockeyFeedbackListmessageResponseNameNotSet" = "Response"; +"HockeyFeedbackListMessageResponseNameNotSet" = "Response"; /* Message pending to be send */ "HockeyFeedbackListMessagePending" = "Pending"; +/* Delete All Messages Action Sheet */ + +/* Title for the Action Sheet */ +"HockeyFeedbackListDeleteAllTitle" = "This will delete all messages on this device."; + +/* Button Title to perform delete action */ +"HockeyFeedbackListDeleteAllDelete" = "Delete"; + +/* Button Title to cancel delete action */ +"HockeyFeedbackListDeleteAllCancel" = "Cancel"; + + /* Compose Message */ /* Title */ diff --git a/Resources/ru.lproj/HockeySDK.strings b/Resources/ru.lproj/HockeySDK.strings index f15bc9c4..7880a7fe 100755 --- a/Resources/ru.lproj/HockeySDK.strings +++ b/Resources/ru.lproj/HockeySDK.strings @@ -156,16 +156,31 @@ /* User Data With Email Button Title */ "HockeyFeedbackListButonUserDataWithEmail" = "Email: %@"; +/* Button title for deleting all local messages*/ +"HockeyFeedbackListButonDeleteAllMessages" = "Delete All Messages"; + /* User Name In Message If Name Not Set */ "HockeyFeedbackListMessageUserNameNotSet" = "You"; /* Name In Message From Server If Name Not Set */ -"HockeyFeedbackListmessageResponseNameNotSet" = "Response"; +"HockeyFeedbackListMessageResponseNameNotSet" = "Response"; /* Message pending to be send */ "HockeyFeedbackListMessagePending" = "Pending"; +/* Delete All Messages Action Sheet */ + +/* Title for the Action Sheet */ +"HockeyFeedbackListDeleteAllTitle" = "This will delete all messages on this device."; + +/* Button Title to perform delete action */ +"HockeyFeedbackListDeleteAllDelete" = "Delete"; + +/* Button Title to cancel delete action */ +"HockeyFeedbackListDeleteAllCancel" = "Cancel"; + + /* Compose Message */ /* Title */ diff --git a/Resources/sv.lproj/HockeySDK.strings b/Resources/sv.lproj/HockeySDK.strings index e42c6b98..82194722 100755 --- a/Resources/sv.lproj/HockeySDK.strings +++ b/Resources/sv.lproj/HockeySDK.strings @@ -156,16 +156,31 @@ /* User Data With Email Button Title */ "HockeyFeedbackListButonUserDataWithEmail" = "Email: %@"; +/* Button title for deleting all local messages*/ +"HockeyFeedbackListButonDeleteAllMessages" = "Delete All Messages"; + /* User Name In Message If Name Not Set */ "HockeyFeedbackListMessageUserNameNotSet" = "You"; /* Name In Message From Server If Name Not Set */ -"HockeyFeedbackListmessageResponseNameNotSet" = "Response"; +"HockeyFeedbackListMessageResponseNameNotSet" = "Response"; /* Message pending to be send */ "HockeyFeedbackListMessagePending" = "Pending"; +/* Delete All Messages Action Sheet */ + +/* Title for the Action Sheet */ +"HockeyFeedbackListDeleteAllTitle" = "This will delete all messages on this device."; + +/* Button Title to perform delete action */ +"HockeyFeedbackListDeleteAllDelete" = "Delete"; + +/* Button Title to cancel delete action */ +"HockeyFeedbackListDeleteAllCancel" = "Cancel"; + + /* Compose Message */ /* Title */ diff --git a/Resources/tr.lproj/HockeySDK.strings b/Resources/tr.lproj/HockeySDK.strings index 6898b29a..42eb475f 100644 --- a/Resources/tr.lproj/HockeySDK.strings +++ b/Resources/tr.lproj/HockeySDK.strings @@ -156,16 +156,31 @@ /* User Data With Email Button Title */ "HockeyFeedbackListButonUserDataWithEmail" = "Email: %@"; +/* Button title for deleting all local messages*/ +"HockeyFeedbackListButonDeleteAllMessages" = "Delete All Messages"; + /* User Name In Message If Name Not Set */ "HockeyFeedbackListMessageUserNameNotSet" = "You"; /* Name In Message From Server If Name Not Set */ -"HockeyFeedbackListmessageResponseNameNotSet" = "Response"; +"HockeyFeedbackListMessageResponseNameNotSet" = "Response"; /* Message pending to be send */ "HockeyFeedbackListMessagePending" = "Pending"; +/* Delete All Messages Action Sheet */ + +/* Title for the Action Sheet */ +"HockeyFeedbackListDeleteAllTitle" = "This will delete all messages on this device."; + +/* Button Title to perform delete action */ +"HockeyFeedbackListDeleteAllDelete" = "Delete"; + +/* Button Title to cancel delete action */ +"HockeyFeedbackListDeleteAllCancel" = "Cancel"; + + /* Compose Message */ /* Title */ diff --git a/Resources/zh_CN.lproj/HockeySDK.strings b/Resources/zh_CN.lproj/HockeySDK.strings index c1dd8dce..443dc1be 100644 --- a/Resources/zh_CN.lproj/HockeySDK.strings +++ b/Resources/zh_CN.lproj/HockeySDK.strings @@ -156,16 +156,31 @@ /* User Data With Email Button Title */ "HockeyFeedbackListButonUserDataWithEmail" = "Email: %@"; +/* Button title for deleting all local messages*/ +"HockeyFeedbackListButonDeleteAllMessages" = "Delete All Messages"; + /* User Name In Message If Name Not Set */ "HockeyFeedbackListMessageUserNameNotSet" = "You"; /* Name In Message From Server If Name Not Set */ -"HockeyFeedbackListmessageResponseNameNotSet" = "Response"; +"HockeyFeedbackListMessageResponseNameNotSet" = "Response"; /* Message pending to be send */ "HockeyFeedbackListMessagePending" = "Pending"; +/* Delete All Messages Action Sheet */ + +/* Title for the Action Sheet */ +"HockeyFeedbackListDeleteAllTitle" = "This will delete all messages on this device."; + +/* Button Title to perform delete action */ +"HockeyFeedbackListDeleteAllDelete" = "Delete"; + +/* Button Title to cancel delete action */ +"HockeyFeedbackListDeleteAllCancel" = "Cancel"; + + /* Compose Message */ /* Title */ diff --git a/Resources/zh_TW.lproj/HockeySDK.strings b/Resources/zh_TW.lproj/HockeySDK.strings index 865c3fe9..3e7b98cf 100644 --- a/Resources/zh_TW.lproj/HockeySDK.strings +++ b/Resources/zh_TW.lproj/HockeySDK.strings @@ -156,16 +156,31 @@ /* User Data With Email Button Title */ "HockeyFeedbackListButonUserDataWithEmail" = "Email: %@"; +/* Button title for deleting all local messages*/ +"HockeyFeedbackListButonDeleteAllMessages" = "Delete All Messages"; + /* User Name In Message If Name Not Set */ "HockeyFeedbackListMessageUserNameNotSet" = "You"; /* Name In Message From Server If Name Not Set */ -"HockeyFeedbackListmessageResponseNameNotSet" = "Response"; +"HockeyFeedbackListMessageResponseNameNotSet" = "Response"; /* Message pending to be send */ "HockeyFeedbackListMessagePending" = "Pending"; +/* Delete All Messages Action Sheet */ + +/* Title for the Action Sheet */ +"HockeyFeedbackListDeleteAllTitle" = "This will delete all messages on this device."; + +/* Button Title to perform delete action */ +"HockeyFeedbackListDeleteAllDelete" = "Delete"; + +/* Button Title to cancel delete action */ +"HockeyFeedbackListDeleteAllCancel" = "Cancel"; + + /* Compose Message */ /* Title */ From 795381d72facc0dfc2a6888b4f0f9d145e8d7e45 Mon Sep 17 00:00:00 2001 From: Andreas Linde Date: Mon, 15 Oct 2012 20:39:54 +0200 Subject: [PATCH 041/176] Use AlertView instead of ActionSheet when asking to delete all feedback messages on the iPad --- Classes/BITFeedbackListViewController.h | 2 +- Classes/BITFeedbackListViewController.m | 39 +++++++++++++++++++------ 2 files changed, 31 insertions(+), 10 deletions(-) diff --git a/Classes/BITFeedbackListViewController.h b/Classes/BITFeedbackListViewController.h index c77a4808..6e39fa16 100644 --- a/Classes/BITFeedbackListViewController.h +++ b/Classes/BITFeedbackListViewController.h @@ -32,7 +32,7 @@ #import "BITHockeyBaseViewController.h" -@interface BITFeedbackListViewController : BITHockeyBaseViewController { +@interface BITFeedbackListViewController : BITHockeyBaseViewController { } @end \ No newline at end of file diff --git a/Classes/BITFeedbackListViewController.m b/Classes/BITFeedbackListViewController.m index 209dbcb3..fc923205 100644 --- a/Classes/BITFeedbackListViewController.m +++ b/Classes/BITFeedbackListViewController.m @@ -210,15 +210,27 @@ - (void)deleteAllMessages { } - (void)deleteAllMessagesAction:(id)sender { - UIActionSheet *deleteAction = [[UIActionSheet alloc] initWithTitle:BITHockeyLocalizedString(@"HockeyFeedbackListDeleteAllTitle") - delegate:self - cancelButtonTitle:BITHockeyLocalizedString(@"HockeyFeedbackListDeleteAllCancel") - destructiveButtonTitle:BITHockeyLocalizedString(@"HockeyFeedbackListDeleteAllDelete") - otherButtonTitles:nil - ]; - [deleteAction setActionSheetStyle:UIActionSheetStyleBlackTranslucent]; - [deleteAction showInView:self.view]; - [deleteAction release]; + if (UI_USER_INTERFACE_IDIOM() != UIUserInterfaceIdiomPad) { + UIActionSheet *deleteAction = [[UIActionSheet alloc] initWithTitle:BITHockeyLocalizedString(@"HockeyFeedbackListDeleteAllTitle") + delegate:self + cancelButtonTitle:BITHockeyLocalizedString(@"HockeyFeedbackListDeleteAllCancel") + destructiveButtonTitle:BITHockeyLocalizedString(@"HockeyFeedbackListDeleteAllDelete") + otherButtonTitles:nil + ]; + [deleteAction setActionSheetStyle:UIActionSheetStyleBlackTranslucent]; + [deleteAction showInView:self.view]; + [deleteAction release]; + } else { + UIAlertView *deleteAction = [[UIAlertView alloc] initWithTitle:BITHockeyLocalizedString(@"HockeyFeedbackListButonDeleteAllMessages") + message:BITHockeyLocalizedString(@"HockeyFeedbackListDeleteAllTitle") + delegate:self + cancelButtonTitle:BITHockeyLocalizedString(@"HockeyFeedbackListDeleteAllCancel") + otherButtonTitles:BITHockeyLocalizedString(@"HockeyFeedbackListDeleteAllDelete"), nil]; + + [deleteAction show]; + [deleteAction release]; + + } } @@ -480,6 +492,14 @@ - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPa } +#pragma mark - UIAlertViewDelegate + +- (void)alertView:(UIAlertView *)alertView didDismissWithButtonIndex:(NSInteger)buttonIndex { + if (buttonIndex == [alertView firstOtherButtonIndex]) { + [self deleteAllMessages]; + } +} + #pragma mark - UIActionSheetDelegate @@ -489,4 +509,5 @@ - (void)actionSheet:(UIActionSheet *)actionSheet didDismissWithButtonIndex:(NSIn } } + @end From ca08b982c3c2f905c75608c7319fd0189586d9ef Mon Sep 17 00:00:00 2001 From: Andreas Linde Date: Tue, 16 Oct 2012 01:50:21 +0200 Subject: [PATCH 042/176] Add a UIActivity subclass and the option to invoke compose view from anywhere modally --- Classes/BITFeedbackActivity.h | 18 +++++ Classes/BITFeedbackActivity.m | 79 +++++++++++++++++++ Classes/BITFeedbackComposeViewController.h | 6 ++ Classes/BITFeedbackComposeViewController.m | 75 ++++++++++++++---- ...BITFeedbackComposeViewControllerDelegate.h | 31 ++++++++ Classes/BITFeedbackManager.h | 18 ++++- Classes/BITFeedbackManager.m | 14 ++++ Classes/BITHockeyBaseManager.m | 8 +- Classes/BITHockeyBaseManagerPrivate.h | 2 +- Classes/BITHockeyBaseViewController.m | 12 +-- Classes/HockeySDK.h | 2 + Support/HockeySDK.xcodeproj/project.pbxproj | 14 +++- 12 files changed, 248 insertions(+), 31 deletions(-) create mode 100644 Classes/BITFeedbackActivity.h create mode 100644 Classes/BITFeedbackActivity.m create mode 100644 Classes/BITFeedbackComposeViewControllerDelegate.h diff --git a/Classes/BITFeedbackActivity.h b/Classes/BITFeedbackActivity.h new file mode 100644 index 00000000..fa2289a7 --- /dev/null +++ b/Classes/BITFeedbackActivity.h @@ -0,0 +1,18 @@ +// +// BITFeedbackActivity.h +// HockeySDK +// +// Created by Andreas Linde on 15.10.12. +// +// + +#import + +#import "BITFeedbackComposeViewControllerDelegate.h" + +@interface BITFeedbackActivity : UIActivity + +@property (nonatomic, retain) UIImage *shareImage; +@property (nonatomic, retain) NSString *shareString; + +@end diff --git a/Classes/BITFeedbackActivity.m b/Classes/BITFeedbackActivity.m new file mode 100644 index 00000000..9529aa6d --- /dev/null +++ b/Classes/BITFeedbackActivity.m @@ -0,0 +1,79 @@ +// +// BITFeedbackActivity.m +// HockeySDK +// +// Created by Andreas Linde on 15.10.12. +// +// + +#import "BITFeedbackActivity.h" + +#import "HockeySDKPrivate.h" +#import "HockeySDK.h" +#import "BITFeedbackManagerPrivate.h" + +@implementation BITFeedbackActivity + +- (NSString *)activityType { + return @"UIActivityTypePostToHockeySDKFeedback"; +} + +- (NSString *)activityTitle { + return @"Feedback"; +} + +- (UIImage *)activityImage { + return [UIImage imageNamed:@"instagram.png"]; +} + + +- (BOOL)canPerformWithActivityItems:(NSArray *)activityItems { + if ([BITHockeyManager sharedHockeyManager].disableFeedbackManager) return NO; + + // we can present the user data screen on top of the compose screen + // so for now only allow this if all required user data is available + BITFeedbackManager *feedbackManager = [BITHockeyManager sharedHockeyManager].feedbackManager; + if ([feedbackManager askManualUserDataAvailable] && + ([feedbackManager requireManualUserDataMissing]) + ) + return NO; + + for (UIActivityItemProvider *item in activityItems) { + if ([item isKindOfClass:[UIImage class]]) { + return YES; + } else if ([item isKindOfClass:[NSString class]]) { + return YES; + } else if ([item isKindOfClass:[NSString class]]) { + return YES; + } + } + return NO; +} + +- (void)prepareWithActivityItems:(NSArray *)activityItems { + for (id item in activityItems) { + if ([item isKindOfClass:[UIImage class]]) { + self.shareImage = item; + } else if ([item isKindOfClass:[NSString class]]) { + self.shareString = [(self.shareString ? self.shareString : @"") stringByAppendingFormat:@"%@%@",(self.shareString ? @" " : @""),item]; + } else if ([item isKindOfClass:[NSURL class]]) { + self.shareString = [(self.shareString ? self.shareString : @"") stringByAppendingFormat:@"%@%@",(self.shareString ? @" " : @""),[(NSURL *)item absoluteString]]; + } else { + BITHockeyLog(@"Unknown item type %@", item); + } + } +} + +- (UIViewController *)activityViewController { + // TODO: return compose controller with activity content added + BITFeedbackComposeViewController *composeViewController = [[BITHockeyManager sharedHockeyManager].feedbackManager feedbackComposeViewControllerWithDelegate:self]; + composeViewController.modalPresentationStyle = UIModalPresentationFormSheet; + return composeViewController; +} + +-(void)feedbackComposeViewControllerDidFinish:(BITFeedbackComposeViewController *)composeViewController { + [self activityDidFinish:YES]; +} + + +@end diff --git a/Classes/BITFeedbackComposeViewController.h b/Classes/BITFeedbackComposeViewController.h index 217db38b..b59b6237 100644 --- a/Classes/BITFeedbackComposeViewController.h +++ b/Classes/BITFeedbackComposeViewController.h @@ -29,8 +29,14 @@ #import +#import "BITFeedbackComposeViewControllerDelegate.h" + + @interface BITFeedbackComposeViewController : UIViewController +@property (nonatomic, assign) id delegate; + - (id)init; +- (id)initWithDelegate:(id)delegate; @end \ No newline at end of file diff --git a/Classes/BITFeedbackComposeViewController.m b/Classes/BITFeedbackComposeViewController.m index 33c91f30..0513d469 100644 --- a/Classes/BITFeedbackComposeViewController.m +++ b/Classes/BITFeedbackComposeViewController.m @@ -57,33 +57,70 @@ - (id)init { if (self) { self.title = BITHockeyLocalizedString(@"HockeyFeedbackComposeTitle"); blockUserDataScreen = NO; + _delegate = nil; _manager = [BITHockeyManager sharedHockeyManager].feedbackManager; } return self; } + +- (id)initWithDelegate:(id)delegate { + self = [self init]; + if (self) { + _delegate = delegate; + } + return self; +} + + +#pragma mark - View lifecycle + - (void)viewDidLoad { [super viewDidLoad]; self.view.backgroundColor = [UIColor whiteColor]; - - // Do any additional setup after loading the view. - self.navigationItem.leftBarButtonItem = [[[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemCancel - target:self - action:@selector(dismissAction:)] autorelease]; - - self.navigationItem.rightBarButtonItem = [[[UIBarButtonItem alloc] initWithTitle:BITHockeyLocalizedString(@"HockeyFeedbackComposeSend") - style:UIBarButtonItemStyleDone - target:self - action:@selector(sendAction:)] autorelease]; + CGFloat yPos = 0; + + // when being used inside an activity, we don't have a navigation controller embedded + if (!self.navigationController) { + UINavigationBar *navigationBar = [[[UINavigationBar alloc] initWithFrame:CGRectMake(self.view.bounds.origin.x, self.view.bounds.origin.y, self.view.bounds.size.width, 44)] autorelease]; + navigationBar.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleBottomMargin; + [self.view addSubview:navigationBar]; + [navigationBar sizeToFit]; + yPos = navigationBar.frame.size.height; + + UIBarButtonItem *cancelItem = [[[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemCancel + target:self + action:@selector(dismissAction:)] autorelease]; + + UIBarButtonItem *saveItem = [[[UIBarButtonItem alloc] initWithTitle:BITHockeyLocalizedString(@"HockeyFeedbackComposeSend") + style:UIBarButtonItemStyleDone + target:self + action:@selector(sendAction:)] autorelease]; + + UINavigationItem *navigationItem = [[[UINavigationItem alloc] initWithTitle:BITHockeyLocalizedString(@"HockeyFeedbackComposeTitle")] autorelease]; + navigationItem.leftBarButtonItem = cancelItem; + navigationItem.rightBarButtonItem = saveItem; + [navigationBar pushNavigationItem:navigationItem animated:NO]; + } else { + // Do any additional setup after loading the view. + self.navigationItem.leftBarButtonItem = [[[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemCancel + target:self + action:@selector(dismissAction:)] autorelease]; + + self.navigationItem.rightBarButtonItem = [[[UIBarButtonItem alloc] initWithTitle:BITHockeyLocalizedString(@"HockeyFeedbackComposeSend") + style:UIBarButtonItemStyleDone + target:self + action:@selector(sendAction:)] autorelease]; + } // message input textfield CGRect frame = CGRectZero; if (UI_USER_INTERFACE_IDIOM() != UIUserInterfaceIdiomPad) { - frame = CGRectMake(0, 0, self.view.bounds.size.width, 200); + frame = CGRectMake(0, yPos, self.view.bounds.size.width, 200-yPos); } else { - frame = CGRectMake(0, 0, self.view.bounds.size.width, self.view.bounds.size.height); + frame = CGRectMake(0, yPos, self.view.bounds.size.width, self.view.bounds.size.height-yPos); } self.textView = [[[UITextView alloc] initWithFrame:frame] autorelease]; self.textView.font = [UIFont systemFontOfSize:17]; @@ -100,6 +137,8 @@ - (void)viewWillAppear:(BOOL)animated { [super viewWillAppear:animated]; self.navigationItem.rightBarButtonItem.enabled = NO; + + [[UIApplication sharedApplication] setStatusBarStyle:(self.navigationController.navigationBar.barStyle == UIBarStyleDefault) ? UIStatusBarStyleDefault : UIStatusBarStyleBlackOpaque]; } - (void)viewDidAppear:(BOOL)animated { @@ -129,6 +168,14 @@ - (void)viewDidDisappear:(BOOL)animated { #pragma mark - Private methods +- (void)dismiss { + if (self.delegate && [self.delegate respondsToSelector:@selector(feedbackComposeViewControllerDidFinish:)]) { + [self.delegate feedbackComposeViewControllerDidFinish:self]; + } else { + [self dismissModalViewControllerAnimated:YES]; + } +} + - (void)setUserDataAction { BITFeedbackUserDataViewController *userController = [[[BITFeedbackUserDataViewController alloc] initWithStyle:UITableViewStyleGrouped] autorelease]; userController.delegate = self; @@ -139,7 +186,7 @@ - (void)setUserDataAction { } - (void)dismissAction:(id)sender { - [self dismissModalViewControllerAnimated:YES]; + [self dismiss]; } - (void)sendAction:(id)sender { @@ -150,7 +197,7 @@ - (void)sendAction:(id)sender { [self.manager submitMessageWithText:text]; - [self dismissModalViewControllerAnimated:YES]; + [self dismiss]; } diff --git a/Classes/BITFeedbackComposeViewControllerDelegate.h b/Classes/BITFeedbackComposeViewControllerDelegate.h new file mode 100644 index 00000000..eebf8118 --- /dev/null +++ b/Classes/BITFeedbackComposeViewControllerDelegate.h @@ -0,0 +1,31 @@ +// +// BITFeedbackComposeViewControllerDelegate.h +// HockeySDK +// +// Created by Andreas Linde on 15.10.12. +// +// + +#import + +@class BITFeedbackComposeViewController; + +@protocol BITFeedbackComposeViewControllerDelegate + +@optional + +///----------------------------------------------------------------------------- +/// @name View Controller Management +///----------------------------------------------------------------------------- + +/** + Invoked once the compose screen is finished via send or cancel + + If this is implemented, it's the responsibility of this method to dismiss the presented + `BITFeedbackComposeViewController` + + @param composeViewController The `BITFeedbackComposeViewController` instance invoking this delegate + */ +- (void)feedbackComposeViewControllerDidFinish:(BITFeedbackComposeViewController *)composeViewController; + +@end diff --git a/Classes/BITFeedbackManager.h b/Classes/BITFeedbackManager.h index c571cce8..64a73b09 100644 --- a/Classes/BITFeedbackManager.h +++ b/Classes/BITFeedbackManager.h @@ -72,9 +72,25 @@ typedef enum { Create an feedback list view @param modal Return a view ready for modal presentation with integrated navigation bar - @return BITFeedbackListViewController The update user interface view controller, + @return `BITFeedbackListViewController` The feedback list view controller, e.g. to push it onto a navigation stack. */ - (BITFeedbackListViewController *)feedbackListViewController:(BOOL)modal; + +/** + Present the modal feedback compose message user interface. + */ +- (void)showFeedbackComposeView; + + +/** + Create an feedback compose view + + @param modal Return a view ready for modal presentation with integrated navigation bar + @return `BITFeedbackComposeViewController` The compose feedback view controller, + e.g. to push it onto a navigation stack. + */ +- (BITFeedbackComposeViewController *)feedbackComposeViewControllerWithDelegate:(id)delegate; + @end diff --git a/Classes/BITFeedbackManager.m b/Classes/BITFeedbackManager.m index 355b0b69..854ac8f1 100644 --- a/Classes/BITFeedbackManager.m +++ b/Classes/BITFeedbackManager.m @@ -177,6 +177,20 @@ - (void)showFeedbackListView { } +- (BITFeedbackComposeViewController *)feedbackComposeViewControllerWithDelegate:(id)delegate { + return [[[BITFeedbackComposeViewController alloc] initWithDelegate:delegate] autorelease]; +} + +- (void)showFeedbackComposeView { + if (_currentFeedbackComposeViewController) { + BITHockeyLog(@"INFO: update view already visible, aborting"); + return; + } + + [self showView:[self feedbackComposeViewControllerWithDelegate:nil]]; +} + + #pragma mark - Manager Control - (void)startManager { diff --git a/Classes/BITHockeyBaseManager.m b/Classes/BITHockeyBaseManager.m index a1345f31..e7230993 100644 --- a/Classes/BITHockeyBaseManager.m +++ b/Classes/BITHockeyBaseManager.m @@ -137,7 +137,7 @@ - (UIWindow *)findVisibleWindow { return visibleWindow; } -- (void)showView:(BITHockeyBaseViewController *)viewController { +- (void)showView:(UIViewController *)viewController { UIViewController *parentViewController = nil; if ([[BITHockeyManager sharedHockeyManager].delegate respondsToSelector:@selector(viewControllerForHockeyManager:componentManager:)]) { @@ -179,14 +179,16 @@ - (void)showView:(BITHockeyBaseViewController *)viewController { _navController.modalPresentationStyle = UIModalPresentationFormSheet; } - viewController.modalAnimated = YES; + if ([viewController isKindOfClass:[BITHockeyBaseViewController class]]) + [(BITHockeyBaseViewController *)viewController setModalAnimated:YES]; [parentViewController presentModalViewController:_navController animated:YES]; } else { // if not, we add a subview to the window. A bit hacky but should work in most circumstances. // Also, we don't get a nice animation for free, but hey, this is for beta not production users ;) BITHockeyLog(@"INFO: No rootViewController found, using UIWindow-approach: %@", visibleWindow); - viewController.modalAnimated = NO; + if ([viewController isKindOfClass:[BITHockeyBaseViewController class]]) + [(BITHockeyBaseViewController *)viewController setModalAnimated:NO]; [visibleWindow addSubview:_navController.view]; } } diff --git a/Classes/BITHockeyBaseManagerPrivate.h b/Classes/BITHockeyBaseManagerPrivate.h index c5028524..e58a3e1f 100644 --- a/Classes/BITHockeyBaseManagerPrivate.h +++ b/Classes/BITHockeyBaseManagerPrivate.h @@ -26,7 +26,7 @@ - (NSString *)executableUUID; - (UIWindow *)findVisibleWindow; -- (void)showView:(BITHockeyBaseViewController *)viewController; +- (void)showView:(UIViewController *)viewController; - (NSData *)appendPostValue:(NSString *)value forKey:(NSString *)key; diff --git a/Classes/BITHockeyBaseViewController.m b/Classes/BITHockeyBaseViewController.m index 98e80ccf..b07411c8 100644 --- a/Classes/BITHockeyBaseViewController.m +++ b/Classes/BITHockeyBaseViewController.m @@ -50,17 +50,7 @@ - (id)initWithModalStyle:(BOOL)modal { - (void)onDismissModal:(id)sender { if (self.modal) { - // Note that as of 5.0, parentViewController will no longer return the presenting view controller - SEL presentingViewControllerSelector = NSSelectorFromString(@"presentingViewController"); - UIViewController *presentingViewController = nil; - if ([self respondsToSelector:presentingViewControllerSelector]) { -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Warc-performSelector-leaks" - presentingViewController = [self performSelector:presentingViewControllerSelector]; -#pragma clang diagnostic pop - } else { - presentingViewController = [self parentViewController]; - } + UIViewController *presentingViewController = [self presentingViewController]; // If there is no presenting view controller just remove view if (presentingViewController && self.modalAnimated) { diff --git a/Classes/HockeySDK.h b/Classes/HockeySDK.h index a377574b..a47d61f1 100644 --- a/Classes/HockeySDK.h +++ b/Classes/HockeySDK.h @@ -41,7 +41,9 @@ #import "BITUpdateViewController.h" #import "BITFeedbackManager.h" +#import "BITFeedbackActivity.h" #import "BITFeedbackComposeViewController.h" +#import "BITFeedbackComposeViewControllerDelegate.h" #import "BITFeedbackListViewController.h" diff --git a/Support/HockeySDK.xcodeproj/project.pbxproj b/Support/HockeySDK.xcodeproj/project.pbxproj index d28dc30f..8d63f261 100644 --- a/Support/HockeySDK.xcodeproj/project.pbxproj +++ b/Support/HockeySDK.xcodeproj/project.pbxproj @@ -34,7 +34,7 @@ /* Begin PBXBuildFile section */ 1E27EF2515BB5033000AE995 /* HockeySDK.strings in Resources */ = {isa = PBXBuildFile; fileRef = 1E59555F15B6F80E00A03429 /* HockeySDK.strings */; }; - 1E49A43C1612223B00463151 /* BITFeedbackComposeViewController.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E49A42D1612223B00463151 /* BITFeedbackComposeViewController.h */; }; + 1E49A43C1612223B00463151 /* BITFeedbackComposeViewController.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E49A42D1612223B00463151 /* BITFeedbackComposeViewController.h */; settings = {ATTRIBUTES = (Public, ); }; }; 1E49A43F1612223B00463151 /* BITFeedbackComposeViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 1E49A42E1612223B00463151 /* BITFeedbackComposeViewController.m */; }; 1E49A4421612223B00463151 /* BITFeedbackListViewCell.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E49A42F1612223B00463151 /* BITFeedbackListViewCell.h */; }; 1E49A4451612223B00463151 /* BITFeedbackListViewCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 1E49A4301612223B00463151 /* BITFeedbackListViewCell.m */; }; @@ -93,6 +93,9 @@ 1E754E601621FBB70070AB92 /* BITCrashReportTextFormatter.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E754E5A1621FBB70070AB92 /* BITCrashReportTextFormatter.h */; }; 1E754E611621FBB70070AB92 /* BITCrashReportTextFormatter.m in Sources */ = {isa = PBXBuildFile; fileRef = 1E754E5B1621FBB70070AB92 /* BITCrashReportTextFormatter.m */; }; 1EC69F601615001500808FD9 /* BITHockeyManagerPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 1EC69F5D1615001500808FD9 /* BITHockeyManagerPrivate.h */; }; + 1EF95CA6162CB037000AE3AD /* BITFeedbackActivity.h in Headers */ = {isa = PBXBuildFile; fileRef = 1EF95CA4162CB036000AE3AD /* BITFeedbackActivity.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 1EF95CA7162CB037000AE3AD /* BITFeedbackActivity.m in Sources */ = {isa = PBXBuildFile; fileRef = 1EF95CA5162CB036000AE3AD /* BITFeedbackActivity.m */; }; + 1EF95CAA162CB314000AE3AD /* BITFeedbackComposeViewControllerDelegate.h in Headers */ = {isa = PBXBuildFile; fileRef = 1EF95CA9162CB313000AE3AD /* BITFeedbackComposeViewControllerDelegate.h */; settings = {ATTRIBUTES = (Public, ); }; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -187,6 +190,9 @@ 1E754E5B1621FBB70070AB92 /* BITCrashReportTextFormatter.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = BITCrashReportTextFormatter.m; sourceTree = ""; }; 1EC69F5D1615001500808FD9 /* BITHockeyManagerPrivate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BITHockeyManagerPrivate.h; sourceTree = ""; }; 1EDA60CF15C2C1450032D10B /* HockeySDK-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "HockeySDK-Info.plist"; sourceTree = ""; }; + 1EF95CA4162CB036000AE3AD /* BITFeedbackActivity.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BITFeedbackActivity.h; sourceTree = ""; }; + 1EF95CA5162CB036000AE3AD /* BITFeedbackActivity.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = BITFeedbackActivity.m; sourceTree = ""; }; + 1EF95CA9162CB313000AE3AD /* BITFeedbackComposeViewControllerDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BITFeedbackComposeViewControllerDelegate.h; sourceTree = ""; }; E400561D148D79B500EB22B9 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; E41EB465148D7BF50015DEDC /* BITHockeyManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BITHockeyManager.h; sourceTree = ""; }; E41EB466148D7BF50015DEDC /* BITHockeyManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = BITHockeyManager.m; sourceTree = ""; }; @@ -267,12 +273,15 @@ 1E49A4371612223B00463151 /* BITFeedbackMessage.m */, 1E49A42D1612223B00463151 /* BITFeedbackComposeViewController.h */, 1E49A42E1612223B00463151 /* BITFeedbackComposeViewController.m */, + 1EF95CA9162CB313000AE3AD /* BITFeedbackComposeViewControllerDelegate.h */, 1E49A4381612223B00463151 /* BITFeedbackUserDataViewController.h */, 1E49A4391612223B00463151 /* BITFeedbackUserDataViewController.m */, 1E49A42F1612223B00463151 /* BITFeedbackListViewCell.h */, 1E49A4301612223B00463151 /* BITFeedbackListViewCell.m */, 1E49A4311612223B00463151 /* BITFeedbackListViewController.h */, 1E49A4321612223B00463151 /* BITFeedbackListViewController.m */, + 1EF95CA4162CB036000AE3AD /* BITFeedbackActivity.h */, + 1EF95CA5162CB036000AE3AD /* BITFeedbackActivity.m */, 1E49A4331612223B00463151 /* BITFeedbackManager.h */, 1E49A4341612223B00463151 /* BITFeedbackManager.m */, 1E49A4351612223B00463151 /* BITFeedbackManagerPrivate.h */, @@ -390,6 +399,8 @@ 1E49A4481612223B00463151 /* BITFeedbackListViewController.h in Headers */, 1E49A47F1612226D00463151 /* BITUpdateViewController.h in Headers */, 1E49A43C1612223B00463151 /* BITFeedbackComposeViewController.h in Headers */, + 1EF95CAA162CB314000AE3AD /* BITFeedbackComposeViewControllerDelegate.h in Headers */, + 1EF95CA6162CB037000AE3AD /* BITFeedbackActivity.h in Headers */, 1E49A4421612223B00463151 /* BITFeedbackListViewCell.h in Headers */, 1E49A4541612223B00463151 /* BITFeedbackManagerPrivate.h in Headers */, 1E49A4571612223B00463151 /* BITFeedbackMessage.h in Headers */, @@ -568,6 +579,7 @@ 1E49A4DB161222D400463151 /* HockeySDKPrivate.m in Sources */, 1E754E5D1621FBB70070AB92 /* BITCrashManager.m in Sources */, 1E754E611621FBB70070AB92 /* BITCrashReportTextFormatter.m in Sources */, + 1EF95CA7162CB037000AE3AD /* BITFeedbackActivity.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; From a54e20b48bc40425c6000f6a0e66c8d20dd0e019 Mon Sep 17 00:00:00 2001 From: Andreas Linde Date: Tue, 16 Oct 2012 01:54:27 +0200 Subject: [PATCH 043/176] Define an extra string for the UIActivity button title --- Classes/BITFeedbackActivity.m | 2 +- Resources/de.lproj/HockeySDK.strings | 6 ++++++ Resources/en.lproj/HockeySDK.strings | 6 ++++++ Resources/es.lproj/HockeySDK.strings | 6 ++++++ Resources/fr.lproj/HockeySDK.strings | 6 ++++++ Resources/it.lproj/HockeySDK.strings | 6 ++++++ Resources/ja.lproj/HockeySDK.strings | 6 ++++++ Resources/nl.lproj/HockeySDK.strings | 6 ++++++ Resources/pt-PT.lproj/HockeySDK.strings | 6 ++++++ Resources/pt.lproj/HockeySDK.strings | 6 ++++++ Resources/ru.lproj/HockeySDK.strings | 6 ++++++ Resources/sv.lproj/HockeySDK.strings | 6 ++++++ Resources/tr.lproj/HockeySDK.strings | 6 ++++++ Resources/zh_CN.lproj/HockeySDK.strings | 6 ++++++ Resources/zh_TW.lproj/HockeySDK.strings | 6 ++++++ 15 files changed, 85 insertions(+), 1 deletion(-) diff --git a/Classes/BITFeedbackActivity.m b/Classes/BITFeedbackActivity.m index 9529aa6d..8a2d4dfe 100644 --- a/Classes/BITFeedbackActivity.m +++ b/Classes/BITFeedbackActivity.m @@ -19,7 +19,7 @@ - (NSString *)activityType { } - (NSString *)activityTitle { - return @"Feedback"; + return BITHockeyLocalizedString(@"HockeyFeedbackActivityButtonTitle"); } - (UIImage *)activityImage { diff --git a/Resources/de.lproj/HockeySDK.strings b/Resources/de.lproj/HockeySDK.strings index f1704fed..84d7517d 100755 --- a/Resources/de.lproj/HockeySDK.strings +++ b/Resources/de.lproj/HockeySDK.strings @@ -183,6 +183,12 @@ "HockeyFeedbackListDeleteAllCancel" = "Cancel"; +/* UIActivity */ + +/* Activity Sharing Button Title */ +"HockeyFeedbackActivityButtonTitle" = "App Feedback"; + + /* Compose Message */ /* Title */ diff --git a/Resources/en.lproj/HockeySDK.strings b/Resources/en.lproj/HockeySDK.strings index 301a4b13..16c42658 100755 --- a/Resources/en.lproj/HockeySDK.strings +++ b/Resources/en.lproj/HockeySDK.strings @@ -180,6 +180,12 @@ "HockeyFeedbackListDeleteAllCancel" = "Cancel"; +/* UIActivity */ + +/* Activity Sharing Button Title */ +"HockeyFeedbackActivityButtonTitle" = "App Feedback"; + + /* Compose Message */ /* Title */ diff --git a/Resources/es.lproj/HockeySDK.strings b/Resources/es.lproj/HockeySDK.strings index f71d05b4..0c3bb7f3 100755 --- a/Resources/es.lproj/HockeySDK.strings +++ b/Resources/es.lproj/HockeySDK.strings @@ -181,6 +181,12 @@ "HockeyFeedbackListDeleteAllCancel" = "Cancel"; +/* UIActivity */ + +/* Activity Sharing Button Title */ +"HockeyFeedbackActivityButtonTitle" = "App Feedback"; + + /* Compose Message */ /* Title */ diff --git a/Resources/fr.lproj/HockeySDK.strings b/Resources/fr.lproj/HockeySDK.strings index 82b14982..1be6c064 100755 --- a/Resources/fr.lproj/HockeySDK.strings +++ b/Resources/fr.lproj/HockeySDK.strings @@ -181,6 +181,12 @@ "HockeyFeedbackListDeleteAllCancel" = "Cancel"; +/* UIActivity */ + +/* Activity Sharing Button Title */ +"HockeyFeedbackActivityButtonTitle" = "App Feedback"; + + /* Compose Message */ /* Title */ diff --git a/Resources/it.lproj/HockeySDK.strings b/Resources/it.lproj/HockeySDK.strings index b31c94e6..a98bca96 100755 --- a/Resources/it.lproj/HockeySDK.strings +++ b/Resources/it.lproj/HockeySDK.strings @@ -181,6 +181,12 @@ "HockeyFeedbackListDeleteAllCancel" = "Cancel"; +/* UIActivity */ + +/* Activity Sharing Button Title */ +"HockeyFeedbackActivityButtonTitle" = "App Feedback"; + + /* Compose Message */ /* Title */ diff --git a/Resources/ja.lproj/HockeySDK.strings b/Resources/ja.lproj/HockeySDK.strings index 0d6a5fd7..cb95172e 100755 --- a/Resources/ja.lproj/HockeySDK.strings +++ b/Resources/ja.lproj/HockeySDK.strings @@ -181,6 +181,12 @@ "HockeyFeedbackListDeleteAllCancel" = "Cancel"; +/* UIActivity */ + +/* Activity Sharing Button Title */ +"HockeyFeedbackActivityButtonTitle" = "App Feedback"; + + /* Compose Message */ /* Title */ diff --git a/Resources/nl.lproj/HockeySDK.strings b/Resources/nl.lproj/HockeySDK.strings index 27d3f6c6..76744ffc 100755 --- a/Resources/nl.lproj/HockeySDK.strings +++ b/Resources/nl.lproj/HockeySDK.strings @@ -181,6 +181,12 @@ "HockeyFeedbackListDeleteAllCancel" = "Cancel"; +/* UIActivity */ + +/* Activity Sharing Button Title */ +"HockeyFeedbackActivityButtonTitle" = "App Feedback"; + + /* Compose Message */ /* Title */ diff --git a/Resources/pt-PT.lproj/HockeySDK.strings b/Resources/pt-PT.lproj/HockeySDK.strings index 0c4d4892..4941af47 100755 --- a/Resources/pt-PT.lproj/HockeySDK.strings +++ b/Resources/pt-PT.lproj/HockeySDK.strings @@ -181,6 +181,12 @@ "HockeyFeedbackListDeleteAllCancel" = "Cancel"; +/* UIActivity */ + +/* Activity Sharing Button Title */ +"HockeyFeedbackActivityButtonTitle" = "App Feedback"; + + /* Compose Message */ /* Title */ diff --git a/Resources/pt.lproj/HockeySDK.strings b/Resources/pt.lproj/HockeySDK.strings index c6d926c9..b6039980 100755 --- a/Resources/pt.lproj/HockeySDK.strings +++ b/Resources/pt.lproj/HockeySDK.strings @@ -181,6 +181,12 @@ "HockeyFeedbackListDeleteAllCancel" = "Cancel"; +/* UIActivity */ + +/* Activity Sharing Button Title */ +"HockeyFeedbackActivityButtonTitle" = "App Feedback"; + + /* Compose Message */ /* Title */ diff --git a/Resources/ru.lproj/HockeySDK.strings b/Resources/ru.lproj/HockeySDK.strings index 7880a7fe..2209e2b6 100755 --- a/Resources/ru.lproj/HockeySDK.strings +++ b/Resources/ru.lproj/HockeySDK.strings @@ -181,6 +181,12 @@ "HockeyFeedbackListDeleteAllCancel" = "Cancel"; +/* UIActivity */ + +/* Activity Sharing Button Title */ +"HockeyFeedbackActivityButtonTitle" = "App Feedback"; + + /* Compose Message */ /* Title */ diff --git a/Resources/sv.lproj/HockeySDK.strings b/Resources/sv.lproj/HockeySDK.strings index 82194722..b619d7f9 100755 --- a/Resources/sv.lproj/HockeySDK.strings +++ b/Resources/sv.lproj/HockeySDK.strings @@ -181,6 +181,12 @@ "HockeyFeedbackListDeleteAllCancel" = "Cancel"; +/* UIActivity */ + +/* Activity Sharing Button Title */ +"HockeyFeedbackActivityButtonTitle" = "App Feedback"; + + /* Compose Message */ /* Title */ diff --git a/Resources/tr.lproj/HockeySDK.strings b/Resources/tr.lproj/HockeySDK.strings index 42eb475f..5c608299 100644 --- a/Resources/tr.lproj/HockeySDK.strings +++ b/Resources/tr.lproj/HockeySDK.strings @@ -181,6 +181,12 @@ "HockeyFeedbackListDeleteAllCancel" = "Cancel"; +/* UIActivity */ + +/* Activity Sharing Button Title */ +"HockeyFeedbackActivityButtonTitle" = "App Feedback"; + + /* Compose Message */ /* Title */ diff --git a/Resources/zh_CN.lproj/HockeySDK.strings b/Resources/zh_CN.lproj/HockeySDK.strings index 443dc1be..791910fe 100644 --- a/Resources/zh_CN.lproj/HockeySDK.strings +++ b/Resources/zh_CN.lproj/HockeySDK.strings @@ -181,6 +181,12 @@ "HockeyFeedbackListDeleteAllCancel" = "Cancel"; +/* UIActivity */ + +/* Activity Sharing Button Title */ +"HockeyFeedbackActivityButtonTitle" = "App Feedback"; + + /* Compose Message */ /* Title */ diff --git a/Resources/zh_TW.lproj/HockeySDK.strings b/Resources/zh_TW.lproj/HockeySDK.strings index 3e7b98cf..4f3c4072 100644 --- a/Resources/zh_TW.lproj/HockeySDK.strings +++ b/Resources/zh_TW.lproj/HockeySDK.strings @@ -181,6 +181,12 @@ "HockeyFeedbackListDeleteAllCancel" = "Cancel"; +/* UIActivity */ + +/* Activity Sharing Button Title */ +"HockeyFeedbackActivityButtonTitle" = "App Feedback"; + + /* Compose Message */ /* Title */ From eb05becb5bbceee4a073f0098c6a3055a7a81561 Mon Sep 17 00:00:00 2001 From: Andreas Linde Date: Tue, 16 Oct 2012 02:10:37 +0200 Subject: [PATCH 044/176] Remove JSON pre iOS5 lib support, always use NSJsonSerialization --- Classes/BITFeedbackManager.m | 2 +- Classes/BITHockeyHelper.h | 1 - Classes/BITHockeyHelper.m | 77 ------------------------------------ Classes/BITUpdateManager.m | 7 ++-- 4 files changed, 5 insertions(+), 82 deletions(-) diff --git a/Classes/BITFeedbackManager.m b/Classes/BITFeedbackManager.m index 854ac8f1..2189b891 100644 --- a/Classes/BITFeedbackManager.m +++ b/Classes/BITFeedbackManager.m @@ -748,7 +748,7 @@ - (void)sendNetworkRequestWithHTTPMethod:(NSString *)httpMethod withMessage:(BIT NSError *error = NULL; - NSDictionary *feedDict = (NSDictionary *)bit_parseJSON(responseString, &error); + NSDictionary *feedDict = (NSDictionary *)[NSJSONSerialization JSONObjectWithData:[responseString dataUsingEncoding:NSUTF8StringEncoding] options:kNilOptions error:&error]; // server returned empty response? if (error) { diff --git a/Classes/BITHockeyHelper.h b/Classes/BITHockeyHelper.h index 3e7ceec8..6121ea40 100644 --- a/Classes/BITHockeyHelper.h +++ b/Classes/BITHockeyHelper.h @@ -33,7 +33,6 @@ NSString *bit_URLEncodedString(NSString *inputString); NSString *bit_URLDecodedString(NSString *inputString); NSComparisonResult bit_versionCompare(NSString *stringA, NSString *stringB); -id bit_parseJSON(NSString *inputString, NSError **error); NSString *bit_encodeAppIdentifier(NSString *inputString); /* UIImage helpers */ diff --git a/Classes/BITHockeyHelper.m b/Classes/BITHockeyHelper.m index 4e7dfeda..73193d0d 100644 --- a/Classes/BITHockeyHelper.m +++ b/Classes/BITHockeyHelper.m @@ -76,83 +76,6 @@ NSComparisonResult bit_versionCompare(NSString *stringA, NSString *stringB) { return result; } -// parse JSON depending on the available framework -id bit_parseJSON(NSString *inputString, NSError **error) { - error = nil; - - if (!inputString) - return nil; - - id feedResult = nil; - -#if BW_NATIVE_JSON_AVAILABLE - feedResult = [NSJSONSerialization JSONObjectWithData:[jsonString dataUsingEncoding:NSUTF8StringEncoding] options:kNilOptions error:&error]; -#else - id nsjsonClass = NSClassFromString(@"NSJSONSerialization"); - SEL nsjsonSelect = NSSelectorFromString(@"JSONObjectWithData:options:error:"); - SEL sbJSONSelector = NSSelectorFromString(@"JSONValue"); - SEL jsonKitSelector = NSSelectorFromString(@"objectFromJSONStringWithParseOptions:error:"); - SEL yajlSelector = NSSelectorFromString(@"yajl_JSONWithOptions:error:"); - - if (nsjsonClass && [nsjsonClass respondsToSelector:nsjsonSelect]) { - NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:[nsjsonClass methodSignatureForSelector:nsjsonSelect]]; - invocation.target = nsjsonClass; - invocation.selector = nsjsonSelect; - NSData *jsonData = [inputString dataUsingEncoding:NSUTF8StringEncoding]; - - if (!jsonData) - return nil; - - [invocation setArgument:&jsonData atIndex:2]; // arguments 0 and 1 are self and _cmd respectively, automatically set by NSInvocation - NSUInteger readOptions = kNilOptions; - [invocation setArgument:&readOptions atIndex:3]; - [invocation setArgument:&error atIndex:4]; - [invocation invoke]; - [invocation getReturnValue:&feedResult]; - } else if (jsonKitSelector && [inputString respondsToSelector:jsonKitSelector]) { - // first try JSONkit - NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:[inputString methodSignatureForSelector:jsonKitSelector]]; - invocation.target = inputString; - invocation.selector = jsonKitSelector; - int parseOptions = 0; - [invocation setArgument:&parseOptions atIndex:2]; // arguments 0 and 1 are self and _cmd respectively, automatically set by NSInvocation - [invocation setArgument:&error atIndex:3]; - [invocation invoke]; - [invocation getReturnValue:&feedResult]; - } else if (sbJSONSelector && [inputString respondsToSelector:sbJSONSelector]) { - // now try SBJson - NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:[inputString methodSignatureForSelector:sbJSONSelector]]; - invocation.target = inputString; - invocation.selector = sbJSONSelector; - [invocation invoke]; - [invocation getReturnValue:&feedResult]; - } else if (yajlSelector && [inputString respondsToSelector:yajlSelector]) { - NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:[inputString methodSignatureForSelector:yajlSelector]]; - invocation.target = inputString; - invocation.selector = yajlSelector; - - NSUInteger yajlParserOptions = 0; - [invocation setArgument:&yajlParserOptions atIndex:2]; // arguments 0 and 1 are self and _cmd respectively, automatically set by NSInvocation - [invocation setArgument:&error atIndex:3]; - - [invocation invoke]; - [invocation getReturnValue:&feedResult]; - } else { - if (error != NULL) - *error = [[NSError errorWithDomain:kBITHockeyErrorDomain - code:HockeyAPIClientMissingJSONLibrary - userInfo:[NSDictionary dictionaryWithObjectsAndKeys:@"You need a JSON Framework in your runtime for iOS4!", NSLocalizedDescriptionKey, nil]] retain]; - return nil; - } -#endif - - if (error != NULL) { - return nil; - } - - return feedResult; -} - NSString *bit_encodeAppIdentifier(NSString *inputString) { return (inputString ? bit_URLEncodedString(inputString) : bit_URLEncodedString([[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleIdentifier"])); } diff --git a/Classes/BITUpdateManager.m b/Classes/BITUpdateManager.m index 67bf42c1..e2fbd9d3 100644 --- a/Classes/BITUpdateManager.m +++ b/Classes/BITUpdateManager.m @@ -559,8 +559,8 @@ - (void)checkForAuthorization { if ([responseData length]) { NSString *responseString = [[[NSString alloc] initWithBytes:[responseData bytes] length:[responseData length] encoding: NSUTF8StringEncoding] autorelease]; - NSDictionary *feedDict = (NSDictionary *)bit_parseJSON(responseString, &error); - + NSDictionary *feedDict = (NSDictionary *)[NSJSONSerialization JSONObjectWithData:[responseString dataUsingEncoding:NSUTF8StringEncoding] options:kNilOptions error:&error]; + // server returned empty response? if (![feedDict count]) { [self reportError:[NSError errorWithDomain:kBITUpdateErrorDomain @@ -816,7 +816,8 @@ - (void)connectionDidFinishLoading:(NSURLConnection *)connection { BITHockeyLog(@"INFO: Received API response: %@", responseString); NSError *error = nil; - id json = bit_parseJSON(responseString, &error); + NSDictionary *json = (NSDictionary *)[NSJSONSerialization JSONObjectWithData:[responseString dataUsingEncoding:NSUTF8StringEncoding] options:kNilOptions error:&error]; + self.trackerConfig = (([self checkForTracker] && [[json valueForKey:@"tracker"] isKindOfClass:[NSDictionary class]]) ? [json valueForKey:@"tracker"] : nil); if (![self isAppStoreEnvironment]) { From 28b2d802d0809f64bed03b26d6dc0dba4d2f3437 Mon Sep 17 00:00:00 2001 From: Andreas Linde Date: Tue, 16 Oct 2012 17:24:52 +0200 Subject: [PATCH 045/176] Fix FeedbackActivity using Navigation Controller No idea why I couldn't get this simple thing working the other day --- Classes/BITFeedbackActivity.m | 20 ++++------ Classes/BITFeedbackComposeViewController.m | 46 ++++++---------------- 2 files changed, 19 insertions(+), 47 deletions(-) diff --git a/Classes/BITFeedbackActivity.m b/Classes/BITFeedbackActivity.m index 8a2d4dfe..56bb9a84 100644 --- a/Classes/BITFeedbackActivity.m +++ b/Classes/BITFeedbackActivity.m @@ -30,20 +30,12 @@ - (UIImage *)activityImage { - (BOOL)canPerformWithActivityItems:(NSArray *)activityItems { if ([BITHockeyManager sharedHockeyManager].disableFeedbackManager) return NO; - // we can present the user data screen on top of the compose screen - // so for now only allow this if all required user data is available - BITFeedbackManager *feedbackManager = [BITHockeyManager sharedHockeyManager].feedbackManager; - if ([feedbackManager askManualUserDataAvailable] && - ([feedbackManager requireManualUserDataMissing]) - ) - return NO; - for (UIActivityItemProvider *item in activityItems) { if ([item isKindOfClass:[UIImage class]]) { return YES; } else if ([item isKindOfClass:[NSString class]]) { return YES; - } else if ([item isKindOfClass:[NSString class]]) { + } else if ([item isKindOfClass:[NSURL class]]) { return YES; } } @@ -66,9 +58,13 @@ - (void)prepareWithActivityItems:(NSArray *)activityItems { - (UIViewController *)activityViewController { // TODO: return compose controller with activity content added - BITFeedbackComposeViewController *composeViewController = [[BITHockeyManager sharedHockeyManager].feedbackManager feedbackComposeViewControllerWithDelegate:self]; - composeViewController.modalPresentationStyle = UIModalPresentationFormSheet; - return composeViewController; + BITFeedbackComposeViewController *composeViewController = [[BITHockeyManager sharedHockeyManager].feedbackManager feedbackComposeViewControllerWithScreenshot:NO delegate:self]; + + UINavigationController *navController = [[[UINavigationController alloc] initWithRootViewController: composeViewController] autorelease]; + navController.modalPresentationStyle = UIModalPresentationFormSheet; + navController.modalTransitionStyle = UIModalTransitionStyleCrossDissolve; + + return navController; } -(void)feedbackComposeViewControllerDidFinish:(BITFeedbackComposeViewController *)composeViewController { diff --git a/Classes/BITFeedbackComposeViewController.m b/Classes/BITFeedbackComposeViewController.m index 0513d469..00c4ec03 100644 --- a/Classes/BITFeedbackComposeViewController.m +++ b/Classes/BITFeedbackComposeViewController.m @@ -79,48 +79,24 @@ - (void)viewDidLoad { [super viewDidLoad]; self.view.backgroundColor = [UIColor whiteColor]; - CGFloat yPos = 0; - // when being used inside an activity, we don't have a navigation controller embedded - if (!self.navigationController) { - UINavigationBar *navigationBar = [[[UINavigationBar alloc] initWithFrame:CGRectMake(self.view.bounds.origin.x, self.view.bounds.origin.y, self.view.bounds.size.width, 44)] autorelease]; - navigationBar.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleBottomMargin; - [self.view addSubview:navigationBar]; - [navigationBar sizeToFit]; - yPos = navigationBar.frame.size.height; - - UIBarButtonItem *cancelItem = [[[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemCancel - target:self - action:@selector(dismissAction:)] autorelease]; - - UIBarButtonItem *saveItem = [[[UIBarButtonItem alloc] initWithTitle:BITHockeyLocalizedString(@"HockeyFeedbackComposeSend") - style:UIBarButtonItemStyleDone - target:self - action:@selector(sendAction:)] autorelease]; - - UINavigationItem *navigationItem = [[[UINavigationItem alloc] initWithTitle:BITHockeyLocalizedString(@"HockeyFeedbackComposeTitle")] autorelease]; - navigationItem.leftBarButtonItem = cancelItem; - navigationItem.rightBarButtonItem = saveItem; - [navigationBar pushNavigationItem:navigationItem animated:NO]; - } else { - // Do any additional setup after loading the view. - self.navigationItem.leftBarButtonItem = [[[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemCancel - target:self - action:@selector(dismissAction:)] autorelease]; - - self.navigationItem.rightBarButtonItem = [[[UIBarButtonItem alloc] initWithTitle:BITHockeyLocalizedString(@"HockeyFeedbackComposeSend") - style:UIBarButtonItemStyleDone - target:self - action:@selector(sendAction:)] autorelease]; - } + // Do any additional setup after loading the view. + self.navigationItem.leftBarButtonItem = [[[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemCancel + target:self + action:@selector(dismissAction:)] autorelease]; + self.navigationItem.rightBarButtonItem = [[[UIBarButtonItem alloc] initWithTitle:BITHockeyLocalizedString(@"HockeyFeedbackComposeSend") + style:UIBarButtonItemStyleDone + target:self + action:@selector(sendAction:)] autorelease]; + // message input textfield CGRect frame = CGRectZero; if (UI_USER_INTERFACE_IDIOM() != UIUserInterfaceIdiomPad) { - frame = CGRectMake(0, yPos, self.view.bounds.size.width, 200-yPos); + frame = CGRectMake(0, 0, self.view.bounds.size.width, 200); } else { - frame = CGRectMake(0, yPos, self.view.bounds.size.width, self.view.bounds.size.height-yPos); + frame = CGRectMake(0, 0, self.view.bounds.size.width, self.view.bounds.size.height); } self.textView = [[[UITextView alloc] initWithFrame:frame] autorelease]; self.textView.font = [UIFont systemFontOfSize:17]; From 3d23e36b59aedc5946fdee3d6288d5f1df88d327 Mon Sep 17 00:00:00 2001 From: Andreas Linde Date: Tue, 16 Oct 2012 18:43:57 +0200 Subject: [PATCH 046/176] Show app name and default icon in FeedbackActivity --- Classes/BITFeedbackActivity.m | 7 +++++-- Resources/de.lproj/HockeySDK.strings | 4 ++-- Resources/en.lproj/HockeySDK.strings | 4 ++-- Resources/es.lproj/HockeySDK.strings | 4 ++-- Resources/feedbackActivity@2x~ipad.png | Bin 0 -> 2510 bytes Resources/feedbackActivity~ipad.png | Bin 0 -> 1732 bytes Resources/feedbackActiviy.png | Bin 0 -> 1614 bytes Resources/feedbackActiviy@2x.png | Bin 0 -> 2354 bytes Resources/fr.lproj/HockeySDK.strings | 4 ++-- Resources/it.lproj/HockeySDK.strings | 4 ++-- Resources/ja.lproj/HockeySDK.strings | 4 ++-- Resources/nl.lproj/HockeySDK.strings | 4 ++-- Resources/pt-PT.lproj/HockeySDK.strings | 4 ++-- Resources/pt.lproj/HockeySDK.strings | 4 ++-- Resources/ru.lproj/HockeySDK.strings | 4 ++-- Resources/sv.lproj/HockeySDK.strings | 4 ++-- Resources/tr.lproj/HockeySDK.strings | 4 ++-- Resources/zh_CN.lproj/HockeySDK.strings | 4 ++-- Resources/zh_TW.lproj/HockeySDK.strings | 4 ++-- Support/HockeySDK.xcodeproj/project.pbxproj | 16 ++++++++++++++++ 20 files changed, 49 insertions(+), 30 deletions(-) create mode 100644 Resources/feedbackActivity@2x~ipad.png create mode 100644 Resources/feedbackActivity~ipad.png create mode 100644 Resources/feedbackActiviy.png create mode 100644 Resources/feedbackActiviy@2x.png diff --git a/Classes/BITFeedbackActivity.m b/Classes/BITFeedbackActivity.m index 56bb9a84..2bfa0f30 100644 --- a/Classes/BITFeedbackActivity.m +++ b/Classes/BITFeedbackActivity.m @@ -10,6 +10,7 @@ #import "HockeySDKPrivate.h" #import "HockeySDK.h" +#import "BITHockeyHelper.h" #import "BITFeedbackManagerPrivate.h" @implementation BITFeedbackActivity @@ -19,11 +20,13 @@ - (NSString *)activityType { } - (NSString *)activityTitle { - return BITHockeyLocalizedString(@"HockeyFeedbackActivityButtonTitle"); + NSString *appName = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleName"]; + + return [NSString stringWithFormat:BITHockeyLocalizedString(@"HockeyFeedbackActivityButtonTitle"), appName]; } - (UIImage *)activityImage { - return [UIImage imageNamed:@"instagram.png"]; + return bit_imageNamed(@"feedbackActiviy.png", BITHOCKEYSDK_BUNDLE); } diff --git a/Resources/de.lproj/HockeySDK.strings b/Resources/de.lproj/HockeySDK.strings index 84d7517d..b4d62901 100755 --- a/Resources/de.lproj/HockeySDK.strings +++ b/Resources/de.lproj/HockeySDK.strings @@ -185,8 +185,8 @@ /* UIActivity */ -/* Activity Sharing Button Title */ -"HockeyFeedbackActivityButtonTitle" = "App Feedback"; +/* Activity Sharing Button Title, App Name will be inserted */ +"HockeyFeedbackActivityButtonTitle" = "%@ Feedback"; /* Compose Message */ diff --git a/Resources/en.lproj/HockeySDK.strings b/Resources/en.lproj/HockeySDK.strings index 16c42658..c42969d4 100755 --- a/Resources/en.lproj/HockeySDK.strings +++ b/Resources/en.lproj/HockeySDK.strings @@ -182,8 +182,8 @@ /* UIActivity */ -/* Activity Sharing Button Title */ -"HockeyFeedbackActivityButtonTitle" = "App Feedback"; +/* Activity Sharing Button Title, App Name will be inserted */ +"HockeyFeedbackActivityButtonTitle" = "%@ Feedback"; /* Compose Message */ diff --git a/Resources/es.lproj/HockeySDK.strings b/Resources/es.lproj/HockeySDK.strings index 0c3bb7f3..061a4549 100755 --- a/Resources/es.lproj/HockeySDK.strings +++ b/Resources/es.lproj/HockeySDK.strings @@ -183,8 +183,8 @@ /* UIActivity */ -/* Activity Sharing Button Title */ -"HockeyFeedbackActivityButtonTitle" = "App Feedback"; +/* Activity Sharing Button Title, App Name will be inserted */ +"HockeyFeedbackActivityButtonTitle" = "%@ Feedback"; /* Compose Message */ diff --git a/Resources/feedbackActivity@2x~ipad.png b/Resources/feedbackActivity@2x~ipad.png new file mode 100644 index 0000000000000000000000000000000000000000..0a3bde767e6b8f8b15231db651857e8d5c5327a0 GIT binary patch literal 2510 zcmaJ@dpMN&9-l$3V;YxLQ{kN%AgTXXYV`f|iBcUkmIp)R;=3?f}t%ymv77|%o z8=8=?X|;8--Q1#7$Vs)Qo21sBl9H%4XS8Y0AE)y^&-ZzM-{153e7@H|et99mex}CD zjA1aCDaW53s{ISKw!u&z27~u>Bwo=vXvilL3X{h`$vmY9<}H--MF2<2ixq{6c*4}g zUJ(rj)5S`{BcVuc5LFPn`9An^Ia zYNIKIG1O4D@8?)rkB${Xkb+7iCMPEol3fXMWh{~8<>fW6K_=t12)rs)2JuqxG8Jw? zfh|%AloACbk;{O2MIK+i6{2Icnf_UVRPjYtruy6_ZNrEuJOz!gPhnMfszO8z6{+M~l>+VHVsP`J6jYW{#DnC@aJf8Tp^G76IV4w!Uq0*P$i|AgmqsT`RK;>iRe4x5hEDi9lJW1Z%;kpFCPTWDJFuX!CsSQhYlPuRpoc zqH*@98NPmUEa(?>ez>XQ^+kq&ugi-%J#fVM4h}J-8)<#Dow5Ao;SpsnVVAX6`3FIj zg=diP8Z%+*F6?!Grc-s2GG}>GWzUxU!Z}n~s$S*tMtdhPU#*9$t2`{B{s%R`Qf#~geT5qsMw z7NNatyox;fe0Ex-_Wk;{gxU(Bf?7R12hKpgFEU$tgFd(yd zAi#;@=-AaaR9|jj@;9Fb2c&6eQStt!P0uz|hZyP<)4C0ExhHKn!pm+Nx zpmfX;qeuvfC2^;9S{Cm&tyG7xOP^x-K`1+0gHBGXf5tka?0k6TyJRRp9pV2x zj-xwi;npH&^zE_lHtM8$ZvL^#Xz(UNQ#2Tdx$}DQvU=jGyt2a~2Gb#!-E|h|5$BwM zyj6isYkH$~i2bxgW&LpctoX=!Jvaka9XkyI%{u&4s-JUxKa6{7l<~XeN%#cNFyOH7 zF+4^yC_VvGi37YC4c!7(x}FFul9bRAyei(~Y&yDdcBbE-1Q8hktaDm?&8|Q4Uk9qk z%uIp%nXF*_yO}G@(~~GP<+>{TbIgPp>I`iQO-JXWmiC+0wrdS>#0LGQr{2$(P98Ul z)19twzGKL$j_-O*s^3=YM<0?+!_>G>VFE$_+WKq z<7IQ89Wmo)?yamsHzWa84uiqTe3t!z+>qIV+PX|03i+e4IrxlHnI@p7F)N3r@~>8< zipS6VHkx$<;cwBR=^M}BXZ9Tdbo;M7KPu*LM4WMmcgadI&x0G1cj%bgy0xd2W~uY) zkBKog>{_q8cDsMEI_2zyx9eCXJ<>w%SNxE@^ku=7vGiq*Mg2Mtqn?~C;N@n;tgxBn zEmdDE;Z-!I!QfesM$ATKFYvp0I!yod2vpTMXMM?1>njl?1eV>1`RHF=!(#M!2afnNvb zh;Lu1W)HL#{95$W@QdF25yQOR4f{P-WPH4mr5ACh7M0&=QjvKn-N?^MU(@ST)IW`9UL=_YJaAS zi9va|qYPW(cV(hjVi+b812fDDGdRI~IOLuC+OujE|-FDM$ZR)T+vxj^LE_K)MC2o78F$r%xH+$n@M01#?^0-3UUw1X} z+gkg^*QtoNAD-&03SRD1M*raL^fv00op~?|Sl`)|xiq`6maX3>r2#O((zE7uTCR`hvl&HA1^p-TodY zuu&D3Hbm4Pof=~Ga?^eeIvU)w8dn@hn}{pSr5%fDs#$7OKUA|gwk@K|m)P1jmb1$> z{k%1A^|=qW0m}F@)x{9{R`-e8w<605X#MsFC1bhJh~^azPL|mnY++BmF3)eG)Z%Z- ze+X}GGGfLY7ah22JIC47jEhCA31@V>mdylFL%ck1Du)F1%|7h1W zKoIGMn{x7Myn}KS84-`CFS-o~f^wutjs1-Nt3IV()$jwx{0ocY6U=UAMyvk=5P9eI literal 0 HcmV?d00001 diff --git a/Resources/feedbackActivity~ipad.png b/Resources/feedbackActivity~ipad.png new file mode 100644 index 0000000000000000000000000000000000000000..7d05136bed9f8b8f2c8856810a17a7923cd46532 GIT binary patch literal 1732 zcmaJ?eM}Q)7{8;mR0^Yld}{Poq`E-cYfI?|t(1NM6^dBuR+-y4+JhEsuePVuhRgy5 zVbMV}Ot(3Op$N?<002a4@>DwF%Ol=YDg^*Q?f6}s2oiC%0WZeN@oL0@0@)_4423jS zqyp8Uh-u@xVN?nLB!)$Azzy00i4n81ksyZcvf2qY07$c3cEnhP;!qh{VX?^=_fLM! zfGj2%;|+lp*4mY**^=jWpvCS&z0qA|6q^`X%OI&sLI_w<9D!WcwKk{3C1XtLN{DrE zo5O%6A$XOH@xqirTLdXF2MP(;Fv|#Mz)%L4&E=;Hg~Bw52XkQ#%;Ru*EUr+(=Sg4~ zntB*SHixNPqEqEe(!;Is035Qc%UCplMvoS{nhbtC~gBm;@i$JiP8*Mn^V%eO@ z(+VooX>?fZxCOI8K}DntTaU{agwq!#SnV^iHs@5Eh=y@oh@Hb_!@-iKfm-eVL#@^s zv=i5%Fa7?fuv5R$j&gLU6I<^v5(ihF986`GC>-kr~4=rx~+D%3=Ye zMT{0(FrLI~wGxfZi6b^6s!_=pgaX@QF-bDg)k1+FLk#DrxLmH9CsHbf3Z5uOC4@70 z>YVIpt_m}*x1u(DnrnK=&7PGT90jYL$gDygmJO&W$AMX)$&w|O*}Vv7)tlm)X7?hR zmCGT_aDoT>uY;c6BBm#}oEcjpm>GQ3Mohbd80!Y}pFPBF5ouJ}de`+blgD#Af;vF; zMZ=c_(6g4tYqdMKH-njUN&tg~zcVaO86{upNZdN2rvg-{b%Y&qEMePDEZ#+8MK3A2EmlM2Lrjof3Y!Z36!N|&68hcNTO%K32S9vR?!nw6QM#604CE`) z;RjhmH$$Q7rwy-Ew-- zBW@(v(mnUe?yE==g?mPR=*p`lE^mA0=KL*iM4MEh-!$%r{utovWYOM3Kfs=wORwg| zu3QLSOJ0-!^`y10yzhb@qn<6p&y@#}w)Rgrx&bBhOksLN{s|n#zokHLM_dadHTv!> z+2Ey*sqR2JD~T>tk`xUf*AI~HiKOS6#*UJ@@0J3ATx0l1WNVenS-4fzE>?343)dlirK5{KxN hcJNf{sFay=meM}Q)9KO;PDl1wT+R-`pdc_SC+Pk*2v{ESjl8QxaJFUz=xVA^z$n|P_NKqUG zG@vm|of?HqV97S3(}`w_^NX);3WG&H0o=Ny$mZO!)v0vBdAT4bq@o1~oWekeDE9?bAvHX$tD?`*YcUL_ zA=Fki{JJQ+xftlk01mQ5NTw5!BS4OdP^nCzP-FlJf+Au>B1R>ds6r)`s1O9qJTRRt z;3`vD^v0Q7bfkto6y;Zm#g&znqDrZV47kOpQmKq;NFFDRT<(Bna8 z!0V^Hqz^SWb1Satt8v1S0HkU!I(eG)sxN& z0{2m~T-O_}a$auK3WT4|tj7c1?YPSrAPF$tvdTMuE%JHwX1K2TYf;S071PCtql^95 zqGzvY_e76#wxxqP&kQSLASkBSq|dj7?m1lHu$#*PZ1@awq9*lmeH?cU{Ym7=@_#~P7?X^H`7 zAs^ht!6&;7eQwvD&I>tOZg>@o19&S}3>Q_0#j(c19A7eR)RCEQKlUpPqpPXA3A&f+L2;LOk<*;u;IX4>tQIZb+xXrn9F=+9kv)P z=he&GiU?*GG_gMIglXM|HS2oI>d)N{PcCM%rzZ1cFP1+eEkd!dzUCMC0c0a3=I!tk-hjSqT~YE~U5lE=N4 zi7JoUkeprQzSe_ubgo!?eOt!hA9+0Juwts+%+5+}=-TZ#DZ7%^^R)fPE2|eyN!xg3 zj(0-gQ-@@+qfhF4YRf}o7ve54Q(|w`zS>(ctWhT2F}gn->ozdQy3K=4Og_3Vp9pUU zSJ_WqR)?1`YYH;txx+oJZ562v4!qP3J>8SE?%#v1u?eKO84B)EyzV`V--rq?r8zpVcn)e3dlTMxc zL7)9W%dJQTHxirNd=N4>JZ##@jnr}LIUZ;tJvB~_a4p@8$cDAJ$Nme&0P=1)5K literal 0 HcmV?d00001 diff --git a/Resources/feedbackActiviy@2x.png b/Resources/feedbackActiviy@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..3868d59c223609053cb485142159ca6398eb6c90 GIT binary patch literal 2354 zcmaJ@X;4$=8a_!N2^b)vLZXPruq$L`4FpbB0uoGtN_4c6^-xB};uQahB%lVZ$UjZHq04Vu86@5;Jj0j~&wmu&zmK$M!tI{iAFik682WP=@ z)yBdhI0*nS6ito{kx4SxO1+jUcVVbzt-;9#fTR?&L9W~YBcK9ar_pgJzaIO70%}wo zN^XpVE-~<7wMJZGgtJRBbCe|;lnE+IN-~&aW;+G6Fd_%d+5(-4ZRSv3>av}->zGCX zUqX-#9Lirw$s|&cuQ$SA43!?Gq{q_1SO%5BijIqmiv*c;2AxJ{(iqGrMjV^PWYg*3 ztB2x@W>n>~vjn17v78=x|( z)xJiXkSzG`eBUT+%GqduX<4vIUu0A|2bUk@3T0sPjj$Zi8*}vff|)K#)p|s4QtJ&M zKRX7L$dwwM%YTWNNZ4sQ6C&3s;WPn<;#8n&G%9u+E1JPiNQkD31Plg4$c*Rn<9N(? zksyv9%M^;ZGhBgQS)_$^$P8EYH#g?3T-PdS4bI2{*r@pjtP&aZTJUAbY|R^TiH#P< z#l*z&-m3SCt9nB&uekiTa%s+FXs*Hj&!A_HoZI6vU$3pxdA<0s&bjSI=UU_2ud@Ka zy)#X~%`snA4nJNe!W_g+tNWf+g?AB>}xGLy-f%n|@-|`s5;hIj88>xZA zCETrEuMQK=!9aj@{|)rmpYh{%lGxxAl;#~4o8PsUj@w}8|CUj0xG^1#HBq;i`BY6|dtcnH_@nP=}P z)=%Q8rlL9??~p!W^I|(~?nm5+*Q>{t$5XJu#Z|ugGh^vp0LpEtDIarikq7n!Mj=_< zI-TN9g@Y5X+yt6OVu@}qc&7AujOxV21zQHLr+WEQFsbVo4AQ5(rYa;4+^egX){=s@ zEqmAUgI~=Z+sdcp8i~W6%w2d2%E;vR6*9MIib9hy+ig>u#i#va`8wXM{oVPxE{aI; zX$I1}RW&eCzB<2KDlNEXUy+V+BPRJ|$;9=wUo?(A6R{J$$&ZMQjn~Ln@4M%Z-`fqo z(|&VNk}LxL_XtzI70cBaMS zvS9$1i8`3jG>o%P*N>YYG?hMtuHx+9H+43c;>-MN_k=cM+sd}faJ502XYTg>!R86l zZ11DXKiC=Dzc#R$AEOkdZ1%n6Rp)&}`*Lw;9u(=Rg)2i_q3r0L0@+7i z_R<>l@$1!nf8<%nAAIPYX~X@R7{1B+9aNBdQo#pL0ABN`!G+YwR;gRWZAh6o2j6nM zS~@5g`)P8DZzP6%n*2asaTB^1ADt}B{=E@f$D*`U+Wguv4rnjSx7?qY!p+8bu9-(+ z4KLlpnD00;tOLIZ>NvcSJe2!5czne|3O{}8c|{vxef@&gsO>2PK^?boR*zNI%42;z zYPkAm{|N4S?P=>A5|-S>HQAoz1q^qm8bN2z-F@x(L<_)AErI^iEFax8uC6}Eg0K%Y zSV;5u37rs+5I*VJy>Fqp)A3{f^z5o%y2zF*BH5_*0cZUMVumAmP>d;)W?Wg^Fxw6K zrRRbT4mRTE+RFz3^0}{$`c2sJU!T&Gq!$InzWaP~zTM>0S9rJ|s99q{{k;2tWyQZU z+fm{YfZ}tw$uK-u%9FUlif{DO|OMYyM;j@lawqIc*jZg-c)kFX&e zwq>aMPH;$FPTomQh~%50!1oX;j=OAgsPyiHWb0h^?p;E!Ka(E_#Xv&i(IEPDWnmR6$!q-aCIM$Y) zNlH(~>ElWl?^$0Zc52z6A9Hl=C-^g2ha3e${3Fc4ILySCVT1j) zn=$CN2_pZ{vMOsjtGEhC#N2+uaHJ2K=U>_Qzn z(7Y3vTtq+(GR4m>*gpC*$-`Q_RiwSN*aw1d1yIoR{OB%xB`ILd2#X*n2wdon2UcYu pqzK@VsIn@_X>UIZtn}eC0HE3@qL=feBHr~ElP1g*9N^_u{1?<(ZCL;S literal 0 HcmV?d00001 diff --git a/Resources/fr.lproj/HockeySDK.strings b/Resources/fr.lproj/HockeySDK.strings index 1be6c064..051b70a7 100755 --- a/Resources/fr.lproj/HockeySDK.strings +++ b/Resources/fr.lproj/HockeySDK.strings @@ -183,8 +183,8 @@ /* UIActivity */ -/* Activity Sharing Button Title */ -"HockeyFeedbackActivityButtonTitle" = "App Feedback"; +/* Activity Sharing Button Title, App Name will be inserted */ +"HockeyFeedbackActivityButtonTitle" = "%@ Feedback"; /* Compose Message */ diff --git a/Resources/it.lproj/HockeySDK.strings b/Resources/it.lproj/HockeySDK.strings index a98bca96..aa33045a 100755 --- a/Resources/it.lproj/HockeySDK.strings +++ b/Resources/it.lproj/HockeySDK.strings @@ -183,8 +183,8 @@ /* UIActivity */ -/* Activity Sharing Button Title */ -"HockeyFeedbackActivityButtonTitle" = "App Feedback"; +/* Activity Sharing Button Title, App Name will be inserted */ +"HockeyFeedbackActivityButtonTitle" = "%@ Feedback"; /* Compose Message */ diff --git a/Resources/ja.lproj/HockeySDK.strings b/Resources/ja.lproj/HockeySDK.strings index cb95172e..935f5d41 100755 --- a/Resources/ja.lproj/HockeySDK.strings +++ b/Resources/ja.lproj/HockeySDK.strings @@ -183,8 +183,8 @@ /* UIActivity */ -/* Activity Sharing Button Title */ -"HockeyFeedbackActivityButtonTitle" = "App Feedback"; +/* Activity Sharing Button Title, App Name will be inserted */ +"HockeyFeedbackActivityButtonTitle" = "%@ Feedback"; /* Compose Message */ diff --git a/Resources/nl.lproj/HockeySDK.strings b/Resources/nl.lproj/HockeySDK.strings index 76744ffc..6c507108 100755 --- a/Resources/nl.lproj/HockeySDK.strings +++ b/Resources/nl.lproj/HockeySDK.strings @@ -183,8 +183,8 @@ /* UIActivity */ -/* Activity Sharing Button Title */ -"HockeyFeedbackActivityButtonTitle" = "App Feedback"; +/* Activity Sharing Button Title, App Name will be inserted */ +"HockeyFeedbackActivityButtonTitle" = "%@ Feedback"; /* Compose Message */ diff --git a/Resources/pt-PT.lproj/HockeySDK.strings b/Resources/pt-PT.lproj/HockeySDK.strings index 4941af47..decaa4ba 100755 --- a/Resources/pt-PT.lproj/HockeySDK.strings +++ b/Resources/pt-PT.lproj/HockeySDK.strings @@ -183,8 +183,8 @@ /* UIActivity */ -/* Activity Sharing Button Title */ -"HockeyFeedbackActivityButtonTitle" = "App Feedback"; +/* Activity Sharing Button Title, App Name will be inserted */ +"HockeyFeedbackActivityButtonTitle" = "%@ Feedback"; /* Compose Message */ diff --git a/Resources/pt.lproj/HockeySDK.strings b/Resources/pt.lproj/HockeySDK.strings index b6039980..3a1b4e5d 100755 --- a/Resources/pt.lproj/HockeySDK.strings +++ b/Resources/pt.lproj/HockeySDK.strings @@ -183,8 +183,8 @@ /* UIActivity */ -/* Activity Sharing Button Title */ -"HockeyFeedbackActivityButtonTitle" = "App Feedback"; +/* Activity Sharing Button Title, App Name will be inserted */ +"HockeyFeedbackActivityButtonTitle" = "%@ Feedback"; /* Compose Message */ diff --git a/Resources/ru.lproj/HockeySDK.strings b/Resources/ru.lproj/HockeySDK.strings index 2209e2b6..e09737e6 100755 --- a/Resources/ru.lproj/HockeySDK.strings +++ b/Resources/ru.lproj/HockeySDK.strings @@ -183,8 +183,8 @@ /* UIActivity */ -/* Activity Sharing Button Title */ -"HockeyFeedbackActivityButtonTitle" = "App Feedback"; +/* Activity Sharing Button Title, App Name will be inserted */ +"HockeyFeedbackActivityButtonTitle" = "%@ Feedback"; /* Compose Message */ diff --git a/Resources/sv.lproj/HockeySDK.strings b/Resources/sv.lproj/HockeySDK.strings index b619d7f9..b646e6d9 100755 --- a/Resources/sv.lproj/HockeySDK.strings +++ b/Resources/sv.lproj/HockeySDK.strings @@ -183,8 +183,8 @@ /* UIActivity */ -/* Activity Sharing Button Title */ -"HockeyFeedbackActivityButtonTitle" = "App Feedback"; +/* Activity Sharing Button Title, App Name will be inserted */ +"HockeyFeedbackActivityButtonTitle" = "%@ Feedback"; /* Compose Message */ diff --git a/Resources/tr.lproj/HockeySDK.strings b/Resources/tr.lproj/HockeySDK.strings index 5c608299..a0747e7d 100644 --- a/Resources/tr.lproj/HockeySDK.strings +++ b/Resources/tr.lproj/HockeySDK.strings @@ -183,8 +183,8 @@ /* UIActivity */ -/* Activity Sharing Button Title */ -"HockeyFeedbackActivityButtonTitle" = "App Feedback"; +/* Activity Sharing Button Title, App Name will be inserted */ +"HockeyFeedbackActivityButtonTitle" = "%@ Feedback"; /* Compose Message */ diff --git a/Resources/zh_CN.lproj/HockeySDK.strings b/Resources/zh_CN.lproj/HockeySDK.strings index 791910fe..a8b77cdb 100644 --- a/Resources/zh_CN.lproj/HockeySDK.strings +++ b/Resources/zh_CN.lproj/HockeySDK.strings @@ -183,8 +183,8 @@ /* UIActivity */ -/* Activity Sharing Button Title */ -"HockeyFeedbackActivityButtonTitle" = "App Feedback"; +/* Activity Sharing Button Title, App Name will be inserted */ +"HockeyFeedbackActivityButtonTitle" = "%@ Feedback"; /* Compose Message */ diff --git a/Resources/zh_TW.lproj/HockeySDK.strings b/Resources/zh_TW.lproj/HockeySDK.strings index 4f3c4072..38ac41ad 100644 --- a/Resources/zh_TW.lproj/HockeySDK.strings +++ b/Resources/zh_TW.lproj/HockeySDK.strings @@ -183,8 +183,8 @@ /* UIActivity */ -/* Activity Sharing Button Title */ -"HockeyFeedbackActivityButtonTitle" = "App Feedback"; +/* Activity Sharing Button Title, App Name will be inserted */ +"HockeyFeedbackActivityButtonTitle" = "%@ Feedback"; /* Compose Message */ diff --git a/Support/HockeySDK.xcodeproj/project.pbxproj b/Support/HockeySDK.xcodeproj/project.pbxproj index 8d63f261..bf8e4b69 100644 --- a/Support/HockeySDK.xcodeproj/project.pbxproj +++ b/Support/HockeySDK.xcodeproj/project.pbxproj @@ -92,6 +92,10 @@ 1E754E5F1621FBB70070AB92 /* BITCrashManagerPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E754E591621FBB70070AB92 /* BITCrashManagerPrivate.h */; }; 1E754E601621FBB70070AB92 /* BITCrashReportTextFormatter.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E754E5A1621FBB70070AB92 /* BITCrashReportTextFormatter.h */; }; 1E754E611621FBB70070AB92 /* BITCrashReportTextFormatter.m in Sources */ = {isa = PBXBuildFile; fileRef = 1E754E5B1621FBB70070AB92 /* BITCrashReportTextFormatter.m */; }; + 1EAF20A8162DC0F600957B1D /* feedbackActivity@2x~ipad.png in Resources */ = {isa = PBXBuildFile; fileRef = 1EAF20A4162DC0F600957B1D /* feedbackActivity@2x~ipad.png */; }; + 1EAF20A9162DC0F600957B1D /* feedbackActivity~ipad.png in Resources */ = {isa = PBXBuildFile; fileRef = 1EAF20A5162DC0F600957B1D /* feedbackActivity~ipad.png */; }; + 1EAF20AA162DC0F600957B1D /* feedbackActiviy.png in Resources */ = {isa = PBXBuildFile; fileRef = 1EAF20A6162DC0F600957B1D /* feedbackActiviy.png */; }; + 1EAF20AB162DC0F600957B1D /* feedbackActiviy@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 1EAF20A7162DC0F600957B1D /* feedbackActiviy@2x.png */; }; 1EC69F601615001500808FD9 /* BITHockeyManagerPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 1EC69F5D1615001500808FD9 /* BITHockeyManagerPrivate.h */; }; 1EF95CA6162CB037000AE3AD /* BITFeedbackActivity.h in Headers */ = {isa = PBXBuildFile; fileRef = 1EF95CA4162CB036000AE3AD /* BITFeedbackActivity.h */; settings = {ATTRIBUTES = (Public, ); }; }; 1EF95CA7162CB037000AE3AD /* BITFeedbackActivity.m in Sources */ = {isa = PBXBuildFile; fileRef = 1EF95CA5162CB036000AE3AD /* BITFeedbackActivity.m */; }; @@ -188,6 +192,10 @@ 1E754E591621FBB70070AB92 /* BITCrashManagerPrivate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BITCrashManagerPrivate.h; sourceTree = ""; }; 1E754E5A1621FBB70070AB92 /* BITCrashReportTextFormatter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BITCrashReportTextFormatter.h; sourceTree = ""; }; 1E754E5B1621FBB70070AB92 /* BITCrashReportTextFormatter.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = BITCrashReportTextFormatter.m; sourceTree = ""; }; + 1EAF20A4162DC0F600957B1D /* feedbackActivity@2x~ipad.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "feedbackActivity@2x~ipad.png"; sourceTree = ""; }; + 1EAF20A5162DC0F600957B1D /* feedbackActivity~ipad.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "feedbackActivity~ipad.png"; sourceTree = ""; }; + 1EAF20A6162DC0F600957B1D /* feedbackActiviy.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = feedbackActiviy.png; sourceTree = ""; }; + 1EAF20A7162DC0F600957B1D /* feedbackActiviy@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "feedbackActiviy@2x.png"; sourceTree = ""; }; 1EC69F5D1615001500808FD9 /* BITHockeyManagerPrivate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BITHockeyManagerPrivate.h; sourceTree = ""; }; 1EDA60CF15C2C1450032D10B /* HockeySDK-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "HockeySDK-Info.plist"; sourceTree = ""; }; 1EF95CA4162CB036000AE3AD /* BITFeedbackActivity.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BITFeedbackActivity.h; sourceTree = ""; }; @@ -231,6 +239,10 @@ 1E5955C115B71C8600A03429 /* buttonHighlight@2x.png */, 1E5955C415B71C8600A03429 /* IconGradient.png */, 1E5955C515B71C8600A03429 /* IconGradient@2x.png */, + 1EAF20A4162DC0F600957B1D /* feedbackActivity@2x~ipad.png */, + 1EAF20A5162DC0F600957B1D /* feedbackActivity~ipad.png */, + 1EAF20A6162DC0F600957B1D /* feedbackActiviy.png */, + 1EAF20A7162DC0F600957B1D /* feedbackActiviy@2x.png */, ); name = Images; sourceTree = ""; @@ -520,6 +532,10 @@ 1E5955CF15B71C8600A03429 /* IconGradient.png in Resources */, 1E5955D015B71C8600A03429 /* IconGradient@2x.png in Resources */, 1E27EF2515BB5033000AE995 /* HockeySDK.strings in Resources */, + 1EAF20A8162DC0F600957B1D /* feedbackActivity@2x~ipad.png in Resources */, + 1EAF20A9162DC0F600957B1D /* feedbackActivity~ipad.png in Resources */, + 1EAF20AA162DC0F600957B1D /* feedbackActiviy.png in Resources */, + 1EAF20AB162DC0F600957B1D /* feedbackActiviy@2x.png in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; From 1f902b43891991c97dbcc4f05d1ab35d54c1a5d1 Mon Sep 17 00:00:00 2001 From: Andreas Linde Date: Wed, 17 Oct 2012 00:47:55 +0200 Subject: [PATCH 047/176] Show the proper app name in feedback activity --- Classes/BITFeedbackActivity.m | 6 ++++-- Resources/de.lproj/HockeySDK.strings | 3 +++ Resources/en.lproj/HockeySDK.strings | 3 +++ Resources/es.lproj/HockeySDK.strings | 3 +++ Resources/fr.lproj/HockeySDK.strings | 3 +++ Resources/it.lproj/HockeySDK.strings | 3 +++ Resources/ja.lproj/HockeySDK.strings | 3 +++ Resources/nl.lproj/HockeySDK.strings | 3 +++ Resources/pt-PT.lproj/HockeySDK.strings | 3 +++ Resources/pt.lproj/HockeySDK.strings | 3 +++ Resources/ru.lproj/HockeySDK.strings | 3 +++ Resources/sv.lproj/HockeySDK.strings | 3 +++ Resources/tr.lproj/HockeySDK.strings | 3 +++ Resources/zh_CN.lproj/HockeySDK.strings | 3 +++ Resources/zh_TW.lproj/HockeySDK.strings | 3 +++ 15 files changed, 46 insertions(+), 2 deletions(-) diff --git a/Classes/BITFeedbackActivity.m b/Classes/BITFeedbackActivity.m index 2bfa0f30..2dd581ef 100644 --- a/Classes/BITFeedbackActivity.m +++ b/Classes/BITFeedbackActivity.m @@ -20,8 +20,10 @@ - (NSString *)activityType { } - (NSString *)activityTitle { - NSString *appName = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleName"]; - + NSString *appName = [[[NSBundle mainBundle] localizedInfoDictionary] objectForKey:@"CFBundleDisplayName"]; + if (!appName) + appName = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleDisplayName"] ?: BITHockeyLocalizedString(@"HockeyFeedbackActivityAppPlaceholder"); + return [NSString stringWithFormat:BITHockeyLocalizedString(@"HockeyFeedbackActivityButtonTitle"), appName]; } diff --git a/Resources/de.lproj/HockeySDK.strings b/Resources/de.lproj/HockeySDK.strings index b4d62901..10752150 100755 --- a/Resources/de.lproj/HockeySDK.strings +++ b/Resources/de.lproj/HockeySDK.strings @@ -188,6 +188,9 @@ /* Activity Sharing Button Title, App Name will be inserted */ "HockeyFeedbackActivityButtonTitle" = "%@ Feedback"; +/* if there can no app name be found, use this instead for HockeyFeedbackActivityButtonTitle */ +"HockeyFeedbackActivityAppPlaceholder" = "App"; + /* Compose Message */ diff --git a/Resources/en.lproj/HockeySDK.strings b/Resources/en.lproj/HockeySDK.strings index c42969d4..5d8d491e 100755 --- a/Resources/en.lproj/HockeySDK.strings +++ b/Resources/en.lproj/HockeySDK.strings @@ -185,6 +185,9 @@ /* Activity Sharing Button Title, App Name will be inserted */ "HockeyFeedbackActivityButtonTitle" = "%@ Feedback"; +/* if there can no app name be found, use this instead for HockeyFeedbackActivityButtonTitle */ +"HockeyFeedbackActivityAppPlaceholder" = "App"; + /* Compose Message */ diff --git a/Resources/es.lproj/HockeySDK.strings b/Resources/es.lproj/HockeySDK.strings index 061a4549..0b77a04f 100755 --- a/Resources/es.lproj/HockeySDK.strings +++ b/Resources/es.lproj/HockeySDK.strings @@ -186,6 +186,9 @@ /* Activity Sharing Button Title, App Name will be inserted */ "HockeyFeedbackActivityButtonTitle" = "%@ Feedback"; +/* if there can no app name be found, use this instead for HockeyFeedbackActivityButtonTitle */ +"HockeyFeedbackActivityAppPlaceholder" = "App"; + /* Compose Message */ diff --git a/Resources/fr.lproj/HockeySDK.strings b/Resources/fr.lproj/HockeySDK.strings index 051b70a7..03544f36 100755 --- a/Resources/fr.lproj/HockeySDK.strings +++ b/Resources/fr.lproj/HockeySDK.strings @@ -186,6 +186,9 @@ /* Activity Sharing Button Title, App Name will be inserted */ "HockeyFeedbackActivityButtonTitle" = "%@ Feedback"; +/* if there can no app name be found, use this instead for HockeyFeedbackActivityButtonTitle */ +"HockeyFeedbackActivityAppPlaceholder" = "App"; + /* Compose Message */ diff --git a/Resources/it.lproj/HockeySDK.strings b/Resources/it.lproj/HockeySDK.strings index aa33045a..eb59079b 100755 --- a/Resources/it.lproj/HockeySDK.strings +++ b/Resources/it.lproj/HockeySDK.strings @@ -186,6 +186,9 @@ /* Activity Sharing Button Title, App Name will be inserted */ "HockeyFeedbackActivityButtonTitle" = "%@ Feedback"; +/* if there can no app name be found, use this instead for HockeyFeedbackActivityButtonTitle */ +"HockeyFeedbackActivityAppPlaceholder" = "App"; + /* Compose Message */ diff --git a/Resources/ja.lproj/HockeySDK.strings b/Resources/ja.lproj/HockeySDK.strings index 935f5d41..b9d77d1e 100755 --- a/Resources/ja.lproj/HockeySDK.strings +++ b/Resources/ja.lproj/HockeySDK.strings @@ -186,6 +186,9 @@ /* Activity Sharing Button Title, App Name will be inserted */ "HockeyFeedbackActivityButtonTitle" = "%@ Feedback"; +/* if there can no app name be found, use this instead for HockeyFeedbackActivityButtonTitle */ +"HockeyFeedbackActivityAppPlaceholder" = "App"; + /* Compose Message */ diff --git a/Resources/nl.lproj/HockeySDK.strings b/Resources/nl.lproj/HockeySDK.strings index 6c507108..b88870c4 100755 --- a/Resources/nl.lproj/HockeySDK.strings +++ b/Resources/nl.lproj/HockeySDK.strings @@ -186,6 +186,9 @@ /* Activity Sharing Button Title, App Name will be inserted */ "HockeyFeedbackActivityButtonTitle" = "%@ Feedback"; +/* if there can no app name be found, use this instead for HockeyFeedbackActivityButtonTitle */ +"HockeyFeedbackActivityAppPlaceholder" = "App"; + /* Compose Message */ diff --git a/Resources/pt-PT.lproj/HockeySDK.strings b/Resources/pt-PT.lproj/HockeySDK.strings index decaa4ba..0d10b835 100755 --- a/Resources/pt-PT.lproj/HockeySDK.strings +++ b/Resources/pt-PT.lproj/HockeySDK.strings @@ -186,6 +186,9 @@ /* Activity Sharing Button Title, App Name will be inserted */ "HockeyFeedbackActivityButtonTitle" = "%@ Feedback"; +/* if there can no app name be found, use this instead for HockeyFeedbackActivityButtonTitle */ +"HockeyFeedbackActivityAppPlaceholder" = "App"; + /* Compose Message */ diff --git a/Resources/pt.lproj/HockeySDK.strings b/Resources/pt.lproj/HockeySDK.strings index 3a1b4e5d..4e42872a 100755 --- a/Resources/pt.lproj/HockeySDK.strings +++ b/Resources/pt.lproj/HockeySDK.strings @@ -186,6 +186,9 @@ /* Activity Sharing Button Title, App Name will be inserted */ "HockeyFeedbackActivityButtonTitle" = "%@ Feedback"; +/* if there can no app name be found, use this instead for HockeyFeedbackActivityButtonTitle */ +"HockeyFeedbackActivityAppPlaceholder" = "App"; + /* Compose Message */ diff --git a/Resources/ru.lproj/HockeySDK.strings b/Resources/ru.lproj/HockeySDK.strings index e09737e6..844b7b30 100755 --- a/Resources/ru.lproj/HockeySDK.strings +++ b/Resources/ru.lproj/HockeySDK.strings @@ -186,6 +186,9 @@ /* Activity Sharing Button Title, App Name will be inserted */ "HockeyFeedbackActivityButtonTitle" = "%@ Feedback"; +/* if there can no app name be found, use this instead for HockeyFeedbackActivityButtonTitle */ +"HockeyFeedbackActivityAppPlaceholder" = "App"; + /* Compose Message */ diff --git a/Resources/sv.lproj/HockeySDK.strings b/Resources/sv.lproj/HockeySDK.strings index b646e6d9..e49649d0 100755 --- a/Resources/sv.lproj/HockeySDK.strings +++ b/Resources/sv.lproj/HockeySDK.strings @@ -186,6 +186,9 @@ /* Activity Sharing Button Title, App Name will be inserted */ "HockeyFeedbackActivityButtonTitle" = "%@ Feedback"; +/* if there can no app name be found, use this instead for HockeyFeedbackActivityButtonTitle */ +"HockeyFeedbackActivityAppPlaceholder" = "App"; + /* Compose Message */ diff --git a/Resources/tr.lproj/HockeySDK.strings b/Resources/tr.lproj/HockeySDK.strings index a0747e7d..59c489e8 100644 --- a/Resources/tr.lproj/HockeySDK.strings +++ b/Resources/tr.lproj/HockeySDK.strings @@ -186,6 +186,9 @@ /* Activity Sharing Button Title, App Name will be inserted */ "HockeyFeedbackActivityButtonTitle" = "%@ Feedback"; +/* if there can no app name be found, use this instead for HockeyFeedbackActivityButtonTitle */ +"HockeyFeedbackActivityAppPlaceholder" = "App"; + /* Compose Message */ diff --git a/Resources/zh_CN.lproj/HockeySDK.strings b/Resources/zh_CN.lproj/HockeySDK.strings index a8b77cdb..a2def09f 100644 --- a/Resources/zh_CN.lproj/HockeySDK.strings +++ b/Resources/zh_CN.lproj/HockeySDK.strings @@ -186,6 +186,9 @@ /* Activity Sharing Button Title, App Name will be inserted */ "HockeyFeedbackActivityButtonTitle" = "%@ Feedback"; +/* if there can no app name be found, use this instead for HockeyFeedbackActivityButtonTitle */ +"HockeyFeedbackActivityAppPlaceholder" = "App"; + /* Compose Message */ diff --git a/Resources/zh_TW.lproj/HockeySDK.strings b/Resources/zh_TW.lproj/HockeySDK.strings index 38ac41ad..1caa729b 100644 --- a/Resources/zh_TW.lproj/HockeySDK.strings +++ b/Resources/zh_TW.lproj/HockeySDK.strings @@ -186,6 +186,9 @@ /* Activity Sharing Button Title, App Name will be inserted */ "HockeyFeedbackActivityButtonTitle" = "%@ Feedback"; +/* if there can no app name be found, use this instead for HockeyFeedbackActivityButtonTitle */ +"HockeyFeedbackActivityAppPlaceholder" = "App"; + /* Compose Message */ From 356e9fb4dafc174efbbdff7f2a75802c19201e34 Mon Sep 17 00:00:00 2001 From: Andreas Linde Date: Wed, 17 Oct 2012 01:10:16 +0200 Subject: [PATCH 048/176] Save feedback data into NSApplicationSupportDirectory instead of NSCachesDirectory We don't want that data to be purged by the system, since there is user entered data in it like name and email, also thread token etc. --- Classes/BITFeedbackManager.m | 1 - 1 file changed, 1 deletion(-) diff --git a/Classes/BITFeedbackManager.m b/Classes/BITFeedbackManager.m index 2189b891..c8803bd9 100644 --- a/Classes/BITFeedbackManager.m +++ b/Classes/BITFeedbackManager.m @@ -83,7 +83,6 @@ - (id)init { _fileManager = [[NSFileManager alloc] init]; // temporary directory for crashes grabbed from PLCrashReporter - NSArray *paths = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES); _feedbackDir = [[[paths objectAtIndex:0] stringByAppendingPathComponent:BITHOCKEY_IDENTIFIER] retain]; if (![_fileManager fileExistsAtPath:_feedbackDir]) { From 76571865848d613a38615cdc61ff3595c05bf889 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Eloy=20Dur=C3=A1n?= Date: Wed, 17 Oct 2012 13:59:39 +0200 Subject: [PATCH 049/176] Prepare podspec for future 2.5.5 version. --- HockeySDK.podspec | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/HockeySDK.podspec b/HockeySDK.podspec index 5c9ea3df..b9600f43 100644 --- a/HockeySDK.podspec +++ b/HockeySDK.podspec @@ -1,12 +1,12 @@ Pod::Spec.new do |s| s.name = 'HockeySDK' - s.version = '2.5.3' + s.version = '2.5.5' s.license = 'MIT' s.platform = :ios, '4.0' s.summary = 'Distribute beta apps and collect crash reports with HockeyApp.' s.homepage = 'http://hockeyapp.net/' s.author = { 'Andreas Linde' => 'mail@andreaslinde.de', 'Thomas Dohmke' => "thomas@dohmke.de" } - s.source = { :git => 'https://github.com/bitstadium/HockeySDK-iOS.git', :tag => '2.5.3' } + s.source = { :git => 'https://github.com/bitstadium/HockeySDK-iOS.git', :tag => '2.5.5' } s.description = 'HockeyApp is a server to distribute beta apps and collect crash reports. ' \ 'It improves the testing process dramatically and can be used for both beta ' \ From 806812098e26fce5f535b662b6ab009ca1547ffb Mon Sep 17 00:00:00 2001 From: Andreas Linde Date: Wed, 17 Oct 2012 19:18:37 +0200 Subject: [PATCH 050/176] Integrate TTTAttributedLabel by @mattt Changed the class and protocol prefix to BIT to make sure no problems come up if the app has its own version of that class --- Classes/BITAttributedLabel.h | 330 +++++++ Classes/BITAttributedLabel.m | 968 ++++++++++++++++++++ LICENSE | 53 +- Support/HockeySDK.xcconfig | 2 +- Support/HockeySDK.xcodeproj/project.pbxproj | 8 + 5 files changed, 1346 insertions(+), 15 deletions(-) create mode 100755 Classes/BITAttributedLabel.h create mode 100755 Classes/BITAttributedLabel.m diff --git a/Classes/BITAttributedLabel.h b/Classes/BITAttributedLabel.h new file mode 100755 index 00000000..9b898d58 --- /dev/null +++ b/Classes/BITAttributedLabel.h @@ -0,0 +1,330 @@ +// TTTAttributedLabel.h +// +// Copyright (c) 2011 Mattt Thompson (http://mattt.me) +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import +#import + +/** + Vertical alignment for text in a label whose bounds are larger than its text bounds + */ +typedef enum { + BITAttributedLabelVerticalAlignmentCenter = 0, + BITAttributedLabelVerticalAlignmentTop = 1, + BITAttributedLabelVerticalAlignmentBottom = 2, +} BITAttributedLabelVerticalAlignment; + +/** + Determines whether the text to which this attribute applies has a strikeout drawn through itself. + */ +extern NSString * const kTTTStrikeOutAttributeName; + +/** + The background fill color. Value must be a `CGColorRef`. Default value is `nil` (no fill). + */ +extern NSString * const kTTTBackgroundFillColorAttributeName; + +/** + The background stroke color. Value must be a `CGColorRef`. Default value is `nil` (no stroke). + */ +extern NSString * const kTTTBackgroundStrokeColorAttributeName; + +/** + The background stroke line width. Value must be an `NSNumber`. Default value is `1.0f`. + */ +extern NSString * const kTTTBackgroundLineWidthAttributeName; + +/** + The background corner radius. Value must be an `NSNumber`. Default value is `5.0f`. + */ +extern NSString * const kTTTBackgroundCornerRadiusAttributeName; + +@protocol BITAttributedLabelDelegate; + +// Override UILabel @property to accept both NSString and NSAttributedString +@protocol BITAttributedLabel +@property (nonatomic, copy) id text; +@end + +/** + `TTTAttributedLabel` is a drop-in replacement for `UILabel` that supports `NSAttributedString`, as well as automatically-detected and manually-added links to URLs, addresses, phone numbers, and dates. + + # Differences Between `TTTAttributedLabel` and `UILabel` + + For the most part, `TTTAttributedLabel` behaves just like `UILabel`. The following are notable exceptions, in which `TTTAttributedLabel` properties may act differently: + + - `text` - This property now takes an `id` type argument, which can either be a kind of `NSString` or `NSAttributedString` (mutable or immutable in both cases) + - `lineBreakMode` - This property displays only the first line when the value is `UILineBreakModeHeadTruncation`, `UILineBreakModeTailTruncation`, or `UILineBreakModeMiddleTruncation` + - `adjustsFontsizeToFitWidth` - Supported in iOS 5 and greater, this property is effective for any value of `numberOfLines` greater than zero. In iOS 4, setting `numberOfLines` to a value greater than 1 with `adjustsFontSizeToFitWidth` set to `YES` may cause `sizeToFit` to execute indefinitely. + + Any properties affecting text or paragraph styling, such as `shadowRadius` or `firstLineIndent` will only apply when text is set with an `NSString`. If the text is set with an `NSAttributedString`, these properties will not apply. + + @warning Any properties changed on the label after setting the text will not be reflected until a subsequent call to `setText:` or `setText:afterInheritingLabelAttributesAndConfiguringWithBlock:`. This is to say, order of operations matters in this case. For example, if the label text color is originally black when the text is set, changing the text color to red will have no effect on the display of the label until the text is set once again. + */ +@interface BITAttributedLabel : UILabel + +///----------------------------- +/// @name Accessing the Delegate +///----------------------------- + +/** + The receiver's delegate. + + @discussion A `TTTAttributedLabel` delegate responds to messages sent by tapping on links in the label. You can use the delegate to respond to links referencing a URL, address, phone number, date, or date with a specified time zone and duration. + */ +@property (nonatomic, unsafe_unretained) id delegate; + +///-------------------------------------------- +/// @name Detecting, Accessing, & Styling Links +///-------------------------------------------- + +/** + A bitmask of `UIDataDetectorTypes` which are used to automatically detect links in the label text. This is `UIDataDetectorTypeNone` by default. + + @warning You must specify `dataDetectorTypes` before setting the `text`, with either `setText:` or `setText:afterInheritingLabelAttributesAndConfiguringWithBlock:`. + */ +@property (nonatomic, assign) UIDataDetectorTypes dataDetectorTypes; + +/** + An array of `NSTextCheckingResult` objects for links detected or manually added to the label text. + */ +@property (readonly, nonatomic, strong) NSArray *links; + +/** + A dictionary containing the `NSAttributedString` attributes to be applied to links detected or manually added to the label text. The default link style is blue and underlined. + + @warning You must specify `linkAttributes` before setting autodecting or manually-adding links for these attributes to be applied. + */ +@property (nonatomic, strong) NSDictionary *linkAttributes; + +/** + A dictionary containing the `NSAttributedString` attributes to be applied to links when they are in the active state. Supply `nil` or an empty dictionary to opt out of active link styling. The default active link style is red and underlined. + */ +@property (nonatomic, strong) NSDictionary *activeLinkAttributes; + +///--------------------------------------- +/// @name Acccessing Text Style Attributes +///--------------------------------------- + +/** + The shadow blur radius for the label. A value of 0 indicates no blur, while larger values produce correspondingly larger blurring. This value must not be negative. The default value is 0. + */ +@property (nonatomic, assign) CGFloat shadowRadius; + +///-------------------------------------------- +/// @name Acccessing Paragraph Style Attributes +///-------------------------------------------- + +/** + The distance, in points, from the leading margin of a frame to the beginning of the paragraph's first line. This value is always nonnegative, and is 0.0 by default. + */ +@property (nonatomic, assign) CGFloat firstLineIndent; + +/** + The space in points added between lines within the paragraph. This value is always nonnegative and is 0.0 by default. + */ +@property (nonatomic, assign) CGFloat leading; + +/** + The line height multiple. This value is 0.0 by default. + */ +@property (nonatomic, assign) CGFloat lineHeightMultiple; + +/** + The distance, in points, from the margin to the text container. This value is `UIEdgeInsetsZero` by default. + + @discussion The `UIEdgeInset` members correspond to paragraph style properties rather than a particular geometry, and can change depending on the writing direction. + + ## `UIEdgeInset` Member Correspondence With `CTParagraphStyleSpecifier` Values: + + - `top`: `kCTParagraphStyleSpecifierParagraphSpacingBefore` + - `left`: `kCTParagraphStyleSpecifierHeadIndent` + - `bottom`: `kCTParagraphStyleSpecifierParagraphSpacing` + - `right`: `kCTParagraphStyleSpecifierTailIndent` + + */ +@property (nonatomic, assign) UIEdgeInsets textInsets; + +/** + The vertical text alignment for the label, for when the frame size is greater than the text rect size. The vertical alignment is `TTTAttributedLabelVerticalAlignmentCenter` by default. + */ +@property (nonatomic, assign) BITAttributedLabelVerticalAlignment verticalAlignment; + +///---------------------------------- +/// @name Setting the Text Attributes +///---------------------------------- + +/** + Sets the text displayed by the label. + + @param text An `NSString` or `NSAttributedString` object to be displayed by the label. If the specified text is an `NSString`, the label will display the text like a `UILabel`, inheriting the text styles of the label. If the specified text is an `NSAttributedString`, the label text styles will be overridden by the styles specified in the attributed string. + + @discussion This method overrides `UILabel -setText:` to accept both `NSString` and `NSAttributedString` objects. This string is `nil` by default. + */ +- (void)setText:(id)text; + +/** + Sets the text displayed by the label, after configuring an attributed string containing the text attributes inherited from the label in a block. + + @param text An `NSString` or `NSAttributedString` object to be displayed by the label. + @param block A block object that returns an `NSMutableAttributedString` object and takes a single argument, which is an `NSMutableAttributedString` object with the text from the first parameter, and the text attributes inherited from the label text styles. For example, if you specified the `font` of the label to be `[UIFont boldSystemFontOfSize:14]` and `textColor` to be `[UIColor redColor]`, the `NSAttributedString` argument of the block would be contain the `NSAttributedString` attribute equivalents of those properties. In this block, you can set further attributes on particular ranges. + + @discussion This string is `nil` by default. + */ +- (void)setText:(id)text afterInheritingLabelAttributesAndConfiguringWithBlock:(NSMutableAttributedString *(^)(NSMutableAttributedString *mutableAttributedString))block; + +///---------------------------------- +/// @name Accessing the Text Attributes +///---------------------------------- + +/** + A copy of the label's current attributedText. This returns `nil` if an attributed string has never been set on the label. + */ +@property (readwrite, nonatomic, copy) NSAttributedString *attributedText; + +///------------------- +/// @name Adding Links +///------------------- + +/** + Adds a link to an `NSTextCheckingResult`. + + @param result An `NSTextCheckingResult` representing the link's location and type. + */ +- (void)addLinkWithTextCheckingResult:(NSTextCheckingResult *)result; + +/** + Adds a link to an `NSTextCheckingResult`. + + @param result An `NSTextCheckingResult` representing the link's location and type. + @param attributes The attributes to be added to the text in the range of the specified link. If `nil`, no attributes are added. + */ +- (void)addLinkWithTextCheckingResult:(NSTextCheckingResult *)result attributes:(NSDictionary *)attributes; + +/** + Adds a link to a URL for a specified range in the label text. + + @param url The url to be linked to + @param range The range in the label text of the link. The range must not exceed the bounds of the receiver. + */ +- (void)addLinkToURL:(NSURL *)url withRange:(NSRange)range; + +/** + Adds a link to an address for a specified range in the label text. + + @param addressComponents A dictionary of address components for the address to be linked to + @param range The range in the label text of the link. The range must not exceed the bounds of the receiver. + + @discussion The address component dictionary keys are described in `NSTextCheckingResult`'s "Keys for Address Components." + */ +- (void)addLinkToAddress:(NSDictionary *)addressComponents withRange:(NSRange)range; + +/** + Adds a link to a phone number for a specified range in the label text. + + @param phoneNumber The phone number to be linked to. + @param range The range in the label text of the link. The range must not exceed the bounds of the receiver. + */ +- (void)addLinkToPhoneNumber:(NSString *)phoneNumber withRange:(NSRange)range; + +/** + Adds a link to a date for a specified range in the label text. + + @param date The date to be linked to. + @param range The range in the label text of the link. The range must not exceed the bounds of the receiver. + */ +- (void)addLinkToDate:(NSDate *)date withRange:(NSRange)range; + +/** + Adds a link to a date with a particular time zone and duration for a specified range in the label text. + + @param date The date to be linked to. + @param timeZone The time zone of the specified date. + @param duration The duration, in seconds from the specified date. + @param range The range in the label text of the link. The range must not exceed the bounds of the receiver. + */ +- (void)addLinkToDate:(NSDate *)date timeZone:(NSTimeZone *)timeZone duration:(NSTimeInterval)duration withRange:(NSRange)range; + +@end + +/** + The `TTTAttributedLabelDelegate` protocol defines the messages sent to an attributed label delegate when links are tapped. All of the methods of this protocol are optional. + */ +@protocol BITAttributedLabelDelegate + +///----------------------------------- +/// @name Responding to Link Selection +///----------------------------------- +@optional + +/** + Tells the delegate that the user did select a link to a URL. + + @param label The label whose link was selected. + @param url The URL for the selected link. + */ +- (void)attributedLabel:(BITAttributedLabel *)label didSelectLinkWithURL:(NSURL *)url; + +/** + Tells the delegate that the user did select a link to an address. + + @param label The label whose link was selected. + @param addressComponents The components of the address for the selected link. + */ +- (void)attributedLabel:(BITAttributedLabel *)label didSelectLinkWithAddress:(NSDictionary *)addressComponents; + +/** + Tells the delegate that the user did select a link to a phone number. + + @param label The label whose link was selected. + @param phoneNumber The phone number for the selected link. + */ +- (void)attributedLabel:(BITAttributedLabel *)label didSelectLinkWithPhoneNumber:(NSString *)phoneNumber; + +/** + Tells the delegate that the user did select a link to a date. + + @param label The label whose link was selected. + @param date The datefor the selected link. + */ +- (void)attributedLabel:(BITAttributedLabel *)label didSelectLinkWithDate:(NSDate *)date; + +/** + Tells the delegate that the user did select a link to a date with a time zone and duration. + + @param label The label whose link was selected. + @param date The date for the selected link. + @param timeZone The time zone of the date for the selected link. + @param duration The duration, in seconds from the date for the selected link. + */ +- (void)attributedLabel:(BITAttributedLabel *)label didSelectLinkWithDate:(NSDate *)date timeZone:(NSTimeZone *)timeZone duration:(NSTimeInterval)duration; + +/** + Tells the delegate that the user did select a link to a text checking result. + + @discussion This method is called if no other delegate method was called, which can occur by either now implementing the method in `TTTAttributedLabelDelegate` corresponding to a particular link, or the link was added by passing an instance of a custom `NSTextCheckingResult` subclass into `-addLinkWithTextCheckingResult:`. + + @param label The label whose link was selected. + @param result The custom text checking result. + */ +- (void)attributedLabel:(BITAttributedLabel *)label didSelectLinkWithTextCheckingResult:(NSTextCheckingResult *)result; + +@end diff --git a/Classes/BITAttributedLabel.m b/Classes/BITAttributedLabel.m new file mode 100755 index 00000000..6baef416 --- /dev/null +++ b/Classes/BITAttributedLabel.m @@ -0,0 +1,968 @@ +// TTTAttributedLabel.m +// +// Copyright (c) 2011 Mattt Thompson (http://mattt.me) +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#import "BITAttributedLabel.h" + +#define kTTTLineBreakWordWrapTextWidthScalingFactor (M_PI / M_E) + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" + +NSString * const kTTTStrikeOutAttributeName = @"TTTStrikeOutAttribute"; +NSString * const kTTTBackgroundFillColorAttributeName = @"TTTBackgroundFillColor"; +NSString * const kTTTBackgroundStrokeColorAttributeName = @"TTTBackgroundStrokeColor"; +NSString * const kTTTBackgroundLineWidthAttributeName = @"TTTBackgroundLineWidth"; +NSString * const kTTTBackgroundCornerRadiusAttributeName = @"TTTBackgroundCornerRadius"; + +static inline CTTextAlignment CTTextAlignmentFromUITextAlignment(UITextAlignment alignment) { + switch (alignment) { + case UITextAlignmentLeft: return kCTLeftTextAlignment; + case UITextAlignmentCenter: return kCTCenterTextAlignment; + case UITextAlignmentRight: return kCTRightTextAlignment; + default: return kCTNaturalTextAlignment; + } +} + +static inline CTLineBreakMode CTLineBreakModeFromUILineBreakMode(UILineBreakMode lineBreakMode) { + switch (lineBreakMode) { + case UILineBreakModeWordWrap: return kCTLineBreakByWordWrapping; + case UILineBreakModeCharacterWrap: return kCTLineBreakByCharWrapping; + case UILineBreakModeClip: return kCTLineBreakByClipping; + case UILineBreakModeHeadTruncation: return kCTLineBreakByTruncatingHead; + case UILineBreakModeTailTruncation: return kCTLineBreakByTruncatingTail; + case UILineBreakModeMiddleTruncation: return kCTLineBreakByTruncatingMiddle; + default: return 0; + } +} + +static inline NSTextCheckingType NSTextCheckingTypeFromUIDataDetectorType(UIDataDetectorTypes dataDetectorType) { + NSTextCheckingType textCheckingType = 0; + if (dataDetectorType & UIDataDetectorTypeAddress) { + textCheckingType |= NSTextCheckingTypeAddress; + } + + if (dataDetectorType & UIDataDetectorTypeCalendarEvent) { + textCheckingType |= NSTextCheckingTypeDate; + } + + if (dataDetectorType & UIDataDetectorTypeLink) { + textCheckingType |= NSTextCheckingTypeLink; + } + + if (dataDetectorType & UIDataDetectorTypePhoneNumber) { + textCheckingType |= NSTextCheckingTypePhoneNumber; + } + + return textCheckingType; +} + +static inline NSDictionary * NSAttributedStringAttributesFromLabel(BITAttributedLabel *label) { + NSMutableDictionary *mutableAttributes = [NSMutableDictionary dictionary]; + + CTFontRef font = CTFontCreateWithName((__bridge CFStringRef)label.font.fontName, label.font.pointSize, NULL); + [mutableAttributes setObject:(__bridge id)font forKey:(NSString *)kCTFontAttributeName]; + CFRelease(font); + + [mutableAttributes setObject:(id)[label.textColor CGColor] forKey:(NSString *)kCTForegroundColorAttributeName]; + + CTTextAlignment alignment = CTTextAlignmentFromUITextAlignment(label.textAlignment); + CGFloat lineSpacing = label.leading; + CGFloat lineSpacingAdjustment = label.font.lineHeight - label.font.ascender + label.font.descender; + CGFloat lineHeightMultiple = label.lineHeightMultiple; + CGFloat topMargin = label.textInsets.top; + CGFloat bottomMargin = label.textInsets.bottom; + CGFloat leftMargin = label.textInsets.left; + CGFloat rightMargin = label.textInsets.right; + CGFloat firstLineIndent = label.firstLineIndent + leftMargin; + + CTLineBreakMode lineBreakMode; + if (label.numberOfLines != 1) { + lineBreakMode = CTLineBreakModeFromUILineBreakMode(UILineBreakModeWordWrap); + } else { + lineBreakMode = CTLineBreakModeFromUILineBreakMode(label.lineBreakMode); + } + + CTParagraphStyleSetting paragraphStyles[10] = { + {.spec = kCTParagraphStyleSpecifierAlignment, .valueSize = sizeof(CTTextAlignment), .value = (const void *)&alignment}, + {.spec = kCTParagraphStyleSpecifierLineBreakMode, .valueSize = sizeof(CTLineBreakMode), .value = (const void *)&lineBreakMode}, + {.spec = kCTParagraphStyleSpecifierLineSpacing, .valueSize = sizeof(CGFloat), .value = (const void *)&lineSpacing}, + {.spec = kCTParagraphStyleSpecifierLineSpacingAdjustment, .valueSize = sizeof (CGFloat), .value = (const void *)&lineSpacingAdjustment}, + {.spec = kCTParagraphStyleSpecifierLineHeightMultiple, .valueSize = sizeof(CGFloat), .value = (const void *)&lineHeightMultiple}, + {.spec = kCTParagraphStyleSpecifierFirstLineHeadIndent, .valueSize = sizeof(CGFloat), .value = (const void *)&firstLineIndent}, + {.spec = kCTParagraphStyleSpecifierParagraphSpacingBefore, .valueSize = sizeof(CGFloat), .value = (const void *)&topMargin}, + {.spec = kCTParagraphStyleSpecifierParagraphSpacing, .valueSize = sizeof(CGFloat), .value = (const void *)&bottomMargin}, + {.spec = kCTParagraphStyleSpecifierHeadIndent, .valueSize = sizeof(CGFloat), .value = (const void *)&leftMargin}, + {.spec = kCTParagraphStyleSpecifierTailIndent, .valueSize = sizeof(CGFloat), .value = (const void *)&rightMargin} + }; + + CTParagraphStyleRef paragraphStyle = CTParagraphStyleCreate(paragraphStyles, 10); + [mutableAttributes setObject:(__bridge id)paragraphStyle forKey:(NSString *)kCTParagraphStyleAttributeName]; + CFRelease(paragraphStyle); + + return [NSDictionary dictionaryWithDictionary:mutableAttributes]; +} + +static inline NSAttributedString * NSAttributedStringByScalingFontSize(NSAttributedString *attributedString, CGFloat scale, CGFloat minimumFontSize) { + NSMutableAttributedString *mutableAttributedString = [attributedString mutableCopy]; + [mutableAttributedString enumerateAttribute:(NSString *)kCTFontAttributeName inRange:NSMakeRange(0, [mutableAttributedString length]) options:0 usingBlock:^(id value, NSRange range, BOOL *stop) { + CTFontRef font = (__bridge CTFontRef)value; + if (font) { + CGFloat scaledFontSize = floorf(CTFontGetSize(font) * scale); + CTFontRef scaledFont = CTFontCreateCopyWithAttributes(font, fmaxf(scaledFontSize, minimumFontSize), NULL, NULL); + CFAttributedStringSetAttribute((__bridge CFMutableAttributedStringRef)mutableAttributedString, CFRangeMake(range.location, range.length), kCTFontAttributeName, scaledFont); + CFRelease(scaledFont); + } + }]; + + return mutableAttributedString; +} + +static inline NSAttributedString * NSAttributedStringBySettingColorFromContext(NSAttributedString *attributedString, UIColor *color) { + if (!color) { + return attributedString; + } + + CGColorRef colorRef = color.CGColor; + NSMutableAttributedString *mutableAttributedString = [attributedString mutableCopy]; + [mutableAttributedString enumerateAttribute:(NSString *)kCTForegroundColorFromContextAttributeName inRange:NSMakeRange(0, [mutableAttributedString length]) options:0 usingBlock:^(id value, NSRange range, BOOL *stop) { + CFBooleanRef usesColorFromContext = (__bridge CFBooleanRef)value; + if (usesColorFromContext && CFBooleanGetValue(usesColorFromContext)) { + CFRange updateRange = CFRangeMake(range.location, range.length); + CFAttributedStringSetAttribute((__bridge CFMutableAttributedStringRef)mutableAttributedString, updateRange, kCTForegroundColorAttributeName, colorRef); + CFAttributedStringRemoveAttribute((__bridge CFMutableAttributedStringRef)mutableAttributedString, updateRange, kCTForegroundColorFromContextAttributeName); + } + }]; + + return mutableAttributedString; +} + +@interface BITAttributedLabel () +@property (readwrite, nonatomic, copy) NSAttributedString *inactiveAttributedText; +@property (readwrite, nonatomic, copy) NSAttributedString *renderedAttributedText; +@property (readwrite, nonatomic, assign) CTFramesetterRef framesetter; +@property (readwrite, nonatomic, assign) CTFramesetterRef highlightFramesetter; +@property (readwrite, nonatomic, strong) NSDataDetector *dataDetector; +@property (readwrite, nonatomic, strong) NSArray *links; +@property (readwrite, nonatomic, strong) NSTextCheckingResult *activeLink; + +- (void)commonInit; +- (void)setNeedsFramesetter; +- (NSArray *)detectedLinksInString:(NSString *)string range:(NSRange)range error:(NSError **)error; +- (NSTextCheckingResult *)linkAtCharacterIndex:(CFIndex)idx; +- (NSTextCheckingResult *)linkAtPoint:(CGPoint)p; +- (CFIndex)characterIndexAtPoint:(CGPoint)p; +- (void)drawFramesetter:(CTFramesetterRef)framesetter attributedString:(NSAttributedString *)attributedString textRange:(CFRange)textRange inRect:(CGRect)rect context:(CGContextRef)c; +- (void)drawStrike:(CTFrameRef)frame inRect:(CGRect)rect context:(CGContextRef)c; +@end + +@implementation BITAttributedLabel { +@private + BOOL _needsFramesetter; +} + +@dynamic text; +@synthesize attributedText = _attributedText; +@synthesize inactiveAttributedText = _inactiveAttributedText; +@synthesize renderedAttributedText = _renderedAttributedText; +@synthesize framesetter = _framesetter; +@synthesize highlightFramesetter = _highlightFramesetter; +@synthesize delegate = _delegate; +@synthesize dataDetectorTypes = _dataDetectorTypes; +@synthesize dataDetector = _dataDetector; +@synthesize links = _links; +@synthesize linkAttributes = _linkAttributes; +@synthesize activeLinkAttributes = _activeLinkAttributes; +@synthesize shadowRadius = _shadowRadius; +@synthesize leading = _leading; +@synthesize lineHeightMultiple = _lineHeightMultiple; +@synthesize firstLineIndent = _firstLineIndent; +@synthesize textInsets = _textInsets; +@synthesize verticalAlignment = _verticalAlignment; +@synthesize activeLink = _activeLink; + +- (id)initWithFrame:(CGRect)frame { + self = [super initWithFrame:frame]; + if (!self) { + return nil; + } + + [self commonInit]; + + return self; +} + +- (id)initWithCoder:(NSCoder *)coder { + self = [super initWithCoder:coder]; + if (!self) { + return nil; + } + + [self commonInit]; + + return self; +} + +- (void)commonInit { + self.dataDetectorTypes = UIDataDetectorTypeNone; + self.links = [NSArray array]; + + NSMutableDictionary *mutableLinkAttributes = [NSMutableDictionary dictionary]; + [mutableLinkAttributes setValue:(id)[[UIColor blueColor] CGColor] forKey:(NSString*)kCTForegroundColorAttributeName]; + [mutableLinkAttributes setValue:[NSNumber numberWithBool:YES] forKey:(NSString *)kCTUnderlineStyleAttributeName]; + self.linkAttributes = [NSDictionary dictionaryWithDictionary:mutableLinkAttributes]; + + NSMutableDictionary *mutableActiveLinkAttributes = [NSMutableDictionary dictionary]; + [mutableActiveLinkAttributes setValue:(id)[[UIColor redColor] CGColor] forKey:(NSString*)kCTForegroundColorAttributeName]; + [mutableActiveLinkAttributes setValue:[NSNumber numberWithBool:NO] forKey:(NSString *)kCTUnderlineStyleAttributeName]; + + self.activeLinkAttributes = [NSDictionary dictionaryWithDictionary:mutableActiveLinkAttributes]; + + self.textInsets = UIEdgeInsetsZero; + + self.userInteractionEnabled = YES; + self.multipleTouchEnabled = NO; +} + +- (void)dealloc { + if (_framesetter) CFRelease(_framesetter); + if (_highlightFramesetter) CFRelease(_highlightFramesetter); +} + +#pragma mark - + +- (void)setAttributedText:(NSAttributedString *)text { + if ([text isEqualToAttributedString:_attributedText]) { + return; + } + + [self willChangeValueForKey:@"attributedText"]; + _attributedText = [text copy]; + [self didChangeValueForKey:@"attributedText"]; + + [self setNeedsFramesetter]; +} + +- (void)setNeedsFramesetter { + // Reset the rendered attributed text so it has a chance to regenerate + self.renderedAttributedText = nil; + + _needsFramesetter = YES; +} + +- (CTFramesetterRef)framesetter { + if (_needsFramesetter) { + @synchronized(self) { + if (_framesetter) CFRelease(_framesetter); + if (_highlightFramesetter) CFRelease(_highlightFramesetter); + + self.framesetter = CTFramesetterCreateWithAttributedString((__bridge CFAttributedStringRef)self.renderedAttributedText); + self.highlightFramesetter = nil; + _needsFramesetter = NO; + } + } + + return _framesetter; +} + +- (NSAttributedString *)renderedAttributedText { + if (!_renderedAttributedText) { + self.renderedAttributedText = NSAttributedStringBySettingColorFromContext(self.attributedText, self.textColor); + } + + return _renderedAttributedText; +} + +#pragma mark - + +- (void)setLinkActive:(BOOL)active withTextCheckingResult:(NSTextCheckingResult *)result { + if (result && [self.activeLinkAttributes count] > 0) { + if (active) { + if (!self.inactiveAttributedText) { + self.inactiveAttributedText = self.attributedText; + } + + NSMutableAttributedString *mutableAttributedString = [self.inactiveAttributedText mutableCopy]; + [mutableAttributedString addAttributes:self.activeLinkAttributes range:result.range]; + self.attributedText = mutableAttributedString; + + [self setNeedsDisplay]; + } else { + if (self.inactiveAttributedText) { + self.attributedText = self.inactiveAttributedText; + self.inactiveAttributedText = nil; + + [self setNeedsDisplay]; + } + } + } +} + +#pragma mark - + +- (void)setDataDetectorTypes:(UIDataDetectorTypes)dataDetectorTypes { + [self willChangeValueForKey:@"dataDetectorTypes"]; + _dataDetectorTypes = dataDetectorTypes; + [self didChangeValueForKey:@"dataDetectorTypes"]; + + if (self.dataDetectorTypes != UIDataDetectorTypeNone) { + self.dataDetector = [NSDataDetector dataDetectorWithTypes:NSTextCheckingTypeFromUIDataDetectorType(self.dataDetectorTypes) error:nil]; + } +} + +- (NSArray *)detectedLinksInString:(NSString *)string range:(NSRange)range error:(NSError **)error { + if (!string || !self.dataDetector) { + return [NSArray array]; + } + + return [self.dataDetector matchesInString:string options:0 range:range]; +} + +- (void)addLinkWithTextCheckingResult:(NSTextCheckingResult *)result attributes:(NSDictionary *)attributes { + self.links = [self.links arrayByAddingObject:result]; + + if (attributes) { + NSMutableAttributedString *mutableAttributedString = [[NSMutableAttributedString alloc] initWithAttributedString:self.attributedText]; + [mutableAttributedString addAttributes:attributes range:result.range]; + self.attributedText = mutableAttributedString; + } +} + +- (void)addLinkWithTextCheckingResult:(NSTextCheckingResult *)result { + [self addLinkWithTextCheckingResult:result attributes:self.linkAttributes]; +} + +- (void)addLinkToURL:(NSURL *)url withRange:(NSRange)range { + [self addLinkWithTextCheckingResult:[NSTextCheckingResult linkCheckingResultWithRange:range URL:url]]; +} + +- (void)addLinkToAddress:(NSDictionary *)addressComponents withRange:(NSRange)range { + [self addLinkWithTextCheckingResult:[NSTextCheckingResult addressCheckingResultWithRange:range components:addressComponents]]; +} + +- (void)addLinkToPhoneNumber:(NSString *)phoneNumber withRange:(NSRange)range { + [self addLinkWithTextCheckingResult:[NSTextCheckingResult phoneNumberCheckingResultWithRange:range phoneNumber:phoneNumber]]; +} + +- (void)addLinkToDate:(NSDate *)date withRange:(NSRange)range { + [self addLinkWithTextCheckingResult:[NSTextCheckingResult dateCheckingResultWithRange:range date:date]]; +} + +- (void)addLinkToDate:(NSDate *)date timeZone:(NSTimeZone *)timeZone duration:(NSTimeInterval)duration withRange:(NSRange)range { + [self addLinkWithTextCheckingResult:[NSTextCheckingResult dateCheckingResultWithRange:range date:date timeZone:timeZone duration:duration]]; +} + +#pragma mark - + +- (NSTextCheckingResult *)linkAtCharacterIndex:(CFIndex)idx { + for (NSTextCheckingResult *result in self.links) { + NSRange range = result.range; + if ((CFIndex)range.location <= idx && idx <= (CFIndex)(range.location + range.length - 1)) { + return result; + } + } + + return nil; +} + +- (NSTextCheckingResult *)linkAtPoint:(CGPoint)p { + CFIndex idx = [self characterIndexAtPoint:p]; + return [self linkAtCharacterIndex:idx]; +} + +- (CFIndex)characterIndexAtPoint:(CGPoint)p { + if (!CGRectContainsPoint(self.bounds, p)) { + return NSNotFound; + } + + CGRect textRect = [self textRectForBounds:self.bounds limitedToNumberOfLines:self.numberOfLines]; + if (!CGRectContainsPoint(textRect, p)) { + return NSNotFound; + } + + // Offset tap coordinates by textRect origin to make them relative to the origin of frame + p = CGPointMake(p.x - textRect.origin.x, p.y - textRect.origin.y); + // Convert tap coordinates (start at top left) to CT coordinates (start at bottom left) + p = CGPointMake(p.x, textRect.size.height - p.y); + + CGMutablePathRef path = CGPathCreateMutable(); + CGPathAddRect(path, NULL, textRect); + CTFrameRef frame = CTFramesetterCreateFrame(self.framesetter, CFRangeMake(0, [self.attributedText length]), path, NULL); + if (frame == NULL) { + CFRelease(path); + return NSNotFound; + } + + CFArrayRef lines = CTFrameGetLines(frame); + NSInteger numberOfLines = self.numberOfLines > 0 ? MIN(self.numberOfLines, CFArrayGetCount(lines)) : CFArrayGetCount(lines); + if (numberOfLines == 0) { + CFRelease(frame); + CFRelease(path); + return NSNotFound; + } + + NSUInteger idx = NSNotFound; + + CGPoint lineOrigins[numberOfLines]; + CTFrameGetLineOrigins(frame, CFRangeMake(0, numberOfLines), lineOrigins); + + for (CFIndex lineIndex = 0; lineIndex < numberOfLines; lineIndex++) { + CGPoint lineOrigin = lineOrigins[lineIndex]; + CTLineRef line = CFArrayGetValueAtIndex(lines, lineIndex); + + // Get bounding information of line + CGFloat ascent, descent, leading, width; + width = CTLineGetTypographicBounds(line, &ascent, &descent, &leading); + CGFloat yMin = floor(lineOrigin.y - descent); + CGFloat yMax = ceil(lineOrigin.y + ascent); + + // Check if we've already passed the line + if (p.y > yMax) { + break; + } + // Check if the point is within this line vertically + if (p.y >= yMin) { + // Check if the point is within this line horizontally + if (p.x >= lineOrigin.x && p.x <= lineOrigin.x + width) { + // Convert CT coordinates to line-relative coordinates + CGPoint relativePoint = CGPointMake(p.x - lineOrigin.x, p.y - lineOrigin.y); + idx = CTLineGetStringIndexForPosition(line, relativePoint); + break; + } + } + } + + CFRelease(frame); + CFRelease(path); + + return idx; +} + +- (void)drawFramesetter:(CTFramesetterRef)framesetter attributedString:(NSAttributedString *)attributedString textRange:(CFRange)textRange inRect:(CGRect)rect context:(CGContextRef)c { + CGMutablePathRef path = CGPathCreateMutable(); + CGPathAddRect(path, NULL, rect); + CTFrameRef frame = CTFramesetterCreateFrame(framesetter, textRange, path, NULL); + + [self drawBackground:frame inRect:rect context:c]; + + CFArrayRef lines = CTFrameGetLines(frame); + NSInteger numberOfLines = self.numberOfLines > 0 ? MIN(self.numberOfLines, CFArrayGetCount(lines)) : CFArrayGetCount(lines); + BOOL truncateLastLine = (self.lineBreakMode == UILineBreakModeHeadTruncation || self.lineBreakMode == UILineBreakModeMiddleTruncation || self.lineBreakMode == UILineBreakModeTailTruncation); + + CGPoint lineOrigins[numberOfLines]; + CTFrameGetLineOrigins(frame, CFRangeMake(0, numberOfLines), lineOrigins); + + for (CFIndex lineIndex = 0; lineIndex < numberOfLines; lineIndex++) { + CGPoint lineOrigin = lineOrigins[lineIndex]; + CGContextSetTextPosition(c, lineOrigin.x, lineOrigin.y); + CTLineRef line = CFArrayGetValueAtIndex(lines, lineIndex); + + if (lineIndex == numberOfLines - 1 && truncateLastLine) { + // Check if the range of text in the last line reaches the end of the full attributed string + CFRange lastLineRange = CTLineGetStringRange(line); + + if (!(lastLineRange.length == 0 && lastLineRange.location == 0) && lastLineRange.location + lastLineRange.length < textRange.location + textRange.length) { + // Get correct truncationType and attribute position + CTLineTruncationType truncationType; + NSUInteger truncationAttributePosition = lastLineRange.location; + UILineBreakMode lineBreakMode = self.lineBreakMode; + + // Multiple lines, only use UILineBreakModeTailTruncation + if (numberOfLines != 1) { + lineBreakMode = UILineBreakModeTailTruncation; + } + + switch (lineBreakMode) { + case UILineBreakModeHeadTruncation: + truncationType = kCTLineTruncationStart; + break; + case UILineBreakModeMiddleTruncation: + truncationType = kCTLineTruncationMiddle; + truncationAttributePosition += (lastLineRange.length / 2); + break; + case UILineBreakModeTailTruncation: + default: + truncationType = kCTLineTruncationEnd; + truncationAttributePosition += (lastLineRange.length - 1); + break; + } + + // Get the attributes and use them to create the truncation token string + NSDictionary *tokenAttributes = [attributedString attributesAtIndex:truncationAttributePosition effectiveRange:NULL]; + // \u2026 is the Unicode horizontal ellipsis character code + NSAttributedString *tokenString = [[NSAttributedString alloc] initWithString:@"\u2026" attributes:tokenAttributes]; + CTLineRef truncationToken = CTLineCreateWithAttributedString((__bridge CFAttributedStringRef)tokenString); + + // Append truncationToken to the string + // because if string isn't too long, CT wont add the truncationToken on it's own + // There is no change of a double truncationToken because CT only add the token if it removes characters (and the one we add will go first) + NSMutableAttributedString *truncationString = [[attributedString attributedSubstringFromRange:NSMakeRange(lastLineRange.location, lastLineRange.length)] mutableCopy]; + if (lastLineRange.length > 0) { + // Remove any newline at the end (we don't want newline space between the text and the truncation token). There can only be one, because the second would be on the next line. + unichar lastCharacter = [[truncationString string] characterAtIndex:lastLineRange.length - 1]; + if ([[NSCharacterSet newlineCharacterSet] characterIsMember:lastCharacter]) { + [truncationString deleteCharactersInRange:NSMakeRange(lastLineRange.length - 1, 1)]; + } + } + [truncationString appendAttributedString:tokenString]; + CTLineRef truncationLine = CTLineCreateWithAttributedString((__bridge CFAttributedStringRef)truncationString); + + // Truncate the line in case it is too long. + CTLineRef truncatedLine = CTLineCreateTruncatedLine(truncationLine, rect.size.width, truncationType, truncationToken); + if (!truncatedLine) { + // If the line is not as wide as the truncationToken, truncatedLine is NULL + truncatedLine = CFRetain(truncationToken); + } + + CTLineDraw(truncatedLine, c); + + CFRelease(truncatedLine); + CFRelease(truncationLine); + CFRelease(truncationToken); + } else { + CTLineDraw(line, c); + } + } else { + CTLineDraw(line, c); + } + } + + [self drawStrike:frame inRect:rect context:c]; + + CFRelease(frame); + CFRelease(path); +} + +- (void)drawBackground:(CTFrameRef)frame inRect:(CGRect)rect context:(CGContextRef)c { + NSArray *lines = (__bridge NSArray *)CTFrameGetLines(frame); + CGPoint origins[[lines count]]; + CTFrameGetLineOrigins(frame, CFRangeMake(0, 0), origins); + + CFIndex lineIndex = 0; + for (id line in lines) { + CGRect lineBounds = CTLineGetImageBounds((__bridge CTLineRef)line, c); + lineBounds.origin.x = origins[lineIndex].x; + lineBounds.origin.y = origins[lineIndex].y; + + for (id glyphRun in (__bridge NSArray *)CTLineGetGlyphRuns((__bridge CTLineRef)line)) { + NSDictionary *attributes = (__bridge NSDictionary *)CTRunGetAttributes((__bridge CTRunRef) glyphRun); + CGColorRef strokeColor = (__bridge CGColorRef)[attributes objectForKey:kTTTBackgroundStrokeColorAttributeName]; + CGColorRef fillColor = (__bridge CGColorRef)[attributes objectForKey:kTTTBackgroundFillColorAttributeName]; + CGFloat cornerRadius = [[attributes objectForKey:kTTTBackgroundCornerRadiusAttributeName] floatValue]; + CGFloat lineWidth = [[attributes objectForKey:kTTTBackgroundLineWidthAttributeName] floatValue]; + + if (strokeColor || fillColor) { + CGRect runBounds = CGRectZero; + CGFloat ascent = 0.0f; + CGFloat descent = 0.0f; + + runBounds.size.width = CTRunGetTypographicBounds((__bridge CTRunRef)glyphRun, CFRangeMake(0, 0), &ascent, &descent, NULL); + runBounds.size.height = ascent + descent; + + CGFloat xOffset = CTLineGetOffsetForStringIndex((__bridge CTLineRef)line, CTRunGetStringRange((__bridge CTRunRef)glyphRun).location, NULL); + runBounds.origin.x = origins[lineIndex].x + rect.origin.x + xOffset; + runBounds.origin.y = origins[lineIndex].y + rect.origin.y; + runBounds.origin.y -= descent; + + // Don't draw higlightedLinkBackground too far to the right + if (CGRectGetWidth(runBounds) > CGRectGetWidth(lineBounds)) { + runBounds.size.width = CGRectGetWidth(lineBounds); + } + + CGRect rect = CGRectInset(CGRectInset(runBounds, -1.0f, -3.0f), lineWidth, lineWidth); + CGPathRef path = [[UIBezierPath bezierPathWithRoundedRect:rect cornerRadius:cornerRadius] CGPath]; + + CGContextSetLineJoin(c, kCGLineJoinRound); + + if (fillColor) { + CGContextSetFillColorWithColor(c, fillColor); + CGContextAddPath(c, path); + CGContextFillPath(c); + } + + if (strokeColor) { + CGContextSetStrokeColorWithColor(c, strokeColor); + CGContextAddPath(c, path); + CGContextStrokePath(c); + } + } + } + + lineIndex++; + } +} + +- (void)drawStrike:(CTFrameRef)frame inRect:(CGRect)rect context:(CGContextRef)c { + NSArray *lines = (__bridge NSArray *)CTFrameGetLines(frame); + CGPoint origins[[lines count]]; + CTFrameGetLineOrigins(frame, CFRangeMake(0, 0), origins); + + CFIndex lineIndex = 0; + for (id line in lines) { + CGRect lineBounds = CTLineGetImageBounds((__bridge CTLineRef)line, c); + lineBounds.origin.x = origins[lineIndex].x; + lineBounds.origin.y = origins[lineIndex].y; + + for (id glyphRun in (__bridge NSArray *)CTLineGetGlyphRuns((__bridge CTLineRef)line)) { + NSDictionary *attributes = (__bridge NSDictionary *)CTRunGetAttributes((__bridge CTRunRef) glyphRun); + BOOL strikeOut = [[attributes objectForKey:kTTTStrikeOutAttributeName] boolValue]; + NSInteger superscriptStyle = [[attributes objectForKey:(id)kCTSuperscriptAttributeName] integerValue]; + + if (strikeOut) { + CGRect runBounds = CGRectZero; + CGFloat ascent = 0.0f; + CGFloat descent = 0.0f; + + runBounds.size.width = CTRunGetTypographicBounds((__bridge CTRunRef)glyphRun, CFRangeMake(0, 0), &ascent, &descent, NULL); + runBounds.size.height = ascent + descent; + + CGFloat xOffset = CTLineGetOffsetForStringIndex((__bridge CTLineRef)line, CTRunGetStringRange((__bridge CTRunRef)glyphRun).location, NULL); + runBounds.origin.x = origins[lineIndex].x + rect.origin.x + xOffset; + runBounds.origin.y = origins[lineIndex].y + rect.origin.y; + runBounds.origin.y -= descent; + + // Don't draw strikeout too far to the right + if (CGRectGetWidth(runBounds) > CGRectGetWidth(lineBounds)) { + runBounds.size.width = CGRectGetWidth(lineBounds); + } + + switch (superscriptStyle) { + case 1: + runBounds.origin.y -= ascent * 0.47f; + break; + case -1: + runBounds.origin.y += ascent * 0.25f; + break; + default: + break; + } + + // Use text color, or default to black + id color = [attributes objectForKey:(id)kCTForegroundColorAttributeName]; + + if (color) { + CGContextSetStrokeColorWithColor(c, (__bridge CGColorRef)color); + } else { + CGContextSetGrayStrokeColor(c, 0.0f, 1.0); + } + + CTFontRef font = CTFontCreateWithName((__bridge CFStringRef)self.font.fontName, self.font.pointSize, NULL); + CGContextSetLineWidth(c, CTFontGetUnderlineThickness(font)); + CGFloat y = roundf(runBounds.origin.y + runBounds.size.height / 2.0f); + CGContextMoveToPoint(c, runBounds.origin.x, y); + CGContextAddLineToPoint(c, runBounds.origin.x + runBounds.size.width, y); + + CGContextStrokePath(c); + } + } + + lineIndex++; + } +} + +#pragma mark - TTTAttributedLabel + +- (void)setText:(id)text { + if ([text isKindOfClass:[NSString class]]) { + [self setText:text afterInheritingLabelAttributesAndConfiguringWithBlock:nil]; + return; + } + + self.attributedText = text; + + self.links = [NSArray array]; + if (self.dataDetectorTypes != UIDataDetectorTypeNone) { + for (NSTextCheckingResult *result in [self detectedLinksInString:[self.attributedText string] range:NSMakeRange(0, [text length]) error:nil]) { + [self addLinkWithTextCheckingResult:result]; + } + } + + [super setText:[self.attributedText string]]; +} + +- (void)setText:(id)text afterInheritingLabelAttributesAndConfiguringWithBlock:(NSMutableAttributedString *(^)(NSMutableAttributedString *mutableAttributedString))block { + NSMutableAttributedString *mutableAttributedString = nil; + if ([text isKindOfClass:[NSString class]]) { + mutableAttributedString = [[NSMutableAttributedString alloc] initWithString:text attributes:NSAttributedStringAttributesFromLabel(self)]; + } else { + mutableAttributedString = [[NSMutableAttributedString alloc] initWithAttributedString:text]; + [mutableAttributedString addAttributes:NSAttributedStringAttributesFromLabel(self) range:NSMakeRange(0, [mutableAttributedString length])]; + } + + if (block) { + mutableAttributedString = block(mutableAttributedString); + } + + [self setText:mutableAttributedString]; +} + +#pragma mark - UILabel + +- (void)setHighlighted:(BOOL)highlighted { + [super setHighlighted:highlighted]; + [self setNeedsDisplay]; +} + +// Fixes crash when loading from a UIStoryboard +- (UIColor *)textColor { + UIColor *color = [super textColor]; + if (!color) { + color = [UIColor blackColor]; + } + + return color; +} + +- (void)setTextColor:(UIColor *)textColor { + UIColor *oldTextColor = self.textColor; + [super setTextColor:textColor]; + + // Redraw to allow any ColorFromContext attributes a chance to update + if (textColor != oldTextColor) { + [self setNeedsFramesetter]; + [self setNeedsDisplay]; + } +} + +- (CGRect)textRectForBounds:(CGRect)bounds limitedToNumberOfLines:(NSInteger)numberOfLines { + if (!self.attributedText) { + return [super textRectForBounds:bounds limitedToNumberOfLines:numberOfLines]; + } + + CGRect textRect = bounds; + + // Adjust the text to be in the center vertically, if the text size is smaller than bounds + CGSize textSize = CTFramesetterSuggestFrameSizeWithConstraints(self.framesetter, CFRangeMake(0, [self.attributedText length]), NULL, bounds.size, NULL); + textSize = CGSizeMake(ceilf(textSize.width), ceilf(textSize.height)); // Fix for iOS 4, CTFramesetterSuggestFrameSizeWithConstraints sometimes returns fractional sizes + + if (textSize.height < textRect.size.height) { + CGFloat heightChange = (textRect.size.height - textSize.height); + CGFloat yOffset = 0.0f; + switch (self.verticalAlignment) { + case BITAttributedLabelVerticalAlignmentTop: + heightChange = 0.0f; + break; + case BITAttributedLabelVerticalAlignmentCenter: + yOffset = floorf((textRect.size.height - textSize.height) / 2.0f); + break; + case BITAttributedLabelVerticalAlignmentBottom: + yOffset = textRect.size.height - textSize.height; + break; + } + + textRect.origin.y += yOffset; + textRect.size = CGSizeMake(textRect.size.width, textRect.size.height - heightChange + yOffset); + } + + return textRect; +} + +- (void)drawTextInRect:(CGRect)rect { + if (!self.attributedText) { + [super drawTextInRect:rect]; + return; + } + + NSAttributedString *originalAttributedText = nil; + + // Adjust the font size to fit width, if necessarry + if (self.adjustsFontSizeToFitWidth && self.numberOfLines > 0) { + CGFloat textWidth = [self sizeThatFits:CGSizeZero].width; + CGFloat availableWidth = self.frame.size.width * self.numberOfLines; + if (self.numberOfLines > 1 && self.lineBreakMode == UILineBreakModeWordWrap) { + textWidth *= kTTTLineBreakWordWrapTextWidthScalingFactor; + } + + if (textWidth > availableWidth && textWidth > 0.0f) { + originalAttributedText = [self.attributedText copy]; + self.text = NSAttributedStringByScalingFontSize(self.attributedText, availableWidth / textWidth, self.minimumFontSize); + } + } + + CGContextRef c = UIGraphicsGetCurrentContext(); + CGContextSetTextMatrix(c, CGAffineTransformIdentity); + + // Inverts the CTM to match iOS coordinates (otherwise text draws upside-down; Mac OS's system is different) + CGContextTranslateCTM(c, 0.0f, rect.size.height); + CGContextScaleCTM(c, 1.0f, -1.0f); + + CFRange textRange = CFRangeMake(0, [self.attributedText length]); + + // First, get the text rect (which takes vertical centering into account) + CGRect textRect = [self textRectForBounds:rect limitedToNumberOfLines:self.numberOfLines]; + + // CoreText draws it's text aligned to the bottom, so we move the CTM here to take our vertical offsets into account + CGContextTranslateCTM(c, 0.0f, rect.size.height - textRect.origin.y - textRect.size.height); + + // Second, trace the shadow before the actual text, if we have one + if (self.shadowColor && !self.highlighted) { + CGContextSetShadowWithColor(c, self.shadowOffset, self.shadowRadius, [self.shadowColor CGColor]); + } + + // Finally, draw the text or highlighted text itself (on top of the shadow, if there is one) + if (self.highlightedTextColor && self.highlighted) { + NSMutableAttributedString *highlightAttributedString = [self.renderedAttributedText mutableCopy]; + [highlightAttributedString addAttribute:(NSString *)kCTForegroundColorAttributeName value:(id)[self.highlightedTextColor CGColor] range:NSMakeRange(0, highlightAttributedString.length)]; + + if (!self.highlightFramesetter) { + self.highlightFramesetter = CTFramesetterCreateWithAttributedString((__bridge CFAttributedStringRef)highlightAttributedString); + } + + [self drawFramesetter:self.highlightFramesetter attributedString:highlightAttributedString textRange:textRange inRect:textRect context:c]; + } else { + [self drawFramesetter:self.framesetter attributedString:self.renderedAttributedText textRange:textRange inRect:textRect context:c]; + } + + // If we adjusted the font size, set it back to its original size + if (originalAttributedText) { + self.text = originalAttributedText; + } +} + +#pragma mark - UIView + +- (CGSize)sizeThatFits:(CGSize)size { + if (!self.attributedText) { + return [super sizeThatFits:size]; + } + + CFRange rangeToSize = CFRangeMake(0, [self.attributedText length]); + CGSize constraints = CGSizeMake(size.width, CGFLOAT_MAX); + + if (self.numberOfLines == 1) { + // If there is one line, the size that fits is the full width of the line + constraints = CGSizeMake(CGFLOAT_MAX, CGFLOAT_MAX); + } else if (self.numberOfLines > 0) { + // If the line count of the label more than 1, limit the range to size to the number of lines that have been set + CGMutablePathRef path = CGPathCreateMutable(); + CGPathAddRect(path, NULL, CGRectMake(0.0f, 0.0f, constraints.width, CGFLOAT_MAX)); + CTFrameRef frame = CTFramesetterCreateFrame(self.framesetter, CFRangeMake(0, 0), path, NULL); + CFArrayRef lines = CTFrameGetLines(frame); + + if (CFArrayGetCount(lines) > 0) { + NSInteger lastVisibleLineIndex = MIN(self.numberOfLines, CFArrayGetCount(lines)) - 1; + CTLineRef lastVisibleLine = CFArrayGetValueAtIndex(lines, lastVisibleLineIndex); + + CFRange rangeToLayout = CTLineGetStringRange(lastVisibleLine); + rangeToSize = CFRangeMake(0, rangeToLayout.location + rangeToLayout.length); + } + + CFRelease(frame); + CFRelease(path); + } + + CGSize suggestedSize = CTFramesetterSuggestFrameSizeWithConstraints(self.framesetter, rangeToSize, NULL, constraints, NULL); + + return CGSizeMake(ceilf(suggestedSize.width), ceilf(suggestedSize.height)); +} + +#pragma mark - UIResponder + +- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event { + UITouch *touch = [touches anyObject]; + + self.activeLink = [self linkAtPoint:[touch locationInView:self]]; + + if (self.activeLink) { + [self setLinkActive:YES withTextCheckingResult:self.activeLink]; + } else { + [super touchesBegan:touches withEvent:event]; + } +} + +- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event { + if (self.activeLink) { + UITouch *touch = [touches anyObject]; + + if (self.activeLink != [self linkAtPoint:[touch locationInView:self]]) { + [self setLinkActive:NO withTextCheckingResult:self.activeLink]; + } else { + [self setLinkActive:YES withTextCheckingResult:self.activeLink]; + } + } else { + [super touchesMoved:touches withEvent:event]; + } +} + +- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event { + if (self.activeLink) { + UITouch *touch = [touches anyObject]; + if (self.activeLink == [self linkAtPoint:[touch locationInView:self]]) { + [self setLinkActive:NO withTextCheckingResult:self.activeLink]; + + if (!self.delegate) { + return; + } + + NSTextCheckingResult *result = self.activeLink; + switch (result.resultType) { + case NSTextCheckingTypeLink: + if ([self.delegate respondsToSelector:@selector(attributedLabel:didSelectLinkWithURL:)]) { + [self.delegate attributedLabel:self didSelectLinkWithURL:result.URL]; + return; + } + break; + case NSTextCheckingTypeAddress: + if ([self.delegate respondsToSelector:@selector(attributedLabel:didSelectLinkWithAddress:)]) { + [self.delegate attributedLabel:self didSelectLinkWithAddress:result.addressComponents]; + return; + } + break; + case NSTextCheckingTypePhoneNumber: + if ([self.delegate respondsToSelector:@selector(attributedLabel:didSelectLinkWithPhoneNumber:)]) { + [self.delegate attributedLabel:self didSelectLinkWithPhoneNumber:result.phoneNumber]; + return; + } + break; + case NSTextCheckingTypeDate: + if (result.timeZone && [self.delegate respondsToSelector:@selector(attributedLabel:didSelectLinkWithDate:timeZone:duration:)]) { + [self.delegate attributedLabel:self didSelectLinkWithDate:result.date timeZone:result.timeZone duration:result.duration]; + return; + } else if ([self.delegate respondsToSelector:@selector(attributedLabel:didSelectLinkWithDate:)]) { + [self.delegate attributedLabel:self didSelectLinkWithDate:result.date]; + return; + } + break; + default: + break; + } + + // Fallback to `attributedLabel:didSelectLinkWithTextCheckingResult:` if no other delegate method matched. + if ([self.delegate respondsToSelector:@selector(attributedLabel:didSelectLinkWithTextCheckingResult:)]) { + [self.delegate attributedLabel:self didSelectLinkWithTextCheckingResult:result]; + } + } + } else { + [super touchesEnded:touches withEvent:event]; + } +} + +- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event { + if (self.activeLink) { + [self setLinkActive:NO withTextCheckingResult:self.activeLink]; + } else { + [super touchesCancelled:touches withEvent:event]; + } +} + +@end + +#pragma clang diagnostic pop diff --git a/LICENSE b/LICENSE index 4cc0bf4e..fe73ef79 100755 --- a/LICENSE +++ b/LICENSE @@ -2,21 +2,21 @@ The Hockey SDK is provided under the following license: - The MIT License - Copyright (c) 2012 HockeyApp, Bit Stadium GmbH. - All rights reserved. - - Permission is hereby granted, free of charge, to any person - obtaining a copy of this software and associated documentation - files (the "Software"), to deal in the Software without - restriction, including without limitation the rights to use, - copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the - Software is furnished to do so, subject to the following - conditions: + The MIT License + Copyright (c) 2012 HockeyApp, Bit Stadium GmbH. + All rights reserved. - The above copyright notice and this permission notice shall be - included in all copies or substantial portions of the Software. + Permission is hereby granted, free of charge, to any person + obtaining a copy of this software and associated documentation + files (the "Software"), to deal in the Software without + restriction, including without limitation the rights to use, + copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following + conditions: + + The above copyright notice and this permission notice shall be + included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES @@ -70,3 +70,28 @@ file are licensed as follows: KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. + +TTTAttributedLabel is licensed as follows: + + Copyright (c) 2011 Mattt Thompson (http://mattt.me/) + + Permission is hereby granted, free of charge, to any person + obtaining a copy of this software and associated documentation + files (the "Software"), to deal in the Software without + restriction, including without limitation the rights to use, + copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following + conditions: + + The above copyright notice and this permission notice shall be + included in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + OTHER DEALINGS IN THE SOFTWARE. diff --git a/Support/HockeySDK.xcconfig b/Support/HockeySDK.xcconfig index b29ea326..4b4654c4 100644 --- a/Support/HockeySDK.xcconfig +++ b/Support/HockeySDK.xcconfig @@ -1,3 +1,3 @@ -OTHER_LDFLAGS=$(inherited) -ObjC -framework CoreGraphics -framework Foundation -framework QuartzCore -framework SystemConfiguration -weak_framework AdSupport -weak_framework UIKit +OTHER_LDFLAGS=$(inherited) -ObjC -framework CoreText -framework CoreGraphics -framework Foundation -framework QuartzCore -framework SystemConfiguration -weak_framework AdSupport -weak_framework UIKit HOCKEYSDK_DOCSET_NAME=HockeySDK-iOS GCC_PREPROCESSOR_DEFINITIONS=$(inherited) CONFIGURATION_$(CONFIGURATION) \ No newline at end of file diff --git a/Support/HockeySDK.xcodeproj/project.pbxproj b/Support/HockeySDK.xcodeproj/project.pbxproj index bf8e4b69..5f123a9e 100644 --- a/Support/HockeySDK.xcodeproj/project.pbxproj +++ b/Support/HockeySDK.xcodeproj/project.pbxproj @@ -92,6 +92,8 @@ 1E754E5F1621FBB70070AB92 /* BITCrashManagerPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E754E591621FBB70070AB92 /* BITCrashManagerPrivate.h */; }; 1E754E601621FBB70070AB92 /* BITCrashReportTextFormatter.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E754E5A1621FBB70070AB92 /* BITCrashReportTextFormatter.h */; }; 1E754E611621FBB70070AB92 /* BITCrashReportTextFormatter.m in Sources */ = {isa = PBXBuildFile; fileRef = 1E754E5B1621FBB70070AB92 /* BITCrashReportTextFormatter.m */; }; + 1EACC97B162F041E007578C5 /* BITAttributedLabel.h in Headers */ = {isa = PBXBuildFile; fileRef = 1EACC979162F041E007578C5 /* BITAttributedLabel.h */; }; + 1EACC97C162F041E007578C5 /* BITAttributedLabel.m in Sources */ = {isa = PBXBuildFile; fileRef = 1EACC97A162F041E007578C5 /* BITAttributedLabel.m */; settings = {COMPILER_FLAGS = "-fobjc-arc"; }; }; 1EAF20A8162DC0F600957B1D /* feedbackActivity@2x~ipad.png in Resources */ = {isa = PBXBuildFile; fileRef = 1EAF20A4162DC0F600957B1D /* feedbackActivity@2x~ipad.png */; }; 1EAF20A9162DC0F600957B1D /* feedbackActivity~ipad.png in Resources */ = {isa = PBXBuildFile; fileRef = 1EAF20A5162DC0F600957B1D /* feedbackActivity~ipad.png */; }; 1EAF20AA162DC0F600957B1D /* feedbackActiviy.png in Resources */ = {isa = PBXBuildFile; fileRef = 1EAF20A6162DC0F600957B1D /* feedbackActiviy.png */; }; @@ -192,6 +194,8 @@ 1E754E591621FBB70070AB92 /* BITCrashManagerPrivate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BITCrashManagerPrivate.h; sourceTree = ""; }; 1E754E5A1621FBB70070AB92 /* BITCrashReportTextFormatter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BITCrashReportTextFormatter.h; sourceTree = ""; }; 1E754E5B1621FBB70070AB92 /* BITCrashReportTextFormatter.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = BITCrashReportTextFormatter.m; sourceTree = ""; }; + 1EACC979162F041E007578C5 /* BITAttributedLabel.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BITAttributedLabel.h; sourceTree = ""; }; + 1EACC97A162F041E007578C5 /* BITAttributedLabel.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = BITAttributedLabel.m; sourceTree = ""; }; 1EAF20A4162DC0F600957B1D /* feedbackActivity@2x~ipad.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "feedbackActivity@2x~ipad.png"; sourceTree = ""; }; 1EAF20A5162DC0F600957B1D /* feedbackActivity~ipad.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "feedbackActivity~ipad.png"; sourceTree = ""; }; 1EAF20A6162DC0F600957B1D /* feedbackActiviy.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = feedbackActiviy.png; sourceTree = ""; }; @@ -268,6 +272,8 @@ 1E49A4A4161222B900463151 /* BITHockeyBaseViewController.m */, 1E49A4A5161222B900463151 /* BITHockeyHelper.h */, 1E49A4A6161222B900463151 /* BITHockeyHelper.m */, + 1EACC979162F041E007578C5 /* BITAttributedLabel.h */, + 1EACC97A162F041E007578C5 /* BITAttributedLabel.m */, 1E49A4A7161222B900463151 /* PSAppStoreHeader.h */, 1E49A4A8161222B900463151 /* PSAppStoreHeader.m */, 1E49A4A9161222B900463151 /* PSStoreButton.h */, @@ -433,6 +439,7 @@ 1E754E5E1621FBB70070AB92 /* BITCrashManagerDelegate.h in Headers */, 1E754E5F1621FBB70070AB92 /* BITCrashManagerPrivate.h in Headers */, 1E754E601621FBB70070AB92 /* BITCrashReportTextFormatter.h in Headers */, + 1EACC97B162F041E007578C5 /* BITAttributedLabel.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -596,6 +603,7 @@ 1E754E5D1621FBB70070AB92 /* BITCrashManager.m in Sources */, 1E754E611621FBB70070AB92 /* BITCrashReportTextFormatter.m in Sources */, 1EF95CA7162CB037000AE3AD /* BITFeedbackActivity.m in Sources */, + 1EACC97C162F041E007578C5 /* BITAttributedLabel.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; From dc654a0a3f61c4c639b56ece71b8f984edf6df78 Mon Sep 17 00:00:00 2001 From: Andreas Linde Date: Wed, 17 Oct 2012 19:20:07 +0200 Subject: [PATCH 051/176] Adjusting the feedback UI to use BITAttributedLabel and fix some bugs --- Classes/BITFeedbackListViewCell.h | 17 ++--- Classes/BITFeedbackListViewCell.m | 46 ++++++------ Classes/BITFeedbackListViewController.m | 96 ++++++++++++++++--------- Classes/BITFeedbackManager.m | 1 + Classes/BITFeedbackMessage.m | 2 +- Resources/de.lproj/HockeySDK.strings | 17 +++-- Resources/en.lproj/HockeySDK.strings | 16 +++-- Resources/es.lproj/HockeySDK.strings | 16 +++-- Resources/fr.lproj/HockeySDK.strings | 16 +++-- Resources/it.lproj/HockeySDK.strings | 16 +++-- Resources/ja.lproj/HockeySDK.strings | 16 +++-- Resources/nl.lproj/HockeySDK.strings | 16 +++-- Resources/pt-PT.lproj/HockeySDK.strings | 16 +++-- Resources/pt.lproj/HockeySDK.strings | 16 +++-- Resources/ru.lproj/HockeySDK.strings | 16 +++-- Resources/sv.lproj/HockeySDK.strings | 16 +++-- Resources/tr.lproj/HockeySDK.strings | 16 +++-- Resources/zh_CN.lproj/HockeySDK.strings | 16 +++-- Resources/zh_TW.lproj/HockeySDK.strings | 16 +++-- 19 files changed, 217 insertions(+), 170 deletions(-) diff --git a/Classes/BITFeedbackListViewCell.h b/Classes/BITFeedbackListViewCell.h index daf09b4c..64e4e693 100644 --- a/Classes/BITFeedbackListViewCell.h +++ b/Classes/BITFeedbackListViewCell.h @@ -28,11 +28,8 @@ #import - -typedef enum { - BITFeedbackListViewCellStyleNormal = 0, // right aligned header style - BITFeedbackListViewCellStyleRepsonse = 1 // left aligned header style for dev responses -} BITFeedbackListViewCellStyle; +#import "BITFeedbackMessage.h" +#import "BITAttributedLabel.h" typedef enum { BITFeedbackListViewCellBackgroundStyleNormal = 0, @@ -41,14 +38,12 @@ typedef enum { @interface BITFeedbackListViewCell : UITableViewCell -@property (nonatomic) BITFeedbackListViewCellStyle style; +@property (nonatomic, retain) BITFeedbackMessage *message; + @property (nonatomic) BITFeedbackListViewCellBackgroundStyle backgroundStyle; -@property (nonatomic) BOOL sent; -@property (nonatomic, copy) NSDate *date; -@property (nonatomic, copy) NSString *name; -@property (nonatomic, copy) NSString *text; +@property (nonatomic, retain) BITAttributedLabel *labelText; -+ (CGFloat) heightForRowWithText:(NSString *)text tableViewWidth:(CGFloat)width; ++ (CGFloat) heightForRowWithMessage:(BITFeedbackMessage *)message tableViewWidth:(CGFloat)width; @end diff --git a/Classes/BITFeedbackListViewCell.m b/Classes/BITFeedbackListViewCell.m index 12f5062e..51750e91 100644 --- a/Classes/BITFeedbackListViewCell.m +++ b/Classes/BITFeedbackListViewCell.m @@ -57,7 +57,6 @@ @interface BITFeedbackListViewCell () @property (nonatomic, retain) NSDateFormatter *timeFormatter; @property (nonatomic, retain) UILabel *labelTitle; -@property (nonatomic, retain) UILabel *labelText; @end @@ -69,13 +68,9 @@ - (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reus self = [super initWithStyle:style reuseIdentifier:reuseIdentifier]; if (self) { // Initialization code - _style = BITFeedbackListViewCellStyleNormal; _backgroundStyle = BITFeedbackListViewCellBackgroundStyleNormal; - _sent = YES; - _date = nil; - _name = nil; - _text = nil; + _message = nil; self.dateFormatter = [[[NSDateFormatter alloc] init] autorelease]; [self.dateFormatter setTimeStyle:NSDateFormatterNoStyle]; @@ -92,10 +87,11 @@ - (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reus self.labelTitle = [[[UILabel alloc] init] autorelease]; self.labelTitle.font = [UIFont systemFontOfSize:TITLE_FONTSIZE]; - self.labelText = [[[UILabel alloc] init] autorelease]; + self.labelText = [[[BITAttributedLabel alloc] init] autorelease]; self.labelText.font = [UIFont systemFontOfSize:TEXT_FONTSIZE]; self.labelText.numberOfLines = 0; self.labelText.textAlignment = UITextAlignmentLeft; + self.labelText.dataDetectorTypes = UIDataDetectorTypeAll; } return self; } @@ -107,9 +103,7 @@ - (void)dealloc { [_labelTitle release], _labelTitle = nil; [_labelText release], _labelText = nil; - [_date release], _date = nil; - [_name release], _name = nil; - [_text release], _text = nil; + [_message release], _message = nil; [super dealloc]; } @@ -132,15 +126,15 @@ - (BOOL)isSameDayWithDate1:(NSDate*)date1 date2:(NSDate*)date2 { #pragma mark - Layout -+ (CGFloat) heightForRowWithText:(NSString *)text tableViewWidth:(CGFloat)width { - CGFloat calculatedHeight = [text sizeWithFont:[UIFont systemFontOfSize:TEXT_FONTSIZE] ++ (CGFloat) heightForRowWithMessage:(BITFeedbackMessage *)message tableViewWidth:(CGFloat)width { + CGFloat calculatedHeight = [message.text sizeWithFont:[UIFont systemFontOfSize:TEXT_FONTSIZE] constrainedToSize:CGSizeMake(width - (2 * FRAME_SIDE_BORDER), CGFLOAT_MAX)].height + FRAME_TOP_BORDER + LABEL_TEXT_Y + FRAME_BOTTOM_BORDER; return calculatedHeight; } - (void)layoutSubviews { UIView *accessoryViewBackground = [[[UIView alloc] initWithFrame:CGRectMake(0, 2, self.frame.size.width * 2, self.frame.size.height - 2)] autorelease]; - + // colors if (_backgroundStyle == BITFeedbackListViewCellBackgroundStyleNormal) { accessoryViewBackground.backgroundColor = BACKGROUNDCOLOR_DEFAULT; @@ -154,30 +148,30 @@ - (void)layoutSubviews { self.labelText.backgroundColor = BACKGROUNDCOLOR_ALTERNATE; } self.labelTitle.textColor = TEXTCOLOR_TITLE; - if (self.sent) { - [self.labelText setTextColor:TEXTCOLOR_DEFAULT]; - } else { + if (_message.status == BITFeedbackMessageStatusSendPending || _message.status == BITFeedbackMessageStatusSendInProgress) { [self.labelText setTextColor:TEXTCOLOR_PENDING]; + } else { + [self.labelText setTextColor:TEXTCOLOR_DEFAULT]; } // background for deletion accessory view [self addSubview:accessoryViewBackground]; - + // header NSString *dateString; - if (self.date) { - if ([self isSameDayWithDate1:[NSDate date] date2:self.date]) { - dateString = [self.timeFormatter stringFromDate:self.date]; + if (_message.status == BITFeedbackMessageStatusSendPending || _message.status == BITFeedbackMessageStatusSendInProgress) { + dateString = BITHockeyLocalizedString(@"Pending"); + } else { + if ([self isSameDayWithDate1:[NSDate date] date2:_message.date]) { + dateString = [self.timeFormatter stringFromDate:_message.date]; } else { - dateString = [self.dateFormatter stringFromDate:self.date]; + dateString = [self.dateFormatter stringFromDate:_message.date]; } - } else { - dateString = BITHockeyLocalizedString(@"Pending"); } [self.labelTitle setText:dateString];// [self.date description]]; [self.labelTitle setFrame:CGRectMake(FRAME_SIDE_BORDER, FRAME_TOP_BORDER + LABEL_TITLE_Y, self.frame.size.width - (2 * FRAME_SIDE_BORDER), LABEL_TITLE_HEIGHT)]; - if (_style == BITFeedbackListViewCellStyleNormal) { + if (_message.userMessage) { self.labelTitle.textAlignment = UITextAlignmentRight; self.labelText.textAlignment = UITextAlignmentRight; } else { @@ -188,9 +182,9 @@ - (void)layoutSubviews { [self addSubview:self.labelTitle]; // text - [self.labelText setText:self.text]; + [self.labelText setText:_message.text]; CGSize size = CGSizeMake(self.frame.size.width - (2 * FRAME_SIDE_BORDER), - [[self class] heightForRowWithText:self.text tableViewWidth:self.frame.size.width] - LABEL_TEXT_Y - FRAME_BOTTOM_BORDER); + [[self class] heightForRowWithMessage:_message tableViewWidth:self.frame.size.width] - LABEL_TEXT_Y - FRAME_BOTTOM_BORDER); [self.labelText setFrame:CGRectMake(FRAME_SIDE_BORDER, LABEL_TEXT_Y, size.width, size.height)]; diff --git a/Classes/BITFeedbackListViewController.m b/Classes/BITFeedbackListViewController.m index fc923205..5a1bf786 100644 --- a/Classes/BITFeedbackListViewController.m +++ b/Classes/BITFeedbackListViewController.m @@ -36,6 +36,7 @@ #import "BITFeedbackComposeViewController.h" #import "BITFeedbackUserDataViewController.h" #import "BITFeedbackMessage.h" +#import "BITAttributedLabel.h" #import "BITHockeyHelper.h" #import @@ -54,7 +55,7 @@ #define BORDER_COLOR2 BIT_RGBCOLOR(221, 221, 221) #define BORDER_COLOR3 BIT_RGBCOLOR(255, 255, 255) -@interface BITFeedbackListViewController () +@interface BITFeedbackListViewController () @property (nonatomic, assign) BITFeedbackManager *manager; @property (nonatomic, retain) NSDateFormatter *lastUpdateDateFormatter; @@ -217,6 +218,7 @@ - (void)deleteAllMessagesAction:(id)sender { destructiveButtonTitle:BITHockeyLocalizedString(@"HockeyFeedbackListDeleteAllDelete") otherButtonTitles:nil ]; + [deleteAction setTag:0]; [deleteAction setActionSheetStyle:UIActionSheetStyleBlackTranslucent]; [deleteAction showInView:self.view]; [deleteAction release]; @@ -227,9 +229,9 @@ - (void)deleteAllMessagesAction:(id)sender { cancelButtonTitle:BITHockeyLocalizedString(@"HockeyFeedbackListDeleteAllCancel") otherButtonTitles:BITHockeyLocalizedString(@"HockeyFeedbackListDeleteAllDelete"), nil]; + [deleteAction setTag:0]; [deleteAction show]; [deleteAction release]; - } } @@ -316,7 +318,7 @@ - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(N cell.textLabel.numberOfLines = 0; cell.accessoryType = UITableViewCellAccessoryNone; cell.selectionStyle = UITableViewCellSelectionStyleNone; - + // button UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom]; [button.layer setMasksToBounds:YES]; @@ -413,31 +415,9 @@ - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(N } BITFeedbackMessage *message = [self.manager messageAtIndex:indexPath.row]; - cell.date = message.date; - - if (message.userMessage) { - cell.style = BITFeedbackListViewCellStyleNormal; - if ([self.manager requireUserName] == BITFeedbackUserDataElementRequired || - ([self.manager requireUserName] == BITFeedbackUserDataElementOptional && [self.manager userName] != nil) - ) { - cell.name = [self.manager userName]; - } else { - cell.name = BITHockeyLocalizedString(@"HockeyFeedbackListMessageUserNameNotSet"); - } - } else { - cell.style = BITFeedbackListViewCellStyleRepsonse; - if (message.name && [message.name length] > 0) { - cell.name = message.name; - } else { - cell.name = BITHockeyLocalizedString(@"HockeyFeedbackListMessageResponseNameNotSet"); - } - } - - if (message.text) { - cell.text = message.text; - } else { - cell.text = @""; - } + cell.message = message; + cell.labelText.delegate = self; + cell.labelText.userInteractionEnabled = YES; UIView *lineView1 = [[[UIView alloc] initWithFrame:CGRectMake(0, 0, cell.contentView.bounds.size.width, 1)] autorelease]; lineView1.backgroundColor = BORDER_COLOR1; @@ -468,8 +448,13 @@ - (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *) - (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath { if (editingStyle == UITableViewCellEditingStyleDelete) { + NSLog(@"%i %i", indexPath.section, indexPath.row); if ([_manager deleteMessageAtIndex:indexPath.row]) { - [tableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationAutomatic]; + if ([_manager numberOfMessages] > 0) { + [tableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationAutomatic]; + } else { + [tableView reloadData]; + } } } } @@ -488,15 +473,23 @@ - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPa BITFeedbackMessage *message = [self.manager messageAtIndex:indexPath.row]; if (!message) return 44; - return [BITFeedbackListViewCell heightForRowWithText:message.text tableViewWidth:self.view.frame.size.width]; + return [BITFeedbackListViewCell heightForRowWithMessage:message tableViewWidth:self.view.frame.size.width]; } #pragma mark - UIAlertViewDelegate - (void)alertView:(UIAlertView *)alertView didDismissWithButtonIndex:(NSInteger)buttonIndex { - if (buttonIndex == [alertView firstOtherButtonIndex]) { - [self deleteAllMessages]; + if (buttonIndex == alertView.cancelButtonIndex) { + return; + } + + if ([alertView tag] == 0) { + if (buttonIndex == [alertView firstOtherButtonIndex]) { + [self deleteAllMessages]; + } + } else { + [[UIApplication sharedApplication] openURL:[NSURL URLWithString:alertView.title]]; } } @@ -504,10 +497,45 @@ - (void)alertView:(UIAlertView *)alertView didDismissWithButtonIndex:(NSInteger) #pragma mark - UIActionSheetDelegate - (void)actionSheet:(UIActionSheet *)actionSheet didDismissWithButtonIndex:(NSInteger)buttonIndex { - if (buttonIndex == [actionSheet destructiveButtonIndex]) { - [self deleteAllMessages]; + if (buttonIndex == actionSheet.cancelButtonIndex) { + return; + } + + if ([actionSheet tag] == 0) { + if (buttonIndex == [actionSheet destructiveButtonIndex]) { + [self deleteAllMessages]; + } + } else { + [[UIApplication sharedApplication] openURL:[NSURL URLWithString:actionSheet.title]]; } } +#pragma mark - BITAttributedLabelDelegate + +- (void)attributedLabel:(BITAttributedLabel *)label didSelectLinkWithURL:(NSURL *)url { + if (UI_USER_INTERFACE_IDIOM() != UIUserInterfaceIdiomPad) { + UIActionSheet *linkAction = [[UIActionSheet alloc] initWithTitle:[url absoluteString] + delegate:self + cancelButtonTitle:BITHockeyLocalizedString(@"HockeyFeedbackListCancelOpenLink") + destructiveButtonTitle:nil + otherButtonTitles:BITHockeyLocalizedString(@"HockeyFeedbackListOpenLinkInSafari"), nil + ]; + [linkAction setTag:1]; + [linkAction setActionSheetStyle:UIActionSheetStyleBlackTranslucent]; + [linkAction showInView:self.view]; + [linkAction release]; + } else { + UIAlertView *linkAction = [[UIAlertView alloc] initWithTitle:[url absoluteString] + message:nil + delegate:self + cancelButtonTitle:BITHockeyLocalizedString(@"HockeyFeedbackListCancelOpenLink") + otherButtonTitles:BITHockeyLocalizedString(@"HockeyFeedbackListOpenLinkInSafari"), nil]; + + [linkAction setTag:1]; + [linkAction show]; + [linkAction release]; + } +} + @end diff --git a/Classes/BITFeedbackManager.m b/Classes/BITFeedbackManager.m index c8803bd9..74223a6c 100644 --- a/Classes/BITFeedbackManager.m +++ b/Classes/BITFeedbackManager.m @@ -799,6 +799,7 @@ - (void)submitPendingMessages { // app defined user data may have changed, update it [self updateAppDefinedUserData]; + [self saveMessages]; NSArray *pendingMessages = [self messagesWithStatus:BITFeedbackMessageStatusSendPending]; diff --git a/Classes/BITFeedbackMessage.m b/Classes/BITFeedbackMessage.m index 10870279..8fca1d70 100644 --- a/Classes/BITFeedbackMessage.m +++ b/Classes/BITFeedbackMessage.m @@ -39,7 +39,7 @@ - (id) init { _text = nil; _name = nil; _email = nil; - _date = nil; + _date = [[NSDate alloc] init]; _token = nil; _id = [[NSNumber alloc] initWithInteger:0]; _status = BITFeedbackMessageStatusSendPending; diff --git a/Resources/de.lproj/HockeySDK.strings b/Resources/de.lproj/HockeySDK.strings index 10752150..ca8120c9 100755 --- a/Resources/de.lproj/HockeySDK.strings +++ b/Resources/de.lproj/HockeySDK.strings @@ -161,17 +161,11 @@ /* Button title for deleting all local messages*/ "HockeyFeedbackListButonDeleteAllMessages" = "Delete All Messages"; -/* User Name In Message If Name Not Set */ -"HockeyFeedbackListMessageUserNameNotSet" = "You"; - -/* Name In Message From Server If Name Not Set */ -"HockeyFeedbackListMessageResponseNameNotSet" = "Response"; - /* Message pending to be send */ "HockeyFeedbackListMessagePending" = "Pending"; -/* Delete All Messages Action Sheet */ +/* Delete All Messages Action Sheet / Alert View */ /* Title for the Action Sheet */ "HockeyFeedbackListDeleteAllTitle" = "This will delete all messages on this device."; @@ -183,6 +177,15 @@ "HockeyFeedbackListDeleteAllCancel" = "Cancel"; +/* Open Link In Safari Action Sheet / Alert View */ + +/* Title for the Action Sheet */ +"HockeyFeedbackListCancelOpenLink" = "Cancel"; + +/* Title for the Action Sheet */ +"HockeyFeedbackListOpenLinkInSafari" = "Open Link in Safari"; + + /* UIActivity */ /* Activity Sharing Button Title, App Name will be inserted */ diff --git a/Resources/en.lproj/HockeySDK.strings b/Resources/en.lproj/HockeySDK.strings index 5d8d491e..000f7525 100755 --- a/Resources/en.lproj/HockeySDK.strings +++ b/Resources/en.lproj/HockeySDK.strings @@ -158,17 +158,11 @@ /* Button title for deleting all local messages*/ "HockeyFeedbackListButonDeleteAllMessages" = "Delete All Messages"; -/* User Name In Message If Name Not Set */ -"HockeyFeedbackListMessageUserNameNotSet" = "You"; - -/* Name In Message From Server If Name Not Set */ -"HockeyFeedbackListMessageResponseNameNotSet" = "Response"; - /* Message pending to be send */ "HockeyFeedbackListMessagePending" = "Pending"; -/* Delete All Messages Action Sheet */ +/* Delete All Messages Action Sheet / Alert View */ /* Title for the Action Sheet */ "HockeyFeedbackListDeleteAllTitle" = "This will delete all messages on this device."; @@ -180,6 +174,14 @@ "HockeyFeedbackListDeleteAllCancel" = "Cancel"; +/* Open Link In Safari Action Sheet / Alert View */ + +/* Title for the Action Sheet */ +"HockeyFeedbackListCancelOpenLink" = "Cancel"; + +/* Title for the Action Sheet */ +"HockeyFeedbackListOpenLinkInSafari" = "Open Link in Safari"; + /* UIActivity */ /* Activity Sharing Button Title, App Name will be inserted */ diff --git a/Resources/es.lproj/HockeySDK.strings b/Resources/es.lproj/HockeySDK.strings index 0b77a04f..d5642862 100755 --- a/Resources/es.lproj/HockeySDK.strings +++ b/Resources/es.lproj/HockeySDK.strings @@ -159,17 +159,11 @@ /* Button title for deleting all local messages*/ "HockeyFeedbackListButonDeleteAllMessages" = "Delete All Messages"; -/* User Name In Message If Name Not Set */ -"HockeyFeedbackListMessageUserNameNotSet" = "You"; - -/* Name In Message From Server If Name Not Set */ -"HockeyFeedbackListMessageResponseNameNotSet" = "Response"; - /* Message pending to be send */ "HockeyFeedbackListMessagePending" = "Pending"; -/* Delete All Messages Action Sheet */ +/* Delete All Messages Action Sheet / Alert View */ /* Title for the Action Sheet */ "HockeyFeedbackListDeleteAllTitle" = "This will delete all messages on this device."; @@ -181,6 +175,14 @@ "HockeyFeedbackListDeleteAllCancel" = "Cancel"; +/* Open Link In Safari Action Sheet / Alert View */ + +/* Title for the Action Sheet */ +"HockeyFeedbackListCancelOpenLink" = "Cancel"; + +/* Title for the Action Sheet */ +"HockeyFeedbackListOpenLinkInSafari" = "Open Link in Safari"; + /* UIActivity */ /* Activity Sharing Button Title, App Name will be inserted */ diff --git a/Resources/fr.lproj/HockeySDK.strings b/Resources/fr.lproj/HockeySDK.strings index 03544f36..a337dbab 100755 --- a/Resources/fr.lproj/HockeySDK.strings +++ b/Resources/fr.lproj/HockeySDK.strings @@ -159,17 +159,11 @@ /* Button title for deleting all local messages*/ "HockeyFeedbackListButonDeleteAllMessages" = "Delete All Messages"; -/* User Name In Message If Name Not Set */ -"HockeyFeedbackListMessageUserNameNotSet" = "You"; - -/* Name In Message From Server If Name Not Set */ -"HockeyFeedbackListMessageResponseNameNotSet" = "Response"; - /* Message pending to be send */ "HockeyFeedbackListMessagePending" = "Pending"; -/* Delete All Messages Action Sheet */ +/* Delete All Messages Action Sheet / Alert View */ /* Title for the Action Sheet */ "HockeyFeedbackListDeleteAllTitle" = "This will delete all messages on this device."; @@ -181,6 +175,14 @@ "HockeyFeedbackListDeleteAllCancel" = "Cancel"; +/* Open Link In Safari Action Sheet / Alert View */ + +/* Title for the Action Sheet */ +"HockeyFeedbackListCancelOpenLink" = "Cancel"; + +/* Title for the Action Sheet */ +"HockeyFeedbackListOpenLinkInSafari" = "Open Link in Safari"; + /* UIActivity */ /* Activity Sharing Button Title, App Name will be inserted */ diff --git a/Resources/it.lproj/HockeySDK.strings b/Resources/it.lproj/HockeySDK.strings index eb59079b..809e8448 100755 --- a/Resources/it.lproj/HockeySDK.strings +++ b/Resources/it.lproj/HockeySDK.strings @@ -159,17 +159,11 @@ /* Button title for deleting all local messages*/ "HockeyFeedbackListButonDeleteAllMessages" = "Delete All Messages"; -/* User Name In Message If Name Not Set */ -"HockeyFeedbackListMessageUserNameNotSet" = "You"; - -/* Name In Message From Server If Name Not Set */ -"HockeyFeedbackListMessageResponseNameNotSet" = "Response"; - /* Message pending to be send */ "HockeyFeedbackListMessagePending" = "Pending"; -/* Delete All Messages Action Sheet */ +/* Delete All Messages Action Sheet / Alert View */ /* Title for the Action Sheet */ "HockeyFeedbackListDeleteAllTitle" = "This will delete all messages on this device."; @@ -181,6 +175,14 @@ "HockeyFeedbackListDeleteAllCancel" = "Cancel"; +/* Open Link In Safari Action Sheet / Alert View */ + +/* Title for the Action Sheet */ +"HockeyFeedbackListCancelOpenLink" = "Cancel"; + +/* Title for the Action Sheet */ +"HockeyFeedbackListOpenLinkInSafari" = "Open Link in Safari"; + /* UIActivity */ /* Activity Sharing Button Title, App Name will be inserted */ diff --git a/Resources/ja.lproj/HockeySDK.strings b/Resources/ja.lproj/HockeySDK.strings index b9d77d1e..fc9703da 100755 --- a/Resources/ja.lproj/HockeySDK.strings +++ b/Resources/ja.lproj/HockeySDK.strings @@ -159,17 +159,11 @@ /* Button title for deleting all local messages*/ "HockeyFeedbackListButonDeleteAllMessages" = "Delete All Messages"; -/* User Name In Message If Name Not Set */ -"HockeyFeedbackListMessageUserNameNotSet" = "You"; - -/* Name In Message From Server If Name Not Set */ -"HockeyFeedbackListMessageResponseNameNotSet" = "Response"; - /* Message pending to be send */ "HockeyFeedbackListMessagePending" = "Pending"; -/* Delete All Messages Action Sheet */ +/* Delete All Messages Action Sheet / Alert View */ /* Title for the Action Sheet */ "HockeyFeedbackListDeleteAllTitle" = "This will delete all messages on this device."; @@ -181,6 +175,14 @@ "HockeyFeedbackListDeleteAllCancel" = "Cancel"; +/* Open Link In Safari Action Sheet / Alert View */ + +/* Title for the Action Sheet */ +"HockeyFeedbackListCancelOpenLink" = "Cancel"; + +/* Title for the Action Sheet */ +"HockeyFeedbackListOpenLinkInSafari" = "Open Link in Safari"; + /* UIActivity */ /* Activity Sharing Button Title, App Name will be inserted */ diff --git a/Resources/nl.lproj/HockeySDK.strings b/Resources/nl.lproj/HockeySDK.strings index b88870c4..eb9e9162 100755 --- a/Resources/nl.lproj/HockeySDK.strings +++ b/Resources/nl.lproj/HockeySDK.strings @@ -159,17 +159,11 @@ /* Button title for deleting all local messages*/ "HockeyFeedbackListButonDeleteAllMessages" = "Delete All Messages"; -/* User Name In Message If Name Not Set */ -"HockeyFeedbackListMessageUserNameNotSet" = "You"; - -/* Name In Message From Server If Name Not Set */ -"HockeyFeedbackListMessageResponseNameNotSet" = "Response"; - /* Message pending to be send */ "HockeyFeedbackListMessagePending" = "Pending"; -/* Delete All Messages Action Sheet */ +/* Delete All Messages Action Sheet / Alert View */ /* Title for the Action Sheet */ "HockeyFeedbackListDeleteAllTitle" = "This will delete all messages on this device."; @@ -181,6 +175,14 @@ "HockeyFeedbackListDeleteAllCancel" = "Cancel"; +/* Open Link In Safari Action Sheet / Alert View */ + +/* Title for the Action Sheet */ +"HockeyFeedbackListCancelOpenLink" = "Cancel"; + +/* Title for the Action Sheet */ +"HockeyFeedbackListOpenLinkInSafari" = "Open Link in Safari"; + /* UIActivity */ /* Activity Sharing Button Title, App Name will be inserted */ diff --git a/Resources/pt-PT.lproj/HockeySDK.strings b/Resources/pt-PT.lproj/HockeySDK.strings index 0d10b835..2ed9221d 100755 --- a/Resources/pt-PT.lproj/HockeySDK.strings +++ b/Resources/pt-PT.lproj/HockeySDK.strings @@ -159,17 +159,11 @@ /* Button title for deleting all local messages*/ "HockeyFeedbackListButonDeleteAllMessages" = "Delete All Messages"; -/* User Name In Message If Name Not Set */ -"HockeyFeedbackListMessageUserNameNotSet" = "You"; - -/* Name In Message From Server If Name Not Set */ -"HockeyFeedbackListMessageResponseNameNotSet" = "Response"; - /* Message pending to be send */ "HockeyFeedbackListMessagePending" = "Pending"; -/* Delete All Messages Action Sheet */ +/* Delete All Messages Action Sheet / Alert View */ /* Title for the Action Sheet */ "HockeyFeedbackListDeleteAllTitle" = "This will delete all messages on this device."; @@ -181,6 +175,14 @@ "HockeyFeedbackListDeleteAllCancel" = "Cancel"; +/* Open Link In Safari Action Sheet / Alert View */ + +/* Title for the Action Sheet */ +"HockeyFeedbackListCancelOpenLink" = "Cancel"; + +/* Title for the Action Sheet */ +"HockeyFeedbackListOpenLinkInSafari" = "Open Link in Safari"; + /* UIActivity */ /* Activity Sharing Button Title, App Name will be inserted */ diff --git a/Resources/pt.lproj/HockeySDK.strings b/Resources/pt.lproj/HockeySDK.strings index 4e42872a..8263e637 100755 --- a/Resources/pt.lproj/HockeySDK.strings +++ b/Resources/pt.lproj/HockeySDK.strings @@ -159,17 +159,11 @@ /* Button title for deleting all local messages*/ "HockeyFeedbackListButonDeleteAllMessages" = "Delete All Messages"; -/* User Name In Message If Name Not Set */ -"HockeyFeedbackListMessageUserNameNotSet" = "You"; - -/* Name In Message From Server If Name Not Set */ -"HockeyFeedbackListMessageResponseNameNotSet" = "Response"; - /* Message pending to be send */ "HockeyFeedbackListMessagePending" = "Pending"; -/* Delete All Messages Action Sheet */ +/* Delete All Messages Action Sheet / Alert View */ /* Title for the Action Sheet */ "HockeyFeedbackListDeleteAllTitle" = "This will delete all messages on this device."; @@ -181,6 +175,14 @@ "HockeyFeedbackListDeleteAllCancel" = "Cancel"; +/* Open Link In Safari Action Sheet / Alert View */ + +/* Title for the Action Sheet */ +"HockeyFeedbackListCancelOpenLink" = "Cancel"; + +/* Title for the Action Sheet */ +"HockeyFeedbackListOpenLinkInSafari" = "Open Link in Safari"; + /* UIActivity */ /* Activity Sharing Button Title, App Name will be inserted */ diff --git a/Resources/ru.lproj/HockeySDK.strings b/Resources/ru.lproj/HockeySDK.strings index 844b7b30..8051c193 100755 --- a/Resources/ru.lproj/HockeySDK.strings +++ b/Resources/ru.lproj/HockeySDK.strings @@ -159,17 +159,11 @@ /* Button title for deleting all local messages*/ "HockeyFeedbackListButonDeleteAllMessages" = "Delete All Messages"; -/* User Name In Message If Name Not Set */ -"HockeyFeedbackListMessageUserNameNotSet" = "You"; - -/* Name In Message From Server If Name Not Set */ -"HockeyFeedbackListMessageResponseNameNotSet" = "Response"; - /* Message pending to be send */ "HockeyFeedbackListMessagePending" = "Pending"; -/* Delete All Messages Action Sheet */ +/* Delete All Messages Action Sheet / Alert View */ /* Title for the Action Sheet */ "HockeyFeedbackListDeleteAllTitle" = "This will delete all messages on this device."; @@ -181,6 +175,14 @@ "HockeyFeedbackListDeleteAllCancel" = "Cancel"; +/* Open Link In Safari Action Sheet / Alert View */ + +/* Title for the Action Sheet */ +"HockeyFeedbackListCancelOpenLink" = "Cancel"; + +/* Title for the Action Sheet */ +"HockeyFeedbackListOpenLinkInSafari" = "Open Link in Safari"; + /* UIActivity */ /* Activity Sharing Button Title, App Name will be inserted */ diff --git a/Resources/sv.lproj/HockeySDK.strings b/Resources/sv.lproj/HockeySDK.strings index e49649d0..ef2361c3 100755 --- a/Resources/sv.lproj/HockeySDK.strings +++ b/Resources/sv.lproj/HockeySDK.strings @@ -159,17 +159,11 @@ /* Button title for deleting all local messages*/ "HockeyFeedbackListButonDeleteAllMessages" = "Delete All Messages"; -/* User Name In Message If Name Not Set */ -"HockeyFeedbackListMessageUserNameNotSet" = "You"; - -/* Name In Message From Server If Name Not Set */ -"HockeyFeedbackListMessageResponseNameNotSet" = "Response"; - /* Message pending to be send */ "HockeyFeedbackListMessagePending" = "Pending"; -/* Delete All Messages Action Sheet */ +/* Delete All Messages Action Sheet / Alert View */ /* Title for the Action Sheet */ "HockeyFeedbackListDeleteAllTitle" = "This will delete all messages on this device."; @@ -181,6 +175,14 @@ "HockeyFeedbackListDeleteAllCancel" = "Cancel"; +/* Open Link In Safari Action Sheet / Alert View */ + +/* Title for the Action Sheet */ +"HockeyFeedbackListCancelOpenLink" = "Cancel"; + +/* Title for the Action Sheet */ +"HockeyFeedbackListOpenLinkInSafari" = "Open Link in Safari"; + /* UIActivity */ /* Activity Sharing Button Title, App Name will be inserted */ diff --git a/Resources/tr.lproj/HockeySDK.strings b/Resources/tr.lproj/HockeySDK.strings index 59c489e8..a76dba2c 100644 --- a/Resources/tr.lproj/HockeySDK.strings +++ b/Resources/tr.lproj/HockeySDK.strings @@ -159,17 +159,11 @@ /* Button title for deleting all local messages*/ "HockeyFeedbackListButonDeleteAllMessages" = "Delete All Messages"; -/* User Name In Message If Name Not Set */ -"HockeyFeedbackListMessageUserNameNotSet" = "You"; - -/* Name In Message From Server If Name Not Set */ -"HockeyFeedbackListMessageResponseNameNotSet" = "Response"; - /* Message pending to be send */ "HockeyFeedbackListMessagePending" = "Pending"; -/* Delete All Messages Action Sheet */ +/* Delete All Messages Action Sheet / Alert View */ /* Title for the Action Sheet */ "HockeyFeedbackListDeleteAllTitle" = "This will delete all messages on this device."; @@ -181,6 +175,14 @@ "HockeyFeedbackListDeleteAllCancel" = "Cancel"; +/* Open Link In Safari Action Sheet / Alert View */ + +/* Title for the Action Sheet */ +"HockeyFeedbackListCancelOpenLink" = "Cancel"; + +/* Title for the Action Sheet */ +"HockeyFeedbackListOpenLinkInSafari" = "Open Link in Safari"; + /* UIActivity */ /* Activity Sharing Button Title, App Name will be inserted */ diff --git a/Resources/zh_CN.lproj/HockeySDK.strings b/Resources/zh_CN.lproj/HockeySDK.strings index a2def09f..b2090e5c 100644 --- a/Resources/zh_CN.lproj/HockeySDK.strings +++ b/Resources/zh_CN.lproj/HockeySDK.strings @@ -159,17 +159,11 @@ /* Button title for deleting all local messages*/ "HockeyFeedbackListButonDeleteAllMessages" = "Delete All Messages"; -/* User Name In Message If Name Not Set */ -"HockeyFeedbackListMessageUserNameNotSet" = "You"; - -/* Name In Message From Server If Name Not Set */ -"HockeyFeedbackListMessageResponseNameNotSet" = "Response"; - /* Message pending to be send */ "HockeyFeedbackListMessagePending" = "Pending"; -/* Delete All Messages Action Sheet */ +/* Delete All Messages Action Sheet / Alert View */ /* Title for the Action Sheet */ "HockeyFeedbackListDeleteAllTitle" = "This will delete all messages on this device."; @@ -181,6 +175,14 @@ "HockeyFeedbackListDeleteAllCancel" = "Cancel"; +/* Open Link In Safari Action Sheet / Alert View */ + +/* Title for the Action Sheet */ +"HockeyFeedbackListCancelOpenLink" = "Cancel"; + +/* Title for the Action Sheet */ +"HockeyFeedbackListOpenLinkInSafari" = "Open Link in Safari"; + /* UIActivity */ /* Activity Sharing Button Title, App Name will be inserted */ diff --git a/Resources/zh_TW.lproj/HockeySDK.strings b/Resources/zh_TW.lproj/HockeySDK.strings index 1caa729b..ee45009b 100644 --- a/Resources/zh_TW.lproj/HockeySDK.strings +++ b/Resources/zh_TW.lproj/HockeySDK.strings @@ -159,17 +159,11 @@ /* Button title for deleting all local messages*/ "HockeyFeedbackListButonDeleteAllMessages" = "Delete All Messages"; -/* User Name In Message If Name Not Set */ -"HockeyFeedbackListMessageUserNameNotSet" = "You"; - -/* Name In Message From Server If Name Not Set */ -"HockeyFeedbackListMessageResponseNameNotSet" = "Response"; - /* Message pending to be send */ "HockeyFeedbackListMessagePending" = "Pending"; -/* Delete All Messages Action Sheet */ +/* Delete All Messages Action Sheet / Alert View */ /* Title for the Action Sheet */ "HockeyFeedbackListDeleteAllTitle" = "This will delete all messages on this device."; @@ -181,6 +175,14 @@ "HockeyFeedbackListDeleteAllCancel" = "Cancel"; +/* Open Link In Safari Action Sheet / Alert View */ + +/* Title for the Action Sheet */ +"HockeyFeedbackListCancelOpenLink" = "Cancel"; + +/* Title for the Action Sheet */ +"HockeyFeedbackListOpenLinkInSafari" = "Open Link in Safari"; + /* UIActivity */ /* Activity Sharing Button Title, App Name will be inserted */ From 3383f3a657f8820f2c1a1c01151b6930757c907f Mon Sep 17 00:00:00 2001 From: Andreas Linde Date: Wed, 17 Oct 2012 19:20:59 +0200 Subject: [PATCH 052/176] Save feedback data into NSApplicationSupportDirectory instead of NSCachesDirectory Part 2 Missed that part in the previous commit --- Classes/BITFeedbackManager.m | 1 + 1 file changed, 1 insertion(+) diff --git a/Classes/BITFeedbackManager.m b/Classes/BITFeedbackManager.m index 74223a6c..f2e4cc9b 100644 --- a/Classes/BITFeedbackManager.m +++ b/Classes/BITFeedbackManager.m @@ -83,6 +83,7 @@ - (id)init { _fileManager = [[NSFileManager alloc] init]; // temporary directory for crashes grabbed from PLCrashReporter + NSArray *paths = NSSearchPathForDirectoriesInDomains(NSApplicationSupportDirectory, NSUserDomainMask, YES); _feedbackDir = [[[paths objectAtIndex:0] stringByAppendingPathComponent:BITHOCKEY_IDENTIFIER] retain]; if (![_fileManager fileExistsAtPath:_feedbackDir]) { From 423bc7ece795eb160c063e7a24ee5926716b3d71 Mon Sep 17 00:00:00 2001 From: Andreas Linde Date: Thu, 18 Oct 2012 01:08:16 +0200 Subject: [PATCH 053/176] Add copy link to Feedback UI --- Classes/BITFeedbackListViewController.m | 71 ++++++++++++++----------- Resources/de.lproj/HockeySDK.strings | 13 +++-- Resources/en.lproj/HockeySDK.strings | 12 +++-- Resources/es.lproj/HockeySDK.strings | 12 +++-- Resources/fr.lproj/HockeySDK.strings | 12 +++-- Resources/it.lproj/HockeySDK.strings | 12 +++-- Resources/ja.lproj/HockeySDK.strings | 12 +++-- Resources/nl.lproj/HockeySDK.strings | 12 +++-- Resources/pt-PT.lproj/HockeySDK.strings | 12 +++-- Resources/pt.lproj/HockeySDK.strings | 12 +++-- Resources/ru.lproj/HockeySDK.strings | 12 +++-- Resources/sv.lproj/HockeySDK.strings | 12 +++-- Resources/tr.lproj/HockeySDK.strings | 12 +++-- Resources/zh_CN.lproj/HockeySDK.strings | 12 +++-- Resources/zh_TW.lproj/HockeySDK.strings | 12 +++-- 15 files changed, 153 insertions(+), 87 deletions(-) diff --git a/Classes/BITFeedbackListViewController.m b/Classes/BITFeedbackListViewController.m index 5a1bf786..b2a69adc 100644 --- a/Classes/BITFeedbackListViewController.m +++ b/Classes/BITFeedbackListViewController.m @@ -477,6 +477,35 @@ - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPa } +#pragma mark - BITAttributedLabelDelegate + +- (void)attributedLabel:(BITAttributedLabel *)label didSelectLinkWithURL:(NSURL *)url { + if (UI_USER_INTERFACE_IDIOM() != UIUserInterfaceIdiomPad) { + UIActionSheet *linkAction = [[UIActionSheet alloc] initWithTitle:[url absoluteString] + delegate:self + cancelButtonTitle:BITHockeyLocalizedString(@"HockeyFeedbackListLinkActionCancel") + destructiveButtonTitle:nil + otherButtonTitles:BITHockeyLocalizedString(@"HockeyFeedbackListLinkActionOpen"), BITHockeyLocalizedString(@"HockeyFeedbackListLinkActionCopy"), nil + ]; + [linkAction setTag:1]; + [linkAction setActionSheetStyle:UIActionSheetStyleBlackTranslucent]; + [linkAction showInView:self.view]; + [linkAction release]; + } else { + UIAlertView *linkAction = [[UIAlertView alloc] initWithTitle:[url absoluteString] + message:nil + delegate:self + cancelButtonTitle:BITHockeyLocalizedString(@"HockeyFeedbackListLinkActionCancel") + otherButtonTitles:BITHockeyLocalizedString(@"HockeyFeedbackListLinkActionOpen"), BITHockeyLocalizedString(@"HockeyFeedbackListLinkActionCopy"), nil + ]; + + [linkAction setTag:1]; + [linkAction show]; + [linkAction release]; + } +} + + #pragma mark - UIAlertViewDelegate - (void)alertView:(UIAlertView *)alertView didDismissWithButtonIndex:(NSInteger)buttonIndex { @@ -489,7 +518,12 @@ - (void)alertView:(UIAlertView *)alertView didDismissWithButtonIndex:(NSInteger) [self deleteAllMessages]; } } else { - [[UIApplication sharedApplication] openURL:[NSURL URLWithString:alertView.title]]; + if (buttonIndex == [alertView firstOtherButtonIndex]) { + [[UIApplication sharedApplication] openURL:[NSURL URLWithString:alertView.title]]; + } else { + UIPasteboard *pasteboard = [UIPasteboard generalPasteboard]; + pasteboard.URL = [NSURL URLWithString:alertView.title]; + } } } @@ -506,35 +540,12 @@ - (void)actionSheet:(UIActionSheet *)actionSheet didDismissWithButtonIndex:(NSIn [self deleteAllMessages]; } } else { - [[UIApplication sharedApplication] openURL:[NSURL URLWithString:actionSheet.title]]; - } -} - - -#pragma mark - BITAttributedLabelDelegate - -- (void)attributedLabel:(BITAttributedLabel *)label didSelectLinkWithURL:(NSURL *)url { - if (UI_USER_INTERFACE_IDIOM() != UIUserInterfaceIdiomPad) { - UIActionSheet *linkAction = [[UIActionSheet alloc] initWithTitle:[url absoluteString] - delegate:self - cancelButtonTitle:BITHockeyLocalizedString(@"HockeyFeedbackListCancelOpenLink") - destructiveButtonTitle:nil - otherButtonTitles:BITHockeyLocalizedString(@"HockeyFeedbackListOpenLinkInSafari"), nil - ]; - [linkAction setTag:1]; - [linkAction setActionSheetStyle:UIActionSheetStyleBlackTranslucent]; - [linkAction showInView:self.view]; - [linkAction release]; - } else { - UIAlertView *linkAction = [[UIAlertView alloc] initWithTitle:[url absoluteString] - message:nil - delegate:self - cancelButtonTitle:BITHockeyLocalizedString(@"HockeyFeedbackListCancelOpenLink") - otherButtonTitles:BITHockeyLocalizedString(@"HockeyFeedbackListOpenLinkInSafari"), nil]; - - [linkAction setTag:1]; - [linkAction show]; - [linkAction release]; + if (buttonIndex == [actionSheet destructiveButtonIndex]) { + [[UIApplication sharedApplication] openURL:[NSURL URLWithString:actionSheet.title]]; + } else { + UIPasteboard *pasteboard = [UIPasteboard generalPasteboard]; + pasteboard.URL = [NSURL URLWithString:actionSheet.title]; + } } } diff --git a/Resources/de.lproj/HockeySDK.strings b/Resources/de.lproj/HockeySDK.strings index ca8120c9..dd7227ed 100755 --- a/Resources/de.lproj/HockeySDK.strings +++ b/Resources/de.lproj/HockeySDK.strings @@ -177,13 +177,16 @@ "HockeyFeedbackListDeleteAllCancel" = "Cancel"; -/* Open Link In Safari Action Sheet / Alert View */ +/* Open/Copy Link In Safari Action Sheet / Alert View */ -/* Title for the Action Sheet */ -"HockeyFeedbackListCancelOpenLink" = "Cancel"; +/* Button Title to cancel */ +"HockeyFeedbackListLinkActionCancel" = "Cancel"; -/* Title for the Action Sheet */ -"HockeyFeedbackListOpenLinkInSafari" = "Open Link in Safari"; +/* Button Title to Open the Link */ +"HockeyFeedbackListLinkActionOpen" = "Open"; + +/* Button Title to Copy the Link */ +"HockeyFeedbackListLinkActionCopy" = "Copy"; /* UIActivity */ diff --git a/Resources/en.lproj/HockeySDK.strings b/Resources/en.lproj/HockeySDK.strings index 000f7525..8bab3935 100755 --- a/Resources/en.lproj/HockeySDK.strings +++ b/Resources/en.lproj/HockeySDK.strings @@ -176,11 +176,15 @@ /* Open Link In Safari Action Sheet / Alert View */ -/* Title for the Action Sheet */ -"HockeyFeedbackListCancelOpenLink" = "Cancel"; +/* Button Title to cancel */ +"HockeyFeedbackListLinkActionCancel" = "Cancel"; + +/* Button Title to Open the Link */ +"HockeyFeedbackListLinkActionOpen" = "Open"; + +/* Button Title to Copy the Link */ +"HockeyFeedbackListLinkActionCopy" = "Copy"; -/* Title for the Action Sheet */ -"HockeyFeedbackListOpenLinkInSafari" = "Open Link in Safari"; /* UIActivity */ diff --git a/Resources/es.lproj/HockeySDK.strings b/Resources/es.lproj/HockeySDK.strings index d5642862..62584366 100755 --- a/Resources/es.lproj/HockeySDK.strings +++ b/Resources/es.lproj/HockeySDK.strings @@ -177,11 +177,15 @@ /* Open Link In Safari Action Sheet / Alert View */ -/* Title for the Action Sheet */ -"HockeyFeedbackListCancelOpenLink" = "Cancel"; +/* Button Title to cancel */ +"HockeyFeedbackListLinkActionCancel" = "Cancel"; + +/* Button Title to Open the Link */ +"HockeyFeedbackListLinkActionOpen" = "Open"; + +/* Button Title to Copy the Link */ +"HockeyFeedbackListLinkActionCopy" = "Copy"; -/* Title for the Action Sheet */ -"HockeyFeedbackListOpenLinkInSafari" = "Open Link in Safari"; /* UIActivity */ diff --git a/Resources/fr.lproj/HockeySDK.strings b/Resources/fr.lproj/HockeySDK.strings index a337dbab..d94efc7a 100755 --- a/Resources/fr.lproj/HockeySDK.strings +++ b/Resources/fr.lproj/HockeySDK.strings @@ -177,11 +177,15 @@ /* Open Link In Safari Action Sheet / Alert View */ -/* Title for the Action Sheet */ -"HockeyFeedbackListCancelOpenLink" = "Cancel"; +/* Button Title to cancel */ +"HockeyFeedbackListLinkActionCancel" = "Cancel"; + +/* Button Title to Open the Link */ +"HockeyFeedbackListLinkActionOpen" = "Open"; + +/* Button Title to Copy the Link */ +"HockeyFeedbackListLinkActionCopy" = "Copy"; -/* Title for the Action Sheet */ -"HockeyFeedbackListOpenLinkInSafari" = "Open Link in Safari"; /* UIActivity */ diff --git a/Resources/it.lproj/HockeySDK.strings b/Resources/it.lproj/HockeySDK.strings index 809e8448..5b64e830 100755 --- a/Resources/it.lproj/HockeySDK.strings +++ b/Resources/it.lproj/HockeySDK.strings @@ -177,11 +177,15 @@ /* Open Link In Safari Action Sheet / Alert View */ -/* Title for the Action Sheet */ -"HockeyFeedbackListCancelOpenLink" = "Cancel"; +/* Button Title to cancel */ +"HockeyFeedbackListLinkActionCancel" = "Cancel"; + +/* Button Title to Open the Link */ +"HockeyFeedbackListLinkActionOpen" = "Open"; + +/* Button Title to Copy the Link */ +"HockeyFeedbackListLinkActionCopy" = "Copy"; -/* Title for the Action Sheet */ -"HockeyFeedbackListOpenLinkInSafari" = "Open Link in Safari"; /* UIActivity */ diff --git a/Resources/ja.lproj/HockeySDK.strings b/Resources/ja.lproj/HockeySDK.strings index fc9703da..256b3086 100755 --- a/Resources/ja.lproj/HockeySDK.strings +++ b/Resources/ja.lproj/HockeySDK.strings @@ -177,11 +177,15 @@ /* Open Link In Safari Action Sheet / Alert View */ -/* Title for the Action Sheet */ -"HockeyFeedbackListCancelOpenLink" = "Cancel"; +/* Button Title to cancel */ +"HockeyFeedbackListLinkActionCancel" = "Cancel"; + +/* Button Title to Open the Link */ +"HockeyFeedbackListLinkActionOpen" = "Open"; + +/* Button Title to Copy the Link */ +"HockeyFeedbackListLinkActionCopy" = "Copy"; -/* Title for the Action Sheet */ -"HockeyFeedbackListOpenLinkInSafari" = "Open Link in Safari"; /* UIActivity */ diff --git a/Resources/nl.lproj/HockeySDK.strings b/Resources/nl.lproj/HockeySDK.strings index eb9e9162..dc27e853 100755 --- a/Resources/nl.lproj/HockeySDK.strings +++ b/Resources/nl.lproj/HockeySDK.strings @@ -177,11 +177,15 @@ /* Open Link In Safari Action Sheet / Alert View */ -/* Title for the Action Sheet */ -"HockeyFeedbackListCancelOpenLink" = "Cancel"; +/* Button Title to cancel */ +"HockeyFeedbackListLinkActionCancel" = "Cancel"; + +/* Button Title to Open the Link */ +"HockeyFeedbackListLinkActionOpen" = "Open"; + +/* Button Title to Copy the Link */ +"HockeyFeedbackListLinkActionCopy" = "Copy"; -/* Title for the Action Sheet */ -"HockeyFeedbackListOpenLinkInSafari" = "Open Link in Safari"; /* UIActivity */ diff --git a/Resources/pt-PT.lproj/HockeySDK.strings b/Resources/pt-PT.lproj/HockeySDK.strings index 2ed9221d..ca0fd6c0 100755 --- a/Resources/pt-PT.lproj/HockeySDK.strings +++ b/Resources/pt-PT.lproj/HockeySDK.strings @@ -177,11 +177,15 @@ /* Open Link In Safari Action Sheet / Alert View */ -/* Title for the Action Sheet */ -"HockeyFeedbackListCancelOpenLink" = "Cancel"; +/* Button Title to cancel */ +"HockeyFeedbackListLinkActionCancel" = "Cancel"; + +/* Button Title to Open the Link */ +"HockeyFeedbackListLinkActionOpen" = "Open"; + +/* Button Title to Copy the Link */ +"HockeyFeedbackListLinkActionCopy" = "Copy"; -/* Title for the Action Sheet */ -"HockeyFeedbackListOpenLinkInSafari" = "Open Link in Safari"; /* UIActivity */ diff --git a/Resources/pt.lproj/HockeySDK.strings b/Resources/pt.lproj/HockeySDK.strings index 8263e637..f826ca0d 100755 --- a/Resources/pt.lproj/HockeySDK.strings +++ b/Resources/pt.lproj/HockeySDK.strings @@ -177,11 +177,15 @@ /* Open Link In Safari Action Sheet / Alert View */ -/* Title for the Action Sheet */ -"HockeyFeedbackListCancelOpenLink" = "Cancel"; +/* Button Title to cancel */ +"HockeyFeedbackListLinkActionCancel" = "Cancel"; + +/* Button Title to Open the Link */ +"HockeyFeedbackListLinkActionOpen" = "Open"; + +/* Button Title to Copy the Link */ +"HockeyFeedbackListLinkActionCopy" = "Copy"; -/* Title for the Action Sheet */ -"HockeyFeedbackListOpenLinkInSafari" = "Open Link in Safari"; /* UIActivity */ diff --git a/Resources/ru.lproj/HockeySDK.strings b/Resources/ru.lproj/HockeySDK.strings index 8051c193..89844ca9 100755 --- a/Resources/ru.lproj/HockeySDK.strings +++ b/Resources/ru.lproj/HockeySDK.strings @@ -177,11 +177,15 @@ /* Open Link In Safari Action Sheet / Alert View */ -/* Title for the Action Sheet */ -"HockeyFeedbackListCancelOpenLink" = "Cancel"; +/* Button Title to cancel */ +"HockeyFeedbackListLinkActionCancel" = "Cancel"; + +/* Button Title to Open the Link */ +"HockeyFeedbackListLinkActionOpen" = "Open"; + +/* Button Title to Copy the Link */ +"HockeyFeedbackListLinkActionCopy" = "Copy"; -/* Title for the Action Sheet */ -"HockeyFeedbackListOpenLinkInSafari" = "Open Link in Safari"; /* UIActivity */ diff --git a/Resources/sv.lproj/HockeySDK.strings b/Resources/sv.lproj/HockeySDK.strings index ef2361c3..8ef42ee8 100755 --- a/Resources/sv.lproj/HockeySDK.strings +++ b/Resources/sv.lproj/HockeySDK.strings @@ -177,11 +177,15 @@ /* Open Link In Safari Action Sheet / Alert View */ -/* Title for the Action Sheet */ -"HockeyFeedbackListCancelOpenLink" = "Cancel"; +/* Button Title to cancel */ +"HockeyFeedbackListLinkActionCancel" = "Cancel"; + +/* Button Title to Open the Link */ +"HockeyFeedbackListLinkActionOpen" = "Open"; + +/* Button Title to Copy the Link */ +"HockeyFeedbackListLinkActionCopy" = "Copy"; -/* Title for the Action Sheet */ -"HockeyFeedbackListOpenLinkInSafari" = "Open Link in Safari"; /* UIActivity */ diff --git a/Resources/tr.lproj/HockeySDK.strings b/Resources/tr.lproj/HockeySDK.strings index a76dba2c..e1f1a158 100644 --- a/Resources/tr.lproj/HockeySDK.strings +++ b/Resources/tr.lproj/HockeySDK.strings @@ -177,11 +177,15 @@ /* Open Link In Safari Action Sheet / Alert View */ -/* Title for the Action Sheet */ -"HockeyFeedbackListCancelOpenLink" = "Cancel"; +/* Button Title to cancel */ +"HockeyFeedbackListLinkActionCancel" = "Cancel"; + +/* Button Title to Open the Link */ +"HockeyFeedbackListLinkActionOpen" = "Open"; + +/* Button Title to Copy the Link */ +"HockeyFeedbackListLinkActionCopy" = "Copy"; -/* Title for the Action Sheet */ -"HockeyFeedbackListOpenLinkInSafari" = "Open Link in Safari"; /* UIActivity */ diff --git a/Resources/zh_CN.lproj/HockeySDK.strings b/Resources/zh_CN.lproj/HockeySDK.strings index b2090e5c..af0ec4d7 100644 --- a/Resources/zh_CN.lproj/HockeySDK.strings +++ b/Resources/zh_CN.lproj/HockeySDK.strings @@ -177,11 +177,15 @@ /* Open Link In Safari Action Sheet / Alert View */ -/* Title for the Action Sheet */ -"HockeyFeedbackListCancelOpenLink" = "Cancel"; +/* Button Title to cancel */ +"HockeyFeedbackListLinkActionCancel" = "Cancel"; + +/* Button Title to Open the Link */ +"HockeyFeedbackListLinkActionOpen" = "Open"; + +/* Button Title to Copy the Link */ +"HockeyFeedbackListLinkActionCopy" = "Copy"; -/* Title for the Action Sheet */ -"HockeyFeedbackListOpenLinkInSafari" = "Open Link in Safari"; /* UIActivity */ diff --git a/Resources/zh_TW.lproj/HockeySDK.strings b/Resources/zh_TW.lproj/HockeySDK.strings index ee45009b..6773222b 100644 --- a/Resources/zh_TW.lproj/HockeySDK.strings +++ b/Resources/zh_TW.lproj/HockeySDK.strings @@ -177,11 +177,15 @@ /* Open Link In Safari Action Sheet / Alert View */ -/* Title for the Action Sheet */ -"HockeyFeedbackListCancelOpenLink" = "Cancel"; +/* Button Title to cancel */ +"HockeyFeedbackListLinkActionCancel" = "Cancel"; + +/* Button Title to Open the Link */ +"HockeyFeedbackListLinkActionOpen" = "Open"; + +/* Button Title to Copy the Link */ +"HockeyFeedbackListLinkActionCopy" = "Copy"; -/* Title for the Action Sheet */ -"HockeyFeedbackListOpenLinkInSafari" = "Open Link in Safari"; /* UIActivity */ From 34bb4cb758c6a9b12259c21d7ee3c4314a0c9365 Mon Sep 17 00:00:00 2001 From: Andreas Linde Date: Thu, 18 Oct 2012 20:04:51 +0200 Subject: [PATCH 054/176] Add option to Feedback compose UI to be pre filled with data Accepts an array with data to fill it up with, much like UIActivity. Allows easier option to expand with more content types in the future --- Classes/BITFeedbackActivity.h | 3 -- Classes/BITFeedbackActivity.m | 44 ++++++++++++++---- Classes/BITFeedbackComposeViewController.h | 3 +- Classes/BITFeedbackComposeViewController.m | 53 ++++++++++++++++------ Classes/BITFeedbackManager.h | 3 +- Classes/BITFeedbackManager.m | 6 +-- 6 files changed, 79 insertions(+), 33 deletions(-) diff --git a/Classes/BITFeedbackActivity.h b/Classes/BITFeedbackActivity.h index fa2289a7..e6657b67 100644 --- a/Classes/BITFeedbackActivity.h +++ b/Classes/BITFeedbackActivity.h @@ -12,7 +12,4 @@ @interface BITFeedbackActivity : UIActivity -@property (nonatomic, retain) UIImage *shareImage; -@property (nonatomic, retain) NSString *shareString; - @end diff --git a/Classes/BITFeedbackActivity.m b/Classes/BITFeedbackActivity.m index 2dd581ef..d0007684 100644 --- a/Classes/BITFeedbackActivity.m +++ b/Classes/BITFeedbackActivity.m @@ -13,8 +13,35 @@ #import "BITHockeyHelper.h" #import "BITFeedbackManagerPrivate.h" + +@interface BITFeedbackActivity() + +@property (nonatomic, retain) NSMutableArray *items; + +@end + + @implementation BITFeedbackActivity +#pragma mark - NSObject + +- (id)init { + if ((self = [super init])) { + self.items = [NSMutableArray array];; + } + + return self; +} + +- (void)dealloc { + [_items release]; _items = nil; + + [super dealloc]; +} + + +#pragma mark - UIActivity + - (NSString *)activityType { return @"UIActivityTypePostToHockeySDKFeedback"; } @@ -36,9 +63,7 @@ - (BOOL)canPerformWithActivityItems:(NSArray *)activityItems { if ([BITHockeyManager sharedHockeyManager].disableFeedbackManager) return NO; for (UIActivityItemProvider *item in activityItems) { - if ([item isKindOfClass:[UIImage class]]) { - return YES; - } else if ([item isKindOfClass:[NSString class]]) { + if ([item isKindOfClass:[NSString class]]) { return YES; } else if ([item isKindOfClass:[NSURL class]]) { return YES; @@ -49,12 +74,9 @@ - (BOOL)canPerformWithActivityItems:(NSArray *)activityItems { - (void)prepareWithActivityItems:(NSArray *)activityItems { for (id item in activityItems) { - if ([item isKindOfClass:[UIImage class]]) { - self.shareImage = item; - } else if ([item isKindOfClass:[NSString class]]) { - self.shareString = [(self.shareString ? self.shareString : @"") stringByAppendingFormat:@"%@%@",(self.shareString ? @" " : @""),item]; - } else if ([item isKindOfClass:[NSURL class]]) { - self.shareString = [(self.shareString ? self.shareString : @"") stringByAppendingFormat:@"%@%@",(self.shareString ? @" " : @""),[(NSURL *)item absoluteString]]; + if ([item isKindOfClass:[NSString class]] || + [item isKindOfClass:[NSURL class]]) { + [_items addObject:item]; } else { BITHockeyLog(@"Unknown item type %@", item); } @@ -63,7 +85,9 @@ - (void)prepareWithActivityItems:(NSArray *)activityItems { - (UIViewController *)activityViewController { // TODO: return compose controller with activity content added - BITFeedbackComposeViewController *composeViewController = [[BITHockeyManager sharedHockeyManager].feedbackManager feedbackComposeViewControllerWithScreenshot:NO delegate:self]; + BITFeedbackComposeViewController *composeViewController = [[BITHockeyManager sharedHockeyManager].feedbackManager feedbackComposeViewController]; + composeViewController.delegate = self; + [composeViewController prepareWithItems:_items]; UINavigationController *navController = [[[UINavigationController alloc] initWithRootViewController: composeViewController] autorelease]; navController.modalPresentationStyle = UIModalPresentationFormSheet; diff --git a/Classes/BITFeedbackComposeViewController.h b/Classes/BITFeedbackComposeViewController.h index b59b6237..b30c357c 100644 --- a/Classes/BITFeedbackComposeViewController.h +++ b/Classes/BITFeedbackComposeViewController.h @@ -37,6 +37,7 @@ @property (nonatomic, assign) id delegate; - (id)init; -- (id)initWithDelegate:(id)delegate; + +- (void)prepareWithItems:(NSArray *)items; @end \ No newline at end of file diff --git a/Classes/BITFeedbackComposeViewController.m b/Classes/BITFeedbackComposeViewController.m index 00c4ec03..93c29905 100644 --- a/Classes/BITFeedbackComposeViewController.m +++ b/Classes/BITFeedbackComposeViewController.m @@ -37,39 +37,59 @@ #import "BITHockeyHelper.h" -@interface BITFeedbackComposeViewController () { - BOOL blockUserDataScreen; -} +@interface BITFeedbackComposeViewController () @property (nonatomic, assign) BITFeedbackManager *manager; @property (nonatomic, retain) UITextView *textView; +@property (nonatomic, retain) NSString *text; + - (void)setUserDataAction; @end +@implementation BITFeedbackComposeViewController { + BOOL _blockUserDataScreen; +} -@implementation BITFeedbackComposeViewController + +#pragma mark - NSObject - (id)init { self = [super init]; if (self) { self.title = BITHockeyLocalizedString(@"HockeyFeedbackComposeTitle"); - blockUserDataScreen = NO; + _blockUserDataScreen = NO; _delegate = nil; _manager = [BITHockeyManager sharedHockeyManager].feedbackManager; + + _text = nil; } + return self; } +- (void)dealloc { + [_text release]; + [_textView release], _textView = nil; + + [super dealloc]; +} -- (id)initWithDelegate:(id)delegate { - self = [self init]; - if (self) { - _delegate = delegate; + +#pragma mark - Public + +- (void)prepareWithItems:(NSArray *)items { + for (id item in items) { + if ([item isKindOfClass:[NSString class]]) { + self.text = [(self.text ? self.text : @"") stringByAppendingFormat:@"%@%@", (self.text ? @" " : @""), item]; + } else if ([item isKindOfClass:[NSURL class]]) { + self.text = [(self.text ? self.text : @"") stringByAppendingFormat:@"%@%@", (self.text ? @" " : @""), [(NSURL *)item absoluteString]]; + } else { + BITHockeyLog(@"Unknown item type %@", item); + } } - return self; } @@ -112,9 +132,14 @@ - (void)viewWillAppear:(BOOL)animated { [super viewWillAppear:animated]; - self.navigationItem.rightBarButtonItem.enabled = NO; - [[UIApplication sharedApplication] setStatusBarStyle:(self.navigationController.navigationBar.barStyle == UIBarStyleDefault) ? UIStatusBarStyleDefault : UIStatusBarStyleBlackOpaque]; + + if (_text) { + self.textView.text = _text; + self.navigationItem.rightBarButtonItem.enabled = YES; + } else { + self.navigationItem.rightBarButtonItem.enabled = NO; + } } - (void)viewDidAppear:(BOOL)animated { @@ -124,7 +149,7 @@ - (void)viewDidAppear:(BOOL)animated { ([self.manager requireManualUserDataMissing] || ![self.manager didAskUserData]) ) { - if (!blockUserDataScreen) + if (!_blockUserDataScreen) [self setUserDataAction]; } else { [self.textView becomeFirstResponder]; @@ -180,7 +205,7 @@ - (void)sendAction:(id)sender { #pragma mark - CNSFeedbackUserDataDelegate - (void)userDataUpdateCancelled { - blockUserDataScreen = YES; + _blockUserDataScreen = YES; if ([self.manager requireManualUserDataMissing]) { if ([self.navigationController respondsToSelector:@selector(dismissViewControllerAnimated:completion:)]) { diff --git a/Classes/BITFeedbackManager.h b/Classes/BITFeedbackManager.h index 64a73b09..1c80a660 100644 --- a/Classes/BITFeedbackManager.h +++ b/Classes/BITFeedbackManager.h @@ -87,10 +87,9 @@ typedef enum { /** Create an feedback compose view - @param modal Return a view ready for modal presentation with integrated navigation bar @return `BITFeedbackComposeViewController` The compose feedback view controller, e.g. to push it onto a navigation stack. */ -- (BITFeedbackComposeViewController *)feedbackComposeViewControllerWithDelegate:(id)delegate; +- (BITFeedbackComposeViewController *)feedbackComposeViewController; @end diff --git a/Classes/BITFeedbackManager.m b/Classes/BITFeedbackManager.m index f2e4cc9b..b5d20f0c 100644 --- a/Classes/BITFeedbackManager.m +++ b/Classes/BITFeedbackManager.m @@ -177,8 +177,8 @@ - (void)showFeedbackListView { } -- (BITFeedbackComposeViewController *)feedbackComposeViewControllerWithDelegate:(id)delegate { - return [[[BITFeedbackComposeViewController alloc] initWithDelegate:delegate] autorelease]; +- (BITFeedbackComposeViewController *)feedbackComposeViewController { + return [[[BITFeedbackComposeViewController alloc] init] autorelease]; } - (void)showFeedbackComposeView { @@ -187,7 +187,7 @@ - (void)showFeedbackComposeView { return; } - [self showView:[self feedbackComposeViewControllerWithDelegate:nil]]; + [self showView:[self feedbackComposeViewController]]; } From b486b8142c2ce4f96e2727033b736b7033fd55bf Mon Sep 17 00:00:00 2001 From: Andreas Linde Date: Thu, 18 Oct 2012 20:08:22 +0200 Subject: [PATCH 055/176] Add more helpers for getting app name and making a screenshot Screenshot is not yet used. --- Classes/BITFeedbackActivity.m | 4 +- Classes/BITHockeyHelper.h | 3 + Classes/BITHockeyHelper.m | 141 ++++++++++++++++++++++++++++++++-- Classes/BITUpdateManager.m | 4 +- 4 files changed, 140 insertions(+), 12 deletions(-) diff --git a/Classes/BITFeedbackActivity.m b/Classes/BITFeedbackActivity.m index d0007684..00e9dd6c 100644 --- a/Classes/BITFeedbackActivity.m +++ b/Classes/BITFeedbackActivity.m @@ -47,9 +47,7 @@ - (NSString *)activityType { } - (NSString *)activityTitle { - NSString *appName = [[[NSBundle mainBundle] localizedInfoDictionary] objectForKey:@"CFBundleDisplayName"]; - if (!appName) - appName = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleDisplayName"] ?: BITHockeyLocalizedString(@"HockeyFeedbackActivityAppPlaceholder"); + NSString *appName = bit_appName(); return [NSString stringWithFormat:BITHockeyLocalizedString(@"HockeyFeedbackActivityButtonTitle"), appName]; } diff --git a/Classes/BITHockeyHelper.h b/Classes/BITHockeyHelper.h index 6121ea40..a8ff3e3d 100644 --- a/Classes/BITHockeyHelper.h +++ b/Classes/BITHockeyHelper.h @@ -34,6 +34,7 @@ NSString *bit_URLEncodedString(NSString *inputString); NSString *bit_URLDecodedString(NSString *inputString); NSComparisonResult bit_versionCompare(NSString *stringA, NSString *stringB); NSString *bit_encodeAppIdentifier(NSString *inputString); +NSString *bit_appName(void); /* UIImage helpers */ UIImage *bit_roundedCornerImage(UIImage *inputImage, NSInteger cornerSize, NSInteger borderSize); @@ -43,3 +44,5 @@ UIImage *bit_reflectedImageWithHeight(UIImage *inputImage, NSUInteger height, fl UIImage *bit_newWithContentsOfResolutionIndependentFile(NSString * path); UIImage *bit_imageWithContentsOfResolutionIndependentFile(NSString * path); UIImage *bit_imageNamed(NSString *imageName, NSString *bundleName); +UIImage *bit_screenshot(void); +UIImage *bit_appIcon(void); diff --git a/Classes/BITHockeyHelper.m b/Classes/BITHockeyHelper.m index 73193d0d..e866ca6e 100644 --- a/Classes/BITHockeyHelper.m +++ b/Classes/BITHockeyHelper.m @@ -29,6 +29,8 @@ #import "BITHockeyHelper.h" #import "HockeySDK.h" +#import "HockeySDKPrivate.h" +#import #pragma mark NSString helpers @@ -80,6 +82,13 @@ NSComparisonResult bit_versionCompare(NSString *stringA, NSString *stringB) { return (inputString ? bit_URLEncodedString(inputString) : bit_URLEncodedString([[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleIdentifier"])); } +NSString *bit_appName(void) { + NSString *appName = [[[NSBundle mainBundle] localizedInfoDictionary] objectForKey:@"CFBundleDisplayName"]; + if (!appName) + appName = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleDisplayName"] ?: BITHockeyLocalizedString(@"HockeyFeedbackActivityAppPlaceholder"); + + return appName; +} #pragma mark UIImage private helpers @@ -89,6 +98,7 @@ NSComparisonResult bit_versionCompare(NSString *stringA, NSString *stringB) { static CGImageRef bit_CreateGradientImage(int pixelsWide, int pixelsHigh, float fromAlpha, float toAlpha); static BOOL bit_hasAlpha(UIImage *inputImage); UIImage *bit_imageWithAlpha(UIImage *inputImage); +UIImage *bit_addGlossToImage(UIImage *inputImage); // 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/ @@ -148,12 +158,7 @@ CGImageRef bit_CreateGradientImage(int pixelsWide, int pixelsHigh, float fromAlp CGContextRef bit_MyOpenBitmapContext(int pixelsWide, int pixelsHigh) { CGSize size = CGSizeMake(pixelsWide, pixelsHigh); - if (UIGraphicsBeginImageContextWithOptions != NULL) { - UIGraphicsBeginImageContextWithOptions(size, NO, 0.0); - } - else { - UIGraphicsBeginImageContext(size); - } + UIGraphicsBeginImageContextWithOptions(size, NO, 0.0); return UIGraphicsGetCurrentContext(); } @@ -199,6 +204,18 @@ BOOL bit_hasAlpha(UIImage *inputImage) { return imageWithAlpha; } +UIImage *bit_addGlossToImage(UIImage *inputImage) { + UIGraphicsBeginImageContextWithOptions(inputImage.size, NO, 0.0); + + [inputImage drawAtPoint:CGPointZero]; + UIImage *iconGradient = bit_imageNamed(@"IconGradient.png", BITHOCKEYSDK_BUNDLE); + [iconGradient drawInRect:CGRectMake(0, 0, inputImage.size.width, inputImage.size.height) blendMode:kCGBlendModeNormal alpha:0.5]; + + UIImage *result = UIGraphicsGetImageFromCurrentImageContext(); + UIGraphicsEndImageContext(); + + return result; +} #pragma mark UIImage helpers @@ -387,3 +404,115 @@ BOOL bit_hasAlpha(UIImage *inputImage) { return roundedImage; } + +UIImage *bit_appIcon() { + NSString *iconString = nil; + NSArray *icons = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleIconFiles"]; + if (!icons) { + icons = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleIcons"]; + if ((icons) && ([icons isKindOfClass:[NSDictionary class]])) { + icons = [icons valueForKeyPath:@"CFBundlePrimaryIcon.CFBundleIconFiles"]; + } + + if (!icons) { + iconString = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleIconFile"]; + if (!iconString) { + iconString = @"Icon.png"; + } + } + } + + if (icons) { + BOOL useHighResIcon = NO; + 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; + } + } + } + + BOOL addGloss = YES; + NSNumber *prerendered = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"UIPrerenderedIcon"]; + if (prerendered) { + addGloss = ![prerendered boolValue]; + } + + if (addGloss) { + return bit_addGlossToImage([UIImage imageNamed:iconString]); + } else { + return [UIImage imageNamed:iconString]; + } +} + +UIImage *bit_screenshot() { + // Create a graphics context with the target size + CGSize imageSize = [[UIScreen mainScreen] bounds].size; + BOOL isLandscapeLeft = [UIApplication sharedApplication].statusBarOrientation == UIInterfaceOrientationLandscapeLeft; + BOOL isLandscapeRight = [UIApplication sharedApplication].statusBarOrientation == UIInterfaceOrientationLandscapeRight; + BOOL isUpsideDown = [UIApplication sharedApplication].statusBarOrientation == UIInterfaceOrientationPortraitUpsideDown; + + if (isLandscapeLeft ||isLandscapeRight) { + CGFloat temp = imageSize.width; + imageSize.width = imageSize.height; + imageSize.height = temp; + } + + UIGraphicsBeginImageContextWithOptions(imageSize, NO, 0); + + CGContextRef context = UIGraphicsGetCurrentContext(); + + // Iterate over every window from back to front + //NSInteger count = 0; + for (UIWindow *window in [[UIApplication sharedApplication] windows]) { + if (![window respondsToSelector:@selector(screen)] || [window screen] == [UIScreen mainScreen]) { + // -renderInContext: renders in the coordinate space of the layer, + // so we must first apply the layer's geometry to the graphics context + CGContextSaveGState(context); + + // Center the context around the window's anchor point + CGContextTranslateCTM(context, [window center].x, [window center].y); + + // Apply the window's transform about the anchor point + CGContextConcatCTM(context, [window transform]); + + // Y-offset for the status bar (if it's showing) + NSInteger yOffset = [UIApplication sharedApplication].statusBarHidden ? 0 : -20; + + // Offset by the portion of the bounds left of and above the anchor point + CGContextTranslateCTM(context, + -[window bounds].size.width * [[window layer] anchorPoint].x, + -[window bounds].size.height * [[window layer] anchorPoint].y + yOffset); + + if (isLandscapeLeft) { + CGContextConcatCTM(context, CGAffineTransformRotate(CGAffineTransformMakeTranslation( imageSize.width, 0), M_PI / 2.0)); + } else if (isLandscapeRight) { + CGContextConcatCTM(context, CGAffineTransformRotate(CGAffineTransformMakeTranslation( 0, imageSize.height), 3 * M_PI / 2.0)); + } else if (isUpsideDown) { + CGContextConcatCTM(context, CGAffineTransformRotate(CGAffineTransformMakeTranslation( imageSize.width, imageSize.height), M_PI)); + } + + // Render the layer hierarchy to the current context + [[window layer] renderInContext:context]; + + // Restore the context + CGContextRestoreGState(context); + } + } + + // Retrieve the screenshot image + UIImage *image = UIGraphicsGetImageFromCurrentImageContext(); + + UIGraphicsEndImageContext(); + + return image; +} diff --git a/Classes/BITUpdateManager.m b/Classes/BITUpdateManager.m index e2fbd9d3..3545cb7a 100644 --- a/Classes/BITUpdateManager.m +++ b/Classes/BITUpdateManager.m @@ -138,9 +138,7 @@ - (void)checkExpiryDateReached { } if (shouldShowDefaultAlert) { - NSString *appName = [[[NSBundle mainBundle] localizedInfoDictionary] objectForKey:@"CFBundleDisplayName"]; - if (!appName) - appName = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleDisplayName"] ?: BITHockeyLocalizedString(@"HockeyAppNamePlaceholder"); + NSString *appName = bit_appName(); [self showBlockingScreen:[NSString stringWithFormat:BITHockeyLocalizedString(@"UpdateExpired"), appName] image:@"authorize_denied.png"]; if (self.delegate != nil && [self.delegate respondsToSelector:@selector(didDisplayExpiryAlertForUpdateManager:)]) { From 4ac8c6e7a85623b79a67a16f6af953182fc85bdf Mon Sep 17 00:00:00 2001 From: Andreas Linde Date: Fri, 19 Oct 2012 00:25:35 +0200 Subject: [PATCH 056/176] Fix rotation issues with Feedback list view --- Classes/BITFeedbackComposeViewController.m | 70 ++++++++++++++++++--- Classes/BITFeedbackListViewCell.m | 1 + Classes/BITFeedbackListViewController.m | 18 +++++- Classes/BITFeedbackUserDataViewController.m | 6 +- 4 files changed, 84 insertions(+), 11 deletions(-) diff --git a/Classes/BITFeedbackComposeViewController.m b/Classes/BITFeedbackComposeViewController.m index 93c29905..2f036691 100644 --- a/Classes/BITFeedbackComposeViewController.m +++ b/Classes/BITFeedbackComposeViewController.m @@ -93,6 +93,47 @@ - (void)prepareWithItems:(NSArray *)items { } +#pragma mark - Keyboard + +- (void)keyboardWasShown:(NSNotification*)aNotification { + NSDictionary* info = [aNotification userInfo]; + CGSize kbSize = [[info objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue].size; + + CGRect frame = CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height); + if (UI_USER_INTERFACE_IDIOM() != UIUserInterfaceIdiomPad) { + if (UIInterfaceOrientationIsPortrait(self.interfaceOrientation)) + frame.size.height -= kbSize.height; + else + frame.size.height -= kbSize.width; + } else { + CGSize windowSize = [[UIScreen mainScreen] bounds].size; + CGFloat windowHeight = windowSize.height - 20; + CGFloat navBarHeight = self.navigationController.navigationBar.frame.size.height; + + if (UIInterfaceOrientationIsPortrait(self.interfaceOrientation)) { + CGFloat modalGap = (windowHeight - self.view.bounds.size.height) / 2; + frame.size.height = windowHeight - navBarHeight - modalGap - kbSize.height; + } else { + windowHeight = windowSize.width - 20; + CGFloat modalGap = 0.0f; + if (windowHeight - kbSize.width < self.view.bounds.size.height) { + modalGap = 30; + } else { + modalGap = (windowHeight - self.view.bounds.size.height) / 2; + } + frame.size.height = windowSize.width - navBarHeight - modalGap - kbSize.width; + } + NSLog(@"%@", NSStringFromCGRect(frame)); + } + [self.textView setFrame:frame]; +} + +- (void)keyboardWillBeHidden:(NSNotification*)aNotification { + CGRect frame = CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height); + [self.textView setFrame:frame]; +} + + #pragma mark - View lifecycle - (void)viewDidLoad { @@ -111,14 +152,7 @@ - (void)viewDidLoad { action:@selector(sendAction:)] autorelease]; // message input textfield - CGRect frame = CGRectZero; - - if (UI_USER_INTERFACE_IDIOM() != UIUserInterfaceIdiomPad) { - frame = CGRectMake(0, 0, self.view.bounds.size.width, 200); - } else { - frame = CGRectMake(0, 0, self.view.bounds.size.width, self.view.bounds.size.height); - } - self.textView = [[[UITextView alloc] initWithFrame:frame] autorelease]; + self.textView = [[[UITextView alloc] initWithFrame:self.view.frame] autorelease]; self.textView.font = [UIFont systemFontOfSize:17]; self.textView.delegate = self; self.textView.backgroundColor = [UIColor whiteColor]; @@ -128,12 +162,22 @@ - (void)viewDidLoad { } - (void)viewWillAppear:(BOOL)animated { + [[NSNotificationCenter defaultCenter] addObserver:self + selector:@selector(keyboardWasShown:) + name:UIKeyboardDidShowNotification object:nil]; + + [[NSNotificationCenter defaultCenter] addObserver:self + selector:@selector(keyboardWillBeHidden:) + name:UIKeyboardWillHideNotification object:nil]; + self.manager.currentFeedbackComposeViewController = self; [super viewWillAppear:animated]; [[UIApplication sharedApplication] setStatusBarStyle:(self.navigationController.navigationBar.barStyle == UIBarStyleDefault) ? UIStatusBarStyleDefault : UIStatusBarStyleBlackOpaque]; + [self.textView setFrame:self.view.frame]; + if (_text) { self.textView.text = _text; self.navigationItem.rightBarButtonItem.enabled = YES; @@ -157,6 +201,9 @@ - (void)viewDidAppear:(BOOL)animated { } - (void)viewWillDisappear:(BOOL)animated { + [[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardDidShowNotification object:nil]; + [[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardWillHideNotification object:nil]; + self.manager.currentFeedbackComposeViewController = nil; [super viewWillDisappear:animated]; @@ -167,6 +214,13 @@ - (void)viewDidDisappear:(BOOL)animated { } +#pragma mark - UIViewController Rotation + +- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)orientation { + return YES; +} + + #pragma mark - Private methods - (void)dismiss { diff --git a/Classes/BITFeedbackListViewCell.m b/Classes/BITFeedbackListViewCell.m index 51750e91..c2c41dfc 100644 --- a/Classes/BITFeedbackListViewCell.m +++ b/Classes/BITFeedbackListViewCell.m @@ -134,6 +134,7 @@ + (CGFloat) heightForRowWithMessage:(BITFeedbackMessage *)message tableViewWidth - (void)layoutSubviews { UIView *accessoryViewBackground = [[[UIView alloc] initWithFrame:CGRectMake(0, 2, self.frame.size.width * 2, self.frame.size.height - 2)] autorelease]; + accessoryViewBackground.autoresizingMask = UIViewAutoresizingFlexibleHeight; // colors if (_backgroundStyle == BITFeedbackListViewCellBackgroundStyleNormal) { diff --git a/Classes/BITFeedbackListViewController.m b/Classes/BITFeedbackListViewController.m index b2a69adc..21d3acc1 100644 --- a/Classes/BITFeedbackListViewController.m +++ b/Classes/BITFeedbackListViewController.m @@ -192,6 +192,7 @@ - (void)setUserDataAction:(id)sender { userController.delegate = self; UINavigationController *navController = [[[UINavigationController alloc] initWithRootViewController:userController] autorelease]; + navController.modalPresentationStyle = UIModalPresentationFormSheet; [self.navigationController presentModalViewController:navController animated:YES]; } @@ -249,6 +250,18 @@ -(void)userDataUpdateFinished { } +#pragma mark - UIViewController Rotation + +- (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration { + [self.tableView beginUpdates]; + [self.tableView endUpdates]; +} + +- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)orientation { + return YES; +} + + #pragma mark - Table view data source - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { @@ -331,6 +344,7 @@ - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(N [button setTitleColor:BUTTON_TEXTCOLOR forState:UIControlStateNormal]; [button setTitleShadowColor:BUTTON_TEXTCOLOR_SHADOW forState:UIControlStateNormal]; if (indexPath.section == 0) { + topGap += 22; if ([self.manager numberOfMessages] == 0) { [button setTitle:BITHockeyLocalizedString(@"HockeyFeedbackListButonWriteFeedback") forState:UIControlStateNormal]; } else { @@ -356,6 +370,7 @@ - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(N [button setTitle:title forState:UIControlStateNormal]; [button addTarget:self action:@selector(setUserDataAction:) forControlEvents:UIControlEventTouchUpInside]; } else { + topGap -= 6.0f; [button.layer setBackgroundColor:BUTTON_DELETE_BACKGROUNDCOLOR.CGColor]; [button setTitleColor:BUTTON_DELETE_TEXTCOLOR forState:UIControlStateNormal]; [button setTitleShadowColor:BUTTON_DELETE_TEXTCOLOR_SHADOW forState:UIControlStateNormal]; @@ -363,13 +378,14 @@ - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(N [button setTitle:BITHockeyLocalizedString(@"HockeyFeedbackListButonDeleteAllMessages") forState:UIControlStateNormal]; [button addTarget:self action:@selector(deleteAllMessagesAction:) forControlEvents:UIControlEventTouchUpInside]; } + [button setFrame: CGRectMake( 10.0f, topGap + 12.0f, self.view.frame.size.width - 20.0f, 42.0f)]; [cell addSubview:button]; // status label or shadow lines if (indexPath.section == 0) { - UILabel *statusLabel = [[[UILabel alloc] initWithFrame:CGRectMake(0, 59, self.view.frame.size.width, 28)] autorelease]; + UILabel *statusLabel = [[[UILabel alloc] initWithFrame:CGRectMake(0, 6, self.view.frame.size.width, 28)] autorelease]; statusLabel.font = [UIFont systemFontOfSize:10]; statusLabel.textColor = DEFAULT_TEXTCOLOR; diff --git a/Classes/BITFeedbackUserDataViewController.m b/Classes/BITFeedbackUserDataViewController.m index dae06618..1bcbda83 100644 --- a/Classes/BITFeedbackUserDataViewController.m +++ b/Classes/BITFeedbackUserDataViewController.m @@ -100,8 +100,10 @@ - (void)viewWillAppear:(BOOL)animated { self.navigationItem.rightBarButtonItem.enabled = [self allRequiredFieldsEntered]; } -- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation { - return (interfaceOrientation == UIInterfaceOrientationPortrait); +#pragma mark - UIViewController Rotation + +- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)orientation { + return YES; } #pragma mark - Private methods From f6f92d20272cf2f9f2fb1e5a31c078568087f5c8 Mon Sep 17 00:00:00 2001 From: Andreas Linde Date: Fri, 19 Oct 2012 00:34:34 +0200 Subject: [PATCH 057/176] Remove some pre-iOS 5 checks that are not needed any more --- Classes/BITHockeyBaseManager.m | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/Classes/BITHockeyBaseManager.m b/Classes/BITHockeyBaseManager.m index e7230993..e9d2164c 100644 --- a/Classes/BITHockeyBaseManager.m +++ b/Classes/BITHockeyBaseManager.m @@ -146,7 +146,7 @@ - (void)showView:(UIViewController *)viewController { UIWindow *visibleWindow = [self findVisibleWindow]; - if (parentViewController == nil && [UIWindow instancesRespondToSelector:@selector(rootViewController)]) { + if (parentViewController == nil) { parentViewController = [visibleWindow rootViewController]; } @@ -170,12 +170,10 @@ - (void)showView:(UIViewController *)viewController { _navController.modalPresentationStyle = _modalPresentationStyle; if (parentViewController) { - if ([_navController respondsToSelector:@selector(setModalTransitionStyle:)]) { - _navController.modalTransitionStyle = UIModalTransitionStyleCoverVertical; - } + _navController.modalTransitionStyle = UIModalTransitionStyleCoverVertical; // page sheet for the iPad - if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad && [_navController respondsToSelector:@selector(setModalPresentationStyle:)]) { + if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) { _navController.modalPresentationStyle = UIModalPresentationFormSheet; } From 3cb7a23bd0085273975b39b05f026f69efc73953 Mon Sep 17 00:00:00 2001 From: Andreas Linde Date: Fri, 19 Oct 2012 13:48:36 +0200 Subject: [PATCH 058/176] Various bug fixes --- Classes/BITFeedbackComposeViewController.m | 1 - Classes/BITFeedbackListViewCell.m | 1 + Classes/BITFeedbackListViewController.m | 7 ++++--- Classes/BITHockeyBaseManager.m | 2 +- 4 files changed, 6 insertions(+), 5 deletions(-) diff --git a/Classes/BITFeedbackComposeViewController.m b/Classes/BITFeedbackComposeViewController.m index 2f036691..6b3fe78b 100644 --- a/Classes/BITFeedbackComposeViewController.m +++ b/Classes/BITFeedbackComposeViewController.m @@ -123,7 +123,6 @@ - (void)keyboardWasShown:(NSNotification*)aNotification { } frame.size.height = windowSize.width - navBarHeight - modalGap - kbSize.width; } - NSLog(@"%@", NSStringFromCGRect(frame)); } [self.textView setFrame:frame]; } diff --git a/Classes/BITFeedbackListViewCell.m b/Classes/BITFeedbackListViewCell.m index c2c41dfc..ec5d2a93 100644 --- a/Classes/BITFeedbackListViewCell.m +++ b/Classes/BITFeedbackListViewCell.m @@ -135,6 +135,7 @@ + (CGFloat) heightForRowWithMessage:(BITFeedbackMessage *)message tableViewWidth - (void)layoutSubviews { UIView *accessoryViewBackground = [[[UIView alloc] initWithFrame:CGRectMake(0, 2, self.frame.size.width * 2, self.frame.size.height - 2)] autorelease]; accessoryViewBackground.autoresizingMask = UIViewAutoresizingFlexibleHeight; + accessoryViewBackground.clipsToBounds = YES; // colors if (_backgroundStyle == BITFeedbackListViewCellBackgroundStyleNormal) { diff --git a/Classes/BITFeedbackListViewController.m b/Classes/BITFeedbackListViewController.m index 21d3acc1..f320c0a1 100644 --- a/Classes/BITFeedbackListViewController.m +++ b/Classes/BITFeedbackListViewController.m @@ -194,7 +194,7 @@ - (void)setUserDataAction:(id)sender { UINavigationController *navController = [[[UINavigationController alloc] initWithRootViewController:userController] autorelease]; navController.modalPresentationStyle = UIModalPresentationFormSheet; - [self.navigationController presentModalViewController:navController animated:YES]; + [self presentViewController:navController animated:YES completion:nil]; } - (void)newFeedbackAction:(id)sender { @@ -203,7 +203,7 @@ - (void)newFeedbackAction:(id)sender { UINavigationController *navController = [[[UINavigationController alloc] initWithRootViewController:composeController] autorelease]; navController.modalPresentationStyle = UIModalPresentationFormSheet; - [self.navigationController presentModalViewController:navController animated:YES]; + [self presentViewController:navController animated:YES completion:nil]; } - (void)deleteAllMessages { @@ -334,6 +334,7 @@ - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(N // button UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom]; + button.autoresizingMask = UIViewAutoresizingFlexibleWidth; [button.layer setMasksToBounds:YES]; [button.layer setCornerRadius:10.0f]; [button.layer setBorderWidth:1]; @@ -379,7 +380,7 @@ - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(N [button addTarget:self action:@selector(deleteAllMessagesAction:) forControlEvents:UIControlEventTouchUpInside]; } - [button setFrame: CGRectMake( 10.0f, topGap + 12.0f, self.view.frame.size.width - 20.0f, 42.0f)]; + [button setFrame: CGRectMake( 10.0f, topGap + 12.0f, cell.contentView.bounds.size.width - 20.0f, 42.0f)]; [cell addSubview:button]; diff --git a/Classes/BITHockeyBaseManager.m b/Classes/BITHockeyBaseManager.m index e9d2164c..d255b88c 100644 --- a/Classes/BITHockeyBaseManager.m +++ b/Classes/BITHockeyBaseManager.m @@ -180,7 +180,7 @@ - (void)showView:(UIViewController *)viewController { if ([viewController isKindOfClass:[BITHockeyBaseViewController class]]) [(BITHockeyBaseViewController *)viewController setModalAnimated:YES]; - [parentViewController presentModalViewController:_navController animated:YES]; + [parentViewController presentViewController:_navController animated:YES completion:nil]; } else { // if not, we add a subview to the window. A bit hacky but should work in most circumstances. // Also, we don't get a nice animation for free, but hey, this is for beta not production users ;) From e6d76ca364dc0fa1c987c0282e26b2b4e47dc0c0 Mon Sep 17 00:00:00 2001 From: Andreas Linde Date: Fri, 19 Oct 2012 13:49:01 +0200 Subject: [PATCH 059/176] Use the proper default app name in the Update View Controller --- Classes/BITHockeyHelper.m | 3 +++ Classes/BITUpdateManager.m | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/Classes/BITHockeyHelper.m b/Classes/BITHockeyHelper.m index e866ca6e..f1c246e0 100644 --- a/Classes/BITHockeyHelper.m +++ b/Classes/BITHockeyHelper.m @@ -87,6 +87,9 @@ NSComparisonResult bit_versionCompare(NSString *stringA, NSString *stringB) { if (!appName) appName = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleDisplayName"] ?: BITHockeyLocalizedString(@"HockeyFeedbackActivityAppPlaceholder"); + if (!appName) + appName = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleName"]; + return appName; } diff --git a/Classes/BITUpdateManager.m b/Classes/BITUpdateManager.m index 3545cb7a..b7a752d2 100644 --- a/Classes/BITUpdateManager.m +++ b/Classes/BITUpdateManager.m @@ -940,7 +940,7 @@ - (void)setAppVersions:(NSArray *)anAppVersions { // populate with default values (if empty) if (![anAppVersions count]) { BITAppVersionMetaInfo *defaultApp = [[[BITAppVersionMetaInfo alloc] init] autorelease]; - defaultApp.name = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleName"]; + defaultApp.name = bit_appName(); defaultApp.version = _currentAppVersion; defaultApp.shortVersion = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleShortVersionString"]; _appVersions = [[NSArray arrayWithObject:defaultApp] retain]; From 59a0319ea952166b2d342eb83d0f64fbf9b7ee90 Mon Sep 17 00:00:00 2001 From: Andreas Linde Date: Fri, 19 Oct 2012 17:18:10 +0200 Subject: [PATCH 060/176] Update appName handling --- Classes/BITCrashManager.m | 5 ++--- Classes/BITFeedbackActivity.m | 2 +- Classes/BITHockeyHelper.h | 2 +- Classes/BITHockeyHelper.m | 7 ++----- Classes/BITUpdateManager.m | 4 ++-- 5 files changed, 8 insertions(+), 12 deletions(-) diff --git a/Classes/BITCrashManager.m b/Classes/BITCrashManager.m index a9574c87..0e49ad81 100644 --- a/Classes/BITCrashManager.m +++ b/Classes/BITCrashManager.m @@ -33,6 +33,7 @@ #import #import "HockeySDK.h" #import "HockeySDKPrivate.h" +#import "BITHockeyHelper.h" #import "BITHockeyManagerPrivate.h" #import "BITHockeyBaseManagerPrivate.h" @@ -444,9 +445,7 @@ - (void)invokeDelayedProcessing { [self.delegate crashManagerWillShowSubmitCrashReportAlert:self]; } - NSString *appName = [[[NSBundle mainBundle] localizedInfoDictionary] objectForKey:@"CFBundleDisplayName"]; - if (!appName) - appName = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleDisplayName"] ?: BITHockeyLocalizedString(@"HockeyAppNamePlaceholder"); + NSString *appName = bit_appName(BITHockeyLocalizedString(@"HockeyAppNamePlaceholder")); NSString *alertDescription = [NSString stringWithFormat:BITHockeyLocalizedString(@"CrashDataFoundAnonymousDescription"), appName]; // the crash report is not anynomous any more if username or useremail are not nil diff --git a/Classes/BITFeedbackActivity.m b/Classes/BITFeedbackActivity.m index 00e9dd6c..2277eb67 100644 --- a/Classes/BITFeedbackActivity.m +++ b/Classes/BITFeedbackActivity.m @@ -47,7 +47,7 @@ - (NSString *)activityType { } - (NSString *)activityTitle { - NSString *appName = bit_appName(); + NSString *appName = bit_appName(BITHockeyLocalizedString(@"HockeyFeedbackActivityAppPlaceholder")); return [NSString stringWithFormat:BITHockeyLocalizedString(@"HockeyFeedbackActivityButtonTitle"), appName]; } diff --git a/Classes/BITHockeyHelper.h b/Classes/BITHockeyHelper.h index a8ff3e3d..a5bb5a8b 100644 --- a/Classes/BITHockeyHelper.h +++ b/Classes/BITHockeyHelper.h @@ -34,7 +34,7 @@ NSString *bit_URLEncodedString(NSString *inputString); NSString *bit_URLDecodedString(NSString *inputString); NSComparisonResult bit_versionCompare(NSString *stringA, NSString *stringB); NSString *bit_encodeAppIdentifier(NSString *inputString); -NSString *bit_appName(void); +NSString *bit_appName(NSString *placeHolderString); /* UIImage helpers */ UIImage *bit_roundedCornerImage(UIImage *inputImage, NSInteger cornerSize, NSInteger borderSize); diff --git a/Classes/BITHockeyHelper.m b/Classes/BITHockeyHelper.m index f1c246e0..7f555df9 100644 --- a/Classes/BITHockeyHelper.m +++ b/Classes/BITHockeyHelper.m @@ -82,13 +82,10 @@ NSComparisonResult bit_versionCompare(NSString *stringA, NSString *stringB) { return (inputString ? bit_URLEncodedString(inputString) : bit_URLEncodedString([[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleIdentifier"])); } -NSString *bit_appName(void) { +NSString *bit_appName(NSString *placeHolderString) { NSString *appName = [[[NSBundle mainBundle] localizedInfoDictionary] objectForKey:@"CFBundleDisplayName"]; if (!appName) - appName = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleDisplayName"] ?: BITHockeyLocalizedString(@"HockeyFeedbackActivityAppPlaceholder"); - - if (!appName) - appName = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleName"]; + appName = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleDisplayName"] ?: placeHolderString; return appName; } diff --git a/Classes/BITUpdateManager.m b/Classes/BITUpdateManager.m index b7a752d2..43ea0734 100644 --- a/Classes/BITUpdateManager.m +++ b/Classes/BITUpdateManager.m @@ -138,7 +138,7 @@ - (void)checkExpiryDateReached { } if (shouldShowDefaultAlert) { - NSString *appName = bit_appName(); + NSString *appName = bit_appName(BITHockeyLocalizedString(@"HockeyAppNamePlaceholder")); [self showBlockingScreen:[NSString stringWithFormat:BITHockeyLocalizedString(@"UpdateExpired"), appName] image:@"authorize_denied.png"]; if (self.delegate != nil && [self.delegate respondsToSelector:@selector(didDisplayExpiryAlertForUpdateManager:)]) { @@ -940,7 +940,7 @@ - (void)setAppVersions:(NSArray *)anAppVersions { // populate with default values (if empty) if (![anAppVersions count]) { BITAppVersionMetaInfo *defaultApp = [[[BITAppVersionMetaInfo alloc] init] autorelease]; - defaultApp.name = bit_appName(); + defaultApp.name = bit_appName(BITHockeyLocalizedString(@"HockeyAppNamePlaceholder")); defaultApp.version = _currentAppVersion; defaultApp.shortVersion = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleShortVersionString"]; _appVersions = [[NSArray arrayWithObject:defaultApp] retain]; From ed63a5a7b9f0357e4d22d8920158534588b6ee03 Mon Sep 17 00:00:00 2001 From: Andreas Linde Date: Fri, 19 Oct 2012 17:34:23 +0200 Subject: [PATCH 061/176] Send userID as extra value in crash reports and feedback if available --- Classes/BITCrashManager.m | 39 +++++++++++++++++------------ Classes/BITFeedbackManager.m | 33 +++++++++++++++++++++++- Classes/BITFeedbackManagerPrivate.h | 1 + Classes/BITFeedbackMessage.h | 1 + Classes/BITFeedbackMessage.m | 4 +++ Classes/BITHockeyManagerDelegate.h | 33 ++++++++++++++++++++---- 6 files changed, 89 insertions(+), 22 deletions(-) diff --git a/Classes/BITCrashManager.m b/Classes/BITCrashManager.m index 0e49ad81..1a9c3d57 100644 --- a/Classes/BITCrashManager.m +++ b/Classes/BITCrashManager.m @@ -48,6 +48,7 @@ // keys for meta information associated to each crash #define kBITCrashMetaUserName @"BITCrashMetaUserName" #define kBITCrashMetaUserEmail @"BITCrashMetaUserEmail" +#define kBITCrashMetaUserID @"BITCrashMetaUserID" #define kBITCrashMetaApplicationLog @"BITCrashMetaApplicationLog" @@ -79,14 +80,6 @@ @implementation BITCrashManager { NSUncaughtExceptionHandler *_exceptionHandler; } -@synthesize delegate = _delegate; -@synthesize crashManagerStatus = _crashManagerStatus; -@synthesize showAlwaysButton = _showAlwaysButton; -@synthesize didCrashInLastSession = _didCrashInLastSession; -@synthesize timeintervalCrashInLastSessionOccured = _timeintervalCrashInLastSessionOccured; - -@synthesize fileManager = _fileManager; - - (id)init { if ((self = [super init])) { @@ -265,6 +258,19 @@ - (NSString *)getDevicePlatform { } +- (NSString *)userIDForCrashReport { + NSString *userID = @""; + + if ([BITHockeyManager sharedHockeyManager].delegate && + [[BITHockeyManager sharedHockeyManager].delegate respondsToSelector:@selector(userIDForHockeyManager:componentManager:)]) { + userID = [[BITHockeyManager sharedHockeyManager].delegate + userIDForHockeyManager:[BITHockeyManager sharedHockeyManager] + componentManager:self]; + } + + return userID; +} + - (NSString *)userNameForCrashReport { NSString *username = @""; @@ -279,12 +285,6 @@ - (NSString *)userNameForCrashReport { userNameForHockeyManager:[BITHockeyManager sharedHockeyManager] componentManager:self]; } - if ([BITHockeyManager sharedHockeyManager].delegate && - [[BITHockeyManager sharedHockeyManager].delegate respondsToSelector:@selector(userIDForHockeyManager:componentManager:)]) { - username = [[BITHockeyManager sharedHockeyManager].delegate - userIDForHockeyManager:[BITHockeyManager sharedHockeyManager] - componentManager:self]; - } return username; } @@ -340,6 +340,7 @@ - (void) handleCrashReport { [metaDict setObject:[self userNameForCrashReport] forKey:kBITCrashMetaUserName]; [metaDict setObject:[self userEmailForCrashReport] forKey:kBITCrashMetaUserEmail]; + [metaDict setObject:[self userIDForCrashReport] forKey:kBITCrashMetaUserID]; if (self.delegate != nil && [self.delegate respondsToSelector:@selector(applicationLogForCrashManager:)]) { applicationLog = [self.delegate applicationLogForCrashManager:self] ?: @""; @@ -449,10 +450,13 @@ - (void)invokeDelayedProcessing { NSString *alertDescription = [NSString stringWithFormat:BITHockeyLocalizedString(@"CrashDataFoundAnonymousDescription"), appName]; // the crash report is not anynomous any more if username or useremail are not nil + NSString *userid = [self userIDForCrashReport]; NSString *username = [self userNameForCrashReport]; NSString *useremail = [self userEmailForCrashReport]; - if ((username && [username length] > 0) || (useremail && [useremail length] > 0)) { + if ((userid && [userid length] > 0) || + (username && [username length] > 0) || + (useremail && [useremail length] > 0)) { alertDescription = [NSString stringWithFormat:BITHockeyLocalizedString(@"CrashDataFoundDescription"), appName]; } @@ -581,6 +585,7 @@ - (void)performSendingCrashReports { NSString *username = @""; NSString *useremail = @""; + NSString *userid = @""; NSString *applicationLog = @""; NSString *description = @""; @@ -597,6 +602,7 @@ - (void)performSendingCrashReports { username = [metaDict objectForKey:kBITCrashMetaUserName] ?: @""; useremail = [metaDict objectForKey:kBITCrashMetaUserEmail] ?: @""; + userid = [metaDict objectForKey:kBITCrashMetaUserID] ?: @""; applicationLog = [metaDict objectForKey:kBITCrashMetaApplicationLog] ?: @""; } else { BITHockeyLog(@"ERROR: Reading crash meta data. %@", error); @@ -606,7 +612,7 @@ - (void)performSendingCrashReports { description = [NSString stringWithFormat:@"%@", applicationLog]; } - [crashes appendFormat:@"%s%@%@%@%@%@%@%@%@%@", + [crashes appendFormat:@"%s%@%@%@%@%@%@%@%@%@%@", [[[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleExecutable"] UTF8String], [self extractAppUUIDs:report], report.applicationInfo.applicationIdentifier, @@ -616,6 +622,7 @@ - (void)performSendingCrashReports { report.applicationInfo.applicationVersion, crashUUID, [crashLogString stringByReplacingOccurrencesOfString:@"]]>" withString:@"]]" @"]]>" options:NSLiteralSearch range:NSMakeRange(0,crashLogString.length)], + userid, username, useremail, [description stringByReplacingOccurrencesOfString:@"]]>" withString:@"]]" @"]]>" options:NSLiteralSearch range:NSMakeRange(0,description.length)]]; diff --git a/Classes/BITFeedbackManager.m b/Classes/BITFeedbackManager.m index b5d20f0c..a483b83d 100644 --- a/Classes/BITFeedbackManager.m +++ b/Classes/BITFeedbackManager.m @@ -43,6 +43,7 @@ #define kBITFeedbackDateOfLastCheck @"HockeyFeedbackDateOfLastCheck" #define kBITFeedbackMessages @"HockeyFeedbackMessages" #define kBITFeedbackToken @"HockeyFeedbackToken" +#define kBITFeedbackUserID @"HockeyFeedbackuserID" #define kBITFeedbackName @"HockeyFeedbackName" #define kBITFeedbackEmail @"HockeyFeedbackEmail" #define kBITFeedbackLastMessageID @"HockeyFeedbackLastMessageID" @@ -95,7 +96,7 @@ - (id)init { _settingsFile = [[_feedbackDir stringByAppendingPathComponent:BITHOCKEY_FEEDBACK_SETTINGS] retain]; - + _userID = nil; _userName = nil; _userEmail = nil; } @@ -115,6 +116,7 @@ - (void)dealloc { [_lastMessageID release], _lastMessageID = nil; [_feedbackList release], _feedbackList = nil; + [_userID release], _userID = nil; [_userName release], _userName = nil; [_userEmail release], _userEmail = nil; @@ -223,6 +225,14 @@ - (void)updateMessagesListIfRequired { } - (void)updateAppDefinedUserData { + if ([BITHockeyManager sharedHockeyManager].delegate && + [[BITHockeyManager sharedHockeyManager].delegate respondsToSelector:@selector(userIDForHockeyManager:componentManager:)]) { + self.userID = [[BITHockeyManager sharedHockeyManager].delegate + userIDForHockeyManager:[BITHockeyManager sharedHockeyManager] + componentManager:self]; + self.requireUserName = BITFeedbackUserDataElementDontShow; + self.requireUserEmail = BITFeedbackUserDataElementDontShow; + } if ([BITHockeyManager sharedHockeyManager].delegate && [[BITHockeyManager sharedHockeyManager].delegate respondsToSelector:@selector(userNameForHockeyManager:componentManager:)]) { self.userName = [[BITHockeyManager sharedHockeyManager].delegate @@ -244,9 +254,17 @@ - (void)updateAppDefinedUserData { #pragma mark - Local Storage - (void)loadMessages { + BOOL userIDViaDelegate = NO; BOOL userNameViaDelegate = NO; BOOL userEmailViaDelegate = NO; + if ([BITHockeyManager sharedHockeyManager].delegate && + [[BITHockeyManager sharedHockeyManager].delegate respondsToSelector:@selector(userIDForHockeyManager:componentManager:)]) { + userIDViaDelegate = YES; + self.userID = [[BITHockeyManager sharedHockeyManager].delegate + userIDForHockeyManager:[BITHockeyManager sharedHockeyManager] + componentManager:self]; + } if ([BITHockeyManager sharedHockeyManager].delegate && [[BITHockeyManager sharedHockeyManager].delegate respondsToSelector:@selector(userNameForHockeyManager:componentManager:)]) { userNameViaDelegate = YES; @@ -281,6 +299,11 @@ - (void)loadMessages { return; } + if (!userIDViaDelegate) { + if ([unarchiver containsValueForKey:kBITFeedbackUserID]) + self.userID = [unarchiver decodeObjectForKey:kBITFeedbackUserID]; + } + if (!userNameViaDelegate) { if ([unarchiver containsValueForKey:kBITFeedbackName]) self.userName = [unarchiver decodeObjectForKey:kBITFeedbackName]; @@ -333,6 +356,9 @@ - (void)saveMessages { if (self.token) [archiver encodeObject:self.token forKey:kBITFeedbackToken]; + if (self.userID) + [archiver encodeObject:self.userID forKey:kBITFeedbackUserID]; + if (self.userName) [archiver encodeObject:self.userName forKey:kBITFeedbackName]; @@ -696,6 +722,9 @@ - (void)sendNetworkRequestWithHTTPMethod:(NSString *)httpMethod withMessage:(BIT [postBody appendData:[self appendPostValue:[message text] forKey:@"text"]]; [postBody appendData:[self appendPostValue:[message token] forKey:@"message_token"]]; + if (self.userID) { + [postBody appendData:[self appendPostValue:self.userID forKey:@"user_string"]]; + } if (self.userName) { [postBody appendData:[self appendPostValue:self.userName forKey:@"name"]]; } @@ -809,6 +838,8 @@ - (void)submitPendingMessages { BITFeedbackMessage *messageToSend = [pendingMessages objectAtIndex:0]; [messageToSend setStatus:BITFeedbackMessageStatusSendInProgress]; + if (self.userID) + [messageToSend setUserID:self.userID]; if (self.userName) [messageToSend setName:self.userName]; if (self.userEmail) diff --git a/Classes/BITFeedbackManagerPrivate.h b/Classes/BITFeedbackManagerPrivate.h index a907dc48..215a02ef 100644 --- a/Classes/BITFeedbackManagerPrivate.h +++ b/Classes/BITFeedbackManagerPrivate.h @@ -51,6 +51,7 @@ @property (nonatomic, retain) NSNumber *lastMessageID; +@property (nonatomic, copy) NSString *userID; @property (nonatomic, copy) NSString *userName; @property (nonatomic, copy) NSString *userEmail; diff --git a/Classes/BITFeedbackMessage.h b/Classes/BITFeedbackMessage.h index 4f8a5d9f..336bfc54 100644 --- a/Classes/BITFeedbackMessage.h +++ b/Classes/BITFeedbackMessage.h @@ -48,6 +48,7 @@ typedef enum { } @property (nonatomic, copy) NSString *text; +@property (nonatomic, copy) NSString *userID; @property (nonatomic, copy) NSString *name; @property (nonatomic, copy) NSString *email; @property (nonatomic, copy) NSDate *date; diff --git a/Classes/BITFeedbackMessage.m b/Classes/BITFeedbackMessage.m index 8fca1d70..f9e194fe 100644 --- a/Classes/BITFeedbackMessage.m +++ b/Classes/BITFeedbackMessage.m @@ -37,6 +37,7 @@ @implementation BITFeedbackMessage - (id) init { if ((self = [super init])) { _text = nil; + _userID = nil; _name = nil; _email = nil; _date = [[NSDate alloc] init]; @@ -50,6 +51,7 @@ - (id) init { - (void)dealloc { [_text release], _text = nil; + [_userID release], _userID = nil; [_name release], _name = nil; [_email release], _email = nil; [_date release], _date = nil; @@ -64,6 +66,7 @@ - (void)dealloc { - (void)encodeWithCoder:(NSCoder *)encoder { [encoder encodeObject:self.text forKey:@"text"]; + [encoder encodeObject:self.userID forKey:@"userID"]; [encoder encodeObject:self.name forKey:@"name"]; [encoder encodeObject:self.email forKey:@"email"]; [encoder encodeObject:self.date forKey:@"date"]; @@ -76,6 +79,7 @@ - (void)encodeWithCoder:(NSCoder *)encoder { - (id)initWithCoder:(NSCoder *)decoder { if ((self = [super init])) { self.text = [decoder decodeObjectForKey:@"text"]; + self.userID = [decoder decodeObjectForKey:@"userID"]; self.name = [decoder decodeObjectForKey:@"name"]; self.email = [decoder decodeObjectForKey:@"email"]; self.date = [decoder decodeObjectForKey:@"date"]; diff --git a/Classes/BITHockeyManagerDelegate.h b/Classes/BITHockeyManagerDelegate.h index 032ca103..b33e77e4 100644 --- a/Classes/BITHockeyManagerDelegate.h +++ b/Classes/BITHockeyManagerDelegate.h @@ -78,7 +78,7 @@ behavior or if you want to define any other parent view controller. @param hockeyManager The `BITHockeyManager` HockeyManager instance invoking this delegate - @param componentManager The `BITHockeyBaseManager` component instance invoking this delegate + @param componentManager The `BITHockeyBaseManager` component instance invoking this delegate, can be `BITCrashManager` or `BITFeedbackManager` */ - (UIViewController *)viewControllerForHockeyManager:(BITHockeyManager *)hockeyManager componentManager:(BITHockeyBaseManager *)componentManager; @@ -90,10 +90,27 @@ /** Return the userid that should used in the SDK components - Right now this is only used by the `BITCrashMananger` to attach to a crash report. + Right now this is used by the `BITCrashMananger` to attach to a crash report. + `BITFeedbackManager` uses it too for assigning the user to a discussion thread. + + In addition, if this returns not nil for `BITFeedbackManager` the user will + not be asked for any user details by the component, including useerName or userEmail. + + You can find out the component requesting the user name like this: + - (NSString *)userNameForHockeyManager:(BITHockeyManager *)hockeyManager componentManager:(BITHockeyBaseManager *)componentManager { + if (componentManager == hockeyManager.feedbackManager) { + return UserNameForFeedback; + } else if (componentManager == hockeyManager.crashManager) { + return UserNameForCrashReports; + } else { + return nil; + } + } + + @param hockeyManager The `BITHockeyManager` HockeyManager instance invoking this delegate - @param componentManager The `BITHockeyBaseManager` component instance invoking this delegate + @param componentManager The `BITHockeyBaseManager` component instance invoking this delegate, can be `BITCrashManager` or `BITFeedbackManager` @see userNameForHockeyManager:componentManager: @see userEmailForHockeyManager:componentManager: @warning When returning a non nil value for the `BITCrashManager` component, crash reports @@ -107,6 +124,9 @@ Right now this is used by the `BITCrashMananger` to attach to a crash report. `BITFeedbackManager` uses it too for assigning the user to a discussion thread. + In addition, if this returns not nil for `BITFeedbackManager` the user will + not be asked for any user details by the component, including useerName or userEmail. + You can find out the component requesting the user name like this: - (NSString *)userNameForHockeyManager:(BITHockeyManager *)hockeyManager componentManager:(BITHockeyBaseManager *)componentManager { if (componentManager == hockeyManager.feedbackManager) { @@ -120,7 +140,7 @@ @param hockeyManager The `BITHockeyManager` HockeyManager instance invoking this delegate - @param componentManager The `BITHockeyBaseManager` component instance invoking this delegate + @param componentManager The `BITHockeyBaseManager` component instance invoking this delegate, can be `BITCrashManager` or `BITFeedbackManager` @see userIDForHockeyManager:componentManager: @see userEmailForHockeyManager:componentManager: @warning When returning a non nil value for the `BITCrashManager` component, crash reports @@ -134,6 +154,9 @@ Right now this is used by the `BITCrashMananger` to attach to a crash report. `BITFeedbackManager` uses it too for assigning the user to a discussion thread. + In addition, if this returns not nil for `BITFeedbackManager` the user will + not be asked for any user details by the component, including useerName or userEmail. + You can find out the component requesting the user name like this: - (NSString *)userNameForHockeyManager:(BITHockeyManager *)hockeyManager componentManager:(BITHockeyBaseManager *)componentManager { if (componentManager == hockeyManager.feedbackManager) { @@ -147,7 +170,7 @@ @param hockeyManager The `BITHockeyManager` HockeyManager instance invoking this delegate - @param componentManager The `BITHockeyBaseManager` component instance invoking this delegate + @param componentManager The `BITHockeyBaseManager` component instance invoking this delegate, can be `BITCrashManager` or `BITFeedbackManager` @see userIDForHockeyManager:componentManager: @see userNameForHockeyManager:componentManager: @warning When returning a non nil value for the `BITCrashManager` component, crash reports From 34f6e3faf454cea96504d3342b977af0db719c98 Mon Sep 17 00:00:00 2001 From: Andreas Linde Date: Fri, 19 Oct 2012 18:16:24 +0200 Subject: [PATCH 062/176] Add installationIDs to feedback and crash reports, so those can be linked together and amount of affected users of a crash can be determined Uses iOS 6 ASIdentifierManager class or identifierForVendor if the class is not available. Fallback on iOS 5 is to use app path UUID which is generated by iOS when installing the app --- Classes/BITCrashManager.m | 4 +++- Classes/BITFeedbackManager.m | 5 +++++ Classes/BITHockeyHelper.h | 1 + Classes/BITHockeyHelper.m | 26 ++++++++++++++++++++++++++ 4 files changed, 35 insertions(+), 1 deletion(-) diff --git a/Classes/BITCrashManager.m b/Classes/BITCrashManager.m index 1a9c3d57..af7fcc6f 100644 --- a/Classes/BITCrashManager.m +++ b/Classes/BITCrashManager.m @@ -588,6 +588,7 @@ - (void)performSendingCrashReports { NSString *userid = @""; NSString *applicationLog = @""; NSString *description = @""; + NSString *installString = bit_appAnonID() ?: @""; NSString *errorString = nil; NSPropertyListFormat format; @@ -612,7 +613,7 @@ - (void)performSendingCrashReports { description = [NSString stringWithFormat:@"%@", applicationLog]; } - [crashes appendFormat:@"%s%@%@%@%@%@%@%@%@%@%@", + [crashes appendFormat:@"%s%@%@%@%@%@%@%@%@%@%@%@", [[[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleExecutable"] UTF8String], [self extractAppUUIDs:report], report.applicationInfo.applicationIdentifier, @@ -625,6 +626,7 @@ - (void)performSendingCrashReports { userid, username, useremail, + installString, [description stringByReplacingOccurrencesOfString:@"]]>" withString:@"]]" @"]]>" options:NSLiteralSearch range:NSMakeRange(0,description.length)]]; diff --git a/Classes/BITFeedbackManager.m b/Classes/BITFeedbackManager.m index a483b83d..cf690b1b 100644 --- a/Classes/BITFeedbackManager.m +++ b/Classes/BITFeedbackManager.m @@ -722,6 +722,11 @@ - (void)sendNetworkRequestWithHTTPMethod:(NSString *)httpMethod withMessage:(BIT [postBody appendData:[self appendPostValue:[message text] forKey:@"text"]]; [postBody appendData:[self appendPostValue:[message token] forKey:@"message_token"]]; + NSString *installString = bit_appAnonID(); + if (installString) { + [postBody appendData:[self appendPostValue:installString forKey:@"install_string"]]; + } + if (self.userID) { [postBody appendData:[self appendPostValue:self.userID forKey:@"user_string"]]; } diff --git a/Classes/BITHockeyHelper.h b/Classes/BITHockeyHelper.h index a5bb5a8b..b9b484ff 100644 --- a/Classes/BITHockeyHelper.h +++ b/Classes/BITHockeyHelper.h @@ -35,6 +35,7 @@ NSString *bit_URLDecodedString(NSString *inputString); NSComparisonResult bit_versionCompare(NSString *stringA, NSString *stringB); NSString *bit_encodeAppIdentifier(NSString *inputString); NSString *bit_appName(NSString *placeHolderString); +NSString *bit_appAnonID(void); /* UIImage helpers */ UIImage *bit_roundedCornerImage(UIImage *inputImage, NSInteger cornerSize, NSInteger borderSize); diff --git a/Classes/BITHockeyHelper.m b/Classes/BITHockeyHelper.m index 7f555df9..2cdde76c 100644 --- a/Classes/BITHockeyHelper.m +++ b/Classes/BITHockeyHelper.m @@ -90,6 +90,32 @@ NSComparisonResult bit_versionCompare(NSString *stringA, NSString *stringB) { return appName; } +NSString *bit_appAnonID(void) { + // try to new iOS6 identifierForAdvertising + Class advertisingClass = NSClassFromString(@"ASIdentifierManager"); + if (advertisingClass) { + id adInstance = [advertisingClass performSelector:NSSelectorFromString(@"sharedManager")]; + + SEL adidSelector = NSSelectorFromString(@"advertisingIdentifier"); + return [[adInstance performSelector:adidSelector] performSelector:NSSelectorFromString(@"UUIDString")]; + } + + // try to new iOS6 identifierForVendor, in case ASIdentifierManager is not linked + SEL vendoridSelector = NSSelectorFromString(@"identifierForVendor"); + if ([[UIDevice currentDevice] respondsToSelector:vendoridSelector]) { + return [[[UIDevice currentDevice] performSelector:vendoridSelector] performSelector:NSSelectorFromString(@"UUIDString")]; + } + + // use app bundle path + NSArray *pathComponents = [[[NSBundle mainBundle] bundlePath] pathComponents]; + + if ([pathComponents count] > 1) { + return [pathComponents objectAtIndex:(pathComponents.count - 2)]; + } + + return nil; +} + #pragma mark UIImage private helpers From b9a6369ed22c523efde70f463db221a4b049a7b0 Mon Sep 17 00:00:00 2001 From: Andreas Linde Date: Fri, 19 Oct 2012 19:18:39 +0200 Subject: [PATCH 063/176] Don't force iOS6 AdSupport framework into the app The developer should be able to freely opt-in, not be forced to opt-out --- Support/HockeySDK.xcconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Support/HockeySDK.xcconfig b/Support/HockeySDK.xcconfig index 4b4654c4..f04fd8b4 100644 --- a/Support/HockeySDK.xcconfig +++ b/Support/HockeySDK.xcconfig @@ -1,3 +1,3 @@ -OTHER_LDFLAGS=$(inherited) -ObjC -framework CoreText -framework CoreGraphics -framework Foundation -framework QuartzCore -framework SystemConfiguration -weak_framework AdSupport -weak_framework UIKit +OTHER_LDFLAGS=$(inherited) -ObjC -framework CoreText -framework CoreGraphics -framework Foundation -framework QuartzCore -framework SystemConfiguration -weak_framework UIKit HOCKEYSDK_DOCSET_NAME=HockeySDK-iOS GCC_PREPROCESSOR_DEFINITIONS=$(inherited) CONFIGURATION_$(CONFIGURATION) \ No newline at end of file From 1bc0c2db6431b75b4cb290488d84b98d73e5d884 Mon Sep 17 00:00:00 2001 From: Andreas Linde Date: Fri, 19 Oct 2012 20:42:56 +0200 Subject: [PATCH 064/176] Allow BITFeedbackActivity title and image to be customized --- Classes/BITFeedbackActivity.m | 6 ++++++ Classes/BITFeedbackManager.h | 26 ++++++++++++++++++++++++++ Classes/BITFeedbackManager.m | 6 ++++++ 3 files changed, 38 insertions(+) diff --git a/Classes/BITFeedbackActivity.m b/Classes/BITFeedbackActivity.m index 2277eb67..02315334 100644 --- a/Classes/BITFeedbackActivity.m +++ b/Classes/BITFeedbackActivity.m @@ -47,12 +47,18 @@ - (NSString *)activityType { } - (NSString *)activityTitle { + if ([BITHockeyManager sharedHockeyManager].feedbackManager.activityTitle) + return [BITHockeyManager sharedHockeyManager].feedbackManager.activityTitle; + NSString *appName = bit_appName(BITHockeyLocalizedString(@"HockeyFeedbackActivityAppPlaceholder")); return [NSString stringWithFormat:BITHockeyLocalizedString(@"HockeyFeedbackActivityButtonTitle"), appName]; } - (UIImage *)activityImage { + if ([BITHockeyManager sharedHockeyManager].feedbackManager.activityImage) + return [BITHockeyManager sharedHockeyManager].feedbackManager.activityImage; + return bit_imageNamed(@"feedbackActiviy.png", BITHOCKEYSDK_BUNDLE); } diff --git a/Classes/BITFeedbackManager.h b/Classes/BITFeedbackManager.h index 1c80a660..7d1e8ce4 100644 --- a/Classes/BITFeedbackManager.h +++ b/Classes/BITFeedbackManager.h @@ -92,4 +92,30 @@ typedef enum { */ - (BITFeedbackComposeViewController *)feedbackComposeViewController; + +///----------------------------------------------------------------------------- +/// @name BITFeedbackActivity settings +///----------------------------------------------------------------------------- + + +/** + Define the image shown when using `BITFeedbackActivity` + + If not set a default icon is being used. + + @see activityTitle + */ +@property (nonatomic, retain) UIImage *activityImage; + + +/** + Define the title shown when using `BITFeedbackActivity` + + If not set, a default string is shown by using the apps name + and adding the localized string "Feedback" to it. + + @see activityImage + */ +@property (nonatomic, retain) NSString *activityTitle; + @end diff --git a/Classes/BITFeedbackManager.m b/Classes/BITFeedbackManager.m index cf690b1b..0e096fbf 100644 --- a/Classes/BITFeedbackManager.m +++ b/Classes/BITFeedbackManager.m @@ -79,6 +79,9 @@ - (id)init { _token = nil; _lastMessageID = nil; + _activityImage = nil; + _activityTitle = nil; + self.feedbackList = [NSMutableArray array]; _fileManager = [[NSFileManager alloc] init]; @@ -124,6 +127,9 @@ - (void)dealloc { [_feedbackDir release], _feedbackDir = nil; [_settingsFile release], _settingsFile = nil; + [_activityImage release]; + [_activityTitle release]; + [super dealloc]; } From 8120d9b2e48aacc1e440ea4e3cf36479274b786f Mon Sep 17 00:00:00 2001 From: Andreas Linde Date: Fri, 19 Oct 2012 20:43:12 +0200 Subject: [PATCH 065/176] Improve BITFeedbackManager public header documentation --- Classes/BITFeedbackManager.h | 41 ++++++++++++++++++++++++++++++++++-- 1 file changed, 39 insertions(+), 2 deletions(-) diff --git a/Classes/BITFeedbackManager.h b/Classes/BITFeedbackManager.h index 7d1e8ce4..485f7d43 100644 --- a/Classes/BITFeedbackManager.h +++ b/Classes/BITFeedbackManager.h @@ -53,9 +53,46 @@ typedef enum { @interface BITFeedbackManager : BITHockeyBaseManager -@property (nonatomic, readwrite) BITFeedbackUserDataElement requireUserName; // default is BITFeedbackUserDataElementOptional +///----------------------------------------------------------------------------- +/// @name General settings +///----------------------------------------------------------------------------- + + +/** + Define if a name has to be provided by the user when providing feedback + + - `BITFeedbackUserDataElementDontShow`: Don't ask for this user data element at all + - `BITFeedbackUserDataElementOptional`: The user may provide it, but does not have to + - `BITFeedbackUserDataElementRequired`: The user has to provide this to continue + + The default value is `BITFeedbackUserDataElementOptional`. + */ +@property (nonatomic, readwrite) BITFeedbackUserDataElement requireUserName; + + +/** + Define if an email address has to be provided by the user when providing feedback + + - `BITFeedbackUserDataElementDontShow`: Don't ask for this user data element at all + - `BITFeedbackUserDataElementOptional`: The user may provide it, but does not have to + - `BITFeedbackUserDataElementRequired`: The user has to provide this to continue + + The default value is `BITFeedbackUserDataElementOptional`. + */ @property (nonatomic, readwrite) BITFeedbackUserDataElement requireUserEmail; // default is BITFeedbackUserDataElementOptional -@property (nonatomic, readwrite) BOOL showAlertOnIncomingMessages; // default is YES + + +/** + Indicates if an alert should be shown when new messages arrived + + This lets the user to view the new feedback by choosing the appropriate option + in the alert sheet, and the `BITFeedbackListViewController` will be shown. + + Default is `YES` + @see feedbackListViewController: + */ +@property (nonatomic, readwrite) BOOL showAlertOnIncomingMessages; + ///----------------------------------------------------------------------------- /// @name User Interface From 0fe87cf8c081739dd4b1528976bfc0794561a47b Mon Sep 17 00:00:00 2001 From: Andreas Linde Date: Fri, 19 Oct 2012 21:11:22 +0200 Subject: [PATCH 066/176] Move BITFeedbackActivity customization out from BITFeedbackManager Also add first documentation parts --- Classes/BITFeedbackActivity.h | 40 +++++++++++++++++++++++++++++++++++ Classes/BITFeedbackActivity.m | 14 ++++++++---- Classes/BITFeedbackManager.h | 25 ---------------------- Classes/BITFeedbackManager.m | 6 ------ 4 files changed, 50 insertions(+), 35 deletions(-) diff --git a/Classes/BITFeedbackActivity.h b/Classes/BITFeedbackActivity.h index e6657b67..165235c8 100644 --- a/Classes/BITFeedbackActivity.h +++ b/Classes/BITFeedbackActivity.h @@ -10,6 +10,46 @@ #import "BITFeedbackComposeViewControllerDelegate.h" +/** + UIActivity subclass allowing to use the feedback interface to share content with the developer + + This activity can be added into an UIActivityViewController and it will use the activity data + objects to prefill the content of `BITFeedbackComposeViewController`. + + This can be useful if you present some data that users can not only share but also + report back to the developer because they have some problems, e.g. webcams not working + any more. + + The activity provide a default title and image that can be further customized + via `customActivityImage` and `customActivityTitle`. + + */ + @interface BITFeedbackActivity : UIActivity +///----------------------------------------------------------------------------- +/// @name BITFeedbackActivity customisation +///----------------------------------------------------------------------------- + + +/** + Define the image shown when using `BITFeedbackActivity` + + If not set a default icon is being used. + + @see customActivityTitle + */ +@property (nonatomic, retain) UIImage *customActivityImage; + + +/** + Define the title shown when using `BITFeedbackActivity` + + If not set, a default string is shown by using the apps name + and adding the localized string "Feedback" to it. + + @see customActivityImage + */ +@property (nonatomic, retain) NSString *customActivityTitle; + @end diff --git a/Classes/BITFeedbackActivity.m b/Classes/BITFeedbackActivity.m index 02315334..dd96b6ba 100644 --- a/Classes/BITFeedbackActivity.m +++ b/Classes/BITFeedbackActivity.m @@ -27,6 +27,9 @@ @implementation BITFeedbackActivity - (id)init { if ((self = [super init])) { + _customActivityImage = nil; + _customActivityTitle = nil; + self.items = [NSMutableArray array];; } @@ -36,6 +39,9 @@ - (id)init { - (void)dealloc { [_items release]; _items = nil; + [_customActivityImage release]; + [_customActivityTitle release]; + [super dealloc]; } @@ -47,8 +53,8 @@ - (NSString *)activityType { } - (NSString *)activityTitle { - if ([BITHockeyManager sharedHockeyManager].feedbackManager.activityTitle) - return [BITHockeyManager sharedHockeyManager].feedbackManager.activityTitle; + if (self.customActivityTitle) + return self.customActivityTitle; NSString *appName = bit_appName(BITHockeyLocalizedString(@"HockeyFeedbackActivityAppPlaceholder")); @@ -56,8 +62,8 @@ - (NSString *)activityTitle { } - (UIImage *)activityImage { - if ([BITHockeyManager sharedHockeyManager].feedbackManager.activityImage) - return [BITHockeyManager sharedHockeyManager].feedbackManager.activityImage; + if (self.customActivityImage) + return self.customActivityImage; return bit_imageNamed(@"feedbackActiviy.png", BITHOCKEYSDK_BUNDLE); } diff --git a/Classes/BITFeedbackManager.h b/Classes/BITFeedbackManager.h index 485f7d43..5228115b 100644 --- a/Classes/BITFeedbackManager.h +++ b/Classes/BITFeedbackManager.h @@ -130,29 +130,4 @@ typedef enum { - (BITFeedbackComposeViewController *)feedbackComposeViewController; -///----------------------------------------------------------------------------- -/// @name BITFeedbackActivity settings -///----------------------------------------------------------------------------- - - -/** - Define the image shown when using `BITFeedbackActivity` - - If not set a default icon is being used. - - @see activityTitle - */ -@property (nonatomic, retain) UIImage *activityImage; - - -/** - Define the title shown when using `BITFeedbackActivity` - - If not set, a default string is shown by using the apps name - and adding the localized string "Feedback" to it. - - @see activityImage - */ -@property (nonatomic, retain) NSString *activityTitle; - @end diff --git a/Classes/BITFeedbackManager.m b/Classes/BITFeedbackManager.m index 0e096fbf..cf690b1b 100644 --- a/Classes/BITFeedbackManager.m +++ b/Classes/BITFeedbackManager.m @@ -79,9 +79,6 @@ - (id)init { _token = nil; _lastMessageID = nil; - _activityImage = nil; - _activityTitle = nil; - self.feedbackList = [NSMutableArray array]; _fileManager = [[NSFileManager alloc] init]; @@ -127,9 +124,6 @@ - (void)dealloc { [_feedbackDir release], _feedbackDir = nil; [_settingsFile release], _settingsFile = nil; - [_activityImage release]; - [_activityTitle release]; - [super dealloc]; } From 5d52d806861cf22864c5f5e206f3d84bfa24b816 Mon Sep 17 00:00:00 2001 From: Andreas Linde Date: Fri, 19 Oct 2012 21:16:30 +0200 Subject: [PATCH 067/176] Further improve feedback documentation --- Classes/BITFeedbackComposeViewController.h | 31 +++++++++++- ...BITFeedbackComposeViewControllerDelegate.h | 5 ++ Classes/BITFeedbackListViewController.h | 11 +++++ Classes/BITFeedbackManager.h | 48 ++++++++++++++++++- 4 files changed, 93 insertions(+), 2 deletions(-) diff --git a/Classes/BITFeedbackComposeViewController.h b/Classes/BITFeedbackComposeViewController.h index b30c357c..b39ef5d0 100644 --- a/Classes/BITFeedbackComposeViewController.h +++ b/Classes/BITFeedbackComposeViewController.h @@ -31,13 +31,42 @@ #import "BITFeedbackComposeViewControllerDelegate.h" +/** + View controller allowing the user to write and send new feedback + */ @interface BITFeedbackComposeViewController : UIViewController + +///----------------------------------------------------------------------------- +/// @name Delegate +///----------------------------------------------------------------------------- + + +/** + Sets the `BITUpdateManagerDelegate` delegate. + + When using `BITUpdateManager` to distribute updates of your beta or enterprise + application, it is _REQUIRED_ to set this delegate and implement + `[BITUpdateManagerDelegate customDeviceIdentifierForUpdateManager:]`! + */ @property (nonatomic, assign) id delegate; -- (id)init; +///----------------------------------------------------------------------------- +/// @name Presetting content +///----------------------------------------------------------------------------- + + +/** + An array of data objects that should be used to prefill the compose view content + + The follwoing data object classes are currently supported: + - NSString + - NSURL + + These are automatically concatenated to one text string. + */ - (void)prepareWithItems:(NSArray *)items; @end \ No newline at end of file diff --git a/Classes/BITFeedbackComposeViewControllerDelegate.h b/Classes/BITFeedbackComposeViewControllerDelegate.h index eebf8118..aa0c7c90 100644 --- a/Classes/BITFeedbackComposeViewControllerDelegate.h +++ b/Classes/BITFeedbackComposeViewControllerDelegate.h @@ -10,6 +10,11 @@ @class BITFeedbackComposeViewController; +/** + The `BITFeedbackComposeViewControllerDelegate` formal protocol defines methods further configuring + the behaviour of `BITFeedbackComposeViewController`. + */ + @protocol BITFeedbackComposeViewControllerDelegate @optional diff --git a/Classes/BITFeedbackListViewController.h b/Classes/BITFeedbackListViewController.h index 6e39fa16..0af01569 100644 --- a/Classes/BITFeedbackListViewController.h +++ b/Classes/BITFeedbackListViewController.h @@ -31,6 +31,17 @@ #import "BITHockeyBaseViewController.h" +/** + View controller providing a default interface to manage feedback + + The message list interface contains options to locally delete single messages + by swiping over them, or deleting all messages. This will not delete the messages + on the server though! + + It is also integrates actions to invoke the user interface to compose a new messages, + reload the list content from the server and changing the users name or email if these + are allowed to be set. + */ @interface BITFeedbackListViewController : BITHockeyBaseViewController { } diff --git a/Classes/BITFeedbackManager.h b/Classes/BITFeedbackManager.h index 5228115b..8cd1c050 100644 --- a/Classes/BITFeedbackManager.h +++ b/Classes/BITFeedbackManager.h @@ -51,6 +51,49 @@ typedef enum { @class BITFeedbackMessage; +/** + The feedback module. + + This is the HockeySDK module for letting your users to communicate directly with you via + the app and an integrated user interface. It provides to have a single threaded + discussion with a user running your app. + + The user interface provides a list view than can be presented modally using + `[BITFeedbackManager showFeedbackListView]` modally or adding + `[BITFeedbackManager feedbackListViewController:]` to push onto a navigation stack. + This list integrates all features to load new messages, write new messages, view message + and ask the user for additional (optional) data like name and email. + + If the user provides the email address, all responses from the server will also be send + to the user via email and the user is also able to respond directly via email too. + + The message list interface also contains options to locally delete single messages + by swiping over them, or deleting all messages. This will not delete the messages + on the server though! + + It is also integrates actions to invoke the user interface to compose a new messages, + reload the list content from the server and changing the users name or email if these + are allowed to be set. + + It is also possible to invoke the user interface to compose a new message anywhere in your + own code, by calling `[BITFeedbackManager showFeedbackComposeView]` modally or adding + `[BITFeedackManager feedbackComposeViewController]` to push onto a navigation stack. + + If new messages are written while the device is offline, the SDK automatically retries to + send them once the app starts again or gets active again, or if the notification + `BITHockeyNetworkDidBecomeReachableNotification` is fired. + + A third option is to include the `BITFeedbackActivity` into an UIActivityViewController. + This can be useful if you present some data that users can not only share but also + report back to the developer because they have some problems, e.g. webcams not working + any more. The activity provide a default title and image that can be also be customized. + + New message are automatically loaded on startup, when the app becomes active again + or when the notification `BITHockeyNetworkDidBecomeReachableNotification` is fired. This + only happens if the user ever did initiate a conversation by writing the first + feedback message. + */ + @interface BITFeedbackManager : BITHockeyBaseManager ///----------------------------------------------------------------------------- @@ -73,13 +116,16 @@ typedef enum { /** Define if an email address has to be provided by the user when providing feedback + If the user provides the email address, all responses from the server will also be send + to the user via email and the user is also able to respond directly via email too. + - `BITFeedbackUserDataElementDontShow`: Don't ask for this user data element at all - `BITFeedbackUserDataElementOptional`: The user may provide it, but does not have to - `BITFeedbackUserDataElementRequired`: The user has to provide this to continue The default value is `BITFeedbackUserDataElementOptional`. */ -@property (nonatomic, readwrite) BITFeedbackUserDataElement requireUserEmail; // default is BITFeedbackUserDataElementOptional +@property (nonatomic, readwrite) BITFeedbackUserDataElement requireUserEmail; /** From 31a78a0420a759dc1a23c96e48e107d53d475a4b Mon Sep 17 00:00:00 2001 From: Andreas Linde Date: Fri, 19 Oct 2012 22:01:08 +0200 Subject: [PATCH 068/176] Some more minor documentation improvements --- Classes/BITFeedbackManager.h | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/Classes/BITFeedbackManager.h b/Classes/BITFeedbackManager.h index 8cd1c050..a95fa5d3 100644 --- a/Classes/BITFeedbackManager.h +++ b/Classes/BITFeedbackManager.h @@ -109,6 +109,8 @@ typedef enum { - `BITFeedbackUserDataElementRequired`: The user has to provide this to continue The default value is `BITFeedbackUserDataElementOptional`. + + @see requireUserEmail */ @property (nonatomic, readwrite) BITFeedbackUserDataElement requireUserName; @@ -124,6 +126,8 @@ typedef enum { - `BITFeedbackUserDataElementRequired`: The user has to provide this to continue The default value is `BITFeedbackUserDataElementOptional`. + + @see requireUserName */ @property (nonatomic, readwrite) BITFeedbackUserDataElement requireUserEmail; @@ -134,8 +138,15 @@ typedef enum { This lets the user to view the new feedback by choosing the appropriate option in the alert sheet, and the `BITFeedbackListViewController` will be shown. + The alert is only shown, if the newest message is not originated from the current user. + This requires the users email address to be present! The optional userid property + cannot be used, because users could also answer via email and then this information + is not available. + Default is `YES` @see feedbackListViewController: + @see requireUserEmail + @see `[BITHockeyManagerDelegate userEmailForHockeyManager:componentManager:]` */ @property (nonatomic, readwrite) BOOL showAlertOnIncomingMessages; From 68ba4f93baa10d16cda8dd354e2b93abab16ea3e Mon Sep 17 00:00:00 2001 From: Andreas Linde Date: Sat, 20 Oct 2012 21:06:33 +0200 Subject: [PATCH 069/176] Fix alerts on new feedback messages not being shown --- Classes/BITFeedbackManager.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Classes/BITFeedbackManager.m b/Classes/BITFeedbackManager.m index cf690b1b..e848d089 100644 --- a/Classes/BITFeedbackManager.m +++ b/Classes/BITFeedbackManager.m @@ -639,7 +639,7 @@ - (void)updateMessageListFromResponse:(NSDictionary *)jsonDictionary { [self updateLastMessageID]; BITFeedbackMessage *latestMessage = [self lastMessageHavingID]; - if (self.userEmail && [latestMessage.email compare:self.userEmail] == NSOrderedSame) + if (self.userEmail && latestMessage.email && [self.userEmail compare:latestMessage.email] == NSOrderedSame) latestMessageFromUser = YES; if (!latestMessageFromUser && self.showAlertOnIncomingMessages && !self.currentFeedbackListViewController && !self.currentFeedbackComposeViewController) { From c48ac5b66c0e60f8f9e901ecafb56042ced91555 Mon Sep 17 00:00:00 2001 From: Andreas Linde Date: Sat, 20 Oct 2012 21:09:46 +0200 Subject: [PATCH 070/176] Fix open url in a feedback list not working --- Classes/BITFeedbackListViewController.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Classes/BITFeedbackListViewController.m b/Classes/BITFeedbackListViewController.m index f320c0a1..180e5efc 100644 --- a/Classes/BITFeedbackListViewController.m +++ b/Classes/BITFeedbackListViewController.m @@ -557,7 +557,7 @@ - (void)actionSheet:(UIActionSheet *)actionSheet didDismissWithButtonIndex:(NSIn [self deleteAllMessages]; } } else { - if (buttonIndex == [actionSheet destructiveButtonIndex]) { + if (buttonIndex == [actionSheet firstOtherButtonIndex]) { [[UIApplication sharedApplication] openURL:[NSURL URLWithString:actionSheet.title]]; } else { UIPasteboard *pasteboard = [UIPasteboard generalPasteboard]; From dff35395344c4767f6f6ca970387da912e4badf5 Mon Sep 17 00:00:00 2001 From: Andreas Linde Date: Sat, 20 Oct 2012 21:50:26 +0200 Subject: [PATCH 071/176] Add example code on how to present a modal Feedback Compose UI with pre filled items --- Classes/BITFeedbackManager.h | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/Classes/BITFeedbackManager.h b/Classes/BITFeedbackManager.h index a95fa5d3..3cf0db99 100644 --- a/Classes/BITFeedbackManager.h +++ b/Classes/BITFeedbackManager.h @@ -180,7 +180,18 @@ typedef enum { /** Create an feedback compose view - + + Example to show a modal feedback compose UI with prefilled text + + BITFeedbackComposeViewController *feedbackCompose = [[BITHockeyManager sharedHockeyManager].feedbackManager feedbackComposeViewController]; + + [feedbackCompose prepareWithItems: + @[@"Adding some example default text and also adding a link.", + [NSURL URLWithString:@"http://hockeayyp.net/"]]]; + + feedbackCompose.modalPresentationStyle = UIModalPresentationFormSheet; + [self presentViewController:feedbackCompose animated:YES completion:nil]; + @return `BITFeedbackComposeViewController` The compose feedback view controller, e.g. to push it onto a navigation stack. */ From b85138a40975eef63454a96b30c2cf2ad8c4424d Mon Sep 17 00:00:00 2001 From: Andreas Linde Date: Sat, 20 Oct 2012 21:53:43 +0200 Subject: [PATCH 072/176] Fix missing navController in last doc commit --- Classes/BITFeedbackManager.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Classes/BITFeedbackManager.h b/Classes/BITFeedbackManager.h index 3cf0db99..7625b5d0 100644 --- a/Classes/BITFeedbackManager.h +++ b/Classes/BITFeedbackManager.h @@ -190,7 +190,9 @@ typedef enum { [NSURL URLWithString:@"http://hockeayyp.net/"]]]; feedbackCompose.modalPresentationStyle = UIModalPresentationFormSheet; - [self presentViewController:feedbackCompose animated:YES completion:nil]; + + UINavigationController *navController = [[[UINavigationController alloc] initWithRootViewController:feedbackCompose] autorelease]; + [self presentViewController:navController animated:YES completion:nil]; @return `BITFeedbackComposeViewController` The compose feedback view controller, e.g. to push it onto a navigation stack. From 10d6c72d950ed5f66a4d451ff8bd84e37acc9f44 Mon Sep 17 00:00:00 2001 From: Andreas Linde Date: Sat, 20 Oct 2012 22:02:32 +0200 Subject: [PATCH 073/176] Another fix *doh* --- Classes/BITFeedbackManager.h | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Classes/BITFeedbackManager.h b/Classes/BITFeedbackManager.h index 7625b5d0..a7afd0ca 100644 --- a/Classes/BITFeedbackManager.h +++ b/Classes/BITFeedbackManager.h @@ -188,10 +188,9 @@ typedef enum { [feedbackCompose prepareWithItems: @[@"Adding some example default text and also adding a link.", [NSURL URLWithString:@"http://hockeayyp.net/"]]]; - - feedbackCompose.modalPresentationStyle = UIModalPresentationFormSheet; UINavigationController *navController = [[[UINavigationController alloc] initWithRootViewController:feedbackCompose] autorelease]; + navController.modalPresentationStyle = UIModalPresentationFormSheet; [self presentViewController:navController animated:YES completion:nil]; @return `BITFeedbackComposeViewController` The compose feedback view controller, From 11a708d446757759b835195440bd662d2aaa4ee9 Mon Sep 17 00:00:00 2001 From: Andreas Linde Date: Sat, 20 Oct 2012 22:42:03 +0200 Subject: [PATCH 074/176] Improve scrolling performance of list view UIButton didn't need setMaskToBounds and it caused slow downs and stuttering when scrolling --- Classes/BITFeedbackListViewController.m | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/Classes/BITFeedbackListViewController.m b/Classes/BITFeedbackListViewController.m index 180e5efc..d19242a3 100644 --- a/Classes/BITFeedbackListViewController.m +++ b/Classes/BITFeedbackListViewController.m @@ -325,17 +325,16 @@ - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(N if (!cell) { cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:identifier] autorelease]; - } - cell.textLabel.font = [UIFont systemFontOfSize:14]; - cell.textLabel.numberOfLines = 0; - cell.accessoryType = UITableViewCellAccessoryNone; - cell.selectionStyle = UITableViewCellSelectionStyleNone; + cell.textLabel.font = [UIFont systemFontOfSize:14]; + cell.textLabel.numberOfLines = 0; + cell.accessoryType = UITableViewCellAccessoryNone; + cell.selectionStyle = UITableViewCellSelectionStyleNone; + } // button UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom]; button.autoresizingMask = UIViewAutoresizingFlexibleWidth; - [button.layer setMasksToBounds:YES]; [button.layer setCornerRadius:10.0f]; [button.layer setBorderWidth:1]; [button.layer setBackgroundColor:BUTTON_BACKGROUNDCOLOR.CGColor]; From 857d02347e1e9bc80126cfa31ddac0b4a81eea54 Mon Sep 17 00:00:00 2001 From: Andreas Linde Date: Sun, 21 Oct 2012 00:38:12 +0200 Subject: [PATCH 075/176] Update App Update screen to be more iOS 6 like Also do some small refactoring and rename the PS classes to BIT to avoid any possible namespacing problems --- Classes/BITAppStoreHeader.h | 41 +++++ Classes/BITAppStoreHeader.m | 161 +++++++++++++++++ Classes/BITStoreButton.h | 81 +++++++++ Classes/{PSStoreButton.m => BITStoreButton.m} | 112 ++++++------ Classes/BITUpdateViewController.h | 4 - Classes/BITUpdateViewController.m | 135 +++++++------- Classes/BITUpdateViewControllerPrivate.h | 4 +- Classes/BITWebTableViewCell.h | 44 +++++ ...bTableViewCell.m => BITWebTableViewCell.m} | 131 +++++++------- Classes/PSAppStoreHeader.h | 39 ----- Classes/PSAppStoreHeader.m | 165 ------------------ Classes/PSStoreButton.h | 78 --------- Classes/PSWebTableViewCell.h | 41 ----- Support/HockeySDK.xcodeproj/project.pbxproj | 48 ++--- 14 files changed, 550 insertions(+), 534 deletions(-) create mode 100644 Classes/BITAppStoreHeader.h create mode 100644 Classes/BITAppStoreHeader.m create mode 100644 Classes/BITStoreButton.h rename Classes/{PSStoreButton.m => BITStoreButton.m} (74%) create mode 100644 Classes/BITWebTableViewCell.h rename Classes/{PSWebTableViewCell.m => BITWebTableViewCell.m} (50%) delete mode 100644 Classes/PSAppStoreHeader.h delete mode 100644 Classes/PSAppStoreHeader.m delete mode 100644 Classes/PSStoreButton.h delete mode 100644 Classes/PSWebTableViewCell.h diff --git a/Classes/BITAppStoreHeader.h b/Classes/BITAppStoreHeader.h new file mode 100644 index 00000000..0175b2f6 --- /dev/null +++ b/Classes/BITAppStoreHeader.h @@ -0,0 +1,41 @@ +/* + * Author: Andreas Linde + * Peter Steinberger + * + * Copyright (c) 2012 HockeyApp, Bit Stadium GmbH. + * Copyright (c) 2011-2012 Peter Steinberger. + * All rights reserved. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + + +#import + +@interface BITAppStoreHeader : UIView + +@property (nonatomic, copy) NSString *headerLabel; +@property (nonatomic, copy) NSString *middleHeaderLabel; +@property (nonatomic, copy) NSString *subHeaderLabel; +@property (nonatomic, retain) UIImage *iconImage; + +@end diff --git a/Classes/BITAppStoreHeader.m b/Classes/BITAppStoreHeader.m new file mode 100644 index 00000000..d31ffbd9 --- /dev/null +++ b/Classes/BITAppStoreHeader.m @@ -0,0 +1,161 @@ +/* + * Author: Andreas Linde + * Peter Steinberger + * + * Copyright (c) 2012 HockeyApp, Bit Stadium GmbH. + * Copyright (c) 2011-2012 Peter Steinberger. + * All rights reserved. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + + +#import "BITAppStoreHeader.h" +#import "BITHockeyHelper.h" +#import "HockeySDKPrivate.h" + + +#define BIT_RGBCOLOR(r,g,b) [UIColor colorWithRed:(r)/255.0 green:(g)/255.0 blue:(b)/255.0 alpha:1] + +#define kLightGrayColor BIT_RGBCOLOR(235, 235, 235) +#define kDarkGrayColor BIT_RGBCOLOR(186, 186, 186) +#define kWhiteBackgroundColor BIT_RGBCOLOR(245, 245, 245) +#define kImageHeight 72 +#define kImageBorderRadius 12 +#define kImageLeftMargin 14 +#define kImageTopMargin 12 +#define kTextRow kImageTopMargin*2 + kImageHeight + +@implementation BITAppStoreHeader + + +#pragma mark - NSObject + +- (id)initWithFrame:(CGRect)frame { + if ((self = [super initWithFrame:frame])) { + self.autoresizingMask = UIViewAutoresizingFlexibleWidth; + self.backgroundColor = kWhiteBackgroundColor; + } + return self; +} + +- (void)dealloc { + [_headerLabel release], _headerLabel = nil; + [_middleHeaderLabel release], _middleHeaderLabel = nil; + [_subHeaderLabel release], _subHeaderLabel = nil; + [_iconImage release], _iconImage = nil;; + + [super dealloc]; +} + + +#pragma mark - UIView + +- (void)drawRect:(CGRect)rect { + CGRect bounds = self.bounds; + CGFloat globalWidth = self.frame.size.width; + CGContextRef context = UIGraphicsGetCurrentContext(); + + // draw the gradient + 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}); + CGPoint top = CGPointMake(CGRectGetMidX(bounds), bounds.size.height - 3); + CGPoint bottom = CGPointMake(CGRectGetMidX(bounds), CGRectGetMaxY(bounds)); + CGContextDrawLinearGradient(context, gradient, top, bottom, 0); + CGGradientRelease(gradient); + + // draw header name + UIColor *mainTextColor = BIT_RGBCOLOR(61, 61, 61); + UIColor *secondaryTextColor = BIT_RGBCOLOR(100, 100, 100); + UIFont *mainFont = [UIFont boldSystemFontOfSize:15]; + UIFont *secondaryFont = [UIFont systemFontOfSize:10]; + +// float myColorValues[] = {255, 255, 255, .6}; +// CGColorSpaceRef myColorSpace = CGColorSpaceCreateDeviceRGB(); +// CGColorRef myColor = CGColorCreate(myColorSpace, myColorValues); + + // icon + [_iconImage drawAtPoint:CGPointMake(kImageLeftMargin, kImageTopMargin)]; + + // shadows are a beast +// NSInteger shadowOffset = 2; +// if([[UIScreen mainScreen] scale] == 2) shadowOffset = 1; +// BITHOCKEY_IF_IOS5_OR_GREATER(shadowOffset = 1;) // iOS5 changes this - again! +// +// CGContextSetShadowWithColor(context, CGSizeMake(shadowOffset, shadowOffset), 0, myColor); + + [mainTextColor set]; + [_headerLabel drawInRect:CGRectMake(kTextRow, kImageTopMargin, globalWidth-kTextRow, 20) withFont:mainFont lineBreakMode:UILineBreakModeTailTruncation]; + + // middle + [secondaryTextColor set]; + [_middleHeaderLabel drawInRect:CGRectMake(kTextRow, kImageTopMargin + 17, globalWidth-kTextRow, 20) withFont:secondaryFont lineBreakMode:UILineBreakModeTailTruncation]; +// CGContextSetShadowWithColor(context, CGSizeZero, 0, nil); + + // sub + [secondaryTextColor set]; + [_subHeaderLabel drawAtPoint:CGPointMake(kTextRow, kImageTopMargin + 29) forWidth:globalWidth-kTextRow withFont:secondaryFont lineBreakMode:UILineBreakModeTailTruncation]; + +// CGColorRelease(myColor); +// CGColorSpaceRelease(myColorSpace); +} + + +#pragma mark - Properties + +- (void)setHeaderLabel:(NSString *)anHeaderLabel { + if (_headerLabel != anHeaderLabel) { + [_headerLabel release]; + _headerLabel = [anHeaderLabel copy]; + [self setNeedsDisplay]; + } +} + +- (void)setMiddleHeaderLabel:(NSString *)aMiddleHeaderLabel { + if (_middleHeaderLabel != aMiddleHeaderLabel) { + [_middleHeaderLabel release]; + _middleHeaderLabel = [aMiddleHeaderLabel copy]; + [self setNeedsDisplay]; + } +} + +- (void)setSubHeaderLabel:(NSString *)aSubHeaderLabel { + if (_subHeaderLabel != aSubHeaderLabel) { + [_subHeaderLabel release]; + _subHeaderLabel = [aSubHeaderLabel copy]; + [self setNeedsDisplay]; + } +} + +- (void)setIconImage:(UIImage *)anIconImage { + if (_iconImage != anIconImage) { + [_iconImage release]; + + // scale, make borders and reflection + _iconImage = bit_imageToFitSize(anIconImage, CGSizeMake(kImageHeight, kImageHeight), YES); + _iconImage = [bit_roundedCornerImage(_iconImage, kImageBorderRadius, 0.0) retain]; + + [self setNeedsDisplay]; + } +} + +@end diff --git a/Classes/BITStoreButton.h b/Classes/BITStoreButton.h new file mode 100644 index 00000000..25d7de10 --- /dev/null +++ b/Classes/BITStoreButton.h @@ -0,0 +1,81 @@ +/* + * Author: Andreas Linde + * Peter Steinberger + * + * Copyright (c) 2012 HockeyApp, Bit Stadium GmbH. + * Copyright (c) 2011-2012 Peter Steinberger. + * All rights reserved. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + + +#import +#import + +// defines a button action set (data container) +@interface BITStoreButtonData : NSObject { + CGPoint _customPadding; +} + ++ (id)dataWithLabel:(NSString*)aLabel colors:(NSArray*)aColors enabled:(BOOL)flag; + +@property (nonatomic, copy) NSString *label; +@property (nonatomic, retain) NSArray *colors; +@property (nonatomic, assign, getter=isEnabled) BOOL enabled; + +@end + + +@class BITStoreButton; +@protocol BITStoreButtonDelegate +- (void)storeButtonFired:(BITStoreButton *)button; +@end + + +// Simulate the Paymeny-Button from the AppStore +// The interface is flexible, so there is now fixed order +@interface BITStoreButton : UIButton { + CAGradientLayer *_gradient; + CGPoint _customPadding; +} + +- (id)initWithFrame:(CGRect)frame; +- (id)initWithPadding:(CGPoint)padding; + +// action delegate +@property (nonatomic, assign) id buttonDelegate; + +// change the button layer +@property (nonatomic, retain) BITStoreButtonData *buttonData; +- (void)setButtonData:(BITStoreButtonData *)aButtonData animated:(BOOL)animated; + +// align helper +@property (nonatomic, assign) CGPoint customPadding; +- (void)alignToSuperview; + +// helpers to mimic an AppStore button ++ (NSArray *)appStoreGreenColor; ++ (NSArray *)appStoreBlueColor; ++ (NSArray *)appStoreGrayColor; + +@end diff --git a/Classes/PSStoreButton.m b/Classes/BITStoreButton.m similarity index 74% rename from Classes/PSStoreButton.m rename to Classes/BITStoreButton.m index b7e215a3..615c42a2 100644 --- a/Classes/PSStoreButton.m +++ b/Classes/BITStoreButton.m @@ -1,28 +1,35 @@ -// -// Created by Peter Steinberger on 09.01.11. -// Copyright 2011-2012 Peter Steinberger. All rights reserved. -// -// This code was inspired by https://github.com/dhmspector/ZIStoreButton -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -#import "PSStoreButton.h" +/* + * Author: Andreas Linde + * Peter Steinberger + * + * Copyright (c) 2012 HockeyApp, Bit Stadium GmbH. + * Copyright (c) 2011-2012 Peter Steinberger. + * All rights reserved. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + + +#import "BITStoreButton.h" #define PS_RGBCOLOR(r,g,b) [UIColor colorWithRed:(r)/255.0 green:(g)/255.0 blue:(b)/255.0 alpha:1] #define PS_MIN_HEIGHT 25.0f @@ -30,12 +37,8 @@ #define PS_PADDING 12.0f #define kDefaultButtonAnimationTime 0.25f -@implementation PSStoreButtonData - -@synthesize label = label_; -@synthesize colors = colors_; -@synthesize enabled = enabled_; +@implementation BITStoreButtonData #pragma mark - NSObject @@ -53,31 +56,26 @@ + (id)dataWithLabel:(NSString*)aLabel colors:(NSArray*)aColors enabled:(BOOL)fla } - (void)dealloc { - [label_ release]; - [colors_ release]; + [_label release], _label = nil; + [_colors release]; [super dealloc]; } @end -@interface PSStoreButton () +@interface BITStoreButton () // call when buttonData was updated - (void)updateButtonAnimated:(BOOL)animated; @end -@implementation PSStoreButton - -@synthesize buttonData = buttonData_; -@synthesize buttonDelegate = buttonDelegate_; -@synthesize customPadding = customPadding_; - +@implementation BITStoreButton #pragma mark - private - (void)buttonPressed:(id)sender { - [buttonDelegate_ storeButtonFired:self]; + [_buttonDelegate storeButtonFired:self]; } - (void)animationDidStop:(NSString *)animationID finished:(NSNumber *)finished context:(void *)context { @@ -101,7 +99,7 @@ - (void)updateButtonAnimated:(BOOL)animated { } self.enabled = self.buttonData.isEnabled; - gradient_.colors = self.buttonData.colors; + _gradient.colors = self.buttonData.colors; // show white or gray text, depending on the state if (self.buttonData.isEnabled) { @@ -148,8 +146,8 @@ - (void)alignToSuperview { [self sizeToFit]; if (self.superview) { CGRect cr = self.frame; - cr.origin.y = customPadding_.y; - cr.origin.x = self.superview.frame.size.width - cr.size.width - customPadding_.x * 2; + cr.origin.y = _customPadding.y; + cr.origin.x = self.superview.frame.size.width - cr.size.width - _customPadding.x * 2; self.frame = cr; } } @@ -183,12 +181,12 @@ - (id)initWithFrame:(CGRect)frame { [self.layer addSublayer:topBorderLayer]; // main gradient layer - 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_.frame = CGRectMake(0.75, 0.75, CGRectGetWidth(frame) - 1.5, CGRectGetHeight(frame) - 1.5); - gradient_.cornerRadius = 2.5; - gradient_.needsDisplayOnBoundsChange = YES; - [self.layer addSublayer:gradient_]; + _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.frame = CGRectMake(0.75, 0.75, CGRectGetWidth(frame) - 1.5, CGRectGetHeight(frame) - 1.5); + _gradient.cornerRadius = 2.5; + _gradient.needsDisplayOnBoundsChange = YES; + [self.layer addSublayer:_gradient]; [self bringSubviewToFront:self.titleLabel]; } return self; @@ -196,14 +194,14 @@ - (id)initWithFrame:(CGRect)frame { - (id)initWithPadding:(CGPoint)padding { if ((self = [self initWithFrame:CGRectMake(0, 0, 40, PS_MIN_HEIGHT)])) { - customPadding_ = padding; + _customPadding = padding; } return self; } - (void)dealloc { - [buttonData_ release]; - [gradient_ release]; + [_buttonData release]; + [_gradient release]; [super dealloc]; } @@ -237,14 +235,14 @@ - (void)setFrame:(CGRect)aRect { #pragma mark - Properties -- (void)setButtonData:(PSStoreButtonData *)aButtonData { +- (void)setButtonData:(BITStoreButtonData *)aButtonData { [self setButtonData:aButtonData animated:NO]; } -- (void)setButtonData:(PSStoreButtonData *)aButtonData animated:(BOOL)animated { - if (buttonData_ != aButtonData) { - [buttonData_ release]; - buttonData_ = [aButtonData retain]; +- (void)setButtonData:(BITStoreButtonData *)aButtonData animated:(BOOL)animated { + if (_buttonData != aButtonData) { + [_buttonData release]; + _buttonData = [aButtonData retain]; } [self updateButtonAnimated:animated]; diff --git a/Classes/BITUpdateViewController.h b/Classes/BITUpdateViewController.h index cf131cc4..b24708a9 100644 --- a/Classes/BITUpdateViewController.h +++ b/Classes/BITUpdateViewController.h @@ -33,9 +33,5 @@ #import "BITHockeyBaseViewController.h" -@class PSStoreButton; -@class PSAppStoreHeader; - - @interface BITUpdateViewController : BITHockeyBaseViewController @end diff --git a/Classes/BITUpdateViewController.m b/Classes/BITUpdateViewController.m index cdf715c0..d5997a10 100644 --- a/Classes/BITUpdateViewController.m +++ b/Classes/BITUpdateViewController.m @@ -31,9 +31,9 @@ #import #import "BITHockeyHelper.h" #import "BITAppVersionMetaInfo.h" -#import "PSAppStoreHeader.h" -#import "PSWebTableViewCell.h" -#import "PSStoreButton.h" +#import "BITAppStoreHeader.h" +#import "BITWebTableViewCell.h" +#import "BITStoreButton.h" #import "HockeySDK.h" #import "HockeySDKPrivate.h" @@ -43,15 +43,15 @@ #define kWebCellIdentifier @"PSWebTableViewCell" -#define kAppStoreViewHeight 90 +#define kAppStoreViewHeight 99 @implementation BITUpdateViewController { BOOL _kvoRegistered; BOOL _showAllVersions; UIStatusBarStyle _statusBarStyle; - PSAppStoreHeader *_appStoreHeader; - PSStoreButton *_appStoreButton; + BITAppStoreHeader *_appStoreHeader; + BITStoreButton *_appStoreButton; id _popOverController; @@ -138,11 +138,11 @@ - (void)realignPreviousVersionButton { } - (void)changePreviousVersionButtonBackground:(id)sender { - [(UIButton *)sender setBackgroundColor:BIT_RGBCOLOR(183,183,183)]; + [(UIButton *)sender setBackgroundColor:BIT_RGBCOLOR(245, 245, 245)]; } - (void)changePreviousVersionButtonBackgroundHighlighted:(id)sender { - [(UIButton *)sender setBackgroundColor:BIT_RGBCOLOR(183,183,183)]; + [(UIButton *)sender setBackgroundColor:BIT_RGBCOLOR(245, 245, 245)]; } - (void)showHidePreviousVersionsButton { @@ -152,35 +152,47 @@ - (void)showHidePreviousVersionsButton { // align at the bottom if tableview is small UIView *footerView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, self.view.frame.size.width, kMinPreviousVersionButtonHeight)]; footerView.autoresizingMask = UIViewAutoresizingFlexibleWidth; - footerView.backgroundColor = BIT_RGBCOLOR(200, 202, 204); + footerView.backgroundColor = BIT_RGBCOLOR(245, 245, 245); + UIView *lineView1 = [[[UIView alloc] initWithFrame:CGRectMake(0, 0, self.view.frame.size.width, 1)] autorelease]; + lineView1.backgroundColor = BIT_RGBCOLOR(214, 214, 214); + lineView1.autoresizingMask = UIViewAutoresizingFlexibleWidth; + [footerView addSubview:lineView1]; + UIView *lineView2 = [[[UIView alloc] initWithFrame:CGRectMake(0, 1, self.view.frame.size.width, 1)] autorelease]; + lineView2.backgroundColor = BIT_RGBCOLOR(221, 221, 221); + lineView2.autoresizingMask = UIViewAutoresizingFlexibleWidth; + [footerView addSubview:lineView2]; + UIView *lineView3 = [[[UIView alloc] initWithFrame:CGRectMake(0, 1, self.view.frame.size.width, 1)] autorelease]; + lineView3.backgroundColor = BIT_RGBCOLOR(255, 255, 255); + lineView3.autoresizingMask = UIViewAutoresizingFlexibleWidth; + [footerView addSubview:lineView3]; UIButton *footerButton = [UIButton buttonWithType:UIButtonTypeCustom]; //footerButton.layer.shadowOffset = CGSizeMake(-2, 2); footerButton.layer.shadowColor = [[UIColor blackColor] CGColor]; footerButton.layer.shadowRadius = 2.0f; footerButton.titleLabel.font = [UIFont boldSystemFontOfSize:14]; [footerButton setTitle:BITHockeyLocalizedString(@"UpdateShowPreviousVersions") forState:UIControlStateNormal]; - [footerButton setTitleColor:[UIColor blackColor] forState:UIControlStateNormal]; + [footerButton setTitleColor:BIT_RGBCOLOR(61, 61, 61) forState:UIControlStateNormal]; [footerButton setTitleColor:[UIColor whiteColor] forState:UIControlStateHighlighted]; [footerButton setBackgroundImage:bit_imageNamed(@"buttonHighlight.png", BITHOCKEYSDK_BUNDLE) forState:UIControlStateHighlighted]; footerButton.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleTopMargin; [footerButton addTarget:self action:@selector(showPreviousVersionAction) forControlEvents:UIControlEventTouchUpInside]; footerButton.frame = CGRectMake(0, kMinPreviousVersionButtonHeight-44, self.view.frame.size.width, 44); - footerButton.backgroundColor = BIT_RGBCOLOR(183,183,183); + footerButton.backgroundColor = BIT_RGBCOLOR(245, 245, 245); [footerView addSubview:footerButton]; self.tableView.tableFooterView = footerView; [self realignPreviousVersionButton]; [footerView release]; } else { self.tableView.tableFooterView = nil; - self.tableView.backgroundColor = BIT_RGBCOLOR(200, 202, 204); + self.tableView.backgroundColor = BIT_RGBCOLOR(235, 235, 235); } } -- (void)configureWebCell:(PSWebTableViewCell *)cell forAppVersion:(BITAppVersionMetaInfo *)appVersion { +- (void)configureWebCell:(BITWebTableViewCell *)cell forAppVersion:(BITAppVersionMetaInfo *)appVersion { // create web view for a version NSString *installed = @""; if ([appVersion.version isEqualToString:[_updateManager currentAppVersion]]) { - installed = [NSString stringWithFormat:@"%@", [appVersion isEqual:_updateManager.newestAppVersion] ? @"left" : @"right", BITHockeyLocalizedString(@"UpdateInstalled")]; + installed = [NSString stringWithFormat:@"%@", [appVersion isEqual:_updateManager.newestAppVersion] ? @"left" : @"right", BITHockeyLocalizedString(@"UpdateInstalled")]; } if ([appVersion isEqual:_updateManager.newestAppVersion]) { @@ -188,12 +200,12 @@ - (void)configureWebCell:(PSWebTableViewCell *)cell forAppVersion:(BITAppVersion installed = [NSString stringWithFormat:@"

 %@

", installed]; cell.webViewContent = [NSString stringWithFormat:@"%@%@", installed, appVersion.notes]; } else { - cell.webViewContent = [NSString stringWithFormat:@"
%@
", BITHockeyLocalizedString(@"UpdateNoReleaseNotesAvailable")]; + cell.webViewContent = [NSString stringWithFormat:@"
%@
", BITHockeyLocalizedString(@"UpdateNoReleaseNotesAvailable")]; } } else { - cell.webViewContent = [NSString stringWithFormat:@"

%@%@
%@

%@

", [appVersion versionString], installed, [appVersion dateString], [appVersion notesOrEmptyString]]; + cell.webViewContent = [NSString stringWithFormat:@"

%@%@
%@

%@

", [appVersion versionString], installed, [appVersion dateString], [appVersion notesOrEmptyString]]; } - cell.cellBackgroundColor = BIT_RGBCOLOR(200, 202, 204); + cell.cellBackgroundColor = BIT_RGBCOLOR(235, 235, 235); [cell addWebView]; // hack @@ -243,28 +255,28 @@ - (void)dealloc { #pragma mark - View lifecycle -- (CAGradientLayer *)backgroundLayer { - UIColor *colorOne = [UIColor colorWithWhite:0.9 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 *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]; - - NSNumber *stopOne = [NSNumber numberWithFloat:0.0]; - NSNumber *stopTwo = [NSNumber numberWithFloat:0.02]; - NSNumber *stopThree = [NSNumber numberWithFloat:0.99]; - NSNumber *stopFour = [NSNumber numberWithFloat:1.0]; - - NSArray *locations = [NSArray arrayWithObjects:stopOne, stopTwo, stopThree, stopFour, nil]; - - CAGradientLayer *headerLayer = [CAGradientLayer layer]; - //headerLayer.frame = CGRectMake(0.0, 0.0, 320.0, 77.0); - headerLayer.colors = colors; - headerLayer.locations = locations; - - return headerLayer; -} +//- (CAGradientLayer *)backgroundLayer { +// UIColor *colorOne = [UIColor colorWithWhite:0.9 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 *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]; +// +// NSNumber *stopOne = [NSNumber numberWithFloat:0.0]; +// NSNumber *stopTwo = [NSNumber numberWithFloat:0.02]; +// NSNumber *stopThree = [NSNumber numberWithFloat:0.99]; +// NSNumber *stopFour = [NSNumber numberWithFloat:1.0]; +// +// NSArray *locations = [NSArray arrayWithObjects:stopOne, stopTwo, stopThree, stopFour, nil]; +// +// CAGradientLayer *headerLayer = [CAGradientLayer layer]; +// //headerLayer.frame = CGRectMake(0.0, 0.0, 320.0, 77.0); +// headerLayer.colors = colors; +// headerLayer.locations = locations; +// +// return headerLayer; +//} - (void)viewDidLoad { [super viewDidLoad]; @@ -280,7 +292,7 @@ - (void)viewDidLoad { [_updateManager addObserver:self forKeyPath:@"apps" options:0 context:nil]; _kvoRegistered = YES; - self.tableView.backgroundColor = BIT_RGBCOLOR(200, 202, 204); + self.tableView.backgroundColor = BIT_RGBCOLOR(235, 235, 235); self.tableView.separatorStyle = UITableViewCellSeparatorStyleNone; UIView *topView = [[[UIView alloc] initWithFrame:CGRectMake(0, -(600-kAppStoreViewHeight), self.view.frame.size.width, 600)] autorelease]; @@ -288,7 +300,7 @@ - (void)viewDidLoad { topView.backgroundColor = BIT_RGBCOLOR(140, 141, 142); [self.tableView addSubview:topView]; - _appStoreHeader = [[PSAppStoreHeader alloc] initWithFrame:CGRectMake(0, 0, self.view.frame.size.width, kAppStoreViewHeight)]; + _appStoreHeader = [[BITAppStoreHeader alloc] initWithFrame:CGRectMake(0, 0, self.view.frame.size.width, kAppStoreViewHeight)]; [self updateAppStoreHeader]; NSString *iconString = nil; @@ -309,17 +321,20 @@ - (void)viewDidLoad { if (icons) { BOOL useHighResIcon = NO; + BOOL useiPadIcon = NO; if ([UIScreen mainScreen].scale == 2.0f) useHighResIcon = YES; - + if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) useiPadIcon = 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) { + if ( + (iconImage.size.height == 57 && !useHighResIcon && !useiPadIcon) || + (iconImage.size.height == 114 && useHighResIcon && !useiPadIcon) || + (iconImage.size.height == 72 && !useHighResIcon && useiPadIcon) || + (iconImage.size.height == 144 && useHighResIcon && useiPadIcon) + ) { // found! break; } @@ -340,11 +355,11 @@ - (void)viewDidLoad { self.tableView.tableHeaderView = _appStoreHeader; - PSStoreButton *storeButton = [[[PSStoreButton alloc] initWithPadding:CGPointMake(5, 40)] autorelease]; + BITStoreButton *storeButton = [[[BITStoreButton alloc] initWithPadding:CGPointMake(5, 58)] autorelease]; storeButton.autoresizingMask = UIViewAutoresizingFlexibleLeftMargin; storeButton.buttonDelegate = self; [self.tableView.tableHeaderView addSubview:storeButton]; - storeButton.buttonData = [PSStoreButtonData dataWithLabel:@"" colors:[PSStoreButton appStoreGrayColor] enabled:NO]; + storeButton.buttonData = [BITStoreButtonData dataWithLabel:@"" colors:[BITStoreButton appStoreGrayColor] enabled:NO]; [storeButton alignToSuperview]; _appStoreButton = [storeButton retain]; self.appStoreButtonState = AppStoreButtonStateCheck; @@ -394,7 +409,7 @@ - (void)redrawTableView { } } - PSWebTableViewCell *cell = [[[PSWebTableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:kWebCellIdentifier] autorelease]; + BITWebTableViewCell *cell = [[[BITWebTableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:kWebCellIdentifier] autorelease]; [self configureWebCell:cell forAppVersion:appVersion]; [_cells addObject:cell]; @@ -421,7 +436,7 @@ - (void)showPreviousVersionAction { } } - PSWebTableViewCell *cell = [[[PSWebTableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:kWebCellIdentifier] autorelease]; + BITWebTableViewCell *cell = [[[BITWebTableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:kWebCellIdentifier] autorelease]; [self configureWebCell:cell forAppVersion:appVersion]; [_cells addObject:cell]; } @@ -440,17 +455,17 @@ - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPa CGFloat rowHeight = 0; if ([_cells count] > (NSUInteger)indexPath.row) { - PSWebTableViewCell *cell = [_cells objectAtIndex:indexPath.row]; + BITWebTableViewCell *cell = [_cells objectAtIndex:indexPath.row]; rowHeight = cell.webViewSize.height; } if ([_updateManager.appVersions count] > 1 && !_showAllVersions) { - self.tableView.backgroundColor = BIT_RGBCOLOR(183, 183, 183); + self.tableView.backgroundColor = BIT_RGBCOLOR(245, 245, 245); } if (rowHeight == 0) { rowHeight = indexPath.row == 0 ? 250 : 44; // fill screen on startup - self.tableView.backgroundColor = BIT_RGBCOLOR(200, 202, 204); + self.tableView.backgroundColor = BIT_RGBCOLOR(235, 235, 235); } return rowHeight; @@ -516,26 +531,26 @@ - (void)setAppStoreButtonState:(AppStoreButtonState)anAppStoreButtonState animat switch (anAppStoreButtonState) { case AppStoreButtonStateOffline: - [_appStoreButton setButtonData:[PSStoreButtonData dataWithLabel:BITHockeyLocalizedString(@"UpdateButtonOffline") colors:[PSStoreButton appStoreGrayColor] enabled:NO] animated:animated]; + [_appStoreButton setButtonData:[BITStoreButtonData dataWithLabel:BITHockeyLocalizedString(@"UpdateButtonOffline") colors:[BITStoreButton appStoreGrayColor] enabled:NO] animated:animated]; break; case AppStoreButtonStateCheck: - [_appStoreButton setButtonData:[PSStoreButtonData dataWithLabel:BITHockeyLocalizedString(@"UpdateButtonCheck") colors:[PSStoreButton appStoreGreenColor] enabled:YES] animated:animated]; + [_appStoreButton setButtonData:[BITStoreButtonData dataWithLabel:BITHockeyLocalizedString(@"UpdateButtonCheck") colors:[BITStoreButton appStoreGreenColor] enabled:YES] animated:animated]; break; case AppStoreButtonStateSearching: - [_appStoreButton setButtonData:[PSStoreButtonData dataWithLabel:BITHockeyLocalizedString(@"UpdateButtonSearching") colors:[PSStoreButton appStoreGrayColor] enabled:NO] animated:animated]; + [_appStoreButton setButtonData:[BITStoreButtonData dataWithLabel:BITHockeyLocalizedString(@"UpdateButtonSearching") colors:[BITStoreButton appStoreGrayColor] enabled:NO] animated:animated]; break; case AppStoreButtonStateUpdate: - [_appStoreButton setButtonData:[PSStoreButtonData dataWithLabel:BITHockeyLocalizedString(@"UpdateButtonUpdate") colors:[PSStoreButton appStoreBlueColor] enabled:YES] animated:animated]; + [_appStoreButton setButtonData:[BITStoreButtonData dataWithLabel:BITHockeyLocalizedString(@"UpdateButtonUpdate") colors:[BITStoreButton appStoreBlueColor] enabled:YES] animated:animated]; break; case AppStoreButtonStateInstalling: - [_appStoreButton setButtonData:[PSStoreButtonData dataWithLabel:BITHockeyLocalizedString(@"UpdateButtonInstalling") colors:[PSStoreButton appStoreGrayColor] enabled:NO] animated:animated]; + [_appStoreButton setButtonData:[BITStoreButtonData dataWithLabel:BITHockeyLocalizedString(@"UpdateButtonInstalling") colors:[BITStoreButton appStoreGrayColor] enabled:NO] animated:animated]; break; default: break; } } -- (void)storeButtonFired:(PSStoreButton *)button { +- (void)storeButtonFired:(BITStoreButton *)button { switch (_appStoreButtonState) { case AppStoreButtonStateCheck: [_updateManager checkForUpdateShowFeedback:YES]; diff --git a/Classes/BITUpdateViewControllerPrivate.h b/Classes/BITUpdateViewControllerPrivate.h index 3ac39c89..905bf07c 100644 --- a/Classes/BITUpdateViewControllerPrivate.h +++ b/Classes/BITUpdateViewControllerPrivate.h @@ -29,7 +29,7 @@ */ #import -#import "PSStoreButton.h" +#import "BITStoreButton.h" typedef enum { AppStoreButtonStateOffline, @@ -44,7 +44,7 @@ typedef enum { @protocol PSStoreButtonDelegate; -@interface BITUpdateViewController() { +@interface BITUpdateViewController() { } @property (nonatomic, assign) BITUpdateManager *updateManager; diff --git a/Classes/BITWebTableViewCell.h b/Classes/BITWebTableViewCell.h new file mode 100644 index 00000000..d951ebcc --- /dev/null +++ b/Classes/BITWebTableViewCell.h @@ -0,0 +1,44 @@ +/* + * Author: Andreas Linde + * Peter Steinberger + * + * Copyright (c) 2012 HockeyApp, Bit Stadium GmbH. + * Copyright (c) 2011-2012 Peter Steinberger. + * All rights reserved. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + + +#import +#import + +@interface BITWebTableViewCell : UITableViewCell + +@property (nonatomic, retain) UIWebView *webView; +@property (nonatomic, copy) NSString *webViewContent; +@property (nonatomic, assign) CGSize webViewSize; +@property (nonatomic, retain) UIColor *cellBackgroundColor; + +- (void)addWebView; + +@end diff --git a/Classes/PSWebTableViewCell.m b/Classes/BITWebTableViewCell.m similarity index 50% rename from Classes/PSWebTableViewCell.m rename to Classes/BITWebTableViewCell.m index 3b0db9e5..6877f1a2 100644 --- a/Classes/PSWebTableViewCell.m +++ b/Classes/BITWebTableViewCell.m @@ -1,36 +1,44 @@ -// -// Created by Peter Steinberger on 04.02.11. -// Copyright 2011-2012 Peter Steinberger. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -#import "PSWebTableViewCell.h" - - -@implementation PSWebTableViewCell - -static NSString* PSWebTableViewCellHtmlTemplate = @"\ +/* + * Author: Andreas Linde + * Peter Steinberger + * + * Copyright (c) 2012 HockeyApp, Bit Stadium GmbH. + * Copyright (c) 2011-2012 Peter Steinberger. + * All rights reserved. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#import "BITWebTableViewCell.h" + + +@implementation BITWebTableViewCell + +static NSString* BITWebTableViewCellHtmlTemplate = @"\ \ \ \ \ \ \ @@ -39,27 +47,22 @@ @implementation PSWebTableViewCell \ "; -@synthesize webView = webView_; -@synthesize webViewContent = webViewContent_; -@synthesize webViewSize = webViewSize_; -@synthesize cellBackgroundColor = cellBackgroundColor_; - #pragma mark - private - (void)addWebView { - if(webViewContent_) { + if(_webViewContent) { CGRect webViewRect = CGRectMake(0, 0, self.frame.size.width, self.frame.size.height); - if(!webView_) { - webView_ = [[[UIWebView alloc] initWithFrame:webViewRect] retain]; - [self addSubview:webView_]; - webView_.hidden = YES; - webView_.backgroundColor = self.cellBackgroundColor; - webView_.opaque = NO; - webView_.delegate = self; - webView_.autoresizingMask = UIViewAutoresizingFlexibleWidth; + if(!_webView) { + _webView = [[[UIWebView alloc] initWithFrame:webViewRect] retain]; + [self addSubview:_webView]; + _webView.hidden = YES; + _webView.backgroundColor = self.cellBackgroundColor; + _webView.opaque = NO; + _webView.delegate = self; + _webView.autoresizingMask = UIViewAutoresizingFlexibleWidth; - for(UIView* subView in webView_.subviews){ + for(UIView* subView in _webView.subviews){ if([subView isKindOfClass:[UIScrollView class]]){ // disable scrolling UIScrollView *sv = (UIScrollView *)subView; @@ -76,38 +79,38 @@ - (void)addWebView { } } else - webView_.frame = webViewRect; + _webView.frame = webViewRect; NSString *deviceWidth = UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad ? [NSString stringWithFormat:@"%.0f", CGRectGetWidth(self.bounds)] : @"device-width"; //HockeySDKLog(@"%@\n%@\%@", PSWebTableViewCellHtmlTemplate, deviceWidth, self.webViewContent); - NSString *contentHtml = [NSString stringWithFormat:PSWebTableViewCellHtmlTemplate, deviceWidth, self.webViewContent]; - [webView_ loadHTMLString:contentHtml baseURL:nil]; + NSString *contentHtml = [NSString stringWithFormat:BITWebTableViewCellHtmlTemplate, deviceWidth, self.webViewContent]; + [_webView loadHTMLString:contentHtml baseURL:nil]; } } - (void)showWebView { - webView_.hidden = NO; + _webView.hidden = NO; self.textLabel.text = @""; [self setNeedsDisplay]; } - (void)removeWebView { - if(webView_) { - webView_.delegate = nil; - [webView_ resignFirstResponder]; - [webView_ removeFromSuperview]; - [webView_ release]; + if(_webView) { + _webView.delegate = nil; + [_webView resignFirstResponder]; + [_webView removeFromSuperview]; + [_webView release]; } - webView_ = nil; + _webView = nil; [self setNeedsDisplay]; } - (void)setWebViewContent:(NSString *)aWebViewContent { - if (webViewContent_ != aWebViewContent) { - [webViewContent_ release]; - webViewContent_ = [aWebViewContent retain]; + if (_webViewContent != aWebViewContent) { + [_webViewContent release]; + _webViewContent = [aWebViewContent retain]; // add basic accessiblity (prevents "snarfed from ivar layout") logs self.accessibilityLabel = aWebViewContent; @@ -126,7 +129,7 @@ - (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reus - (void)dealloc { [self removeWebView]; - [webViewContent_ release]; + [_webViewContent release], _webViewContent = nil;; [super dealloc]; } @@ -163,18 +166,18 @@ - (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *) - (void)webViewDidFinishLoad:(UIWebView *)webView { - if(webViewContent_) + if(_webViewContent) [self showWebView]; - CGRect frame = webView_.frame; + CGRect frame = _webView.frame; frame.size.height = 1; - webView_.frame = frame; - CGSize fittingSize = [webView_ sizeThatFits:CGSizeZero]; + _webView.frame = frame; + CGSize fittingSize = [_webView sizeThatFits:CGSizeZero]; frame.size = fittingSize; - webView_.frame = frame; + _webView.frame = frame; // 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]); } diff --git a/Classes/PSAppStoreHeader.h b/Classes/PSAppStoreHeader.h deleted file mode 100644 index 4f3d9466..00000000 --- a/Classes/PSAppStoreHeader.h +++ /dev/null @@ -1,39 +0,0 @@ -// -// Created by Peter Steinberger on 09.01.11. -// Copyright (c) 2011-2012 Peter Steinberger. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -#import - -@interface PSAppStoreHeader : UIView { - NSString *headerLabel_; - NSString *middleHeaderLabel_; - NSString *subHeaderLabel; - UIImage *iconImage_; - - UIImage *reflectedImage_; -} - -@property (nonatomic, copy) NSString *headerLabel; -@property (nonatomic, copy) NSString *middleHeaderLabel; -@property (nonatomic, copy) NSString *subHeaderLabel; -@property (nonatomic, retain) UIImage *iconImage; - -@end diff --git a/Classes/PSAppStoreHeader.m b/Classes/PSAppStoreHeader.m deleted file mode 100644 index e90c1e51..00000000 --- a/Classes/PSAppStoreHeader.m +++ /dev/null @@ -1,165 +0,0 @@ -// -// Created by Peter Steinberger on 09.01.11. -// Copyright (c) 2011-2012 Peter Steinberger. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -#import "PSAppStoreHeader.h" -#import "BITHockeyHelper.h" -#import "HockeySDKPrivate.h" - - -#define BIT_RGBCOLOR(r,g,b) [UIColor colorWithRed:(r)/255.0 green:(g)/255.0 blue:(b)/255.0 alpha:1] - -#define kLightGrayColor BIT_RGBCOLOR(200, 202, 204) -#define kDarkGrayColor BIT_RGBCOLOR(140, 141, 142) - -#define kImageHeight 57 -#define kReflectionHeight 20 -#define kImageBorderRadius 10 -#define kImageMargin 8 -#define kTextRow kImageMargin*2 + kImageHeight - -@implementation PSAppStoreHeader - -@synthesize headerLabel = headerLabel_; -@synthesize middleHeaderLabel = middleHeaderLabel_; -@synthesize subHeaderLabel; -@synthesize iconImage = iconImage_; - - -#pragma mark - NSObject - -- (id)initWithFrame:(CGRect)frame { - if ((self = [super initWithFrame:frame])) { - self.autoresizingMask = UIViewAutoresizingFlexibleWidth; - self.backgroundColor = kLightGrayColor; - } - return self; -} - -- (void)dealloc { - [headerLabel_ release]; - [middleHeaderLabel_ release]; - [subHeaderLabel release]; - [iconImage_ release]; - - [super dealloc]; -} - - -#pragma mark - UIView - -- (void)drawRect:(CGRect)rect { - CGRect bounds = self.bounds; - CGFloat globalWidth = self.frame.size.width; - CGContextRef context = UIGraphicsGetCurrentContext(); - - // draw the gradient - 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}); - CGPoint top = CGPointMake(CGRectGetMidX(bounds), bounds.origin.y); - CGPoint bottom = CGPointMake(CGRectGetMidX(bounds), CGRectGetMaxY(bounds)-kReflectionHeight); - CGContextDrawLinearGradient(context, gradient, top, bottom, 0); - CGGradientRelease(gradient); - - // draw header name - UIColor *mainTextColor = BIT_RGBCOLOR(0,0,0); - UIColor *secondaryTextColor = BIT_RGBCOLOR(48,48,48); - UIFont *mainFont = [UIFont boldSystemFontOfSize:20]; - UIFont *secondaryFont = [UIFont boldSystemFontOfSize:12]; - UIFont *smallFont = [UIFont systemFontOfSize:12]; - - float myColorValues[] = {255, 255, 255, .6}; - CGColorSpaceRef myColorSpace = CGColorSpaceCreateDeviceRGB(); - CGColorRef myColor = CGColorCreate(myColorSpace, myColorValues); - - // icon - [iconImage_ drawAtPoint:CGPointMake(kImageMargin, kImageMargin)]; - [reflectedImage_ drawAtPoint:CGPointMake(kImageMargin, kImageMargin+kImageHeight)]; - - // shadows are a beast - NSInteger shadowOffset = 2; - if([[UIScreen mainScreen] scale] == 2) shadowOffset = 1; - BITHOCKEY_IF_IOS5_OR_GREATER(shadowOffset = 1;) // iOS5 changes this - again! - - CGContextSetShadowWithColor(context, CGSizeMake(shadowOffset, shadowOffset), 0, myColor); - - [mainTextColor set]; - [headerLabel_ drawInRect:CGRectMake(kTextRow, kImageMargin, globalWidth-kTextRow, 20) withFont:mainFont lineBreakMode:UILineBreakModeTailTruncation]; - - // middle - [secondaryTextColor set]; - [middleHeaderLabel_ drawInRect:CGRectMake(kTextRow, kImageMargin + 25, globalWidth-kTextRow, 20) withFont:secondaryFont lineBreakMode:UILineBreakModeTailTruncation]; - CGContextSetShadowWithColor(context, CGSizeZero, 0, nil); - - // sub - [secondaryTextColor set]; - [subHeaderLabel drawAtPoint:CGPointMake(kTextRow, kImageMargin+kImageHeight-12) forWidth:globalWidth-kTextRow withFont:smallFont lineBreakMode:UILineBreakModeTailTruncation]; - - CGColorRelease(myColor); - CGColorSpaceRelease(myColorSpace); -} - - -#pragma mark - Properties - -- (void)setHeaderLabel:(NSString *)anHeaderLabel { - if (headerLabel_ != anHeaderLabel) { - [headerLabel_ release]; - headerLabel_ = [anHeaderLabel copy]; - [self setNeedsDisplay]; - } -} - -- (void)setMiddleHeaderLabel:(NSString *)aMiddleHeaderLabel { - if (middleHeaderLabel_ != aMiddleHeaderLabel) { - [middleHeaderLabel_ release]; - middleHeaderLabel_ = [aMiddleHeaderLabel copy]; - [self setNeedsDisplay]; - } -} - -- (void)setSubHeaderLabel:(NSString *)aSubHeaderLabel { - if (subHeaderLabel != aSubHeaderLabel) { - [subHeaderLabel release]; - subHeaderLabel = [aSubHeaderLabel copy]; - [self setNeedsDisplay]; - } -} - -- (void)setIconImage:(UIImage *)anIconImage { - if (iconImage_ != anIconImage) { - [iconImage_ release]; - - // scale, make borders and reflection - iconImage_ = bit_imageToFitSize(anIconImage, CGSizeMake(kImageHeight, kImageHeight), YES); - iconImage_ = [bit_roundedCornerImage(iconImage_, kImageBorderRadius, 0.0) retain]; - - // create reflected image - [reflectedImage_ release]; - reflectedImage_ = nil; - if (anIconImage) { - reflectedImage_ = [bit_reflectedImageWithHeight(iconImage_, kReflectionHeight, 0.5, 0.0) retain]; - } - [self setNeedsDisplay]; - } -} - -@end diff --git a/Classes/PSStoreButton.h b/Classes/PSStoreButton.h deleted file mode 100644 index 5efb5b4b..00000000 --- a/Classes/PSStoreButton.h +++ /dev/null @@ -1,78 +0,0 @@ -// -// Created by Peter Steinberger on 09.01.11. -// Copyright 2011-2012 Peter Steinberger. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -#import -#import - -// defines a button action set (data container) -@interface PSStoreButtonData : NSObject { - CGPoint customPadding_; - NSString *label_; - NSArray *colors_; - BOOL enabled_; -} - -+ (id)dataWithLabel:(NSString*)aLabel colors:(NSArray*)aColors enabled:(BOOL)flag; - -@property (nonatomic, copy) NSString *label; -@property (nonatomic, retain) NSArray *colors; -@property (nonatomic, assign, getter=isEnabled) BOOL enabled; - -@end - - -@class PSStoreButton; -@protocol PSStoreButtonDelegate -- (void)storeButtonFired:(PSStoreButton *)button; -@end - - -// Simulate the Paymeny-Button from the AppStore -// The interface is flexible, so there is now fixed order -@interface PSStoreButton : UIButton { - PSStoreButtonData *buttonData_; - id buttonDelegate_; - - CAGradientLayer *gradient_; - CGPoint customPadding_; -} - -- (id)initWithFrame:(CGRect)frame; -- (id)initWithPadding:(CGPoint)padding; - -// action delegate -@property (nonatomic, assign) id buttonDelegate; - -// change the button layer -@property (nonatomic, retain) PSStoreButtonData *buttonData; -- (void)setButtonData:(PSStoreButtonData *)aButtonData animated:(BOOL)animated; - -// align helper -@property (nonatomic, assign) CGPoint customPadding; -- (void)alignToSuperview; - -// helpers to mimic an AppStore button -+ (NSArray *)appStoreGreenColor; -+ (NSArray *)appStoreBlueColor; -+ (NSArray *)appStoreGrayColor; - -@end diff --git a/Classes/PSWebTableViewCell.h b/Classes/PSWebTableViewCell.h deleted file mode 100644 index e5549c01..00000000 --- a/Classes/PSWebTableViewCell.h +++ /dev/null @@ -1,41 +0,0 @@ -// -// Created by Peter Steinberger on 04.02.11. -// Copyright 2011-2012 Peter Steinberger. All rights reserved. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -#import -#import - -@interface PSWebTableViewCell : UITableViewCell { - UIWebView *webView_; - NSString *webViewContent_; - CGSize webViewSize_; - - UIColor *cellBackgroundColor_; -} - -@property (nonatomic, retain) UIWebView *webView; -@property (nonatomic, copy) NSString *webViewContent; -@property (nonatomic, assign) CGSize webViewSize; -@property (nonatomic, retain) UIColor *cellBackgroundColor; - -- (void)addWebView; - -@end diff --git a/Support/HockeySDK.xcodeproj/project.pbxproj b/Support/HockeySDK.xcodeproj/project.pbxproj index 5f123a9e..2bceac86 100644 --- a/Support/HockeySDK.xcodeproj/project.pbxproj +++ b/Support/HockeySDK.xcodeproj/project.pbxproj @@ -63,12 +63,12 @@ 1E49A4BB161222B900463151 /* BITHockeyBaseViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 1E49A4A4161222B900463151 /* BITHockeyBaseViewController.m */; }; 1E49A4BE161222B900463151 /* BITHockeyHelper.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E49A4A5161222B900463151 /* BITHockeyHelper.h */; }; 1E49A4C1161222B900463151 /* BITHockeyHelper.m in Sources */ = {isa = PBXBuildFile; fileRef = 1E49A4A6161222B900463151 /* BITHockeyHelper.m */; }; - 1E49A4C4161222B900463151 /* PSAppStoreHeader.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E49A4A7161222B900463151 /* PSAppStoreHeader.h */; }; - 1E49A4C7161222B900463151 /* PSAppStoreHeader.m in Sources */ = {isa = PBXBuildFile; fileRef = 1E49A4A8161222B900463151 /* PSAppStoreHeader.m */; }; - 1E49A4CA161222B900463151 /* PSStoreButton.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E49A4A9161222B900463151 /* PSStoreButton.h */; }; - 1E49A4CD161222B900463151 /* PSStoreButton.m in Sources */ = {isa = PBXBuildFile; fileRef = 1E49A4AA161222B900463151 /* PSStoreButton.m */; }; - 1E49A4D0161222B900463151 /* PSWebTableViewCell.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E49A4AB161222B900463151 /* PSWebTableViewCell.h */; }; - 1E49A4D3161222B900463151 /* PSWebTableViewCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 1E49A4AC161222B900463151 /* PSWebTableViewCell.m */; }; + 1E49A4C4161222B900463151 /* BITAppStoreHeader.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E49A4A7161222B900463151 /* BITAppStoreHeader.h */; }; + 1E49A4C7161222B900463151 /* BITAppStoreHeader.m in Sources */ = {isa = PBXBuildFile; fileRef = 1E49A4A8161222B900463151 /* BITAppStoreHeader.m */; }; + 1E49A4CA161222B900463151 /* BITStoreButton.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E49A4A9161222B900463151 /* BITStoreButton.h */; }; + 1E49A4CD161222B900463151 /* BITStoreButton.m in Sources */ = {isa = PBXBuildFile; fileRef = 1E49A4AA161222B900463151 /* BITStoreButton.m */; }; + 1E49A4D0161222B900463151 /* BITWebTableViewCell.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E49A4AB161222B900463151 /* BITWebTableViewCell.h */; }; + 1E49A4D3161222B900463151 /* BITWebTableViewCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 1E49A4AC161222B900463151 /* BITWebTableViewCell.m */; }; 1E49A4D8161222D400463151 /* HockeySDKPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E49A4D4161222D400463151 /* HockeySDKPrivate.h */; }; 1E49A4DB161222D400463151 /* HockeySDKPrivate.m in Sources */ = {isa = PBXBuildFile; fileRef = 1E49A4D5161222D400463151 /* HockeySDKPrivate.m */; }; 1E5954D315B6F24A00A03429 /* BITHockeyManager.m in Sources */ = {isa = PBXBuildFile; fileRef = E41EB466148D7BF50015DEDC /* BITHockeyManager.m */; }; @@ -151,12 +151,12 @@ 1E49A4A4161222B900463151 /* BITHockeyBaseViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = BITHockeyBaseViewController.m; sourceTree = ""; }; 1E49A4A5161222B900463151 /* BITHockeyHelper.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BITHockeyHelper.h; sourceTree = ""; }; 1E49A4A6161222B900463151 /* BITHockeyHelper.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = BITHockeyHelper.m; sourceTree = ""; }; - 1E49A4A7161222B900463151 /* PSAppStoreHeader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PSAppStoreHeader.h; sourceTree = ""; }; - 1E49A4A8161222B900463151 /* PSAppStoreHeader.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PSAppStoreHeader.m; sourceTree = ""; }; - 1E49A4A9161222B900463151 /* PSStoreButton.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PSStoreButton.h; sourceTree = ""; }; - 1E49A4AA161222B900463151 /* PSStoreButton.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PSStoreButton.m; sourceTree = ""; }; - 1E49A4AB161222B900463151 /* PSWebTableViewCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PSWebTableViewCell.h; sourceTree = ""; }; - 1E49A4AC161222B900463151 /* PSWebTableViewCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PSWebTableViewCell.m; sourceTree = ""; }; + 1E49A4A7161222B900463151 /* BITAppStoreHeader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BITAppStoreHeader.h; sourceTree = ""; }; + 1E49A4A8161222B900463151 /* BITAppStoreHeader.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = BITAppStoreHeader.m; sourceTree = ""; }; + 1E49A4A9161222B900463151 /* BITStoreButton.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BITStoreButton.h; sourceTree = ""; }; + 1E49A4AA161222B900463151 /* BITStoreButton.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = BITStoreButton.m; sourceTree = ""; }; + 1E49A4AB161222B900463151 /* BITWebTableViewCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BITWebTableViewCell.h; sourceTree = ""; }; + 1E49A4AC161222B900463151 /* BITWebTableViewCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = BITWebTableViewCell.m; sourceTree = ""; }; 1E49A4D4161222D400463151 /* HockeySDKPrivate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HockeySDKPrivate.h; sourceTree = ""; }; 1E49A4D5161222D400463151 /* HockeySDKPrivate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HockeySDKPrivate.m; sourceTree = ""; }; 1E5954F215B6F24A00A03429 /* libHockeySDK.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libHockeySDK.a; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -274,12 +274,12 @@ 1E49A4A6161222B900463151 /* BITHockeyHelper.m */, 1EACC979162F041E007578C5 /* BITAttributedLabel.h */, 1EACC97A162F041E007578C5 /* BITAttributedLabel.m */, - 1E49A4A7161222B900463151 /* PSAppStoreHeader.h */, - 1E49A4A8161222B900463151 /* PSAppStoreHeader.m */, - 1E49A4A9161222B900463151 /* PSStoreButton.h */, - 1E49A4AA161222B900463151 /* PSStoreButton.m */, - 1E49A4AB161222B900463151 /* PSWebTableViewCell.h */, - 1E49A4AC161222B900463151 /* PSWebTableViewCell.m */, + 1E49A4A7161222B900463151 /* BITAppStoreHeader.h */, + 1E49A4A8161222B900463151 /* BITAppStoreHeader.m */, + 1E49A4A9161222B900463151 /* BITStoreButton.h */, + 1E49A4AA161222B900463151 /* BITStoreButton.m */, + 1E49A4AB161222B900463151 /* BITWebTableViewCell.h */, + 1E49A4AC161222B900463151 /* BITWebTableViewCell.m */, ); name = Helper; sourceTree = ""; @@ -430,9 +430,9 @@ 1E49A4B5161222B900463151 /* BITHockeyBaseManagerPrivate.h in Headers */, 1E49A4B8161222B900463151 /* BITHockeyBaseViewController.h in Headers */, 1E49A4BE161222B900463151 /* BITHockeyHelper.h in Headers */, - 1E49A4C4161222B900463151 /* PSAppStoreHeader.h in Headers */, - 1E49A4CA161222B900463151 /* PSStoreButton.h in Headers */, - 1E49A4D0161222B900463151 /* PSWebTableViewCell.h in Headers */, + 1E49A4C4161222B900463151 /* BITAppStoreHeader.h in Headers */, + 1E49A4CA161222B900463151 /* BITStoreButton.h in Headers */, + 1E49A4D0161222B900463151 /* BITWebTableViewCell.h in Headers */, 1E49A4D8161222D400463151 /* HockeySDKPrivate.h in Headers */, 1EC69F601615001500808FD9 /* BITHockeyManagerPrivate.h in Headers */, 1E754E5C1621FBB70070AB92 /* BITCrashManager.h in Headers */, @@ -596,9 +596,9 @@ 1E49A4B2161222B900463151 /* BITHockeyBaseManager.m in Sources */, 1E49A4BB161222B900463151 /* BITHockeyBaseViewController.m in Sources */, 1E49A4C1161222B900463151 /* BITHockeyHelper.m in Sources */, - 1E49A4C7161222B900463151 /* PSAppStoreHeader.m in Sources */, - 1E49A4CD161222B900463151 /* PSStoreButton.m in Sources */, - 1E49A4D3161222B900463151 /* PSWebTableViewCell.m in Sources */, + 1E49A4C7161222B900463151 /* BITAppStoreHeader.m in Sources */, + 1E49A4CD161222B900463151 /* BITStoreButton.m in Sources */, + 1E49A4D3161222B900463151 /* BITWebTableViewCell.m in Sources */, 1E49A4DB161222D400463151 /* HockeySDKPrivate.m in Sources */, 1E754E5D1621FBB70070AB92 /* BITCrashManager.m in Sources */, 1E754E611621FBB70070AB92 /* BITCrashReportTextFormatter.m in Sources */, From 76a7ec78b11e98a282092eb2b7ae85d1f69025b0 Mon Sep 17 00:00:00 2001 From: Andreas Linde Date: Sun, 21 Oct 2012 00:49:02 +0200 Subject: [PATCH 076/176] Be more conservative with returned JSON for feedback messages --- Classes/BITFeedbackListViewCell.m | 6 +++--- Classes/BITFeedbackManager.m | 26 ++++++++++++++------------ 2 files changed, 17 insertions(+), 15 deletions(-) diff --git a/Classes/BITFeedbackListViewCell.m b/Classes/BITFeedbackListViewCell.m index ec5d2a93..5ae14785 100644 --- a/Classes/BITFeedbackListViewCell.m +++ b/Classes/BITFeedbackListViewCell.m @@ -160,17 +160,17 @@ - (void)layoutSubviews { [self addSubview:accessoryViewBackground]; // header - NSString *dateString; + NSString *dateString = @""; if (_message.status == BITFeedbackMessageStatusSendPending || _message.status == BITFeedbackMessageStatusSendInProgress) { dateString = BITHockeyLocalizedString(@"Pending"); - } else { + } else if (_message.date) { if ([self isSameDayWithDate1:[NSDate date] date2:_message.date]) { dateString = [self.timeFormatter stringFromDate:_message.date]; } else { dateString = [self.dateFormatter stringFromDate:_message.date]; } } - [self.labelTitle setText:dateString];// [self.date description]]; + [self.labelTitle setText:dateString]; [self.labelTitle setFrame:CGRectMake(FRAME_SIDE_BORDER, FRAME_TOP_BORDER + LABEL_TITLE_Y, self.frame.size.width - (2 * FRAME_SIDE_BORDER), LABEL_TITLE_HEIGHT)]; if (_message.userMessage) { diff --git a/Classes/BITFeedbackManager.m b/Classes/BITFeedbackManager.m index e848d089..923416a1 100644 --- a/Classes/BITFeedbackManager.m +++ b/Classes/BITFeedbackManager.m @@ -609,18 +609,20 @@ - (void)updateMessageListFromResponse:(NSDictionary *)jsonDictionary { matchingSendInProgressOrInConflictMessage.id = messageID; matchingSendInProgressOrInConflictMessage.status = BITFeedbackMessageStatusRead; } else { - BITFeedbackMessage *message = [[[BITFeedbackMessage alloc] init] autorelease]; - message.text = [(NSDictionary *)objMessage objectForKey:@"text"]; - message.name = [(NSDictionary *)objMessage objectForKey:@"name"]; - message.email = [(NSDictionary *)objMessage objectForKey:@"email"]; - - message.date = [self parseRFC3339Date:[(NSDictionary *)objMessage objectForKey:@"created_at"]]; - message.id = [(NSDictionary *)objMessage objectForKey:@"id"]; - message.status = BITFeedbackMessageStatusUnread; - - [_feedbackList addObject:message]; - - newMessage = YES; + if ([(NSDictionary *)objMessage objectForKey:@"id"] && [(NSDictionary *)objMessage objectForKey:@"text"]) { + BITFeedbackMessage *message = [[[BITFeedbackMessage alloc] init] autorelease]; + message.text = [(NSDictionary *)objMessage objectForKey:@"text"] ?: @""; + message.name = [(NSDictionary *)objMessage objectForKey:@"name"] ?: @""; + message.email = [(NSDictionary *)objMessage objectForKey:@"email"] ?: @""; + + message.date = [self parseRFC3339Date:[(NSDictionary *)objMessage objectForKey:@"created_at"]] ?: [NSDate date]; + message.id = [(NSDictionary *)objMessage objectForKey:@"id"]; + message.status = BITFeedbackMessageStatusUnread; + + [_feedbackList addObject:message]; + + newMessage = YES; + } } } else { // we should never get any messages back that are already stored locally, From a6c2b9a1b5a7deee34043c3b4c845c090a726cb9 Mon Sep 17 00:00:00 2001 From: Andreas Linde Date: Sun, 21 Oct 2012 00:51:28 +0200 Subject: [PATCH 077/176] Some more --- Classes/BITFeedbackManager.m | 74 ++++++++++++++++++------------------ 1 file changed, 38 insertions(+), 36 deletions(-) diff --git a/Classes/BITFeedbackManager.m b/Classes/BITFeedbackManager.m index 923416a1..459bf566 100644 --- a/Classes/BITFeedbackManager.m +++ b/Classes/BITFeedbackManager.m @@ -587,46 +587,48 @@ - (void)updateMessageListFromResponse:(NSDictionary *)jsonDictionary { __block NSMutableSet *returnedMessageIDs = [[[NSMutableSet alloc] init] autorelease]; [feedMessages enumerateObjectsUsingBlock:^(id objMessage, NSUInteger messagesIdx, BOOL *stop) { - NSNumber *messageID = [(NSDictionary *)objMessage objectForKey:@"id"]; - [returnedMessageIDs addObject:messageID]; - - BITFeedbackMessage *thisMessage = [self messageWithID:messageID]; - if (!thisMessage) { - // check if this is a message that was sent right now - __block BITFeedbackMessage *matchingSendInProgressOrInConflictMessage = nil; - - // TODO: match messages in state conflict + if ([(NSDictionary *)objMessage objectForKey:@"id"]) { + NSNumber *messageID = [(NSDictionary *)objMessage objectForKey:@"id"]; + [returnedMessageIDs addObject:messageID]; - [messagesSendInProgress enumerateObjectsUsingBlock:^(id objSendInProgressMessage, NSUInteger messagesSendInProgressIdx, BOOL *stop) { - if ([[(NSDictionary *)objMessage objectForKey:@"token"] isEqualToString:[(BITFeedbackMessage *)objSendInProgressMessage token]]) { - matchingSendInProgressOrInConflictMessage = objSendInProgressMessage; - *stop = YES; + BITFeedbackMessage *thisMessage = [self messageWithID:messageID]; + if (!thisMessage) { + // check if this is a message that was sent right now + __block BITFeedbackMessage *matchingSendInProgressOrInConflictMessage = nil; + + // TODO: match messages in state conflict + + [messagesSendInProgress enumerateObjectsUsingBlock:^(id objSendInProgressMessage, NSUInteger messagesSendInProgressIdx, BOOL *stop) { + if ([[(NSDictionary *)objMessage objectForKey:@"token"] isEqualToString:[(BITFeedbackMessage *)objSendInProgressMessage token]]) { + matchingSendInProgressOrInConflictMessage = objSendInProgressMessage; + *stop = YES; + } + }]; + + if (matchingSendInProgressOrInConflictMessage) { + matchingSendInProgressOrInConflictMessage.date = [self parseRFC3339Date:[(NSDictionary *)objMessage objectForKey:@"created_at"]]; + matchingSendInProgressOrInConflictMessage.id = messageID; + matchingSendInProgressOrInConflictMessage.status = BITFeedbackMessageStatusRead; + } else { + if ([(NSDictionary *)objMessage objectForKey:@"text"]) { + BITFeedbackMessage *message = [[[BITFeedbackMessage alloc] init] autorelease]; + message.text = [(NSDictionary *)objMessage objectForKey:@"text"] ?: @""; + message.name = [(NSDictionary *)objMessage objectForKey:@"name"] ?: @""; + message.email = [(NSDictionary *)objMessage objectForKey:@"email"] ?: @""; + + message.date = [self parseRFC3339Date:[(NSDictionary *)objMessage objectForKey:@"created_at"]] ?: [NSDate date]; + message.id = [(NSDictionary *)objMessage objectForKey:@"id"]; + message.status = BITFeedbackMessageStatusUnread; + + [_feedbackList addObject:message]; + + newMessage = YES; + } } - }]; - - if (matchingSendInProgressOrInConflictMessage) { - matchingSendInProgressOrInConflictMessage.date = [self parseRFC3339Date:[(NSDictionary *)objMessage objectForKey:@"created_at"]]; - matchingSendInProgressOrInConflictMessage.id = messageID; - matchingSendInProgressOrInConflictMessage.status = BITFeedbackMessageStatusRead; } else { - if ([(NSDictionary *)objMessage objectForKey:@"id"] && [(NSDictionary *)objMessage objectForKey:@"text"]) { - BITFeedbackMessage *message = [[[BITFeedbackMessage alloc] init] autorelease]; - message.text = [(NSDictionary *)objMessage objectForKey:@"text"] ?: @""; - message.name = [(NSDictionary *)objMessage objectForKey:@"name"] ?: @""; - message.email = [(NSDictionary *)objMessage objectForKey:@"email"] ?: @""; - - message.date = [self parseRFC3339Date:[(NSDictionary *)objMessage objectForKey:@"created_at"]] ?: [NSDate date]; - message.id = [(NSDictionary *)objMessage objectForKey:@"id"]; - message.status = BITFeedbackMessageStatusUnread; - - [_feedbackList addObject:message]; - - newMessage = YES; - } + // we should never get any messages back that are already stored locally, + // since we add the last_message_id to the request } - } else { - // we should never get any messages back that are already stored locally, - // since we add the last_message_id to the request } }]; From 1eb68fece6f1b7b76aeb1999ddf6d28b192a75f6 Mon Sep 17 00:00:00 2001 From: Andreas Linde Date: Sun, 21 Oct 2012 01:10:22 +0200 Subject: [PATCH 078/176] Minor clean up --- Classes/BITAppStoreHeader.m | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/Classes/BITAppStoreHeader.m b/Classes/BITAppStoreHeader.m index d31ffbd9..b2c7c880 100644 --- a/Classes/BITAppStoreHeader.m +++ b/Classes/BITAppStoreHeader.m @@ -89,20 +89,9 @@ - (void)drawRect:(CGRect)rect { UIFont *mainFont = [UIFont boldSystemFontOfSize:15]; UIFont *secondaryFont = [UIFont systemFontOfSize:10]; -// float myColorValues[] = {255, 255, 255, .6}; -// CGColorSpaceRef myColorSpace = CGColorSpaceCreateDeviceRGB(); -// CGColorRef myColor = CGColorCreate(myColorSpace, myColorValues); - // icon [_iconImage drawAtPoint:CGPointMake(kImageLeftMargin, kImageTopMargin)]; - // shadows are a beast -// NSInteger shadowOffset = 2; -// if([[UIScreen mainScreen] scale] == 2) shadowOffset = 1; -// BITHOCKEY_IF_IOS5_OR_GREATER(shadowOffset = 1;) // iOS5 changes this - again! -// -// CGContextSetShadowWithColor(context, CGSizeMake(shadowOffset, shadowOffset), 0, myColor); - [mainTextColor set]; [_headerLabel drawInRect:CGRectMake(kTextRow, kImageTopMargin, globalWidth-kTextRow, 20) withFont:mainFont lineBreakMode:UILineBreakModeTailTruncation]; @@ -114,9 +103,6 @@ - (void)drawRect:(CGRect)rect { // sub [secondaryTextColor set]; [_subHeaderLabel drawAtPoint:CGPointMake(kTextRow, kImageTopMargin + 29) forWidth:globalWidth-kTextRow withFont:secondaryFont lineBreakMode:UILineBreakModeTailTruncation]; - -// CGColorRelease(myColor); -// CGColorSpaceRelease(myColorSpace); } From aee5c4adda1f90ecc56e60b76e228bc693b9f8f6 Mon Sep 17 00:00:00 2001 From: Andreas Linde Date: Mon, 22 Oct 2012 01:08:26 +0200 Subject: [PATCH 079/176] Update update view to be more iOS 6 like Not completely finished yet --- Classes/BITAppStoreHeader.m | 2 - Classes/BITHockeyBaseManager.h | 14 ++++ Classes/BITHockeyBaseManager.m | 7 +- Classes/BITStoreButton.h | 18 +---- Classes/BITStoreButton.m | 105 ++++++++++-------------------- Classes/BITUpdateManager.m | 1 + Classes/BITUpdateViewController.m | 85 ++++++++++-------------- 7 files changed, 94 insertions(+), 138 deletions(-) diff --git a/Classes/BITAppStoreHeader.m b/Classes/BITAppStoreHeader.m index b2c7c880..db46d83e 100644 --- a/Classes/BITAppStoreHeader.m +++ b/Classes/BITAppStoreHeader.m @@ -34,8 +34,6 @@ #import "HockeySDKPrivate.h" -#define BIT_RGBCOLOR(r,g,b) [UIColor colorWithRed:(r)/255.0 green:(g)/255.0 blue:(b)/255.0 alpha:1] - #define kLightGrayColor BIT_RGBCOLOR(235, 235, 235) #define kDarkGrayColor BIT_RGBCOLOR(186, 186, 186) #define kWhiteBackgroundColor BIT_RGBCOLOR(245, 245, 245) diff --git a/Classes/BITHockeyBaseManager.h b/Classes/BITHockeyBaseManager.h index 3e3340ee..234874df 100644 --- a/Classes/BITHockeyBaseManager.h +++ b/Classes/BITHockeyBaseManager.h @@ -33,9 +33,23 @@ /** The UIBarStyle of the update user interface navigation bar. + + Default is UIBarStyleBlackOpaque + @see tintColor */ @property (nonatomic, assign) UIBarStyle barStyle; +/** + The tint color of the update user interface navigation bar. + + The tintColor is used by default, you can either overwrite it `tintColor` + or define another `barStyle` instead. + + Default is RGB(25, 25, 25) + @see barStyle + */ +@property (nonatomic, retain) UIColor *tintColor; + /** The UIModalPresentationStyle for showing the update user interface when invoked with the update alert. diff --git a/Classes/BITHockeyBaseManager.m b/Classes/BITHockeyBaseManager.m index d255b88c..17db241d 100644 --- a/Classes/BITHockeyBaseManager.m +++ b/Classes/BITHockeyBaseManager.m @@ -38,7 +38,8 @@ - (id)init { _serverURL = BITHOCKEYSDK_URL; _navController = nil; - _barStyle = UIBarStyleDefault; + _barStyle = UIBarStyleBlackOpaque; + self.tintColor = BIT_RGBCOLOR(25, 25, 25); _modalPresentationStyle = UIModalPresentationFormSheet; NSLocale *enUSPOSIXLocale = [[[NSLocale alloc] initWithLocaleIdentifier:@"en_US_POSIX"] autorelease]; @@ -67,6 +68,8 @@ - (void)dealloc { [_navController release], _navController = nil; [_rfc3339Formatter release], _rfc3339Formatter = nil; + + [_tintColor release], _tintColor = nil; [super dealloc]; } @@ -167,6 +170,7 @@ - (void)showView:(UIViewController *)viewController { _navController = [[UINavigationController alloc] initWithRootViewController:viewController]; _navController.navigationBar.barStyle = _barStyle; + _navController.navigationBar.tintColor = _tintColor; _navController.modalPresentationStyle = _modalPresentationStyle; if (parentViewController) { @@ -191,6 +195,7 @@ - (void)showView:(UIViewController *)viewController { } } + #pragma mark - Manager Control - (void)startManager { diff --git a/Classes/BITStoreButton.h b/Classes/BITStoreButton.h index 25d7de10..a54f4475 100644 --- a/Classes/BITStoreButton.h +++ b/Classes/BITStoreButton.h @@ -29,18 +29,14 @@ */ -#import #import // defines a button action set (data container) -@interface BITStoreButtonData : NSObject { - CGPoint _customPadding; -} +@interface BITStoreButtonData : NSObject -+ (id)dataWithLabel:(NSString*)aLabel colors:(NSArray*)aColors enabled:(BOOL)flag; ++ (id)dataWithLabel:(NSString*)aLabel enabled:(BOOL)flag; @property (nonatomic, copy) NSString *label; -@property (nonatomic, retain) NSArray *colors; @property (nonatomic, assign, getter=isEnabled) BOOL enabled; @end @@ -54,10 +50,7 @@ // Simulate the Paymeny-Button from the AppStore // The interface is flexible, so there is now fixed order -@interface BITStoreButton : UIButton { - CAGradientLayer *_gradient; - CGPoint _customPadding; -} +@interface BITStoreButton : UIButton - (id)initWithFrame:(CGRect)frame; - (id)initWithPadding:(CGPoint)padding; @@ -73,9 +66,4 @@ @property (nonatomic, assign) CGPoint customPadding; - (void)alignToSuperview; -// helpers to mimic an AppStore button -+ (NSArray *)appStoreGreenColor; -+ (NSArray *)appStoreBlueColor; -+ (NSArray *)appStoreGrayColor; - @end diff --git a/Classes/BITStoreButton.m b/Classes/BITStoreButton.m index 615c42a2..9cd5480c 100644 --- a/Classes/BITStoreButton.m +++ b/Classes/BITStoreButton.m @@ -30,11 +30,12 @@ #import "BITStoreButton.h" +#import "HockeySDKPrivate.h" +#import -#define PS_RGBCOLOR(r,g,b) [UIColor colorWithRed:(r)/255.0 green:(g)/255.0 blue:(b)/255.0 alpha:1] -#define PS_MIN_HEIGHT 25.0f -#define PS_MAX_WIDTH 120.0f -#define PS_PADDING 12.0f +#define BIT_MIN_HEIGHT 25.0f +#define BIT_MAX_WIDTH 120.0f +#define BIT_PADDING 12.0f #define kDefaultButtonAnimationTime 0.25f @@ -42,34 +43,26 @@ @implementation BITStoreButtonData #pragma mark - NSObject -- (id)initWithLabel:(NSString*)aLabel colors:(NSArray*)aColors enabled:(BOOL)flag { +- (id)initWithLabel:(NSString*)aLabel enabled:(BOOL)flag { if ((self = [super init])) { self.label = aLabel; - self.colors = aColors; self.enabled = flag; } return self; } -+ (id)dataWithLabel:(NSString*)aLabel colors:(NSArray*)aColors enabled:(BOOL)flag { - return [[[[self class] alloc] initWithLabel:aLabel colors:aColors enabled:flag] autorelease]; ++ (id)dataWithLabel:(NSString*)aLabel enabled:(BOOL)flag { + return [[[[self class] alloc] initWithLabel:aLabel enabled:flag] autorelease]; } - (void)dealloc { [_label release], _label = nil; - [_colors release]; [super dealloc]; } @end -@interface BITStoreButton () -// call when buttonData was updated -- (void)updateButtonAnimated:(BOOL)animated; -@end - - @implementation BITStoreButton #pragma mark - private @@ -94,21 +87,17 @@ - (void)updateButtonAnimated:(BOOL)animated { [UIView setAnimationDuration:kDefaultButtonAnimationTime]; [UIView setAnimationDelegate:self]; [UIView setAnimationDidStopSelector:@selector(animationDidStop:finished:context:)]; - }else { + } 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]; + [self setTitleColor:BIT_RGBCOLOR(106, 106, 106) forState:UIControlStateNormal]; + } else { + [self setTitleColor:BIT_RGBCOLOR(148, 150, 151) forState:UIControlStateNormal]; } // calculate optimal new size @@ -121,7 +110,7 @@ - (void)updateButtonAnimated:(BOOL)animated { if (animated) { [CATransaction setAnimationDuration:kDefaultButtonAnimationTime]; [CATransaction setAnimationTimingFunction:[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut]]; - }else { + } else { // frame is calculated and explicitely animated. so we absolutely need kCATransactionDisableActions [CATransaction setValue:[NSNumber numberWithBool:YES] forKey:kCATransactionDisableActions]; } @@ -165,35 +154,31 @@ - (id)initWithFrame:(CGRect)frame { // register for touch events [self addTarget:self action:@selector(buttonPressed:) forControlEvents:UIControlEventTouchUpInside]; - // border layers for more sex! - CAGradientLayer *bevelLayer = [CAGradientLayer layer]; - 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.cornerRadius = 2.5; - bevelLayer.needsDisplayOnBoundsChange = YES; - [self.layer addSublayer:bevelLayer]; - - CAGradientLayer *topBorderLayer = [CAGradientLayer layer]; - 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.cornerRadius = 2.6; - topBorderLayer.needsDisplayOnBoundsChange = YES; - [self.layer addSublayer:topBorderLayer]; - // main gradient layer - _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.frame = CGRectMake(0.75, 0.75, CGRectGetWidth(frame) - 1.5, CGRectGetHeight(frame) - 1.5); - _gradient.cornerRadius = 2.5; - _gradient.needsDisplayOnBoundsChange = YES; - [self.layer addSublayer:_gradient]; + CAGradientLayer *gradient = [CAGradientLayer layer]; + gradient.colors = @[(id)BIT_RGBCOLOR(243, 243, 243).CGColor, (id)BIT_RGBCOLOR(222, 222, 222).CGColor]; + gradient.locations = @[[NSNumber numberWithFloat:0.0], [NSNumber numberWithFloat:1.0]]; + gradient.frame = CGRectMake(0.0, 0.0, CGRectGetWidth(frame), CGRectGetHeight(frame)); + gradient.cornerRadius = 2.5; + gradient.needsDisplayOnBoundsChange = YES; + [self.layer addSublayer:gradient]; + + // border layers for more sex! + CALayer *borderLayer = [CALayer layer]; + borderLayer.borderColor = [BIT_RGBCOLOR(191, 191, 191) CGColor]; + borderLayer.borderWidth = 1.0; + borderLayer.frame = CGRectMake(0.0, 0.0, CGRectGetWidth(frame), CGRectGetHeight(frame)); + borderLayer.cornerRadius = 2.5; + borderLayer.needsDisplayOnBoundsChange = YES; + [self.layer addSublayer:borderLayer]; + [self bringSubviewToFront:self.titleLabel]; } return self; } - (id)initWithPadding:(CGPoint)padding { - if ((self = [self initWithFrame:CGRectMake(0, 0, 40, PS_MIN_HEIGHT)])) { + if ((self = [self initWithFrame:CGRectMake(0, 0, 40, BIT_MIN_HEIGHT)])) { _customPadding = padding; } return self; @@ -201,7 +186,6 @@ - (id)initWithPadding:(CGPoint)padding { - (void)dealloc { [_buttonData release]; - [_gradient release]; [super dealloc]; } @@ -210,10 +194,10 @@ - (void)dealloc { #pragma mark - UIView - (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 = BIT_MAX_WIDTH}; CGSize newSize = [self.buttonData.label sizeWithFont:self.titleLabel.font constrainedToSize:constr lineBreakMode:UILineBreakModeMiddleTruncation]; - CGFloat newWidth = newSize.width + (PS_PADDING * 2); - CGFloat newHeight = PS_MIN_HEIGHT > newSize.height ? PS_MIN_HEIGHT : newSize.height; + CGFloat newWidth = newSize.width + (BIT_PADDING * 2); + CGFloat newHeight = BIT_MIN_HEIGHT > newSize.height ? BIT_MIN_HEIGHT : newSize.height; CGSize sizeThatFits = CGSizeMake(newWidth, newHeight); return sizeThatFits; @@ -248,25 +232,4 @@ - (void)setButtonData:(BITStoreButtonData *)aButtonData animated:(BOOL)animated [self updateButtonAnimated:animated]; } - -#pragma mark - Static - -+ (NSArray *)appStoreGreenColor { - return [NSArray arrayWithObjects:(id) - [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]; -} - -+ (NSArray *)appStoreBlueColor { - return [NSArray arrayWithObjects:(id) - [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]; -} - -+ (NSArray *)appStoreGrayColor { - return [NSArray arrayWithObjects:(id) - PS_RGBCOLOR(187,189,191).CGColor, - PS_RGBCOLOR(210,210,210).CGColor, nil]; -} - @end diff --git a/Classes/BITUpdateManager.m b/Classes/BITUpdateManager.m index 43ea0734..1cc9b496 100644 --- a/Classes/BITUpdateManager.m +++ b/Classes/BITUpdateManager.m @@ -408,6 +408,7 @@ - (void)showUpdateView { return; } + self.barStyle = UIBarStyleBlack; [self showView:[self hockeyViewController:YES]]; } diff --git a/Classes/BITUpdateViewController.m b/Classes/BITUpdateViewController.m index d5997a10..c22e1077 100644 --- a/Classes/BITUpdateViewController.m +++ b/Classes/BITUpdateViewController.m @@ -76,20 +76,20 @@ - (void)restoreStoreButtonStateAnimated:(BOOL)animated { - (void)updateAppStoreHeader { BITAppVersionMetaInfo *appVersion = _updateManager.newestAppVersion; _appStoreHeader.headerLabel = appVersion.name; - _appStoreHeader.middleHeaderLabel = [appVersion versionString]; - NSDateFormatter *formatter = [[[NSDateFormatter alloc] init] autorelease]; - [formatter setDateStyle:NSDateFormatterMediumStyle]; - NSMutableString *subHeaderString = [NSMutableString string]; - if (appVersion.date) { - [subHeaderString appendString:[formatter stringFromDate:appVersion.date]]; - } - if (appVersion.size) { - if ([subHeaderString length]) { - [subHeaderString appendString:@" - "]; - } - [subHeaderString appendString:appVersion.sizeInMB]; - } - _appStoreHeader.subHeaderLabel = subHeaderString; + _appStoreHeader.middleHeaderLabel = [_updateManager currentAppVersion];// [appVersion versionString]; +// NSDateFormatter *formatter = [[[NSDateFormatter alloc] init] autorelease]; +// [formatter setDateStyle:NSDateFormatterMediumStyle]; +// NSMutableString *subHeaderString = [NSMutableString string]; +// if (appVersion.date) { +// [subHeaderString appendString:[formatter stringFromDate:appVersion.date]]; +// } +// if (appVersion.size) { +// if ([subHeaderString length]) { +// [subHeaderString appendString:@" - "]; +// } +// [subHeaderString appendString:appVersion.sizeInMB]; +// } +// _appStoreHeader.subHeaderLabel = subHeaderString; } - (void)appDidBecomeActive { @@ -190,20 +190,30 @@ - (void)showHidePreviousVersionsButton { - (void)configureWebCell:(BITWebTableViewCell *)cell forAppVersion:(BITAppVersionMetaInfo *)appVersion { // create web view for a version + NSMutableString *dateAndSizeString = [NSMutableString string]; + if (appVersion.date) { + [dateAndSizeString appendString:[appVersion dateString]]; + } + if (appVersion.size) { + if ([dateAndSizeString length]) { + [dateAndSizeString appendString:@" - "]; + } + [dateAndSizeString appendString:appVersion.sizeInMB]; + } + NSString *installed = @""; if ([appVersion.version isEqualToString:[_updateManager currentAppVersion]]) { - installed = [NSString stringWithFormat:@"%@", [appVersion isEqual:_updateManager.newestAppVersion] ? @"left" : @"right", BITHockeyLocalizedString(@"UpdateInstalled")]; + installed = [NSString stringWithFormat:@"%@", BITHockeyLocalizedString(@"UpdateInstalled")]; } if ([appVersion isEqual:_updateManager.newestAppVersion]) { if ([appVersion.notes length] > 0) { - installed = [NSString stringWithFormat:@"

 %@

", installed]; - cell.webViewContent = [NSString stringWithFormat:@"%@%@", installed, appVersion.notes]; + cell.webViewContent = [NSString stringWithFormat:@"

%@%@
%@

%@

", [appVersion versionString], installed, dateAndSizeString, appVersion.notes]; } else { cell.webViewContent = [NSString stringWithFormat:@"
%@
", BITHockeyLocalizedString(@"UpdateNoReleaseNotesAvailable")]; } } else { - cell.webViewContent = [NSString stringWithFormat:@"

%@%@
%@

%@

", [appVersion versionString], installed, [appVersion dateString], [appVersion notesOrEmptyString]]; + cell.webViewContent = [NSString stringWithFormat:@"

%@%@
%@

%@

", [appVersion versionString], installed, dateAndSizeString, [appVersion notesOrEmptyString]]; } cell.cellBackgroundColor = BIT_RGBCOLOR(235, 235, 235); @@ -255,29 +265,6 @@ - (void)dealloc { #pragma mark - View lifecycle -//- (CAGradientLayer *)backgroundLayer { -// UIColor *colorOne = [UIColor colorWithWhite:0.9 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 *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]; -// -// NSNumber *stopOne = [NSNumber numberWithFloat:0.0]; -// NSNumber *stopTwo = [NSNumber numberWithFloat:0.02]; -// NSNumber *stopThree = [NSNumber numberWithFloat:0.99]; -// NSNumber *stopFour = [NSNumber numberWithFloat:1.0]; -// -// NSArray *locations = [NSArray arrayWithObjects:stopOne, stopTwo, stopThree, stopFour, nil]; -// -// CAGradientLayer *headerLayer = [CAGradientLayer layer]; -// //headerLayer.frame = CGRectMake(0.0, 0.0, 320.0, 77.0); -// headerLayer.colors = colors; -// headerLayer.locations = locations; -// -// return headerLayer; -//} - - (void)viewDidLoad { [super viewDidLoad]; @@ -292,12 +279,12 @@ - (void)viewDidLoad { [_updateManager addObserver:self forKeyPath:@"apps" options:0 context:nil]; _kvoRegistered = YES; - self.tableView.backgroundColor = BIT_RGBCOLOR(235, 235, 235); + self.tableView.backgroundColor = BIT_RGBCOLOR(245, 245, 245); self.tableView.separatorStyle = UITableViewCellSeparatorStyleNone; UIView *topView = [[[UIView alloc] initWithFrame:CGRectMake(0, -(600-kAppStoreViewHeight), self.view.frame.size.width, 600)] autorelease]; topView.autoresizingMask = UIViewAutoresizingFlexibleWidth; - topView.backgroundColor = BIT_RGBCOLOR(140, 141, 142); + topView.backgroundColor = BIT_RGBCOLOR(245, 245, 245); [self.tableView addSubview:topView]; _appStoreHeader = [[BITAppStoreHeader alloc] initWithFrame:CGRectMake(0, 0, self.view.frame.size.width, kAppStoreViewHeight)]; @@ -359,7 +346,7 @@ - (void)viewDidLoad { storeButton.autoresizingMask = UIViewAutoresizingFlexibleLeftMargin; storeButton.buttonDelegate = self; [self.tableView.tableHeaderView addSubview:storeButton]; - storeButton.buttonData = [BITStoreButtonData dataWithLabel:@"" colors:[BITStoreButton appStoreGrayColor] enabled:NO]; + storeButton.buttonData = [BITStoreButtonData dataWithLabel:@"" enabled:NO]; [storeButton alignToSuperview]; _appStoreButton = [storeButton retain]; self.appStoreButtonState = AppStoreButtonStateCheck; @@ -531,19 +518,19 @@ - (void)setAppStoreButtonState:(AppStoreButtonState)anAppStoreButtonState animat switch (anAppStoreButtonState) { case AppStoreButtonStateOffline: - [_appStoreButton setButtonData:[BITStoreButtonData dataWithLabel:BITHockeyLocalizedString(@"UpdateButtonOffline") colors:[BITStoreButton appStoreGrayColor] enabled:NO] animated:animated]; + [_appStoreButton setButtonData:[BITStoreButtonData dataWithLabel:BITHockeyLocalizedString(@"UpdateButtonOffline") enabled:NO] animated:animated]; break; case AppStoreButtonStateCheck: - [_appStoreButton setButtonData:[BITStoreButtonData dataWithLabel:BITHockeyLocalizedString(@"UpdateButtonCheck") colors:[BITStoreButton appStoreGreenColor] enabled:YES] animated:animated]; + [_appStoreButton setButtonData:[BITStoreButtonData dataWithLabel:BITHockeyLocalizedString(@"UpdateButtonCheck") enabled:YES] animated:animated]; break; case AppStoreButtonStateSearching: - [_appStoreButton setButtonData:[BITStoreButtonData dataWithLabel:BITHockeyLocalizedString(@"UpdateButtonSearching") colors:[BITStoreButton appStoreGrayColor] enabled:NO] animated:animated]; + [_appStoreButton setButtonData:[BITStoreButtonData dataWithLabel:BITHockeyLocalizedString(@"UpdateButtonSearching") enabled:NO] animated:animated]; break; case AppStoreButtonStateUpdate: - [_appStoreButton setButtonData:[BITStoreButtonData dataWithLabel:BITHockeyLocalizedString(@"UpdateButtonUpdate") colors:[BITStoreButton appStoreBlueColor] enabled:YES] animated:animated]; + [_appStoreButton setButtonData:[BITStoreButtonData dataWithLabel:BITHockeyLocalizedString(@"UpdateButtonUpdate") enabled:YES] animated:animated]; break; case AppStoreButtonStateInstalling: - [_appStoreButton setButtonData:[BITStoreButtonData dataWithLabel:BITHockeyLocalizedString(@"UpdateButtonInstalling") colors:[BITStoreButton appStoreGrayColor] enabled:NO] animated:animated]; + [_appStoreButton setButtonData:[BITStoreButtonData dataWithLabel:BITHockeyLocalizedString(@"UpdateButtonInstalling") enabled:NO] animated:animated]; break; default: break; From 9e436f3d2673db6697347f452398f875c16b5382 Mon Sep 17 00:00:00 2001 From: Andreas Linde Date: Mon, 22 Oct 2012 01:09:22 +0200 Subject: [PATCH 080/176] Fix done button in modal feedback and update view missing --- Classes/BITHockeyBaseViewController.m | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) diff --git a/Classes/BITHockeyBaseViewController.m b/Classes/BITHockeyBaseViewController.m index b07411c8..17811b80 100644 --- a/Classes/BITHockeyBaseViewController.m +++ b/Classes/BITHockeyBaseViewController.m @@ -9,15 +9,10 @@ #import "BITHockeyBaseViewController.h" -@interface BITHockeyBaseViewController () - -@property (nonatomic) BOOL modal; -@property (nonatomic) UIStatusBarStyle statusBarStyle; - -@end - - -@implementation BITHockeyBaseViewController +@implementation BITHockeyBaseViewController { + BOOL _modal; + UIStatusBarStyle _statusBarStyle; +} - (id)init { @@ -36,7 +31,7 @@ - (id)initWithModalStyle:(BOOL)modal { //might be better in viewDidLoad, but to workaround rdar://12214613 and as it doesn't //hurt, we do it here - if (self.modal) { + if (_modal) { self.navigationItem.leftBarButtonItem = [[[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemDone target:self action:@selector(onDismissModal:)] autorelease]; @@ -49,7 +44,7 @@ - (id)initWithModalStyle:(BOOL)modal { #pragma mark - View lifecycle - (void)onDismissModal:(id)sender { - if (self.modal) { + if (_modal) { UIViewController *presentingViewController = [self presentingViewController]; // If there is no presenting view controller just remove view From f09ea53fbaa2aabdba9849c7c3841fcb80e4db77 Mon Sep 17 00:00:00 2001 From: Andreas Linde Date: Mon, 22 Oct 2012 01:10:18 +0200 Subject: [PATCH 081/176] Store the app identifier with the feedback thread. So in case they change by accident, new posts will cause a new thread in the current app to be created --- Classes/BITFeedbackManager.m | 15 +++++++++++++++ Classes/BITHockeyBaseManager.m | 3 +-- Classes/BITHockeyBaseManagerPrivate.h | 2 ++ 3 files changed, 18 insertions(+), 2 deletions(-) diff --git a/Classes/BITFeedbackManager.m b/Classes/BITFeedbackManager.m index 459bf566..a25c101a 100644 --- a/Classes/BITFeedbackManager.m +++ b/Classes/BITFeedbackManager.m @@ -47,6 +47,7 @@ #define kBITFeedbackName @"HockeyFeedbackName" #define kBITFeedbackEmail @"HockeyFeedbackEmail" #define kBITFeedbackLastMessageID @"HockeyFeedbackLastMessageID" +#define kBITFeedbackAppID @"HockeyFeedbackAppID" @implementation BITFeedbackManager { @@ -320,6 +321,17 @@ - (void)loadMessages { if ([unarchiver containsValueForKey:kBITFeedbackToken]) self.token = [unarchiver decodeObjectForKey:kBITFeedbackToken]; + if ([unarchiver containsValueForKey:kBITFeedbackAppID]) { + NSString *appID = [unarchiver decodeObjectForKey:kBITFeedbackAppID]; + + // the stored thread is from another application identifier, so clear the token + // which will cause the new posts to create a new thread on the server for the + // current app identifier + if ([appID compare:self.appIdentifier] != NSOrderedSame) { + self.token = nil; + } + } + if ([unarchiver containsValueForKey:kBITFeedbackDateOfLastCheck]) self.lastCheck = [unarchiver decodeObjectForKey:kBITFeedbackDateOfLastCheck]; @@ -356,6 +368,9 @@ - (void)saveMessages { if (self.token) [archiver encodeObject:self.token forKey:kBITFeedbackToken]; + if (self.appIdentifier) + [archiver encodeObject:self.appIdentifier forKey:kBITFeedbackAppID]; + if (self.userID) [archiver encodeObject:self.userID forKey:kBITFeedbackUserID]; diff --git a/Classes/BITHockeyBaseManager.m b/Classes/BITHockeyBaseManager.m index 17db241d..67812a8a 100644 --- a/Classes/BITHockeyBaseManager.m +++ b/Classes/BITHockeyBaseManager.m @@ -26,7 +26,6 @@ @implementation BITHockeyBaseManager { NSDateFormatter *_rfc3339Formatter; - NSString *_appIdentifier; BOOL _isAppStoreEnvironment; } @@ -54,7 +53,7 @@ - (id)init { - (id)initWithAppIdentifier:(NSString *)appIdentifier isAppStoreEnvironemt:(BOOL)isAppStoreEnvironment { if ((self = [self init])) { - _appIdentifier = appIdentifier; + self.appIdentifier = appIdentifier; _isAppStoreEnvironment = isAppStoreEnvironment; } diff --git a/Classes/BITHockeyBaseManagerPrivate.h b/Classes/BITHockeyBaseManagerPrivate.h index e58a3e1f..50b30799 100644 --- a/Classes/BITHockeyBaseManagerPrivate.h +++ b/Classes/BITHockeyBaseManagerPrivate.h @@ -14,6 +14,8 @@ @interface BITHockeyBaseManager() +@property (nonatomic, retain) NSString *appIdentifier; + - (id)initWithAppIdentifier:(NSString *)appIdentifier isAppStoreEnvironemt:(BOOL)isAppStoreEnvironment; - (void)startManager; From 657277e90773a4e25f028dd540e2ffd8257abb0e Mon Sep 17 00:00:00 2001 From: Andreas Linde Date: Mon, 22 Oct 2012 01:10:58 +0200 Subject: [PATCH 082/176] Fix implemented delegates for userid, name and email cause the feedback userUI not to show anything --- Classes/BITFeedbackManager.m | 39 ++++++++++++++++++++++-------------- 1 file changed, 24 insertions(+), 15 deletions(-) diff --git a/Classes/BITFeedbackManager.m b/Classes/BITFeedbackManager.m index a25c101a..e374bc2c 100644 --- a/Classes/BITFeedbackManager.m +++ b/Classes/BITFeedbackManager.m @@ -228,27 +228,36 @@ - (void)updateMessagesListIfRequired { - (void)updateAppDefinedUserData { if ([BITHockeyManager sharedHockeyManager].delegate && [[BITHockeyManager sharedHockeyManager].delegate respondsToSelector:@selector(userIDForHockeyManager:componentManager:)]) { - self.userID = [[BITHockeyManager sharedHockeyManager].delegate - userIDForHockeyManager:[BITHockeyManager sharedHockeyManager] - componentManager:self]; - self.requireUserName = BITFeedbackUserDataElementDontShow; - self.requireUserEmail = BITFeedbackUserDataElementDontShow; + NSString *userID = [[BITHockeyManager sharedHockeyManager].delegate + userIDForHockeyManager:[BITHockeyManager sharedHockeyManager] + componentManager:self]; + if (self.userID) { + self.userID = userID; + self.requireUserName = BITFeedbackUserDataElementDontShow; + self.requireUserEmail = BITFeedbackUserDataElementDontShow; + } } if ([BITHockeyManager sharedHockeyManager].delegate && [[BITHockeyManager sharedHockeyManager].delegate respondsToSelector:@selector(userNameForHockeyManager:componentManager:)]) { - self.userName = [[BITHockeyManager sharedHockeyManager].delegate - userNameForHockeyManager:[BITHockeyManager sharedHockeyManager] - componentManager:self]; - self.requireUserName = BITFeedbackUserDataElementDontShow; - self.requireUserEmail = BITFeedbackUserDataElementDontShow; + NSString *userName = [[BITHockeyManager sharedHockeyManager].delegate + userNameForHockeyManager:[BITHockeyManager sharedHockeyManager] + componentManager:self]; + if (userName) { + self.userName = userName; + self.requireUserName = BITFeedbackUserDataElementDontShow; + self.requireUserEmail = BITFeedbackUserDataElementDontShow; + } } if ([BITHockeyManager sharedHockeyManager].delegate && [[BITHockeyManager sharedHockeyManager].delegate respondsToSelector:@selector(userEmailForHockeyManager:componentManager:)]) { - self.userEmail = [[BITHockeyManager sharedHockeyManager].delegate - userEmailForHockeyManager:[BITHockeyManager sharedHockeyManager] - componentManager:self]; - self.requireUserName = BITFeedbackUserDataElementDontShow; - self.requireUserEmail = BITFeedbackUserDataElementDontShow; + NSString *userEmail = [[BITHockeyManager sharedHockeyManager].delegate + userEmailForHockeyManager:[BITHockeyManager sharedHockeyManager] + componentManager:self]; + if (userEmail) { + self.userEmail = userEmail; + self.requireUserName = BITFeedbackUserDataElementDontShow; + self.requireUserEmail = BITFeedbackUserDataElementDontShow; + } } } From 2b32b40a5eee012e7c7f5304e20e24a939fa1926 Mon Sep 17 00:00:00 2001 From: Andreas Linde Date: Mon, 22 Oct 2012 01:11:16 +0200 Subject: [PATCH 083/176] Fix sorting of pending feedback messages --- Classes/BITFeedbackManager.m | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Classes/BITFeedbackManager.m b/Classes/BITFeedbackManager.m index e374bc2c..49c0bcf7 100644 --- a/Classes/BITFeedbackManager.m +++ b/Classes/BITFeedbackManager.m @@ -424,9 +424,9 @@ - (void)sortFeedbackList { // archived on the very bottom if ([obj1 status] >= BITFeedbackMessageStatusSendInProgress && [obj2 status] < BITFeedbackMessageStatusSendInProgress) { - return NSOrderedAscending; - } else if ([obj1 status] < BITFeedbackMessageStatusSendInProgress && [obj2 status] >= BITFeedbackMessageStatusSendInProgress) { return NSOrderedDescending; + } else if ([obj1 status] < BITFeedbackMessageStatusSendInProgress && [obj2 status] >= BITFeedbackMessageStatusSendInProgress) { + return NSOrderedAscending; } else if ([obj1 status] == BITFeedbackMessageStatusArchived && [obj2 status] < BITFeedbackMessageStatusArchived) { return NSOrderedDescending; } else if ([obj1 status] < BITFeedbackMessageStatusArchived && [obj2 status] == BITFeedbackMessageStatusArchived) { From 155e8a72bc3da7162317ad990b7227d9fd542a86 Mon Sep 17 00:00:00 2001 From: Andreas Linde Date: Mon, 22 Oct 2012 01:13:27 +0200 Subject: [PATCH 084/176] Show clean feedback message texts, which is always stripped from quoted text in emails --- Classes/BITFeedbackManager.m | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Classes/BITFeedbackManager.m b/Classes/BITFeedbackManager.m index 49c0bcf7..dc48d4e4 100644 --- a/Classes/BITFeedbackManager.m +++ b/Classes/BITFeedbackManager.m @@ -634,9 +634,9 @@ - (void)updateMessageListFromResponse:(NSDictionary *)jsonDictionary { matchingSendInProgressOrInConflictMessage.id = messageID; matchingSendInProgressOrInConflictMessage.status = BITFeedbackMessageStatusRead; } else { - if ([(NSDictionary *)objMessage objectForKey:@"text"]) { + if ([(NSDictionary *)objMessage objectForKey:@"clean_text"] || [(NSDictionary *)objMessage objectForKey:@"text"]) { BITFeedbackMessage *message = [[[BITFeedbackMessage alloc] init] autorelease]; - message.text = [(NSDictionary *)objMessage objectForKey:@"text"] ?: @""; + message.text = [(NSDictionary *)objMessage objectForKey:@"clean_text"] ?: [(NSDictionary *)objMessage objectForKey:@"text"] ?: @""; message.name = [(NSDictionary *)objMessage objectForKey:@"name"] ?: @""; message.email = [(NSDictionary *)objMessage objectForKey:@"email"] ?: @""; From 17ed4b962e44d9a289b8f824c255c7988f86fb6e Mon Sep 17 00:00:00 2001 From: Andreas Linde Date: Mon, 22 Oct 2012 01:13:43 +0200 Subject: [PATCH 085/176] Feedback list view fixes --- Classes/BITFeedbackListViewController.m | 86 ++++++++++++------------- 1 file changed, 42 insertions(+), 44 deletions(-) diff --git a/Classes/BITFeedbackListViewController.m b/Classes/BITFeedbackListViewController.m index d19242a3..d7af1414 100644 --- a/Classes/BITFeedbackListViewController.m +++ b/Classes/BITFeedbackListViewController.m @@ -44,29 +44,40 @@ #define DEFAULT_BACKGROUNDCOLOR BIT_RGBCOLOR(245, 245, 245) #define DEFAULT_TEXTCOLOR BIT_RGBCOLOR(75, 75, 75) -#define BUTTON_DELETE_BACKGROUNDCOLOR BIT_RGBCOLOR(225, 0, 0) -#define BUTTON_BACKGROUNDCOLOR BIT_RGBCOLOR(225, 225, 225) + #define BUTTON_BORDERCOLOR BIT_RGBCOLOR(175, 175, 175) -#define BUTTON_DELETE_TEXTCOLOR BIT_RGBCOLOR(240, 240, 240) +#define BUTTON_BACKGROUNDCOLOR BIT_RGBCOLOR(225, 225, 225) #define BUTTON_TEXTCOLOR BIT_RGBCOLOR(58, 58, 58) -#define BUTTON_DELETE_TEXTCOLOR_SHADOW BIT_RGBCOLOR(175, 175, 175) #define BUTTON_TEXTCOLOR_SHADOW BIT_RGBCOLOR(175, 175, 175) -#define BORDER_COLOR1 BIT_RGBCOLOR(215, 215, 215) -#define BORDER_COLOR2 BIT_RGBCOLOR(221, 221, 221) -#define BORDER_COLOR3 BIT_RGBCOLOR(255, 255, 255) + +#define BUTTON_DELETE_BORDERCOLOR BIT_RGBCOLOR(61, 61, 61) +#define BUTTON_DELETE_BACKGROUNDCOLOR BIT_RGBCOLOR(225, 0, 0) +#define BUTTON_DELETE_TEXTCOLOR BIT_RGBCOLOR(240, 240, 240) +#define BUTTON_DELETE_TEXTCOLOR_SHADOW BIT_RGBCOLOR(175, 175, 175) + +#define BORDER_COLOR BIT_RGBCOLOR(215, 215, 215) + @interface BITFeedbackListViewController () -@property (nonatomic, assign) BITFeedbackManager *manager; +@property (nonatomic, assign) BITFeedbackManager *manager; @property (nonatomic, retain) NSDateFormatter *lastUpdateDateFormatter; + @end -@implementation BITFeedbackListViewController + +@implementation BITFeedbackListViewController { + NSInteger _deleteButtonSection; + NSInteger _userButtonSection; +} - (id)init { if ((self = [super init])) { _manager = [BITHockeyManager sharedHockeyManager].feedbackManager; + _deleteButtonSection = -1; + _userButtonSection = -1; + self.lastUpdateDateFormatter = [[[NSDateFormatter alloc] init] autorelease]; [self.lastUpdateDateFormatter setDateStyle:NSDateFormatterShortStyle]; [self.lastUpdateDateFormatter setTimeStyle:NSDateFormatterShortStyle]; @@ -240,13 +251,13 @@ - (void)deleteAllMessagesAction:(id)sender { #pragma mark - BITFeedbackUserDataDelegate -(void)userDataUpdateCancelled { - [self.navigationController dismissModalViewControllerAnimated:YES]; + [self dismissViewControllerAnimated:YES completion:^(void){}]; } -(void)userDataUpdateFinished { [self.manager saveMessages]; - [self.navigationController dismissModalViewControllerAnimated:YES]; + [self dismissViewControllerAnimated:YES completion:^(void){}]; } @@ -266,11 +277,18 @@ - (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)orientati - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { NSInteger rows = 2; - if ([self.manager isManualUserDataAvailable] || [self.manager didAskUserData]) + _deleteButtonSection = -1; + _userButtonSection = -1; + + if ([self.manager isManualUserDataAvailable] || [self.manager didAskUserData]) { + _userButtonSection = rows; rows++; + } - if ([self.manager numberOfMessages] > 0) + if ([self.manager numberOfMessages] > 0) { + _deleteButtonSection = rows; rows++; + } return rows; } @@ -306,7 +324,7 @@ - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(N [self.manager lastCheck] ? [self.lastUpdateDateFormatter stringFromDate:[self.manager lastCheck]] : BITHockeyLocalizedString(@"HockeyFeedbackListNeverUpdated")]; return cell; - } else if (indexPath.section == 0 || indexPath.section == 2 || indexPath.section == 3) { + } else if (indexPath.section == 0 || indexPath.section >= 2) { CGFloat topGap = 0.0f; UITableViewCell *cell = nil; @@ -315,7 +333,7 @@ - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(N if (indexPath.section == 0) { identifier = ButtonTopIdentifier; - } else if (indexPath.section == 2) { + } else if (indexPath.section == _userButtonSection) { identifier = ButtonBottomIdentifier; } else { identifier = ButtonDeleteIdentifier; @@ -344,14 +362,14 @@ - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(N [button setTitleColor:BUTTON_TEXTCOLOR forState:UIControlStateNormal]; [button setTitleShadowColor:BUTTON_TEXTCOLOR_SHADOW forState:UIControlStateNormal]; if (indexPath.section == 0) { - topGap += 22; + topGap = 22; if ([self.manager numberOfMessages] == 0) { [button setTitle:BITHockeyLocalizedString(@"HockeyFeedbackListButonWriteFeedback") forState:UIControlStateNormal]; } else { [button setTitle:BITHockeyLocalizedString(@"HockeyFeedbackListButonWriteResponse") forState:UIControlStateNormal]; } [button addTarget:self action:@selector(newFeedbackAction:) forControlEvents:UIControlEventTouchUpInside]; - } else if (indexPath.section == 2) { + } else if (indexPath.section == _userButtonSection) { topGap = 6.0f; NSString *title = @""; if ([self.manager requireUserName] == BITFeedbackUserDataElementRequired || @@ -370,8 +388,9 @@ - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(N [button setTitle:title forState:UIControlStateNormal]; [button addTarget:self action:@selector(setUserDataAction:) forControlEvents:UIControlEventTouchUpInside]; } else { - topGap -= 6.0f; + topGap = 0.0f; [button.layer setBackgroundColor:BUTTON_DELETE_BACKGROUNDCOLOR.CGColor]; + [button.layer setBorderColor:BUTTON_DELETE_BORDERCOLOR.CGColor]; [button setTitleColor:BUTTON_DELETE_TEXTCOLOR forState:UIControlStateNormal]; [button setTitleShadowColor:BUTTON_DELETE_TEXTCOLOR_SHADOW forState:UIControlStateNormal]; @@ -379,7 +398,7 @@ - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(N [button addTarget:self action:@selector(deleteAllMessagesAction:) forControlEvents:UIControlEventTouchUpInside]; } - [button setFrame: CGRectMake( 10.0f, topGap + 12.0f, cell.contentView.bounds.size.width - 20.0f, 42.0f)]; + [button setFrame: CGRectMake( 10.0f, topGap + 12.0f, self.view.frame.size.width - 20.0f, 42.0f)]; [cell addSubview:button]; @@ -399,19 +418,9 @@ - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(N [cell addSubview:statusLabel]; } else if (indexPath.section == 2) { UIView *lineView1 = [[[UIView alloc] initWithFrame:CGRectMake(0, 0, cell.contentView.bounds.size.width, 1)] autorelease]; - lineView1.backgroundColor = BORDER_COLOR1; + lineView1.backgroundColor = BORDER_COLOR; lineView1.autoresizingMask = UIViewAutoresizingFlexibleWidth; [cell addSubview:lineView1]; - - UIView *lineView2 = [[[UIView alloc] initWithFrame:CGRectMake(0, 1, cell.contentView.bounds.size.width, 1)] autorelease]; - lineView2.backgroundColor = BORDER_COLOR2; - lineView2.autoresizingMask = UIViewAutoresizingFlexibleWidth; - [cell addSubview:lineView2]; - - UIView *lineView3 = [[[UIView alloc] initWithFrame:CGRectMake(0, 2, cell.contentView.bounds.size.width, 1)] autorelease]; - lineView3.backgroundColor = BORDER_COLOR3; - lineView3.autoresizingMask = UIViewAutoresizingFlexibleWidth; - [cell addSubview:lineView3]; } return cell; @@ -436,19 +445,9 @@ - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(N cell.labelText.userInteractionEnabled = YES; UIView *lineView1 = [[[UIView alloc] initWithFrame:CGRectMake(0, 0, cell.contentView.bounds.size.width, 1)] autorelease]; - lineView1.backgroundColor = BORDER_COLOR1; + lineView1.backgroundColor = BORDER_COLOR; lineView1.autoresizingMask = UIViewAutoresizingFlexibleWidth; [cell addSubview:lineView1]; - - UIView *lineView2 = [[[UIView alloc] initWithFrame:CGRectMake(0, 1, cell.contentView.bounds.size.width, 1)] autorelease]; - lineView2.backgroundColor = BORDER_COLOR2; - lineView2.autoresizingMask = UIViewAutoresizingFlexibleWidth; - [cell addSubview:lineView2]; - - UIView *lineView3 = [[[UIView alloc] initWithFrame:CGRectMake(0, 2, cell.contentView.bounds.size.width, 1)] autorelease]; - lineView3.backgroundColor = BORDER_COLOR3; - lineView3.autoresizingMask = UIViewAutoresizingFlexibleWidth; - [cell addSubview:lineView3]; return cell; } @@ -464,7 +463,6 @@ - (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *) - (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath { if (editingStyle == UITableViewCellEditingStyleDelete) { - NSLog(@"%i %i", indexPath.section, indexPath.row); if ([_manager deleteMessageAtIndex:indexPath.row]) { if ([_manager numberOfMessages] > 0) { [tableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationAutomatic]; @@ -482,8 +480,8 @@ - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPa if (indexPath.section == 0 ) { return 87; } - if (indexPath.section == 2) { - return 75; + if (indexPath.section >= 2) { + return 65; } BITFeedbackMessage *message = [self.manager messageAtIndex:indexPath.row]; From df52022391d2bad909f630306271deaffc137a67 Mon Sep 17 00:00:00 2001 From: Andreas Linde Date: Mon, 22 Oct 2012 01:18:11 +0200 Subject: [PATCH 086/176] Fix update view This should not have been committed. *sigh* --- Classes/BITUpdateViewController.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Classes/BITUpdateViewController.m b/Classes/BITUpdateViewController.m index c22e1077..fc426f18 100644 --- a/Classes/BITUpdateViewController.m +++ b/Classes/BITUpdateViewController.m @@ -76,7 +76,7 @@ - (void)restoreStoreButtonStateAnimated:(BOOL)animated { - (void)updateAppStoreHeader { BITAppVersionMetaInfo *appVersion = _updateManager.newestAppVersion; _appStoreHeader.headerLabel = appVersion.name; - _appStoreHeader.middleHeaderLabel = [_updateManager currentAppVersion];// [appVersion versionString]; +// _appStoreHeader.middleHeaderLabel = appVersion versionString]; // NSDateFormatter *formatter = [[[NSDateFormatter alloc] init] autorelease]; // [formatter setDateStyle:NSDateFormatterMediumStyle]; // NSMutableString *subHeaderString = [NSMutableString string]; From 139b17b0211ca6636a45b94db73e64864be9eba0 Mon Sep 17 00:00:00 2001 From: Andreas Linde Date: Mon, 22 Oct 2012 01:19:19 +0200 Subject: [PATCH 087/176] We don't need the PLCrashReporter headers in the distributed framework --- Support/HockeySDK.xcodeproj/project.pbxproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Support/HockeySDK.xcodeproj/project.pbxproj b/Support/HockeySDK.xcodeproj/project.pbxproj index 2bceac86..89d4f589 100644 --- a/Support/HockeySDK.xcodeproj/project.pbxproj +++ b/Support/HockeySDK.xcodeproj/project.pbxproj @@ -561,7 +561,7 @@ ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "# Sets the target folders and the final framework product.\nFMK_NAME=HockeySDK\nFMK_VERSION=A\nFMK_RESOURCE_BUNDLE=HockeySDKResources\n\n# Documentation\nHOCKEYSDK_DOCSET_VERSION_NAME=\"de.bitstadium.${HOCKEYSDK_DOCSET_NAME}-${VERSION_STRING}\"\n\n# Install dir will be the final output to the framework.\n# The following line create it in the root folder of the current project.\nPRODUCTS_DIR=${SRCROOT}/../Products\nTEMP_DIR=${PRODUCTS_DIR}/Temp\nINSTALL_DIR=${TEMP_DIR}/${FMK_NAME}.framework\n\n# Working dir will be deleted after the framework creation.\nWRK_DIR=build\nDEVICE_DIR=${WRK_DIR}/Release-iphoneos\nSIMULATOR_DIR=${WRK_DIR}/Release-iphonesimulator\nHEADERS_DIR=${WRK_DIR}/Release-iphoneos/usr/local/include\n\n# Building both architectures.\nxcodebuild -project \"HockeySDK.xcodeproj\" -configuration \"Release\" -target \"${FMK_NAME}\" -sdk iphoneos\nxcodebuild -project \"HockeySDK.xcodeproj\" -configuration \"Release\" -target \"${FMK_NAME}\" -sdk iphonesimulator\n\n# Cleaning the oldest.\nif [ -d \"${TEMP_DIR}\" ]\nthen\nrm -rf \"${TEMP_DIR}\"\nfi\n\n# Creates and renews the final product folder.\nmkdir -p \"${INSTALL_DIR}\"\nmkdir -p \"${INSTALL_DIR}/Versions\"\nmkdir -p \"${INSTALL_DIR}/Versions/${FMK_VERSION}\"\nmkdir -p \"${INSTALL_DIR}/Versions/${FMK_VERSION}/Resources\"\nmkdir -p \"${INSTALL_DIR}/Versions/${FMK_VERSION}/Headers\"\n\n# Creates the internal links.\n# It MUST uses relative path, otherwise will not work when the folder is copied/moved.\nln -s \"${FMK_VERSION}\" \"${INSTALL_DIR}/Versions/Current\"\nln -s \"Versions/Current/Headers\" \"${INSTALL_DIR}/Headers\"\nln -s \"Versions/Current/Resources\" \"${INSTALL_DIR}/Resources\"\nln -s \"Versions/Current/${FMK_NAME}\" \"${INSTALL_DIR}/${FMK_NAME}\"\n\n# Copies the headers and resources files to the final product folder.\ncp -R \"${HEADERS_DIR}/\" \"${INSTALL_DIR}/Versions/${FMK_VERSION}/Headers/\"\ncp -R \"${DEVICE_DIR}/${FMK_RESOURCE_BUNDLE}.bundle\" \"${INSTALL_DIR}/Versions/${FMK_VERSION}/Resources/\"\ncp -f \"${SRCROOT}/${FMK_NAME}.xcconfig\" \"${INSTALL_DIR}/Versions/${FMK_VERSION}/Resources/\"\n\n# Uses the Lipo Tool to merge both binary files (i386 + armv6/armv7) into one Universal final product.\nlipo -create \"${DEVICE_DIR}/lib${FMK_NAME}.a\" \"${SIMULATOR_DIR}/lib${FMK_NAME}.a\" -output \"${INSTALL_DIR}/Versions/${FMK_VERSION}/${FMK_NAME}\"\n\n# Combine the CrashReporter static library into a new Hockey static library file if they are not already present and copy the public headers too\nif [ -z $(otool -L \"${INSTALL_DIR}/Versions/${FMK_VERSION}/${FMK_NAME}\" | grep 'libCrashReporter') ]\nthen\nlibtool -static -o \"${INSTALL_DIR}/Versions/${FMK_VERSION}/${FMK_NAME}\" \"${INSTALL_DIR}/Versions/${FMK_VERSION}/${FMK_NAME}\" \"${SRCROOT}/../Vendor/CrashReporter.framework/Versions/A/CrashReporter\"\ncp -r \\\n\"${SRCROOT}/../Vendor/CrashReporter.framework/Versions/A/Headers/\" \\\n\"${INSTALL_DIR}/Versions/${FMK_VERSION}/Headers/\"\nfi\n\nrm -r \"${WRK_DIR}\"\n\n# build embeddedframework folder and move framework into it\nmkdir \"${INSTALL_DIR}/../${FMK_NAME}.embeddedframework\"\nmv \"${INSTALL_DIR}\" \"${INSTALL_DIR}/../${FMK_NAME}.embeddedframework/${FMK_NAME}.framework\"\n\n# link Resources\nNEW_INSTALL_DIR=${TEMP_DIR}/${FMK_NAME}.embeddedframework\nmkdir \"${NEW_INSTALL_DIR}/Resources\"\nln -s \"../${FMK_NAME}.framework/Resources/${FMK_RESOURCE_BUNDLE}.bundle\" \"${NEW_INSTALL_DIR}/Resources/${FMK_RESOURCE_BUNDLE}.bundle\"\nln -s \"../${FMK_NAME}.framework/Resources/${FMK_NAME}.xcconfig\" \"${NEW_INSTALL_DIR}/Resources/${FMK_NAME}.xcconfig\"\n\n# copy license, changelog, documentation\ncp -f \"${SRCROOT}/../Docs/Changelog-template.md\" \"${TEMP_DIR}/CHANGELOG\"\ncp -f \"${SRCROOT}/../LICENSE\" \"${TEMP_DIR}\"\nmkdir \"${TEMP_DIR}/${HOCKEYSDK_DOCSET_VERSION_NAME}.docset\"\ncp -R \"${SRCROOT}/../documentation/docset/Contents\" \"${TEMP_DIR}/${HOCKEYSDK_DOCSET_VERSION_NAME}.docset\"\n\n# build zip\ncd \"${PRODUCTS_DIR}\"\nrm -f \"${FMK_NAME}-iOS-${VERSION_STRING}.zip\"\ncd \"${TEMP_DIR}\"\nzip -yr \"../${FMK_NAME}-iOS-${VERSION_STRING}.zip\" \"./${FMK_NAME}.embeddedframework\" \"./CHANGELOG\" \"./LICENSE\" \"./${HOCKEYSDK_DOCSET_VERSION_NAME}.docset\" -x \\*/.*\n"; + shellScript = "# Sets the target folders and the final framework product.\nFMK_NAME=HockeySDK\nFMK_VERSION=A\nFMK_RESOURCE_BUNDLE=HockeySDKResources\n\n# Documentation\nHOCKEYSDK_DOCSET_VERSION_NAME=\"de.bitstadium.${HOCKEYSDK_DOCSET_NAME}-${VERSION_STRING}\"\n\n# Install dir will be the final output to the framework.\n# The following line create it in the root folder of the current project.\nPRODUCTS_DIR=${SRCROOT}/../Products\nTEMP_DIR=${PRODUCTS_DIR}/Temp\nINSTALL_DIR=${TEMP_DIR}/${FMK_NAME}.framework\n\n# Working dir will be deleted after the framework creation.\nWRK_DIR=build\nDEVICE_DIR=${WRK_DIR}/Release-iphoneos\nSIMULATOR_DIR=${WRK_DIR}/Release-iphonesimulator\nHEADERS_DIR=${WRK_DIR}/Release-iphoneos/usr/local/include\n\n# Building both architectures.\nxcodebuild -project \"HockeySDK.xcodeproj\" -configuration \"Release\" -target \"${FMK_NAME}\" -sdk iphoneos\nxcodebuild -project \"HockeySDK.xcodeproj\" -configuration \"Release\" -target \"${FMK_NAME}\" -sdk iphonesimulator\n\n# Cleaning the oldest.\nif [ -d \"${TEMP_DIR}\" ]\nthen\nrm -rf \"${TEMP_DIR}\"\nfi\n\n# Creates and renews the final product folder.\nmkdir -p \"${INSTALL_DIR}\"\nmkdir -p \"${INSTALL_DIR}/Versions\"\nmkdir -p \"${INSTALL_DIR}/Versions/${FMK_VERSION}\"\nmkdir -p \"${INSTALL_DIR}/Versions/${FMK_VERSION}/Resources\"\nmkdir -p \"${INSTALL_DIR}/Versions/${FMK_VERSION}/Headers\"\n\n# Creates the internal links.\n# It MUST uses relative path, otherwise will not work when the folder is copied/moved.\nln -s \"${FMK_VERSION}\" \"${INSTALL_DIR}/Versions/Current\"\nln -s \"Versions/Current/Headers\" \"${INSTALL_DIR}/Headers\"\nln -s \"Versions/Current/Resources\" \"${INSTALL_DIR}/Resources\"\nln -s \"Versions/Current/${FMK_NAME}\" \"${INSTALL_DIR}/${FMK_NAME}\"\n\n# Copies the headers and resources files to the final product folder.\ncp -R \"${HEADERS_DIR}/\" \"${INSTALL_DIR}/Versions/${FMK_VERSION}/Headers/\"\ncp -R \"${DEVICE_DIR}/${FMK_RESOURCE_BUNDLE}.bundle\" \"${INSTALL_DIR}/Versions/${FMK_VERSION}/Resources/\"\ncp -f \"${SRCROOT}/${FMK_NAME}.xcconfig\" \"${INSTALL_DIR}/Versions/${FMK_VERSION}/Resources/\"\n\n# Uses the Lipo Tool to merge both binary files (i386 + armv6/armv7) into one Universal final product.\nlipo -create \"${DEVICE_DIR}/lib${FMK_NAME}.a\" \"${SIMULATOR_DIR}/lib${FMK_NAME}.a\" -output \"${INSTALL_DIR}/Versions/${FMK_VERSION}/${FMK_NAME}\"\n\n# Combine the CrashReporter static library into a new Hockey static library file if they are not already present and copy the public headers too\nif [ -z $(otool -L \"${INSTALL_DIR}/Versions/${FMK_VERSION}/${FMK_NAME}\" | grep 'libCrashReporter') ]\nthen\nlibtool -static -o \"${INSTALL_DIR}/Versions/${FMK_VERSION}/${FMK_NAME}\" \"${INSTALL_DIR}/Versions/${FMK_VERSION}/${FMK_NAME}\" \"${SRCROOT}/../Vendor/CrashReporter.framework/Versions/A/CrashReporter\"\nfi\n\nrm -r \"${WRK_DIR}\"\n\n# build embeddedframework folder and move framework into it\nmkdir \"${INSTALL_DIR}/../${FMK_NAME}.embeddedframework\"\nmv \"${INSTALL_DIR}\" \"${INSTALL_DIR}/../${FMK_NAME}.embeddedframework/${FMK_NAME}.framework\"\n\n# link Resources\nNEW_INSTALL_DIR=${TEMP_DIR}/${FMK_NAME}.embeddedframework\nmkdir \"${NEW_INSTALL_DIR}/Resources\"\nln -s \"../${FMK_NAME}.framework/Resources/${FMK_RESOURCE_BUNDLE}.bundle\" \"${NEW_INSTALL_DIR}/Resources/${FMK_RESOURCE_BUNDLE}.bundle\"\nln -s \"../${FMK_NAME}.framework/Resources/${FMK_NAME}.xcconfig\" \"${NEW_INSTALL_DIR}/Resources/${FMK_NAME}.xcconfig\"\n\n# copy license, changelog, documentation\ncp -f \"${SRCROOT}/../Docs/Changelog-template.md\" \"${TEMP_DIR}/CHANGELOG\"\ncp -f \"${SRCROOT}/../LICENSE\" \"${TEMP_DIR}\"\nmkdir \"${TEMP_DIR}/${HOCKEYSDK_DOCSET_VERSION_NAME}.docset\"\ncp -R \"${SRCROOT}/../documentation/docset/Contents\" \"${TEMP_DIR}/${HOCKEYSDK_DOCSET_VERSION_NAME}.docset\"\n\n# build zip\ncd \"${PRODUCTS_DIR}\"\nrm -f \"${FMK_NAME}-iOS-${VERSION_STRING}.zip\"\ncd \"${TEMP_DIR}\"\nzip -yr \"../${FMK_NAME}-iOS-${VERSION_STRING}.zip\" \"./${FMK_NAME}.embeddedframework\" \"./CHANGELOG\" \"./LICENSE\" \"./${HOCKEYSDK_DOCSET_VERSION_NAME}.docset\" -x \\*/.*\n"; }; 1E8E66B215BC3D8200632A2E /* ShellScript */ = { isa = PBXShellScriptBuildPhase; From 359ec04f533af0d4a02b9a5283bdc8306cc77985 Mon Sep 17 00:00:00 2001 From: Andreas Linde Date: Mon, 22 Oct 2012 01:45:20 +0200 Subject: [PATCH 088/176] Another rotation fix for feedback list view --- Classes/BITFeedbackListViewController.m | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Classes/BITFeedbackListViewController.m b/Classes/BITFeedbackListViewController.m index d7af1414..730538d9 100644 --- a/Classes/BITFeedbackListViewController.m +++ b/Classes/BITFeedbackListViewController.m @@ -398,13 +398,13 @@ - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(N [button addTarget:self action:@selector(deleteAllMessagesAction:) forControlEvents:UIControlEventTouchUpInside]; } - [button setFrame: CGRectMake( 10.0f, topGap + 12.0f, self.view.frame.size.width - 20.0f, 42.0f)]; + [button setFrame: CGRectMake( 10.0f, topGap + 12.0f, cell.frame.size.width - 20.0f, 42.0f)]; [cell addSubview:button]; // status label or shadow lines if (indexPath.section == 0) { - UILabel *statusLabel = [[[UILabel alloc] initWithFrame:CGRectMake(0, 6, self.view.frame.size.width, 28)] autorelease]; + UILabel *statusLabel = [[[UILabel alloc] initWithFrame:CGRectMake(0, 6, cell.frame.size.width, 28)] autorelease]; statusLabel.font = [UIFont systemFontOfSize:10]; statusLabel.textColor = DEFAULT_TEXTCOLOR; @@ -417,7 +417,7 @@ - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(N [cell addSubview:statusLabel]; } else if (indexPath.section == 2) { - UIView *lineView1 = [[[UIView alloc] initWithFrame:CGRectMake(0, 0, cell.contentView.bounds.size.width, 1)] autorelease]; + UIView *lineView1 = [[[UIView alloc] initWithFrame:CGRectMake(0, 0, cell.frame.size.width, 1)] autorelease]; lineView1.backgroundColor = BORDER_COLOR; lineView1.autoresizingMask = UIViewAutoresizingFlexibleWidth; [cell addSubview:lineView1]; @@ -444,7 +444,7 @@ - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(N cell.labelText.delegate = self; cell.labelText.userInteractionEnabled = YES; - UIView *lineView1 = [[[UIView alloc] initWithFrame:CGRectMake(0, 0, cell.contentView.bounds.size.width, 1)] autorelease]; + UIView *lineView1 = [[[UIView alloc] initWithFrame:CGRectMake(0, 0, cell.frame.size.width, 1)] autorelease]; lineView1.backgroundColor = BORDER_COLOR; lineView1.autoresizingMask = UIViewAutoresizingFlexibleWidth; [cell addSubview:lineView1]; From dfcc124f1cbaecfaf189ed5e364648b6fc222bed Mon Sep 17 00:00:00 2001 From: Andreas Linde Date: Mon, 22 Oct 2012 22:59:44 +0200 Subject: [PATCH 089/176] Some fixes regarding feedback user data UI --- Classes/BITFeedbackManager.m | 65 +++++++++++++++++------------------- 1 file changed, 31 insertions(+), 34 deletions(-) diff --git a/Classes/BITFeedbackManager.m b/Classes/BITFeedbackManager.m index dc48d4e4..57c9eae4 100644 --- a/Classes/BITFeedbackManager.m +++ b/Classes/BITFeedbackManager.m @@ -225,7 +225,9 @@ - (void)updateMessagesListIfRequired { } } -- (void)updateAppDefinedUserData { +- (BOOL)updateUserIDUsingDelegate { + BOOL availableViaDelegate = NO; + if ([BITHockeyManager sharedHockeyManager].delegate && [[BITHockeyManager sharedHockeyManager].delegate respondsToSelector:@selector(userIDForHockeyManager:componentManager:)]) { NSString *userID = [[BITHockeyManager sharedHockeyManager].delegate @@ -233,21 +235,34 @@ - (void)updateAppDefinedUserData { componentManager:self]; if (self.userID) { self.userID = userID; - self.requireUserName = BITFeedbackUserDataElementDontShow; - self.requireUserEmail = BITFeedbackUserDataElementDontShow; + availableViaDelegate = YES; } } + + return availableViaDelegate; +} + +- (BOOL)updateUserNameUsingDelegate { + BOOL availableViaDelegate = NO; + if ([BITHockeyManager sharedHockeyManager].delegate && [[BITHockeyManager sharedHockeyManager].delegate respondsToSelector:@selector(userNameForHockeyManager:componentManager:)]) { NSString *userName = [[BITHockeyManager sharedHockeyManager].delegate userNameForHockeyManager:[BITHockeyManager sharedHockeyManager] componentManager:self]; if (userName) { + availableViaDelegate = YES; self.userName = userName; self.requireUserName = BITFeedbackUserDataElementDontShow; - self.requireUserEmail = BITFeedbackUserDataElementDontShow; } } + + return availableViaDelegate; +} + +- (BOOL)updateUserEmailUsingDelegate { + BOOL availableViaDelegate = NO; + if ([BITHockeyManager sharedHockeyManager].delegate && [[BITHockeyManager sharedHockeyManager].delegate respondsToSelector:@selector(userEmailForHockeyManager:componentManager:)]) { NSString *userEmail = [[BITHockeyManager sharedHockeyManager].delegate @@ -255,44 +270,26 @@ - (void)updateAppDefinedUserData { componentManager:self]; if (userEmail) { self.userEmail = userEmail; - self.requireUserName = BITFeedbackUserDataElementDontShow; + availableViaDelegate = YES; self.requireUserEmail = BITFeedbackUserDataElementDontShow; } } + + return availableViaDelegate; +} + +- (void)updateAppDefinedUserData { + [self updateUserIDUsingDelegate]; + [self updateUserNameUsingDelegate]; + [self updateUserEmailUsingDelegate]; } #pragma mark - Local Storage - (void)loadMessages { - BOOL userIDViaDelegate = NO; - BOOL userNameViaDelegate = NO; - BOOL userEmailViaDelegate = NO; - - if ([BITHockeyManager sharedHockeyManager].delegate && - [[BITHockeyManager sharedHockeyManager].delegate respondsToSelector:@selector(userIDForHockeyManager:componentManager:)]) { - userIDViaDelegate = YES; - self.userID = [[BITHockeyManager sharedHockeyManager].delegate - userIDForHockeyManager:[BITHockeyManager sharedHockeyManager] - componentManager:self]; - } - if ([BITHockeyManager sharedHockeyManager].delegate && - [[BITHockeyManager sharedHockeyManager].delegate respondsToSelector:@selector(userNameForHockeyManager:componentManager:)]) { - userNameViaDelegate = YES; - self.userName = [[BITHockeyManager sharedHockeyManager].delegate - userNameForHockeyManager:[BITHockeyManager sharedHockeyManager] - componentManager:self]; - self.requireUserName = BITFeedbackUserDataElementDontShow; - self.requireUserEmail = BITFeedbackUserDataElementDontShow; - } - if ([BITHockeyManager sharedHockeyManager].delegate && - [[BITHockeyManager sharedHockeyManager].delegate respondsToSelector:@selector(userEmailForHockeyManager:componentManager:)]) { - userEmailViaDelegate = YES; - self.userEmail = [[BITHockeyManager sharedHockeyManager].delegate - userEmailForHockeyManager:[BITHockeyManager sharedHockeyManager] - componentManager:self]; - self.requireUserName = BITFeedbackUserDataElementDontShow; - self.requireUserEmail = BITFeedbackUserDataElementDontShow; - } + BOOL userIDViaDelegate = [self updateUserIDUsingDelegate]; + BOOL userNameViaDelegate = [self updateUserNameUsingDelegate]; + BOOL userEmailViaDelegate = [self updateUserEmailUsingDelegate]; if (![_fileManager fileExistsAtPath:_settingsFile]) return; From a14fa23f28dae23aa27b8ab00e2115b8a25ea67a Mon Sep 17 00:00:00 2001 From: Andreas Linde Date: Tue, 23 Oct 2012 16:22:23 +0200 Subject: [PATCH 090/176] Convert to ARC --- Classes/BITAppStoreHeader.h | 2 +- Classes/BITAppStoreHeader.m | 17 +----- Classes/BITAppVersionMetaInfo.m | 15 +---- Classes/BITCrashManager.h | 2 +- Classes/BITCrashManager.m | 36 +++-------- Classes/BITFeedbackActivity.h | 4 +- Classes/BITFeedbackActivity.m | 12 +--- Classes/BITFeedbackComposeViewController.h | 2 +- Classes/BITFeedbackComposeViewController.m | 27 +++------ Classes/BITFeedbackListViewCell.h | 4 +- Classes/BITFeedbackListViewCell.m | 28 +++------ Classes/BITFeedbackListViewController.m | 38 +++++------- Classes/BITFeedbackManager.m | 47 ++++----------- Classes/BITFeedbackManagerPrivate.h | 12 ++-- Classes/BITFeedbackMessage.m | 12 ---- Classes/BITFeedbackUserDataViewController.h | 2 +- Classes/BITFeedbackUserDataViewController.m | 21 +++---- Classes/BITHockeyBaseManager.h | 2 +- Classes/BITHockeyBaseManager.m | 21 +------ Classes/BITHockeyBaseManagerPrivate.h | 2 +- Classes/BITHockeyBaseViewController.m | 4 +- Classes/BITHockeyHelper.m | 35 ++++++----- Classes/BITHockeyManager.h | 8 +-- Classes/BITHockeyManager.m | 24 ++------ Classes/BITHockeyManagerPrivate.h | 2 +- Classes/BITStoreButton.h | 4 +- Classes/BITStoreButton.m | 15 +---- Classes/BITUpdateManager.h | 6 +- Classes/BITUpdateManager.m | 67 +++++++-------------- Classes/BITUpdateManagerPrivate.h | 10 +-- Classes/BITUpdateViewController.m | 21 +++---- Classes/BITUpdateViewControllerPrivate.h | 2 +- Classes/BITWebTableViewCell.h | 4 +- Classes/BITWebTableViewCell.m | 8 +-- Classes/HockeySDKPrivate.m | 2 +- Support/HockeySDK.xcodeproj/project.pbxproj | 8 ++- 36 files changed, 171 insertions(+), 355 deletions(-) diff --git a/Classes/BITAppStoreHeader.h b/Classes/BITAppStoreHeader.h index 0175b2f6..3f3e2e84 100644 --- a/Classes/BITAppStoreHeader.h +++ b/Classes/BITAppStoreHeader.h @@ -36,6 +36,6 @@ @property (nonatomic, copy) NSString *headerLabel; @property (nonatomic, copy) NSString *middleHeaderLabel; @property (nonatomic, copy) NSString *subHeaderLabel; -@property (nonatomic, retain) UIImage *iconImage; +@property (nonatomic, strong) UIImage *iconImage; @end diff --git a/Classes/BITAppStoreHeader.m b/Classes/BITAppStoreHeader.m index db46d83e..5716e65d 100644 --- a/Classes/BITAppStoreHeader.m +++ b/Classes/BITAppStoreHeader.m @@ -56,15 +56,6 @@ - (id)initWithFrame:(CGRect)frame { return self; } -- (void)dealloc { - [_headerLabel release], _headerLabel = nil; - [_middleHeaderLabel release], _middleHeaderLabel = nil; - [_subHeaderLabel release], _subHeaderLabel = nil; - [_iconImage release], _iconImage = nil;; - - [super dealloc]; -} - #pragma mark - UIView @@ -75,7 +66,7 @@ - (void)drawRect:(CGRect)rect { // draw the gradient 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((__bridge CGColorRef)[colors objectAtIndex:0]), (__bridge CFArrayRef)colors, (CGFloat[2]){0, 1}); CGPoint top = CGPointMake(CGRectGetMidX(bounds), bounds.size.height - 3); CGPoint bottom = CGPointMake(CGRectGetMidX(bounds), CGRectGetMaxY(bounds)); CGContextDrawLinearGradient(context, gradient, top, bottom, 0); @@ -108,7 +99,6 @@ - (void)drawRect:(CGRect)rect { - (void)setHeaderLabel:(NSString *)anHeaderLabel { if (_headerLabel != anHeaderLabel) { - [_headerLabel release]; _headerLabel = [anHeaderLabel copy]; [self setNeedsDisplay]; } @@ -116,7 +106,6 @@ - (void)setHeaderLabel:(NSString *)anHeaderLabel { - (void)setMiddleHeaderLabel:(NSString *)aMiddleHeaderLabel { if (_middleHeaderLabel != aMiddleHeaderLabel) { - [_middleHeaderLabel release]; _middleHeaderLabel = [aMiddleHeaderLabel copy]; [self setNeedsDisplay]; } @@ -124,7 +113,6 @@ - (void)setMiddleHeaderLabel:(NSString *)aMiddleHeaderLabel { - (void)setSubHeaderLabel:(NSString *)aSubHeaderLabel { if (_subHeaderLabel != aSubHeaderLabel) { - [_subHeaderLabel release]; _subHeaderLabel = [aSubHeaderLabel copy]; [self setNeedsDisplay]; } @@ -132,11 +120,10 @@ - (void)setSubHeaderLabel:(NSString *)aSubHeaderLabel { - (void)setIconImage:(UIImage *)anIconImage { if (_iconImage != anIconImage) { - [_iconImage release]; // scale, make borders and reflection _iconImage = bit_imageToFitSize(anIconImage, CGSizeMake(kImageHeight, kImageHeight), YES); - _iconImage = [bit_roundedCornerImage(_iconImage, kImageBorderRadius, 0.0) retain]; + _iconImage = bit_roundedCornerImage(_iconImage, kImageBorderRadius, 0.0); [self setNeedsDisplay]; } diff --git a/Classes/BITAppVersionMetaInfo.m b/Classes/BITAppVersionMetaInfo.m index 44cdae2c..22e4645d 100644 --- a/Classes/BITAppVersionMetaInfo.m +++ b/Classes/BITAppVersionMetaInfo.m @@ -45,7 +45,7 @@ @implementation BITAppVersionMetaInfo #pragma mark - Static + (BITAppVersionMetaInfo *)appVersionMetaInfoFromDict:(NSDictionary *)dict { - BITAppVersionMetaInfo *appVersionMetaInfo = [[[[self class] alloc] init] autorelease]; + BITAppVersionMetaInfo *appVersionMetaInfo = [[[self class] alloc] init]; if ([dict isKindOfClass:[NSDictionary class]]) { appVersionMetaInfo.name = [dict objectForKey:@"title"]; @@ -63,17 +63,6 @@ + (BITAppVersionMetaInfo *)appVersionMetaInfoFromDict:(NSDictionary *)dict { #pragma mark - NSObject -- (void)dealloc { - [_name release]; - [_version release]; - [_shortVersion release]; - [_notes release]; - [_date release]; - [_size release]; - [_mandatory release]; - - [super dealloc]; -} - (BOOL)isEqual:(id)other { if (other == self) @@ -144,7 +133,7 @@ - (NSString *)versionString { } - (NSString *)dateString { - NSDateFormatter *formatter = [[[NSDateFormatter alloc] init] autorelease]; + NSDateFormatter *formatter = [[NSDateFormatter alloc] init]; [formatter setDateStyle:NSDateFormatterMediumStyle]; return [formatter stringFromDate:self.date]; diff --git a/Classes/BITCrashManager.h b/Classes/BITCrashManager.h index d6361d96..c49d2a10 100644 --- a/Classes/BITCrashManager.h +++ b/Classes/BITCrashManager.h @@ -86,7 +86,7 @@ static NSString *kBITCrashManagerStatus = @"BITCrashManagerStatus"; /** Sets the optional `BITCrashManagerDelegate` delegate. */ -@property (nonatomic, assign) id delegate; +@property (nonatomic, weak) id delegate; ///----------------------------------------------------------------------------- diff --git a/Classes/BITCrashManager.m b/Classes/BITCrashManager.m index af7fcc6f..6f1f0da8 100644 --- a/Classes/BITCrashManager.m +++ b/Classes/BITCrashManager.m @@ -54,7 +54,7 @@ @interface BITCrashManager () -@property (nonatomic, retain) NSFileManager *fileManager; +@property (nonatomic, strong) NSFileManager *fileManager; @end @@ -118,7 +118,7 @@ - (id)init { // temporary directory for crashes grabbed from PLCrashReporter NSArray *paths = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES); - _crashesDir = [[[paths objectAtIndex:0] stringByAppendingPathComponent:BITHOCKEY_IDENTIFIER] retain]; + _crashesDir = [[paths objectAtIndex:0] stringByAppendingPathComponent:BITHOCKEY_IDENTIFIER]; if (![self.fileManager fileExistsAtPath:_crashesDir]) { NSDictionary *attributes = [NSDictionary dictionaryWithObject: [NSNumber numberWithUnsignedLong: 0755] forKey: NSFilePosixPermissions]; @@ -127,8 +127,8 @@ - (id)init { [self.fileManager createDirectoryAtPath:_crashesDir withIntermediateDirectories: YES attributes: attributes error: &theError]; } - _settingsFile = [[_crashesDir stringByAppendingPathComponent:BITHOCKEY_CRASH_SETTINGS] retain]; - _analyzerInProgressFile = [[_crashesDir stringByAppendingPathComponent:BITHOCKEY_CRASH_ANALYZER] retain]; + _settingsFile = [_crashesDir stringByAppendingPathComponent:BITHOCKEY_CRASH_SETTINGS]; + _analyzerInProgressFile = [_crashesDir stringByAppendingPathComponent:BITHOCKEY_CRASH_ANALYZER]; if ([_fileManager fileExistsAtPath:_analyzerInProgressFile]) { NSError *error = nil; @@ -146,26 +146,9 @@ - (id)init { - (void) dealloc { - _delegate = nil; [[NSNotificationCenter defaultCenter] removeObserver:self name:BITHockeyNetworkDidBecomeReachableNotification object:nil]; [_urlConnection cancel]; - [_urlConnection release]; - _urlConnection = nil; - - [_crashesDir release]; - [_crashFiles release]; - - [_fileManager release]; - _fileManager = nil; - - [_approvedCrashReports release]; - _approvedCrashReports = nil; - - [_analyzerInProgressFile release]; - _analyzerInProgressFile = nil; - - [super dealloc]; } @@ -324,7 +307,7 @@ - (void) handleCrashReport { [self saveSettings]; // Try loading the crash report - NSData *crashData = [[[NSData alloc] initWithData:[crashReporter loadPendingCrashReportDataAndReturnError: &error]] autorelease]; + NSData *crashData = [[NSData alloc] initWithData:[crashReporter loadPendingCrashReportDataAndReturnError: &error]]; NSString *cacheFilename = [NSString stringWithFormat: @"%.0f", [NSDate timeIntervalSinceReferenceDate]]; @@ -357,7 +340,7 @@ - (void) handleCrashReport { } // get the startup timestamp from the crash report, and the file timestamp to calculate the timeinterval when the crash happened after startup - PLCrashReport *report = [[[PLCrashReport alloc] initWithData:crashData error:&error] autorelease]; + PLCrashReport *report = [[PLCrashReport alloc] initWithData:crashData error:&error]; if ([report.applicationInfo respondsToSelector:@selector(applicationStartupTimestamp)]) { if (report.systemInfo.timestamp && report.applicationInfo.applicationStartupTimestamp) { @@ -471,7 +454,6 @@ - (void)invokeDelayedProcessing { } [alertView show]; - [alertView release]; } else { [self sendCrashReports]; } @@ -559,7 +541,7 @@ - (void)performSendingCrashReports { NSData *crashData = [NSData dataWithContentsOfFile:filename]; if ([crashData length] > 0) { - PLCrashReport *report = [[[PLCrashReport alloc] initWithData:crashData error:&error] autorelease]; + PLCrashReport *report = [[PLCrashReport alloc] initWithData:crashData error:&error]; if (report == nil) { BITHockeyLog(@"WARNING: Could not parse crash report"); @@ -754,9 +736,7 @@ - (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)err _sendingInProgress = NO; - [_responseData release]; _responseData = nil; - [_urlConnection release]; _urlConnection = nil; } @@ -808,9 +788,7 @@ - (void)connectionDidFinishLoading:(NSURLConnection *)connection { _sendingInProgress = NO; - [_responseData release]; _responseData = nil; - [_urlConnection release]; _urlConnection = nil; } diff --git a/Classes/BITFeedbackActivity.h b/Classes/BITFeedbackActivity.h index 165235c8..d801529f 100644 --- a/Classes/BITFeedbackActivity.h +++ b/Classes/BITFeedbackActivity.h @@ -39,7 +39,7 @@ @see customActivityTitle */ -@property (nonatomic, retain) UIImage *customActivityImage; +@property (nonatomic, strong) UIImage *customActivityImage; /** @@ -50,6 +50,6 @@ @see customActivityImage */ -@property (nonatomic, retain) NSString *customActivityTitle; +@property (nonatomic, strong) NSString *customActivityTitle; @end diff --git a/Classes/BITFeedbackActivity.m b/Classes/BITFeedbackActivity.m index dd96b6ba..82c07dfc 100644 --- a/Classes/BITFeedbackActivity.m +++ b/Classes/BITFeedbackActivity.m @@ -16,7 +16,7 @@ @interface BITFeedbackActivity() -@property (nonatomic, retain) NSMutableArray *items; +@property (nonatomic, strong) NSMutableArray *items; @end @@ -36,14 +36,6 @@ - (id)init { return self; } -- (void)dealloc { - [_items release]; _items = nil; - - [_customActivityImage release]; - [_customActivityTitle release]; - - [super dealloc]; -} #pragma mark - UIActivity @@ -99,7 +91,7 @@ - (UIViewController *)activityViewController { composeViewController.delegate = self; [composeViewController prepareWithItems:_items]; - UINavigationController *navController = [[[UINavigationController alloc] initWithRootViewController: composeViewController] autorelease]; + UINavigationController *navController = [[UINavigationController alloc] initWithRootViewController: composeViewController]; navController.modalPresentationStyle = UIModalPresentationFormSheet; navController.modalTransitionStyle = UIModalTransitionStyleCrossDissolve; diff --git a/Classes/BITFeedbackComposeViewController.h b/Classes/BITFeedbackComposeViewController.h index b39ef5d0..674ccb10 100644 --- a/Classes/BITFeedbackComposeViewController.h +++ b/Classes/BITFeedbackComposeViewController.h @@ -50,7 +50,7 @@ application, it is _REQUIRED_ to set this delegate and implement `[BITUpdateManagerDelegate customDeviceIdentifierForUpdateManager:]`! */ -@property (nonatomic, assign) id delegate; +@property (nonatomic, weak) id delegate; ///----------------------------------------------------------------------------- diff --git a/Classes/BITFeedbackComposeViewController.m b/Classes/BITFeedbackComposeViewController.m index 6b3fe78b..82a6f3c5 100644 --- a/Classes/BITFeedbackComposeViewController.m +++ b/Classes/BITFeedbackComposeViewController.m @@ -39,10 +39,10 @@ @interface BITFeedbackComposeViewController () -@property (nonatomic, assign) BITFeedbackManager *manager; -@property (nonatomic, retain) UITextView *textView; +@property (nonatomic, weak) BITFeedbackManager *manager; +@property (nonatomic, strong) UITextView *textView; -@property (nonatomic, retain) NSString *text; +@property (nonatomic, strong) NSString *text; - (void)setUserDataAction; @@ -70,13 +70,6 @@ - (id)init { return self; } -- (void)dealloc { - [_text release]; - [_textView release], _textView = nil; - - [super dealloc]; -} - #pragma mark - Public @@ -141,17 +134,17 @@ - (void)viewDidLoad { self.view.backgroundColor = [UIColor whiteColor]; // Do any additional setup after loading the view. - self.navigationItem.leftBarButtonItem = [[[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemCancel + self.navigationItem.leftBarButtonItem = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemCancel target:self - action:@selector(dismissAction:)] autorelease]; + action:@selector(dismissAction:)]; - self.navigationItem.rightBarButtonItem = [[[UIBarButtonItem alloc] initWithTitle:BITHockeyLocalizedString(@"HockeyFeedbackComposeSend") + self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] initWithTitle:BITHockeyLocalizedString(@"HockeyFeedbackComposeSend") style:UIBarButtonItemStyleDone target:self - action:@selector(sendAction:)] autorelease]; + action:@selector(sendAction:)]; // message input textfield - self.textView = [[[UITextView alloc] initWithFrame:self.view.frame] autorelease]; + self.textView = [[UITextView alloc] initWithFrame:self.view.frame]; self.textView.font = [UIFont systemFontOfSize:17]; self.textView.delegate = self; self.textView.backgroundColor = [UIColor whiteColor]; @@ -231,10 +224,10 @@ - (void)dismiss { } - (void)setUserDataAction { - BITFeedbackUserDataViewController *userController = [[[BITFeedbackUserDataViewController alloc] initWithStyle:UITableViewStyleGrouped] autorelease]; + BITFeedbackUserDataViewController *userController = [[BITFeedbackUserDataViewController alloc] initWithStyle:UITableViewStyleGrouped]; userController.delegate = self; - UINavigationController *navController = [[[UINavigationController alloc] initWithRootViewController:userController] autorelease]; + UINavigationController *navController = [[UINavigationController alloc] initWithRootViewController:userController]; [self.navigationController presentModalViewController:navController animated:YES]; } diff --git a/Classes/BITFeedbackListViewCell.h b/Classes/BITFeedbackListViewCell.h index 64e4e693..082d7fba 100644 --- a/Classes/BITFeedbackListViewCell.h +++ b/Classes/BITFeedbackListViewCell.h @@ -38,11 +38,11 @@ typedef enum { @interface BITFeedbackListViewCell : UITableViewCell -@property (nonatomic, retain) BITFeedbackMessage *message; +@property (nonatomic, strong) BITFeedbackMessage *message; @property (nonatomic) BITFeedbackListViewCellBackgroundStyle backgroundStyle; -@property (nonatomic, retain) BITAttributedLabel *labelText; +@property (nonatomic, strong) BITAttributedLabel *labelText; + (CGFloat) heightForRowWithMessage:(BITFeedbackMessage *)message tableViewWidth:(CGFloat)width; diff --git a/Classes/BITFeedbackListViewCell.m b/Classes/BITFeedbackListViewCell.m index 5ae14785..b4c63457 100644 --- a/Classes/BITFeedbackListViewCell.m +++ b/Classes/BITFeedbackListViewCell.m @@ -53,10 +53,10 @@ @interface BITFeedbackListViewCell () -@property (nonatomic, retain) NSDateFormatter *dateFormatter; -@property (nonatomic, retain) NSDateFormatter *timeFormatter; +@property (nonatomic, strong) NSDateFormatter *dateFormatter; +@property (nonatomic, strong) NSDateFormatter *timeFormatter; -@property (nonatomic, retain) UILabel *labelTitle; +@property (nonatomic, strong) UILabel *labelTitle; @end @@ -72,22 +72,22 @@ - (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reus _message = nil; - self.dateFormatter = [[[NSDateFormatter alloc] init] autorelease]; + self.dateFormatter = [[NSDateFormatter alloc] init]; [self.dateFormatter setTimeStyle:NSDateFormatterNoStyle]; [self.dateFormatter setDateStyle:NSDateFormatterMediumStyle]; [self.dateFormatter setLocale:[NSLocale currentLocale]]; [self.dateFormatter setDoesRelativeDateFormatting:YES]; - self.timeFormatter = [[[NSDateFormatter alloc] init] autorelease]; + self.timeFormatter = [[NSDateFormatter alloc] init]; [self.timeFormatter setTimeStyle:NSDateFormatterShortStyle]; [self.timeFormatter setDateStyle:NSDateFormatterNoStyle]; [self.timeFormatter setLocale:[NSLocale currentLocale]]; [self.timeFormatter setDoesRelativeDateFormatting:YES]; - self.labelTitle = [[[UILabel alloc] init] autorelease]; + self.labelTitle = [[UILabel alloc] init]; self.labelTitle.font = [UIFont systemFontOfSize:TITLE_FONTSIZE]; - self.labelText = [[[BITAttributedLabel alloc] init] autorelease]; + self.labelText = [[BITAttributedLabel alloc] init]; self.labelText.font = [UIFont systemFontOfSize:TEXT_FONTSIZE]; self.labelText.numberOfLines = 0; self.labelText.textAlignment = UITextAlignmentLeft; @@ -96,18 +96,6 @@ - (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reus return self; } -- (void)dealloc { - [_dateFormatter release], _dateFormatter = nil; - [_timeFormatter release], _timeFormatter = nil; - - [_labelTitle release], _labelTitle = nil; - [_labelText release], _labelText = nil; - - [_message release], _message = nil; - - [super dealloc]; -} - #pragma mark - Private @@ -133,7 +121,7 @@ + (CGFloat) heightForRowWithMessage:(BITFeedbackMessage *)message tableViewWidth } - (void)layoutSubviews { - UIView *accessoryViewBackground = [[[UIView alloc] initWithFrame:CGRectMake(0, 2, self.frame.size.width * 2, self.frame.size.height - 2)] autorelease]; + UIView *accessoryViewBackground = [[UIView alloc] initWithFrame:CGRectMake(0, 2, self.frame.size.width * 2, self.frame.size.height - 2)]; accessoryViewBackground.autoresizingMask = UIViewAutoresizingFlexibleHeight; accessoryViewBackground.clipsToBounds = YES; diff --git a/Classes/BITFeedbackListViewController.m b/Classes/BITFeedbackListViewController.m index 730538d9..1b2b0310 100644 --- a/Classes/BITFeedbackListViewController.m +++ b/Classes/BITFeedbackListViewController.m @@ -60,8 +60,8 @@ @interface BITFeedbackListViewController () -@property (nonatomic, assign) BITFeedbackManager *manager; -@property (nonatomic, retain) NSDateFormatter *lastUpdateDateFormatter; +@property (nonatomic, weak) BITFeedbackManager *manager; +@property (nonatomic, strong) NSDateFormatter *lastUpdateDateFormatter; @end @@ -78,7 +78,7 @@ - (id)init { _deleteButtonSection = -1; _userButtonSection = -1; - self.lastUpdateDateFormatter = [[[NSDateFormatter alloc] init] autorelease]; + self.lastUpdateDateFormatter = [[NSDateFormatter alloc] init]; [self.lastUpdateDateFormatter setDateStyle:NSDateFormatterShortStyle]; [self.lastUpdateDateFormatter setTimeStyle:NSDateFormatterShortStyle]; self.lastUpdateDateFormatter.locale = [NSLocale currentLocale]; @@ -91,9 +91,7 @@ - (void)dealloc { [[NSNotificationCenter defaultCenter] removeObserver:self name:BITHockeyFeedbackMessagesLoadingStarted object:nil]; [[NSNotificationCenter defaultCenter] removeObserver:self name:BITHockeyFeedbackMessagesLoadingFinished object:nil]; - [_lastUpdateDateFormatter release]; _lastUpdateDateFormatter = nil; - [super dealloc]; } @@ -125,12 +123,12 @@ - (void)viewDidLoad { id refreshClass = NSClassFromString(@"UIRefreshControl"); if (refreshClass) { - self.refreshControl = [[[UIRefreshControl alloc] init] autorelease]; + self.refreshControl = [[UIRefreshControl alloc] init]; [self.refreshControl addTarget:self action:@selector(reloadList) forControlEvents:UIControlEventValueChanged]; } else { - self.navigationItem.rightBarButtonItem = [[[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemRefresh + self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemRefresh target:self - action:@selector(reloadList)] autorelease]; + action:@selector(reloadList)]; } } @@ -199,19 +197,19 @@ - (void)viewWillDisappear:(BOOL)animated { #pragma mark - Private methods - (void)setUserDataAction:(id)sender { - BITFeedbackUserDataViewController *userController = [[[BITFeedbackUserDataViewController alloc] initWithStyle:UITableViewStyleGrouped] autorelease]; + BITFeedbackUserDataViewController *userController = [[BITFeedbackUserDataViewController alloc] initWithStyle:UITableViewStyleGrouped]; userController.delegate = self; - UINavigationController *navController = [[[UINavigationController alloc] initWithRootViewController:userController] autorelease]; + UINavigationController *navController = [[UINavigationController alloc] initWithRootViewController:userController]; navController.modalPresentationStyle = UIModalPresentationFormSheet; [self presentViewController:navController animated:YES completion:nil]; } - (void)newFeedbackAction:(id)sender { - BITFeedbackComposeViewController *composeController = [[[BITFeedbackComposeViewController alloc] init] autorelease]; + BITFeedbackComposeViewController *composeController = [[BITFeedbackComposeViewController alloc] init]; - UINavigationController *navController = [[[UINavigationController alloc] initWithRootViewController:composeController] autorelease]; + UINavigationController *navController = [[UINavigationController alloc] initWithRootViewController:composeController]; navController.modalPresentationStyle = UIModalPresentationFormSheet; [self presentViewController:navController animated:YES completion:nil]; @@ -233,7 +231,6 @@ - (void)deleteAllMessagesAction:(id)sender { [deleteAction setTag:0]; [deleteAction setActionSheetStyle:UIActionSheetStyleBlackTranslucent]; [deleteAction showInView:self.view]; - [deleteAction release]; } else { UIAlertView *deleteAction = [[UIAlertView alloc] initWithTitle:BITHockeyLocalizedString(@"HockeyFeedbackListButonDeleteAllMessages") message:BITHockeyLocalizedString(@"HockeyFeedbackListDeleteAllTitle") @@ -243,7 +240,6 @@ - (void)deleteAllMessagesAction:(id)sender { [deleteAction setTag:0]; [deleteAction show]; - [deleteAction release]; } } @@ -312,7 +308,7 @@ - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(N UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:LastUpdateIdentifier]; if (!cell) { - cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:LastUpdateIdentifier] autorelease]; + cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:LastUpdateIdentifier]; cell.textLabel.font = [UIFont systemFontOfSize:10]; cell.textLabel.textColor = DEFAULT_TEXTCOLOR; cell.accessoryType = UITableViewCellAccessoryNone; @@ -342,7 +338,7 @@ - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(N cell = [tableView dequeueReusableCellWithIdentifier:identifier]; if (!cell) { - cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:identifier] autorelease]; + cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:identifier]; cell.textLabel.font = [UIFont systemFontOfSize:14]; cell.textLabel.numberOfLines = 0; @@ -404,7 +400,7 @@ - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(N // status label or shadow lines if (indexPath.section == 0) { - UILabel *statusLabel = [[[UILabel alloc] initWithFrame:CGRectMake(0, 6, cell.frame.size.width, 28)] autorelease]; + UILabel *statusLabel = [[UILabel alloc] initWithFrame:CGRectMake(0, 6, cell.frame.size.width, 28)]; statusLabel.font = [UIFont systemFontOfSize:10]; statusLabel.textColor = DEFAULT_TEXTCOLOR; @@ -417,7 +413,7 @@ - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(N [cell addSubview:statusLabel]; } else if (indexPath.section == 2) { - UIView *lineView1 = [[[UIView alloc] initWithFrame:CGRectMake(0, 0, cell.frame.size.width, 1)] autorelease]; + UIView *lineView1 = [[UIView alloc] initWithFrame:CGRectMake(0, 0, cell.frame.size.width, 1)]; lineView1.backgroundColor = BORDER_COLOR; lineView1.autoresizingMask = UIViewAutoresizingFlexibleWidth; [cell addSubview:lineView1]; @@ -428,7 +424,7 @@ - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(N BITFeedbackListViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier]; if (!cell) { - cell = [[[BITFeedbackListViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease]; + cell = [[BITFeedbackListViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier]; cell.accessoryType = UITableViewCellAccessoryNone; cell.selectionStyle = UITableViewCellSelectionStyleNone; } @@ -444,7 +440,7 @@ - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(N cell.labelText.delegate = self; cell.labelText.userInteractionEnabled = YES; - UIView *lineView1 = [[[UIView alloc] initWithFrame:CGRectMake(0, 0, cell.frame.size.width, 1)] autorelease]; + UIView *lineView1 = [[UIView alloc] initWithFrame:CGRectMake(0, 0, cell.frame.size.width, 1)]; lineView1.backgroundColor = BORDER_COLOR; lineView1.autoresizingMask = UIViewAutoresizingFlexibleWidth; [cell addSubview:lineView1]; @@ -504,7 +500,6 @@ - (void)attributedLabel:(BITAttributedLabel *)label didSelectLinkWithURL:(NSURL [linkAction setTag:1]; [linkAction setActionSheetStyle:UIActionSheetStyleBlackTranslucent]; [linkAction showInView:self.view]; - [linkAction release]; } else { UIAlertView *linkAction = [[UIAlertView alloc] initWithTitle:[url absoluteString] message:nil @@ -515,7 +510,6 @@ - (void)attributedLabel:(BITAttributedLabel *)label didSelectLinkWithURL:(NSURL [linkAction setTag:1]; [linkAction show]; - [linkAction release]; } } diff --git a/Classes/BITFeedbackManager.m b/Classes/BITFeedbackManager.m index 57c9eae4..68764135 100644 --- a/Classes/BITFeedbackManager.m +++ b/Classes/BITFeedbackManager.m @@ -86,7 +86,7 @@ - (id)init { // temporary directory for crashes grabbed from PLCrashReporter NSArray *paths = NSSearchPathForDirectoriesInDomains(NSApplicationSupportDirectory, NSUserDomainMask, YES); - _feedbackDir = [[[paths objectAtIndex:0] stringByAppendingPathComponent:BITHOCKEY_IDENTIFIER] retain]; + _feedbackDir = [[paths objectAtIndex:0] stringByAppendingPathComponent:BITHOCKEY_IDENTIFIER]; if (![_fileManager fileExistsAtPath:_feedbackDir]) { NSDictionary *attributes = [NSDictionary dictionaryWithObject: [NSNumber numberWithUnsignedLong: 0755] forKey: NSFilePosixPermissions]; @@ -95,7 +95,7 @@ - (id)init { [_fileManager createDirectoryAtPath:_feedbackDir withIntermediateDirectories: YES attributes: attributes error: &theError]; } - _settingsFile = [[_feedbackDir stringByAppendingPathComponent:BITHOCKEY_FEEDBACK_SETTINGS] retain]; + _settingsFile = [_feedbackDir stringByAppendingPathComponent:BITHOCKEY_FEEDBACK_SETTINGS]; _userID = nil; _userName = nil; @@ -108,24 +108,6 @@ - (void)dealloc { [[NSNotificationCenter defaultCenter] removeObserver:self name:BITHockeyNetworkDidBecomeReachableNotification object:nil]; [[NSNotificationCenter defaultCenter] removeObserver:self name:UIApplicationDidBecomeActiveNotification object:nil]; - - [_currentFeedbackListViewController release], _currentFeedbackListViewController = nil; - [_currentFeedbackComposeViewController release], _currentFeedbackComposeViewController = nil; - - [_lastCheck release], _lastCheck = nil; - [_token release], _token = nil; - [_lastMessageID release], _lastMessageID = nil; - [_feedbackList release], _feedbackList = nil; - - [_userID release], _userID = nil; - [_userName release], _userName = nil; - [_userEmail release], _userEmail = nil; - - [_fileManager release], _fileManager = nil; - [_feedbackDir release], _feedbackDir = nil; - [_settingsFile release], _settingsFile = nil; - - [super dealloc]; } @@ -154,10 +136,10 @@ - (void)cleanupDidBecomeActiveNotifications { - (NSString *)uuidString { CFUUIDRef theToken = CFUUIDCreate(NULL); - CFStringRef stringUUID = CFUUIDCreateString(NULL, theToken); + NSString *stringUUID = (__bridge_transfer NSString *)CFUUIDCreateString(NULL, theToken); CFRelease(theToken); - return [(NSString *)stringUUID autorelease]; + return stringUUID; } - (NSString *)uuidAsLowerCaseAndShortened { @@ -167,7 +149,7 @@ - (NSString *)uuidAsLowerCaseAndShortened { #pragma mark - Feedback Modal UI - (BITFeedbackListViewController *)feedbackListViewController:(BOOL)modal { - return [[[BITFeedbackListViewController alloc] initWithModalStyle:modal] autorelease]; + return [[BITFeedbackListViewController alloc] initWithModalStyle:modal]; } - (void)showFeedbackListView { @@ -181,7 +163,7 @@ - (void)showFeedbackListView { - (BITFeedbackComposeViewController *)feedbackComposeViewController { - return [[[BITFeedbackComposeViewController alloc] init] autorelease]; + return [[BITFeedbackComposeViewController alloc] init]; } - (void)showFeedbackComposeView { @@ -294,7 +276,7 @@ - (void)loadMessages { if (![_fileManager fileExistsAtPath:_settingsFile]) return; - NSData *codedData = [[[NSData alloc] initWithContentsOfFile:_settingsFile] autorelease]; + NSData *codedData = [[NSData alloc] initWithContentsOfFile:_settingsFile]; if (codedData == nil) return; NSKeyedUnarchiver *unarchiver = nil; @@ -354,7 +336,6 @@ - (void)loadMessages { } [unarchiver finishDecoding]; - [unarchiver release]; if (!self.lastCheck) { self.lastCheck = [NSDate distantPast]; @@ -396,8 +377,6 @@ - (void)saveMessages { [archiver finishEncoding]; [data writeToFile:_settingsFile atomically:YES]; - [archiver release]; - [data release]; } @@ -605,7 +584,7 @@ - (void)updateMessageListFromResponse:(NSDictionary *)jsonDictionary { NSInteger pendingMessagesCount = [messagesSendInProgress count] + [[self messagesWithStatus:BITFeedbackMessageStatusSendPending] count]; __block BOOL newMessage = NO; - __block NSMutableSet *returnedMessageIDs = [[[NSMutableSet alloc] init] autorelease]; + NSMutableSet *returnedMessageIDs = [[NSMutableSet alloc] init]; [feedMessages enumerateObjectsUsingBlock:^(id objMessage, NSUInteger messagesIdx, BOOL *stop) { if ([(NSDictionary *)objMessage objectForKey:@"id"]) { @@ -632,7 +611,7 @@ - (void)updateMessageListFromResponse:(NSDictionary *)jsonDictionary { matchingSendInProgressOrInConflictMessage.status = BITFeedbackMessageStatusRead; } else { if ([(NSDictionary *)objMessage objectForKey:@"clean_text"] || [(NSDictionary *)objMessage objectForKey:@"text"]) { - BITFeedbackMessage *message = [[[BITFeedbackMessage alloc] init] autorelease]; + BITFeedbackMessage *message = [[BITFeedbackMessage alloc] init]; message.text = [(NSDictionary *)objMessage objectForKey:@"clean_text"] ?: [(NSDictionary *)objMessage objectForKey:@"text"] ?: @""; message.name = [(NSDictionary *)objMessage objectForKey:@"name"] ?: @""; message.email = [(NSDictionary *)objMessage objectForKey:@"email"] ?: @""; @@ -668,12 +647,12 @@ - (void)updateMessageListFromResponse:(NSDictionary *)jsonDictionary { latestMessageFromUser = YES; if (!latestMessageFromUser && self.showAlertOnIncomingMessages && !self.currentFeedbackListViewController && !self.currentFeedbackComposeViewController) { - UIAlertView *alertView = [[[UIAlertView alloc] initWithTitle:BITHockeyLocalizedString(@"HockeyFeedbackNewMessageTitle") + UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:BITHockeyLocalizedString(@"HockeyFeedbackNewMessageTitle") message:BITHockeyLocalizedString(@"HockeyFeedbackNewMessageText") delegate:self cancelButtonTitle:BITHockeyLocalizedString(@"HockeyFeedbackIgnore") otherButtonTitles:BITHockeyLocalizedString(@"HockeyFeedbackShow"), nil - ] autorelease]; + ]; [alertView setTag:0]; [alertView show]; _incomingMessagesAlertShowing = YES; @@ -802,7 +781,7 @@ - (void)sendNetworkRequestWithHTTPMethod:(NSString *)httpMethod withMessage:(BIT [self saveMessages]; [self performSelector:@selector(fetchMessageUpdates) withObject:nil afterDelay:0.2]; } else if ([responseData length]) { - NSString *responseString = [[[NSString alloc] initWithBytes:[responseData bytes] length:[responseData length] encoding: NSUTF8StringEncoding] autorelease]; + NSString *responseString = [[NSString alloc] initWithBytes:[responseData bytes] length:[responseData length] encoding: NSUTF8StringEncoding]; BITHockeyLog(@"INFO: Received API response: %@", responseString); NSError *error = NULL; @@ -896,7 +875,7 @@ - (void)submitPendingMessages { } - (void)submitMessageWithText:(NSString *)text { - BITFeedbackMessage *message = [[[BITFeedbackMessage alloc] init] autorelease]; + BITFeedbackMessage *message = [[BITFeedbackMessage alloc] init]; message.text = text; [message setStatus:BITFeedbackMessageStatusSendPending]; [message setToken:[self uuidAsLowerCaseAndShortened]]; diff --git a/Classes/BITFeedbackManagerPrivate.h b/Classes/BITFeedbackManagerPrivate.h index 215a02ef..ff38bb98 100644 --- a/Classes/BITFeedbackManagerPrivate.h +++ b/Classes/BITFeedbackManagerPrivate.h @@ -36,20 +36,20 @@ } -@property (nonatomic, retain) NSMutableArray *feedbackList; -@property (nonatomic, retain) NSString *token; +@property (nonatomic, strong) NSMutableArray *feedbackList; +@property (nonatomic, strong) NSString *token; // used by BITHockeyManager if disable status is changed @property (nonatomic, getter = isFeedbackManagerDisabled) BOOL disableFeedbackManager; -@property (nonatomic, retain) BITFeedbackListViewController *currentFeedbackListViewController; -@property (nonatomic, retain) BITFeedbackComposeViewController *currentFeedbackComposeViewController; +@property (nonatomic, strong) BITFeedbackListViewController *currentFeedbackListViewController; +@property (nonatomic, strong) BITFeedbackComposeViewController *currentFeedbackComposeViewController; @property (nonatomic) BOOL didAskUserData; -@property (nonatomic, retain) NSDate *lastCheck; +@property (nonatomic, strong) NSDate *lastCheck; -@property (nonatomic, retain) NSNumber *lastMessageID; +@property (nonatomic, strong) NSNumber *lastMessageID; @property (nonatomic, copy) NSString *userID; @property (nonatomic, copy) NSString *userName; diff --git a/Classes/BITFeedbackMessage.m b/Classes/BITFeedbackMessage.m index f9e194fe..f6915278 100644 --- a/Classes/BITFeedbackMessage.m +++ b/Classes/BITFeedbackMessage.m @@ -49,18 +49,6 @@ - (id) init { return self; } -- (void)dealloc { - [_text release], _text = nil; - [_userID release], _userID = nil; - [_name release], _name = nil; - [_email release], _email = nil; - [_date release], _date = nil; - [_id release], _id = nil; - [_token release], _token = nil; - - [super dealloc]; -} - #pragma mark - NSCoder diff --git a/Classes/BITFeedbackUserDataViewController.h b/Classes/BITFeedbackUserDataViewController.h index 7a4795b8..14824a0b 100644 --- a/Classes/BITFeedbackUserDataViewController.h +++ b/Classes/BITFeedbackUserDataViewController.h @@ -33,7 +33,7 @@ @interface BITFeedbackUserDataViewController : UITableViewController -@property (nonatomic, assign) id delegate; +@property (nonatomic, weak) id delegate; @end diff --git a/Classes/BITFeedbackUserDataViewController.m b/Classes/BITFeedbackUserDataViewController.m index 1bcbda83..346b341a 100644 --- a/Classes/BITFeedbackUserDataViewController.m +++ b/Classes/BITFeedbackUserDataViewController.m @@ -34,7 +34,7 @@ #import "BITFeedbackManagerPrivate.h" @interface BITFeedbackUserDataViewController () -@property (nonatomic, assign) BITFeedbackManager *manager; +@property (nonatomic, weak) BITFeedbackManager *manager; @property (nonatomic, copy) NSString *name; @property (nonatomic, copy) NSString *email; @@ -58,26 +58,19 @@ - (id)initWithStyle:(UITableViewStyle)style { return self; } -- (void)dealloc { - [_name release], _name = nil; - [_email release], _email = nil; - - [super dealloc]; -} - - (void)viewDidLoad { [super viewDidLoad]; [self.tableView setScrollEnabled:NO]; // Do any additional setup after loading the view. - self.navigationItem.leftBarButtonItem = [[[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemCancel + self.navigationItem.leftBarButtonItem = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemCancel target:self - action:@selector(dismissAction:)] autorelease]; + action:@selector(dismissAction:)]; - self.navigationItem.rightBarButtonItem = [[[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemSave + self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemSave target:self - action:@selector(saveAction:)] autorelease]; + action:@selector(saveAction:)]; } - (void)viewDidUnload { @@ -195,13 +188,13 @@ - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(N UITableViewCell *cell = [self.tableView dequeueReusableCellWithIdentifier:CellIdentifier]; if (cell == nil) { - cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease]; + cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier]; cell.accessoryType = UITableViewCellAccessoryNone; cell.selectionStyle = UITableViewCellSelectionStyleNone; cell.backgroundColor = [UIColor whiteColor]; - UITextField *textField = [[[UITextField alloc] initWithFrame:CGRectMake(110, 10, 185, 30)] autorelease]; + UITextField *textField = [[UITextField alloc] initWithFrame:CGRectMake(110, 10, 185, 30)]; textField.adjustsFontSizeToFitWidth = YES; textField.textColor = [UIColor blackColor]; textField.backgroundColor = [UIColor lightGrayColor]; diff --git a/Classes/BITHockeyBaseManager.h b/Classes/BITHockeyBaseManager.h index 234874df..31a008d2 100644 --- a/Classes/BITHockeyBaseManager.h +++ b/Classes/BITHockeyBaseManager.h @@ -48,7 +48,7 @@ Default is RGB(25, 25, 25) @see barStyle */ -@property (nonatomic, retain) UIColor *tintColor; +@property (nonatomic, strong) UIColor *tintColor; /** The UIModalPresentationStyle for showing the update user interface when invoked diff --git a/Classes/BITHockeyBaseManager.m b/Classes/BITHockeyBaseManager.m index 67812a8a..625b25e2 100644 --- a/Classes/BITHockeyBaseManager.m +++ b/Classes/BITHockeyBaseManager.m @@ -41,7 +41,7 @@ - (id)init { self.tintColor = BIT_RGBCOLOR(25, 25, 25); _modalPresentationStyle = UIModalPresentationFormSheet; - NSLocale *enUSPOSIXLocale = [[[NSLocale alloc] initWithLocaleIdentifier:@"en_US_POSIX"] autorelease]; + NSLocale *enUSPOSIXLocale = [[NSLocale alloc] initWithLocaleIdentifier:@"en_US_POSIX"]; _rfc3339Formatter = [[NSDateFormatter alloc] init]; [_rfc3339Formatter setLocale:enUSPOSIXLocale]; [_rfc3339Formatter setDateFormat:@"yyyy'-'MM'-'dd'T'HH':'mm':'ss'Z'"]; @@ -52,28 +52,13 @@ - (id)init { - (id)initWithAppIdentifier:(NSString *)appIdentifier isAppStoreEnvironemt:(BOOL)isAppStoreEnvironment { if ((self = [self init])) { - - self.appIdentifier = appIdentifier; + _appIdentifier = appIdentifier; _isAppStoreEnvironment = isAppStoreEnvironment; - } return self; } -- (void)dealloc { - [_serverURL release]; _serverURL = nil; - - [_navController release], _navController = nil; - - [_rfc3339Formatter release], _rfc3339Formatter = nil; - - [_tintColor release], _tintColor = nil; - - [super dealloc]; -} - - #pragma mark - Private - (void)reportError:(NSError *)error { @@ -165,7 +150,7 @@ - (void)showView:(UIViewController *)viewController { #pragma clang diagnostic pop } - if (_navController != nil) [_navController release], _navController = nil; + if (_navController != nil) _navController = nil; _navController = [[UINavigationController alloc] initWithRootViewController:viewController]; _navController.navigationBar.barStyle = _barStyle; diff --git a/Classes/BITHockeyBaseManagerPrivate.h b/Classes/BITHockeyBaseManagerPrivate.h index 50b30799..81c5ad71 100644 --- a/Classes/BITHockeyBaseManagerPrivate.h +++ b/Classes/BITHockeyBaseManagerPrivate.h @@ -14,7 +14,7 @@ @interface BITHockeyBaseManager() -@property (nonatomic, retain) NSString *appIdentifier; +@property (nonatomic, strong) NSString *appIdentifier; - (id)initWithAppIdentifier:(NSString *)appIdentifier isAppStoreEnvironemt:(BOOL)isAppStoreEnvironment; diff --git a/Classes/BITHockeyBaseViewController.m b/Classes/BITHockeyBaseViewController.m index 17811b80..f54a1eb4 100644 --- a/Classes/BITHockeyBaseViewController.m +++ b/Classes/BITHockeyBaseViewController.m @@ -32,9 +32,9 @@ - (id)initWithModalStyle:(BOOL)modal { //might be better in viewDidLoad, but to workaround rdar://12214613 and as it doesn't //hurt, we do it here if (_modal) { - self.navigationItem.leftBarButtonItem = [[[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemDone + self.navigationItem.leftBarButtonItem = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemDone target:self - action:@selector(onDismissModal:)] autorelease]; + action:@selector(onDismissModal:)]; } } return self; diff --git a/Classes/BITHockeyHelper.m b/Classes/BITHockeyHelper.m index 2cdde76c..5df67095 100644 --- a/Classes/BITHockeyHelper.m +++ b/Classes/BITHockeyHelper.m @@ -36,22 +36,20 @@ #pragma mark NSString helpers NSString *bit_URLEncodedString(NSString *inputString) { - NSString *result = (NSString *)CFURLCreateStringByAddingPercentEscapes(kCFAllocatorDefault, - (CFStringRef)inputString, - NULL, - CFSTR("!*'();:@&=+$,/?%#[]"), - kCFStringEncodingUTF8); - [result autorelease]; - return result; + return CFBridgingRelease(CFURLCreateStringByAddingPercentEscapes(kCFAllocatorDefault, + (__bridge CFStringRef)inputString, + NULL, + CFSTR("!*'();:@&=+$,/?%#[]"), + kCFStringEncodingUTF8) + ); } NSString *bit_URLDecodedString(NSString *inputString) { - NSString *result = (NSString *)CFURLCreateStringByReplacingPercentEscapesUsingEncoding(kCFAllocatorDefault, - (CFStringRef)inputString, - CFSTR(""), - kCFStringEncodingUTF8); - [result autorelease]; - return result; + return CFBridgingRelease(CFURLCreateStringByReplacingPercentEscapesUsingEncoding(kCFAllocatorDefault, + (__bridge CFStringRef)inputString, + CFSTR(""), + kCFStringEncodingUTF8) + ); } NSComparisonResult bit_versionCompare(NSString *stringA, NSString *stringB) { @@ -94,16 +92,25 @@ NSComparisonResult bit_versionCompare(NSString *stringA, NSString *stringB) { // try to new iOS6 identifierForAdvertising Class advertisingClass = NSClassFromString(@"ASIdentifierManager"); if (advertisingClass) { +# pragma clang diagnostic push +# pragma clang diagnostic ignored "-Warc-performSelector-leaks" id adInstance = [advertisingClass performSelector:NSSelectorFromString(@"sharedManager")]; +# pragma clang diagnostic pop SEL adidSelector = NSSelectorFromString(@"advertisingIdentifier"); +# pragma clang diagnostic push +# pragma clang diagnostic ignored "-Warc-performSelector-leaks" return [[adInstance performSelector:adidSelector] performSelector:NSSelectorFromString(@"UUIDString")]; +# pragma clang diagnostic pop } // try to new iOS6 identifierForVendor, in case ASIdentifierManager is not linked SEL vendoridSelector = NSSelectorFromString(@"identifierForVendor"); if ([[UIDevice currentDevice] respondsToSelector:vendoridSelector]) { +# pragma clang diagnostic push +# pragma clang diagnostic ignored "-Warc-performSelector-leaks" return [[[UIDevice currentDevice] performSelector:vendoridSelector] performSelector:NSSelectorFromString(@"UUIDString")]; +# pragma clang diagnostic pop } // use app bundle path @@ -360,7 +367,7 @@ BOOL bit_hasAlpha(UIImage *inputImage) { UIImage *bit_imageWithContentsOfResolutionIndependentFile(NSString *path) { #ifndef __clang_analyzer__ // clang alayzer in 4.2b3 thinks here's a leak, which is not the case. - return [bit_newWithContentsOfResolutionIndependentFile(path) autorelease]; + return bit_newWithContentsOfResolutionIndependentFile(path); #endif } diff --git a/Classes/BITHockeyManager.h b/Classes/BITHockeyManager.h index 86f3d4d8..5a0088ec 100644 --- a/Classes/BITHockeyManager.h +++ b/Classes/BITHockeyManager.h @@ -169,7 +169,7 @@ By default this is set to the HockeyApp servers and there rarely should be a need to modify that. */ -@property (nonatomic, retain) NSString *serverURL; +@property (nonatomic, strong) NSString *serverURL; /** @@ -181,7 +181,7 @@ @see disableCrashManager @return The BITCrashManager instance initialized by BITHockeyManager */ -@property (nonatomic, retain, readonly) BITCrashManager *crashManager; +@property (nonatomic, strong, readonly) BITCrashManager *crashManager; /** @@ -207,7 +207,7 @@ @see disableUpdateManager @return The BITUpdateManager instance initialized by BITHockeyManager */ -@property (nonatomic, retain, readonly) BITUpdateManager *updateManager; +@property (nonatomic, strong, readonly) BITUpdateManager *updateManager; /** @@ -233,7 +233,7 @@ @see disableFeedbackManager @return The BITFeedbackManager instance initialized by BITHockeyManager */ -@property (nonatomic, retain, readonly) BITFeedbackManager *feedbackManager; +@property (nonatomic, strong, readonly) BITFeedbackManager *feedbackManager; /** diff --git a/Classes/BITHockeyManager.m b/Classes/BITHockeyManager.m index a5579e0c..f4222785 100644 --- a/Classes/BITHockeyManager.m +++ b/Classes/BITHockeyManager.m @@ -118,24 +118,11 @@ - (id) init { return self; } -- (void)dealloc { - [_appIdentifier release], _appIdentifier = nil; - - [_crashManager release], _crashManager = nil; - [_updateManager release], _updateManager = nil; - [_feedbackManager release], _feedbackManager = nil; - - _delegate = nil; - - [super dealloc]; -} - #pragma mark - Public Instance Methods (Configuration) - (void)configureWithIdentifier:(NSString *)appIdentifier delegate:(id)delegate { _delegate = delegate; - [_appIdentifier release]; _appIdentifier = [appIdentifier copy]; [self initializeModules]; @@ -143,7 +130,6 @@ - (void)configureWithIdentifier:(NSString *)appIdentifier delegate:(id)delegate - (void)configureWithBetaIdentifier:(NSString *)betaIdentifier liveIdentifier:(NSString *)liveIdentifier delegate:(id)delegate { _delegate = delegate; - [_appIdentifier release]; // check the live identifier now, because otherwise invalid identifier would only be logged when the app is already in the store if (![self checkValidityOfAppIdentifier:liveIdentifier]) { @@ -232,7 +218,6 @@ - (void)setServerURL:(NSString *)aServerURL { } if (_serverURL != aServerURL) { - [_serverURL release]; _serverURL = [aServerURL copy]; } } @@ -345,9 +330,9 @@ + (void)applyJMCConfiguration:(NSDictionary *)configuration { id jmcInstance = [self jmcInstance]; SEL configureSelector = @selector(configureJiraConnect:projectKey:apiKey:); - NSString *url = [configuration valueForKey:@"url"]; - NSString *project = [configuration valueForKey:@"project"]; - NSString *key = [configuration valueForKey:@"key"]; + __unsafe_unretained NSString *url = [configuration valueForKey:@"url"]; + __unsafe_unretained NSString *project = [configuration valueForKey:@"project"]; + __unsafe_unretained NSString *key = [configuration valueForKey:@"key"]; NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:[jmcInstance methodSignatureForSelector:configureSelector]]; invocation.target = jmcInstance; @@ -382,12 +367,11 @@ - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(N NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; NSMutableDictionary *trackerConfig = [[defaults valueForKey:@"BITTrackerConfigurations"] mutableCopy]; if (!trackerConfig) { - trackerConfig = [[NSMutableDictionary dictionaryWithCapacity:1] retain]; + trackerConfig = [NSMutableDictionary dictionaryWithCapacity:1]; } [trackerConfig setValue:[object trackerConfig] forKey:_appIdentifier]; [defaults setValue:trackerConfig forKey:@"BITTrackerConfigurations"]; - [trackerConfig release]; [defaults synchronize]; [self configureJMC]; diff --git a/Classes/BITHockeyManagerPrivate.h b/Classes/BITHockeyManagerPrivate.h index 92dd1566..1b0c9e0d 100644 --- a/Classes/BITHockeyManagerPrivate.h +++ b/Classes/BITHockeyManagerPrivate.h @@ -32,6 +32,6 @@ @interface BITHockeyManager () { } -@property (nonatomic, assign) id delegate; +@property (nonatomic, weak) id delegate; @end diff --git a/Classes/BITStoreButton.h b/Classes/BITStoreButton.h index a54f4475..81906b09 100644 --- a/Classes/BITStoreButton.h +++ b/Classes/BITStoreButton.h @@ -56,10 +56,10 @@ - (id)initWithPadding:(CGPoint)padding; // action delegate -@property (nonatomic, assign) id buttonDelegate; +@property (nonatomic, weak) id buttonDelegate; // change the button layer -@property (nonatomic, retain) BITStoreButtonData *buttonData; +@property (nonatomic, strong) BITStoreButtonData *buttonData; - (void)setButtonData:(BITStoreButtonData *)aButtonData animated:(BOOL)animated; // align helper diff --git a/Classes/BITStoreButton.m b/Classes/BITStoreButton.m index 9cd5480c..0f69eff7 100644 --- a/Classes/BITStoreButton.m +++ b/Classes/BITStoreButton.m @@ -52,14 +52,9 @@ - (id)initWithLabel:(NSString*)aLabel enabled:(BOOL)flag { } + (id)dataWithLabel:(NSString*)aLabel enabled:(BOOL)flag { - return [[[[self class] alloc] initWithLabel:aLabel enabled:flag] autorelease]; + return [[[self class] alloc] initWithLabel:aLabel enabled:flag]; } -- (void)dealloc { - [_label release], _label = nil; - - [super dealloc]; -} @end @@ -184,11 +179,6 @@ - (id)initWithPadding:(CGPoint)padding { return self; } -- (void)dealloc { - [_buttonData release]; - - [super dealloc]; -} #pragma mark - UIView @@ -225,8 +215,7 @@ - (void)setButtonData:(BITStoreButtonData *)aButtonData { - (void)setButtonData:(BITStoreButtonData *)aButtonData animated:(BOOL)animated { if (_buttonData != aButtonData) { - [_buttonData release]; - _buttonData = [aButtonData retain]; + _buttonData = aButtonData; } [self updateButtonAnimated:animated]; diff --git a/Classes/BITUpdateManager.h b/Classes/BITUpdateManager.h index 2554d243..e15c4a84 100644 --- a/Classes/BITUpdateManager.h +++ b/Classes/BITUpdateManager.h @@ -96,7 +96,7 @@ typedef enum { application, it is _REQUIRED_ to set this delegate and implement `[BITUpdateManagerDelegate customDeviceIdentifierForUpdateManager:]`! */ -@property (nonatomic, assign) id delegate; +@property (nonatomic, weak) id delegate; ///----------------------------------------------------------------------------- @@ -244,7 +244,7 @@ typedef enum { @see requireAuthorization */ -@property (nonatomic, retain) NSString *authenticationSecret; +@property (nonatomic, strong) NSString *authenticationSecret; ///----------------------------------------------------------------------------- @@ -269,7 +269,7 @@ typedef enum { @see [BITUpdateManagerDelegate didDisplayExpiryAlertForUpdateManager:] @warning This only works when using Ad-Hoc provisioning profiles! */ -@property (nonatomic, retain) NSDate *expiryDate; +@property (nonatomic, strong) NSDate *expiryDate; ///----------------------------------------------------------------------------- diff --git a/Classes/BITUpdateManager.m b/Classes/BITUpdateManager.m index 1cc9b496..c4d9c83d 100644 --- a/Classes/BITUpdateManager.m +++ b/Classes/BITUpdateManager.m @@ -82,7 +82,6 @@ - (void)reportError:(NSError *)error { delegate:nil cancelButtonTitle:BITHockeyLocalizedString(@"OK") otherButtonTitles:nil]; [alert show]; - [alert release]; _showFeedback = NO; } } @@ -197,7 +196,7 @@ - (NSString *)currentUsageString { } - (NSString *)installationDateString { - NSDateFormatter *formatter = [[[NSDateFormatter alloc] init] autorelease]; + NSDateFormatter *formatter = [[NSDateFormatter alloc] init]; [formatter setDateFormat:@"MM/dd/yyyy"]; double installationTimeStamp = [[NSUserDefaults standardUserDefaults] doubleForKey:kBITUpdateDateOfVersionInstallation]; if (installationTimeStamp == 0.0f) { @@ -370,31 +369,14 @@ - (void)dealloc { [[NSNotificationCenter defaultCenter] removeObserver:self name:UIApplicationDidBecomeActiveNotification object:nil]; [[NSNotificationCenter defaultCenter] removeObserver:self name:UIApplicationWillResignActiveNotification object:nil]; - _delegate = nil; - [_urlConnection cancel]; - self.urlConnection = nil; - - [_expiryDate release]; - _expiryDate = nil; - - [_blockingView release]; - [_currentHockeyViewController release]; - [_appVersions release]; - [_receivedData release]; - [_lastCheck release]; - [_usageStartTimestamp release]; - [_authenticationSecret release]; - [_uuid release]; - - [super dealloc]; } #pragma mark - BetaUpdateUI - (BITUpdateViewController *)hockeyViewController:(BOOL)modal { - return [[[BITUpdateViewController alloc] initWithModalStyle:modal] autorelease]; + return [[BITUpdateViewController alloc] initWithModalStyle:modal]; } - (void)showUpdateView { @@ -419,22 +401,22 @@ - (void)showCheckForUpdateAlert { if (!_updateAlertShowing) { if ([self hasNewerMandatoryVersion]) { - UIAlertView *alertView = [[[UIAlertView alloc] initWithTitle:BITHockeyLocalizedString(@"UpdateAvailable") + UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:BITHockeyLocalizedString(@"UpdateAvailable") message:[NSString stringWithFormat:BITHockeyLocalizedString(@"UpdateAlertMandatoryTextWithAppVersion"), [self.newestAppVersion nameAndVersionString]] delegate:self cancelButtonTitle:BITHockeyLocalizedString(@"UpdateInstall") otherButtonTitles:nil - ] autorelease]; + ]; [alertView setTag:2]; [alertView show]; _updateAlertShowing = YES; } else { - UIAlertView *alertView = [[[UIAlertView alloc] initWithTitle:BITHockeyLocalizedString(@"UpdateAvailable") + UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:BITHockeyLocalizedString(@"UpdateAvailable") message:[NSString stringWithFormat:BITHockeyLocalizedString(@"UpdateAlertTextWithAppVersion"), [self.newestAppVersion nameAndVersionString]] delegate:self cancelButtonTitle:BITHockeyLocalizedString(@"UpdateIgnore") otherButtonTitles:BITHockeyLocalizedString(@"UpdateShow"), nil - ] autorelease]; + ]; if (self.isShowingDirectInstallOption) { [alertView addButtonWithTitle:BITHockeyLocalizedString(@"UpdateInstall")]; } @@ -448,12 +430,12 @@ - (void)showCheckForUpdateAlert { // nag the user with neverending alerts if we cannot find out the window for presenting the covering sheet - (void)alertFallback:(NSString *)message { - UIAlertView *alertView = [[[UIAlertView alloc] initWithTitle:nil + UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:nil message:message delegate:self cancelButtonTitle:BITHockeyLocalizedString(@"HockeyOK") otherButtonTitles:nil - ] autorelease]; + ]; [alertView setTag:1]; [alertView show]; } @@ -471,14 +453,14 @@ - (void)showBlockingScreen:(NSString *)message image:(NSString *)image { CGRect frame = [visibleWindow frame]; - self.blockingView = [[[UIView alloc] initWithFrame:frame] autorelease]; - UIImageView *backgroundView = [[[UIImageView alloc] initWithImage:bit_imageNamed(@"bg.png", BITHOCKEYSDK_BUNDLE)] autorelease]; + self.blockingView = [[UIView alloc] initWithFrame:frame]; + UIImageView *backgroundView = [[UIImageView alloc] initWithImage:bit_imageNamed(@"bg.png", BITHOCKEYSDK_BUNDLE)]; backgroundView.contentMode = UIViewContentModeScaleAspectFill; backgroundView.frame = frame; [self.blockingView addSubview:backgroundView]; if (image != nil) { - UIImageView *imageView = [[[UIImageView alloc] initWithImage:bit_imageNamed(image, BITHOCKEYSDK_BUNDLE)] autorelease]; + UIImageView *imageView = [[UIImageView alloc] initWithImage:bit_imageNamed(image, BITHOCKEYSDK_BUNDLE)]; imageView.contentMode = UIViewContentModeCenter; imageView.frame = frame; [self.blockingView addSubview:imageView]; @@ -490,7 +472,7 @@ - (void)showBlockingScreen:(NSString *)message image:(NSString *)image { frame.size.width -= 40; frame.size.height = 50; - UILabel *label = [[[UILabel alloc] initWithFrame:frame] autorelease]; + UILabel *label = [[UILabel alloc] initWithFrame:frame]; label.text = message; label.textAlignment = UITextAlignmentCenter; label.numberOfLines = 2; @@ -556,7 +538,7 @@ - (void)checkForAuthorization { NSData *responseData = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error]; if ([responseData length]) { - NSString *responseString = [[[NSString alloc] initWithBytes:[responseData bytes] length:[responseData length] encoding: NSUTF8StringEncoding] autorelease]; + NSString *responseString = [[NSString alloc] initWithBytes:[responseData bytes] length:[responseData length] encoding: NSUTF8StringEncoding]; NSDictionary *feedDict = (NSDictionary *)[NSJSONSerialization JSONObjectWithData:[responseString dataUsingEncoding:NSUTF8StringEncoding] options:kNilOptions error:&error]; @@ -665,7 +647,7 @@ - (void)checkForUpdateShowFeedback:(BOOL)feedback { [request setValue:@"Hockey/iOS" forHTTPHeaderField:@"User-Agent"]; [request setValue:@"gzip" forHTTPHeaderField:@"Accept-Encoding"]; - self.urlConnection = [[[NSURLConnection alloc] initWithRequest:request delegate:self] autorelease]; + self.urlConnection = [[NSURLConnection alloc] initWithRequest:request delegate:self]; if (!_urlConnection) { self.checkInProgress = NO; [self reportError:[NSError errorWithDomain:kBITUpdateErrorDomain @@ -683,7 +665,7 @@ - (BOOL)initiateAppDownload { } #if TARGET_IPHONE_SIMULATOR - UIAlertView *alert = [[[UIAlertView alloc] initWithTitle:BITHockeyLocalizedString(@"UpdateWarning") message:BITHockeyLocalizedString(@"UpdateSimulatorMessage") delegate:nil cancelButtonTitle:BITHockeyLocalizedString(@"HockeyOK") otherButtonTitles:nil] autorelease]; + UIAlertView *alert = [[UIAlertView alloc] initWithTitle:BITHockeyLocalizedString(@"UpdateWarning") message:BITHockeyLocalizedString(@"UpdateSimulatorMessage") delegate:nil cancelButtonTitle:BITHockeyLocalizedString(@"HockeyOK") otherButtonTitles:nil]; [alert show]; return NO; #endif @@ -811,7 +793,7 @@ - (void)connectionDidFinishLoading:(NSURLConnection *)connection { self.checkInProgress = NO; if ([self.receivedData length]) { - NSString *responseString = [[[NSString alloc] initWithBytes:[_receivedData bytes] length:[_receivedData length] encoding: NSUTF8StringEncoding] autorelease]; + NSString *responseString = [[NSString alloc] initWithBytes:[_receivedData bytes] length:[_receivedData length] encoding: NSUTF8StringEncoding]; BITHockeyLog(@"INFO: Received API response: %@", responseString); NSError *error = nil; @@ -837,7 +819,7 @@ - (void)connectionDidFinishLoading:(NSURLConnection *)connection { } - NSString *currentAppCacheVersion = [[[self newestAppVersion].version copy] autorelease]; + NSString *currentAppCacheVersion = [[self newestAppVersion].version copy]; // clear cache and reload with new data NSMutableArray *tmpAppVersions = [NSMutableArray arrayWithCapacity:[feedArray count]]; @@ -853,7 +835,7 @@ - (void)connectionDidFinishLoading:(NSURLConnection *)connection { } // only set if different! if (![self.appVersions isEqualToArray:tmpAppVersions]) { - self.appVersions = [[tmpAppVersions copy] autorelease]; + self.appVersions = [tmpAppVersions copy]; } [self saveAppCache]; @@ -875,7 +857,6 @@ - (void)connectionDidFinishLoading:(NSURLConnection *)connection { cancelButtonTitle:BITHockeyLocalizedString(@"HockeyOK") otherButtonTitles:nil]; [alert show]; - [alert release]; } if (self.isUpdateAvailable && (self.alwaysShowUpdateReminder || newVersionDiffersFromCachedVersion || [self hasNewerMandatoryVersion])) { @@ -913,8 +894,7 @@ - (BOOL)hasNewerMandatoryVersion { - (void)setCurrentHockeyViewController:(BITUpdateViewController *)aCurrentHockeyViewController { if (_currentHockeyViewController != aCurrentHockeyViewController) { - [_currentHockeyViewController release]; - _currentHockeyViewController = [aCurrentHockeyViewController retain]; + _currentHockeyViewController = aCurrentHockeyViewController; //HockeySDKLog(@"active hockey view controller: %@", aCurrentHockeyViewController); } } @@ -925,7 +905,6 @@ - (NSString *)currentAppVersion { - (void)setLastCheck:(NSDate *)aLastCheck { if (_lastCheck != aLastCheck) { - [_lastCheck release]; _lastCheck = [aLastCheck copy]; [[NSUserDefaults standardUserDefaults] setObject:_lastCheck forKey:kBITUpdateDateOfLastCheck]; @@ -935,16 +914,15 @@ - (void)setLastCheck:(NSDate *)aLastCheck { - (void)setAppVersions:(NSArray *)anAppVersions { if (_appVersions != anAppVersions || !_appVersions) { - [_appVersions release]; [self willChangeValueForKey:@"appVersions"]; // populate with default values (if empty) if (![anAppVersions count]) { - BITAppVersionMetaInfo *defaultApp = [[[BITAppVersionMetaInfo alloc] init] autorelease]; + BITAppVersionMetaInfo *defaultApp = [[BITAppVersionMetaInfo alloc] init]; defaultApp.name = bit_appName(BITHockeyLocalizedString(@"HockeyAppNamePlaceholder")); defaultApp.version = _currentAppVersion; defaultApp.shortVersion = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleShortVersionString"]; - _appVersions = [[NSArray arrayWithObject:defaultApp] retain]; + _appVersions = [NSArray arrayWithObject:defaultApp]; } else { _appVersions = [anAppVersions copy]; } @@ -960,8 +938,7 @@ - (BITAppVersionMetaInfo *)newestAppVersion { - (void)setBlockingView:(UIView *)anBlockingView { if (_blockingView != anBlockingView) { [_blockingView removeFromSuperview]; - [_blockingView release]; - _blockingView = [anBlockingView retain]; + _blockingView = anBlockingView; } } diff --git a/Classes/BITUpdateManagerPrivate.h b/Classes/BITUpdateManagerPrivate.h index 67abbe92..a18dd685 100644 --- a/Classes/BITUpdateManagerPrivate.h +++ b/Classes/BITUpdateManagerPrivate.h @@ -41,25 +41,25 @@ // are we currently checking for updates? @property (nonatomic, assign, getter=isCheckInProgress) BOOL checkInProgress; -@property (nonatomic, retain) NSMutableData *receivedData; +@property (nonatomic, strong) NSMutableData *receivedData; @property (nonatomic, copy) NSDate *lastCheck; // get array of all available versions @property (nonatomic, copy) NSArray *appVersions; -@property (nonatomic, retain) NSURLConnection *urlConnection; +@property (nonatomic, strong) NSURLConnection *urlConnection; @property (nonatomic, copy) NSDate *usageStartTimestamp; -@property (nonatomic, retain) UIView *blockingView; +@property (nonatomic, strong) UIView *blockingView; // if YES, the API will return an existing JMC config // if NO, the API will return only version information @property (nonatomic, assign) BOOL checkForTracker; // Contains the tracker config if received from server -@property (nonatomic, retain) NSDictionary *trackerConfig; +@property (nonatomic, strong) NSDictionary *trackerConfig; // used by BITHockeyManager if disable status is changed @property (nonatomic, getter = isUpdateManagerDisabled) BOOL disableUpdateManager; @@ -77,7 +77,7 @@ - (void)checkForAuthorization; // get/set current active hockey view controller -@property (nonatomic, retain) BITUpdateViewController *currentHockeyViewController; +@property (nonatomic, strong) BITUpdateViewController *currentHockeyViewController; // convenience method to get current running version string - (NSString *)currentAppVersion; diff --git a/Classes/BITUpdateViewController.m b/Classes/BITUpdateViewController.m index fc426f18..5f2aa05d 100644 --- a/Classes/BITUpdateViewController.m +++ b/Classes/BITUpdateViewController.m @@ -153,15 +153,15 @@ - (void)showHidePreviousVersionsButton { UIView *footerView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, self.view.frame.size.width, kMinPreviousVersionButtonHeight)]; footerView.autoresizingMask = UIViewAutoresizingFlexibleWidth; footerView.backgroundColor = BIT_RGBCOLOR(245, 245, 245); - UIView *lineView1 = [[[UIView alloc] initWithFrame:CGRectMake(0, 0, self.view.frame.size.width, 1)] autorelease]; + UIView *lineView1 = [[UIView alloc] initWithFrame:CGRectMake(0, 0, self.view.frame.size.width, 1)]; lineView1.backgroundColor = BIT_RGBCOLOR(214, 214, 214); lineView1.autoresizingMask = UIViewAutoresizingFlexibleWidth; [footerView addSubview:lineView1]; - UIView *lineView2 = [[[UIView alloc] initWithFrame:CGRectMake(0, 1, self.view.frame.size.width, 1)] autorelease]; + UIView *lineView2 = [[UIView alloc] initWithFrame:CGRectMake(0, 1, self.view.frame.size.width, 1)]; lineView2.backgroundColor = BIT_RGBCOLOR(221, 221, 221); lineView2.autoresizingMask = UIViewAutoresizingFlexibleWidth; [footerView addSubview:lineView2]; - UIView *lineView3 = [[[UIView alloc] initWithFrame:CGRectMake(0, 1, self.view.frame.size.width, 1)] autorelease]; + UIView *lineView3 = [[UIView alloc] initWithFrame:CGRectMake(0, 1, self.view.frame.size.width, 1)]; lineView3.backgroundColor = BIT_RGBCOLOR(255, 255, 255); lineView3.autoresizingMask = UIViewAutoresizingFlexibleWidth; [footerView addSubview:lineView3]; @@ -181,7 +181,6 @@ - (void)showHidePreviousVersionsButton { [footerView addSubview:footerButton]; self.tableView.tableFooterView = footerView; [self realignPreviousVersionButton]; - [footerView release]; } else { self.tableView.tableFooterView = nil; self.tableView.backgroundColor = BIT_RGBCOLOR(235, 235, 235); @@ -241,8 +240,6 @@ - (id)init { } - (void)dealloc { - [_appStoreHeader release]; _appStoreHeader = nil; - [_popOverController release], _popOverController = nil; [[NSNotificationCenter defaultCenter] removeObserver:self]; // test if KVO's are registered. if class is destroyed before it was shown(viewDidLoad) no KVOs are registered. @@ -257,9 +254,7 @@ - (void)dealloc { for (UITableViewCell *cell in _cells) { [cell removeObserver:self forKeyPath:@"webViewSize"]; } - [_cells release]; - [super dealloc]; } @@ -282,7 +277,7 @@ - (void)viewDidLoad { self.tableView.backgroundColor = BIT_RGBCOLOR(245, 245, 245); 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)]; topView.autoresizingMask = UIViewAutoresizingFlexibleWidth; topView.backgroundColor = BIT_RGBCOLOR(245, 245, 245); [self.tableView addSubview:topView]; @@ -342,13 +337,13 @@ - (void)viewDidLoad { self.tableView.tableHeaderView = _appStoreHeader; - BITStoreButton *storeButton = [[[BITStoreButton alloc] initWithPadding:CGPointMake(5, 58)] autorelease]; + BITStoreButton *storeButton = [[BITStoreButton alloc] initWithPadding:CGPointMake(5, 58)]; storeButton.autoresizingMask = UIViewAutoresizingFlexibleLeftMargin; storeButton.buttonDelegate = self; [self.tableView.tableHeaderView addSubview:storeButton]; storeButton.buttonData = [BITStoreButtonData dataWithLabel:@"" enabled:NO]; [storeButton alignToSuperview]; - _appStoreButton = [storeButton retain]; + _appStoreButton = storeButton; self.appStoreButtonState = AppStoreButtonStateCheck; } @@ -396,7 +391,7 @@ - (void)redrawTableView { } } - BITWebTableViewCell *cell = [[[BITWebTableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:kWebCellIdentifier] autorelease]; + BITWebTableViewCell *cell = [[BITWebTableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:kWebCellIdentifier]; [self configureWebCell:cell forAppVersion:appVersion]; [_cells addObject:cell]; @@ -423,7 +418,7 @@ - (void)showPreviousVersionAction { } } - BITWebTableViewCell *cell = [[[BITWebTableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:kWebCellIdentifier] autorelease]; + BITWebTableViewCell *cell = [[BITWebTableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:kWebCellIdentifier]; [self configureWebCell:cell forAppVersion:appVersion]; [_cells addObject:cell]; } diff --git a/Classes/BITUpdateViewControllerPrivate.h b/Classes/BITUpdateViewControllerPrivate.h index 905bf07c..cf6ecb0e 100644 --- a/Classes/BITUpdateViewControllerPrivate.h +++ b/Classes/BITUpdateViewControllerPrivate.h @@ -47,7 +47,7 @@ typedef enum { @interface BITUpdateViewController() { } -@property (nonatomic, assign) BITUpdateManager *updateManager; +@property (nonatomic, weak) BITUpdateManager *updateManager; @property (nonatomic, readwrite) BOOL modal; @property (nonatomic, assign) AppStoreButtonState appStoreButtonState; diff --git a/Classes/BITWebTableViewCell.h b/Classes/BITWebTableViewCell.h index d951ebcc..f2bcf0e1 100644 --- a/Classes/BITWebTableViewCell.h +++ b/Classes/BITWebTableViewCell.h @@ -34,10 +34,10 @@ @interface BITWebTableViewCell : UITableViewCell -@property (nonatomic, retain) UIWebView *webView; +@property (nonatomic, strong) UIWebView *webView; @property (nonatomic, copy) NSString *webViewContent; @property (nonatomic, assign) CGSize webViewSize; -@property (nonatomic, retain) UIColor *cellBackgroundColor; +@property (nonatomic, strong) UIColor *cellBackgroundColor; - (void)addWebView; diff --git a/Classes/BITWebTableViewCell.m b/Classes/BITWebTableViewCell.m index 6877f1a2..f6adf07b 100644 --- a/Classes/BITWebTableViewCell.m +++ b/Classes/BITWebTableViewCell.m @@ -54,7 +54,7 @@ - (void)addWebView { if(_webViewContent) { CGRect webViewRect = CGRectMake(0, 0, self.frame.size.width, self.frame.size.height); if(!_webView) { - _webView = [[[UIWebView alloc] initWithFrame:webViewRect] retain]; + _webView = [[UIWebView alloc] initWithFrame:webViewRect]; [self addSubview:_webView]; _webView.hidden = YES; _webView.backgroundColor = self.cellBackgroundColor; @@ -100,7 +100,6 @@ - (void)removeWebView { _webView.delegate = nil; [_webView resignFirstResponder]; [_webView removeFromSuperview]; - [_webView release]; } _webView = nil; [self setNeedsDisplay]; @@ -109,8 +108,7 @@ - (void)removeWebView { - (void)setWebViewContent:(NSString *)aWebViewContent { if (_webViewContent != aWebViewContent) { - [_webViewContent release]; - _webViewContent = [aWebViewContent retain]; + _webViewContent = aWebViewContent; // add basic accessiblity (prevents "snarfed from ivar layout") logs self.accessibilityLabel = aWebViewContent; @@ -129,8 +127,6 @@ - (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reus - (void)dealloc { [self removeWebView]; - [_webViewContent release], _webViewContent = nil;; - [super dealloc]; } diff --git a/Classes/HockeySDKPrivate.m b/Classes/HockeySDKPrivate.m index fa879de6..2bcbf8ed 100644 --- a/Classes/HockeySDKPrivate.m +++ b/Classes/HockeySDKPrivate.m @@ -39,7 +39,7 @@ dispatch_once(&predicate, ^{ NSString* mainBundlePath = [[NSBundle mainBundle] resourcePath]; NSString* frameworkBundlePath = [mainBundlePath stringByAppendingPathComponent:BITHOCKEYSDK_BUNDLE]; - bundle = [[NSBundle bundleWithPath:frameworkBundlePath] retain]; + bundle = [NSBundle bundleWithPath:frameworkBundlePath]; }); return bundle; } diff --git a/Support/HockeySDK.xcodeproj/project.pbxproj b/Support/HockeySDK.xcodeproj/project.pbxproj index 89d4f589..d9c37f00 100644 --- a/Support/HockeySDK.xcodeproj/project.pbxproj +++ b/Support/HockeySDK.xcodeproj/project.pbxproj @@ -93,7 +93,7 @@ 1E754E601621FBB70070AB92 /* BITCrashReportTextFormatter.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E754E5A1621FBB70070AB92 /* BITCrashReportTextFormatter.h */; }; 1E754E611621FBB70070AB92 /* BITCrashReportTextFormatter.m in Sources */ = {isa = PBXBuildFile; fileRef = 1E754E5B1621FBB70070AB92 /* BITCrashReportTextFormatter.m */; }; 1EACC97B162F041E007578C5 /* BITAttributedLabel.h in Headers */ = {isa = PBXBuildFile; fileRef = 1EACC979162F041E007578C5 /* BITAttributedLabel.h */; }; - 1EACC97C162F041E007578C5 /* BITAttributedLabel.m in Sources */ = {isa = PBXBuildFile; fileRef = 1EACC97A162F041E007578C5 /* BITAttributedLabel.m */; settings = {COMPILER_FLAGS = "-fobjc-arc"; }; }; + 1EACC97C162F041E007578C5 /* BITAttributedLabel.m in Sources */ = {isa = PBXBuildFile; fileRef = 1EACC97A162F041E007578C5 /* BITAttributedLabel.m */; }; 1EAF20A8162DC0F600957B1D /* feedbackActivity@2x~ipad.png in Resources */ = {isa = PBXBuildFile; fileRef = 1EAF20A4162DC0F600957B1D /* feedbackActivity@2x~ipad.png */; }; 1EAF20A9162DC0F600957B1D /* feedbackActivity~ipad.png in Resources */ = {isa = PBXBuildFile; fileRef = 1EAF20A5162DC0F600957B1D /* feedbackActivity~ipad.png */; }; 1EAF20AA162DC0F600957B1D /* feedbackActiviy.png in Resources */ = {isa = PBXBuildFile; fileRef = 1EAF20A6162DC0F600957B1D /* feedbackActiviy.png */; }; @@ -749,6 +749,7 @@ buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; ARCHS = "$(ARCHS_STANDARD_32_BIT)"; + CLANG_ENABLE_OBJC_ARC = YES; COPY_PHASE_STRIP = NO; DEAD_CODE_STRIPPING = NO; GCC_C_LANGUAGE_STANDARD = gnu99; @@ -768,7 +769,7 @@ GCC_WARN_UNDECLARED_SELECTOR = YES; GCC_WARN_UNUSED_VARIABLE = YES; INFOPLIST_FILE = "../Resources/HockeySDK-Info.plist"; - IPHONEOS_DEPLOYMENT_TARGET = 4.0; + IPHONEOS_DEPLOYMENT_TARGET = 5.0; MACOSX_DEPLOYMENT_TARGET = 10.5; RUN_CLANG_STATIC_ANALYZER = YES; SDKROOT = iphoneos; @@ -782,6 +783,7 @@ buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; ARCHS = "$(ARCHS_STANDARD_32_BIT)"; + CLANG_ENABLE_OBJC_ARC = YES; COPY_PHASE_STRIP = NO; DEAD_CODE_STRIPPING = NO; GCC_C_LANGUAGE_STANDARD = gnu99; @@ -797,7 +799,7 @@ GCC_WARN_UNDECLARED_SELECTOR = YES; GCC_WARN_UNUSED_VARIABLE = YES; INFOPLIST_FILE = "../Resources/HockeySDK-Info.plist"; - IPHONEOS_DEPLOYMENT_TARGET = 4.0; + IPHONEOS_DEPLOYMENT_TARGET = 5.0; MACOSX_DEPLOYMENT_TARGET = 10.5; RUN_CLANG_STATIC_ANALYZER = YES; SDKROOT = iphoneos; From 54b17917f6d7ecd4aa933c198350eb6abef62962 Mon Sep 17 00:00:00 2001 From: Andreas Linde Date: Tue, 23 Oct 2012 18:37:19 +0200 Subject: [PATCH 091/176] Fix public headers being copied into the apps archive when using as a subproject --- Support/HockeySDK.xcodeproj/project.pbxproj | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Support/HockeySDK.xcodeproj/project.pbxproj b/Support/HockeySDK.xcodeproj/project.pbxproj index d9c37f00..4cc24f4d 100644 --- a/Support/HockeySDK.xcodeproj/project.pbxproj +++ b/Support/HockeySDK.xcodeproj/project.pbxproj @@ -682,6 +682,7 @@ ); GCC_THUMB_SUPPORT = NO; PRODUCT_NAME = HockeySDK; + PUBLIC_HEADERS_FOLDER_PATH = "include/$(PRODUCT_NAME)"; SKIP_INSTALL = YES; }; name = Debug; @@ -700,6 +701,7 @@ ); GCC_THUMB_SUPPORT = NO; PRODUCT_NAME = HockeySDK; + PUBLIC_HEADERS_FOLDER_PATH = "include/$(PRODUCT_NAME)"; SKIP_INSTALL = YES; }; name = Release; @@ -773,7 +775,6 @@ MACOSX_DEPLOYMENT_TARGET = 10.5; RUN_CLANG_STATIC_ANALYZER = YES; SDKROOT = iphoneos; - STRIP_STYLE = "non-global"; }; name = Debug; }; @@ -803,7 +804,6 @@ MACOSX_DEPLOYMENT_TARGET = 10.5; RUN_CLANG_STATIC_ANALYZER = YES; SDKROOT = iphoneos; - STRIP_STYLE = "non-global"; VALIDATE_PRODUCT = NO; }; name = Release; From d8f61f363a18a35cd83c70b50fb2c188f46beff3 Mon Sep 17 00:00:00 2001 From: Andreas Linde Date: Thu, 25 Oct 2012 22:19:06 +0200 Subject: [PATCH 092/176] Remove option to change version update compare style --- Classes/BITUpdateManager.h | 25 ------------------------- Classes/BITUpdateManager.m | 7 +------ 2 files changed, 1 insertion(+), 31 deletions(-) diff --git a/Classes/BITUpdateManager.h b/Classes/BITUpdateManager.h index e15c4a84..b9ccb4c4 100644 --- a/Classes/BITUpdateManager.h +++ b/Classes/BITUpdateManager.h @@ -33,11 +33,6 @@ #import "BITHockeyBaseManager.h" -typedef enum { - BITUpdateComparisonResultDifferent, - BITUpdateComparisonResultGreater -} BITUpdateComparisonResult; - typedef enum { BITUpdateAuthorizationDenied, BITUpdateAuthorizationAllowed, @@ -99,26 +94,6 @@ typedef enum { @property (nonatomic, weak) id delegate; -///----------------------------------------------------------------------------- -/// @name Configuration -///----------------------------------------------------------------------------- - -/** - The type of version comparisson. - - Defines when a version is defined as being newer than the currently installed - version. This must be assigned one of the following: - - When running the app from the App Store, this setting is ignored. - - - `BITUpdateComparisonResultDifferent`: Version is different - - `BITUpdateComparisonResultGreater`: Version is greater - - **Default**: BITUpdateComparisonResultGreater - */ -@property (nonatomic, assign) BITUpdateComparisonResult compareVersionType; - - ///----------------------------------------------------------------------------- /// @name Update Checking ///----------------------------------------------------------------------------- diff --git a/Classes/BITUpdateManager.m b/Classes/BITUpdateManager.m index c4d9c83d..7889b7c4 100644 --- a/Classes/BITUpdateManager.m +++ b/Classes/BITUpdateManager.m @@ -252,11 +252,7 @@ - (BITUpdateAuthorizationState)authorizationState { - (void)checkUpdateAvailable { // check if there is an update available - if (self.compareVersionType == BITUpdateComparisonResultGreater) { - self.updateAvailable = (bit_versionCompare(self.newestAppVersion.version, self.currentAppVersion) == NSOrderedDescending); - } else { - self.updateAvailable = ([self.newestAppVersion.version compare:self.currentAppVersion] != NSOrderedSame); - } + self.updateAvailable = (bit_versionCompare(self.newestAppVersion.version, self.currentAppVersion) == NSOrderedDescending); } - (void)loadAppCache { @@ -328,7 +324,6 @@ - (id)init { self.showDirectInstallOption = NO; self.alwaysShowUpdateReminder = YES; self.checkForUpdateOnLaunch = YES; - self.compareVersionType = BITUpdateComparisonResultGreater; self.updateSetting = BITUpdateCheckStartup; if ([[NSUserDefaults standardUserDefaults] objectForKey:kBITUpdateDateOfLastCheck]) { From 90f4b017af00a68954e128297c44fa8dea9bd5d0 Mon Sep 17 00:00:00 2001 From: Andreas Linde Date: Tue, 30 Oct 2012 17:42:23 +0100 Subject: [PATCH 093/176] Update Update view presentation --- Classes/BITAppStoreHeader.h | 1 - Classes/BITAppStoreHeader.m | 44 +++++++++++++++++-------------- Classes/BITUpdateManager.m | 20 +++++--------- Classes/BITUpdateManagerPrivate.h | 2 ++ Classes/BITUpdateViewController.m | 15 +---------- Classes/HockeySDKPrivate.h | 15 ++++++----- 6 files changed, 42 insertions(+), 55 deletions(-) diff --git a/Classes/BITAppStoreHeader.h b/Classes/BITAppStoreHeader.h index 3f3e2e84..5b5f8873 100644 --- a/Classes/BITAppStoreHeader.h +++ b/Classes/BITAppStoreHeader.h @@ -34,7 +34,6 @@ @interface BITAppStoreHeader : UIView @property (nonatomic, copy) NSString *headerLabel; -@property (nonatomic, copy) NSString *middleHeaderLabel; @property (nonatomic, copy) NSString *subHeaderLabel; @property (nonatomic, strong) UIImage *iconImage; diff --git a/Classes/BITAppStoreHeader.m b/Classes/BITAppStoreHeader.m index 5716e65d..40eea590 100644 --- a/Classes/BITAppStoreHeader.m +++ b/Classes/BITAppStoreHeader.m @@ -61,7 +61,6 @@ - (id)initWithFrame:(CGRect)frame { - (void)drawRect:(CGRect)rect { CGRect bounds = self.bounds; - CGFloat globalWidth = self.frame.size.width; CGContextRef context = UIGraphicsGetCurrentContext(); // draw the gradient @@ -72,26 +71,38 @@ - (void)drawRect:(CGRect)rect { CGContextDrawLinearGradient(context, gradient, top, bottom, 0); CGGradientRelease(gradient); + // icon + [_iconImage drawAtPoint:CGPointMake(kImageLeftMargin, kImageTopMargin)]; +} + + +- (void)layoutSubviews { + [super layoutSubviews]; + + CGFloat globalWidth = self.frame.size.width; + // draw header name UIColor *mainTextColor = BIT_RGBCOLOR(61, 61, 61); UIColor *secondaryTextColor = BIT_RGBCOLOR(100, 100, 100); UIFont *mainFont = [UIFont boldSystemFontOfSize:15]; UIFont *secondaryFont = [UIFont systemFontOfSize:10]; - // icon - [_iconImage drawAtPoint:CGPointMake(kImageLeftMargin, kImageTopMargin)]; - - [mainTextColor set]; - [_headerLabel drawInRect:CGRectMake(kTextRow, kImageTopMargin, globalWidth-kTextRow, 20) withFont:mainFont lineBreakMode:UILineBreakModeTailTruncation]; + UILabel *headerLabelView = [[UILabel alloc] init]; + [headerLabelView setFont:mainFont]; + [headerLabelView setFrame:CGRectMake(kTextRow, kImageTopMargin, globalWidth-kTextRow, 20)]; + [headerLabelView setTextColor:mainTextColor]; + [headerLabelView setBackgroundColor:[UIColor clearColor]]; + [headerLabelView setText:_headerLabel]; + [self addSubview:headerLabelView]; // middle - [secondaryTextColor set]; - [_middleHeaderLabel drawInRect:CGRectMake(kTextRow, kImageTopMargin + 17, globalWidth-kTextRow, 20) withFont:secondaryFont lineBreakMode:UILineBreakModeTailTruncation]; -// CGContextSetShadowWithColor(context, CGSizeZero, 0, nil); - - // sub - [secondaryTextColor set]; - [_subHeaderLabel drawAtPoint:CGPointMake(kTextRow, kImageTopMargin + 29) forWidth:globalWidth-kTextRow withFont:secondaryFont lineBreakMode:UILineBreakModeTailTruncation]; + UILabel *middleLabelView = [[UILabel alloc] init]; + [middleLabelView setFont:secondaryFont]; + [middleLabelView setFrame:CGRectMake(kTextRow, kImageTopMargin + 17, globalWidth-kTextRow, 20)]; + [middleLabelView setTextColor:secondaryTextColor]; + [middleLabelView setBackgroundColor:[UIColor clearColor]]; + [middleLabelView setText:_subHeaderLabel]; + [self addSubview:middleLabelView]; } @@ -104,13 +115,6 @@ - (void)setHeaderLabel:(NSString *)anHeaderLabel { } } -- (void)setMiddleHeaderLabel:(NSString *)aMiddleHeaderLabel { - if (_middleHeaderLabel != aMiddleHeaderLabel) { - _middleHeaderLabel = [aMiddleHeaderLabel copy]; - [self setNeedsDisplay]; - } -} - - (void)setSubHeaderLabel:(NSString *)aSubHeaderLabel { if (_subHeaderLabel != aSubHeaderLabel) { _subHeaderLabel = [aSubHeaderLabel copy]; diff --git a/Classes/BITUpdateManager.m b/Classes/BITUpdateManager.m index 7889b7c4..2efad549 100644 --- a/Classes/BITUpdateManager.m +++ b/Classes/BITUpdateManager.m @@ -40,18 +40,6 @@ #import "BITAppVersionMetaInfo.h" - -// API defines - do not change -#define BETA_DOWNLOAD_TYPE_PROFILE @"profile" -#define BETA_UPDATE_RESULT @"result" -#define BETA_UPDATE_TITLE @"title" -#define BETA_UPDATE_SUBTITLE @"subtitle" -#define BETA_UPDATE_NOTES @"notes" -#define BETA_UPDATE_VERSION @"version" -#define BETA_UPDATE_TIMESTAMP @"timestamp" -#define BETA_UPDATE_APPSIZE @"appsize" - - @implementation BITUpdateManager { NSString *_currentAppVersion; @@ -256,6 +244,8 @@ - (void)checkUpdateAvailable { } - (void)loadAppCache { + _companyName = [[NSUserDefaults standardUserDefaults] objectForKey:kBITUpdateCurrentCompanyName]; + NSData *savedHockeyData = [[NSUserDefaults standardUserDefaults] objectForKey:kBITUpdateArrayOfLastCheck]; NSArray *savedHockeyCheck = nil; if (savedHockeyData) { @@ -270,6 +260,8 @@ - (void)loadAppCache { } - (void)saveAppCache { + if (_companyName) + [[NSUserDefaults standardUserDefaults] setObject:_companyName forKey:kBITUpdateCurrentCompanyName]; NSData *data = [NSKeyedArchiver archivedDataWithRootObject:self.appVersions]; [[NSUserDefaults standardUserDefaults] setObject:data forKey:kBITUpdateArrayOfLastCheck]; [[NSUserDefaults standardUserDefaults] synchronize]; @@ -319,6 +311,7 @@ - (id)init { _disableUpdateManager = NO; _checkForTracker = NO; _didSetupDidBecomeActiveNotifications = NO; + _companyName = nil; // set defaults self.showDirectInstallOption = NO; @@ -610,7 +603,7 @@ - (void)checkForUpdateShowFeedback:(BOOL)feedback { return; } - NSMutableString *parameter = [NSMutableString stringWithFormat:@"api/2/apps/%@?format=json&udid=%@&sdk=%@&sdk_version=%@&uuid=%@", + NSMutableString *parameter = [NSMutableString stringWithFormat:@"api/2/apps/%@?format=json&extended=true&udid=%@&sdk=%@&sdk_version=%@&uuid=%@", bit_URLEncodedString([self encodedAppIdentifier]), ([self isAppStoreEnvironment] ? @"appstore" : bit_URLEncodedString([self deviceIdentifier])), BITHOCKEY_NAME, @@ -795,6 +788,7 @@ - (void)connectionDidFinishLoading:(NSURLConnection *)connection { NSDictionary *json = (NSDictionary *)[NSJSONSerialization JSONObjectWithData:[responseString dataUsingEncoding:NSUTF8StringEncoding] options:kNilOptions error:&error]; self.trackerConfig = (([self checkForTracker] && [[json valueForKey:@"tracker"] isKindOfClass:[NSDictionary class]]) ? [json valueForKey:@"tracker"] : nil); + self.companyName = (([[json valueForKey:@"company"] isKindOfClass:[NSString class]]) ? [json valueForKey:@"company"] : nil); if (![self isAppStoreEnvironment]) { NSArray *feedArray = (NSArray *)([self checkForTracker] ? [json valueForKey:@"versions"] : json); diff --git a/Classes/BITUpdateManagerPrivate.h b/Classes/BITUpdateManagerPrivate.h index a18dd685..65f8ffa3 100644 --- a/Classes/BITUpdateManagerPrivate.h +++ b/Classes/BITUpdateManagerPrivate.h @@ -54,6 +54,8 @@ @property (nonatomic, strong) UIView *blockingView; +@property (nonatomic, strong) NSString *companyName; + // if YES, the API will return an existing JMC config // if NO, the API will return only version information @property (nonatomic, assign) BOOL checkForTracker; diff --git a/Classes/BITUpdateViewController.m b/Classes/BITUpdateViewController.m index 5f2aa05d..aa783d93 100644 --- a/Classes/BITUpdateViewController.m +++ b/Classes/BITUpdateViewController.m @@ -76,20 +76,7 @@ - (void)restoreStoreButtonStateAnimated:(BOOL)animated { - (void)updateAppStoreHeader { BITAppVersionMetaInfo *appVersion = _updateManager.newestAppVersion; _appStoreHeader.headerLabel = appVersion.name; -// _appStoreHeader.middleHeaderLabel = appVersion versionString]; -// NSDateFormatter *formatter = [[[NSDateFormatter alloc] init] autorelease]; -// [formatter setDateStyle:NSDateFormatterMediumStyle]; -// NSMutableString *subHeaderString = [NSMutableString string]; -// if (appVersion.date) { -// [subHeaderString appendString:[formatter stringFromDate:appVersion.date]]; -// } -// if (appVersion.size) { -// if ([subHeaderString length]) { -// [subHeaderString appendString:@" - "]; -// } -// [subHeaderString appendString:appVersion.sizeInMB]; -// } -// _appStoreHeader.subHeaderLabel = subHeaderString; + _appStoreHeader.subHeaderLabel = _updateManager.companyName; } - (void)appDidBecomeActive { diff --git a/Classes/HockeySDKPrivate.h b/Classes/HockeySDKPrivate.h index 3b426027..f17574c8 100644 --- a/Classes/HockeySDKPrivate.h +++ b/Classes/HockeySDKPrivate.h @@ -41,13 +41,14 @@ #define BITHOCKEY_FEEDBACK_SETTINGS @"BITFeedbackManager.plist" -#define kBITUpdateArrayOfLastCheck @"BITUpdateArrayOfLastCheck" -#define kBITUpdateDateOfLastCheck @"BITUpdateDateOfLastCheck" -#define kBITUpdateDateOfVersionInstallation @"BITUpdateDateOfVersionInstallation" -#define kBITUpdateUsageTimeOfCurrentVersion @"BITUpdateUsageTimeOfCurrentVersion" -#define kBITUpdateUsageTimeForVersionString @"BITUpdateUsageTimeForVersionString" -#define kBITUpdateAuthorizedVersion @"BITUpdateAuthorizedVersion" -#define kBITUpdateAuthorizedToken @"BITUpdateAuthorizedToken" +#define kBITUpdateCurrentCompanyName @"BITUpdateCurrentCompanyName" +#define kBITUpdateArrayOfLastCheck @"BITUpdateArrayOfLastCheck" +#define kBITUpdateDateOfLastCheck @"BITUpdateDateOfLastCheck" +#define kBITUpdateDateOfVersionInstallation @"BITUpdateDateOfVersionInstallation" +#define kBITUpdateUsageTimeOfCurrentVersion @"BITUpdateUsageTimeOfCurrentVersion" +#define kBITUpdateUsageTimeForVersionString @"BITUpdateUsageTimeForVersionString" +#define kBITUpdateAuthorizedVersion @"BITUpdateAuthorizedVersion" +#define kBITUpdateAuthorizedToken @"BITUpdateAuthorizedToken" #define BITHOCKEYSDK_BUNDLE @"HockeySDKResources.bundle" #define BITHOCKEYSDK_URL @"https://sdk.hockeyapp.net/" From 7e94d45acb5dd34bae771906baf8060be0e199ea Mon Sep 17 00:00:00 2001 From: Andreas Linde Date: Tue, 30 Oct 2012 20:10:41 +0100 Subject: [PATCH 094/176] Add support for in-app-updates without changing the version string --- Classes/BITAppVersionMetaInfo.h | 3 ++ Classes/BITAppVersionMetaInfo.m | 31 ++++++++++++---- Classes/BITUpdateManager.m | 66 ++++++++++++++++++++++++++++++--- Classes/HockeySDKPrivate.h | 4 +- 4 files changed, 90 insertions(+), 14 deletions(-) diff --git a/Classes/BITAppVersionMetaInfo.h b/Classes/BITAppVersionMetaInfo.h index f47897a8..7c1db67f 100644 --- a/Classes/BITAppVersionMetaInfo.h +++ b/Classes/BITAppVersionMetaInfo.h @@ -38,6 +38,8 @@ @property (nonatomic, copy) NSDate *date; @property (nonatomic, copy) NSNumber *size; @property (nonatomic, copy) NSNumber *mandatory; +@property (nonatomic, copy) NSNumber *versionID; +@property (nonatomic, copy) NSDictionary *uuids; - (NSString *)nameAndVersionString; - (NSString *)versionString; @@ -46,6 +48,7 @@ - (NSString *)notesOrEmptyString; - (void)setDateWithTimestamp:(NSTimeInterval)timestamp; - (BOOL)isValid; +- (BOOL)hasUUID:(NSString *)uuid; - (BOOL)isEqualToAppVersionMetaInfo:(BITAppVersionMetaInfo *)anAppVersionMetaInfo; + (BITAppVersionMetaInfo *)appVersionMetaInfoFromDict:(NSDictionary *)dict; diff --git a/Classes/BITAppVersionMetaInfo.m b/Classes/BITAppVersionMetaInfo.m index 22e4645d..7b1394fd 100644 --- a/Classes/BITAppVersionMetaInfo.m +++ b/Classes/BITAppVersionMetaInfo.m @@ -33,14 +33,6 @@ @implementation BITAppVersionMetaInfo -@synthesize name = _name; -@synthesize version = _version; -@synthesize shortVersion = _shortVersion; -@synthesize notes = _notes; -@synthesize date = _date; -@synthesize size = _size; -@synthesize mandatory = _mandatory; - #pragma mark - Static @@ -55,6 +47,8 @@ + (BITAppVersionMetaInfo *)appVersionMetaInfoFromDict:(NSDictionary *)dict { appVersionMetaInfo.size = [dict objectForKey:@"appsize"]; appVersionMetaInfo.notes = [dict objectForKey:@"notes"]; appVersionMetaInfo.mandatory = [dict objectForKey:@"mandatory"]; + appVersionMetaInfo.versionID = [dict objectForKey:@"id"]; + appVersionMetaInfo.uuids = [dict objectForKey:@"uuids"]; } return appVersionMetaInfo; @@ -89,6 +83,8 @@ - (BOOL)isEqualToAppVersionMetaInfo:(BITAppVersionMetaInfo *)anAppVersionMetaInf return NO; if (self.mandatory != anAppVersionMetaInfo.mandatory && ![self.mandatory isEqualToNumber:anAppVersionMetaInfo.mandatory]) return NO; + if (![self.uuids isEqualToDictionary:anAppVersionMetaInfo.uuids]) + return NO; return YES; } @@ -103,6 +99,8 @@ - (void)encodeWithCoder:(NSCoder *)encoder { [encoder encodeObject:self.date forKey:@"date"]; [encoder encodeObject:self.size forKey:@"size"]; [encoder encodeObject:self.mandatory forKey:@"mandatory"]; + [encoder encodeObject:self.versionID forKey:@"versionID"]; + [encoder encodeObject:self.uuids forKey:@"uuids"]; } - (id)initWithCoder:(NSCoder *)decoder { @@ -114,6 +112,8 @@ - (id)initWithCoder:(NSCoder *)decoder { self.date = [decoder decodeObjectForKey:@"date"]; self.size = [decoder decodeObjectForKey:@"size"]; self.mandatory = [decoder decodeObjectForKey:@"mandatory"]; + self.versionID = [decoder decodeObjectForKey:@"versionID"]; + self.uuids = [decoder decodeObjectForKey:@"uuids"]; } return self; } @@ -172,4 +172,19 @@ - (BOOL)isValid { return valid; } +- (BOOL)hasUUID:(NSString *)uuid { + if (!uuid) return NO; + if (!self.uuids) return NO; + + __block BOOL hasUUID = NO; + + [self.uuids enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop){ + if (obj && [uuid compare:obj] == NSOrderedSame) { + hasUUID = YES; + *stop = YES; + } + }]; + + return hasUUID; +} @end diff --git a/Classes/BITUpdateManager.m b/Classes/BITUpdateManager.m index 2efad549..0926b510 100644 --- a/Classes/BITUpdateManager.m +++ b/Classes/BITUpdateManager.m @@ -52,7 +52,11 @@ @implementation BITUpdateManager { BOOL _sendUsageData; BOOL _didSetupDidBecomeActiveNotifications; + + BOOL _firstStartAfterInstall; + NSNumber *_versionID; + NSString *_versionUUID; NSString *_uuid; } @@ -146,17 +150,17 @@ - (void)startUsage { BOOL newVersion = NO; - if (![[NSUserDefaults standardUserDefaults] valueForKey:kBITUpdateUsageTimeForVersionString]) { + if (![[NSUserDefaults standardUserDefaults] valueForKey:kBITUpdateUsageTimeForUUID]) { newVersion = YES; } else { - if ([(NSString *)[[NSUserDefaults standardUserDefaults] valueForKey:kBITUpdateUsageTimeForVersionString] compare:[[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleVersion"]] != NSOrderedSame) { + if ([(NSString *)[[NSUserDefaults standardUserDefaults] valueForKey:kBITUpdateUsageTimeForUUID] compare:_uuid] != NSOrderedSame) { newVersion = YES; } } if (newVersion) { [[NSUserDefaults standardUserDefaults] setObject:[NSNumber numberWithDouble:[[NSDate date] timeIntervalSinceReferenceDate]] forKey:kBITUpdateDateOfVersionInstallation]; - [[NSUserDefaults standardUserDefaults] setObject:[[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleVersion"] forKey:kBITUpdateUsageTimeForVersionString]; + [[NSUserDefaults standardUserDefaults] setObject:_uuid forKey:kBITUpdateUsageTimeForUUID]; [[NSUserDefaults standardUserDefaults] setObject:[NSNumber numberWithDouble:0] forKey:kBITUpdateUsageTimeOfCurrentVersion]; [[NSUserDefaults standardUserDefaults] synchronize]; } @@ -240,10 +244,55 @@ - (BITUpdateAuthorizationState)authorizationState { - (void)checkUpdateAvailable { // check if there is an update available - self.updateAvailable = (bit_versionCompare(self.newestAppVersion.version, self.currentAppVersion) == NSOrderedDescending); + NSComparisonResult comparissonResult = bit_versionCompare(self.newestAppVersion.version, self.currentAppVersion); + + if (comparissonResult == NSOrderedDescending) { + self.updateAvailable = YES; + } else if (comparissonResult == NSOrderedSame) { + // compare using the binary UUID and stored version id + self.updateAvailable = NO; + if (_firstStartAfterInstall) { + if ([self.newestAppVersion hasUUID:_uuid]) { + _versionUUID = [_uuid copy]; + _versionID = [self.newestAppVersion.versionID copy]; + [self saveAppCache]; + } else { + [self.appVersions enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) { + if (idx > 0 && [obj isKindOfClass:[BITAppVersionMetaInfo class]]) { + NSComparisonResult compareVersions = bit_versionCompare([(BITAppVersionMetaInfo *)obj version], self.currentAppVersion); + BOOL uuidFound = [(BITAppVersionMetaInfo *)obj hasUUID:_uuid]; + + if (uuidFound) { + _versionUUID = [_uuid copy]; + _versionID = [[(BITAppVersionMetaInfo *)obj versionID] copy]; + [self saveAppCache]; + + self.updateAvailable = YES; + } + + if (compareVersions != NSOrderedSame || uuidFound) { + *stop = YES; + } + } + }]; + } + } else { + if ([self.newestAppVersion.versionID compare:_versionID] == NSOrderedDescending) + self.updateAvailable = YES; + } + } } - (void)loadAppCache { + _firstStartAfterInstall = NO; + _versionUUID = [[NSUserDefaults standardUserDefaults] objectForKey:kBITUpdateInstalledUUID]; + if (!_versionUUID) { + _firstStartAfterInstall = YES; + } else { + if ([_uuid compare:_versionUUID] != NSOrderedSame) + _firstStartAfterInstall = YES; + } + _versionID = [[NSUserDefaults standardUserDefaults] objectForKey:kBITUpdateInstalledVersionID]; _companyName = [[NSUserDefaults standardUserDefaults] objectForKey:kBITUpdateCurrentCompanyName]; NSData *savedHockeyData = [[NSUserDefaults standardUserDefaults] objectForKey:kBITUpdateArrayOfLastCheck]; @@ -262,6 +311,10 @@ - (void)loadAppCache { - (void)saveAppCache { if (_companyName) [[NSUserDefaults standardUserDefaults] setObject:_companyName forKey:kBITUpdateCurrentCompanyName]; + if (_versionUUID) + [[NSUserDefaults standardUserDefaults] setObject:_versionUUID forKey:kBITUpdateInstalledUUID]; + if (_versionID) + [[NSUserDefaults standardUserDefaults] setObject:_versionID forKey:kBITUpdateInstalledVersionID]; NSData *data = [NSKeyedArchiver archivedDataWithRootObject:self.appVersions]; [[NSUserDefaults standardUserDefaults] setObject:data forKey:kBITUpdateArrayOfLastCheck]; [[NSUserDefaults standardUserDefaults] synchronize]; @@ -307,10 +360,13 @@ - (id)init { _authenticationSecret = nil; _lastCheck = nil; _uuid = [[self executableUUID] copy]; + _versionUUID = nil; + _versionID = nil; _sendUsageData = YES; _disableUpdateManager = NO; _checkForTracker = NO; _didSetupDidBecomeActiveNotifications = NO; + _firstStartAfterInstall = NO; _companyName = nil; // set defaults @@ -791,7 +847,7 @@ - (void)connectionDidFinishLoading:(NSURLConnection *)connection { self.companyName = (([[json valueForKey:@"company"] isKindOfClass:[NSString class]]) ? [json valueForKey:@"company"] : nil); if (![self isAppStoreEnvironment]) { - NSArray *feedArray = (NSArray *)([self checkForTracker] ? [json valueForKey:@"versions"] : json); + NSArray *feedArray = (NSArray *)[json valueForKey:@"versions"]; self.receivedData = nil; self.urlConnection = nil; diff --git a/Classes/HockeySDKPrivate.h b/Classes/HockeySDKPrivate.h index f17574c8..346482d7 100644 --- a/Classes/HockeySDKPrivate.h +++ b/Classes/HockeySDKPrivate.h @@ -41,12 +41,14 @@ #define BITHOCKEY_FEEDBACK_SETTINGS @"BITFeedbackManager.plist" +#define kBITUpdateInstalledUUID @"BITUpdateInstalledUUID" +#define kBITUpdateInstalledVersionID @"BITUpdateInstalledVersionID" #define kBITUpdateCurrentCompanyName @"BITUpdateCurrentCompanyName" #define kBITUpdateArrayOfLastCheck @"BITUpdateArrayOfLastCheck" #define kBITUpdateDateOfLastCheck @"BITUpdateDateOfLastCheck" #define kBITUpdateDateOfVersionInstallation @"BITUpdateDateOfVersionInstallation" #define kBITUpdateUsageTimeOfCurrentVersion @"BITUpdateUsageTimeOfCurrentVersion" -#define kBITUpdateUsageTimeForVersionString @"BITUpdateUsageTimeForVersionString" +#define kBITUpdateUsageTimeForUUID @"BITUpdateUsageTimeForUUID" #define kBITUpdateAuthorizedVersion @"BITUpdateAuthorizedVersion" #define kBITUpdateAuthorizedToken @"BITUpdateAuthorizedToken" From 02972946ea3cd67adea9934ebd13d86d0a9634e6 Mon Sep 17 00:00:00 2001 From: Andreas Linde Date: Wed, 31 Oct 2012 01:33:15 +0100 Subject: [PATCH 095/176] Update documentation --- docs/Changelog-template.md | 48 +++++++++++- ...de-Installation-Setup-Advanced-template.md | 68 ++++++----------- docs/Guide-Installation-Setup-template.md | 69 ++++-------------- docs/XcodeBundleResource1_normal.png | Bin 161062 -> 0 bytes docs/XcodeFrameworkSearchPath_normal.png | Bin 81774 -> 0 bytes docs/XcodeFrameworks1_normal.png | Bin 111028 -> 87734 bytes docs/XcodeFrameworks3_normal.png | Bin 108303 -> 0 bytes docs/XcodeLinkBinariesLib_normal.png | Bin 96971 -> 70374 bytes docs/XcodeMacros1_normal.png | Bin 64343 -> 0 bytes docs/XcodeMacros2_normal.png | Bin 72878 -> 0 bytes docs/XcodeOtherLinkerFlags_normal.png | Bin 67418 -> 0 bytes 11 files changed, 84 insertions(+), 101 deletions(-) delete mode 100644 docs/XcodeBundleResource1_normal.png delete mode 100644 docs/XcodeFrameworkSearchPath_normal.png delete mode 100644 docs/XcodeFrameworks3_normal.png delete mode 100644 docs/XcodeMacros1_normal.png delete mode 100644 docs/XcodeMacros2_normal.png delete mode 100644 docs/XcodeOtherLinkerFlags_normal.png diff --git a/docs/Changelog-template.md b/docs/Changelog-template.md index 862c8ad0..01845154 100644 --- a/docs/Changelog-template.md +++ b/docs/Changelog-template.md @@ -1,3 +1,49 @@ +### Version 3.0.0b1 + +- General: + + - [NEW] Feedback component + - [NEW] Minimum iOS Deployment version is now iOS 5.0 + - [NEW] Migrated to use ARC + - [UPDATE] Improved Xcode project setup to only use one static library + - [UPDATE] Providing build settings as `HockeySDK.xcconfig` file for easier setup + - [UPDATE] Using embedded.framework for binary distribution containing everything needed in one package + +- Feedback: + + - [NEW] User feedback interface for direct communication with your users + - [NEW] iOS 6 UIActivity component for integrating feedback + +- Updating: + + - [NEW] Support for In-App updates without changing `CFBundleVersion` + - [UPDATE] Update UI modified to be more iOS 6 alike + - [UPDATE] Update UI shows the company name next to the app name if defined in the backend + + +### Version 2.5.4 + +- General: + + - Declared as final release, since everything in 2.5.4b3 is working as expected + +### Version 2.5.4b3 + +- General: + + - [NEW] Atlassian JMC support disabled (Use subproject integration if you want it) + +### Version 2.5.4b2 + +- Crash Reporting: + + - [UPDATE] Migrate pre v2.5 auto send user setting + - [BUGFIX] The alert option 'Auto Send' did not persist correctly + +- Updating: + + - [BUGFIX] Authorization option did not persist correctly and caused authorization to re-appear on every cold app start + ### Version 2.5.4b1 - General: @@ -115,4 +161,4 @@ If you want users to be able not to send analytics data, implement the `[BITUpdateManagerDelegate updateManagerShouldSendUsageData:]` delegate and return - the value depending on what the user defines in your settings UI. + the value depending on what the user defines in your settings UI. \ No newline at end of file diff --git a/docs/Guide-Installation-Setup-Advanced-template.md b/docs/Guide-Installation-Setup-Advanced-template.md index 98808d00..a829bc97 100644 --- a/docs/Guide-Installation-Setup-Advanced-template.md +++ b/docs/Guide-Installation-Setup-Advanced-template.md @@ -16,7 +16,9 @@ This document contains the following sections: ## Requirements -The SDK runs on devices with iOS 4.0 or higher. +The SDK runs on devices with iOS 5.0 or higher. + +If you need support for iOS 4.x, please check out [HockeySDK v2.5.4](https://github.com/bitstadium/HockeySDK-iOS/downloads) If you need support for iOS 3.x, please check out [HockeyKit](http://support.hockeyapp.net/kb/client-integration/beta-distribution-on-ios-hockeykit) and [QuincyKit](http://support.hockeyapp.net/kb/client-integration/crash-reporting-on-ios-quincykit) @@ -52,44 +54,38 @@ If you need support for iOS 3.x, please check out [HockeyKit](http://support.hoc 8. Select `Add Other...`. - - 9. Select `CrashReporter.framework` from the `Vendor/HockeySDK/Vendor` folder -10. The following entries should be present: - * `libHockeySDK.a` - * `CrashReporter.framework` - * `CoreGraphics.framework` - * `Foundation.framework` - * `QuartzCore.framework` - * `SystemConfiguration.framework` - * `UIKit.framework` +10. Select `Build Settings` - +11. Add the following `Header Search Path` -11. Expand `Copy Bundle Resources`. + `$(SRCROOT)/Vendor/HockeySDK/Classes` -12. Drag & Drop `HockeySDKResources.bundle` from the `Products` folder in `HockeySDK.xcodeproj` +12. Create a new `Project.xcconfig` file, if you don't already have one (You can give it any name) - + a. Select your project. -13. Select `Build Settings` + b. Select the tab `Info`. -14. Search for `Header Search Paths` + c. Expand `Configurations`. -15. Add a path to `$(SRCROOT)/Vendor/HockeySDK/Vendor` and make sure that the list does not contain a path pointing to the `QuincyKit` SDK or another framework that contains `PLCrashReporter` + d. Select `Project.xcconfig` for all your configurations + + - +13. Open `Project.xcconfig` in the editor -16. Hit `Done`. +14. Add the following line: -17. HockeySDK-iOS also needs a JSON library. If your deployment target iOS 5.0 or later, then you don't have to do anything. If your deployment target is iOS 4.x, please include one of the following libraries: - * [JSONKit](https://github.com/johnezang/JSONKit) - * [SBJSON](https://github.com/stig/json-framework) - * [YAJL](https://github.com/gabriel/yajl-objc) + `#include "../Vendor/HockeySDK/Support/HockeySDK.xcconfig"` + + (Adjust the path depending where the `Project.xcconfig` file is located related to the Xcode project package) + + ## Modify Code @@ -115,7 +111,7 @@ If you need support for iOS 3.x, please check out [HockeyKit](http://support.hoc 6. Replace `BETA_IDENTIFIER` with the app identifier of your beta app. If you don't know what the app identifier is or how to find it, please read [this how-to](http://support.hockeyapp.net/kb/how-tos/how-to-find-the-app-identifier). -7. Replace `LIVE_IDENTIFIER` with the app identifier of your release app. +7. Replace `LIVE_IDENTIFIER` with the app identifier of your release app. We suggest to setup different apps on HockeyApp for your test and production builds. You usually will have way more test versions, but your production version usually has way more crash reports. This helps to keep data separated, getting a better overview and less trouble setting the right app versions downloadable for your beta users. ## Submit the UDID @@ -131,27 +127,7 @@ If you only want crash reporting, you can skip this step. If you want to use Hoc return nil; } -The method only returns the UDID when the build is not targeted to the App Sore. This assumes that a preprocessor macro name CONFIGURATION_AppStore exists and is set for App Store builds. You can define the macro as follows: - -1. Select your project in the `Project Navigator` (⌘+1). - -2. Select your target. - -3. Select the tab `Build Settings`. - -4. Search for `preprocessor macros` - - ![XcodeMacros1_normal.png](XcodeMacros1_normal.png) - -5. Select the top-most line and double-click the value field. - -6. Click the + button. - -7. Enter the following string into the input field and finish with "Done".
CONFIGURATION_$(CONFIGURATION)
- - ![XcodeMacros2_normal.png](XcodeMacros2_normal.png) - -Now you can use `#if defined (CONFIGURATION_AppStore)` statements in your code. If your configurations have different names, please adjust the above use of `CONFIGURATION_AppStore`. +The method only returns the UDID when the build is not targeted to the App Sore. This assumes that a preprocessor macro name CONFIGURATION_AppStore exists and is set for App Store builds. The macros are already defined in `HockeySDK.xcconfig`. ## Mac Desktop Uploader diff --git a/docs/Guide-Installation-Setup-template.md b/docs/Guide-Installation-Setup-template.md index e4005238..5830fe72 100644 --- a/docs/Guide-Installation-Setup-template.md +++ b/docs/Guide-Installation-Setup-template.md @@ -16,7 +16,9 @@ This document contains the following sections: ## Requirements -The SDK runs on devices with iOS 4.0 or higher. +The SDK runs on devices with iOS 5.0 or higher. + +If you need support for iOS 4.x, please check out [HockeySDK v2.5.4](https://github.com/bitstadium/HockeySDK-iOS/downloads) If you need support for iOS 3.x, please check out [HockeyKit](http://support.hockeyapp.net/kb/client-integration/beta-distribution-on-ios-hockeykit) and [QuincyKit](http://support.hockeyapp.net/kb/client-integration/crash-reporting-on-ios-quincykit) @@ -42,41 +44,24 @@ If you need support for iOS 3.x, please check out [HockeyKit](http://support.hoc 4. Select your project in the `Project Navigator` (⌘+1). -5. Select your target. +5. Select your project. -6. Select the tab `Summary`. +6. Select the tab `Info`. -7. Expand `Link Binary With Libraries`. +7. Expand `Configurations`. -8. The following entries should be present: - * CoreGraphics.framework - * Foundation.framework - * HockeySDK.framework - * QuartzCore.framework - * SystemConfiguration.framework - * UIKit.framework +8. Select `HockeySDK.xcconfig` for all your configurations (if you don't already use a `.xcconfig` file) -9. If one of the frameworks is missing, then click the + button, search the framework and confirm with the `Add` button. - -10. Remove `CrashReporter.framework` if present, and also remove if from the project by deleting it also from the filesystem - -11. Select `Build Settings` +9. If you are already using a `.xcconfig` file, simply add the following line to it -12. Search `Framework Search Paths` - -13. Make sure that the list does not contain a path pointing to the `QuincyKit` SDK or another framework that contains `PLCrashReporter` + `#include "../Vendor/HockeySDK/Support/HockeySDK.xcconfig"` - - -14. HockeySDK-iOS also needs a JSON library. If your deployment target iOS 5.0 or later, then you don't have to do anything. If your deployment target is iOS 4.x, please include one of the following libraries: - * [JSONKit](https://github.com/johnezang/JSONKit) - * [SBJSON](https://github.com/stig/json-framework) - * [YAJL](https://github.com/gabriel/yajl-objc) + (Adjust the path depending where the `Project.xcconfig` file is located related to the Xcode project package) - - + ## Modify Code 1. Open your `AppDelegate.m` file. @@ -101,7 +86,7 @@ If you need support for iOS 3.x, please check out [HockeyKit](http://support.hoc 6. Replace `BETA_IDENTIFIER` with the app identifier of your beta app. If you don't know what the app identifier is or how to find it, please read [this how-to](http://support.hockeyapp.net/kb/how-tos/how-to-find-the-app-identifier). -7. Replace `LIVE_IDENTIFIER` with the app identifier of your release app. +7. Replace `LIVE_IDENTIFIER` with the app identifier of your release app. We suggest to setup different apps on HockeyApp for your test and production builds. You usually will have way more test versions, but your production version usually has way more crash reports. This helps to keep data separated, getting a better overview and less trouble setting the right app versions downloadable for your beta users. ## Submit the UDID @@ -117,27 +102,7 @@ If you only want crash reporting, you can skip this step. If you want to use Hoc return nil; } -The method only returns the UDID when the build is not targeted to the App Sore. This assumes that a preprocessor macro name CONFIGURATION_AppStore exists and is set for App Store builds. You can define the macro as follows: - -1. Select your project in the `Project Navigator` (⌘+1). - -2. Select your target. - -3. Select the tab `Build Settings`. - -4. Search for `preprocessor macros` - - - -5. Select the top-most line and double-click the value field. - -6. Click the + button. - -7. Enter the following string into the input field and finish with "Done".
CONFIGURATION_$(CONFIGURATION)
- - - -Now you can use `#if defined (CONFIGURATION_AppStore)` statements in your code. If your configurations have different names, please adjust the above use of `CONFIGURATION_AppStore`. +The method only returns the UDID when the build is not targeted to the App Sore. This assumes that a preprocessor macro name CONFIGURATION_AppStore exists and is set for App Store builds. The macros are already defined in `HockeySDK.xcconfig`. ## Mac Desktop Uploader @@ -149,8 +114,4 @@ The Mac Desktop Uploader can provide easy uploading of your app versions to Hock This documentation provides integrated help in Xcode for all public APIs and a set of additional tutorials and HowTos. -1. Download the latest [HockeySDK-iOS documentation](https://github.com/bitstadium/HockeySDK-iOS/downloads). - -2. Unzip the file. A new folder `HockeySDK-iOS-documentation` is created. - -3. Copy the content into ~`/Library/Developer/Shared/Documentation/DocSet` +1. Copy `de.bitstadium.HockeySDK-iOS-3.0.0b1.docset` into ~`/Library/Developer/Shared/Documentation/DocSet` diff --git a/docs/XcodeBundleResource1_normal.png b/docs/XcodeBundleResource1_normal.png deleted file mode 100644 index 85231fb10df5b31eb295fdf2bf9f1094c3488698..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 161062 zcmcG!^;=Z$7dDE5bT>!{NGRRi-5^SbG$`FYbcaYu4xxl}Ne|sI(jXl}4l(oqGaNqO z_qxt`|AF)C-uqe4z2aJX#T}=krHqG7jg5kWf~TsY@Bsw{bqxjOMI9#k^OGiVbaoUJ zY*|Nnc^y@G`8PTqu6B-2wkRknc=?&WAN7{WW58X)U4Mxg-!NZM2VlLK5mzBY(~VON z)p;2m$>O8%N{N){oxaV-o)^k7jMj>zI1%Aii&z(gIzzp>3W|`m#IIOq)q{rU9K|Jcyr1XYSXd8(XGScx$p!?WfYcwi;jY=I4>j-!a@OgnXcD3NX7SrHg=Wq zjxU;*kGu%0xQcOSpw{W8Y>&NT^hXxUZV|Q76ji4{L1Kr_dJgkeNg`U2=?~^j`;s6G z+pdqQIVg}@w%OUcJPi~c(rk-~eU>7pI6g&Es?)fOmnfL&1EQTC_z7@PhXNG8Qv2O_ zv^Z6(QliBlj*x>9yL(up9^8tTJ-uIZE7nf~eAR@T%tH}c>zb+fg4xJ9+adL&n&#xh zXkpI*-o3m*7ovxd90_>%1Y?1M3uF@uj5eI0Roq?VC^v77b7>nv8J|#^oY7?IxGRxcFIM8^kT)(@u}5RM;@?;0v2`fN%tTfD>BZZBT6F7@Eey6 zb|hea3qUEvia`~U|CQ9i+X5vxN>ry+6=TFz5=EW~^{tC^z{}uc6GC3>5m2W?b!x3= z3SR(n|DGPlG~Q)PLzYo*?*=!;#)G+-gQ{dB(y8|)@iz>wLTrIBE}oYhpYdoy`Q1?0 z-=IW>st}@PqH?Lcbd*7Bkd<0`4nf|f7d{bR+)(Di0{)_Dg$uc%o1z)?;JM-8hAPWo zNB64pyjTx�)f<|#Q6J003GonIFjhc%UMgjC6qs*%XQ*3n96K8^c7D<*ahO|*J8)XklBN=n;nzz6= z7R&_SrFGKTSV*oRL+ zv^uRa^=rm)Rv@!>`eK%EmIW7()q(+_hAe$-eW}|k)2kO&Qm0>}wAIun8KtV2Q=DNH zYn5XaXBDw6IH=3q`917=3$b>E%wgRO^DhQ!x!GU-Gp$XUO=ACS|MAc&3;%qWO*e}N1TJOJH_a8|frBUZlgQ%&fKT&513<*-@xa5rHKyvm4hMOFWahlPLA;$a7<~$kM zrxPFTm>UyBi>hl*$~dQ`ey&wYR$G@h8rqj=HBOP3edjU}mTfU@(estlR_8Y4wy4!T zE0WR$Rs(-_D|ed!#(Ms~`S&?NHn+FDD88uMvcR%r%bMwTYUT9%65|r_Arb38?(s0G z9TS$ixO~;`s!5}odP{TbA3wK)o4~kV_Z(ORDg`@+i|ba6jH;9t3Pt-RMuJNGbK&eb zk_mZLhhyf^);C z`y^OA$E zxkq`QC_E4%cTTzZO*0#z|2&!@ z731KVZx+2q?(gYd)6;GcKE;vrRX{Xqt}NPoA!v(f9Wf8z_lMZ`lVE0dwvVZ3S&W21EH1)!E7HHEm%QVzn68*~jBL7Vnw4X=jIU!iovOj+X=K;&BN?f2t&;dQmpQ@+r}0a}y1lY3a7=fCXzyw_ zXV+z%cJy-eAw=iuyieDYIP-D8%rsZqa+rD)TI!{Z* ziTh^)#}u2CCcg59F16Y(%JXGMKaawwQ*!pYjsjaw^8XF5EOu`=17=?&p$=k5(UH=0 z0!D6izE;aR4_dBnRrQ09i;vp7?Ew}5g%cH6Dp)y6`PXn?iub(u+@f%~aJo=m()XeI z9rs~Z#OAepAW7w+4u4789hwM(C~SN9j{d9wS7O;eKKS<`D*|})=dW?RanZu+LfoI9 zLXLqNfg6XRv-z}Bw4BnpPeE6SH`zIjWA^Ic)G4yOTv4EJ$c5Zc6f7Z*B1X)>ORBwT zcP784u4a8aEUVTW*5*;M()IB8DXY@HM$}9^I6t`SBpQ*lK-W=_X#ov!JZwI5?mBd9 zL}cz%Cxc!E@86p}aIfFA2Sbvd@?WDSpx>WzfdZe*S0xXF*Adeg6$Iwe69FO!2ZS|r zr1xFM-J)GZ*A=vI@iVwF);=Y=Ri67P1754${|a0IW>;!bI#RAy1}DN3 z*8=LV2G7S6vu1aqy5AxH+-6Ky0z-Tsy6mk+2hP7vA7@Let(SvD?-y>I_iYY#XMG*d zO3UKcD?!pXVThs!>#O0^L#Xzhb_Os>+BXR6@xqVA*=}#+HuCa;Ps}I;1w{r$RYCTn z-wUW2Mkwjv4D#l}J?xEW{M)$j-M4RIL&I>3+1^mf@DvqWz2w(U-Qb93EiS}lW7E~q zB}{+w@;kpu@-XCXaj~&kShyw7hOSc>FEIai`|rxi!1ngQ0Ey$pS}-w&H(d%w;%wP$ zXXngfjah;RWQ;*T;NvD9d3boZM`qePst-RK^Cl)V4LGMT^Q*Z#_4Pz z1|jL8mC~nq-!7A7b`%P|d>=)mcZNszOv3&#>D)(sDI?Sh8I9Dk$_MR1G75hDh$YRI z@#w2?`=ZgvsKKw)Ou3Hx^;dQoL>w+c7Br)wrp9OcrA=+)kUhV1hD^!-&qL1swn_A_ zv0g3;ycNhE!Bj!5NaSptvC-aM7^OU*&#%0$Cpa4BCUU8(cQgT%R0L zPvJb>!FGmPJ9Vzov-Gw!kAH%;^AZ|CjG}7T#5IpF+9~pKf=RHtRdtdBNZLm>LV@V->>v?B$ z$qBe<8rQW|7r|S(1XF-`+f_$Sp}0I|J4Y*)RC~#uIncRt`LJf)DAd6;*j_Xd zh%a?GeXdVEbpf?q9``8~hY6fU&bHoTQ;hibIp#@G;OJKwh5?Z9;lixif`vT7logbeirsgH+T!c`dG&UV_T}8(iafsrp-LFcVU@XG zdoqX+=ea#2eo?@F^xqwAgfv)MB1x5JC}1-0K1Wl8DdswwJ!oj2AkvrNfe2$_Y00p= zN(4UFdLNSN6sIL(zlwe|>!_(`cr7UT%{3+=AwfQsQSmWZIT8m8OV-aXHZg61QAI_i zym^KGty1eQD^Nww%S(V-$SL+Y0K=_W#!DJ!>xc6X(U-vVta(H8w-Mi&M*oKmoy2_S=s~f8S?oUr@#b9r{_j)9 zW#at*6huD~KKM_;|ARWI(iQdkwb!$Z;BJ*a3jf{P5_XUGzoQm!O^Qjho*g8EK>y!S z?(dw_|H*PL42k&PZ4{%K|C1%8(=Gcy$O$&;|C9B)e53HcqyN9d@M%q(Y?*VglZ`I} zZS*-m`{Do9C@%z)H(hiRlhn7ABuhk~T~u~XwIg#U(f4=(&(hLT;j(Ra*G8j2VwsiH z4y|wTVvbdFhQ%V@df4}(^4YXod9Fb-1$?&HAmsg5{;lM=INsrlHox$6TG zttF(Skl{0pm(~OiJ4x^~$41T?E;_ZV*#WRWF{(=MbV;1Y z(K{O5dN?5?7^AwQ%L$?!43Kz;Fc2BkvzSdyjV)0o{zgUu?@PAmrv#HjxV|EBJL?(e_N+KXIly+^uDWfD+GcW8@1o->yj-2SZUAuUQz z>p33jlPdu=$O?0jYlUZ<<(b(-E&sEXFN`}MISwZmc00^Fp6%)J>y4-fK9T^{bJtL@B8+8t?VrMtkj# z53HhJ z^BCuh26A^l65pH$o^{#JVBphW28wX+wV}B41^93AyWXCzm3FTN99OfVN;)DbEP}$G z-CF2%IKvu+ht?zJ4#g2DZFq`_M3bHPq8F(EF>~?nVr8S0wG{9pD0#{q4<0l~#3Ykk zPIy*fHET~5{+d9jl`M&cTNbRA%98KsD?}N=kRaXn3C_W^6yr7{L!2r3D3T0Vr)f@z zCkr6w@?NZ^^x66RSZ@2#k36Bwr+57@rD%NCQ{dAhdaLj5o2x@Zj3DZ_&U7hCDN)!^ zP8JYg`n7|&1FO`7H*QUQ^XX$9LtsSQ-No-Akw>`Ps)1fIG+_mFK;lJn1y~P)9pUv1 z0M=r@MD3o2rsq=%Ls>eJX?DUrXsHHCn}U8Hb{***k9=AQZgJab@x~1=KH)C!n#x$X69`~t@4NE0=c>WP2V0nX@X z)c+-YJOAFcnTM4kc|&=BeQbY9<+hbFSq_-?$&zC5!mlLCf4@VQQ#R;frEC{Ivn+OLo)6ik|62Y#y6E zVKk7vP@FdyeY=W)qq&Nu=C2g%ln8VomwygE4P%*{3CeW-Xs%t?naj+T=3Qbwr>j_f z9*Zlr;_~;P1~kA>B9+5jIgv~27J8%c0L~#fhvA!!D$XfG0>cpV>)H>$;+LB*VX4Y8 z8}qj~9{5LR+9|5++{ob0JceNE*^Kv}_}aT%H>65BKzz(SW|QHsaHuJ{CYG-M;oG-| zmCzS(Zg6a9fi3(4)S}#O>OjQ3UU>Fn2t5BJR?`DfsxBIDA>1+gird}@4A?L|VDq`| z0tLQ(gyrIFO~W^jPMU%Yc4c<`;}4pG%bL{r$=<^#C@WB0^}h zMQZ^opj@TjjN{JSMCwB}RoA1ybdI6s)gO3+;r+43qKdeu9k7*!R5p6zl*wZsMs^Mo zBab=Y_!I%o`Zx4fZU>uo8iA)utHC=Gox;A1)D+G7GpIZa4Ow}!b7?fTkg!^}vK9R2 zKT`s?CTU^PN2UEnS~GaZh3_?ZarP18f)Zm5xpPAgK9^dbSfg1-R6y@u| zw`Sc|e)orEnkIkm#LW-;2wS2g`72 zA1Gxew*@{|EX>Rv-$|geIj{48%FY>(S7&;@$?PD}+#fRLw$|>QMC2lW`6~Y|9piWa zrU+-KqfO@N?Pd6up~cjV>#`kRFCOeqEHKHTg#x`ZVDA?x;Mc+<0n=hm04TAJ0E<|X<-{)Bdsd9cI^}i;t=9H%Skm9 z*)!%(x3x36b#?k7McftgJAB#oNWblRV!Zs)vc7+!bs20qT5Y}#TIwh z*=>$j;`Yfs{2l+SHnHLcPWtu$H{rQ^QRx~UIi4~@l*{s_(y>BQXM{Cixz*EI8 z5WV%hv$wl#Je%4tho3{Wy%G5_B^#{cfA1SeN<)0$sromD-@<{zNE~I?5bS(*JIk#= zdKCGxtv{8;^}h7ONrbBxkGDUBu9bqi4un=SCz>domRfO$`b?c*`vl9*dh@^g_j!wPPxxbu_gEZ8&MdFCbzm1H;-Iv2x*!o(pV=;tQD9 z1b}!}X`{G?7EmN_KI6GZN=y-WdR# z`bMa{u7~I81A&%5E;;uRpM4~^h8CW?gs2R5gPb--i{+i@q~MTDy>T|{>njiaBS^nN z>G=SUqvxlvrgsYVpe?X20UgAyZS|LR1kvKDUtH=QZHDg?^pQPp!6;aMcwDchE(v)w zUn$#rsbocs?}SU&%&l7-DatZFWR<;}k}SSiX;7`yb$_kZMtf20ik%_-v)AmD&vuM5 zBG(=1@b~Yxt-&wO|C)F=_ZyHLZeThiPGaMKAt5Uhxvso#0NU~daV3!4I!$CEFdpf= z-bq#4jTDQED2#u&n$NqPYg1MO?=?yqhrvJB z42MSVi7XFP)boQ;Jfnk8j?3r-T(p(659?|@Hh&`PfFEm2mlrqQ@%QC_L1X|}UDHL! zxBD;wod-!n!rDV~HD)V$a_3u1UUOVu7gXUeb>#ta#6-a(78$2ad;#)rh=18DdmD(H4b1 zkvR`;hFHy5X}EY$=?4XIi?sw&Y;Xn=ZmF-!0JqZ4?|s#$+j5{srzGs6>g#|^;=aDd zy0a{UzsGG|Kbp4jNJquOBN8?UBRbH?PnIIAa#;$ka;MAT51tO*!68krFPH+jI$ph! z=-_p~6EMBK=65jj;>c-geSK02h>zLu!%GvM%p$nc_yT(yxL$S@^4GkhS|BlwxREQ;Cy`Y9kFv6 zs%rhgG#X{|31$Hl@ut9Wh7R#hQ>jdOXtRKBQunP2=yxhJt*NOU`k@g{H3orV(aNPa zthcq>{V|g*Xy%k_AgGfv@E>G25;T8)HId`j5p3l5;i*^nDS&YLc_fvi=-yg+cyhqE zg&x%GfQOBcqFKZUt4f>|v72Mx6nObHcMT1$EAje}HLKw}*Rg%ynU?pJRO>6I_Tiy3@ zKPcf+C^`4WXIBYV8~c)-Cn&1rQ>DICM?A0@U*zm6ncqlNx_FnYUPVRf^Vp<{WIW%m zVt2o5iR@gwb4l(K0l|q2NBIjuMdTg!Tj7~IHOKv_{K?08doT9yMOKXZD(t)C`$5y< zVcQB}@PH;$)-@j*{t^85LdZ2UJlH8`l|2i3QDQ>)yj^mn+ z=a?i2j>yvT3-Z5^;-r0LH!K`?p?oL~`Np(CQUB5uzG+iX$-P>%(=xd%Bf#c>a_QG% zCbjA><#$k6Yknh^j}<(~D!HCxUTrMckF%2Kv3n|v7i@kp|J+qTeHyNohcUi-mR`Z> zc#>2LwC)0C77zT@wKt|3Rnx{H9z80LrlUZK6-ede&Xqq}f$&)Oc^}SRSHK^t{4p@a z%`5?KA?m_Z_l!NgVS`_s1tJg$-%o;KsUsS8_SrUMH-@taMzHhnH>UWYt-IFio&Kdd zAmk>_*-{(^ebC>LmXwAoY;ACW>KZQ9!X_ zZdb^2tYp1x?o%WeMMy#$0l0az*81gjH1}?}rlpI+ndz4^c$|n_CdKr}Lc0~_jIBcg z-ff`{=uJ8sF=LiDiY+!;!WM0m^=Nj(3%Vqrepzl5l?7EFtEPhf$sYO1->tDAl~i64 z0n0QRU=HVvAIpvF5AHVZ!r+V`kydW}c`ks{CMZ83p-1XWGE`lqX8@IQBK6Egn+8`%SsM30Ot;GbkWO4U0VkE6e`I3S}=`* z9$qc`Vc{)_-JT%M;W%)>>^Jk~FJ$NhbWVw@)g~=D`L5=_l}d7>SyRXwwKx()-Yauv zJvJi8aQtlw_Ev%ckCzt$?_Z`=r{O2LQL6}WRTP?{{1Er$`uE3K{mN4xa4~4o*47BN z-jP_SaG&9IoJr0Z5?Se+)4OOkx7T~po0qQ9NxjK+1;uUk$E0<6ssV!p9RCfRY279X zuRHw9=dm{iTm-gzFinl#Pv4xZ1bZxjH2cgYcT;J-O-&h{ow@J5+U`=D(x#c{Hr%_P zXA*T*ZIsp?MX#j!he8zKf2Vyj`@H~HP>FXb*yEs5YZ8mJIPF-BZsw_1d^g%Pzb|aU zw<~Jzt`1e?S0=Sm{CD{^$IJn-IPZJB$-?We-J+ph31O`7MjKGgOZ+hPowU|97VY%C!XK3Z9tCt;ZG0$Te>U-`H$pNszO4gS{Z+9QvgJr^~9RxmsJ?zg$y0M+*iB5fhP_l$@M54hTGK1*`2xtLa^!-yK_G_ zmJ*%TPU~usT`6W%axQyhJ;4lDf{Ycmwr>5Ds*3c`k%`6KHwCD4U*}tYZlLqA)m_xF%cbc9&iTWCQr?_6#VjtIG1}g4Pnn5r_jL8){7Uj5V$F}=3iWw=1&2{ z5D(h8q_)y$!}u&lRfqxn4SlwrZvmMTvfc7-(`rFYulH&84MEgvtAu;U9TI|TAhSTX zoxPE1rUjS>Z3?LjlqLE|wAgF?!-6=| z;PGG{-}rP*PCftTJ8^$WzX20>==JBEy;So2J|o`aT18e?i)AOYPl}EnX3PuxO*+%%tZ*pUJkeeOb|UAu#vM$q3_ptu|1qR0Nbu z&nDpmHAMA%ZbuX7{Uo-;=YE!S%XpM%=};UkR3`kRYOeP>{NTAGjiJXyY|E{YZ;U{l zPdbsy{zkq6M1%&1p7fOL?e5rgHfYf}p!VwWGkzOwTVq~#s{o#R66(DR!vMbjxcNG+^AMnM;;+@I9*yo*+JAXavrb@zy z6P&VG_Z6}fQ(YA1f9v?GaO#j&f83f%%7hY(9YQ@3T#o?k>j2zA6Jc`s`I`K1f_BuW zUq0e`<338z1k}Ad%FMVOCrM_?_Bf9$QtjSa@}9*^lr;&uQIkyt6G86+#V^csRr`jC z0Fmmb^MoY5gG8c)-S9~0=6G>b=SHXNwbxb9X9?pj0SrjQ>>G;KaoB|jRGKD9mz~x6 z>xqkl-Wy^Zx-U_&=i@p}>DSm{GTHa{|KzsmO5}MR5Cf8a8bjbwLA%27PZz(n?ky(* zD}_t9@im-H35SKa`+Ljd%MC?HR9W%E?L3y{ct5OL`p>==A@co5{>duU&xUocd+qhv zcz92ivpN$8+pAl3B)BrU(7HCK;blRxHS4ZQNM=xl{J)9e1c?#&mv)umZC%_i?NwDO z0tYjwf#|_;NzO6FRyGpkS^;DSk3~=q6EWLf2sAB+T*ac=OU_7Z=gRZ;MDO@D$LOFh zWdDfZAz_}PDg<&vpBkO2s?~P)eWJCwHs?A=-v z0hi!EVgL6rC_n2`F$(;vOtn&%Z$sL{hD(in)Rv!7QR{VWpk`1}YC2}hYNH#bmir?oQy&uB3sZLZTY9L@M#_SxD~jV8J!>0Vg_@c0{-f3;&c0wz(rZK zO0P#mYyAn*%LGoYsC>p4xJ5tQb#^8W_01btBt4I;hpIw#h#ZzuTPkbXu_Xhpcz|Qu zCnpkGOe+OhhpE!efDCQ(yWI?tc9oqJe0VJJ50UJi^jNIkpWall z*r~77`O9`9P=7RvqDp>=WZ<%1W@Im=9)W1 zqm4jk2@`gR2uaHVZDa))LErA>pyuGtc|O`{pd+Z}p&cH|bc zaT2j#m1K!3d5-WeC(DjTWIysO;T(8P;;@+A9KyB-fNpx;$J_0=6(sLXfW|AShQz?9 zdmQdf5-Moqx zZo|VfZ$$YbaYr?DQ_hyae6gzW=O9qRqoms=#@0}5$ahh9S?m+pvIF7J`Yl^PO9SXS z4jmPS=vW-<5AGh}d??oKDEO`QFw4Z9TPDELdS@@(;tts#0|(p`JT4apFRZ7SA>5yb zH9-Cr&dVcdSfzVtjg;8gAad7u7qtvy|;+(oPSy)5S{)3e{g(kR!|Z2 zCM`YM3XgR}d^IXH)q^l@+*L{8BW3*Xn9FVQA>VT4R&LqKe$;AH5$7ODKjPt5IqdOO zVtp643o!fj#qtS%yOF3jM`W_2vE!sLC{!&uJa-Q8XTWLArj2FUpp;y?ofnaK|Uv zO*TAU=$D!)MvecdC6p1GRptJx^mzm->QE1DECPR`0F_Ls7cHTG9Q*RAvdBAkL1{|D zN2`5;2_W$0P75uGt$K0!uRWDO@yYd4z1g<8ye`zt+dWMS-+a&Yn2! zl6Y_2-6e*$H+^SqvxT19>?vx;UWZv(diblO`+e%q9E@NHyYz0p#CfZb#S5KbFXTlr z(4gzG?{Z%8rE&C(-u-)wq?O=7%be)Li5cR`{+--hW;r9!d`lGUPj-A+=msQ|GL!a z*e>opBgE@G$KSjiN!Z?MpbnBrhRoJvG)sQWdi|&6Ch*fbL)I(x<*2=4lN9bhV`UBa zRO|hf*F#gZ1i2S!yD9;LT-sL0)!-c8DWe7RqTYsYZYY%l&&8sDw<=dq1oU7XcCFvW zEFrrdqou5HW!q2^gsD2J+FHEA2Bj%v;S@#3r;+$fE@@O7%N}4kOw*?00d`?Zh$s@| zF*q8T-+pE*;dL%p*dD`n8}BmRlXmPqJ~Yfd_&`_vgp+ZC{hJuxijI4)<^sy zsA~qW5pP58f)$!fKieG=LqwGvl6XH>Nz=S0pj~%N?&F7i{!4bZm|X40C5uK$oZPhQ z=gC+clm$MI;CQ4H=h`3sg>0GlmyBre>x~gRZVJ|N_hgl^`oNY$fW$SS|0Yy7YIfa! z7c#^*vvAL+k!6B!kJPYQ<~Xwnasa7sWOP>o%7le|9%==Bc_XsKL)vy)BwP=gEb=BV zV=g(RzBY3NYfbM*GYZRyJZ*AanxUTZ)z)cciwy>>!~NHzM^AQ*urd`>nLT3@2P8A6 zIYacrgP2+S8_bv>4xfvibWFaLib>J=b#{Hts@W4XcKHWg=?0${d)o!ek2HyOpa^Kv z@e}WIjC(|GJ+%4^lVMN~#DnX!+TWq@=aWiko!`0aR)}bofBF#*=EDnysYU?jx3pSj zW;`+ol1xHQcTNPLWLcKTIbNr%$%+wKchu>!B29T?L>p4eC zl1#o4A68e4sB7h?6zNQA`Q(e@lD-SXOOUIKGE-X9Cv?*a_;GFbgk0DQkyny+n^kdf zJ}8O!x7V?qY% zHS<$I2O{Gm)#J-o@3Qhcj9ABcYb2H+W$<*OhvFF~+{4SYFUN>4I3IFm%SeJy#sK5l z_Bukr>t{s)$5H409J$Wz*7iPY9QPNX&KAJ?V6K4j5`3PTN6%^gmDDGv`*>hJQ2Zxk zccOl`(9u6*XWO2etGx4Liood@_wDKwSMF-?z-#IXf+(FI^=62%Zdi9 z@8NS*;VOxs^`Hv%VWkdfn{z_9E>7zF}+d<|j(6kcfyY zzqV_)S+hgvsCOoulw@2-0&jMoW&q?NLs>A`vcsRGHC|d9U761vD3Yt6X>|D4H_9lP z`X+K~&@Akt>OzYPBU6T%{B`XLOvgA3$QAVXd)tPs`}jj|c2EfP4{e zkWq3MZs3m~x8Bg?h|KQuOiq)DLM6)6194b&>mb1yVPRwcQh(V8*VFfxSK;lQ=Z)iy zh52i6DrCCvsF1>(s2Ywi=(X#40X;wY7vvIg~ z)s_PZ>LA5Gn_MTFQr&r+X;A|wD4F})TRdHAN_SLqodlHUO=Z!2fnOnJ>)t%>n>_{; zUVFm9E|pMFYX07z?#d_RL+r{E>TQyG$CDdqP|xMYrzOTaZ)8M8_z!K;XO}&r=(=AN z*!_k9y|3L(LymrAjkFoRXfx0xnZKRdg5FJRFS@A2;JjG&7llBL>ORX(k#eR>d2)y^ z7UZx`9RKxy_MajMGW((0Wn6X?A=nIA$aj(?sA?BZkg``mXVGWo z-k<;No~5JOntg6fL6y=q$j6l9=Qd_Afx=NY8c*YID% z?vS8atNieZIQpA+&buzMFEoa0R-X($!1Zp)JcDoqpe(j6zm2Inxua^$g&q^Cn zaUlnpx^aqX!>)SgBNCJenvzySg6ur?3_>!|OrJ|o<^8yStS{kNV|QSKP zR(Qd_h`H9#XcJ!zsI+k!>iCk=y$zRbuAL>{EpN$#j}}uIHt$QlUlsuj?p)pOC%i^l z!qwyvG7^rGTyLewSZZ%qz!*;wLR$S&zT*GB7SQUqRRDNL!BewMO7P9Ksc`?BSAYUVBJo5JSoe@D;X z%Bi)J&2&!~P+n)3SzdGA;ViPK83bp69LX#m+D;rCBay!f%4^D9-?ALG0Uc}TI_^ty ztl`g%EJAr0?|KckGgE-^chk<~-`e0hIGCd1IShSpGzI zvBML49+D=BQ_jBMPTzLF|KGAmR9GE8v90~U^e_SsNH&W_mUUXZKY<>ucLh$_zEm6a zu0b=!Y9)62zez#=--8|_^&X}TYoDakM)DGqQ1&o&lb4TD65ZOTVg@fMI?zfrbN7yp z2G>=%0ROif8GNkB^!IwBZx3`)*M7IiAO7ij#Rizy*vE2lT^a;SO}S*z_SZZ*ZKyOK zCL&%28UT=u_wpsV!Ur8w89l$=yg(@Zp-a=V@PDSjX|%*#hBx;Ad*-WAY9o;AHj@bf!SjqkcJ@(bUBBE~C3 z>^E{;l6;okxRCG+3uEK(U0CLYTYe)N|dd{_$N@*YX9{ zNS%?9bv^W+MOW^~Nj!&wEQEMrq99T5aQ-hWx{~PKwFt#y*&zKOY!^3DL4oPL*h@aI zdo)1EF6##KMmvTP?=PJ{ZmpWgQIR0Fb%Ez*tS?rm`p8*$HpEdRSYK;ZEiz04p2Th0epRX$;VCUszn-ptP1y2Hxye>Rr z`mHpAl?F2N*n@xFpER(ZxU7&(90u#w!(_^q6Z=CSuhcqD7>r+nAQw$)> zF97tJCPONx@616Gn)>vr>UsB|bJYXo42lu!RH@F{!Inj7+gSy#ASa3UH^CSrK!=n> z=Y;xQKMo^VmDpcyYv%c}FAO04(H5+mVH6hqd84&kCAKlsAOS);j!;%PTyA9meG-0( z<{+w`P?0z6bAoh5f;8Md%3xp{e)&zmH9o52+*aW5<~OO&>r##oazT0Fok=O$a}VIq z(&eFA=Uj~l==Ji8oyCQLgEOgNJcFOxU<;(uPs|_JE$f`Ec)-cim>&^eVe==qJNcFy zJNc6qmJcI;Fa@2tLMd7i73#>NS}_(HBM&Q?Jje00rtU68kO=z9V9V{RS`|}pMvo%r zi~QYhs?pw^oBZPxdx=H`fz)NSTC7T3p#QT7EU_MlqLKcdmX^vgJPuzr@xE~%)o`-G zoE3m@4(}=x3Ic7H`njZDedkQ`Waw_X5~y2S-A}RI*V$i%U0w}oe+`sD8>y~r!9U7+8#!`V(JH7>Mc5P%TwrnyRmJ?7jFVPS2Y=(F=N%Q ziBl;W0^;2^kdd=9wQOxmYpdVA^7?Gy#a!}jm97e4eTc`%PxGBW<)6x41rQ)8y8$!9 zJt>b)^(h1cN=%TyFRu`e5yQC@lVNAC-^5m2Xm6y%fpL4Y5^k`evKj%==)&hW zu4l!%@Z#9_Yn0rRISF6iI-72!)ajyo5g4!!{6bTHQ|iXtbhJ*E!Q|w;1|rKbGow$c zJ&ULhM9KhO0`6XhEQ4KzfIY7ClF1*;jifGaQZ`xISmCY`i@&kx5DqV;{F}m3J@?C4 zt>%BbPH(KR)FPT@O@Mxnuz5_=eNETpeg8+c4&=TG;Bidb&p^`cu=4HFW{oGao1} zGwp~8r|S5CBx(fnon@ctieUb`O!18iYq*o}*!n!+7G4>w;~nNcpCt2~y-!B+!W-FV zTPK7xJ%+j{n8%m}^~=DdpV`qk%gbX?4`F9V&P5EycfR zWFqKrZ4mi!w2)%JZ!a6wDRrcgQQT6y1MN+dHhKRonot#4B)f&u4ts+w6@@X?nhQ!u zc0GyvJKoltg4CWw`*Veu_jj%1X?~D6S%;4-{}x@Wl9@gwPeiKex))ru!cyb!?waS9 znxyFlLnuQ}wGp9NcC~{^ae6wH>J$SD|3dAle_EckH{T&EWDoeZQE|`U=;n`ZZ~g)N z@RUIJ0>m+rDZH+egQ5DU=ioc>Y4~*8!TlJG#+R(H=@##vlS$#v|MtM{-X9BZgw@z+ zAnD5H_gQ)X(;%kK*>AwU4$yOVE2+V@@sU0n)#MMb`wTK70B5RAeHw2ZPwkSYbI z`J`?S(~Cutt`8HvPH;Q+n_(V&`o;B>_gH4VPrtEM>57yINXq4D^3{v<-=}!0zRzkz zE*umhqC@VBKK*$7iZ15;JAy~~Xt4cFy=e z+xnjdK3@r7yIri$pTleBU`bLQ6xo3VfYK1K8Sx#{1GmJM5?VWSpk z-0W&GS}o^E*oXyUaHIV@=-HqgO4jL#!D3`$@j~o4u*u46`VJnuttCp7s)cJ?TMA+L z-!TP4JGaFm!F_)~ZBwVjZOg#oF!N`8HF-9+FpTNgo)C#|e)T^-9pMiB z2lw5IPA#e%xM${lgM03L7`L)Lg7OJp@mTZYT#4L_yJd1xpjczvH@KU`zsIsI`i{Fn zwehbK%$6S^vQwFEkGc4iKz93Q%SQE&`Pr%d*m3hqwB{V=fOIP2yk*8E zCgGeFdk#2ri#R_L;6t5GAMU&`&7P(cR%e<$elg<*r|rN81InOkojRypy9O#<(F?1S zf^*dIV&?x+lK-X&eNm>z6eQYo${+v12N$AQw+E1Mbt6=WmJNpg0{z=G`972_TNY)? zmJz=fMt`#g86pRN^=BIUPtuyV1a>TrN&VCIEx;r9|AAyb{V#Q|m6zm|lj2ivcP@Ar zWh!2YI-=h-t5!nCPuAwp?Y!s{-`Q7MGDm=t~Scd(uEP6cf7FHe3$U(>6e=Pb57$>l={~2#C z4BfYA0PbCM(BS0M{}e2`_W}HN$l9g1^BLu%_G^|iS(GbHj*z-;Mj3E-6vd->^y|aGJIN^#3Vf= zM2=o_fR=$+S_H|mni(A(je2$KVDXYa3`|jeqtJ`5*2tn+1PmO zUKGl24bq;(b@+Y;Ghz@CoFxkc5-i#XPkf$$TV_0hy1n1S)Wti{w>rxgmnExS!V|$f zo^6;qbh3n6phnsJ*lh_@k{7OH|NQ#&K1M0vs4E-*laLeWT0<;tIl%5tmhnx|*T zAZx{`7s1|Toh;eO&yu46$>~<6M+RTJ{t)AA^zVNGKQ2LTuRjonW73xrl2VPVsZOFI z2nz{DRAd+m#zvx4;TYtP=KTey-hZtYJB7cgTk!ge-(a_|=Y-<2%5pm7mTOR8=MQ-D z(^a-YLQ(s=PUzjNta+`28UL)DhY!DzMJyYB{q~)3YooG0yrgYbIW2nMi%ylIpm867 z1hPV}!icBZAiv)-B|qwF++A}cK3pR2o%nV6aObdrsF}}irki+?OTa#%u*MOKVe{}e zW2QCE5H35P16uY@I57yHoo~hMY5z(5gDWQBg*o?N;g)AmJ|qE~*X=@)2w7zH?($#k z{FA@`r2I~Yevn7Z$0MnR-(Z_gIQdUK&c){!G4z%$kfyk(_2*RUAC$&1@-h6eu{XAi zdkDSme*rDqeT{l@63tnE?LW~KdSd?k4CEJGObzE5zfgpU+=Aq1??3sX3rJoj!lfU| zY*4~l=0Qxq{T1~4_Y%C&wu~HR+=LxT#jH7F0Qqm7bUT`Vbu+e3?O|R$+&ZbZ#5-Zj zly0UiqOR!S(=Dv>S#9TuywJe2^CH{{OwKgs zD}GoAmo}j-MkI&JY? z|7wO7<HE@ky=DfuS#15Mbt$p*>_g{vSC9}xQQ%~$&Q@!`5{J{q5IIJ z-!SOPM2vr|4F*143$3TzhUh$=pFyVIhk5(9#Ugn))B3Z7{|S84j+VSkM=%{p5_Q6E zS7dKLG0>WB#}5k$kp>O&{X*r_RAJ!}h={Oew!APRR*uLuZqxufw{4Q|-N|52J@Pu1 zY0;O2xMakqWgPA07*naRBjb!$~(~w`@SjpE%8{-x(3qx*%OE0qBmgemk&#H4eo9*41dd*Ndr4P zwh;2g7C_Wg~>#*kcX&BM9F5Zyr`Xio2gP2IvXwlAq zA37d_E9%t46{U*Et>@kw)+Of{t!sPxQERkZ346rwuhNh*n~pDMt;VrK8!>n06p7bF zg_2%t$Bs|=$&Z5%C24$bc~(a@?3h13I{!oXzx=r!TmLzNBXLR6FZihuOCIzYXZn`i zNASza9cLuJZ0Y75Vs8v9Uk80VH$#=^R2<&86yty7l9=TxHEM<4ax^VJJ|OUW!+3%$E{K=012 z(YtF+L`%-0WnWumq5#@=zXea;e+TZnrKPN)6++RguS3t9u1DYQ*W=pqoFW4yYd1IX z9-Z6BF*lRs{<#DtpbuxV&M=R5ae~3HrrE>HXO=z99=;gylMntQRXL2KahV7TjX|Ya zRZ$>RM#bc{c)a!FSe0l^{8G10MAsoxkRs}WeSV-4Qy zUP|I6(dUg{%%!A3DVs5(+X&44=}YtwxKgFA!#96#!!Kj{pk&FCD0Sxt*q%aJCS&n? z_nESY-{r9{uumQVl-;&(pT;8}&%}gbg5OF`kM(bb*MHjUlmE79Lvi!y-wf=hNrBNcL2%5KUX4;PiH1(?U;IGZ@KihAc?4%AHztQBU9A1Q1 zK3Q(&R(wu#BB1^6pWnyfIL4VfT!>~WKYk{Mx6eeIa}GHP}n zCHE20SWdwFQGIaJh}lRGTFD1i;`K*g$FhSo+PSeMf4q|mmcRYykI}7WP1LN}6(c_r zncG|r`Xn!|RJ8`E(Yz;Kda<>MA4`x87w^v4&c##FzeWuys~g7uzR%P%W$%1EXv!yz zns{cs?4Ek*?_E9xPxiOcYu2oRDVvfEjwf*|CXDQd8d6pb;cNUN*#=+-6OCLkX|$I{ zP04=(8_hUIRxCLOl%K)RTmHmlyZLM1(`|o?UrSf0U&QBB=`wi*_p(Z@&|Jd%^~*@Vl2aH0tIwL%i9BJ29Akpj@3Z+oxOBYf_k4Z~{c5F;*I#VU z4>M*ee>PsU{&tzz!{?*_ImxtmR&hL5Hbj;m~R%vY!Q zgboP_LU>pRBEmz(4@Iyi7$HFs2n*x%80i1zatwTbHHJ;tfmORRuy@ZM8FX^fHz_e; zvOAVdpX+P+!rlI9RkR)Q zL-sA`amSIGuO2>}K2pk=fgb(FVsCU4j9>Z{dU`%a?^e>et5?Of9Y$lnOe|Rc%iH$0 zjPkzEp?Lwz;7mKQ77yIj0Zr;uM(z4-@%G;}@#5r{QA<{aRWx4>yBXKDZi#!I{s8R< zzK%s(z7s=MRyD<$`pFg@hq(MLpTV4w-6ix1+R3GDCnPg3`De=kDA@E_ES)k6H5R{! zP7Nx_F|BLy!t9!OcHA<&)xDC?NyF~%?nd|4wNU%YO1NR*2dLCzG~Ve|i)?t^o4ED* zrs&YQA3i#E6JDCQ6yFZ2XX;V&&awDXc$@H47c{6=0d*QS!5d2t8U73(Vzij{3u8=P znU_^G)?Yksv>W+dJ@9jkAKC$*-gk`*s0}e6}dzKvAzq)ogG_PG6l?qr-x!{;WXk5E2n%69WqP!`Pa3TllugZmT&b$9wc&GX| zx@aX_Rl6bX?q=Ola6)$9)s?7T8+DsqkDk@J1CofNCwLs|80O5_VnEvTyA_Sg7e?W- zHF3}V9mF`#!seL^u+8coT1+ngvdUMXZjGv_Te~*uRV^mt!(q&xv%|o(>)!`$Ym`Ef z%Zi|4)w<|*(^V*3>UB|>5*RF&@URjw8_s=CI0Y1?5A!#0N zR#)&&j;#qX(-n?(frjnr8a8%=NWgkHUL5$Bw|^YZG@Xo_>XgCIkAJ|v46SoIwyobL z#)@SmW+lgC$y94)D=Q-&bEiIv;VWxm>6%|Ktndf8smb-o_s|looI4uxUV8z5i?Qy> zOv0|kW6}4vjdBU`t*@av(2_Jm)60Vm;g+ZT=Ms1n0QLlcV%44e*|H%oP@n^hs+%+ry z2!8nDsJEWkLr3tDpHRQ^6X^KuGVI#*6>e?XfE~|I{mY{NxS^Q#cn6fd_HoQvV=cM{ zc``+&4e@B?v)HwFFMb}h2{#X&fvn4K#FWR%38BX=*|+S1slzV!wMCc8`H*?ya5hh> z-#vcDolE}4&mZ-|%l&2{PU>=S!3*d(Y!@ai+k)NSyo~yu_1GBCxm`Mze{m-!m-!gm zg!cN;*CRrBKVR*~qvbTZ)#e z^FetUTP}J33T)pciy0El%s7Vm8|UL_ayBnsFeGi7ikpUv!GY${$DK3`(ZP^Uc4qtOPKg<(T}LANn4Na_ZRdS!uGc=2RJq1WUE*s%F; zd_JrJroP%Ab9bc*{2ol{^DMsmqdlgr+=vx(r=eCs&MuE*@)I5L^4H}sdD&n1=IJsR zb?-y?P2QUH#I455BR|3KUEac9Qr^$g2Fh~0modT2%bkk+*XH7kZ{asMm|@u_mLY6CzZSnP z{b)-+EZx2vQ(o;UGG|w`@SXh2bRC=5|AoI7eT7la??SIPnxdf4@p!CfjeI!D(9KFt zu*L-DnMEEe-Lro-YIk}Zk1pMTeVb<^{oxxhafh57+P@IJUicQD|G67`x2?y`va8lxlT=nfbe!4)Kfods)F`wP-VWXK zjvNaY$wWlUilwxH94TiTnf4Gmm2Y_q$NIc)>O9HP$IeYk2!SzwfL-Dcz#@6sf1bBxFR?Xo0i9+^p%&R z_T}4rXI#_d5&g3nL4OOw9gT^2HN_s^v%0W%R6*7;C$ zI(bx@e_V7@XNL{Z_X4W7BV zt`S|)4vzzmcE|iZ_uT!0C{?5&V$!!^wmd+eoOwGc$R+_|TH=Wp>*AUT%P^{aXF23~Y3QF-_Yx>o zt{Un|yU(4!5dB--jzX$e)HC^o$v2~U+&Ek3q+N~9W$WL8H9v}cUcz0C%bH8oT6XFp zdX;M6tY!9WT`1S?G3@;7dVKu+VDxQU8@G;`k1^e&uz-`2CiC#xE6b3wLCTwZ4N^o8 zixjN@R4!s<&&NdJB3DSfs4t#q__cTn4z+d-|NYmyxTd(gZkSTVv|Fer1&gPAf-+Cf zMhm%67N~-Do$KNgIrSJ66oxW&ZUsK*kD+h8g&}=9qMFo?E|AXJ(+wbDPjUPR3k#Et zDxMCtE`?-S`pjk-{LgrfbT5q3wdb>qc)UEeOi`4TcKm(qLj1g>C3?xLTOp>A<#>2d zu+&pdc(Pg&4wL!?%Vrr}P;iLkS@#18QS-{^?qxKbfoGq)3#DRHQ04A>Fzky*r9I`9 zM+e_p&U^QC!h1w&(g)*SdK~p*v#?9<2qJIemQO^p0!I)z`zb6uUeM5wyu2PtuULSw zqyEOe?bgZB<8s+caBwUtH5If)v+(d!MR9MpThOjSID+HXLZ;>7reMz0Du~_A1;_RH zdv5}o$>K|SiLIMD1jC~rLAP7Fp+P=NzQj;j`jemL8MpxQH>Y={-Ok7JM~&DLWlNz# z@!nFsAMooRcc4PEQfv;9xoCw1_~Rph*F3Q;na8#_{n85;9JB}X{*Pl*50s6Rxl!e7 z(OGoju)(p~TjjxW*%Ll~`w4u!b}exCS2%EMH5t7`_ax7P<4(N9InAVgv)`L6E4=H^ zg$C}&&*egD9KmFXl|3rE@6{`!uY`Nw`VhuEGZ>w(Ey%BU`kc0dFF^uQqWO2pKfeQv z|EB)>Xy6XvP1m=O2DFPHJIr+EQ!LhQqJ^pW!P04U5MhUg7~#{GC!uBKC>b;(5E>bU z$b9mPiADY*rOfy4Si0hCnaARja6$}VE8QB1_#P{dnp?+IJcy$~Cr7bqS~5(h_?jos zNR;6SLU2Gu+ zWxCWaI2@jc2&qSsF`h|3MGR8nlVAEY-V>5j4PDlU`0?_|F~f_%(`z2 zRX*v{nAfsNKRGqS)HPjX&3dNDZS2G+EbB_gc40YObRb>U&E9^AQvdigk*&x#UT6xK zj|TCrdS<8D>64bJi^z>|l!Nlmbh`f)d{bFzZ%zs6@)hI+5GYf~jD!-R4qHy!|8(T% zMLnq}nuPeZ^YH2iv*hSs6zaF{j$5i)->E0^-#^X9zkgUG>(OE8^Kg6X3j|uKoK`U_ zeHs^?$lF}@0m}6QAt)fPJrs~Jf%Rs}*|;uWY+89yMou)45t@t9zCFa*WX8KP;S!VVcK% zEl$*|-44hNB>B8$1ck9zD_n*(#!xN^e_?Q`8hCR}Fq*V&j@km1>c!{r!_xW1sP@Va zMH=GY@;27!abMxncVEZN@AW`Q^5^&|eS5ky?Ly0+ywE96s8STMUcOmRl?_i9XqdY| zG$q1AX{=Z>^-zp*vWNFYX<1I+2WyjyGwp)bpZkqX8smm`UGdtypHO-HP<*oVfZ-pN zWsakANIhukuDoW;AzMBv#}CN_UxeVTzo?hN(K6^OKEn}maqE5WF2ql-x5k7Azn6Pt z(#;9LHXS;kN0*z>?U8v{ut>g|LLRutBhH8KjoZsqo=Bg&tfgWs{mX7QdF4?o_AGfe zDNh-x2L#P(zlvSPVD*BDsJ!(pw5nbfv;VQ)p;lNst-R8-{&pA*EB|VAGp_Sy8nXNa z$!nTSH({@@VTHBlGc72HhlI~m0NJujF?4*3; z%RZzfvZd4Vtf#sXJNsswbAaj2ar^&4Z3t{Yn3l^)}Ww*=sjgUzJLE2RNgWUkM?bk znqwAo_s42pIe=Zc%9W^j-Tj#K)g-hpUqJ5fy$YXgU4##wxf@$QdkuX%G{Wl(_nUg2 zOn%JQUm*E2pRdVkTdJ>h)cC2izrxa2d@dg}Y<`2h)-f8tz7~ODUBAXY$){+u!Yy4U zY^vDCOf+RM=#??y*sh+8B-4+=qe6VVGKV-y%TAxi*kAs1KDN((5*XVPU#w5affw*u zLt2Ipo}uWD4)TSgn{MiZdGi*a&y{lWBC-lb?feU04ZIv5_G*E0FD^i)k5|Rb&C{96 zPwRA1;~P^(dVm@*VWAPYrjfOB%{H>TW(}^E3!AJ9!Zh8EA0onxOP3W!`NhS1aAVCV z6p0PNZh0rIYn^DM1x3nANi0Ib^2>z`k;sr^8g_hBrq%zcH^wPnN{_x}epxB!6F)0| zBh1--0K4DmDi?QTb8w;Po4R@p%WUcwuKq6l?0#`E$=}CI!Tcx@6pIpK?`D|!v~3OX zH2aUQ%u@((iXTkPg!S7V8MSKf91I}*@$z&L@> zNrW>^^PD~(%uZN;X-+(i`-AnDrtnVRAFRK$qgz&B-2v;;9+p7^uTUX*hRQK>k4&i7 zZjVFSfnPDG^-E$jMObx`JZ!KgF~l*(26whqPJ*elSc)&*YfSp$LW>i*q#eKGYYF$i zqZ_V_O~PMPF`2|0`EiElE!!$HA6nn{Jhr|$1kcUtfPw8R`^wjH=_~z{rP=fC;q!yf zih1SakfAY3REDfGEB4^CKziH|Ht$3Be_>y@{iZw;Rx{&VZJ z(sTMw`ko*;UjEw&98O8ap4ICyQ)(C)F1vY@!^S_bEiMat7mdZWBX*)ngtz_7E!1B9 zA)HqxC9BESJc!KJbohPQrzYL|T?Iyd~S6+K7c0WG^ z6aV-dOJ}@>=1=ZIu~?Rwi9K7kAfozpcy!EIbP$d<+WMc?!6`qc`%6=Jr?0TQSeOPJ zcTZ`whRCKB!}cEyb9>x`<&t72tTB3p4_WcS^2LAQhsmE~DMczz-H-^mQrO65CKfGN zf+-`e!7F?$#|Bwtiy=uDBpYQc-)y>xd>Jk)@~8X!!>_UO?|FEv^D8Ea{3Rfpn+hGlVh%X(9Ox@?GrdJbczoTMw( zq8~o^>|^T-M%xpRk-rRDG$YtiobVJ!t*fe{cmcUsSuX4gINnXEYxy0o4 zT^jvB*ud>%z;T`?3by-NNRAwf|@DIsmJxx$yV8_kgk~Etb7eHnKt4LpBHw6hu)J z5D}Fnf{GvxKu}Z!L>USW6cIsDKp7$%$}YQw?)J5P<3A_&=DqtKuly)wX##!8O>#26 zo8;ysCntFpQm~*ivoe3NL#L-N!l*^Lk;Lu7NqNYbG-idJM)sqtZ9h)Rt95A~SWmI@s3=hl zI-yAjNpSB70Yg3sSyMOW>aP@+jol-D=xNfU&p zWRXc{f({-#ioN^e>F)&6tVMB8yHXT44`0vz5I^iWiNuSSaO&iKe6{o^9Frme9#d1E zw=)7pQ9J(Ni9h=OINZ`NKigAWPkuL%K56qCXhxHlsHi9uF4qnhpI(5+>O_$kb9p>I zv>cvp8i!KVK198#1H`KonDEwOB_|HPBobUafQB(q5ABU>SkauD9*uYz>1b1hdZh`$ zRXSl3P2T!cD~!VTEkaDsN_eI11K3ID!hLBanv!*&Z{XcejmkMN1fu+R>#^^WLGj?>Rc_U#~DiDzwJP zs-M%Gt{7^*k&KB$%hP#%9S0WWmhDX9MQQq1Aq7v*)W^`K6;Uj<9<~>4BpRJd-Ki{I zw$pg~-iC-RPP#p!ilh06T+H7{BJFe^eajbj;?1yUP+f#YA$H)G;`*xSy4}$M<58Wk z{_sE+T%Px5(ISYUOytb3eaCj1ij~tF03I8}VG9 zPU!!{G;FNW0dK5)5*3K~iD}$TFs;*`co6H$y@MBcMS%>{6Mrp?zn(uqCv@^~Sm>Pt zFlT5(99cC1eY(#=wdWsjiR+TTOotXxq(9>(@~~@CdGa`dGml6#8~7;6gHK0?x()D4 z-W^&wC$1s=Mp^i2aBtMDToz^O4kC5K9Weie4x~}L2p(PZ3tsM-he-qP!JWjfG`+X0 zP`GE$JB%Usw?p}uGN|2;q*U9D#f#mvbJ316<%6F`O!e|hT7F-Cv>;Uw@Bi{PC1A%J z-D;wEY;`>Pb1%&Kp(lz`87j1S4As^=fpW!TG3i2UJYJRBEB~V~|3bQ(>g61hiO-rk zA5A`a6qSn?N1f@rgkm;H<63^LuLQ7w3Z>WN`K1_%&(V6^H!xr2w+1CTV)vJ?;H8dL z#rGfk|JkZ(QQOH`>p+9HIiexlBROLs0(Nl z=Yykk$K1XI762!OWW~Kvt+)?<+(+WxG+)o6yL5f_eTrUv?l+{#$!Yl;ZDXEBH^*k< z^y8;ngWgJK*Ryg-h>1jD{rD_|fJ+mV&dcUA*4kNg&*e80J~sG}N`60DA#~Qy)y=eQ zoZlPz323VI#|L&LDA8 z^1n<%q`=EhM~vwB5bwCb&+o!QyHX(`v|w1^_}|R-n}^KQ9MW48;#dm38vMFy@W(Xh-<&JmrlP_WyUm*CX23ZjgGEm+YuNTsF#OsxuHFg06JdhSgQTM z_|uh}If2l+Q!*BGz5|Q8ZpPY&D~aqa*;FR0rrXC^R#|#y|8x4dx&CkdJRdaC^=9kD zz1E?jp^knc@}tW0CK5A9ax;nJ%d)V|hW(^rKYuzR!i>DbP_#_adt|j~Iv7GID8=l9 zKw2d6p(7ETK8JHUyn8F+lD-CZbG})bq>G9E1+r9X4(U(wiGaU%p4c_!U2Itn&X3*9 zn2K~VwLFdGmt{-ONEdN~gM%IUi`{S99XC^Z@$)9-TO@Ij&Bq}vW_tIbbgYs37H!kJ^J(%=V8OwfII!5|DIzpOB@APl>UwS#hNX(4i z8tHdgzU;weq#KTW0=4gw7FYXzuudrcR$Y;v(=e7_e`oA1&FxN4w_I@z*)Yn~#q{SA zv^rAhjxsoK^rW!)na}WYKi8sYjHH8{yAXw)OSYj+B_HbOz+dNV@TLyV!$*9g4Ka~+ z)F6dN>-Og&l$4*bk@*?(zp(vN%=&aKQnE|q(KjZedayR&aQUv3zp?zF6@KyZ1kLrO zKfGiJrqkNcd;M4`TqgcpF%2KDJ1*+SKaKiLAf_UQT&Y+;=Q*t0t?iuKBD&z!DP3v5 zl8uIc`hiuL{MMJ^JO=wVd1?+Z9(JsG?J<0N+$la>^v>>hWMC&0qcgJEM?S^q`9XMX zYF7l=FJjdT&)`_=DR{aC?*cjpnp59R#k8*varCEx)7e>~JZ+A3`Iwu~fcm+5R}H^kcWf5Pe{1r1r?)AU!=9*Gcb7%m9g$^Q6vb z^hd@t@G|;98rz+b?RHWQ%L)vP#_;H={(W5CVYcJ9ePGQ z(L2kZfBj|RSEA>I0v2^p$aTjIpFn8O)93fY3^yBQfU`+=57YC`FXx|2N`mRmLb~xF6S*|6=Vw`F zWByE^MH@<-9;ah0KbOstWpU8u=z1Y933pP3|3S+O7ecZ6}dGFcfh(VFbU$P*s2{vt#Dhw0h4mtW#0ZFl@x3Wd@!5 zm)>~kA($Ft8u^z9^}*8pRs{R7k_Lg6h`Z*n6}_tY(Imo3I@ajA0!~0T#{B)ls^Ebk zMe+X3ADCFsax`cDIrw(u5Trdi2YoAP6LTZINYYSFjnGJcdHFrjA7AkdUdtJRIsLR1 zP-p(G^mnwMfGIx3gf{fkKfX>3w+&BDUyM3*e^c_l&+zor38XM&HahzMiZ6GS!-V-S z;ST={oIa7^Sl!j~&%s}-mZNB&X_(X@7MYjM;H=e;>Tibk1!CTxco&b<4aB7ryD)$J zTX^}5FJ2pWFMPNW(_NNcq-5;C!m(Hz*bg(>l%Z888i2X-Iu<7LIpo!P4DUWxn?@;K zS#<7JIO`7-Dc2H1N(ExZGD?$Ea9}B4f@}R5ZzsLpp&T^M{Dqgn-`IW>y=(uI@67oA zM7x$h)*K|HWT8RvFq}V|26IsvpxXwVooP{+!QY6#8};>l^!7s}oxyT7fvD4?ExeCh zAOZAHRHC6}^Tm|HW}J0Hjnpy8C$|r25F9$NCk+h#u=3V5 zhjZuW#!UY>u92P_U@(b8uR3TGR}%Pgd`eoZMv)yxV%A^oqt!0{CkHd~ch5hvLM;@s z?MI-Vy1ZXl=AZE6Z2XW-RBu0ygnP$ebjLt^I&K{PNamDEq3=sCp?(Q}WFKFNSKp6E zY5%?0eWpELnbiW@=1#$?Jt?#l8$@-ffF~zEjq*Vj#IJn|v%cId=zEMEi~80LcynC} z>9~9i!%lX`tIu^H&5NGvfBKKlu)^LA!|w^kPhTEKwTEUQE-)9#q=3YmMDCw#upBd& zZ^6BN=-iR%7!DmxL7~!q2rkTGMUtW^azh*m+&xOJW|fBmI-~694?(zX<1dCK?50M&;%66W7x^sf!Tt_EF(zpt?(yB96}=Ouzl)!LFeypZ0aW;__V;(&kL-JFU(fc# zJMlqbbQo68hiyk$`GL&!%%9U|5o;k9FLs4Ff7ddI{CRf9pLDnJOO}nx%x?Ox=x+di zjI|JrSKl8;e_>46-01!z^Sj;h_u>Nc6-|Oy(rxa&?9WQod`P5$uhk{{ddG?Jb{ z2qdwN09w)XB~6IhJ}K>$lE{d5O%&ht$ae*@as?hqE>DXy;9H?AImF~^5yWU>%>Rxy zebJO6))_Jt&vdE)TV4Pf4|x+Gf3gVAG(C<58;*!FvP$RF7_p?gbD)3sxC&DZg-@$MHkjQj9&OdnDNOK1Fm+?bXa*2Euq^&Z2FF`cyQ zgY&7sCH*84F46gy%riJaBV@(W+F3R(GcQ&|*KH2dv1CfK4f<9|!;&eqd%kijGI(>7 z(vsOcY`w(Ez)njDyUD%n0D$=cocAQGdgpEX$ye}=m z^jT}sYsxs3uxbo9$K~|J`y{tFt?F7fOvclXkHYe82^8p_KYOs~5n;lMEL0aGJw1s0 zUCV4NzeX?H4?QV*1OC^FU!&?}5K|(OuFWEimUNW|H49~B4OEUM=~+CO8EL_!G2*&$f0q9ILYUc< z^q1$a#S}$hj-6g4yScQvqzN%H$d0_gND{3kAO9$n3_c<>79ZK;gTi-_=qjb{Mdw0n zw$2#PI1WB^Z{4ZAXHencF$m4gfmdu56vl5N|D@wbDfx7KHSZl*&h4OsDaB!--QbYG z09r&K(IY_X1smP54t(9=NKB@ z9WDH1{$j<0$`adc3g&jRA@Sf3c=3&K2rd2|?kPp$>xTTD?_W!hQ?|R|?_Ph;^v?Rr z{Iyc@FTZszzvfc(i~vo51tx?F17m1E62FjOKU56n)p-p+ayV&>^z7?_o|AQ=?sSQF zF2dB0Lg4m5fWIH|+aks}YVXF6Jco&K*jOFWwX|L!X*gKA6}@wkpzu@eNA(})cUBA| z1w4MRk}%1@8HXvxozFQ-{N?z>GX!xA&oE{&os1{bQ1sUiKW4i5y{Yeylh>2&Q++?L z?)&MZ?PqEL@^nN3C^{}pT-X@>G%u&Wq~G<|pV+@-A!#->UcxKLJ^paRtyrlF?S@nO z^p8LCuK8-)53wT z-9q=!nPADK-C|0_O1t2sE<)s=b14C~LJd&=?%JfdqcQFYDken9Q)q{tI8Kq4r~Cy* zj@r?VZ(ulRj}ZqF($KhAgjiJI;Dqfz!e07eA$FIZWkspR{V~643jFze@o=v1|aGZ(#1rb{QVk50}FC`Aff&Xa2XLValW-V0-1 z9*PLIsABSycV@oC~$V-^It;aTP(=|y-x`6Gul7}IqC z#4t0X$i|p|E?tY1OWF{*92fU*CNc2gxVLs3w*8WY>|*RK%OJ}igi4JHVfmsjurKBw zoL~MLrCuDQz8z)jwSd=;zalrXH>!}PKa1Hc?jxrRkWIVdT3R_c^y^w&h`Jk%D^Vma zx1NX02`GuK-Aj^~Ix*7~Mxi3{!x=}u$DA!bxMy@DcwIV)6FE^NA{>MiUKk*u^#Hy= zp3|Zy6WzCb`tVtV#FiyOx>SkP>j!GrN$_5GZZ>H>w+0|RWgnJK_=J?A4Mp`ZE8T@h zv`KU=Lh){RWx$_!;oY$)HsLMQCuW{gmF2Y2y$dE1O|n|(!upGJH*ztp9@eD&_+e`b z>fh4{k(#1QSXg5v>5wEnl|;`=Bd++9rz2f1yH|Idw zC%&1Cx7Qr!B(dQ6M{xI(GtrGXSTZ6HTL2pLy%Xc-jlhX}p2G`GyTSLBX?W@nplsy| zu>3p)-`)8xT5#-OO@BSpm25vAeJ@PI2UDh_dW#moq5UL)PHC2EkLS7{$7?S<#96== z(Fw0i?uyclyTX^^4nNu*Q(kJ0V=KSF*EQ}yqYB~rgpMK;IJ9y>cOPnHD}2vOcFg|7VnOKA7$Peg5vas z<@-Cb>RHVGNn6bDuk`@NRAyyzbbkBdPWJzoo=7@}MiM2oSZ1RID@$Gu z^2}MZ(36Ymk=bZdyC~w~;!vEfAXG*n@J|u2(tWa?j2JR#z>rLXr#M&gQ}i_6D*ROY zp^jjjTwbZq7{gTmxv~8xDJcmTE?mIHix-iWmWFKFm{I*#jsNQVcVovdJ|+?t7KTEF z3Zq!Dq9|OraK7WG>Co{D#M$UOt=wD5h!;kz4*QCMmqt=%w&co}h(&Q_yn?3pC#6uq z0lE%U$}BZKo6cBkXI!*ANpX}PU3^brX%_miS?G+nH|-Pq)4r?~UbLf|LKh0s9xW-C z3L-7ynWFr*>=fh$6hX;wKU_Mr5+f$>z*BEMk660CjMEDtCX;R%M1Zd!QYcU6_6kwD zStOR7otKB?wXfid@F(#|y)ZGd%K8WRYd5c%=~^{5LH@q*&C5b6UCR{^UIitVxZ&v&JFXq2~%}NX&JXpN)fBLgx#R_c9sjJO8 zC=o05Ln|@fd3o6+rI8IA=^uE#e=K(I-i;bHYADA0p91|Kr<*r#9`3vEKK*;dU}%G) z80!q!h<iHKteku~76SVmvitg7wTVcwy#O`g0IE4u2If#Bg&- z`5y8dJtW(#r$Yf+x*U*;w8EXx`>sNS1BDyv&&;pUWSUttn;3CYx{#e|$e)wB;{3HTXlb$^zpQLg zEh?9l&bKpOI=zMJ!VJ1JDa7bsZd~y<)?dbTzH2VtKY#z6o}$0;_{sP9PiqYuB0wEat_h@~@F5`%9xV5ZyO-(R%Bnl)>R9dA~s z$c*^)H5UB2{Bxw$?SW=7@)qH1$wLXq zU?fr3H98a9wr#s7wry)-Ol&(7JDF%=+fGlciEZ1yJ+G}7 zUTg2=%{Gg({;wg1Xa8_APiH%i*h1n{7Z{;N7)JT;g9f z3xk|i+z@;nxN~3cAp8I(!)2-^OjEO+i0cs< znN9oyxDtLpp|(z-rgGvs1IHT(?dk zr|pX|)j}^je&^KrX$4|HXU0Bt9>XjPAWv1}1wNe}(;Oznfp^3eT9Fhh^z-VqJIT4b zLrfa-M3|G~7s$8mYk7O|>!fwQPkvz|FNy(8_FpJZH6)J5vy}NPRc_}iBGyUCcw@yj zj+!+Fu@hO`(IZ04FzgNQpgQE+SK9+eYi$izpEX-WCuJzD88BC<$QN0aTCpimwU_7;)q8zA4i*DgAsr6s;KEFOD5ge0;C*3fQBVv(5RSU$$kr`-k1+WV4EloC3z?FXo^|I(HH zB9;`vjUZKXG*(e~Dnh^Lbr&mJ!W?h3tBKiwh;05#4q3XN)mS^+IZINj56(O0u>cfx z4__!-j^XfvWo98%g>NYul+6oQV+99_Vx>T&@cd_3lmE%g$5WLhPSCL2b|Mdf52ft)*!{4khEFe>`WmqLx< z-O4fn1D$64s_;dT$&9>f*Ny`Z2W+M58OSH|jc*u~v!b%OgQwUR!l$=2g_nN~m5ra! zd^l-P;unwTYTX&Wpv36{as#}OyQu0ry`R7se14FafDf7mezMF>MEBUXR!O&bOR&kU zu&q7Wx{f(okFi*Hyxul=r^lEgxWt?KaJ9!aMr}k^@k|AYWkG0j>v5sO zNPXd{{-7=O-nLpM;<`=vR)xO76;+)JaR;%Fympa%UaKZ@*adWNt&`%mYs$BFs8DhO zQmT00k!A5iZchi_m!7ALUxm?Ls=c2z@MWFP#aMj;jK-ym?UP{3#h${i8`AjQ>y)oC-D)+r*a?de%{N zE_O4F3aP_*-trwp$J>a1Y$UB6AH?G;vcwJ_0qt=$hndkhJ!6u`D*U>BMCzXeY7rw6IX6tK4F*4^+sitDnE@$5D^2x?nHg$I6| z*&C$3X-+>^G94jxZ2b5b(Y>^W07*?Fqjxs4N;3p{JlSA>W25IRQC8;-dmmA<`H84n zsV3Z29-+En;y8SG)dwQyJTWrX=ZW?%1O)3~2gR6vUs(8SB7@#CsO_ShF8T#?;(@3Z zV1Z;B|MhsGtfP|walx(8UHLU;#B2y!u+L6QPV2XEo=b{`5#D;V0m+7|N%cq*^yp$GUR?vt3o~O3lpF zQL0mnpF|6s<`XN}Fqg4w#Y6rIaKe_Dfo(E#biD>*SD(XT*w3pKh6I;;3Q3HJj!Y3bC8m&^Xs%`WuICapioNOZhQ zp?o%XoI&HP0(ag-^MD-x)_l~f5%5}IDH0jcI5sXQsk1ZcY`uM`tJF{w5Mc*PzMy5= z-oPG#SVPCO??Ng!H40uVH9WO@@m)&^BlJBK@WB^}L^&3f?juahcP|_ti1?-8^1~5j zlsyU0i(6w&@$JAnZ|m(t`l#vX*Agza*w?xvp%>Mn#x{IZ_lKb=bgzOS7{_7_6#j>fxaTE@$aH=)8W)UR434B*!7f>oi7206K`mv`}9=&LD ztzi1Bnx*VN`3lo`Wdc6k^!TMQs+PP)5?PM6dOo7$J1Z()If3Mn-=h0?&RnalS#}|} z-m>!7sF7?pJpD!w-pP)oDV#~%ro}i=v?qOatu~5f^&d=D6wQS(mW*ZV)@lJ@=L-jgj&Uy%z>lTK{$3r~8RG1Y zPfon=D_?&!{dNyS@Z!eB+5*nn;*25EF8H<47gaXTHoyQQ)q@H*ffD?uOG2CVC&$#BK%KBzTRaF90&Tse!&X;HEk@F_g_)Lavilq#tUZj*VX(r?s^=t>@Vg!DBr zyx3e@N;3yE1eif*8ILo(HbVFYGDQb3rg{l9Aqq8s=svqsW48fzk51Zk2m7`FkgwBE z?SbIUFGhaciYK~KI@_jZ>1vEZFw7Rx^BqMq$CUK~?Zhku$* z7}I;H-v%50#O&S(%h78gV@a~Y7~_KSPCJej9D69#iIp;GT5cRX?9li*Z124B3boMl zz@qb)CTN4;uPxCm*B$E4zP0u;OpiB%f?uBO%D~vKrBpEig=>G`XpFLy#5GdZ0&Bwp zqzRiKn@1|&J@V_F^ldAe1Kzf$-RF+0UM~eL_QJFaVfLMt$Ee$bsRG-r1}`biaRc`+ zqPlpl7HadsQ5*v&1BL}cIfxG0JDRp$)pbOUZ9^v4vlu;(Kg!)v$~oy_O{_WR-XLw; zSwOP27vBCEA(^7xNu*W+7Ld8sim>VNk+bsO^`VmPrsD<2oiGbc|oL+3~B=PDx*M%Bc*eRA2r zTUbcchK7I@)liSxUXON^QGfYzN_QwX^{v3QTzVf(iEdPzQYjnigF%?}( zp!9g!4*%5d#$umsxJ8ko|GcOO$8zDTzxA=!{Kht?IVlp2yx1r;=h0Hze$=`dBisnj z6r15TFlQ~vPtpie&E_es!@@Ps$eZO};44M``?MN*kz6oGY#Cex^|=M!l2k|M%ROR| zR~xz45An~ARzv;r>bir8tZ>lL;pOF#*pW^YR6Qy?V_02uQ64ZyPWy)8=M2h#TZxUS zSc$iJ<@LOwc*=GQhC&p`J>3AQiYrBonjG1dt5<}vTTa4+b%2NlN1HvL<_H~wI?Ml= zE9AYSb0CkJEY35TR#n36YRW?6Ir;ogT~d0MBUjg*x*@rxOBQ)2$GzNMCoE#1>2E+YxrT|@8pTj z)A*;eCpua^vSPs2?iTp_CfDOm5#ULssDgHjG$;@r1sF&2+0FL0&d`arc3={kv@GNb zL5v2Sy>5)d)Fg(#SHjaLdj?#*qNWzjt0+S4ZV?f@C z4_z{jb~dYus0lvp@ifu%RufC4d0*?c9Z|yvC!V7d4fU$z`CQaM4(GfdD0qwsjCWia z=ktAOZ1sz%A!EZ^Fxcq!_2#gi6+5$U04w?V6UC|Kakg02>ETS9L9Z3%{pDVCB#|<< zXte5IaDW;@YlQSOg-Ks0?~~8G9iBm!9^`tz`9g0Pwi1NL5%rj~a|!j!Kd!Dg&lyjQ z{W`BfSlL#f4&%>}NtFgWwBDN}kyu6GKmV>QwiL0;mCy;wn`6x!_uUM7>;k--bQ-nt zGLTTfapEnA!?qMd+VmrPyxF(QrnyB%iMb7iXH7;Hd6f7p{A_RkEL_USm;Z+3&ka5y zzNU2d;g}XN1~}yQ-?}31_UO3C3q*7P6qTSxJ-;Hyh(8DiYW);Q4m z-z&de(nS8Bp;QMV3yn?iuY+>gaWJXrHZpldM48>a=ROuZQ9)|lp_i%!JG)T!X9XozmJ!*H# zv&v~I;&R4iEV!0fFAP?e-&k^o3u8n|jOhF)IPFvZrpI4Hw=eiQ*b*ve(LYq`CVhjy zpXc=fI})c^or%LFxQF^Bq;YUszX}4GfhDi1(^O=Hkys^Kf~;A4)gu*z_B4YGW?GS&y}GAmN@cV+}%-@!aP=@*9K+K`)Atm z(@wq_vAOuaE$5O=#Q&Pa|F`M-uiw+;W=IIc*;*TVlg*+Vjr<&qz-PUc=VrHWXsIVi zOGHporTgD34kYb;&wQoHJB*8q!#W=A_FGT4*Y?8V{oES&6j*9Nujn-V@d^=w#3k^Z_4rtFx*e{BI3PVd;9AhT;HpydTB+vuS>&!RH;nf>P_+&{ zZO~j|Mw+))lQ|xmw#e`i$l@}~-dd9)B{r!3Z{*m)YC3O5d)mCp?ORa5hNa6pblJAk zBBSP@2XQntfS|3Rc+Gavl?!?ki05!m+%iE#Bx=9+w0(JrjKz4^u;N3gRVNP1yb@hKlBS`PUOBY7i1V-T-xOl1S{88Oz8d z{>9@ZL!F1edjB4Jr7Q778)PFvvsD%qWi!s_go?UvmP_Im#KN|0i6OT$ZKVd7wt{@I z5iT-2)7L9dJ7~a~h?gab>}-k8fIH=#-oDp6;V{^qB*pQAwc~7tD*E#n|IG1bFeo<_Tp|CM*k;sDnvI zmnQkfo@`l!3bWsK?IN6bZq`XzA96k#ir^9ME&HfyRYJdtO!$4hp#pGQn3p4hnsgs>}&x7Wrq!`KAbqwwKtP3%eG-dJABL!$#FNT z{~bGGV&Xod+hse0FQ$}Xwq|*p?eN*h5BWLAzY$M=c^0_M?qwlU)RHh0?VN#@-Mv+S=oK~&I8azndFEW@-z{tWCb=VH&r7fnEi$ zuc;Ae(G7R>)YX{=D2L&3@5@*2V#BCJJK+O*8DGQ|)2ID;m6bql|A4;ueV(rSo6*qs z&RfO}RCj}U|M{olOSSUr*Mr#2&W;@74@fV?$Ecca$wO})5()+!-nLKwA-gemMU-Ho zxH~hzN?Y@+N8e$K^~tU*b;t5TQmyB6q70{9qB*-KDaVo=-t3%G&w7W+%ic#)LLx-F z1h&vu(g>JqpO(0xY+(V9h*ph1i3wlfhcGqg5>xLGx`Wd+=wj&6EaF5pF+y864J&|$ zo!P=zW@hQ)9}0j+m2%6_-m1WF!s~OsHh(2jb~fX_Y|d5vH(>og#E!sK*stV7EHsS2tg=M|KR+h?#c!cG}j~ zH+l+DQIJI~9n<4mB<`zs2uVO?;o2Y%j)!=25beJ548jY{(kTApj({fg6A;Grcy^z7 zj!xu%TK;YL&AaC z!Nc2o&UfAU@%8eceCJ;{_5X3D|E0QY4U;&kW?YCU7v1aP{_hX{@5le1=0E1CwM>rN z)XVD9Yp>{I2du{5LshMGrGH3K@c+~Ge^0mEM7Mskua7$}mZ~WLW5tKN>Q29~Z$}+> zuj3`r)%<6i{^y_hzaOxb?BC6F=~|F7^Ao12JcHRWcbQ@BSy&pswjYK_xNJ)=hQsbw zN#^tGya$7dHiIAfE_p@N|Ieds0iyo#1W<{I+&)_ zA_69v*^np{-mvna7j*JUjm>!it-RR0mNEO{Hh!)VaAx+vvT~ z#00td_d#3l1iQ)5^{k5vDs!7(r~Pl>wptAbl4$~R2ZT5}1-Plwn{>ffeXr;<#iR2n z;)%4n{~13Ju>}BuM8Fe(POb0@RIRa8r5Fwj96Tol#a(%}ILWO&bGC?a2XCFN;4Z28 zZtK#kD%#((m{y#1H0on&yJHag^xwU?lO9X^J`d@85##&(6G(*; z+2HID1ZJ!@lTuMhj7t(+1`$C|nrwM88*|fk^9e56ApL%aHSzFA`{Za2=sg$7-!refL zkEsq#-4r-#jbEj#_xeAx%O4UfGBPq~+x~B9!fuCY!z?4tU3`Y^E=9=tO@^KI+WQ%W zaxn<2D}OKjAO}Jb(JwLPEvF8zE5;Ike^c9x|J-;Ce%?T%l=U>VV;?8(9 zQrj)5V;9wh`x9vxFd59*o-LZU{n6)gJt3*6;zd}Ova^@{3a?-oyQwYVNB}z!+UN(J_UxqOtsNrk>%c)QP`|1?jheR*0E-CF$mZbH94R< zSh$Zf8fQ-?+Ie&UUPOmq54V~gz1pjaC2of18Hk0Wiq}!Hf)644#w-n+Dsf+ftI4bc zjb1icBZ!m3g$hSltG>#S?y_r=zaJIS8>} z^P^pe7V+XPfBj&|d4-x^0R+dpQ|6oQ2_eMVM}@{Fvan36;@-!A*1RWd@}DWWQ3UzA zGswcifmdmKgwTrJ)fi3M zZ_boSD7WyILC)fTNwig`E_G&@;WNJUJfT;gwcSv*8)yr)MZq*X+$LBcKvY!Xw@y4T zEr!g32eSX*10Nm`cXdaOhg6g=R? z?P`a~S6&ZShCDC}6t5~6f&++r`^Q-M`;k`nskj?dxtiVg^rzrJfSWb*bkbEb zDq0xGC69`OAxE}-H_wK{Dm>aHh2TmO*|5AVZrQrL@Ow~$bjN}WU}xEngr#q}E8ekb z??S)rALnPN|AhZy;Dydw)nPOf;L_R?)zS>U-VDumUo9)=PQ*@+Q#(G=@J?Kn!@p)25EpSW=S5Tmh~?N$$_8)?vIOHxk+iq
9at>1x~1 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 z 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

Q$C1 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

&|Sk=}$g@*|yjqhRS@yk{; zj6+IIGQSC!=+}dkL7z3H1zxyOy)G2Oon3Pvdy|#@c7MHG9a`L+nE9aayOC{ow4w?W zqI~}0hurSJX-X#@`@=TUMbfxMe3U1gno6aK(w9C)fqaGQY^fJ;A8J-T9dZkJB&GKT)^!+z>t`w?btf z(L2UjYVD_SVdZl8aLFa2%d!CW?Z5B$%?ZkIf{IhfOKwvB=|EI{GA#gXYROxiFqn)V z%_pju-()r~HiJ$RN+Zmsj)z{NkF=iWY{9odTnlyJ0@&V*K}jPx8lgCoF(DFH782_5 z$G-9Ui@b!roJ+J;zxvVsK-j27{yUm(#C5u1j&?*IhwP9W_T=8daNC99Dmufr#|JhR zmN9TR=47Y0mj>`P$}{l}x575>r^jw$B&nr`L2rABFQR_95p}-@7bC$w#pMJ8b^e%| zUz7(y!6`;Pw1E2eFsQo>hcPK5hm8>FqEYaI!h(d4k076HYOk~Q2CrxSjV;DeETmpO zDXu*2=U-|~`k^fRKd?}GO{Y6o1RUSZf3}mOOsjq7 zZ#w7s$#DFmbS|;Tu{4#BkNrO{L(;rjS(^!DPLKR1bF@91Vmg>Zx6oLx1CjYK#fX}B zHd*Q{J_~{V{^nx6l-t^ek%)6-**7JE?Hy!KPjSZ#^7zC=HKT=~dIp%a zuZiK>#`APX2RO7uRvjZDiFkyRA_^1|&?^^}a$L*?R5>@51gx7Q{{@VmlIG+Oc5 z=(SL_ca|=B&Ck-!Kf1+&$zRED`(lq4YHG<^;{#qytJis?Raxj{Cy)SHhg zzmdV#SN=SMitj9)?}%u5Au%~b7O~g$(5u1mcfb3W$2cx3mAtbG3P(OzoE@SuBr5_E zu4(2TcAZ}nPN69`4G5msL6kWEXA_mVE&MXC?m$ z`1#$`Gd4y}g~@bBo@dNgOb^_&8}CCtg*21oJfqoOw6F!Uu8zG%RWxkuV?c-bZmwsF zYm!q<7{dP+bfeK0o$n$2h<>af3Qh)WNfC_qCw-N#9Bphe#Q%FuM?y^Q8DT2Ma?w%J z7RZ2=k_6-rNW#)zPDN4}W|128W?r4j*Jw@3y8CJgW(mevy)1azi~rAK{69a_;Ne`R zH|L?0_OpB#*{@RxSlU259r|hN#&sHRo@tK`-Z;zsJ8R(wEdEM$zqKO#TU{(HV=FWf zkM4#zK$pI8W7my)jnhvK_?}9Hg<6UW4v-Xe6;Jy*=2pOgYENyP5nwH-!%MnV`JYQG z&4j)&o}L!Ys2 zjGHzJAuMUSY1(ZVm|F8#?>OdsaO4r6uC`!-Kkj?=%)9D%0A20+8=!}mJBe%o+w;)o z>kPT2+>t|COLj})7u`m!^zDoQ2~;dOy%^(R(`2nVW6D)tn#o<+o#%8*r4Z9K!+pbp z0N(kr(icx2HZCr-`$&0&%!sJmC0zGNLCXLQ>WcXfA3=8)?CrsA84iDy0FI1_(pI-H|#*1&T-1ze$B};s*l6iyp!hv3gqe(UHW}-sgrXmi(H03x@&4 zf(ojBi6;Hs5#LQDZ&;tB7$r>e58hMxH-BX;T)g<~a}#i6h%thw%5T)_lJ>m(ep*|)1@R4x?gGEidFE1S2K=ftXHVvXr2EIaK!=<3n+2D?24$U=zNf>#=F*%KoJw?ayjke0<_&U` z3!3(DV$+OuPh^V^e#3w#TpD6)50}I%1#2-RyI~Xp0F-wxrA|e-V>O~ul`BFxXIWIX z7P16TE{ehi%bZmOlmN0Vv?%z_mHuTj-S|tAH&A398vSAHSsp?tbl7|;>6oDQ1DKZM zdi;Dy*a>&AX=p`QJxHkCN?#*|el+X-4~+=Zm-9Z=a8Gz-64FN0bt-&C?I#i@YHXW^ zJ7t-?)Ps(boyDm3sHZ-K=Lp=#IgYJp`H5E2&Sc(N2}OgU3sjN0a!qor*2}>}a0O=~ zxw4dmP^8lYJm&8XnR=s3`wPaBHcGf`-eS@SafU$X^ECTDB1OKp?6g3~3^~oTfzWK- zXOj&Uc_L~ZKYaq>+}@(TA?EMQ#v&ujSgNV;*PM87PCV6y?YoL4z#nlV7~!b1+V;5U zN`8X5Q*l(PXn!WjdjiGh9{JkY<_>`DA7*1qVN1l0>jXzSJjgq`i zAk-SS%-TFBgq9Gn#EcMKonAT1XKZxE<;nv0P?I`bfBkmxT8Iy=2Jt#2T zxg*ORg3%T8dyZXN&WNkLt7GPBuV2*}1w&@gXudy^KfvC5|Fem6248+c2{wSc&a<)`;+;S!7YtGB+{;C6RP&fTB@NJ@(iXpR_X0)iA6W#vIG)Jimy zO$P2L-<9#qg^jB-Ei*LWy9eabyWh%~|DuS7jAXb zyMFpQmu0D0AR9|55YCf3nm*gpZ&{HWN#>c9zFDs23)tSf_a~?%Wuft=GOb4p5W%Zh zix-Sa8@t!t(aO>k#gnld$YMS&7ozUV3pFoPZ2fr zf_?Hf%@l&s@Eeae8b9C!Mt<_(Edr$R=Tq*euhi$#;V`DQAVWZ=>5UyhN=Dcbq`3V+U>XCpo zeXq%yZ9*Mc%i^>D@sIFedrZ)YI?jkL2w72c0UP~Fr8E!i&#vs0)GInIu;?SbVIQ$S zfnzqA1yzfYYInAZHD4*o#8qE|3j>LzHtE#9h>mD4Jo3F+|5r1pa-DAbf?572T+!cT zPKoWEHjk3O)Zd;b&v!`v>^w43H)SoqfcdRi!60%B$T8dgtz!d;g59b8F@#B27@q=^ zFop2Z3r};O1E{HSUGO%Jz8X?XvHcGAseLE2Z;kSX@7Ci*C&yv+_B5x;wIze*J{Wvm86-~y*{Kv+MOpVx6}|sz^|r9WExA4{NZT)?RzJ~ zmChkKV@4-lJ|*twc5uKoTk6NpUWFZ1)%;pFOu75<)Ql=l6g`p}CocPp{%ugi=@2Yu zgBm+8ZGBq*pj@`kSG9gA+=&$-@+9eY*^joTpRmbxUZ`$oXE3au6?a(qOrG|H{~G9> znw-b&yPk3%w6YU6wlp8;i|LgIfkw%uA1Q0$5BhwyChfOoxsp$p$>C7xa}Z(p!UBU< z#RY!zY6l)BA-_>*^hsqof8trBP1NtRps{~!7B*Ydi7lw;jYiD4A#KLdpPrU86oP1M zv~i1Q|ECTrNRnbd3E4u`fNt~dEa@ao;ZsPdh;zcO%aVWl&kcs}6eC%>n%>u6U|Wj~ zny>Ghj@&eU@H2oY1R_&){qD5e<80Kh>*o!Py^k{o6tY4;^@908HXjJ`<{aofkr$Gm zvOJUkAL5Ez73|EMy2o*SSpBXeOrKt;1)$?!(M{%NVqwKdeAtqG<_m@G>xTrePZ3yd z!$azIsc-0@b zrt>b#`)wcHdu}|q_H(bj5+F8yA{+m>2W`o^C%dWi3*ErOkWT|UL#bAudbRahG&gK# zc(w$UtL2K9@9UtGOH6G6YBTQEmZDB`jE~)KH`)OP)nL=nvR|7dIkTti|b}fQ=VTBidtcR-od|fY8QJKd(&+^LaJGoz z)4?vbQ`0<#Qeu>9xXHpXmz0(GLAaLwdTwqz+Dg)B0)-Y)y9$MCDXuUUFvWWd{Fu_J z`+~WsN~UegHlW}vq10>^t#?|oCm_{9*dbdBDZXC@mOet3EwB^PQsE=b8YBn5MTGCa zbr!~FSc~`N7p~Tw!i@I=XA9k_Iyei889Th2&_>ISe=~n4=X3@cjw#D1`|PcQQzvFdA!hqr1VXMR3C$VFTh(H|Z zV|b4THsqO&$UQhDMSD2sPzdVzwRCFxii9>n*o~k%Q=l88>_rMa$2RY+{fTinvhDNz z#n-_Rhvu4xj)0Pq9Q;!7nf|Pav^mEyTP}{!^4*MCIaV)I0T3Ofi9Iyf2%KUEzyJKO zC4h~i&g9T0>2Wi)Ra|eR`f8j0$M9#By;PDB)U`VLqZdVR5rQ@N5oz}m&`e)C%@~4{ z9|&Pc#3*$Lg?s9;fPKe)?V|#I9>&GfS&8_~rk~h;KHh8sT6mF?+n&Vk&y)QJPHbg} zPJ5im7)&E0!~{dDf5J$nn}{3)1kuG42`l2#QdxYzW_@1FETD)yfZ&^c<@kbKTv&n^ z4P=e_KI!g0v9B9r%C2?;k~^kGyF-^_ag3xLbT_vnBg}V+3NTX{L21O~7N_f#!oT!i zOu$!8VFYlWnU6AShHS3o#jdl6ZyuTs_uDt%;p(sctkhRMIqIz^n(y?yg6Ycemu)

ds#>{V-nMs}gqNDQp!Zc_vBz|J_ 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 diff --git a/docs/XcodeLinkBinariesLib_normal.png b/docs/XcodeLinkBinariesLib_normal.png index 73ce4ce1afbd1df74ab55952483cd82f9e9a0da5..e1c243e45b3951f1fbb2adeb173a1decb727c4bf 100644 GIT binary patch delta 68271 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 PAnZ=pey^1!r(~9bof*`)Z$m zaBjQ0YSrqhRjc}Wx}()p9$JZ5Q+>l={9Xj0+6k`H5Ia9 zcJCSI<{omDVL0)#O#bZC7db|A%iw=Ji@t(`K}j1F>T<`5eH60Ihw&-1*@;1jRxmHa zUCgxGJs7cmx@`RVXwJowHt=OD%13$XrU@f~lPI{>B|`?5PR}XJHu#P3<_lKx~WUm`AFZ^QAVnxmT#=8jfBhrF>TT??kk3F-6hR<-Im70eYP zOw)SqHARG@amwH}1_OHR$%&%}Y=Hwi%YndiL8!}EZ-mf&*7(`8wn!NfAcRJNfX7N^ zx2(KON&3$p3@p%;<;y+J8|1f;-NfhsYi_}BqRa3DE%k#m)UasV&T!EX-6VEPw6LK0 ztsr842IP;xJO_N+ZzeE-;X-O{3dkcaVlYxP@U+eVKe)hS0~{{2k)AHwn&euKL~g&= z{U=Iv!x-l+WrDmn=#<@4h-eFZV|_n$>lYGOAu zo+KS8M&F+bk*BG6kzQZ}!*Da<=FBjcU|NEg>qN*<)8iet6* z6K#=Rz_5m!^rxbH9zlVhk<~>Zy_A+r(xrvPrFKaER0>xqlbwWBO4=STpX{~+j}%#C zmPt%F{1FnV7q?}uZMI;p$T^>Bk*Tdrw8w9a!xQot`ony_zD$>)8sLS>kDC+EHmGfy zXlhUgs)t`PI}stn0{{NFP38)0BR1rA=KF=vioF=u8GJl|xkZ2J)5W}we;$h6=W$^k zK;45DL>5G`kw`h*%aDYskKhoBO`SnS>qx7KLxQr8@)CyI&#N9%q3Zc50>^jI(4470 zVM(G(fs9@y6<;BOmPmt^DXS?&Q^Ed|5xp3FH+AZ$u%(!TDFC%J zMtXczMKT%5WfdXC_RqebeWiYAU{*N))%}^-k*BZPEgh&B$RU@?1G)x5Mr%^5k{!~I zLH=~AX^S9lkO_MMg9&wz;%gbS4Nkr9bKlpHk~-}o*{!C2v2X>M?BaCuDD!OdX!Gye zd_(GVT`3_ctshh?KOff3(*2+&k(~SCJKNUurAhdo)jv*hIf2sWxzxj<8_I+38&oSg zD}!CeU9w%0-NrEuq<&7*2Of=&KjKp3I^z7UZA z(_zySe=2La%;V4J{dD@N`j^w5-rmf9+5UN+y()gHe9Ak2D$j)XZ3h~8RM!#h*Y;$8 zJ8&d+luD9K(nIo*M2iH(JIwbn+c|qQdpCQZ7u;m4kKT-+zpKCBY|NRSb@oTonyxWc zsHo=GX*t`BcsN0{RV5Bx4wG8-^CEHef|`QT zUb$X_pt0Z6RR2t4C35;Iieid-&GOAkwk&9VCRfccm*|&>3=3McxW!zGLk#HaqVp6| z6yis}d|mpxu4&pa)ij0SuxCrpTgBH2F0NbE)2o(UC=?nH9SJD$&3R-&7mL-6%_CeR zG+{ku{mORCN~y=Bhp6k+bX4~=@NY2N!N?*I9AOW!Xq+rt+iR|=WZUrSJq;AeHmX}A z>{RKTy2HBr^i2QEg)A276WNV*zvSt~*clc$k9&Nu)i!w<2SH}=XQ-c3DBsA_n`D~A zoGd}dAi5y>%SP-zonUM?;y9xWa(j@RSWQx(YZVDooU!v5W;CAsb8p_Q9H07?WYVYS z#!NvMKMO!HR zQXo)(z^O_!Z+>eqxeD2-OiM~DVdANrshqG2YkFv!lcY0?sbewX5o74)7~n18l zn?KXSEB-u_tjy@4XWf~Z@Tz<(A4i)*_gxRY(Y|5bM$W2WO#Kh;-px+-j`KMA==JC` zkk6XW`t>nj881)&+BB-!{c}}()!M0Z(xYu=;AV<#muQ*T z#9h(QtypU>H(!2KdK5yEn7!A17`?WqE z0;)B>Y3)W4fvRkN2^on5<^^`2M!du?P;};Jn4AFZ4x7)Nx({6&Uos#y2|b8` z`%gyC9P4)-fx8KBd8F{MNKa?%J^pXTt73n}6NmDt9BKYoHQwl5YZkYWZjRp$Jk zfSQ;2hehkk?wgasMboLqD4WEHHYtv`^v7D&0mP}wDHho#*(13cxv99vxHZ4}o1u&G zIM5s<^Y0Zecwj49sU31!)OQAJ`KkWK+$d zg;)M=JV}=#6nO>4PhUR!os+}DN@!~0OUOvz)|D_$l@~vJ57kYgub_f^7fV!XNS%j- z-L#Cp?*Ca^&gWpXc9R8kFSZWJbfbI!o`;{hG7&ek(XoRpQ<~>&hEHuwm`>)cpX8 ziD2pPbIh^c&j%y{$bKH5iq}&z#L`)N^L(3oQB4GZNEu$wpf9S&+@LBjL85oi%Pr^& zJ$;tuia{>PuMRC^ukkh|5IgD*Sxla}JtBs=(Zu1exnnkyQ~#4sKot}e7&R+!bPunk zTm5eB$zqQBsZbUSi^nJEtvDFqmp^_S8E-Zn3wB@X@@-VR(+pRg82|c@tTv*`Iek&N ze7I8dr@@aI=r6&lrHaf-=kz_r%T&?D?1Vi5!psk<^LG*P|JM!w*slXxt$W@wze)M+ z+m5_;7asfvWHEKtNB}wrU1lZk_H>-tg4XNQ-=_^v5x}}ERc!rSNjDfT5ODnKIv-ea zVPO=pc(lIo!foPW_1~~??PmBqdY!aJXcdnmveI*Obd*t}6s61TV1GaI_h*2{nWK5+->IpM zrL`OC-9*k&<CvY9hQh|0NDBXg8{*!PxCYbW%y}KoGFl6?h#NW&VoqtZLw`q-78P;0( z5Y!UAI^po2q?0QX?teOX?Kz9e3@@`@7MzHghovU}=-mZs|7U*K6pi!02Y=adHvXU0 z_&$8o|8#Rk*1G;@jPyIx@Bei9lRJI?=b8Z0*Wmwjoj!SAXa8r+8KVs5f4b6Vdwl;H z`~R&Y2`|;-_-y)rk2_4}^=RK;g!}(pujM-ndp*IATN5r=HpZhR9TT1>s$af*Bg4MM zKabu}E}yM%=E++QqHB7*^nvUP*Gqzj|4ad2(F-5Cx(wyIYHP7|7q5#bweR5I;SnR^ zNd<<7<4JKzNMbfOO_93?b;>xLKK{!1@-64Ebi=yQ{Ctcu8FvNAo8aCigT+~@Ed5aM zdP>sVT$tPjQ`%M<1u9>WIsCu4UYS_DwjatX%YUB`z*kqNPUsj3n8m|Ow!4{80dk^rqt23$UySwk1gqN6|@n1x19`i(^^XoVvv@f%FgC&>V zV+|h}-t%c#b=(BlV4Co*33-pZKJfK^Cvx!xsz^fGNak~$GcYe?{Ef#* zd)5WzX8dyoA8`ockz132ICJ6=|31x&|!@cF{!Yn`(i$QCK1|7u?Sk z17WiKyu4F&yval`S*!QC@tKcETxCUq<1%9Vs=?Tx{6Oj|?!*d**|h zLwNf;>&H|vIF`kdaryRQWJivx&A}-wi32jdZ+lSSr1D78u6O-xxP-IQI0xzy|mMjzC-&TE$IYX$oXKVVy^o?|3Vjy9)L+*-|=YfE$c01Tmu8MYhD&W#nuXW##}&7Kk9e z*5g#g^$)k3uF|FS+Ybpt2b`8DJtEgZx=+(Kjb}Ew_goJtubC<_>tLVP*a@FvUp-xJRny72TUV27N7gldlA;x&l;V3FpqS{# z-4_iv+jF-ixGU2Vnr5hv1@C2iHBmJBWn`VDIfLk5JA$&e8v+tSzWgP@20oFrr%oC5 z)%3BZES*~uCy|P-lLhGF0u~7%exv!uf(@V#Y=UOm(51d1O_p@L9lmyZxMGg>*HmGS|^8z;+ZxL-`U$Fvaw>tk8TY=3t{2FqY0z zZcY7Qw7v{c*7Mz5W9HXL-t?Yj-)~vY9L_T-8-mH&a2ij{zXtf8xhpq?9z!}dHq3xzw9ezdm5?@R*(-&WKT|%gdAfF*$3JGd;%jRu zu{g${m&XTXsTk7YELPh(5mNmE2N38JJeD;?ly!>4$%B;Oui zk3D3;E_@A4PyPlZElVIvKtv8{SYxo*i_OE45e0)(`%aWF)$X@#hy@%(il2KU?AAgr z{0e5^o|DfxhT!kh%D8RJr@VPMZMSU(5&s?mP;28(;!;*=9orzr!#-dMvp)>v6SZRr zRVyKd!&9)~%SF3jE$duJQfOKRB_f7Sc?KmLz`j6z4NGC>1^l1Egi42JIUC?KL5}N6`z9Cqo7msf-mm)n9lo_cTRqwpOi}3!bDM^VD?b(pW0=`$aaV zoUChy@Fv2uhc@WJiEIQ5vD&cB)p&eJ5BfQa>jj}ayDxS`NhPZ0G~rk!yiWTIC74Wp zQ$dZW=x0n}0BiBkvs3XwZv#1M*XvGV(N|LCmosnATG>ur8wHWZnP;ao$b- z^`{DgGh}Qw^UJV{)@G+TpVp!eR!SRuY!a15(rrYq4mfyN@cOu%W>5;u_v>j_6`Z2J zZ8e7G;e4dGa!F%TFaWNB?JymJsB zi}17xuPl@j>;^Aq)-QH?`MDGE;O>T3bhR8c=3xoN0wN)6%)Y`T@h)g-P z{=F1flsWG#*l*+9f9QpHv72P?D?m~&FbjQRBbinT~WA8hQA0=Kt0Ny+_(Cj&_ z##gXGW}Ys;9Q4!>Rp*o?7kiVLym_Huq8kmC!ylE*rO7*f+!(o3DbZ^&JW|ON+WrzK zMdgrqKUVU{2fPZ&%b?@}34w7fl($}gJSTEbR#-$FEnJoCf~_bPUgQ!;XSMe&1zOJl ztwwKK-+GUu#VyFXbJw@E-ja{o;|kOpBoSu0ry7Z8CSIZ$zcOPGdDna*-|7q4XIY4S zxS{LK7!G1k%^!^A=!x>XJu33QKQreUFFH}6CTK^&uCt$K-Vy^s+vWmK1ZCq%=(zXB z>T@QBVu@rjFD|eh@Ez4J~6%Isu|2*Vco!1P#9{)C3>e1Db>~GUczOTn@LosD_Qxy@et%PP2 zwj%yz35X+vJGrOyB79rJn!@QJ+-!oqs%>&U87Vzg3s1IAY0m3FjSfMtN&Zq*L>{ak zL@UOLy?<9*wxl!tI*Bt_@I|)y7tQp+kM)P^9Zu<&D@@MKx9RFQz=sd1o1~Vku5jpZ z4tqUumFSR*$CmVpB=7vIk$#CXhV+v+`h-YTFS2$HD(dmjCHllve`5aJc5Jq(*I-|t z4*;zz8AWGu)~Jyu@)(wnC)HI8o^CjdOsC z!s-holDM}IyIcn@huJ2!<3X2c5!^H6;lz?Mn-`VfNp`nh`6ltB(DGqjJ-kg)!LD_i zqraY)sXjd*6{p}J_L-qKD%uIycUewaB+9gGh`3(68?alPnn~`HwWjQXg}3CV09LMg z&ra*C=_^P#Wp@4Si`+eBqw>LP$uo8$dj6hUWA(u$qSrMEe&mA>|G&gV}}#aFC;WO}qRTCBz_s#Hp^UI|hgI zBX3^O`FLL;CvgrI$d3s(!$~ql{|!V+XPc&;0isBbz1c|$CPMra1rZ?E(8~pQhOFbu z2Syx<1jAYFo!ElhjPP00p)%i7;R;<@3^q^G8IUHo#vP*z%c)}#Hxql)E=cKh2SYpf zAg~{UMZSColS`K=VQyRUg4CfJM@9y}WW-9h^AcP0mr3aMVadJnMj4CneI**D2G9>P zTDmTXJtcs7E0yB+PPkIC&kdfZp9}e?LwAy2L!+^Tyc8EmulAbQ^R|npiO2?pAJV_` zY&|vF5A7;HTr>QOcZ>upA$~f?cT&|piU;j0%c>1!*z&B$XmNN;3(g?QY7Ja)%_r|$ zoWL0bxF;W~%1K^FMW#&r$eUc<{BWQcv(R)KIo)bVASW{5M|La#JAs6cL!2)L3jKh2 zK2W)ac_FQ=^G}96ROEbH!y_xso2}iEe?_R;=bMOquOY#!Hl#ndCC|S^LYE!tci)F+ z7BJz=?jF^Ge^_XD7*|gKt)ODN#CJzSq!wez`AXM;q08ZRi%OY-&cFXbFrlYLUe4X) zkhRtkJ%Q)Sn>kPeSUSNQx~{_FYh_}oyyWwa)$;aowQ$Ok0EDmv>!+_uo)akmJ`}E$ zk+%<(``BVZM~`18lYg>S9KRkM*s|(1ASm@1g*pW}mgH=e3?6VAhw*B2ao6*h{b zx%44r1yaV$H8~!KBCC~=rs$;;MR5GN;@9K>vD#N-waorPLPDEU{dBWmZcbO4iAZ%& zqfv*sR48^Tl;#QocSqRKNJV`(7jYYHrtXgNxhx_IKZ--C8;l;~J!P6I1fO>c%AtZP zj3}kF7nAxcEl!BRU5z7P7AeUC`yh?!%wf{rl?;-n|=|83_e(f5n;icVnNQtEiN`xhSZvE1eVI!`Yw=$)C{I;`@_}a)flqZ zDV3EZ=^>`5zs0cQz|oVboS06W`|+V+s&EOXLNQ5b=_7eze-X45s;EVy(%pr9{20T% zSPw0(Z(jc`8!64)k50`%n+X`tbKpCY(h}V0A*(~2%F8`4kq)<#RU@X=fj@;p;n0h0 znHEdx6I!VFW0Q(pn*v_VL`7_I2nV6T6nyA?*4G-hsrSO@d zsmf*~O~S^+5uIYxq4e92hEpc;4AhBp@r;jcoaPb9z?OMfLrD4Vd$n8(x-uBQKq&@e z@8|vitDbR0C?7mR?g{|!EoTfxYqO)v0{raU+)R}Yhv&f(EIJW8K9S;2zt~dmV~&rV zYTP^cMfr1!r_iy@e0{Y#xPA*={|}VRxikm4r}^uAnAk4E z;YUGn!ZCtPRq;CRVSS$72S&hF5@l}@28pkKm4U1*(qx_pgZRyQ$2SLc@ku%MJuAJg zOApaSrdY3uzp|QKn@y6@^jY|!AGUxG)-LRlF9(h2=ImAyu-ar}G6k712w^+@8v=% zr{0oculKiLoGi{>A-J z{NoI2!4gCt%a@?a8%t9DpTf=#;V@n=Fy!(c<8yZ_W@x6m2WN?@jK*wbfhEbK0jsAJ zn+);}iJZmbnsmpUY#LizUrFZW5)bjx>VquWQT*?F%9g^(fCN_v(E8-8(w%wWDpg<^ z)TTMh=Jc`bQ7qBw1Ep$amD&4_yI`i=a9@%QFv%r1B$)^p_F?CmfkaXOZXULNDUG}q zO*Xqvltiqdy@2OB01OO7Aa*0TV}d@3zP6yv7fBbrI@b^>m*it_kHA2Vz{u^HFg3!p zKLyF(&2M{4y>HNH1Xw5zS30N|d0~cVY`xEyG&F?G2cOipnJ%}#u!u+NmMMS4AmztM zM*I|>;?4h9J*|%LQrr8gc=HR76rCkUj>1=Zi8Amed0=8=9&&zMZzd4*J@N6p^IRNv z7?5I8Hvak@89Rn1=@z($hrl2tDU`Lg; z5Wyd*66G(t3K-YpQnT4iwrge0=n+-9NaBjl%m>b8@(4C`A+9*&TC9DqHT_8+&QvK_4{I(7~xs$@{&@sn{EKGJZVnY zVrqcF0zltF5;F`q`5Zf`tGWh?jfQ&)O6n=CRrpKs>doI!N+j3U)kCyMWSZzJ zhHu10W+8$edvTkfTY04)7QZCSJh@^Bpb1RnUpqAIBxr)#z8kmsNchP-DyFl_%K6$E zta0E7WmTFZXBHeh%$)uNrLadsAC+%}G_v))+Ej*O35d=E+$Fo>rzqWY+;pt6$5oGd zMpDO1hlS82u~Y>sn(}97pehKwz+v5AcQo(m)-H2TdG9u|?0@r60>%~tx&}={%J-Yc z-nJh`JCsxDzYOZ@kA;)*_;zgqdK|(QcdJ`3vOTwo!)-Tux^)Gz7Xzum6q56^NIiO8 z8NWm*VUzg|5Z19Qolm8Xy@0)FOWyyG53Q`*YDk5gAFp-~mP^Xpj>80M9<*qBx{~5^ z&yB=?PKNUm&2%BGC#{E3Gjis{42fKiTkpN8 zTM=N&u_f`{ICsUvs1K7AH=t|_s#h3)zmK74uM(+T_j@jAVEP$k{|Z)}7PvpTZT%|9 zs*jT8xVUZK%*U zu5Vo=j}P(}`ft2WHy7FK)6~kxli!XPgmkvh1hBoJ%kcbN--n1mnQLxtZtvVu6v}?A zzNQ5Q>!Svdc<<4A2nIV(cXo#7zMMq@&$AVY<316?;Z;epn;}EbZN$dqwPlOra_EJ> z+}tktFB~O|+?FCJ;#~XhYZhZzN){`c>&vtjjPXSJ-nOb;>>`(EL?ZU^Sesl$lJaB| zipL=%r`MEq$9<3-(2Y9}YI_yixek5YO*dJ+Wsg)=ZT|L}PbkhT*+IF(K=U}HfPY;w z%As;iin0@_4s?4jyOcCZ1#vq>@BP5|)LS<6qN7*ihvK$$VOr2U|2@(A0U8z-Vfg@U zUY2Y`W1dNFDbL)6ov`+mE-W8d$Y;&FY(`Dno1vdyM}a_S*uTgUui#L9Eo7K2>)uL6*K%(wgBv|dG( z>*1A&0cDDs16eJmTztXsx$uNlgOYK2&93TrK}K)Y5jXo_$J@cHN9qmbg4IL%Czl*i zNoN;H-{xw)#)w#}w8Vs#dTk%N;idHL>q-@Stn1;al^DX zXn}8GUD@LtFZx){6hdk%(g`%&e{yP8R9iPDxDymUT4nvcI<{H|Q7t>I1$}#)f4Se& zjU4@zwec`?{7TgkMwhd2G`l0mVORR%a_c=l1$g@-HZe33s+2?X!{8q~27O{_a?6;@ zCjw&y2B&mm%zNe zoz%Pe_pK#eZ&NKl`6z?aM9|AHH^J9sV{3z1c>_r8C8&YQsqs$*P=UtjKUlkzRo)<- zsPRAHcwz=66Z$Owc-#?)cXr{*Vg%b{1e}=}KdA6e0M9rhokb_+!}V9e=3skjF|DWp z+QcL6g1xLc3t_BI5&+Tp&B+=Prmu*O*=P!#^M-a;-f`7&+5bzz6yml~pga(; zXrK6%mds6~tg0dG2%PQQwKZ9ly)(7%toq|jWz#$RwE#te`+#S+9~ql9Ogj0_z4t!P ze2k86;(L7`$F{5DrsL8W&=hvrvL6mnf=v7bA z9(D4OvHuHW-`zepQV^a9f?Pt*X|FLO8dT+Tp0P;Z$vP5xloJ5A@jveWOXy`P#%U^R z=5~eW*mceLqAx-hgP^IIiaGT*G%vH-0|>A$#0AzMaVG}^XAOj%(wg;yvCxT#Gq=zQ z^ENv2$SP;BbnPn2e`tt4(DQ8u0xm1Om-N23|le^?N~Aq+f?8Hin;N zha(f?b6y1v+0B5Rk~O{TT?q7 zj#|0^d)-arCk7;CV07l&OgXy`6~WeBc{_7=b@iTrbK2~K-QzoMEpGh|yOdD?Jl=m0 zhzS7AKQTG+UI#v8psR5ci4^B=&{hBu{*AI3@x+_zCI|$I&CMkP2h{AFz{7UGP9I}~ zg|*_W1bkkYMeC@ z?@0PG(Z~?G&9aT>o11wNI5EfuY9*t3wpw4@A3>x%{EK|>QhB}He88;B0X$q^QCx4_ z!S@FEP6?S9%l|JSsrNsK0bj2no|CA1Iy_m|Kn@ge@PQv|@NIvZ2>C z^H5(5N>AUtQq$V2eBP*;f4g})TrdLIStb6^$;qLB&Bxyv{2iX2Dim3-4xz2VurW|! zci&!wP9pXWDwvmCdYs)UKF(fQki}+j7e6PS0UA`HsSr6YuNDg;)jbX;w?i}sZ_6-q z@YEAVElR3KSen^?ML-p86Z3cC<*rw%1(HC7=lG>o3nsYU0CS&nS=O;}2I>b*=I*;H z+y(pCQq^Dl4QgrtAJ}@#(fmHQb=}YSE=sf%$!@SkBf_n$^1&S^3GaJh^Er~D{zQ;J z1eBi?jFH39kB0x5D&DaM~_bc9hv;K=F<(CfjsaB?kC@@qm(_&^x+hIZ9!{NU#A*2zWB z{3 zaNcnO3^sz}PT_B&`U*2q+Yui-k4#0H0h#xriI}qj3s73X{XpwM$;N4c>VD0 z1cZ%aRLMN*hKo6gLrJpBHFNb<~#~6^G zU!UQOA2vDseh-r5I=t##u5i6JUp}0M*0YTIjzi}d$@$)n<|DWBhJvWRj}^4})6;*+ zj=dJT^HVqavkS6|zIl~>c|!#{b2tlV{rUxhK3JX)R&dJ#c6yecqu)$*LND1r?QiJ; z=eTlg%g^Kqtb`lgh-IOEeFG2a@g|hMA4sQc@ET+(Q(HzBXWp3J_#qbqA)4O8b5AtS zag7^qIgrKMeiNrT12bsS>3y&6+xYp371->kD%Ne*jiR42oO!Xo4tW3R>OnE?*|8kQ z6#}Mg*7qLxJv_77*|3!RuLrGwbv=PLyw~~J`Cx{vmy|_x6_D?a6oTA3k$_?L>nsOIVeHOKe5C%3j51W6CBOJ?fj{W zDfOiqS9|uWMIRj%wcKjl0Zl=R-$9Vjs2pRJ4riGOHo^w|!}HFC=rt=)gcHZjLl)A* zU@Xz-b*(P&r=3$E5n$$hGjufH9z_-B4);BJgED02PK(nF`d!L5qftGVBi{7r;T!D6 z+8Yu@W;1GSQ@rd``**<%b>&SCtADG&$li~^^w%BK&So44>ObZ7HWG(Tys3j+wsgh^ zOMYa%S(5^IxVZ->^VKR&h?>;ujh=WZ!Mqsv-ymze?bi%ec@*EG#tq?Kc%qtw%l-gA zO8D<>M>Ba`_=gWK-C9ba-A__#^blpR9m2hto2AJKe;UK{)d+jYNEdqBRP*bXppT;X zRkziW^625agi&xM^iPg_NCdklDvQHWB8y~Ynu<2XJoJzU@6MufhX+*PyF7Ad(<&6S zcc~pzX5&HgsJ9I9vRF>p6>#S}Dv2=ahCWi|eegfZG2v=jG8SF&BsQ*|N7@k6&6E6S z(EKJ3?VqtbwYMZfC9t}}{PkU<1xB5J5elz%KtaV2wU50IFEs;fsv5*@7u*2@CjgX8kZ0eAUcV z>Tj|7F(W<}83^776qKnAXxdMc!5e^+K4rw8vIPB}#HWGI-VOQqUt-ZN#}rN_^$`QA zF@GXhLhg63FZ=d9Qr65!r&P&|cL-`iLb^pvP46>^mv{(y6Sw;p9%Zwmq@UMcIM1Rb ze5y@&cz=vsGO zl#Gp*zJ@!a>Jnd3+E^JAi$uhuteZ>kN52N*J!C)cPZ$Qp(tY%7K_41GD^ZA*h5HV} z?5e#AI^c4L^l@Rplol3sndklzo z9zm}p@p3Q9uj>78x39`=X$oWa!$Ur5Bi;&KZ*y)mfhmVI9tHffF7wFPch1q}y+Vvf z>A(Xy(dC$D`1GKWfSGdVzYpV}zzg%7Hw7930^BoQTaRi98i-7knDH)hG45QUaL3)D zBW)HDs|p&q!5xWtXK(mR*H4CY^V_t(175dwHFoYP7w})3GV|j{3}$Q=UFm)-|0lVi ztZ3tUuBiCaaD_%xkIrN(w+Tu{tr`mR?3*En+7|pY&}>Ei9ZdxoXcUEPVIiaM!C!!T zsb`~Yk%kg0qpXZ!oUPP3m?lsjbeAYYED(1n^rp)y`1=TFRQ|~Kv5Ol@_N`%`;{%@tVQ;nV*ovS~@blwsZcrsdvFjx_ zqh_TLN$PX8*bB`@+;G$swrfV3jc|te%m8tae8yYmvp9b)pEF7`UX**EpX3cq#%@M8 z!C^NSI#kbRN?!DC9* zmmY#Cp|p)m-xV2N(6?^xpeU|Xp9x5b@!P>|0W;pumAMChnK23_Q{5TG3cV_EiX*MB zD3*$709+pB=%Z$}ayNsUnn_ibx#Z0LPeG_Gz$iR~8j6F&h+Xs&S5H<7U@<&XI6s+w z3!xml$6bTkZgvIUSAuT`@(XKPhp6;y+dxA%<e zwyxe7_OroSCA=WS3f-!f3xR4aRCV`G^}&Mz15{Y9-~ZA@sQ=!%&EeQvQ0=%XfE}0) zwFiEz^vE`I{N(E$lri_J+Sd8?;^9*{1LyhEh(vYDFx1zi}qOT6$> zNMye~g3g8)r^3uESLh#v0}x)Jfn5J;Gvm%*6$!AZ(bmPtg2;rvdp!3>z7b8Ck5WTM zTliiWdjc*c$m}{WIzd=6jTu`$Hk%r5O;hGVF{%_VBsB)p#Qw1(97JhWvgS+vzW58L z>oHmP9N=l0QjD;{%~1}yIW?Y)exef9@Xyu$x9pdg|3d#batZ2An#%bWyU&SJ9?fLMt z28p8rN}TWaXKq(&1l`Ojo&+lQH$mva@Sp}_VSnBX(M4D*{kWkRqx}1he_jPIZO&+U`Cye(wA{YxB@8+&5)7t0M;L5Yggbxc+b@{ecN=oCv$$i2{w zK%bWo%5cZw+CW4jaQ^SE4T!7z<#C0>awI&H_80)$pqDrX(aL%oWw-l0uLWh#D2bG| z7y1fX{ZSlah&+&(1cJ=z7)um%Qo{Tcjht5%AYe#kUB1~oQ0r1V6D;}T5wv-Ls$n>i z2l7X)!mgGz&sdeQL>sUqGYp%gDK~o)n=;$oyH^Llg~eUj7lmvPyn z)2%bEEF~XLJN#q8@1Xp;uB%jDin6|{w%TgSc1QW|d%MN4*-XyB#T+Wo5J-ZK+#7Zd zbV#II!QM@a`sR8LTDh=(p50~=ZuGBeB$@PdtU%b_04%@7cYr>RHt_bUcfK|G!AI~@MoCKk zs!)zYO=k<1rOV)|S1Ub=nY}7jrTx96htuni8Qzf;fH%h#$-S5E zAV3KAZW{Olq68=LH%|xsvsXSQk7*8LI@1ep-B^mLerZa*nd=_8LY3J1L=ZeCgZdom zNtNXFDQ11^;`(onGe;^m`N!K!n@1$^wM*)3!hKTwb6OJ^xQZZ0V?lH)V<_%Ku^wzY z-f72TUo|azFQC}r{{2={1lM^_Wb*gUA`*}eQ=>j`{tGIq2j3|X4$fyV$qSjBj*!^8 z-ZpRB3pvnV(55h=-eh_O5-2THMN_P-F8x)+`OyI$xV(ySKjT0TyyM@7G>Pw&&29co z4n)Nk_B*z@QKK{g#FSundi1AdU>m*PVq;-({H=r+S)wUTcouMA7WcCKv43o_W|ced z5Zime)4Ick)4KPL>_~RWwLh{IzslmSrFL478@3P76O5^VDD&F4dnS7bSTG+>6D!5J z0CH4%9BL~9;L=HwZ6NM(z#>M9!+Gq}BgB4zTMkF+dKg0Up<)qSw=@Gk%DY?zDaaT# zqiRogtgLy!(%iv(EzwapF;Ov>9PmMC`>JnaV}o+lS$RCj`h68#_5_}A)joCbGUHRq z&l^O4Ge9bmglMdidBP^n+*c58Z<9H@I4dPs2wXR=5D%!B%?J579>q6M|K(zC{p_6* z9UBU^b;$x;yQyYAzItRnE}Hz7+SoLF`&n#{MWRjn2uCfnxO5F^a0N2Fu2LNYXP5ar2t#?!Hwp|m641)&~6g z3Gs9JR`W!=rRF;pO>wArwoc-3VtL&C4sA^~sFgFTH%`YX-9+o|A;S7`AEJat{FtTP zY}M6d)ipO2c{#S-6In2b?BHd}%fGo>M7brO5P~i9DXB@+WCJ5td{R6%nZXP!TL#`0 zsJoI#>U}{`_bQ80RhHkB-^#e*4g#8_PVDSH;{=IQ>=S;G7)X&7BZg-;$ef}RM#@rr zARS&@{6EaSI9q$#t7D~|H9xq9Vfx&RfBycSDyMo?t zv#@HhSuy6Jjgn`LlfNDl<&Z0=%Dl}#4K{ng+;r!L-5-$eVyj>~q1g?NV3YLk^4OV3 zg~6w{?`A72!kI8O=suo<9(Sk5+A7W*y10p(Vrm;-DdWbbe_Fj#5zp*{+y;^UA!_Uj$CT;$0Dzz1opR%X9^K`-AJOCeG*8`5sTFl+fTrL=jFP-78EWl&TbOfAOHS?zp2zse?%X z4GFQ-6w{vd{Bx|bUG(0_y7ipm4mvNdkghLcyWE9xQ)Z$0X(BujoML&=f9NDXTd?x! zqyo9eb*lpL%C*a<*-%S{Ee_;r8 zv~&uPa+edewZe{T;f1Gsvh-qSlRce3i&^~iuLI4lhm+PMrnUkx)&KA#V`#fMET z{?M~4buEOmb%&%Q#~YhktFo!>%dM~{bWO8KSvjjQ5x}BVSBvc_M!nmRX4#@SR?@{= z@X`iaY2L@WsM1C<_VtF1A-8NvWQvlegh4cAZ2a*LFj^m9b*-=4Tg(DSvY^I#q`v z(FwPH-yDSj9KdY!c_HbC>|F6&FfEJym6swnx`v`rg_uz;$25>-&MfoyS_bO z;Msk0!9<#m<9aDG-i*fg)41(FNhC;RT69lD;xKUWDmY-?A~TWh5JGk#A#U2nYl-pJ zAH1L*zbwD=O1L$GBT9e7$k}{nfLm`vTG^&p4-BAeq0D3dizN{^3wje&OZUq$T5iq(jFLe|d`3|lEAEoe^1zs|4{1J>txcipQM2y-X1VpbF4 z6v7wzS{9oCf0tsU5rm|^jua%{p|g_^hc)75&SNTn)r_W=OSZr({U@jx;>U|EOYaSU=ZUBvLh6IGmxI2r9N4GzqB}Zn2c-C$+wTH!%ZpoDIB~$w8 z;LIKUI=f@`OyIv5KtTzcP<~Vw^bDVv=N74S8UCTeej7y_EFy4NV0}sF-t=l@tynl@ z^o5k8q13q6&m!g`&wQY_EKE6$B$8)Nv+gQ5rIa~E5_(VE;gnpL*~T>{uwSjadGQ-b zoyE3uJ6ub4v@9EMtnQYn1+SIqsah9uX0CN)2i>QZ^=N(X4qhvkEi_xlJZ4GVI;he_ zG)~bqmb>$?(60OZvpXkTnw)Ny&o21Ge(Cq3)(@3;y=SF=O$NK%3bfihS2S)($ebCu zF?tj)Xgimi$;LjFK5V1lNj9*ornfB6pFPJi840k8Jfn{Uiq6w~$*FE+Uu`x=4N;>b_gSs49OkjK2JmDPAPn9>DCK zMOP{*HJk9m09VuyA_Gbq{)pN_!e4!<4YDy+0Kv@ zW+!IPRxnl&A8AMZ#aJ4sJS9yZFTxcBc~LT4sMaBwtvXgdohI7GH0~B>_P*fl+~7k< zLTKvKciRl{T6Y;}j=GJA%ocTbH}X=WBV@o4Xe158YaihrBma8@2hcWK7U~Azk?jpz4JejR4Zs* z10qq1au738o#fCYpO?)GerNBN>2z{my>1xMxV~M?n&0Ai-aD5K)u;AGB z`VnflsuzSsTxSKUbgxr&VKMwv;^^!91)&X3>XUKZ|F8g-_i}ZHiI&`Ne|FZF(HCr7 zmwF3?urTIA{)y`U6)%u1JU`DsvFWsHmU~5}qUFmFJicTnGIl>!vdaw(Imi_r?-YK7 zu%bZtS|cuZvkRQylP%tHQl_hc--691s?Xvyn>85Ou9iQ>>q#JROI^UvGr;g738=8c z4k%{N0Xpr(^k2JQuaeN%X@1#H^^1JqqRv~4ADNl;Wh<54Z8}O7HX4q`Kb|j*d$_KL zT_1`X%0S>-bVpX*U!)%VPe{WBK-HxiRqRD`lBJk9p`*yjdMt;POV}U-7v8tZ5=GxKp2c>M1V!>$oCep7pjW^B}TZWLwxDkDNoRpHz&$0Bw z({5O0jhASlhlhh(C9O0QaYjGU1nb|hQp_NZe>hFm zcptE*m;wNKgz4>zBrx-S_okgkCo6h+d;*m+f0L3`#6AfL2}N>aJRghjRmdnURv}8E zq+v$nN7H`&in)^|FZl!$pD7{9l5&9Cp)HM!lJCqqH~8>j@j9x0mXYcb?9e7EB0}`o z0CS-DX!aBm0afo?gz*H${#m=u+Vf)MqQ|G(mO+!|EFsS;W z?rWCB{29@8Sl*i|`uq@rX8YClnu+jaV z=Ch^7aG--*t?N|`pCW?5fO55~javJ6@wjmjVXf$7CY_!9R9S(v1P80(;i|Ao!+=3^{v@dV;vs$}z73 z{dtwIghq$gd#S(5D;}$PLWL@-2g0K$uiUsqL|5ozaduL$0_{%^*GGTrA6x#~{i(U> zSp}g-(dmoE71Ar`@ZT#E`tcO2u`jv0SJ#Hm-M2rk{a4pAK%nXr~Rege!?=w`DfFltGKE( z&DZJjuck!iy%M99q};ONoj|oF!iN8G1sse5NdQDqcsvGMANQ$y+(x+!uKBF0#I7Qv z$4g@kU#5r%(NxD7PqXG@agBCAAZJqD^hQZ z_oUTl_~4W6ETZ>mA!V#>S zQ$sY+n?=_C7pR+r9@9|{FGS5(%;RJa!;7uLB= zv)xrj(Q`L*x2|VN_9GbQ$EYLEQWf2ZcQgOFG9!)8`TuCwvQ3If05Qb00)E`4BGbTo zmkBa(>E*Ja-_XP++==Tql&Ut5(ebIkl)Na2|uqH?+DEQiMle%H7-W~pSssk(2JGK7hm8v}}Y2_OIF9|i>qLOm4XTROWp3$VOr zG8j8)Cmt+gLG%pra8Y{M1jZOl8+-%Vmqx!g`Jp%Q{C})Xx8UDhy*!%XCxbQ+DS7!J zs5j2xVuJ_gn^wFamokicg&JmB%$1kL+P_4E06*;aTd=!fics`StMds~v)wi$PPgO1 z7!q9kIMs3ww2z<|t$^F6oNS_Y_#h2sUth?cgqQ;%F2e+yDk}yqZfJV?=aSyLRd3)!r7AhDOqqf_#k|49u29VA7;Ub29sl#Z(C7KD*&MzgT(9YgakamLSuT3sh z+uvGam^@#YF~EkO0od4Bb#J}Czf?2}B~U?)dRs6R2H(D#imd;OZrIrt@?ZWo6#0o< z;2VNB^6qE?`AU}+7oB=da9J76GZoT_`La&yI|n$&8d0y?ySw+>-e;nKsehX8M?1-kVJ(1^Jh@K>xdVSFVI^lQkSs-4Bakh=6i_g?=`>Rk-;xQA|8?JH>$D5dEg8;2< z|7(gMW0P|wXNNjq{`XWKG+9Y8fXe#RJpOCjiyjK*HLI{~>e)csrv~63UG{@SXjxgY z$jHbVbCEEjXa)0c`w&Qtpyp8b)9RMq2i&64QZ}Ohxz&l@F9E=?FmcNK8ldzc6Fj>{ zVm{Z2I!M={&lf*G!;uzduzE!{5z2)fR)7n_ym5ord@;kx=-8N$h9?~w)iZKT(sWlA zD!r06PcG9g^SnU>pbS2q*q$=^ao+kVkG$LGnvX*MG&nw4b;XMrk8C1wh|)LY?=38H z5yj5vQms;t74`&A9sDyjy9x3fA}YPt+flgf11`kQ9GL)@y`TS0BJXG`XOzy2W(<$3 zGnj8(aoB1cZU6E9KstgiQZY15aI zid3fN<|eE4rYnt>Nm_Csam1=W4EpUjVQ9o6P(zOxIEF4w;Xj&RJ+$|N9=#^Ge#?nW z!+*k5LC)84aZUy|Q@K#Y1+m>Nb|$6%xU?jyPo1+ae5N{@IPUq?BSP3$?qEnixl*3J zbXr!`1RVM;n_wzkf6$A5!L)UTIG@kGe&bld)_v#lP(#D;f($n^fJ?ILLI8XKPUl?43rGl4t=2?_M4%^se% zNa!&nP2@~}_TD7BQCu^|b>SE{`zz&mfkE1lz4wU;_siTkILB?-@wiq8)={;&z$Zo6 z{cL^zGp<+Ler3kWEr?LdhczfY2{aJ=ySE56v_O&!kuGeP6cUT;j=-joD?Yqxg5&-k zgj7WF98x%@Ul(3qd07>Sn}Bu!L-+C^DBBzlu=C9`FzcS^uL;L%zeToJ zS#PzTzp0?PREIgvu!e0SYRd&~wtt$_)gHQiw;GnZtF(>TzDx0IW8NG81D0;%uWvIM zL9^ay#e`ZZhSFI~u13k@cFIe0`vo30f}p->Bj|(mUJm|4hHTh>zd_L6lQg)W?Xg6s z@cYKa9YtGht=^E!Ul*h_-&$ZA$+zU|<|v&BBm^b>_Bht&`zY)7)SDLT_OuGKV<#Q9 zD5H~vfGunsr|1q-S^*ctcuj#F2JFlKp}-{i8-Czw?Jswgg)*!zWF0+5Hf8{GT@AL{ zo!}0^TS#V|<+fHE1L=sBOno>{iBQ4&f%_*qPo&}0v=FV#-*2;AzD3;U(W^?|x8;I| zVuc5?S1mTkV4Cqy+AP7@N8RHA?O< zR0jWkpYNksKtzOrWX9xU0?037wtux-;VY-S_|-c+9Wf<%zlAkMxnV>tzf;|=I2gk+ zzz@p$fbE*wn@nvuq&rE!o2%l)Y`vx;=UK%jQ_k>HxvnPsdD|-7O>oP9keVDMQ*L(k zde3aFk7A_IBJ%lG{KE@(9;>6u9pD%Y%kQl?x-4*td6} zc_cxed&$d)NrOaQxZykAm2%iM&6^mGqnYz{WSo_F&D2Q$SSVZu9(RTEzzTyUWem?h zD`}DSFPl_!20%^6v6(kilKy(+dJcH8g!BD66-9aX6<6an5{EVrYKseG`kAmVak^AJ zR7u8STfx?sWFu`1yJ9SYb%z^e|5srVFY8i-Cc;ttdWBSjCn6o*J_ehPAY^h zUx~Lxyn@t@Oy7oD8H86lV6`05UIqH9WP69{<3(F{Tne*rk)-iaD9n`_ z0Zv6gWVll)DVx=`x2iu5h+fJMjjlX$gAJ(FCXnQ~Jq$q!tQ0LK9aU6EqB0DpMkJ_&~B9TKb>K zY{kdeVTm4Lh1?QPum2UC*`@==xa!^OU+pg6%{-wQ5_PA`@_D^nHVJJaiXojs0e)2!!b}^3P0*5}!146zDR+DsxUkw24UeQTsFD z@%^_QA9~KYV`C}DoiOSjOPv6>1PkxJKysn<@rabdt6?qf_}lEb!<~(--^XljJu65* z90dheZ&sNc%3Vyvwp>V;6wYGCzV_c8oz-s7*#6+^RE@yN6Ll`BTQl;$ntw*Ts}24B z;e&(2#g{b>SeU4#ArtJ2Jo4H^0D^CbOroSm0g1u;SE*S~msNx4*lK#D6Q53UtuFZE zTMEmD{+ZYxwMRy>7Lk3*4?7K$`}SP4>HRBlbp*MpT33Tq3qS}`V0G0Wn9ZlHxYPvB zKevBFmLmx{_D(9SivsB8!#m{8`GTj)zkMh-FAu5Yr4vf7+NC4}v+lcaHuEPkN3kj6 z8f-b(vwaJ{Hp$3WjPqc(n7#*??K;8DYKR@O( z1D9z3){wM(GhFG9%v-&p_5a8lIapht?lIB0R{L+_1fhj>=ijS~-sU>IYtZ&<|Lb@a z_-y^1L`M@O%6LM@H+9&z42)fy9osSTCKyJKZ-1g=dBLd z?cL;xW2_dz{5s>NYGMlVf_-Hz@@7YruY~Q-OdNg4h({7xpH-c`sp)eM#c4JKm>*DM zKR3UGT>a!wqRVz=g4355gS(j`-fXWU0wJ$+Lsipn@5XF*f%yeF5*4D|V8u7Fb%( zBhXz#6Ei}bk>Utz>n}St1x#rVI(RULQV$JMI@3rdxOfv&47>m|d zY3TIG3W`8H(JQk-2V1Isu&YkjXsEjVogjACCGiwK)-oKp!F33o|mobR$u(U?6-o&dl`e@*OA#%n|#|Tu;xSd&x7{2m%nET-LZMPB5CWs#Q+RHGeWCyX?aq>PIfSfAxjQUe3d5r7f5K&_NCVZ zKhBchK<8L8qoTIPT{iVwUwHv>f|xn^qZsjjZ00iwG?YN$Qr;U2O|l6lbW8_BBmol38x8(B9an8{mNGrDCU#~Yw~yKC7!PW zU2i`f-uV0{(pf%CW^#0VtK7Kj_?C|cGkNLz7=u^F4{!Ct?z_yK!|kdsfV}((_UGgL zwOjS|NF-5D*m9omhq%l0YQr89DA5F4vQUe{dVj??(ZCgNfDrc$AL{iTiG&G4b#2H>Ah6xM%UU-LE z+@DF?u+zOx$1FFi(hd`hscnxyXvbylMnl|_>p-?{;ePU2N#kANF}xe^#DOHfq+aD% zc2IK8hglb$$mwM?Zy|)fPHW}cbi?j$|HQYukMxe!$G`Mq8%Za!gRWj2;H;2FfFEd5 zi&Np9&PGB9)QNPKejASKMp=#i2p7%AdlB<3f=E4+ol}ns{gk1Tk&#{4RP%OjTfDN& zrUrVmO2iVCo85rl1rH92ovk(?*!8?}x?XHVEE{;C;^{kM^1AE^fWJeBB7^~U!PpTk z2FGa<+OOXalsL(4c}yeF+b4WD9yQlj+hShPNsqm;TH9oL#^KORoC902l6ka*zZ;KP zGx@RVghMM^)e2hsVS3{$$i_(h`NSM`9>0QHWcwq1pW+|Mzj1AnT5F{Hg_*@R0@-WR z!Go|(XO{cJF@GyUMpbz{-ca7OQAq=P**w|ICWN%L@nvLX#aA0(C~W`fnK)W`r0%>-0SKu;G*HkqOr9V zz>5FgocuNrsLt3}WwC0c`>efR2Ovx!74>z8w|l-n*J^X5ghwYK;*TB@DnBqZ==azS z!KkU{1E!ta*0NUL3aMF){C4tT z1=*K@{L8h8w^-d0er1R0f=G8DaA#!BCX>7mVm6=+aPL z9&u4)^Qf?vDofV=@7Q0w5xI%bn&Q#{N+1MUfvnO`0-J}C^$#~)AEY0t#r$h8^6X~l z#2GrDM2t@J{K>BxVha&J(xI{Fd9Idvkaf(2*&F-A0uo5ep+Dl_g*7DsWf!qE^tnIL z_kruEsrZ~>y3c)vqx<_gdaUY#`dmeC`46vvE6AekQQ+7!-Xk?E+WphCOzz=qygsDq zwe^FJ2vUSB2G|2rtNsUQIxC=v5t`Ee+t>eo5Sby4PHY+9i=Z#>MH6ye*fV4%%VJ>s zvseoK&j(l=Bd>C5=>Kf^KkaQ1!|UBzyOe3;pp*Z9|4Xnxjn`NB|NVUb(=7C#W}my& zXcPZGniZTyeEh!;1wDxU=dWK%9Y{i%?)=K7yzbA0jg84FDk^py+aPI?jHaLd&rXv{ ze&OWAEiW%0ot~D2R)90}$;J%Wqz3nug#WoaSDI}IJs&P&x_zGKhFU;mOOFuUoBrj| zabMAdex`RzAhp&R6yL9aK9u@4h2!!1Vn{H?Ou7Z%=db5sjihtF!Aw7Lt>T-dn%C zAs2envTSfAIa`{xw!%KayJBnl_k``X_WH&xzGk{vQh;*6oUha~?Q7UA>73tjxA0S( zVa;1~M69re1}>BXRcF5|!qKtZ?c=qnA61VhCPEa31JmgYC5+{U$Hs=b#QzSN`Ji%t zv?^c|2s!jucatgFhD+g(C5)zqu9c&4HG=t`WOtIr&>^vurQEANp;!NreWTq+zz5)y ziuqN8sN*6$to78if`c?xt;(uH$0a921mG3S`M;m{ISj|ygOya(5lGMMsT?u^(glD( zQnFWCjIx><4OuRifqqM!P5yVvktFnv?A!+d+C@lFOwiMsF3J4!_0mYXK_m0;(15JI z@u2y9c3(MJ`44tZ^_f0Q`_6X#LFk=vj;FWbA-ua~4GwQ7`YDS0sZ0(>JsMvyHu2oH ze6Uzu_+?D!ij}`h7pnFowEpePm*U!IztD=%G@BS2=B*Se-f8Enk+3r-KjeR87hEOu zwLcEO87a7`j(hmMUbM}=lW}Bj(x6*uk^624tAQIzcZK|7H zscsg~)H=o+k6wuAhv9i+)wM%?O@1f2hHeQcelvnCdizL9(|Aqs&qaeh9jjgOlNb>T z8X47Surp;U!JZOy`u5jCpE0>D6TF zEO&#h9y6&RIZMgQFJlUmfgK}&o^$3x#2GR*h6h`Uz6K1kmm^!I+f z{Mp@+6w>^*2~7bza{Cys#2;B&wG$BR;uQ&O(;l%v>s8d^l)UZA4v1C`d})3E~l0{1&R3mp)xW zJ=m5J#Z=N&NAXgDrhMdpoN4qiAl5c@S8XOZNh4v zn*KaahelU(6Y6Vo~@f6)35*ZezbePGuo5F?O~$|`F$6$OvV-7g-U z;;kRs@uh3$O|uZ5e4k1;lH+8y8&jx9kjA%BG(Y%Yk?|Z9k83>9JiyC!9~xUz7}~56 zd+^t^-+m=Z_(ZJXOKe-be6Zxote^#vK*0RCj_}r8QVkWk@7upYYTZu?3;@cIMfbN* z!2TEVN5G3^dqUYRV zSJt8{xbbH6mmminhBwHKCO@K&*6VUBoi*&+2kV}-Enkc5Ho@bkQiS6^=03wKKpsT( zkK!`1WlzytL+o3XBW5?}90ArzNdN~SVdpI||Aw`0ce>e&qr(9z-gk=0PH`Lk=*yo2 z`wJSjLu(weS95+`D*o6#Ct1R-#4>K2@i~Fmp&5||+}g*#H3IzJP6awS_Zd1Hs=oc1 zuEF()8ksG8Qp!WP*?vK|aK9I=qBDV0o!AY0hmPgm+uKaS%+A4K3rqSgFeI5Y8J^CCfw4NWBdOpN$`Jq!O5(SB|0hf+lAav*ceb^&5 zvXGhr?bgF5LXfX=VP95?;LaDM=03J#82+o#9~K4G+^1jMRJrhP5#0N~N3QmYA1B9a_d>?n052^**A!bToUqe+ zGBPFu59uP224|O$$QDCjFgbm9pTM*)YOS~}x1XPg9Y2Q)GGvB6;JS8%+D$LW%J!M5 z)%551vlYE>`wJwU-2U=l)%`iw&q&pz^~I5>=kAr%=rP3L3j2}g*ZqUgX>Emx@ww*u znqtYi;WOo(=HJ={!}6Z?YH-~?`r=MH;5lQpLBeLT3jw8j1I1566I?-%uo!Z|tGn($ zoqFDzH#>ZWJPqTCjJsP5qc9Nq{>UJd>|AU5SE-^%fG!f0R zHu>jEC!t&6eSWV`ccKp$n~M-ZwEeL{bM2L-(BWl@4uP3j+`NO};jpk5lCGIH!pYo6 zADYJ}bvgH4lurUeq@0Xh&l=Gu3BkiQz@28v<=tq9@^ls_a$CPcOlLZ8^ap;B;R5-4 zNs?L2EKchEC0ee0gvp0Y|tf29W4q|HOi2e;tK%Vn?`s)trueUqP>`i)u zlrXj^Rs=+kN69?hBgRp_OU54~8*x38FKAAh$%P|VYE@aUSR_72xLRte)hpEPo&ZZxM-`QEXO zo0$eMac55n=BDBk+Xb)PyMoSQ@YQdG6ho0`Sh_S+o)VG0TD_n&+G;x*2ESp4)}wAf zURVPOP?0$9Q`=F2Ca5El@vr;*Up3OHstHYiA zayt{Q;>D9z`m1I7SaC;HvfS=hT8eCb_>QfN5Y$H5$Bite0K0n=_nw)WUmZ6akZ{|L zV0=aX07VqSPlctM9K_}i_67T8fV_G7hyC%plw;m69N_LIxu2_?KNjP)74p;{IS#~* zV|W?B_>m!_=(SbxPlfAnmH?fTx8hf|*Q8WzO8|P@y=s@*P3bwCmj+!_N1Z)f>iiDV z&j%SfpBMGcj-_;gbOcoaSN0vu9QeKFPeY77uG=AAobj7Nm-wR!t^tRqq`3CF$T zlG^Y98Csd0uQjFfxiNwb1c~ELZVkh8llfavTQuQGHa9+&>xG^(aSG*6`#1ZWejjP6Ezb zFB){dK3HlQ@gb-JyV1$%4~@rkD`~oD-2eWqbG@(B+HxTB-5v>(Zvc=Djm8B&09BFK z)3d0I`?Z7AwgxF)w}V<}s%s}2W2@6^=a6A7s1oONxSly=PMuRUX3u!&s@t1tO|WRK zA;xJt2_rOJPM&=VntBU%Op?mPJ=2k9F9P@XKVdu9L0jWa%1JJqxsS^Y>E4zA?yp-t zljrvtO*swx?&NILQr;b{vR?WQYr__+9Q<%LYDw)}cS_Szj65{QP5J`NmH zFs^^u@Yt6cRA(C5gg!*&I3nbF96O$Y{{r33)r;3S=7iWrZnhp_pz4=M1!uK|4n@J( zCIP1YV_RRGscmG9%jPLBSz6CDx$IcHl8qSSb0RvsGzP*#K5$)G*;jBZzSg1S4en!= zsc=|BHMnK82m0i%BPizEf10#FS_oXYCW9s!z&XF*I8yW$NYe8=8#KLDr<;B$n++`% zyH78cqM%-%mR*NCHx$NW%hJ^(mYH~xqSRTuC z8SBk#&8x9x@v@>*Ji1J+@rJ3p*}`gqO3hEkCc9=;`i9~C^-61W?;#O8=N%r~MvJM) zDP~>EFMI35+I>cud)yY7J5w@*`qFm|i?$XPc|Juq3v$4V9p|vp{gBzPMD-7Lu}L1c zASoupa7}|ZuB8MKW9oyVfEzAq1iMTKMUCJkY>}p|@-t+r?abL(etIN=`u^)r!h#RZ zG?JJM9~)ClPF^0hT0>)zBXq*gQQtRSCReYF0t)aFzZWcY1)Sx(vvU3l`2Hg6M^3`nzq)DRXYz=aysTzqBH)uvTNspl z=o=7%Q)le)zCzpBqOnilOws-2?>x(4*;aBY3W*(RWNJ!pnmsNfHx-^h>?`q;^4Q&k zrVkwQL}NF^+m^YSpc^j#rO31-Zp5Gjw@pBD&A4&eU#4&0n!1*!<*p z9oHUr$Irq9S0gMovJXq^QwgDN{{>Uy}7Noy#T6UiRk2tJm;O)6-3%15SqmXo3 z6Di;)%ECp2`F;HK-K7B-OaD(!i-q$v%bNc~ z{EuYcwbe4|t8JrC?>P4dq}X_ZrC-E1veutH`}}tt=`?oWV@P7TP`dlL4Doh48GrAX zW(%^Fc2fgGA={I^Zl{97(HyJJUyoSQoz;oVIyvwv1+&EcsH_6ibZW|1e`MWnbpcRr zmtOeHM2*?2IZ1-B6V1^%O#30_?z-QtlV2 zeulngCmafO{l!hRt#ydwYZPXPUSRoHqHL_6{;+cA?qN!u?RBT+tlOPkgOxwPXR%ra zBxrtDACIdZ^p~J#&2WU@y^9@1vf;Zr2Y=6g9%YGgsElywYO}1OBxGp$dpdbUs_WB? zki#l?v#CgLmeqoDADIePW;7d>IQ-R8Zf#8*Ob(hSc=LfXnh-FgYzD68~qaH#A}uC2iHHb}ALQ z@)ADqiwu=iUIsu=Y*>*ESmOAn5T8Fsqoax>S%Zl?(P`(0Y264um&jM$0Ji`JSWkkr%^)l<$-MIc*A#FiKF$=la{Q zQ#$x>`MHsFq1)-XY+b6kY4*GrZGQTnN=RQ290Q)U?q*ozi-lklafyQEH12si|AvHD zbbmA(x|_t4a&WrBfMu$kJM+)aIbGy6t@QjkMH|B4eX#J3>|z)DM;LwYT%oiILcW_l zmit4{XF|DZI7!*gfD_vxho+chs;tix)F(W_xN{h_qFC>1f~^~E7+|08PUaDy?`;Yi zF#ZPIm#Jz*Vk;au5&kdLj;@xRVqls|mtxK3=R%avlh5bohVx-hr ziFVraT)&89f8dlfb;e2aDN0;{(IBq~g=*@N6ov-5LQ&tlxX`e0wD^)cI z<9D3uw9t*S9#{4Bf~z|^SDs(J`JeA)<`hFstlz{`hAeO+)TU)53Eh!4*YjKaX^2Iaa)zE6%HRqa?S^Mi|Y_9&{dfi0`3occY zC!Wjsvr5*OvWSd8T8O-mj}fz~5lP^C3HPDQkg`d^_emrtK?ra5T&cE<%{! zRF0x$E8WY?kN{h@C=Nu_N#JvKIsqVZvJ4)VYt??dxg|uetrmZ)X@K0Qsv~}th~D`7 z%&!n-nK&bc(MuE4&_yjKfi>o2IPOnTd_%JY=V-OkE%vW zVS|@F;sak>&>uf}ipWFrBwtL5-x<4{vk6GS42|x1L{^;~h#)deY=c%n;%_e|)lES;ig_S>(H8muNp z4JzyKLX?($m`W*2`>xnJO`oZy^MR`;$rGK z5G~n$Y3Hex)d>dHeUykd6#A8O8`yF^G&DSi^;<>_XEMK%LSsK*nM4@fPoPslCHiN@ z%uc=nBQFW9w1PV!;ZD=YSF+)-u`Xv<3r~Uq0hblsQxQ28f^*WMapiD8+<-L5WM*Y2 zge|s&$his11M!vgJZJ9SD(pfkSCcUg{;Q5 z;>knc(x!ks z7+i|2?_c*%*rnL~2#ZY$=XoB#piaum`X&&aCHblJs+}CKqxy9_q)ZGjpx5*TTl$H( zQOi5cSYy#w=M$YoSkkaE?S2H2W>or?h*}m{UzIyI8ji*m6fb8>+Vfb@&>YualWK3J zUbkG2M9kE&R;|N(pixa2H=0d@ZB3~|c>Qg3|Hdnfkr7VON4lfWL>GhZligMn!?&)? z2%aD|CBLCGpUjiuRlZ@aIkCC05Ntc;&XV}8ma*+^e*#Sc-crwrI3x|o0L=hN6*vTL zWsu~&fM=tV$S!a{(J=bqRD~euAraz zrA;7=mM^~muvIZpi<8a?(__#0fL0k!X{E%A<{YG60V#`x%-%*U7EASt{w~Z1ZT(L98%Z+^H|!mhY+D!uh5wn*}c> zxu5)H%Z!$XC66EP;+&l1yso9UfeG!`qXkxhG{NK^1IXt;69vMSPyQi*SV_s;GVR6G zYjn__xJ^tDT9|a;cy*fO^|ee+QXf!eI?+6Q3-MvTe#3s?fD3EY4Z@HNysj%TYoI10 zUyaI~i9$+((}!HW41m^2-pCdo zNO(E8;o{pZAxNJ8vsat?R;%p`q%PYbNj_+~dYB(K1b;cp`_?1=JMsE$;XJO>&+3`+ zdRq_lYmfX+@h|BzCZ`T#W3}nPlXc99EvJaz)$S3*OXc_Lx_mzJKS5r!DBgT_($?j80J5-9EPw| z-Gp8JC<|3C{JZ_7^NdbHc=LJnClO;@TW@$zbA4!SPy5f7@;lv#wLL}w^8bgmw+d^s z?Yef`(gMXP?pBJsYl=G*cQ3^$?gS`S+}+*X-MzTGyE}mp{`C3Y_tUkxb~y-y90~Vz z&vA}(lB5Hu^U@guw?3eqqA;Yfz|=Wqfi9>z#$^sFYp0yqfcLQ(1(u~m$=b_4UV6bWlWY&wZ@k=NCwZ)3Q}9sCYCpGcyt@y(Xuj3AQ<|Dn*&*=9&2uIg%To z?~=u<^Gv`J&ZKo(*o)N(y~0P!R-OI^<2p$#pcVtRYAK_kx6%?ta`8_TXA<9EqV7eO zQ4>B|lkbTvPmnAC-OXj>%*|i$x?U>U)`~b~^Z7TC18gSIBY8opa|Ks@5d-${bPWVaT z2pU9zO`a6gu8)t8s~isG9nV)a!$a>}6Rnl*>o_qg+C*uo)X1G3dIy5&4`Jm4PVx@B z-KP7C((Z9)8Is`+q7=oeD0R}`Na9Bewku@L_Bsz~z-yc!*d`qnu8p85nk7QC49>Ek z+y(4wHYJ95OZKg|6^J8MDD`@my*~OH;~wr7!eLM5(dF}YXnb58n#+!i9M)JQ?v4EV z#%}lVeY$Ql*5{<{`scnYR{0@ z{n$|6v#F_{-LV|7?Vuo{tA$Og4@9$*2xm7{7e+u;Xena<^ByE=?+hC$u8tHHl*~WK zg~^?Zbepc(Z<>lcWAO<%avmL!6tcFcW8#0pyc0b7<68|8D_LWR0w6GwX!s)vuk(80 zx$sUvB||(QPX06C4f>wJ@u5zSFEt0uwX3~ zDZ5`7zFKyMysQ<+M3Rfwc&w+zm*-3Q=a<_{0uux?-|o(3Bn6*Ks*)MXjcNFJKTt&+ z{vNpt(CAp1RC_ly{P^;l9+Q6kHv{AN9~Bi@YcVP{lWdy=IEb0;@BKL|N z)=t_D15ZCSbKxIui$?NBGb=ky6f4oJCivdS9gh}p)6e%^U9u-*SU{C?#=(+1RkOUJ zspKWx89JY4MCmTBiu#jztX>BqjR$M82KMW+qUeloWsHkg)w8+p^pKgvn;ng6V5uYk2; zq!!!KgNbZN*zh;*ya3q$nE$qJzRy{tmy(pqe`IgDLfy%-GN>5Gs<5{((kAsK;lE$A z|Dg)%(BB4Sylf$6%uS1zj~$s)H`G^K$e=IlTMu(_AO9hpC|a7}zsxK!q-y4fye(Qy zp$ZvPH(K&^46bHWh=PuZXT#)btZL26!8~hHQ>7bz%^T-|q4JDpaVYGH>u*&fU_GDZ zXz-15rx;5GB8G;0uBtgb+l)}FB|xI+7=6Fny{MFKx2ueG-*V2Cu5wE}&6rF_3SxTd zOG}q%pTS9u9EpeM@zXX~_vVZt=dJed9FpnU^(pF3G5=)KAzF#eS@8dfVJgio=gl+m>J|j3^DE3lX33yVS|Lp>ZQ|gz( zZFx(VbZa2r0rJ$FewHOp`GY5@^d+hP_H>-P0B3BTrMmIsiJG;LA;(~Ku1BWM?a8hR z0?MlDqhq&?h-p@6iC3PLlK?sNcj;S*)Mk)9D$TVR{;%@Xx_Se7r8BqDXQp@pF8WxpcariuEuX zm{;t?c zdReA9rE9S1=aM$2Tzz)#k0uHOiTu>X>d;jTu~$H36{W`;sWW5?Wk}2vkrYPiSI z{x`VupBT@w|JQFz#%unAb5^y6>7%$&1QW|+oT**M#UsuaWc`L0&fxul)Nj=%PM%jA zxVr2RDYEwTZ;k<}AJuIr2$N|-#yK~gM<77ZHj)c|}q0 zj40-Mx>*jt8qHuUvFi*Gq(xFhoCmgNV)w*uz(_cUhz$phY1EI(NnG(w zejn!qt-h_xz4RqI)o3*%pe_1V>?R;Nbz?MzL!h`M2uDSdEF(QFewx+p<=4_6B5X)x z0V8#|LIXQTaBm<7bM{J*=4%|OAimV_iJqoNsm+4O-xNi2Z?`7yXNeD0BOB`s(c-vr zsNyj9{UZC~L&D}vxD$f5+~6Kc!baW!>mXn5R@PVyr09Jem9EW0ghf6(+=he*va>rM z86OWepL(K!%a^fRqBWc~+L7whR^7#uT%7L-ndZ0vPRLhePSvRCgbaVzO2poX^Ea;z z46c=3axxMgTS$ zX=Q#l2OZ*a6{O2fR^XjrBO-KBM{m$Zd*svs1Z5bHGU;UhoHu)!N?2?S7{@~PHgE6c zQ+ViA%W6Xo3QYkcPVcq zmbPe_x)V=a8%gl4?~`Sq2TjbmLLv1jKbo07BV_D9x{)?s4$Rzz0^%>6cyt|lkzT(cjo74$QIV`K|zQqoT6^h~00gy906Mh*E4MR*TglArqeZUH{}o zCdtvn;=!Qr={)dQ5%}Mkx_>^Jn{UwJ&z9Ie%H4_35O$;U1tl9h>`6r4In`@4IFj+Y z$aPP$yi}R@o@wv`h=`0zs~o5J3*b}CQjqPf$Wwli)4RVQb6@k41;afRT=$@?8#lO^ z;vqQWB4AkQ-JZ*Hb;agjoMrtPzMm#hc%R}wk{J(BLylX|i-X%Ue7t6rRw81P6hb^L zr_iDxX|k+#b3h(5vTM;h&6|t#9YCe(ft2JZZn^lX8}`OI`j|gy^v>MLsj(JQVihxd`@`yD-4BeA zh98@C(dp3}H0bPaEpXNDn~~f`6X_?_qy^nr|M4*GKIhnOAdU|1BxG)gH|xPl7oR%IIRL zCTg0JH~in@1)lHbp9~g+NL*bwiS@V)=TzsO>R83b7fV7eb_C)HoW~z}4BItSHt3((Tz@4rOBVQfl2aYlN`9p!l)^KeOb23qrFtYO*JdXx1wpQ%flZU z&&rSItIC@VI0e%yl}HXRE&VR=|FXMhG99K&nV_hlB~55i(&mUyZS6uw-N$O`k~YnU zO7$M$@+i>VYH9ciW6O+s;E9&x)XvUviSz>T*1*~j`8q;Y<6FyJgAI`H9 zQJyohFr^TTGiAqQ4@7hEaVhD@&>wJY4h}3i9{j7VA=Swd8(|0AGw!oKjh|j$c=1h1 zR`5Ds!*NI^%d$f6A=WheUash_%EgOCc+Ea=Cynem4tgl!j+R{uo?k=Pg0lyA$usPA z>Z-A6lFy=-Re~8*^wu#3LsANZvFbHA*s$di!*1M?#&jzfauSh>##2+8L38z2*|)jerdo57GDvqdBKEco(pOh% zn8s7{u7qq^Of4t|`Xrp?T9HOvSFIgyHVSXMqhZ`Jm@s$OLNy(nsjtl>FfBq5m=~rH zscsL0cT(mJ1^e~mXAxl}ZY8|sL$CuG(_8VyGN_@-Bj0O^*r^V8ocTF|y^B>g9Nnk= zk|eNly)~k%r8Z8#9jkb_B2uxVG$-~}sj!mlF!f73(DmbwtP&&=AVD}=(2woeY{s_Q zB$O!g5BeGOxkqZ-8;}_*I`PXyC{owFLY2_4MUZ<`}lqFmXSho@v zV-}hKAa8x_hOqmDXWGmRyyKjj(N@mbqPPc|ua;-EE8GCe!~hSKX({~rn)c;=qlZwX zkH7EZ7jf5o%F=aC-owC+PDNHC$+Ln6KeB&DxISlvp$%1MP!$fek{|-@ zxX(6mQ!DINwR2k1gw6rOSzHT!Ym1StN%_ZKuwaqA&@aZzeCd9$jtQIh7rNP}4F{hc z;rnC=OsUkvk(B3~#9@or@8VN+t{E|z};J}FP+k})RA;UPDP~NA`hm;?W5g8sSLcX^$yXXVkxc}{7{2np} zF}kP)t2BHb$uvDGISIqya`Mb*cNkbfxApiYW3sS%S_y^)D2mD`$2uZd2+)i_vzF%{ z{0{*%?Yf7dsh41sb?4M(>T_VN9qoGE!$rXoN#{I#y3TmH z@n>bNGMrus9Eao=Ct;@DP{P$4a>08<#(jzbT62fRXBlTB?K@i}-uzCMo0$|wQAnv8 zqr{8L%_K|oIh!Q7e2V2;id9%I54V?e60){d?v|-NToIa+(Ab~bnJHZxUNN@!W-?%{ zNIxXez5{!g>{uRS#o)Po3qiV}%+Lx(GYe)+U1OA(Yc=pxWU_aZdM-D^O{G~AvkoDQ zWy8{GEm)3G<%WkE+nu(gr%%q%MvE7(coX`<5pF23Io}}%#yp6u19pn958fTR+&RQ$ z&O|Z?1OyyPk)Y({=FWXm>jx-^#cWCES*7^0Z*gSQcbZ%N!Bx*jog@0ECWBi4@$V~D z{LEH@*6pnLggTcg{c4_OLi(2nCX(HeAjY^^Y$~dv)>%SauN_3jMNJqBEL+;tb*nN$ zvv`?4V!fh$r8xxt=?}~)6o)S%Vg`n>C{MPR?tHU)*{qc04ovXiopTpLm|>GnvvGZr zZe}U+bH_iz8L8?&H^5H$X$@zLccm)pgdZaBbF=gQ&o$cGJ=VsSZc9RzUhROQU;i4H zw~+WRB)s91)zqMq8e;xEz~lo7JqC_aqV|d!pp*|6Xs~zixvU^X-exa9wFPFMxm5cq zSD&R_`#gzUPQw#gS}L=K8!aA+oD!9OiH45QCWg)_+S=nF6omgk&{0qj^aL=YG}E<` zRu+h2HZ>AxQU1%2|6K86gfQ)d2hgzO*=f&$Jpm!?1RU`CpbQrkmy5_+5i%5q<}W4S zVvU|;mm(g9z$TV{)N44JSb4FsT70C5S;-VGP71D-L8eAZomp@bxQx;p_8jEe?+GV)+9ZsZ=%}+gFj(R9CFyOKQJH-t%IP1HfZnIaeiaoH>_j zwljlF{v3UPi|78OK9L3cf_Yy43g5no6NmM;apC{QyB>K&^h7QQ;qTuVnN{|m9{@-f zq*tbJyHc+nf6p<9GnKl-XVvI-k<0JApP1X0R5$tzKEgZK+yg5zy8MePJ{8xu`G}A; zPbAWAJL zzvb0Sy?)@xDwz+;oBh1lKDT)J^5e53iBH=1(l%VALr2i?Nauze)r@=Y?*)zRKG<|!qevdUzSG#JISCLzBbOkhE~<@A{%Afj{5q$WYXRXbNb*_KC6r_4=j z4YnN>i!xp^7sJP#tL%%a^U9$J$V|_PT$m)r{AE042ioxAL5Buyg)1nk3d^%Vsh8*{ z2iu3&dCrYvi22h+uLwlFTuaP7hQ#aXR&j^-oCy?(ywm6HNi72{ovBsomERv~UMWM1 z)Dhw>6LMjsw#*a;#GTV&VkEj|KZ%&#+x7k=v%&enA&VD|r>l4pRamFP11$T$siUD- z(rbn!>bv4^UXo;IB>{wwLqjTRU(Q(0T2&aM{k}B3>pQ zKmxiOtX++ccW~_nXPWYU3RiiS&&&*$OaOj)Gt#Rb!5(f$wPvLLTDM59i$+bXbaFq& zq~B9&BO-l;litv{C9cQ>Q=Yp*%x{-pNOYVgIIok_TsXy!6p-bI}{88OG*z0Dm^VUO&* zRN7TeK3SD_G#l{#H12xM5*9A62(o&b*s!~J7F-4OP#h8wXa%k(Kq2-&p4yDw{NwJs zpFC{`KYKdQ-f(A&Sf%b#CEdU6@K!D2+{XE1oCzlIGmY@5YWLpSc;wFBlV72S5wa2m zs>Gv#;-Bcw7CN52%>lwBAt;Uav4a&Kp%sAgaxuoWov{Vl)8%@Z`fyE6P3SI12|K%L zrN=P43Z5O)dlK55y`b?m913{C6nG5+UgsOxOit(~>i4gACkv=+tuE@%&)i{rsB6?! z<;XKXU!RnfZmqb_3ruaheMD0PuF1+*(9-58e8gLvjb{=ojgCw8b2EM~6WM*TX+9#{ z?R(dsDc>z3Q){Pn;NKNA`;K9`J}gPZ>_XbdC?|2J=Cf-wpS1 z-Hd{tPxse;g*#ow9_56{&?pO5-Dt6kDDa1ynOW3S}e-qJ*zn4Zk3>) z2i|@vXnQWd=8M1_qZ2>qn*ZjXtRNVy(6h~}s>wcYQVJLh{0iV_r-fl`xrTX*6M#Bk zZkpzAm7n$Qd_a5~kXQBo9kK>^xmRQQ1~!aj>38G$hR{#wGL1?vG;fdlpNB_J#7qM0 zScs#!o1?e^!4J9-ZLWX@?|a<#L_&8aOKl)iq+Hiz81+9`G!&l>h~;|LY2$XI|HK>K z*DO`JHO9ngc>AFpb6#iBYZx`?#NJ|Q*A$qztbeFo>HSaHib~15>@2g6M2iv1p4`tI zDvN0UY1*i2z=@s+vUnY3b8l0KtW?^pw$jrhUK6v?k%&r950^{jEM|`AwY!t%vIH%a z%bAs@+@ouwaf_mDB8-OvUh98ASN?`JI~@GF*qgaZl7H1a@(lZiK3kR?ER}bdpULx9LBJC^XTdY9Q;?G+JkF&{WE8CP<5csCk=UyR z2`7Ui1{M@RP5U$JC&Sy>?01=C;P+mYEtnFNA1;?}m<+9zeHd#Bp%~lB7TKEejU-Z! zTI(m5=o}oEk@x)1mwVJN$0V+%PO4EZj3PPjv8cL!NgTDo8*X)9qt7kqi@)mfF!-7ff{B&v4>J=v7*aHq`5^>HoqVyF+2U<% zptnlvr`+B>-&X-!KW-I*#rI0M{>>@3z1ATvj^H(@*990@fav<_f_xRJ<9(4(YiwXewy`DCF|VxdBJj-+)dvbPMbkvTF2u)kp;x>TD(b}oYO7TdzQF6zXzbnGPc zU@Wz;BjON&Sd%Pi{n2O^8P86u`0ivhVhALf`n7q@z5kIV$of0=K*#ACzgs0^^#W} z99O9sUi9OtU|;}4oB=xnj!Et%+fBpNY3#n;Q2319gX%$!w-MI-w3X%nP2*PC+vdaR zSF_tO`z#}m>KrDm1~h#}J&AMoGNuY~r681%*E!QdCCgcm8M9X{B9WaJg;OypxZZ>!$-$d-(F&%AJ7XHzOnvZf zxiHjTj@(BGAK10E05s8CJ+AZX6%0!gCC0ukjsXb^!p{{PU#1|-2_|XyAFEM$-rv@7 zAo9>z=zP>-)uDMb(-O>?#}8VYr+mvPK`4N;75meL^nxqd!nUM0cdj_PF0HoX?YS8N zp;T}j)}GX>83f)p53`B3bZc*kYS}5#tW?xmEMF_;BS}BmhhK@N1-t@9<&`426K0bH z<{=r*i!=?*{6Meh&sW&Y^<80q9KTO1&7QauNA8}EhcJC%etgI+5kxnBy=ITlAjI z9|*KnVry!rXC@ggjC8p8@t2ybCFMFlDui8x;OM9OYEG;L@r=IyF08=Y|*PiASUF0qEx_<_ zoAU7esr3iB02}Ip?gB={F5%~I%kldjcItCkHJrD4#}6v07Xg>|^}SeZ1>`6Cm0NQY zf?e&Qg8iy>pKo!s){ky(K525%6acHpD@=s2GJxcJ5`a=$BbL5SMZIjU1QJ9b>^m*J zy0k;nXcFPCe`~J^oazhcP^k4zEa=Fz7@*{h5_Ipkmt>MkMdvy}{93MAD<1rSE4K1WX?hsqhUvYUNM z!k_js)FsC|R^hZ=j*C$&s64GF1dAXzNboS$`n;LVoCfdgSFJAG=P6~kco?_dz^y}y zmS4_Y0aq7{8$Oh!jgw_2c*mY~zEN_X^f5KEKpgQ)0#gYK3BcI*^8V=y?Cs(pK~}S} z)mGP!bbC9pLO9nOY$s0iOKRaM*Pl+yoXG^J)TdO$3k@ePvkx~IU^ulRnoZBhReogp zNJXwjc8e}lnQ-YCYCN0YS7MCySoad^aY_$ps|QYp;5Vf@8_Dp{jMeeinijr~2Lx$v zVAT#?OzeEgpHcHoUn$)RR*+CYsIs;emX6G2J}sh%l8UO?E%XMT!Pcbr=2kl6dYB+0tsyDc6^135jl6rt0uxdqgF#84Sy zxC%7)0_hp{W%tdDVy^9CiOc~BCjK|&ux=4;@Kj-~@4R`M2_rkN-e9*29Z@0;u6e%_ zt%XW>OnBxEP~yY&iC&Qcx)2D*@X@_br{kl8=qr%f>`oZkxMw0_e>VS$qhYd;!v_#) zY&Qm&@fY_pA2ld#AIXJv-pl2@<;`&BI~SmIB=RYACem|%!oV5;bTAs*o)o)DhMxs? zT9E>s74`xzrSCb&rk6=F074t8lm&)Lhw^$tP>qt7BcahYs zXKrn`T|~5zQ#*y5F}~^sV7&SyRtMUOWb^M{%a7)VouE$F&8?#mim#y*OzroseHgIw zjd8%f;zJt`+@HWZk5$$Z3?0fFy9eV;yx_@;B+K(b^lD;ubo6%enItw3_TGcS&Qn9G zoE@mKln!;n*Sb-@7fbo47^u%Yi5H@cwXtABSOBiP%1(10(%~X6+B?PIhNaWJJD;u^kLNy<>UufKZzMoPr{C<{pkHvGS25`DaKo?V!o6x)B>_c@=8 zW;t}Ey&k^rGnv4!Z_9{u%3O$;mOJ^Fo@#bQ1w6(p7#AoK6r~d-QKz?zxL+wG=Le@K z8aw|^u6$JD`6MQ4cemJ+gs{3!d_`SC=96xB4zsm=SfXnV!i5tl4-0<%9J}&Yus^f|@_=8r^c3ut1Vm;M=?&jp1rk~v`tYbiK#gAL&cq1S=BDV@2MeDiMX z6tXv#41k#;qM$FR)}xvBS;_TTWb{Z4VG2?uSBgM?wyhsD8RS!-730{=BB-60o+hlX zA>6g`X5TntDeN=C5Amx*{mYkRx05~mKb`Jew-s7FzhghU z3=PYP){9j`M@h9P8-O`;l{g8k4W?$CT;$gafD=+Gl>ebd=j~svd z3+wAwpTsYL`n9G zW#TT@V0j<+@1M8V>hUU2ez~ZX8Ob*E>d5y4|~n18GcFz*DvKvF^)zYrxY*; z%!QB?nvKmI+hDx@Z4;10lbcBGQq2NcIF}_~*p?OMAn4TdoP)>z5V9kFvm`LSBIPdz zd*SiidIQBL{E4EiAfg+RLF0Ud)cNC1Y7cy}YE+u{P4B9FwCR4?Y}So^u#mbe--4PU zm-Sb8|NIBYIX^NuG5^>NhLKxTwn;M@wks=;yTyKI`E=?DVCY>Zw3>d?L&T56PvrYW1!$TXKlJ1tEaG{kb=|qcRC?@0u zbn^Zlr?TELVEyaYOE%tw`Q1DY?`V=}5^?BBXO@JxsBvDtZlCEth*8OB^D}^}RoTPS z(Y;WdK)C-RR950iJ2etd7cC0sd6{B@?WosV7JkmYG;c#xK_~WIhiDv`DIDj-o?V7hFaHXn5U)0@t>QLVmDE^l=O$dbotw zwne0q{|mMJMTMowhsB7xKqr{jr`26HlI>hOCVnWA{%MEopB&_$A@}4Pxd*&eL5s$} z@|7C?p+}(s)D~TX=R|x!bIPSPC!Ume8=W}jqD!Hoq8ZS4f<}?{r&Ey< zw4Sp6l|^4dO>v11!T(sy{!`5JFTRKS4;q@u1+z!C65)SId;XLC!F{WEFN*Si*n_WV z+(_tuALd!C^!fkeVWLYIc>nn`{_D}3%%Wf8+IuharKA7ri~sqAqDpZ@VNuNA|M&bA z<%o;s4^+$aR}S@W`w#WIr;K(m7>r#>fnjp-6+QkD4*4AvgzajuUYTrl`3WuC;9Ol@ zk*&Ymt$XYH^$jNh&ydF2NbmLnz3g8YHnWO%rYu78<>U4Y62V^>HtL>21JKlIttLSa zjRT>EHRu=_L(Md0F8cS=j(v00f7kLDRk$qwt|^R0gZ|U`pH`l=|FH5j*Qy~opO`k( z2j3z-CTsme-|BKTRa9vMYRl#FGXGs45_v*B0yu6!FZN6e-UFh8q;zzMM@L5*O}5!7 zYnB@w?dKIx1{ruPSR=@*@qGa|A%CG_v26xnn0R{O5zKuMZ;eSpw zr_dhA{Crl<)N0*-PfpV?#q-UA{0|w%ot8lX8r6 zx{be=qMJ;F1U5nMVIBLY!>ukgQI#}yYH`cK)rkewE!ug|h@xg7bhqxi)`Jywq#FKN z#Zm`KfYUJUWUB)+Fh%}JSg(@m(k$UK^BVMU_Nnm6bGhc`lE2c)5Q3ZY=Le9pmKqPRklO=*p(@eTsUPqlXYguq_d`)(J8<6h56MB{f9Zt{i~l zS`RDLTQY0&jwEn$a=L_cfy?c&XgXnE<&s_-S8RhmnCj{^JSZq!WQSkR*h8S#>$B1q zzRM@NYs)jhdjJFKG{isB8y6=ayl%trB`pD`0W}{|nVtQ%xw%!D8)qlqhe|gag z#np9xKyJf$D6=!iw&mXuhXo-M9!CeP1vDqYufF;S|Cthl!D*auCXdT3Y_EWmV60JP zWs?}lL5#oCTl(;danW9dW}G1a1H$1Cr5flbv&+0KKbQcq0G=$BMnT$#v9(bW)d%z| z5hp<=Ic0}@jIam|=K~k5-wkKD0uH&J+-YAGyRTPtQf)8lQ4J1;UAAAxPqME=FVMc4 z(((~ha=mF?1GkvcbON%fk-g%#AMFI_7oUu}$F$Pe#Pd(6o~U~OgaE`>Or!qJ`s>EK zmwNHao5tpl%SUMDas$m=FfT+zq<^M4;B#a<;#)cXk^hqh!UBIRt_o`Je4lo;s}dIe zqZ!^{)Eg2JeDQ31fEbzOQbuN~f@E@^2#`P+VA*SM1Eq7HM9W-u6UAPFrkFPU%ghRL z+UmhX+`xZ93Fg|*4sTviDHq#bK0R?hZ2a0VWB|w)V*E$YqKZJIUs`3kz*rI3t;`h~ z8XC_!WVdANHGQ4SPY=jB)$Bq$$PVzS&ovl-ez>SS$2Bj3 zUapE64BTOl^9&9uwCZtEw)vW2O;Mox`iWPc7kjU=JNpDEHQwjhp#@!sA@?5$;qN(odxnt4&>dI$wSvmG|V zkidS6RFkU)6+4!9$O^G;5Zge$(ZHYZrkCN=>iufCU)+wwK$`O=XUrJu@JCN*-)Ts| z&(;-2|31a1FmjD}x6>ny-~<4~i|n{z$VVY`ITF|QRps{6me#*qgZ_039a7>HG zA=%AzD}Mws&ci)zZ7H5j?K<^FbG$jwcgM{C^!23$&lQH~ax+tcf_L&wr>0(N`NvRw z4|o~(b)S!e99v@#E|VvXTiuozlS4$2vEXHm$TQUDq{78vj6)Im&PFtnT zy9umk=!ZD_O?0ac&TdVa?tg3hkHD;<(RgKn?ecI`KP#i@U-}#|qk|n=n`uken;T*9 zeU2dJ2Ca8s>R$S2UU-Gf^2F2MOK$?A4bBq7Uu)dx`$n?)d-7||zxud3C}A*le;-?k zx#Q(dtd-sXt?umZ?M)3jRvy>X*49>=&wRlefQ||#94*tFyi}scNHhn`#Y9%22WR@p zRadiqdMYZa(;`hvLtdA2LL_6}7t?&yey$!+a<3PVYvj1GcdV9zU9dvrgCOwCDNoN9 z`)TUyE8v1b#7~OQb|AOIlk6Na*vNgdJ~|nXDPXBbtL6Cy>qfu7E*QsnAORB$f+)|0 zsdd#NJEdAQANYsg>v6D`b$9A5hg6$}=Sl1Qb~*U@K~nwH5ghOOl$lorzS4-J2V#{v z+roSe7uFS+AI}KJ!ZVf#0wz_abx;_DJ`q!5 z(Gp+sehNe4SW#d&8;fWCzYH@VNMBf;|$~{{H=U z9y}7(_o7iWy#b`kCfsOPqAFkC3q{kADkoT>`PR_X=1;b#M&wDQT&yOxvFjpeRF@wJ z$3C3%KRk$^Hy@x3ioaY+A6R@MA@G3t^zibV4N7&DM`VnwhQo(XwNO0{-zBmZqJnfh zPj1=w(-tk{+=B$J`0Jbj$0!893m9QfU-q?ivdLl*{M5Fub`-cK%O4yrt67tHJo!r) zaug~Cnz`+mzHZx^9BBEY2X)JNAr56a1Jm;k1=!4quPh^aOAmHrTiz-L&C7(WXSsBC zO@r7bdq#(PlptYE1e4EPJ~(Tr!uR~;TE|Yx`MN!(7uLPTI|XE-(KIyf=L1Hs0`s_%Dc%gN(t2M3b* zJg%Oba?dDFX9__GD>jVmL(f>B6|SSp)y?(G(B)ZpKV4@}TH>(?&G~{30XuMjfM>8` zCTi0YlEc`ed5r_C>4dK>`?=-7LtMxNdg%sVUvPDJBM2&h!I#ex{1{-!?n9v`>Tj1{ zU_EMZ2j+orG{(F@_M&dPI~H{JQ9Put`Vzx10kIK!4~gzJ6cI0w{N6i}@7=a9O z;z`C{FGWv3tr#>4=j!~v*VLbnb7kTU^398|8rBRIZz>+zH^wpiKCy156%Op0HHrv% zBy;d*-69qAe$_TxR_O6T)817w*5~G7+Tlu%U0Pcj&U74cuW^3PzZv{R}iE|PD5m7zP!_Hr~=SrW!im7`7mu<4Z znD<$)E7@|GyVHe;T{kd0P|0#CYr;<=JWxf2AHwYjub$4g$)J>0wym)9IE67eXO4mz zGg<@T)Qcx=IJ!kB4l=-D5k(u~h<^rM9!xcxQ-jPTgXw@xSw)?c-VW<35%9{f?CBd2 zLYNl*@V5e%ic5-;vY+>)X+PpNnvn%QocVt(ls;TsP3H#t%fZPJs(gvp-e-2AZkc^x zB=w$Nqoye&D2&``#7I2iM%;Q(vAust1gm?!P&%*H2v-%_Q5Q!^ar+7Rd2oF?Bt_L? z-NLWTWjWoBys=}va8sI3%g!F9)&uK=!Dm5-iRXEYo#bB=1Mv>S)$)K9`(7iT?8AlVhS_u2BtDg)I`Gx@GS?xfnSs! zK0XFfT=BU<@~iR)d^M~iPzJ@fJ}%QJr81bCk-l?R0yJb!UzrJyA%BlCnASn+5d86G z=XuZ(b!Z|4Y=iy~bV{{G7XV~?gk-xQ002K=uiJYbBCiCr6*EZ`nYQ{m+>DY6z8&|~ z<9KgtJO(o_4L|sSpXr`QH~7PpzjSZxMfg}XU~@Gy>xTw?y>;{t4BUQlVu7DL>}zIr z7zNwh$T&+%G>e*YLe+`TeAvpZEP&xud*k4)~p$GGX-c znj#_=gHcR5N5OEmArd=QIs_fH6zO}BWWnPGa}6$vQaUv%nS!_lZ#Mcv01HXCs<}zr z#>Oays%6`6#d0fjm0{S7^_}Xj4%&o@Cv@#jAW7>)M0bxmv0wcWgn2TpS9;Df`!@%T zz!#7ci^mm+4B0)}X`WXZhGpWLy-MCy$0z&Ihc`5aG5s?>gj!-UmJDhKn7-?m*SDf$ zI1)LOV`ru2l@hG>W{^Sx`x#Y9%F?W&)>?A87M%AK-O80WeN`lYfQ^wkjd~Zvb-rr2 zO3z0cEss!=5BO-7L-E+Z&>zYav3I=4V-VFJA&C?DUu(ey9--G!nOHPwGi;s07YZHT zVVzW9Fxp$7H>T^s^>d;(fcW-7xlN+ai-KvE9NVbb@hIlj9en^X`!twYb1QbGSLyxK zA@%NJjXFGhW&+c@Z9}y2Ywa*=Y?(QPgZ=$LTGbNCLGp;hyQq#(DJt^dRhy0Wkl(E? zw$Jz0t1XGNAUw7#+t|0`S=m={0|hNClDiT&{kI)NEOz6#7P$Id5~0o%GI8dL39BbL z5zW6s4TEgA3lueL6>(3Zw_KB9 zAw;NYA`56Qi3rhgm=m=B{v!XKj85g1Ux{7V{4n2k%mVJ~7QR24ayY?)W8yWd)R%6u z7a;_>kWg{03Of#F8kTs=qurTzWi&l!eCp_K7ZL35x11e2K3USnSmkzg`*l(Xu%Q?l zE)?lGeJhMf8a8!w*LowqTderP0Y}!T(vg)nGd!qnoNN|Iabli;yZZ&9IzI$nl*lH>c$6vVcS>JN|;~k5?2#bKe z!Wcyole5F)4FlIHAnT1A!OK(qkn>@ z0l^_cQL8E2B+|D?em)IXTA|!wB*^`DF{4uQcQOn&#O69q_r<3Laoy9d8k(I=-O_CK zu%8Dp8 zQcS2J%9R$x@)C7IzY7EI##Fr9jVT?ikHRSj6L!X`%sj6&)g791OovJ7rL%baV^(vR zb1@JnC9M>GcBRdTclKBfW5ctUGSS(?thrwL-DMXEgNhF&1T*25P`pBSY<;+Q zM=A6jinq*SHp-{IwXG=!C;*=@DS)gaSF0=~Z`3>*}U zzsVeg-5$ojpIluJb#jTr<<8?pKBz16RY8`fA7K%s`$BRwdaC{vIEtIL4j%$azQ77y z={+5Mi0r@l`BqYJ_aJfu0EWabTU=9+b%0(BpX4~(0b(A~)b2g@E}(0ZVj|p6S1i?-N;8SoJ!Wy{S4$af4F<_($)antIMTS^9x8qM*@n~<|XVYrPpmd}(vGCX+~ zDQrT{g<-ygaJ*Mdg@`VO-dkVKyGv`XI(kdb?e5+so*Ilvmb81@)O2j^X$LW<*PO*t zYwl+U(_}DM<7^sLezw#^V0FOy0+Q^OmMRo8H;bvtr*~sFTpS}ph{0=^A1bgKmzPf-|5CtlBqsFoR@JSlyT{{%B~3LYhrbTHfFa>bd5dyvL2Gdn1pXynQ6*ng%2cd0f^$$In}R!0DRfFZX9y-bTK{G7rxeoj7J(wKb+v zL6M`MePiO<_s3FG_ZawzmkAB*NE6zqC>jG4Aci1m1&(NX2^Ab(wE9o~kFs|PuWakO zg)6pgCl%YQq+(TUTNT?C+qP|6E4J;5Z6_ytfBUWd{{J}_=d7!BG3R*39Oz^8)?05~ zYxug4evyiPpMiXG-RIugD>ReUa#%vi?M`J1R8OxWwk=d5Eo&(%+IV%EL8OH(H!xst z^5BPR=Bwh9DAmm8&)8v za1V(6Q(^61jyZ8+LW1gBoQr$_ZK)<9i2ZYKr!pzV6BY*4%(SMkx)JLV){$|+W^(r9 zZ6Sl)#Y;k$z*D+5;@7j6E=)lG+Q(B(vqz`*(-ZB{xS5B{afHgX zaP;k7wZa-6x|gGXQ}U;y?njiQ4`)>D>zldvSXs$3X8X52qeI}aY;X`kPd@TI~KIzJxYQJVZ*_+d<*##HfdUfL|% zy8^Ds(T$M$IQA^aE7Lq^DpMX&uKZ^x+F~mSsNI=}-szk{e`Cb&jnh*Ry@c)V{PY;L z;f#DteA~0;9J^j)%H%+=EKjtaDvnN%H>*sNTX}UGIWSW4O0iPgt(s3(CS?Vp(Rekz zO2u`>yzqW`r!RYu-F|7YT;~VdL=bH3y+-FVd4gffq`Pkad2 zdn1bHfU8)0GdZ6;M@3Cb`HvO=!Kg#|soKoeuAQ&|4{9Pp;A@}yw}k|3xaPxSp;5QfD1M8i;&pYPj~YI!OQ#drS9?~=v6zqOYJ}B zDz)1+LVo*mZgKD_MdzLYr>57}-_RKF2e)IgofMDn+XteZ7>{pyxHMxIlfM>9dmkV^ zygu9TkiES4{5SN_oA>?}z1nom{yBJ1e+?c$zOFZ9Ajl;e&}5T{kibFV8PyxA4n(_a z>$X4m@cEsu?^_Q=pG)Ddb|{(%n%@-hSEF{;jgC~8>+*X(7hiV(48}-8I}Oc0+Z%|y z8#MU~ic37G>au%$eM`AKS@n+bi~M*Lv%%l{|DOkRf%j6nr&5Dpf+t6`fp9(Kry*6p zL3o?cdYm$CXAcSZ)Zx#+qT1Bg_0VJB+7gX7zvEj8TN|*QjT3V0na**-i17tgdZ9%E}ovGdy?sm4B@pQJd*=FS}c%CC=|n=K1gLd zK$_ai>+NpIai#F~YL?^cscE93JPtyAg;Sqv?D9R=4w9Q?gqLwrF4ky*|3#$|7?#J3 zizi-#0@FH`I9rj%3V>lvANjL((G`7f~KZc)zIi0Sb%S2@t>8@17lZF zaWGZGu<|4cGc>EV?@mv8yDX=s-80*Uy&VcayohQ#=1UbFY$)YMhqDu{4uJJOsCH7) z;L)B3PdI~KIJx*eZ1%_a0+IiSfm-9P{erDTbB>p;b6)yns$RYa4+Eo#50!6d7-Q!Q z!Ka;Rx{?pY!_&UCa~ye-L`Ou&2M<3HnSUD7Yhnavfn)J|I(mX?zD!s3p|n_^Kp}g? zbpqa{wi2Rr71#|!7B>YWG-N~Yn|!V`iZja%{qrHFt{=T|kp8BPiM@93MHzxnP3d}H zMDl&vX{a$=#DjGn?`Lk~1fKb= zvE#G-cwOT#J)pBKl3F?;{muw#SwV4`3XK2G=vEfdR7nQHKoF|c;&6e{+6##IHh017 zZ;h82Y}@bfR2Z8Gi@>xPN(Mw97NGGmKtt7)Q3hRE{&jIE$BWiJt+OeHCOm=(@j*&AfhtqzoBBPA%!{!ayi^0!GJu z)~T%xtQvu(OWpNtoSob65?N;o*ZT1}qcn3KTlCgPGp96Lg7ick>>$0F|NT$_VnVJK zj1Co$h@1d*GdOqC>b;_`9&QDjFO$jnXh1o+#OowJk z_J223JLWs(4)?!b;qjC<#L14nep&>hcjOu$1i|j{Q4n7zpnAwK6u$RMlKP8B(3J*@ zC?6k*W(+*PAMEU^lnG+e;yq9H2evN@aIapJ@Rauz5;Ox_`ce2=9lFli0nFI)w_=mF zFxUN)1a5>rsDQC%)b=h8e9^B`92weQO>1XoPvEPWGg|#!wpWup5NTXLM|4vwd^Imo zklP8md+z)v!wOh~D(3|`{Lu1L6JIwT_r|5@N+)D{y{KQL7PX$TiAit}$B_h0rbbF+ zO`hQ8FHdAQIw@i7CkQr}?pAyWOGu2GYs4)Ruzon&1zaR~N<_h|UVb_vjKx^gW^}9| zC1*Ge-d+&;#=4$Nd*bwXeH?C&8@De!v9XtPBU0OH0I0If)}GAE=y+q^iHopa)7Ut? zKbGfGhbY^}Pd*4PYYl*b1$|3^`D@Y5CAv0A^Y}~rFy$c=*`D=5ns~<}*E9{)0A+bR z65K62Pwc48 z?TiWT=GLbwi{E2M+?`qNER;pjr2)4!zVxfnZYu z7v)%GB0pP~cuaY~Op!l3B|rP&&=*k;?p_El=N(1|Tdq=PxZdyyCB_GB4sx@%OCU-& zL9?`WaWDvP4boAjqr0J6dw{b1t>y(_+f_cho(MGywF88@YCFS){gsRJOBlgu_b+Nr z%-eMOK#0PvI7~7T{ylJEO&avq*g*1}gv*`al|wgbC>RxT{j9=lF!?!YjuRX+$i-R2 zh1U9HI7)Xec?um|9lVJJs_={?Qp%WtWH5fM2J_PoGT^MtspuIs7(XsIA_rO6UKo*G z=0D~%`xiUtcH4Nx>9V2@cxTz^u%)0>|cX0jrexkx!v+ z;u84T>T(uiccs;!@yg(!&HLTM%TR89Ku0N5nw@rFa5%hy` z$`6R?DYoh!-ReFL^yeMu>s5jDJI8k7I3Wxa5@{pC0J*zS+P;Y~{fz6cw5M?Y9g|Q8 zW7Os>ie0Xlg2}Xt-pL&YcY(c;%-aSo0;aA`Sa2#u;5tO~rcyMFkW`)^;qFkHdSQ|x zh%34|)D2aE!iR(JzyI_1H&+hyNWj5gcm2POl>ity;R+P=qjJL_b43S3RUT{PDQly@ zpt{OHvpSVSiYH9QenIYAH(`B&Q%o{>ZFLpNf`=W5?09E{^~G1y99|0r96=xq>=?4B zXgj+fGs@~Bcm28+U?wV@nWl8hd7iAS+R3Pq)1tSSOzqg%qMHdL?pMjI+5~5mwge3M zRH;RP>|OV!%hO&%LvCeD$6#7_v`5>QDy522E7IeqqpjbVQW`WIc~)un!P4O(jUsT) z&a$9jDzS|^kWeK=Iktry=lJKJ2EebQsfuW@WWtjO#s1RH?mD4wt{iywEjvVdum~bt z2oKJ1xomk_0Xy}`oW!m1I$H8(Gn@{AOFp=~qC%Gevo93h4fP%TceMQB`L_Rr6XnuZ zO5dIS{C)xoc_b67aQm0iOzkQbhhJ{Pw^sh8>Y0aDDU(Z?s14g&(|J_=aC{xD?rkBkG*btn=XP2~6TvqiPywg+o66SR@ zZfXwEFlYdv3Si$y?4OrYh6em<>;BwMbSNpZ2lP%9t|J6KpEx}3Q7}db zt6o@6SB9d+J8dZ9_tz*09-aLn9|FYXNUSZBu5jd9<@W@r@@CQ`n+0%{EtOgZv?^+* zbP*#uzHssI@*p{~hwkqIp=^4A>}unMDW;kf&K}G_r?bsu)x|Ntdc1C(ANf84Kmq*& zgk*qx_rZK0_e5C(p@;!w-q*6K4? z@2O(L2a;{?8X>6?7##ByZl~pvDK0^sXnCE04b6;#-lV~>fjb$(hs~!&FBeMfTH$}Q<-vy?HK9+W~@Wf8M zulTNk7aZKZUN`Ns+m6YLALTk|$#`@{c#5n}x_3LFmTHh%8+9i5Vyso5`if z!bclc1Ox$3Mihq}Na@)w?lRu5&Jj~Y07aa%Z86HfydI%- zoaJLj5Ipn@yYh)i$_t71$@1gu{eqYLJseaB{22DfwJ4qfO)t?|eU<^{;A)u-{+h>ToKRjEX=j%o6S6Rq zd~bL)t6CZ$EQ%d+2rY5xZio*KrlI$NKN_%CZW9#SR4TH*abRx-S;E|^q$KDroKJNO z0H*DXc;0zlfZFd)tq@6$8twD#6{zHa9AQfI1Ws&<6_k7Jdthkz4|+y;v{0c@^XZ}i zdxf@j>GnK2Rp&y~F~Kdj+ucFSi(Q$mlw+l@ry~)df%wfp4^x(K5IEtl_Sr?B&!Z`` z)gumraQNX>n3fFt_4I>FpWSk#k!lQ`)1&AimF-#u&?KNc!_da+XX}AGYN7^9&LlJ= zh8j`Yd5pFLrUI%=R75K*(G&$l7|1-c}yFkC={9aw|X>Pm(-=B>~Xpu&C;REJnH@}?eHpi6Pgs!o5TY=$3 zIO*#2LqoNGyi9c|NJKV|h-@4k5zH8nkjjfZW1cg1vsZMyt&q^#Uv6o3(ePc!QHRYy ziWt>D30TBqNQs<8rBXpeHS%UFp;BMkBc_rBk~Q3pm_)YW?B>Ym7tRwkmIt3W(L{7% zMW)C5y4H~8jra511A>zMzL&R|)%@<6i9Z__AFjf+S)eT?p@YdKW+YEca2mzi)zx(- zDAqg=3KQ22>`a}t$kn#x^6t7PLW3RAYnRJ>9@;mk4B~t(tk*YA z1u1dfzudmzqteuf$y2vZVrgzMgvM|CF*muz(MaAD{a^R?Q5F#~V^3NWHaM7aspf3o z$`5C@s4s`9-H=0TSeC6!E1Z7u~WP0kinS*CJXLS#inMNYm_Jbpl( z?RDR=eMmD#8^U^~DKTY+msh8agUxp-OPaGXXRI!5CF0RG3`)2AD8YR1g7Cwz8cYcx zj9#_r7nMi*oPVzk!=R`v#}wtsSolZzV;KcN$>8c*YpvbS5G-c_z4!}QH?+y>-(dCw zK9RH`8g3JUxw9_lMmjGrW-17i^3w#rFh%_DsOTNI>htnnoqNq#u$R=wVm%F^vs65B zl^1(E6DahOP@tUEiM|&x6AD=%WH?JMfhiV{$x}5dOjY||=8n24pGw%D{ec{Op}%!g zaiSTRS_IZM%38ZB-U8ryMzjN5Xx`r>AWt%@_o14+-rNk0jdu!?w5bS}^5h@O%dPZu z)W!}hq8#Et1$)X4CA5K-JbM4dF?{XB1XS01%@7Qn3WR(TI%c+qS`dLcwCUm2!wZPw z^fNPTKJt5=^|gx?!M*G^p#zxXF~1%XGT>rXmOr8Pr3kfiEIo*z zOH2Lkx5uCU|IckqjjVe_Tdji$O`uXV=Thm5lqT4ptH9rlUPdA68eI_djHHZ!zFP&z z(qP-~U6bV(l9G@=-VJ|GiiQ8XFh4y|;H)WILiy_~}tzl`1l% zyt4+-KhRyvN9xYXy2r%l3Rd{2x^Nk99RfMm!#^Tt^4)D6u0qN9P735W_%&2$fRRkj z>-{%W^wjw1`^3fZA~U5=m7XaK)s^|hv%sOIY!AusK`&0J^=lJ4suRnb zxn=wL!K7!LNg6?Ec zmf5-Lsha+045EU&%O8x1pEtBVWe&hLy_&9(64bf+RTE^`(qT}(N(fjs5Pm?_H7z+? zf7WK@u-W=@dU~2)fem=~&|eLlu_Om2bv&CB!{MyniDq3eq#%?g(-=CR@3&$lGROo^t?lhc;0a@@ zP=MzT1nDvDcCOQ}bN!_4&wT>T94o0G+V7SS@?jw=3mr0Jm0^1PRMR!IHSeC!CzDU@Pi+(O)4I=>>A7B$no$woba@~&#Eg~lqm z!6?q9ggptkiTt46r)UnX`Zqx-76*Qp~Aq1i$_}ufop4J#N zc1ij4MwZ_ z3@-Z~vUYFCUKpL6c;w|-gCoa@PxO0c>gcWeEU#CZtrGJOLw>lM5U{wlg8`S!d)vR^ zU_Q(nm!}J$Hy7#DGPBNG?Bt%};MV?k^WsV^qI6 zB~pf;x>$K49iE1};c<(5VJ#P0kr$^Y?BZb0vZVQMqTIAmfM;O&=*wk zBHLGCZlcI%x8E2`UY1?$)pi78oRsxhKTI`&y!rk$I^m!I`pe%L+rb_7;Pz$oebMaf z-y95*8tuy&F)3v4d`CA&masR@%t|AruTp~9&I-r72v2*BZZ_{T_C{+5N3^dN6FmuH zeFSp^#Ka&sTo3RZKFh`49nTA;u~{LaqX(w3Tj!e3mqNnBi~RV3xVE;YYhVBpQ^=yJ z9Eoq9T13$n|Hwe9^#NI$95EEW32${zd&(CdTp_xSlp+sy&Zk65HaXfCX&9}5)phaO ziBeqm#R?eO%(u{VWlZDIOP_!3*aa5pMdugy_-~8*5p00r!Oq0CY_)l>NwWZSAo2MZ zHz|#vh$g#ii4f7M(%OWu{VJ`D@XRik?c0pBN83kbSXKA=c6e)QZPL(FHzAFd+BbxxEVU@q?A8vd5|iUNp>c{#>QPRWZOF;OP{B*d2@ogut@5(oQiT^!h@)>t!MadwKTF~?3c!hU~%5orw= zNHjyIKvBeSx56oJ6z0IUTCQ={!ulPMZ`-(#iY!t#H%n(=kn4f(-F}uOZ+>x=ZAL}W z!I}b>v@Q@#@I<(&K-b-$%*TsmUMRqjLH-bvzy5`eAUKQ8zgr>6$kBKU*1l+;#8Tei zvfMshyhnsHFX^zpyOL95N;*q_eX# z2N##bNG9fhnz~HE3<MHOUZ?6J@>in6D*V>Q~10RRP<#^9N7c zs*a?A=q@p%$Oe5yTPvX|a;p@WM2_mYwH+lI!&?%1FqbP^iI~zO!>Jl!)7>fYGFqhf zw7Jk--ehnx0?- zeeREy)ku1>Z)?EC6f3=SMg7cP3h%7$F)+BA1bz8k7ma`eB`G)#;t+SK%>#bp%`k<9 zX7?xZI7>a782wE}n{ke<4Pk#m?wMmrYuoD6z@c z{OBe8-q-i2p0ej%m&ofBS4&1NaLTWV|s8MuS+ z;&g*KO7b4a8SE0Whzf?#Cw>Fo~`lS&!pbY|!$sp&>TD6hIW=$l*mi z9B)MTQ@ayr_L2P1p2@}|;|B$hrwFo>r%9+vzQS?|0REc9zIgX_#Z*&fcpx&s@5;X< zKlGWbiHF+!tyw!N*r$3zO+!OcxivT#($L5#hf3`VplYIbWU=1bz!HA*sUbFlC`**c z5Rp`vd+Ji?&Qejy&}=l=F*@da%Og+ zr_W{8mFSL*!!?m`Su_fL#z=nk2;Ivy`=tdRkb*KUz=sZBl~vl*D4%{MXy+y#lBZ1% z%=p$cyavUY*iqTUpq9&PKL_GkQVROV8ju(zXYB(PjrDdAMp326Sm-xY6$-VhR^Ck* zdcN%dOD${I^ga4L+a%=Uv+IM~y@Mhl@_^+Su=!Je__RdoyIQD(*>zrT-XD1W2%OCL zjF<+5neI6R9uDfar>y9mtm3Y5nh;Z{!^jy!;(A`ZVWx>!3N?jU1R_`)gXhbhNG=Z+ zmaJ%2hG{w&M3w1Lk&)M0SGBG=5FO2fJF7;Ew#V~k91OQuig?!`oqX>^;2lnB`{KrY zh$zS0`NSF9(gUNxaVAJ5CqAk9?X~~LJVTLfh^xr5A_rq7F??&dbKFYko{Ev~M;C9` zeMM-cgNQ|?&{{yIy>Xp?V&Ktt7Y|ZPQfE3JOLx@QU5lE_>2}u5X+q;_I8cQ-rJWbn z__b#o67mDVMOgMmM&5>bLA345Q9SneLZWB9HMHd-I8u$48hL#~J1D-DqCyLTTKr7} z6^zEFM3qqAYP>g+P>_=DUm=mog2<2K8&(i&;V_sXIqh=Y~$DvSP=m{ zU)r22pN;Za#abLoDO+5ti8xeSq!9jys?LezlktascYbujv!{tadak1|A z)$Bd#x6ylWi-&)t&fw_VN;fM7_>9l@5&0za01K#d7rRRbnvYs;hL2X;wbrjP_zh+g z{X2wYeyH3C;Tz8|*yT8ZHTv)Aj?z5r_>Xs6cpO1&B6**xuk(`}^6LW=Ak);1JL;*) z4~d~97KZ^`jp%EX;~$3^oQ~U0yHkT>VXD06&bJgRGRpaYlng(1&q6}p!J$0$ zvV+4{(UCz^k1e zNmAqmFsR4Wlz}c$&w0u#p>gEkbjDd$5M9v=nW$A*&h>i@*f?b0b54gmK`_yZoU{EY zI^g?a+iS`g{M%}?G2y97_5%MQu6_)lXH+$&8G20{Ts^hCx+-K@vvqI)VQp<~CX*Qy z6ja~;3v-0BQS&d2)0x>%HB&itR@reVfuBD+`#*nyG(o~Rd#LXcaESU zHmy1GwbwUBG4WK-15)F;N5nG=7qQ(@UY@rprx8X&1*w&q9G|iU30M$SpOyOHAqAby z?;p<)(=D@2^$cTPEHJEv){H;d`PQaaoAu*e%;twDbGN92_D@|yzabi8!5&7!;ZW$` z9EvPCXhg|eY<3eTF&3YhucZ=YUvM22kO?cN_fH8x#LgoK(YHtO8#@zOTkzcVV~qvl z`0K`wFE>%XCpY8k+*Xm3)zsngiSvyd<1u`+z_@gVg1C9RgMoh>*g76~NF8BY;u>5W zhoGrMP$y%P#n;C0Ay3ft{l20`GLa92A^K(H;b*Va&bezwb4Gc6=6gv6VtQzVLjyfZ z*Q@;7K$JQuH6ui0xRx_-`KC(#*7tB>3<~@NF<3?r)*TJ5-)0HIkl2x#ip4PRw%>nO zg`w|QYYyj<7I_@_3g}N5QCD0bt}@V|Zg}a*NjltuXn&0}d+)|zsI?I%rIJVP5;P*mN_;?nTFDgPeDHFip4f+TtQH_RNah%= zp(1#5KL__D6ctAYDG~?+5o1)Ou><{s^Yt7hjhx^HYuBSQ4`vDQeD!1$261`e@N`k-Qq}S?}W66uUK4?{I2TVqqZjcw8KJ&u`6eGcod;_HUf| zhfV53l6MRTMDr06H2qw`@&Qud>W+%x;Ak2SOS3gCW4Zch7dPyN?ug|57!#d;Kqnt5 z0m}{spGNINn~{1WRJfw_J#~yMSdFOf*xL^0Ws6frJJ1TZ_#E-oNYd#FmoOEHyq9si zvEE(pjy2~SE`U?lfWlHk{fB&Im+jFL)CG{b19!cF#C`eX>ubTs4nx0W=Bi#LDrabI z$)&JF`9V5im09Ths+rgJhQgf{FWQ39wt6HGjrL%n-nMlC9^2od4%~^sR}p5NB2Yi) zf>o-|l4xCWg+yQLe;Pp5j08TU&Qn9zr>QMd<17~RiV>mmF?!3M3nBKg+S}QY3d^3B zP$+LY*xALF`&{F8b(OxpQMnUmjn!iUzR!$g)eo;G@Oz1jWAoV{m`3`Po{64uJmz#vy3MPWm3VhJcm!-@KISmil{i~h6DtSEW z+pkJDE8w~IiO4*PMJ+W3>|K7Exl(xjW-Jj!%@bEUm4Y6cxUG&y{(WwbjR&e{M?9$N2rX&0r(*M9M*|12u4K1)*u;_a|kR05qG=m?y;+$;% z-{*=iK|lHU+w_bo(SOkJe+Wk(#6XRwZx~h2-o+F8t3farbcCFoSk4z4!ctP<^;a+c zQ1yBg{~kww!+kacpx-rSMn_Nh^b;$-egdZzCp|Oq#6W)gbSzLo)yDHxViIyW$^tYz zxHGmcS={Q+^np#*TFsyif$n<;x<+T<7OS!Bvoyjr9Mpei;In04yYGaIj7WIgPJmA; zBN8Iwk4Vykd5+Qfeto@zk@^zRR)IJl`yg`C|< z4L^lQcV&qtE8*p5ScYU;gV*YJFReJ5mVoC$AdH z6Slt@#b?eES?+QfvRwF4lrAM`HwM_vl>O9yTO75$OhnU8=0eH%=&6N9(<&``1~98O zh(-Z{Xo$JL#hdS^WBnQGA9PSsX>4$Ea&pO^P}ZjkuU6%8xBdOd{N88x!@IX>4Q!8p zTL(w9K?Eq_W6wE#UoC_;MLqU!g=-^e-cWT}NDX^1i4=;Iwl_Rz6*Mz|@Z-Z%hMx~J zu4oOVhoIitItnAy(Q#?z>K2)XDN+*7<13dnenf|rTk4McR4q=(Ijn}oLP*n#aadmZ z=p{UjQo?`&O1LJo`pJKjztnzv(L!<&xYa)|;owRPI%W2uZTz8ce%GPHXgQ^4_z}ir zGyP}nb?1FDh5Ee#IozqpFgzZQ44-7Q6_wG@Kz)_@h- zX*zCnw5fncF1RhH)>MHccRTYk5~my3Ef@Ep{Y`X6%CGunW}kgz%lMZ4+IAsrMgoxO z3fF>YuBb(9y`|(kBjr`~=L-IW}L;pj#l`NZB^9w;n0p-L7+#fFcR`~*`i zZcMBV$`KSs3~medCJnA1LFWf<7X5NmP2FxxZ0R=#OZ4wtl1Ywc)P-?__c{k+p_!0% z&R5^!oM@3qTg5)1u)Bd9M4W-JE-32AUQ_PT?#aB*42DmIG}tGVw?|xI<=v&&?ZW1W z>Q}?qA^4=G$!=Gvz8-{tTndl!?HvV_vz7V8K*W7*jfevX&k$+(6$)Fyf}S2%`qWWN zemksOGnW#ZMQ`k=Z5>PE6v2pX-u)eiTy1C+KX%9IEVyzW2u5Be+x-SHt3$mz7++^dqrF&-57jgQL7+ z0Wor!?Z0dMAWI*lU`@>4e1t3D(5LJ&EJ_tJMe4-ZO1-#46m7gb6SHbZelAUrAagoh z^0ip3O!>G!TYW&>dvzCAU4D63vL7yxBBT~YXyBSmw~+9_jIHzrRT>j99Iy^zdqH<1 zkN_;?od-*m06S+<#l{}&eUk|7O_$;d=IO*MZh|}mhIz)BbXa08K@Rk97>t0e9S}b6 zU)MWhFh0?ug~!lXxn-G;d}|IE5J%Ge!khs!o9qQ9<`mz$@w-g~|Hymi0J zPeim0%_k=8j}VyJzVh+-rAt6%KjyyI)~!Fh~$d zTLBL!wp>iuyC*X{?BAjcl`{OGFe0sgrkau+$eVp$Cte z5bcdyNG+11S)G`HSGq!-N#+?0UxC)E(N(=hA)@A6!~--8o3k z{Fnu@uO&AczcG!@r>y)ldAW1nh8je`)NpJ{d2N+VmCpZrTu)@Hi&ihwY$aVXsdgQ1TLf* z)ci3cBMURrBJ3s-rmbU3;jr@NDSc{XQ`Fp`q$0f2voM_TbZATo)hT~%{4{=ueJ>VZ zR;_rO${8&CPSc2l(Wn@>sQLj&-JQ-i%(;9n+D72?jrL@^K`0M)dn!KF&V7lPE+nbws+fnSpf z4xuHkSm@*%itRy$keH%YPa*-=c0^Bip`YP!M>7<}ig#2aJ`#dW1)wbRz0z`EsB*q~ zFJsfj<$71X<+bO}wqGLv(lcvwIzsJ*FYm4wN5Xv85;aRUvd!330YDby;}r|ywR$3K z=0u+JVs1!Ibf8%jV4*7wry3KsF@5)-XMalBXV6AO~f zF4)#cBG>+wrotw6R_1pR`_WJnJT$%2ts+!hAy=ctNZS;urB|udPqy`cz`IUQ%gxYa za6na@db%?cw$DlgtGmoz4WKxvSiOC*-@<=%P0`QT)}>!1@NN#P@tBM7gPuoz>aNBO<-|y>@@2!np!mrtIot<1iFzMb z%g|JoL+=bGc0k(^wO~JimjCYnmgzK{1z74-bZ_rJ2$rNUn2p6H&ju-sW|GXTE%^Y4 zqI{8zFlI$JYDpQG`WCXaXD1wGuIfCP2m3MUbEG8%MzXeyasME`m0L`L)v8RfrbUi; z9J#6LyewwdR5pZ}1q*ZaL;0B)0|tS>NYqe#`jjJ`r09(3!gyb-u*KLV5TxTcz-*h^ zEY?t}&VF#+NW+Fz33gbjr-uN27N!xMCv=F!Na=T9rJH0bFQk-uy;7{O=nWo9NC+P* zvdZrI)Y+c%)oyH&PgJF(a$A0#Mzzf_+f8~8F_yYp@y}g%Ceui~H|Uk16_WdFIA~T% zyMSZU>jo)WJQa%@T+b>&m((UewRm5t4H}}>u^u2BCYkd|1NLMccOyqOmjZ4tT}HVx zCWC60WeB20IX(+9`=^FSH5qIx??z7`% z@O5xRw6ni)|D~yEscWQU%7nj{nq(p%rO74}NVdB*ECndW_p|nNBU0l!Nli|&!L~Oa z6Rsn~Fl%p$@S{j=_l$Q7D8D*YIbftP{?ZP}C8>5h3;m?vkf{muxiSQLeHjll_yjL-f<-^ ziY<@z-8M@z(%kP@PyJ+L-}bbcD*`BUAwCKN+<&|$A*vPH_H&wDQ~9oqDnhYhxTp5> zKE!L6nxFOW9N})EUgVleYu@if&w5Q>p2dV1cVy}NPx88iXy%2QUsdX_G;fbnG9*2v zGVfr~`SAp5dHty8!DpsM(H~D?)lQ)2<qK}WP34zt&*@WnrKzLz;Y1cRN(^UgeuK-*o>nBOxzk4mbav=S7jE8BNYTQSU_5@A z*c9^%RAwZYGgQy1Mh4_eY-n45;eOckmCPWQ7qwNYd2V(jt1oPv(+K-6+6Lc*;1LmH z=tEO^L}Z5!Qy-4aI?~P&rdn)tIF&<&s?OGd25x7hz>*jWg$YHY)r!jNcKg*w=+vIc z?)MO|SKGpjMEGJ9G3PxG+&roT!c>8lqv7oS@exZtbLRe;k>P4@m7OH$qGgx_D?w0_ zP6e%27yHMIcK zVR{lUfuV@G>Jv|mEyKA^4r(uIDL64xWV;_`Yx=Tcr-09UB|2ctVlUn^so=ilO@N>9 z3L$55kKn8$^xT6qSCHm=X3a8a4^ye2D(lfcg%juflPG|a-V^-by-}=-1-??gC61BO zfM0!-S!J$XU=%Vn>%p(2nIci*=$fu_@B{nauO3?FQ>Ze|MN73-Fni87A^oh%aFEQ|}=mC#)|QRW|!lnpz*N=oHFZNgeiloiFS%?8SEb zLAqFN9YXsvYrjRr9dzCj&UvzwSUtf0fUhKSfb&E*dAYrJK7tzX=lD>>1txR!DpM+% z;&Pe#^)pNl!(5=%H=aYGp#Xjt7;pMvvTteGg2XX0O+oI!mI@2_yvd%2jt>58wP~=b z>pk={x}H);83ys$HH5_{9dwHUCPpCQtsVSeE@{AK-68Amn-ADH5o^tFfuH!%#~9c_ zDAPZ=HD8NB0b-Oj^3HlD7sSf=MP$pS{nFhF^;&+6iM$c8ZmJYB=#&#HnaYUtI~w{( z@9*z_aX5fMV5;)8^<$Y(x-0sa>?u_d$uHR%tXUqMQ>c+zWWPxorOf>>xKurWxHJ}EJd2jsR{HXuo z>6ieQvn3srJrE@ED$rOB|A#sJpL{uAeW+@qDpi`(f8*BwfwR7D{sky?RuM>kV1U}$ z+1dP`=w5GO@wj7uX6Nr$!~dasDV^I?*Q%V;VZnH8g4$gW)9*pDz13rgQ&P=A2L}`x zfJfrnh@SY+ZyzZjM0RFup+3T*O0cW0Cbp;SdnOGd{Tn0w+yqppzMo2SJnJ1WjaHjr zA3i>IO6#V z+PK8TX9Z%gB2Rzk*}!GonJn|CGH9_lz29;lcU|&>uHxWJr}QW03IS^1R2%LgZ=>$| z7FBwqg2=ZerJY|ksh2X z=%dWc*oH27nl2eZ-qL0YKw3H62<*g1LKeh_VF!VC`fu*c6~q&m{F^BGxsP%cTxcUj z%p}TZrt?@NEO*@~Jq{wRmf8*$k#`gOzcijE^q2KA@uK?TG$~cv+X)Ef0$qh*1NI!g zCDEN-P8f>*K17>3InACN7jiO&p4plBk}6p(x1TzCU3DA#q>5`ez4@DVk)bAndoKS> zb(R0u8Sh!fB`8<$&Ih36GqOsZ=*Stg8Ms*BGU38^N>lGO;T^l*^NWRYJ6;#45cXU} zhSu%ruAvNpW9fI+4bq>nzMTAvzuL#EVNj9o*@5)v)vtM5c|rFQzv6uV6t%s$f-bjg z-MyP*&*}tSL?A`u1RDJb@El}$0rT^F+e5)%cm&dEwWUmsJ_Bjok36I4Kj8=a_=@oT zKk=%5iK#3ZMF&|Y5H4}McdxI5Ox)*Me~(};D@vjDTHkmFk~0s8zuiBMaXDJ0F0^E- zu~ns@>4=v;aNy}=NB@k5y1s=k^zsp$`i-C}ptz$}H8DK%ODh)(+4$wB9iDH6=|!cC zVt>-GhI`RljCe$>KxAZ1zw7PV$W;swj2>(^xfg0vVneqY%Uj#G{!Ob=T*w;LLxzC9 z6PEhP7b2q*RAsluYgbCbh%EgEBC^y70mGOw!W1ylABeCBzr>yf2@~)8A>$Q zsB<96{RGxnMJKG##+u>Jn|NcjNLKLO-z9vH?pjw1mp^svimK&H0RJ0<%51|ieX&d8 zFBFG$d^S$&{{qF)g9wnLh>nxkth{Y88)qulX@cf2-|)q(J@3Cr3y05p@21}_sqa02 zyY1wFy(2%5j;}r)E91zB>3Yz)F3202!k%PCY23}gpX{|ABU|HWK<=7wg-{_CCdDRL zJoFC}f+u1m0fEsu7A`34OCG@<*H-gOKGj^~e1%e$euTvkt0{jzbr>VGP-+O_w&mU? znX6eOy5CYKl`uN8(N$*+=URk6K(<4~=){@M%j!;By%2Y#QiG>deP&o%N9zA-d zch+IhFF5$K-Jo}7Eg>{<;R^xYleQvvj8L$GnaH~?@jo#E7!1lRvOav#(Tfh-^9gC1 zqb@XS%NB_m|8ycu>klOP60ag{1knQ(_MR3ek~LL+1eM~<&^8E0+f^l+*P~>>!*gZJ z(sU`lhxieUt3D~$41&116ZHLkdt{OMm;mZt>7tSDLF*#p&4fa;hY23OJ)8N}eI)qz z3lF@gs8B#MWpi*GE zoGqbN#4?)48M1Xu9B@odAJOopJ{eG9b%hfe<9BF>Y_|~Nu5+aCfe&4bPNvlVvH=~5 zClT^WX!{+gB*D}lKeL@N^WZ_yT$TB$-S=0+5vYKHKEa%1Ro0oAyP;u;xcHWGOIo-y z#a*ZG;F=i~TRS_z5bo40(9?aRv+(z^{gwVJFnzcYw{v2jg8GmzdlsORPhar-GE7xX z&|u#j@GsZF*I3jZXzVF3cL;aqhG^w57jw{o%@+!DQZwZhdEqGDK;f=>qS>mO8b!sL zv{8-i{-H_bTUK%tD`E*CRWo1wM+<C?|j=4k&T?Qk>D$K|E09FXj zge?6Rx86Vz?Qp7Vx^~TPiReCJh@&ZrAH}UdA#ah;rMc$vfl(gxovQXPor<<|$%e`0 z6|hiDd0wJL667izRpvw?PBmE3Sv`JDH@ixTDYM1e6AXv^H^&NF{bM277iP(x2#Wpw z^!p)oRnA7_8>9+_{zdcVmD%QgGe%}yAqXPp~y zvLQz9DpFa7PNcADR^F0}1;)zrl)ub>IR^ZK0`-KII-C(V5M6_(B}kaB(hz3J1&0h5 zOdAAxbBy@T<}?i<8zRk-T+VS$c``{?haC^-^2|5JwPn3)S89`rJ;dQEnpVghdG_0 zO&iYHWeDkrtgNsVVmhAdp@$9D(lk#xIilCeyXQF&rOTf^rrgRu6qcGR6}cFp2lVO& zeLTxXj;c>b20-smsr6ET!;s|tYJFk6H_6lx9;5=cr!2d zLNxBazFk1GaxD0yg@Ahb&^%A|S0StUb`CLEx#{lq(`E2y8i{z%7${`HD=h1S>E za<%GCuj9 zaeWv}+8-0|QQjBNTgoPHz$V$Kmve}>Zk~|OJRh|1xauJXx3BqP#0sVSS155ga779d z7pTf{4l1TcuxdrJICC?uV6h4=Q(s_R4$0ryxlv_qHOMkg%}eaEsrjj=7=3TgmO3Kd zt+u>742RWpXR4}|b!EV)uCqaB(B`AFDj8b*sf~=xRMfB^%w`)p5NY+WwCk;p2(WhzYD-$+8* zUv<5NaMK5H3AcO=L{5d#^IU7C+U&hf64*N535&`LU5tY^B@RS)kNDg?Y=3xQz+CwT zEbI6dGf=Xcb63pXl`fOtYm7Z8<9fV5I`xtk=S*h<3QUm|Co74Yb^&2owDPvR? z5x{{oTGZwP78DzbAa{{MJB33TE@09ULkZr3YBbGU(qc7Dx9D(>=6=G3bf?J#)2xWo zCNleF@%&2-$h3#4tjUt-nWI6wJmzAn&#eU-8>DE+@}m;ZOw%j+)TQ>98Tbu zXJv@Bo2^El$t&Alvy|);(_|fNHi1~15V6}RWKTqP$36_jY-qh~@%M7^%Uszp0ESxI zarApPzq2`FI7r%kB80@@=msfQy`#Iq3?$= zm6euQ?nmcO&%%zn4M&d@VW&>0w<+`RO#De^xsZW(=3#n|=3z3T40X7q+Yx&ycnmX#^ge)@eM@%-qm^&I&@r8nsav3(04FJbeuEyLR4=Eg zczclV=(#atXq&%bq6`)Y+CH+^A#uf*7>Gx&Sn((6Bn`*$i}0!xEt=50TurSfK~c<3 z{yFN!;%fOzzY;hDSE--Nrv}@N$jMOz7+Fu2nADUmH}WH3i(|vO6g|+io+H|35xnA@ zc^sps`cJ_AOBeW*AqI416jY_s>qk!Qi%-{d-OeDK15sy8_bQLHOTXgw#`~bxQgyoi z${5+BpU5`hlBqk=P!-w`mlB#h*R1y3{WbTy0E_0Qr}TRUZsCBI>hZ&c@jwB+PY_?% z@HoMpK;Ndq(amdH(AOB@ztx6+sTEw*z>JJ5>0^*67tH9R8~c<;^-xvQ^14*#VXB=h|w*_wKVTa(GvYJ^tm z9x*E+NwUOj%5KP(%$Ys~V`z+NGunl!2LkMbe{$zfqKGen zC^|hooK~|%=WrsUSgBmC;5QDATf(t@b&V5AbTd9H?YmFl-l(^Bw*9=n z5Hu~RZX{<}5a6 zq6|4!)NL=EzhkyN$P~)-RnXE4J18dOA8WvVvfz7jC{_@*&HoD*&LtWRl# zKZ7skO6!P#?X%uE&Krz|in{ezv1y=X=yuwU)kd2Og5pkRMoL7xR~lQ=gBVn_bl|J6 zKrwV^G>xo?QY6SstX_1AJ$y;^=vD7)h|1N8@}udrrPT8g{LIXa^@$@qmh6D(e)^_2 zD{&g}PLc_vV?!)FxMOng?56*2tLLb7m>%s12e_bDQ}%drz&tUhiQ95~a5g@hrr@H@ zEAm>bYk$q)tG`_3wj{4MpXaTu|5Wv74v_bWjNC3t zg$7;29&|dPSy`%vbW6AAGa5Qh6yvQRjlWu$Xou`}ww2S>_L_|%mRdB@ez1V)cRry= zY83`H4g;6`km9;*SB#vp8Jirecc6bA>8Y{N4bJz{opU2Urm%N&>;rynHl|LPh5Hz~ zktjbj{eAe_`7zL{$sF+(|8vlK`vRfv`ED?=bY(-#fjUvjxH!b>8T?(GmXE&&-M&7# znAID>g9R2(YgLFDl@Q&oCA_b~K(58Z^+_Nr3%<{cGP^B!v9&F{-t17)mX{}?BxKR^ zSEgF%fq~9NZVlT%Q4Jx94?QHU{)KW++~~?BLl~2BA0fCY2oKj!behQBZ|j=R*J5iH ztg4oQu5V-n`m-)g#NNK{-RiT;>j8@Ll*(toJqppSACdhk`r}JMja(MP*@Q{H#yjY> zfBjHLE!6L|&vF<#EFAb2LY8vUwKg*ek<6l28Z5A9^BIxTZRuNX$nNujtB98H>|pNT zB#>rR44ZEX1+vk|%>*fw5kT8mJZP+F!sHU1uqPzD)d#r)P2%mfNEfiFevV|7JCA!> z$<;>a`&N+-7;y|FztS=`F#Y$Qa<%<2UmuqXsyKv5_wGH1;>jcQ2ANqE`3c(` zU42iKvUCt#lTKIq_*~^8Y?^-T)!QY9T*=;2lP&Z{*s=FR?of4de|MufKWz#GAUXQro#d!@X; z<=RICo0<`hQr$>j5c6vrk5?H2Rc?JzGJtIOlaMVU>+^hF3y&p9Zs!FaSck zz{XBq+}OtK;TvAv+l%SsX?{%S6-y2ar~z%$bd?7@Q_pLt%rXFIiY86?#{rDaFhLVh z&HnUdNaMrKtWWvY*?IU$(1X}=BW>!Zt8*jfs4-pUV=_3IHi7dr@57hpIHf`)lY_0P z4>&$)D<@OTiyxC7tyl8KUwv2Zzr|Hk!B?h)a~S9}nxo0s8jF!IH>`H%j@PEqn+?EH zYc|3yImcn2sbSKCBsUX7vrn&H3C2M=`_yq^#`)Ntbn=~CymS-4lOM#!y!KON0C0!p z@_I3;Ey2rpoPQ$Icp5vNr}!l@zZD2Olv%7>+pi`aZS#7&idyN5430F~GyV(#`8!ZU z%ktgU31{&J&boOHi~$xIo{MNNv)Q(jEk9}qDvFJ7=h?9xKD!O&_6-%qj~9!}9Cg3! z4pp~-=x51ocj;yj7WX9FC}-Q1m)d@}(J6RLC>jhNGcZ@nl~(SVJ~3X%q0TfQ+8`6P zyZxr2TwGm7CrxEMA(rCFf(N>lZu!a;QrYyS<$Se8Gt<7c*Nia^cDo?S1A$T15(u0 zSdrIl6DKXWj@^1Z-`9Q&$hXicD<3w<&rZlQs~YAdbJ=~q#qq{yaV1n{M$F?aA;lV$ z2A=>E@apMNf1y7+Idf*9#0SBk>7K64xLha)m!p!6;ggLvwy5%}$}BgbA(){BqTSK|_VV=@D$ zMm?mU#UHL)aoHIzCxRfI4PD+D&Kb{|e(?Ssx!ymnou3Yt#HiZ2u=KZ&+x_q36p!!|lG+;ourOE_ zrbX)FLYUt#oIUIF;EX9?0w!WvB{@k6qP(G+@zihl@D#Bw%veY``Ax!JOL@;ay!i%YjBh&JwsrPHiL z;6^+yqHmWmjS<46p-Ta05`+vCf+Ot1n!dn#(DoL<(tWxc5Y?&DG>O3#s>B>ayj~8P z+)zbAa~}H^8eh3gx}uXYcaoF_y(<>cwC--LMc;naG=1U_H_^o55k5FVNbYFD&b0gq z0@unFA*nrUJD4$$6W57mZWgp_$ibWSQSyVF^BKVebKo+v``4)akBeV-6?D6cw~$Ni znyYq}kgzwGS3{aJ3yDFL%mZ2NY~5WXB~=y=Lf&sSj6azk@}M+MQw3_KL^^p1-u zMKVPopBb7nRpjE4z;rLh+M(Zs;|9}9%N2ceqNo|4hoY?0}`8Y-QvjgB)1uXB^S3TM2+FE968fntqn7M!C z6CvDT5#Kg;_f$DQ15{x8?_YyrNEELu?biZBg)(o0MmYXZj}Gx;;_Y76I~Rxg>tP6Sx4 zvqa?V46Q?bIaLOjTqROwZf;8mi2Acv$34c^@)A)fcV&Y>%L z`fHBJ?;?dD5{Go#;!l>gMTj&sD%Vpz4||${6ka_}I{iHwZ{?m$^mc$Ix^*rNw{6_? zNn#QlNSYJq$8Pnu1~l{@gUaKAL8?R^^LsuJrzs2UwC!JM;{xqB za$HPQn^`W)r?Gvy&wgaULdt57(~A@HlXC799Ov4djhq)?@*d%(7o6$VHqO%f<5%Tv zFarWkX3|-D!%c?(-p&B_2$F0IW{aeS_^B=M=GelMW$}TO98|kiQ}%YnjFuMzM$V>L zT&~`1rI`~l#RVrC$to3L?S3}`7xyT+yv5lYY6n3+${jCdzOvWITl<(+EcgJlz5P(?W` zLtMOApF)h4uIs}24uDlc?J5nu6{k}`9hdzyV64ZkbGP}Ips_n*zy$F$vmSdUM~cs) zpk_Ukq-Xo%PT1o~W#?46I%}DFV}*e)G^+md+Sq^=7zcYX#&JTgz)B6pTWJl{Jp5o`Rh+os z93gv1UC%s$iQ~7Bc?sC#(-R>P5%7DRo~t3ur}onDec<_ToaW!PNt6;@)&2GchSRr6 z&`O>EyGVmIzHNlEubbhe6>*~*W5E6&BlGX8K?`}0A3)nPsw7+^4JnD8TqV+>6#Wk> zCJGAZeA!J(hDkZ@kKq09(+9)8Je+cC9llhTmVY+sm2rTQ=8#o7y0UO{0S0C4e2`RLU!KYa_jY(5f|`uYJ5Jqy1zx#>tmA|2^EZ`s>R z2m|rZMA)_h?Ci`M=qIbp_RI?gL!~@qF5#7OK)ev&{~vvPy`dE4fQN^Nk7i3bSu9te zJ5A>)ixUs#_4FsXFe1zSK@FC@h_6NnhQ>ohwPcWO69R@5mbaAJKzLl)ab)1pt?las zMkM#Rs+RGhx~-^N%jiy{U!YnBDUwR!yK_yRM+nsF9$&!5A$BvWGjz2n z%yI{o9n1)=mI=;4ET|0OR80P!FbOeTK?Gx;BglGrKIU|}E8D5~oANTfUBaP7Ww{lJ ztzrLXI#&aM)A^cj0oqhu2gpieov0XyD3j>|j86nvcix7^SSB+T^a=gmL2K8@3c4^@ zN|g;X3wn8YH>;qzT=}mrzNXJTs|64;hU%C_Pf_=_xsCeiejuh|EnwNHQ84Ll)B&#@ zcg+D$(k(j}jJGY!*Mc+ClUt{kXfqe;8-50314Ixw?)Fk`a(COHVXLiEWiRBYb)OYm zw=?*6y+|(vVn6gYFEOfEe>@Syj|=}jeTzdu{fQlz;Rg;A)SCSuOyZYTHVbyuS*-dd z@Kz(r?yCzfB(eZD}f=7itY@#-!sBV1imDn+qFNT#sYXr9pmB#{qMvg zRH#e91zDfFr&_H@ao6VY?ywnis!tl@W~#$((i3{q8mI5@9pU_e=I5^1c(@n~r)gn! z_7`oBD|UB}w_B32k7r5yi)n>U?P=B~qsrVY!i7o=(9j{JVLEdE-`SAM*9HdrY+q?8 zz*EEzqp@3YdB;92J32iBD$&md@}thb(r_a*S|0N4eTNO@ysAqJkGDUDh-J^w5<_v$ zC+NC?_xo&1u)8qw1VF4!7g3EavW-F@W z+c@)cmQJI!zlNsdN73{AARwh%3$MR$iZQ5jzHwrtXWcO&jC$`_veA^ltiJ6N()9T^m-t0>Z-YkY!OG)z|GcR)| z!97F@5w{RT+W1Yfa_fe)`Ra)b9bwvpRSjuTz$L4*6iqg5cYPuMc1`;co|(t&fF`b= z7&QpPDY|~>p259%FJO-XYi!gtjtZE0lI402d*|YuW#@2KS9pkp zW#%3go>Fm(>05QV6!>P$wDpH-Mf3H3G;}u`C0UE)3~8=U(wRH)N__P2#0=$_!wMlD z1n0@NQvdi>>kO2RJR;lh>eU7Mg+);2P&5rZT7p(p`b8X zz*LZU_y#&wCu(Lv1%*W{5|Z+Hmi(Gpax;Tgs% zUA8Ny-|v#Yvz)1n5vQn;K=^JFqDxy@Jnw>SjO6LX?Nms>l9u+|9XhUMv3tOoQD(k5 zn3JAB@cFchE!M?+KI~EF(lr*~-$C#iK{{8<>UQU7zFrN}***(o#%d-78P?Z1T{Vfy z)%b)xQ|qXw(F7gzAwE5)9TU)NR&$HJ_e;AkgnGOc0cK8hspf!rEc7G-#>Q-FtppOk zyznbWgewuseeZKo$m5MXtpua|u4A9+w^Dyx=KC?&9{=xn)}-P-eUhuzC;Kwa9<$OV zW2gDj&aD@-*2&KJ%8_rrXLcJR@xyYfM6HF%4cnR$yf|b#jyq2}5XLG9-Sf0T)*cTq z)_FYBWCLYHzn+3uKiCu7pGk;@=`r}@uNJZqY89biIdoZ^OBn~j*IHxm{JWqFZ1rTiZ!K0NgC}jXOn80a#7eokh?|9rVp2;8iu);-=BMID z8N9!tftuUCKs6=|{r{?CP)0^ZORK6x`IbOj+~&GQmiuU}I&Cd9a1hE93E@@Gv~f0+ zy;zeSH?%vOZ;|MXKohS_xXy;8YMiQsRr_IG2i?y5ABnr9xJ-hShMC3ZK+aFDy{p4e z=vRZ6H2YyI9f$;NA0#Y4DmN?4R+>#*m;^0Xc*by6a5L*yx3L(Jjqsk~HBH@e_`~P{ zw_g++j#zOmEgz%w|)o`ybj z7)x{41_2IzfgNHavm@I; zv)atEZ7=Y6q^cNIX>*jiWi%2!f%(&B)K}b?{_^XB)_Umu1`~V2KjNJb-|MkfB!^Ee zQs+({)*{1o(8LV=C}-=2zypORn{?!MpMKoY!;7?re4HSYAr7`+k!p=G7m09`k}^OI>otv;L$I15-Z`m;b`0Ag;yKM(Wq~LF=Y7!f;Gf| zf+A>zQ$=Lz!UMhy48xa@k?UO(Dai$GnD{ zZ*fJ)C566HC@rl{gc`#zm2YK+>!lBaOv+3*otH<8Sm4s7=A}HUBRIhC*ijL38vaEs zTL?5mYCQ8^AuPYII?w+bq~ zGG`r?e4&XHmd#vr3`_I9q_js$U(ZTcIBLJ)o+Q42F7%U&C?Edsjxw@@Go6SMSu} z(8t411%0Ab9)F`%_zHi}s?Yss(HX;O427zrS9YBl^dW6T_+KP4A8*_qP6MG)8vy|V zQZK=R(A-MjGM6P*we8NwU zTFpFU!a&a5c(j2lg6Cuh}2T7_Q{QEIT4AN!k>$Kz~<3F_o)r??ES*z z##DKMQ%8KEDVTBg>1Ifco?&#X zYmVpzH&G!fp&j^O@$I!)}$lr7puC2I6SS%-Kdvy@?#z_?-xB zcQmK2EY*4DCWWHwKA4S-8S$_l%=F2$?D*M31cbLeq9DNI)5Kxlgu4j?T_!D}Y7!tC zXbVvfAiG+(=Mju`FkB@%?X|WqKrWko?x9v8d1?&W3d#KcrB2F>(GT54(m0X^EtbeaAQuf5<&W9Y+{ zTDZ8cfGG|CMVq7n56&NzT8!nM?9B;tm3{{x+QJGFZ^v~-b)~!%HabcQpff~-GWayr zHbaY;xRkDur&F$TxH>XqvENe%(iVHvlNyLF$7QUO(79~7ytVTRYyohHBK)T-rWiZX z@NySXkV-z2ME94JOqr~hcigz&-rC-9bdMtqj-Ox#(q~Jf?_*UE2f#gPwEE`IjOe8p z#Y#lQh;ttmsA}1IbR@MmzG|#p(^%3R`P>s^_Q3GQRj2&Ma=TFJB-=2rLC$zRo4)*z zXE3t$+gW4|PF&&Z5Zv`-fV0fB+Xx@E#X(i`C@j==1>Vm?Nx-Pjz|F^+@e zTD}vNuFTa++F`WkMQE|oopZ|Y0Ndn{74pCs*JGFmubh5Op8Fdw1E`g(N0uo=@4B)^ zca#G|Y#)t0(03$6*-xl(5lGr$b_i6dpw0W|41GOLPb&46Tm>`<*+KH2DdR}O9&m{X zJo)`wH0kn^`bwt&6-2htlgR1^coH9L&f9!3B9p&ZVKHc(OTf*OHhmJ4<#>EOInU(m=?YFDineF3Dz6c(pRZ^Iu3~o{&C_w_J z6^%6pm%kmdyq6NYJdMj}_fD13*XnVi^;^a^quy@%c9{9v&`}0qU-(i$Su=yE^TONF zOPa4|0%>KwvbYSEaDYBTtGL7*bfeDo4mF7}2b$RB8J%Lgi0nGQBjna-Xk z(dUXulOML|b*cb~#|z-}jqWJmJ4{jTOI=p|{%wCpem$gvMDOOs!{Fs4g5;Ip5MkTD zk+n(eSkWR7s_7d!#=<)5gb~&U2HiDG^H(=+4u^B! z&4n`Nr2L+~a<%u`X}j+@ZfFN{RYV0yE+%N9Y1PARtSbgD#8fX ztKkhbnSm%jq!yql3^=>eY0zPeo!MYwXnEy^yHMINn&y9qM%+d{Q`!&E6)kQzKkEtc z{3lZtALTv3F0-2@g`580WEichW5#qP6W!k<(5{XVKK*lS@>#5GSlkT41;Q z#T+rB_O#FpeemS$4E=X*IOqge%lCKd1Esv&43dSQfB%#C3JAZ7;D<2q6n0ODmu$tPBqs|92SN)yx0G;QkAP+xYpK$6Gv54^mof z-w%XZhZ%~Xbxzc7bugXuQY9(3d%MCs1dS6c!)!s&V4e8S?k~NMS3=ikv(?W=?@@r+ zBK@c9{SVV+1U1abWj8tB^v)i{rA|-eNWA5+)eu%)UDe>iJG`lm0&W3pw%i}JT9D>k zQ22KTdiQ0+awDz}5Y0KN%8l!+VuOlW_6M?w{d14pC~zq8St6VSD!tZH}E zp58+?(vpX|YWJPN-5(bLpTRV5Yq`q4j;1zwhSSYXf>Pzm#7L{9DxlQ{3o2#{VXiK2 zH?*s=Dwzl2tr2E+bG);dcnyEfVHYt)d(nq;yvuuacsW#+Y(9%H-&cXXUqyt(SKp$Y z@E4T&NfVUU86Id^B^EKGNs@9`3(YZ@RB!TO?D>7#+ulRA^NDcR<_v|Lia+as%&C6BrT% z8n&b|r+71$@^o(%TDBwy-P7P6%jB?#(WHV$y(Ip&ku!R`sau{F0|Ntlyq%Se2(+9? zV?}6py=%EZ{x}O?t9`ISIlRWF@W~}&WQ2y!p(Gb*;KEX6hZmC!<^MIqo`=--8*O~=Jl-aAd{0Q<_as3-pn4SsA`1lb~>yfgdH>zrS8fK8<4-qJ~A8= z>@%92Z3wvi7YQdHwx+7Wy{$U-@nY4s`qR#Q|{68)bxDPcu077Yu4Q*hNL%-aW=3XIoW>lVY0(?(Puf%SNZcT`%o zP`&fAk-Gew*sfT|e^D*5zC_2RZpRtp#xkNCYpzhD9Y;oMY|G4p;T9LO)9k?#D`6PN z9Q*~b`nw|(&YTShdT|T60d`1Sy+u2PxsbvpLAvb*Tnid=m^Rm(I9F<$s>R%N@QY#- zzT4%~1|=AJv3gf0!FSGvXTq`N|Bzqnng1*KMX363@(b|}{jm|tkF4ZM3C(bO%iGu< zKAFGp>)4Ta4C*Ovn6>`yr&!H^j>Ib?uD4a(x6P z1WE!g4sX8A2H!nHOd((P7|eUgE$}VK7V`P-#5ag8h+wz%F#<*yHPn1r05GmD! zi6h9h0`WhXLin>NS;HB9S#gL)F;mRVvJ?9770F5J8K2)z-2+C*3vwnjIda3$$|PDlItI39kO&;3cg^;qJ31QTjJsDVH*v-pk)Kat zeZ!hz9WppM0WrPaI@H8FpCCy?+x)_?G>ZnbaXy8M?qOzUee?mIP1?WwiHL3UH+ATf zpwsYXGob$jOP#3znY}+7kj(LcG+jj*pF#^-loG*XG*)kbE@H}uWOn_ZNES+SaRAVF z?-b75Xq0w5-l^y?4C5~Y-N~@&>K|ZgUYiJ^C}tG9jmcB>EC$vhtv0nK{&Y55zmL|x z&(}gW)G=OdYD)`k)k0JQ7U1o#8*=S&{|Sb_W%#(ph5nnv`jm3|&St0H4S6+wOdpln zDbTaL!U;i9(Hnj@b#w>wdl-xXae)}%$?5Uw0@opuap-h(>3<5a%r1&FMI6&77XhfV?A@Leroc?tLW-aE(?PpqEf-k+XZI8P)j zME{e8^O?%3x?JFqdU55{3J)FZ5|*^SH6v?tCnyJc$6y&ZS z)Wr2iH?lc3=gPds_(l8AN-z623gW;<T)8d*_t>% zcW-sc^Zflhi6DzOKv)tCy%#$3Rvbz!b%UedW`7pq(#Ei!W?s9sGY&|MR1ZkUo zT1vqP*91QDPyi=+aP-cOLWNdBV5+Hkx8ofDcplSWK<|!u?}L`(-7)@Q7LGS3Kvwdo zu3~}_>SU*PFNu=L8i5xGzVKr03m<@1NvDurRY#-BefvQ$W#@#8E_>_)ZvQYk%e+gZ z@yR{4yAXbIPgFz)^L&DvMK*wW@uoR|y8D?G*rKCi5{zK=_8Me(zW72CD_tM{NOf@z zighG3)06^gRuZ&*<|RcU?;%_xe7z6NRq}ePv$L5Aii{|FAkeKF?WhSGYAhBZE$_c_tDVKn2qpsddNQs|jC zlVx%;p{!~llV(HK%@rmU4$7{e$xtD+aq3EraWG|l;I??WieYn8xc23LEe$}*y6+Cc zEA8G{HjIw*0`&ESBtNc0m2Ah%9L|K~)eCBtxCnuBBf38<`Sw751cJ@7yiOU3GLTi{$tA{omGQ-5S4AoZ+;sM>(nv)ea zVWf0l65dqR!GE@P4rkL+AU1Wws_oD%ya-;bJ;Ins=95{|?E!t;q1MYuoX!(X%m2O9 ziY|;w*$`T`zAK}1wbOsJ+E|GMew7(_wL6H@Z=v}{t4B*9bbMCJq^KYw0yUN4nqUjq zKTcuFzkwfL9UZCnv5HuLgtd%1HkfjL4((`Y1tW=#6TV1-J!i6-NN)sKHjm>eP!3a( zieqH_D$Hm5d7n&plqRD>vu>@&5^w!D5;%?_D_w{nlWwb9*4Du+b< zL(3;*`~@KKw!3bNyMoPst7c?}D{^0Kp*@IvL4kG^y&AS6&3l_GSW&z0y()8X?qP@X z8b1m<@HTprm~b0{?*5ZEu9b`{Q=YaU0b_Q|LqdsPSDTZU5 zlno41JXcT7tjF2jt4s8aMK{J0y}3~`e&D1@yhh7>!JA~p5g?8yx5p2uKpMT88-{Je zrxfu@L7?k+Bzk{7q5I2C=47G#dseY;Un&o4ZM8DL3~cES4xrgErFrDTO04;rg={ zY+cvwj&q5HT;LZHmW|q*e_Sf#T2kIxnO|D^;$N`QsTRwjgPtA{hvRARXU`pCa`GeI zY^8f5>8!M6c5O$;^crMDYsVYWUb(9Wrst^V-^j*el>aOgrMCWxn|2Eo9F`hJoJQ5x zY|(;LmZ2^#fmGB>)4{nfa70!i40238BkS#-fRXUufYJMVL19TT#3y)OY!rB>_opD| zUvK0nETBR3*_Z_3Sw%{fcB;G_GQ^r{06mK6m@v=fD!Z91wc(+T zrT!n^_#6{CAIPd@4IdfsQh6R=Jz&az-a7xP+3ErvL(%y^hz=;|Km-n%3B?A!9{+{v zl*h?W3_7%&MLNs@98ZY*wl81kp~Qvw6)jI@06X@ZEzZU_VIJ!Y>y0MZz0SQBnjD(x z=js@hRC&}_Br~t0t~O7pCsJPL$se7r+Lw2Oi&@5paDL~hpVy7z&TrV1tJrR+!2Q=b zRu!6bF@eY@pI1%Smh_(76m)T9Xsdv2bXZKGm3b%+J3L7e>4mc;00ae(QU6X3Tk#JAjkdoJ+c#61Ah!u&a zn87Mwe(G*f$0GX3n|jkdy34-Xc|~y4q~|>#s{qnWQ_5@zyZC^xN_u+VeTll@we+G? zf1z6O?Cl!JB!t_jPz3e2$!`S`)~EJe!r*VLlq43$?vos(kW{@1yX8nhsD-UpgQKFN z5^oQpP=<6@aY%~KL(qI19gVy(gQVvj=N?%^upt*+?R`Ml0Jk zf}7T;2ER%Io892R;P>P#{~axYXEPC9~hJe1mf3k1f zod09!LBTVlUUek4liFmAQZA6uzuIVtJS9ONTNS*yP&NFXz0-g9N2W6IMj_`|))NX) z$2-2qs)g%`_>23;)!X0$K_l-+Pp!VNsn^odcQ+Qc8b-vayVHcb9C6nC**Z(ZVeLdF z0ZW%rIdatJ09C0w#x=T1jovoBv>P)eGn(##a5$bDeb0k*#;D(#hfycmq(^B$5TMKtC_*MJRm<7$K@BPQ5%^NTtCoBb$e6SFVDCj%S(rE&*I6& zG^{@E?(!Pyd}-dOVzt~98X9KT?y|@x0}T0a{8^x)F+V-e9o*$SKWyKLU?jN_o>g;Z z#y{@G97?|&UUYVNHoZ#By-y2Mt>D@{R0i*EcD`7BywiBf=ly>BjF!>hR?3vXJApYL zsG)8&eOkIm%*DcUV$;0qAhE$twzj_Y_4OTBl#-q?m0X6HiABS1PI%wHf4@VpCh{<8 zNm8ybS!eG&;8&$b&!Ilth)&sNIrNfxoDM-B$gBsc$7yJ=uCEq-{Jx%}(hg%pOPVcH z4BN_@5va}0n$GEjH_v%57Z0zHR*T z%ZVD^RB1qEQ+geO3}yOeH4M7}y++t0h|PJ#mHA|0)o@GXTWi#oW2SRcm2f+YCX(7{ zy-;hsyCazl`RjIu4SLeP!<3brS#c#^|2?rXiO1S;W8Sr?*uG(ZOlA-ranyaNxyMwY zy6Bu^y~umU?2;=Hf`j`EB32%s^T#{nP;2BmXCzUE&JxE6c@)jv0NRgMVfUH}K$L1T zE8j&Xp*8KuV8GdGv{pO3?L>y4h>j?%3C7oYyWGpyRkCVgHGcJ%D$@jrm4^%evfwjt z0H>~8FSYr)2e#@CsGN(#3Rg&#+JyHpyrTsN!p8u9lRagseN2vSP^5L6BPf~We(q2; zY0HBt4BZJ4Dq^FiTDwCF3Em@4QihsY)2ROCL!lU`gBQ4Tds&Qw3&B0;2z!G^)LTlSzjI3*0ybZaEenL3Te?&+}*vD;!?CY6n78q5}e`%f)#gncXxMp zm%vNUz4v_geJ_6{*}trnz4zQ}%{9iFW9abK_%sz`4a79rPDb15dDBMjQV`_VT8TD0 z(DAR-QlrE&8SJ%IDUpV~Bl+IW_CWhC+vdbxBO_LiaJF}i4#3^M zxiSA0p_Hd8g{Q4gMs8WaX!P5)`Zp3GLiU%F*lrUTr0&;2NpYl?3~=MMF0%JczwInf zB#AeZe16Ts^oOm=24%p?U%&Htzr=n>x*Q(xytxsc@}w8!ULuNJ17YVEYs!-QMPeDI zRN+0O2u7@xY&%a;=q2r|rO?vfVKm9T+ddo`tje!MDC!L3(dGBv_AjfVkJ`xg8DT(vd~vE{F#& zmHOqKrVH+Z$OhrLIERt0px=tAvf_KU_Q`UPW0mD9oEY)^#&9qCJSmZnX)3Q+Or}4{ z9%Hu16U{`27Ga(v)#sBM1f$kSEPPwMd=$~~BGtc+`(Zy1Pl0Xbv-lQ0c*W9fd?imF zf8}Me9n@hU$!kkarDT;esbF6jr3oMe+_@1yn7XWQ`wG}%popE3CC2(thdIn^KPz+;-|CRFJ|+c+^UZCM6D`Q!AqP;Q*xeix8EJBL zwfjb9jj9P#|D3RiJIy{Y>-1*n6f!Ksrs&Y?LBLzs`yp%e^iKJX;zF_`=+h0Y!{x_Bcem|J%fh~5yCp2{Z}=j~vR0w# zsPSAm;0H5%SwDHnFOrfdrIPvWlVu3a^!6Xd>ijc7=++-AWot1JB#gLy+($naks}R) zE$Y$f*imnNSd}sAXC!~A(i<3TuIr7tD#pDFM3Kml!_rKT$mK^cDC?Ht?aP=C*HZWp zerp-4RJcsIh$2iXFWb+SU|XV$$vHRno|+M_W~RY$7zw(Op+;fv!``f_+=EDIe{NRN zZ0pQ-e_U2%wwMe@yaCbO8^d|0DHNUtdiAkK|yqA7=?aI+jr)dFui!vWPzc z3~XhC${#Z*<s?Wr&ZqVQ=z}3CvV~wkFQ^bbSO?O><%} z2ed#{qfy3kX&xzo_-|&@<&4cCrVX%lYky)vr&O!=NLa2M@C5`#sHA7rz|G+8;*94S=4I z__G(5JnvAYW=&A(MsGoqaE6rFlcsrk)9l0~|YUYrC!)Xk zO?;)%UyG&Bjz23pA}E%;+f$G)Osz1mM<0fc3sA2hG`C|>sAQnJsH&a+A?gKaZNf?- z)$pL2gM9dHxGK1;jLEY_=ernZL`dDo`oJUFl#IOV`63lqqCm3F?^#MWiG&Gf+aizK zTb~m2Gzz*$uJ+795$cV=0BcyBp$wMYNoqdp^j>8b3mQSK~9 zNcAEK=@c^4qzTT$;j>BFjn>Y{1*bm6-9`m1kPU-9IH4wfO6uK?wkV;QVMO4}fi_k5 z`(*AZ8HwW^5_W=eL?S=l3zd422S;kfd{rs-E4udFE)VQfDhzybItFysGEFlgGV=7P z;&*mmp>8G5O5g=d>$VYneQ2l?u6pm5V#_W6d2r$;xb%7_pcSs4U|_E9DnmDW+6G-t z&8U};aN?=FzfCTe>@-NdG~FHx_-M#%Mlisd@25u-G9hDg0 zbw;5Q!`51JV9z#S^GobuIJpz0aF$<)me(<4Gm^E}hO5~+IFQ4gp^dH{1nqX{o5f0< zCGfcr*R8-Rh6gFEz9sd~>zKr=dA7uMJN>Ixw=mE;o#cJ7D(O3JNr#(K^S2(+#gC^- z>RF1`blAqy$LZB^K*MBHeXE+6V)!ma^CPcM*w*@`K5}CQ4!w8#->(i_7-?r|Ewy zH(CqYqQ0l#KK=A;f#R=&sOL@4ts9rco6d)w=C74){rDkmxk`1BVDBch)(PxTVrr?- zT92smL-sz{(eH6vP@Gf{Id!xo25OsAVe}lXuubTrpyy8};{U7!TLoBt`PoBGo~&1B z7KV9#qdeScbW~9fj5x9sX(4rKAdkSgB7-_rA^&Tm%`L|#cc@qS{!CGl;&O}g@_v>G z{KS)*VyD|>JeT<-IJ=97XEh+G4jL zejnQ?YBW3ayOh+>xeCgVrVL6YLDF}`9pVsl1_|f~BoAq7HuKmSnT2lT?smcLo9O<+ zrHfEbUrdbc@J#B?C2RCvK^tOHeHOsrM`!&H%1`#(5P60B!W_q`%(#RAW4sX;OOF(?Ol`mJYbmiI+6JlI~{KLQ|PMAW65wsi9p`D zL?ql#0TYkt8#E0;6cc`U+<>MTbMkgthSuR_fL0(Bu5dApXDB^f5&E3_c9Up(*p$1tCx3>)JaM|&k zlZ^XL6Vq=4poKea6HZC%k%7^EXv!tT=F~H__YW+PdBBmiu=mu*Pq3xY>P?pUL=%Z0 z{C2EA$Tw0zjJR3H92p)7X=^f9c4xNkI$?c~;rBG!4sF-xlncGzA9LV#Vl3hno4Ou` zZWX>qrH2>-hs&xhps<%G1R9HpN8oDqzuzs^C?>kL0?9x}Qo}f}ueYP{f`gmSTWurO zQ6q17kfk~!)BK=f?IIEq736;3RpVz-Evzg`@R;Dm6|i6jvqW>%Fhp=;G_fQ!v)-y; z@eE-{KcT&8;2O|<-Ai^cy<3rky{kICk!E|WZT%HApD6KJA~GEnD}RgWMuGY89zMVa3kz0M7#Z33OwMO* zVvBU|k7+9y9G2=GT6xzJ6V@&t`WM0BAj+*gZDcI|fBypJg8~V>5s|5tLK1i2f13HH zO^z?Z@h!xN^c|@GeD$ZBKOcVh`+W4M5z*Pi{k!M?K0eJ1qj>v+upFKV{-1yL@8bpN zu-V5mh)$u(|7zvGjw^J*i!T)Ex4&)v_sRUfCVz1v_vaJ*@NevP>p(ttxvi|M+~)Hj zh$w)k{O=wV)RFhkj%&=P@+QY(LMzqPPr=|SSl^WvIkbmlK!<*cZH>CDPX*6rP0gQ+|@=&ed7CU9t(l8hIS6OD2T6Lxm4Rl0V+JB@@| zDJM9Cmf)Bm751j3gqCxAp3~IRBS-q?F$6#*pySGVW2dv%sFaoH3iw6(>BC9>HDJ

%2{lZ4h4_jDRDE;M&xQR(#%8IOv%)|%DZ7T_Wt)Ws6nSTS;{Va(Wg}eU@RRTJvuBN?G8g^sSIM2wBNEK%Z!tL? zw3x%9k>3)_5Yoe&&*LsBZlo45&4qGbqhFMJF|)ez*DqotGX319FYhaWEsyJSX~U8x zx5H5NDpTb6q@<#60-!#ec$3#DXXjiL(=4Hy`av!d?CpkFoR~X-l0VnvpX=~N_;KvB zBr0CI(ewK)ByXJuUr7GYLFX)kR*V<57G8CE`8tSZzrx1eo|Um-`|Z3X=PTWp4eX6| zmdb^YO4Ga#x4crq>hvr9_6Xmb^aczg$Be4^_{@o_bb{4&H+{m5N@k_SB{d-*RMd5! z3?-&4tDAVfR_XMWK_FOe>H~I`OKvCwR(uo!tKo)Cbvewn9E-UZcOr8QkZMTCqPG_0hLgR@85U#_(-G$ln&;si@j+1at2SBn z1IrQ!iu(EVRY8fAd=@h>OX?Rq&l_*yiUp zQU{u4_@;vc6V=Oih+N2IkIK$#KG}!&q#8UgALth?KE|*9%p+vq#71ici*W47$xp_M zzkjLhvWQ`U7+!nWQ=cA~^#r|9uDB1%FW)Y84%0GzP&dELeQm;HGCYpeX;tv8UUk`E z!qf(de?ANx@}463JP4HE9h^fCSVKV~wZlt$A)oG~LFAz*pVpvU5z^ z8`Bey*-U`*D;03V)cTdl6T)#Hl*m@tmT=eBDKzd)htIM68ki`%@jA7kr=*m<+Oma? zd_$kUYL`(~5gHz@9JUS}^JiQ+uU}~8TfMW7lg&d~zG9Eda}9?w=K8wq27O`wF)b}; zB{lUvt*C5{q}cNSLl?jkQGO}#^YNJeScDK!hzCK8m*&G>yIS#@VPFE{O)<)Tuj0@F z#n4mPgGrTRF!1!=yykl=!cLNaPv~63#qE7vx#O+7_S0gC^f@hfFACt*iQw?E@S09lBG%yC<0w!MwQLJoVKRnkD@7w2qlz^XR0c1_R-QB;+%dzBA zIaM=Nx!o=)b1u&s-R{rzbI*ykme((WFU=ll1~c9SX&m9hIEZyPXB-9yE zPE;Dp-T(o5Y-1*NreO3Tz{94p(lvek<6V`lRFVew;7Y+-HWFgpZRf_vju-DSvEF7T zg)gEq>5tHwbAaEq^!j;z+{NZCetqtS8vVmD_pIZ!ROuiLW0$v5zFCR`ryVs<~at)>o?V$&BQlYi4}hdy5D#^>0!$J<=zhMnyt zOS+=k572$Z(9L*a>giA5#C6cEk1-KX=RSY%#A!-B->2}OVE_FtnN3PRg9%hCmbpGQ zR@UuP5oc?7sQAV0UXH!F3iFm;GmKNdC2S*7-k>8w{oFiJY^4?^$7Hj1S3(2wh(`as zOSnTv+Lif=T52UZq!M0Lemw0T6tYQu_#|!!p3<5|C;VOT0*^;sHg33^hACn zbp`Acuj3#A6@E1^$1&~6cdHW!M8v2kZLApgg_a{QMY&?jkGP{)4Y_p;>6 z^>VZ_dSv}IVI#{rPwcKL?)9GRMo6t7{-4sRZ-)5Gf=!ggLf<;o<%@UpdlPtL6uSZc8sU z0|WZg-I@B_Jm%93-O7CE~!M6{Z3nRHM~R*2JW#2lqU3SBOgs08TXihe8muq?F#Q=J0#P8uye*w)$L903`NYNopC%{1H;g znJ*Ix@4e2>&Tsee`m>(NG@Ha}-CaP*Q44WWSp+2l=q;~-`IYNmTL@)NSrhKyhVr){ z%3dsYWBxIt#4QY>17>7F%?LeGl@(!EW~lz8`}?f#Ps*-^8g$ybcrsQDd#s@{ie{_L4UZM+EB7gGTlg5VNeqcx zB#M7$O!>&RS+kM^_FmS4myf$+La*8ar20fBTq>)s1}m@wV9yE`^^`cI%Kc^pvgR9u zX$wy(>$5{Y1`7s^#PQ~++{lJJ_)Dk9c^3BL1x!2KQT3(Ut?fkli*(b! ztj&mug$qKs89mqy42feql>=8pq{IgGVwMQSt42%>w^%kt;K#lQ$QYLQr&mu2(T&vz!j(tDMp?oq8Y$Gr5~_##ut<$LtM7NI3zx5erN|TsT0731&imGlcy(_7Wr#G)eai z;fIKTkxU>3)2H{3`9tiPM^E`v#mk;{WH!VhjonwTQ1(ls^1XL6|GzwDesD(m} z5VZ1*O7cJJ4(KTL+Q585Ge^hyyuz=WH}IKsj_u{|u;I*lu4xh+Wc~VQ?GfdZQM)TT z8b++{H;AT=vI?E|3pk$io3hr4F7dT+)6cq~Qif7Rbi@T6QLSWOhX~B?;iT-|40bV; z_gq9J_Da&To5IO=8P$*CLj`<((wOi{%1HX6)?v}h@8FG1sJ(?@BvN4V*o zI2gjk2(#mc&`-C?tR$m9ETQ-{W01y}aP={1qo&ZA{{G0*^K#>;|M@!&^$2MY?&qo{ zF)q9v++d_@lswj~9retj@OXM1rhBv6r*2i9@tsrcs*pdK<2&1FRPU6M5 z145R5hujDh6~p6kXf0=9>Vpk#y}cnYIOV@9Djhbn9R&{Cb9QRELlSG*;Ulz>4+jqq#T_la=714gXww!%{vlhZx3cyw*-kK`ISsqnp zDvI5Rm%RSwiIsFCe1n8>$kZ`ws7`CBPIbv3f9zMopOy9$auaXNBx#4gwf?0?HY_G` ztC$8}sJqT%iSK7CpRoW9dFX`U(>lj1E>_jqv@cX!uvkyJjt6yrW6^JkG zWp8prZUB2NEn#*{x+Hx+c#=KuSj$jki-(gM>+vTwRDDh(?CI^3=pg4Z2Z79;R}Z}4LZ5FxHwEvT#bOiSsK{^4S_jXtMX;~ zD@L)`2fuUfqH996uqLv^kZ!L1A@C2mz%)8|AtyGH;9L$#Q+~e#rm^m@1)N_qbbCE6 z8;ibon-!^*EGOx2=Fc$#2^@$d1?Di-7U#QU*?7yhztdV_h|(c%SUclLE=QvfwA>M_ zZLn&l)RCbFuLMvkX{YfAA&0HOkuVrL7H0-u96cz(x}(37{0zo3_VRu+lqi2bI}E9R zY#g0`THp-OiY)ZZ*xMjzYf#+ye4NX?yc$G!-_$yPzSzdXWyqIOV*z6X$j*%qiXd(+ zk0=s69lmF)?E50oi=!9Ep3CF*KCf*Yb7D9^;Ie}h-Q5jqhY@M>X%z%R_Zk8cObd0= zVf&N>Siz^um+NHDgpHdtCM>nWLui`mvxceA`fjo(9z1v{EsM)-BT3e<_3PdUrevp(`h{x`ecRX6Uk#~Syt8Z&-4o1_6t!zDEXMZSQ42n3+t2|gIiOj4=ykbH)9 zMv+P&1iW^C<;ux5CdV&pg7H3_B3!^wYx%fUZ6CMg%ySie_C0ms-sILyEp{ql_Q;+6 zu}{m@V>6EXUIX#;$}XLkwcV-rp5&Qcpw*)n6S=vS*-V>uB3;>{GBbPs>oAqu>J!d;?i_aYV0h$&v7y1L9 zRdwE9h~5GCGmIrbrl+oFZ^&$_&ATuseA!G#3s!jC-ugqz^ErPjwwhScw`i@UvfYxQ)xd|g+VGCP!2wzs_CIpQF z8YW?vomC$lgK~fd^x6_e`R^0>87}xdYO!kfUAra5>(;b6=gkKw%T5^Y9>QgdLAIvY z_A>o%t))cYjj&HL<}g0mdVUEYF?BdlM$PM%=$?_%t{>X77V|WK?PLJ|#6QpOE(p6c z9g2=7L^qX5Mqyjr6$R>I+ktO(RLiT11$N4-MuC@{u7S`T&eeLKZ_xf~LROZ(^l6`E>YX3a&w&3%^(L_$L z&`6fW7KGpnenw4}jCGuB`|q6^*`Eo5-oiAx8R(Y+n2J?`DjW3R^L=yoTW`-3I>IMa zmoES}s$+gS3D&`Skp3z_PgL!dhQ;kW@8I$bXbstij=K%eXTA>AN{r8EuRJZ7I>9V@ z>xP<}OxhRcEc|J>|?V9|cAl6$xL)li?uuz;Z3)gF4CHjzkwUH^n#Q%EY6_pW@VCXffz= z2Tm{w22;Y5MG`L4IKSo(Vm@S-f1Gd}&1zDxos}I@H9UZP`LPbypsaZ04dZsAbfM95 zPd8{z5L0FXnQ9k}>Xg5ifs`~yCfv%_y?%%cI#5{zWvV~vS1s6X_hWMy<_mRw|Ag@) z50oHC7peN-CHNxlzhJps&mz4LXPjojYfz>PKkV;SmClCkUb^fFXMCz53i%1Sa^jMU z3?`mYRMx}$wDz1-?KV*IHAO8ynI%Q%+C_VI_r7aWqMSE8CT@(xhmcgKz|&0g`I25l z7E(O{7kD)o=d%PxPM2MkJwWH!y&swT6yBE2zY~*Klala`G-%0!8C|YTbF@HU;==R7 z!*zk4=t{t$3GQx)Ngi#up@<$*ItlB#6^C_1uij*DUk`K>WJw;}o-q#V!yCVf=TGui zP|oFdL)-3IC*ZF8Ksyuk3~RUrz+j69G$A~{3QaOyc8*Q!dY)Y}?MOkn6o7S5Ld>Ib z!=`4-i~J*#4p76*kSZ$4?ocoj^=GX^=9tj!-rDl0%L+f4LSXDmXyunrv;N;|@` zHnthaA_ zhNfTt8YBIeU{)CSbF4{*_e{JkO_k$zg8S-?tEcW7z8GIr!S)*({=+u?Rc6Te%Vqa) z>dAU>-&f9TLnyPUp9FriukceTG%{FVXoZ3d6jcQZ2X+3WcZEWeKxydgO+%NcdV{0d zpg!w;KCjVslwTJ9pHtQeZH3%wb@%iXatvu>5A#_ce(sX8nwxXV`OWsuJ$0zZZym#-xkFN^PLsVOkYX?c z5U6qZ)>kr;cmrzKG2i0BHBW|vv$a;(zg%FSA-$G^V&cfl3o_YJSbFG}+=h!}y~6r8 z@ZaIDX62YVu(!zghY8Up1HZ<?APokm9yO-*7bGh}->U3gV$Rq8+#5C6YuD_;k!kcbEsfZm>b?8V)kXyiwaEb;AT z=*<_^`PNaYoE-iC(`m%-*I(lu&;uAm{x{F|H#H^9fQ@Bbme?*^{U1*3A2!Q3h4THN xuH0lo`TynAYQ&+OnkFpM#Q$ybM{N5mj6kIgRSufk)?d(65QPM)2<4{T@ zB&?5iva%Y=va;_q+?=iLzFQ$7DdFa&dw}rF{);? z@(&HTj(awl1yMTm~+6AZfsVq7HcIz52mls7G{h+Hd%laB}D#ne5FgJiS+aJJ!~yiZD6k zd3d)(R#t`5NYmW~*AL6iHI7~lCilgc;3PUBSq5|@EcpdN@gOGBedJW_reSj47u1QH zG*;e-54IRg@&1o+cw1k z7*^e1l(Uic?^)*NV7Z@>c!;u0rVg13zen@R6Oms;Um+vCP8|~Ia>I*#5V6fi@+q^~ zi$RT6HZLPs%Cy@*8nb?cHfcYYe_&4?RNaa4`3$^i#!28I{ZZ$fF8_*A-!aQJ>AZ&O z{9J$W!1kecWs4?A8zC{~_oM@5Is@i^jLX;G`hHf;-A#gY$M7wOx~V5k2dUW+U3!0~ zTK)1J(iIv~^JeZfO~iNOXYic9r_ z&jn@k9a7j2r8g+)C|pX&cG9SgA0?OnrQnC^U zzO|iCZ6uO-tplVxln^A2aFcLtZC=TGUqjrMS)?r-QgVOi-UL zwoRhTpZNXm5c7cdJy^k1!8BWmv?IODzc9a{I{d_cpZ<>FJHwYZ6t53oBfEi1%@>lyOKkaTi>czN*~wHGM2ulkeMs>oo#DYZ5Ca%TIHcu6e@X| zOF16Cp*`xp!L(wuGT3L?r`o63Z<^3TAK)>C@oABl#-+q{#wA|!AG8C(z%{`-JL8uw z*0cvUC$@kzx-{#wS80jAKkGOz5G~~WcKoeA&tuPIZ)U$@|FpnW6%Q;2dglZ4O!!~+ z;E^Zw9npSmkM_5NClV(q6xkF#6yy{-6dC*@0_53F+2h&!*@yh2&9>jL|Db-`|91Gt zm?tgkV(N=EV^ge1VNLCMIVVW6WTQ%=#-gH0&!$+dX@<}!nae=vW2<4SwzrJB3b!7& zNuB0pp`<3D22j$g*lQ3x(f9Y=s%h-Uoc@Z!n8IGOe6!*m3;N$lRUo$FZ^dFG!WJ#A zF;Gdc0aJZ+o^rBs{J5(2^8Dr((+*%W5Xa%bmWjVgpmVgSeqCR`T4Aw3WKeu8px8I( zfgM{SRxdV>WP`+nDpH&}C&$0QW{&8@1DBHovB5*Xq9&FJxQ?_yNr>2r~ z%d7W1P%PW1euJb_trK{McSrZc^z;EkBGMOFqkj`_Gxq)1F+Nj);xGcHiOnh7l=XKW7z~4?Er&O2X550yQ zhc=caRuFAZ?D#79Ns6(fspTn$6hLg_sEoR=Nnh()lkd$h?JvtEMJ1yp<0T1uyn3nv zxnX7qWQ5n_#`O~9@Nwx$9aR{$8uJLN1XTf57ef-87xOKeC+cATtNzZPwA`~M42JV0 z$TDzQuW)fp0URUZM|UzV4*qJUGv78HpCBJ^R8DhwIoY93rNpt>F~!(;5)~3}g>l7U z`2|H)d4Kr~d6f)34*jM*g}85V@5&@dXeo*P8NA#o?`JnuBEe_7Sl|mTKEw2;vsJf0 z`<0Wx+FvI9`mSs=l(f`aZ(gDa2P*eJ*WQ@4d+(zzrF2F%X)Qqsk zFpylvkWsXSa;-A4G8kF??ZrhO&dikz=Y-$!NJX5 z_MX!u_4xJpQ;>kQfVZbjkJobqykFqL0k0-}vDR>{UCrC5zhmdN=QPproukqUWKv-= z-imU|DQ0tCvp}=H$JDmz@?b=!T}E@Kn{&nh@B8p~;_v4h)=f3`YZ-LLpj-3F-I!f< z#`WaWE&af+4;xc=VdveYcco9>+g`7|*EfzkuJy9a^^I5l)@~cs>`z@4UA1<8J?qgm zGjKJw$!`j7(DkX9%UFql7@(? zD|qZ)!=dJ*-XuJtRAt z_h$2I>uWbBLo(`&q3v#!Yu!(9os24*S`j0$z`Vfj^9V%zB28z0y2)9P-SMAG$L?d7 zCPX^8CZPu{@bJ;-iF@;|BXB?AC65v%7X9&ptH=MvcwOQ+a1#N-sKhsxn(`Ay*di>> zz(veh>TLPHrD_lhuqErt?whlMB~xHilucqpn=JQB+C!cCAR4d|$ga?=aH3eF2#kA( z+wg0+8HP;8Wz2!Yds&}b?$bb3fFSRuZX5IQA&3L$G)wB!W<`(4XOS|4oPhh0DMis}a;AxR@C%YFRf z^Xkk9!<1N_@Y&c813B!iAM?$o{O=z(312>Dv(O2~(3x^C2L%%lebMk!)GSfPC{-q4 zEnGqhxyio=o^|`SdmG9u!Thng*Q~v4Y;3#_t?%!?N8;1A4DNgvq&)KyTecZB^J@L{ zRa(EVw7h(9dU{%are^!{k0h7LgpY=2X<6C8#)ib4-`&MV?1B*6;KpFYd^3LuGvj*! zMod;^=w5k&R;|xG>v3qVh&!EnzPL@{Y=8*h zy_VujS(=*VeAb6s;OSjmn|g#8Ko=;27hzAmG{My_vF4luTs=5=(Xn;vOOcEw0pp#n z;0P@a5u;gDg-e_C@_$cn+o%K&$iaTFsjHjg$9kHKK}}7~u{<#$J*Z%)L8}vW0!FJ% z5s^Jbe<@?iKwk2Xy)e|0@)d~FrTKD$MWj~S?WfiruBJv26F@EgscXE;qqszZWOZZ% z#OR^=Fh1YrpUnfW2WH{>ZwcXbte6Ap-2igu{|_o_|9I}!40|gLB@3$XZ+xe@0UQ`7 z^ym?|ybEB*;04D^8qs&=>Uw}kh7+4o+tDD>6`|Ah`#-XxuxPn$~oftaa#J^p<$tquFAXv z%7y`?rYTVbYP-8R1#JxEJO3tuU9UX!n%Nbqs$rNM=kk_x3vHRfJS?RR#>7<l$$J z>l{;}!vEh;>I%ER|IlzsdknEWi`{{(pR{I>s@ zDpTr^`%kbGl8qk!9|n!}vy=F$CFjry%XB)nA(U zcHMJ>jZ*>n`3F0uzS7W zZ{oFzBmEZ_iQA@9HU=g6u+ya^Tkpu=gm*rjIiTRg+bzBq-V-5kbhGT$e+lQll^OoO z0N^N^r2pq%0~k4pC!aCd1A{Ac+J)oUW~?zu{a=7~0gS==<3B&B|5LfL7+2SAG@bef z>P;_2V@>ic|Hl9BY@Fs`I_L0hzNqK#PqdN&!Z&7Vnd5-HJxgsB7pCp9agQ4`KAV{# z|I2Qh>|o~Tt-yO~3L&RBnQ*KP%xr9q)@X94_4jYyT@c~p3;p_3lg#qTrghHD-90jg zl)ZC_=O|?ZIYCP@zvPFBT!Z;=u3bxsESb*Jhk2uB6p2qyzdh6_^`7X(yAdj1pzbui z-n*96N`18;i#NB9^j~n_IQ2eA$3rU0bqILLm<6YBR4_eC z3DhjFA2BgXCvFxtb?w{zG5jhPg#?2GZ=Dp61zU(cv_z~!n46oM*k)Lh_6`blEmIMe z$TMm7_~;!S6>ji$`XoiX9N58-=6f>FI+ewTp_oV`Uu)P-MKYgr?72&hZ0*@#TxdxwQNBLj* zREZ@es0_oSySB|@Zn>`&K}GTcKF=yv3@I6(M^(Q_7!sBG4yp{7I$_wR2lnyA8+lkSA-?oMY_OTyS6?QU73RZ$gjG?97oaVS?)w<;5|f+ z=s0~7u_orjzp}qk@4Sk6E=iI4)rb%%tHxF={XxdWO?Vi4k+VoYpgI`4%9oaUZb$aC zffx5(i>PI&Df2eK@y0$mj<{2CFnG&ct0mHOEqa{gf*=+g3GBN_!xN*v+(G$LjCpyy zD&l%O;mQG6CXrpO9i9gq78yqwFx`qJXZ47s5@sMb^^po6eAKm2?zhrR2zQ18lWECS zvtWxbU(@SMffv2&M1dDe-b;)kZ?A1kUYNthI9-cfOv~;fYF6az3&6 zQtj|)mdDpKHR;jpXJM)&bSV?cbyy}QA^;xni^5Y* ze=6KrX>Q(=+nd{_b4O#h-8krPyPqlf$UPu#D|4A55Hd_juR%YQL#HeZ0e|(efO}Bw zcSSN;Oe(6TJp!D(wfCv@Kah6|rVgvq-bugizcjkRL+@#b`!Q)cAOt9u9p>loabl_U zejpm8*gMp6v0h;KEWGx1(1PV{Ajv4u1eJ2~nh2uRymk%>%f~qW0J^E)PAC%aw^&*t z)pYN}IlDAM*-uu|_=NFJ_9HG~d55 zhr494yR$Po}-5g3! z&C}H-G9h=`81XwM$&;hd){aEouHeTxVxO*{_eCNEk-BP%z0oFwBpSC3%07r=FP1T* zfdtYggSM%M0@bE~jM#88Gx%H`D=ItVknDB_8zQqi%v}8!<&@Xbj zWYKSA$mX{z;u!xNT3%kRHE=_1s|!%+Q8xOXWzFuLKqWGtXmVmXEXKfqs#B$_V^f)T zleO*su+GFKd*oG_vL^Q;al|&{P)XH7FR+=AAfN=2%=zgKIzH0kL}I_|?9WTc@LBHO zwoa5k`SWGi-j2`{9i}rUBo#&2^& zZ#OpG2w#rc)qPYVUEg${DjGWT;oXI$EPqxfwHPIpH8(HPPM~}H^KZ8#pxz>nh09HJ}h2A<`shXug!2xz!QmhTSEner} zMn<#vY|R zt8lHt&FFz?J8Rfu^VEPLDf@(BdfWE4DJnYZE4E*B#`m* z4?#bXMtxTNl4MV@v9$3TY4G+;CP!B`N#soJL#nZ;1HaAuZGwO)q{;G}o`}KFIFO5h? z2u2#Nv*@u?O_zHR3HhaAUxc&CVCwKrX171?rxHaCYGvUONC`=>h^zQ|@*ryfagws& z7yBEca167_VPjjbV~nX$K3IFRnE9-|sU}Pf&U3Ab6Lj|>;P0_&HRV?FV|d@Vve>eE zoVupnX8!62#st(9w*aS68pESpb^Tu=oX2PAT`%wdu(pE5JqL95?BF;N{6K7PbM!wy zJe)gjBTQ3Lz(;jn%@M9E4FQAGq^@^eKIRu@{4hHb8gfyr$<523E2pFHr`B8*a&40_ zq|3Mklkl>MfVgYnp_!`k^YCN7xUJm~Y=?XB>spnI1d}`mNm@7C?$n91pxnr^ zfVf#nkPEkdLOuMrpOrZH4J|e(RL<_6#jyP%p(n+pe<;0od+HijBbUab4YSL+|8`

u+YcGkY6#Qs2Q68k(^61i1rF3{O1=zp-W0>dgnF2z*ZY{2 z@4EAG2bD_2xniTY38$)4(J}Umr*xLvJn<*yS*0It%;+MVS6-cWWJFT378qgdh1J;($IkTa4YRu-=1Faz#+mj?NEO}xNxHoX?rn7MXTGM~s0@xON?pTm9XT*eYLIG7jJcJyDh7Qsr zFi;AnBvKv46eLPMRl3u<45=^1> zS}-*qWp_7gv~qj&PuuBXQt}!GRC(Nxt)KDTExHf@ChOLJ;l^+X+Bo$PXNjL7RyJ|T z*A0%?<-DSo9AxpqsNSB?v&^rbtfrc2g5bInK&N&AOz!D$$m@oGX%q|*b-5OwYBZY$ zEW%mchY)(f8~kXxIUa4MUK|04$6MK#XT%?uV57`gkwmjHbwGmMT$v`!IzTgyJR!~c z?jb`zFgIVu#5683@hiyzs92Gm{dzc-bUZt&n#fW&xoIFnbO?x}+w*38REA5@Q1>hJ zkMkDILe+$!`VV4<@ zq?oUv-G17W`;#6R@^EP}4LwcGh#6x~QerIFJGJaTf2P9YrU~U%^cuQ3&xk6|r+@<; zTo-8K2IR5mGpqZnA#2BNDu~fh@Yzxd1jNk=>h|I))yo%mA{V<*A&-b6^# z2JsZh@{C%HxdCFr!t`<<9l5?q@lmR729OMIM4MEH6Lx3Rp>1yj#%eg-0gZraQ#KW6-0_J3}`ws+)6?p(~%u z>B7<(Qkr=KR_9z8|7iY$5zRC`a~=pZuWsXo$KdNULmR<-Dh2qg{-vO8{T7 za`xs%@4G$(?{6ixe(N8M8601bi_Xe#BmG2N=G=b_y&G?eH|K^XAiVCD8M+?MJ>#?J zPVNdC@J{+lFU9c;T_*CL6aKR|N+Gof)8vIX=LV;R=LmQQy;8s2vwqt$Z$)x<4UXOP z`MF@cJqLEzV;7Sy|!LBnm*Q!P0%S0s-uPrF2q?7|)}b12A|benm~Qx!RR#Z0CZuKDgS3N~JO|5j)% z>K=wdI7+o-e#8ZF_x65&V3KKn zp;0-70(O|Bfdt{hY|)OsmGD7gyiDR|4TRT5hcea^AP`AP&DySnPu^f=RPU}!cXD(3 z!_cI9z(OE@C^?$8*gXdwN455Yb!{N!K4LsMr;f(BAoV^!0J(JbSdf5n;}D@A{COT{ z0Lu?{=%BeGgqAU<&t$AP8fpCX*b*>G=`K`Ygm%ujz<&YYUGuFh%@hf<$(c#<+k0{sh1|6y?|;l2ho?%mPVYm&dpPJidywRX-P$T3aaICBLL<>hreMt~DSrX>Te^n{_>4zC<<>@8|D;rpFtYpJ~WO zZ*Xr%T3Bz;I3Ul4@zYL)_5itud-f)#WI3%=5S8cYV)p}F^gRz%aN|bj#avVoA=;Ey z&%3{|0bC$`wzL#!W_;KVeIGrwCgrAlY&xf*k6xRGnI~c7a};)Yo`kn<(!t?r#DE8i0Hg_Lm zwjmv<13wp->8?*o?b*gi)jxEA0)j+tf%t7WT*o8eXjk-{9};Gy$_JR=3B5J1rF*aW z&zWX`Cn2pSk2*9ZuG5zS{l?%R_qp zn~;C$mu305qBW6VH+xtqH%iMVd1N*{(E#BSHifF^OzK-NlUq$E19C>qB5pE)vWu`e z8a5)@&j%l3gUPAt4`>~p&FuaHduJS8S@F)iA>|yx3K#ykCoEN{Y?!~uzy;yA`cNVo z%BkL(Y-0>SuZuKe=QSvPK%3|f#b7T@x^~7eF-gc5?0MK5iD!Y3d$=0Xm{8grOr7kq zzvy8uUMu1=i$nKY5majWGOSb0wl~ZCjJdVJ2X*R=Z>{&{?ELI>%8RPJ0Fv(CV!j*# zA8S9+)5KWVHY{gn-h;8EuDO^Lc7n+Z$Mq zbt0mIC3P=T`W-22g+GMf<b|2Ox^>Dcz3V+p&F_rf3|UjyH#B?-{2CFi-~CQn}$bE2mz^= zKIq-8C0dHkX5Q`-Xk)9#SH|_+JfbLoo#N64AyWqe{!XaAD#@)jZJg-bg6S`$>1-m( zWGCjHbP?7Qo%yo*i8`^tBrle=-f7u!db+&HI{B%;h(GK4lJty(RQsgrz#C%XvYVj%)miIA0!2}O)$WaopP z=SK&~ITz^WRpy#&0KE8hcZHD4b{`JpN%|0RGKf=j@y-$y>};W==Lm&v!fc_y-L1fH zla@-GNzUW{IMj6b2I!aTt7j<+sTN#HK^OPb+pIs(HP=-_vAlm9Gu*#f!&aeKt!oiN zvo7Vg(CCo0(sQTNUBUKtXbsiB1{#?JK8%X5_xpsmYmVqgcgyQhCm0G(KpEU?J@0Br zuPhu$?efG6fA?_zb*w5WDB8g7SKyxX7IW5gDKdS}La^?ORfg|p?v!-6b>jtg3RRCl z(2EgxsU-;E=hQIQfCMom0Przz^bjsHyyMwDg{tgt{FLc2oz~a$)KF@VA2;kl9HF<*1hd5MvU3ZT?2&kZSUAm81L82 zhkqj&rPAS198u0pLdi@#|EOg5%PR|mCTrXc-Gkqzr{wHYq<}1-n#+wDLc69Xg$Nn( zVRsWN9~vi|%j9Vj?mRS!l|E@{GqlreuwXUht8vT2xf|!{_E>X7WO&C3@66c2=$ASc z<1!dXr?S$E(lfq=n@Tn`?Fsvjf4Glk>F_)))10PXcKeTg z)uXEazv$Snc*{pl)+#$absT@NIssJMi8SPw#=U@j11tUizcLL!hWOR~yOUVN0rzg>KsG~dlFk2mXnHe+3n z(OCqX&AdXOR*>3~SPL9O!^U1%T5vhu=nW19q?8xLXH2=f}+84;yL zYy#70gDZcVt5YVN=73m~l{6II2k5&)o~JX0yg{~U*M@LD01-<+fjE>iAU1eKKS*y! z?Q4u6_8)6p%Pe9>L)L}VVOP!im7;00bYHc@PDFb=$@3Oa>LPJ|{)@wNxW4z2fQfcX}K8Q_Y-fqE!jR#2q@ua2tV!em&(TK!`#G~Ein3a0oJ8sYFC3M z^{Vebicgx_5uzFF`baE=!AYS`3W)=vei1(%SHPP3`YJEZL}h0Y*r6+I;3mzz{<$D%7A$-? ziOO1^Jkx{oCgfkaWK!KpfsE_|?%vS_Jaq0ci-=@Z>8kBz5L*>DPPs~sPA@u!5Q>wN zCOhrC1j50RNs@p5E1pRo#@*h7zYI`i@H`<;N{XojJ-1(3u&#d!tC3pCLNO;!j*hU? z;f_s0Q=gU7E(^OH}=YzqEMz4wvrcwK)zDn>t#n&3U{9R zPZ>25-eH|XzXSXrWeO6u4=PGZKc1=XRozq_>To6}(tDPjqcSMwY>09H* zfCsLpHNJ;=%LltLsO81VOWU%zJ^57lm2B*uo_d!dtl-+y|MHi_iDvMOrWr20HtxAG z0{2Gzr8rZn2owB+)yDGU^J%=SLjz|I^6Da{=bhc+P5I6?KKmQ(ea(5?+m4#Y_RG?j z;lqxV4Lrn)ZoqMlq5~;Egc~hVx8_TrM%}O06QP~rUDn?3fsv=>h{ul{tEmxq)KvqA zT#(B@&o3D8-fbLj-rB7wtzH(;n?8+DqtZQ2Y zkTsBkw?ts>t(CqUjO0445pQVnh~zazkzwdyA76K2#B~0$>d{xZJ86L({$BZ zW}jM=-xK40d7+(qeK)wJv$^l6Zo0h4&gH@z#O*{KwzF0%I!O?a!$}jH4?6jBOL7s7 zpFu6dmR#?-%(v_%FkC8LNRJ{F+A=i)$iH|I3TWL!knJDw9hkHx(SoHdM>u5%g6&!l zM!}Rn^RE1>cWZ8@r{O9if+wLh1gmOU`H8G1S-9t{!(@f9uFeKMYT7XbmT^!c<8 z>~AkS;ntEbC&wg@&*N7qf5OE?sI)irV%+V$zz2SG-dVrN=C9xHi8rBxdp3d5c!$xy zIYo=q2kBhAOLDhb|7{!Fh-9G-s#&Cl>TS^d3=2#7CKCUIBRe|#Jkv(_1KA76mU-jm zzE=R5w$kbe_Qa|5ATl}o8>Wz06^`J6l` z{c(z@`Ib(c1V}wfAqt`f-k#xX_5OM>-(gyq^6jS89!3D&-c1yag?-37Zk_u;*do`6 zmbJ5t8{{pR?R!4zP`o+l5c&zc6RQ4xsBr#t(sTDIb%?u4_uc!7%-?HE+{|ga*g|Z4 z8y~Tkrlm}R{pj8w%1%(p8=XjXKN@v)Y%}=vcA|2(aK!L+3W5WEDWq&uo~nyByb)Mc zm)p-s-|3WOtlVRO3zwlA!+OXME*{B9$mbK)!W?i zv)yrpij*s_ZWNCv_LD*rQyHj7GOaBj{<(sE+5?A$lXI~I>hYgNd&m-{Brqs5x}$%h zVbe7qTb@Y-z6N*{^Efu$Kbg`eXWA%_erTAKtA4PO^waROwZ-NT@j<4PIxF9n!B86< zmpjmZ>-CxXqa8(1Icd+ZRiicUiyB8DIrkKtz}K8UlL}kF+^o(Cc|!TcYKy- zxhz0Kqtq^iKEBU&F}(^89ZPqUu5U%0`aQ19D|4%(ANh?k{X#9Uz9a%MhaDCbrxnGD zN+)jR+0wECuKYbJ=h4^`udeWO^>0boJpD)&QnB;3bqvM0{QB8{xqO~oOcsH9ebT!T$sf^S*1GIUK>-B}=eC_bB9&C}UZ@!inJHP7j{afIm&bEVZNH;0S z-CCK^3ce0m6`y?>R9$t_S``V9OirM$6k#C(PCqWRI}klzm)q_rU5Y*Z3O$f3+V_o5 z|2h4^nOpy20S@?~%CBB2lIYU&kYc59^l~`$0+MsjhleM1dJyuLKo}zfat#Y^a~8{d z7M$&$3m<%etpM}M(zp#2^VE^5`KHWkEsNnQ>y7-O3dbAB>2|bhkolbD<~rJTh8T{j z11Y*!$q(+DJrU>cO%2UWztggaBr);;#wCjsW#NaPleXA9DYd4~g?sGj)i!sj zlrDI6G>XlA=L^nnv-hu)7T^>?-vYm-t=MY>H&>H=LQWwqomi4y^3wUmY=Svos@#U9 zx|)Xlfm6Ej_rjMhxbb%zNFc56}tseZ>gjsof6t!Qnq?}~9x`l%$UYL|*nD|FdrHJ;Qp0e8IY z89L9|m4qK^y-@<9uwdrbb1X_|rRBp(L0&{l#}qRA$;bVdFk)LpB(Uqj5_p-~{W>hq zUR95$8GQ?K3J$A(7G!qWd$aF3%pcef zDVKd+_>6J&qit4$V_(Ax%@RX?cWDKdZAaRCqw_ALAgk44+sXaQKyCOCltxxPco{s_Ht!{g=Um`Ax^4 zKy5AlT*l9C#G*adgb7qD@r)>^!rt~eX&qAf(2V}6t9I`FZ_?@bUia?LS9r*GwVCli zDT z0d$5zZbKo4Yth0AMYf&IrNa)j zA!8%CVMqZ9oD~NJ|D^I9<$mkh3UI1$Lw+Z9p7@7@>Q~ zF4cKZUe*?bM$KQcv&4fIyQ?Xz7W)j+QM=>MSB3NYYM1-qL(wl}M73xqaTbF3|;q+JK4`{&GIi z89+=LQXfXet?2ukmW6IHQ>P8cN+%bj-F@zmOfjg9~Q`0Qij*OVt;Y!VJQK{Z7a+LK`s z#?RQR4{r-x^aN7JWVyE*YUz&xoAh^?6wotT!exUrQ7#rRu!~X+~$T=fu`P*UWAZ0qzx4 zX!@-!MS65v&Qu_sB*UUvh#$UaIyZxz;PtB({5^IWS|oV?>b`U_@>{TLFOWA2+$y_>aQb*Wf!FY~wUQ8pPm(&6WFvn#QI=%8cyvPSVU)j8Ak@XNanWV@ z1Gh_{&ApQuPxZ^4Y}YN|vOa3yur6gm;;Wra@6=k*c(cjP`C?&Ta9}~gO zMLIJu+|VEC$^kD%8Ls{U`Wh>FDB}7@!Mr?-s`*NcwfFJ$xi+6CjbSBYEtJvhiow!C z0r3z10;jC^Nu;dPG0*(EjeI^o8$UwaA!Cy{v=NMnOwu-)0!gMYP4eFeWBVq}G>pcA zDn;!B)%8mswq`m>k)wo1PRc?yGiVY~Z3gFAxb2f3EV9cJqVu)UGLR2{E8y3f`T!|gU>Om>q$D7NeV{3Agf~%!|t-3c_Mt(K5W>j2P*{aDi^ zlGath+%=!8-`W=~tdC;pif=BDS$czfQ@IUDrUBWpXxCD5th2e=y8=~l5_z^B&5B}~ zGTe2uvIX|N#YTd=uLdh@5p*uG9U%;(Y8<_?duopJ-!R+epm?1U=wIidiYN2~w{^=H z+I4&_8t#TZM@NyJJ5pd5K=$|$;#aU=w!*DwJVYs@yuoj74R$d+ z1G}YwhLM@yr$6*X>`68E%o+L zwSt@+s_tj#1a zy^h$vX`ZPddlZ}jX$o4!Ixk?JcX%tTIdPkxj~rL*D!%Tqf?i~8eF*mX@cHugO-xS% z$OGrZZecaxI#37#| z>au|ADC(`y>4j+UI#;;iR=m_adfbmSj@P`IRu#I9Z64RBO=2@Eb`IMQuvpz%3H}Vs zo4?FF&m2BTC>MXBpoZ?093BZ7c0(#un<(J2p$et}r$335`;*f+i1)gX?d+IEch$iB zDyeO-re#89)K!U(Lc&(ZKdS^kW-M}osn1;fn+J4I;Aw%M+*2hK^R;~_JCRLZT@~A z=VXa^|L5C2|8Ffsk!XslT&t+HX~&V)^u~kH>iHu>v}>k5r@S+MrMT9P0xE<)#m?vs z>DEIjZR8x~&_rR230YmOu*mPn1d=OVp9-~wwikd)e?L%Y*@E#cF0MO4g~1Z2t|pmq z-YS#FA)LrLWMt&+^YfbO^?aKAY;|3&mej_p5xeR>SHqXj^@4{s1(w?`8Dx1B;5)tLxZUo{_bXyOkMdbF;8D_$=>@vTzz#=Tu;z#2oAwLxVyWD;2t2jEbi{Q zxLXMB!9#F&m&F%%cXwxj$M3!Rs$PA6-m1BCyJmW%Z=Z9T;MF!nhp8#TYBkNxO|w?qOC7#_{~99KD|93->!|5+i9{FP z#j1v%-ezGFX2kqnpTki}3pT6-y0C*%D#YmpVHrg;BXiMmdT=rfC$jltaFFM1KuR!6 z*Y8z)f9$fYptIqBJ@YrpW;@C9-i#ZLPmekBkAE!IGm@(+dw3QS~TZW>sXtD z&YtQFFBy8eSXx;`{JS5rAsShc%MN$yuVu?hxHd_no3SP1O3{?`1W~w(UrbLDXgz4V zB7njq1ZtiPq5fKe3dNCa76Yq8Yfrk^XBwyu_2=<^PK9Zc73e?9k>6h#Jw7kV1gMCs zWHzQ|@11xV4KmhoeIQ_LKfJ9NG!?FBbkv9ygUXEBs;h~o)3PhmSpiPST3|HmWo8Sc6X_;Fmpu&3 zZr!1G`ciniKd~~zomE{w;zHwnMc_HwrTB8T^!2VxQ@ZcIz=`eDY3!vL8R9(Kb4t9C z-?p-VKlxAOpL$iOw1Copx`6qnem#`Pu?8HixlrWb+yVLWIG$Tur??wYzl%QMR721$ zNpOL_Y6(Sv%P3`q>AQ!n;lIjN5~5zzhgk91R3qkEVvN$Qp+`x((scR|uJ@b@AA z9iL8IMl7mPMrg{@!8D0I>CG+bBN$2Wp;S#o!HmO%NN`IlZrl*X$^iC|eK#AGE~N{f zgrt?275Ii>z598j9zQIqO!^OYk#d}69BpZ?SC&iq^Hn)oxZBgGov*;K!6KwQ%L+7% zZr|xxc*)EHpuwPv=ZU*-n!&SI;(+2@!J%eH{&e)hkt~{4ZXRZAE-E1B+XGVORO=a2 zf02H_^c};$mMX&nys4w{2bJt+cEF76<5h)WeThe-r@U)+PFIYOu@?L_e!CG-2XGjKy^0s+3gQB4PE3kxNwo(qiy+*M3Z54$) z$|K< z|F=|N)(Hvq9vPvHW zF~pw*cc-_NbC14zP*m5J>JwNEhsWI{&t=d}V*@WXEPsGtqeG2#h|af3WG?3l($puM ze_B!cJe~?2i7e-VAZo@@M!J-C`&k#R!ykwXvGSTU8 zYF6?~$m})jNTPIXGQo;U6lL@s=+aRp3Nh~3-JlhCrn*uR{;j>7@=N0#x42JKgP>{ocvm-a`l>hJI+ca24$1J>h4BgS0vf$*Hp!uR;%<_sTYuli zD6x>l^y;)_IBoVsBwWzRE*@4(EM(f)S4ew!7#0rZpYp$w!eX-HMN}gBJfCy<-N8Fi zTocC^Jg4eW+YtX%m^V}M2WnUJ1p0 zplf0p=e4n(YJhcyJMb=RnocT*VZ&V?_jtr%1mV$p zc-4lK0l||)0gU~1u#4;Ztw6SuYYBM96J|dkmm`ICv*bZ!;Mi2)Q~DSy)6-UsMR>l3 zQh3XD%Isyh!(%Y7Yvr%T#@tiO-tw$(d)y0;%BNXH)%iVe(f82Za4P{*09{!9UjopTZggq3z8{)Yg$)hPG z^X4Qvl7M**@BZBR!zGa$nB`mZA7(W z0H5)Nrz1ZvJY_(>h=2(v>jM%}_Vl`++Xg@velw>-!+lRDU~-JYk}KVw%pS?@>Js(! z^_`XXDOWB#Ab8%H_7C&Ua>Hk8zy-p+uO8ZX_1u~mTw&mSfY7pmZ)`fP7x3>|OZz)w z)6&~zBPe$pXiqJgPj#0KIZgx)almb&vUeh^tU;R8E0bYXSp!eMq7N&lHt2hI8DhIN1o+fFYq7Yd)`E>k;=oiz5MLHynoxI2GsrJ#~ofC2P>4 zin=@%;L%zc59W-9=srSBw~ybf-Js_1QS1-Kd^^6$)rCWH zE|C~NVWQ86ywv~G0!RwY+)Fl7?-ZanQnCPv92|inMkeoaHyv9;m?2#${=S7Ffb%4v zF(B*zavEc#6A&9Qbx-iv1Bq_JKoKGkWn$5k-ip?#=frG&whu1vsX~rq=Ks)A{~s`l zOdeGW$s^^ohNBJ|{bB;Qs+Fr71aEKxD-AmSi4+0vj=5XWguf!XDz|XIo6$*W50{I8e{Xb21B=k!NFOgw zP730puB6kyfB!x!9Z=|J{`O%K9;-oNJQDV_cZ{5p{GH@i`ZfB_b=Nu7&%IbKhL(}W ziyw&Ke+#OuL5$&7eNxJ&^={3E4xZ-Xb44F(NwIvkn}D>civ%j2uxoEDIpo_{jul@v}+0U3t-`qVnm^VhRVda+C} zXSro?7&ZFWJA70ctkqi|>brxj+tknB+2JKDTOx^y6#<1SGwRXYV)NLxUNvJ(fW^eM zEC2Ub4lqFJd&05N$`P7#fMJ6-ZmNJ!xGzWu9XqCK&gKdAZjTAfP9 zRbOLE!of{B7{C2R&R^JnyEEk?$%|q{?B(nCoL_ez6o0+1!r)pL z9VRf<%!JojCzG($IlA}6M?`$`pUA|~AfbfpNG9X`teLlvEMsR)7Reh2G?@%!i_(vG znU80b(mD#W#&}{{-~)qFTkrUu+4?f4CPqYb*I)o69csBJ#;L@kMkF`xotJ4ZN}gj} zCr?S*X05_0oPB$)!g}UL$f7Q&rh}Y*-usIW@$XKzEiP|zW;Wm#R^z^a-jk`59~b7tGdSP7Yi)4qM09UFZmq^3j zxBh#=G(Fz%5&q{HUAh%-J-FGvovW1~*}v(jog%58L>CWCv3M!+?rIPz$iJf&UiRbRbH2&v zgua7`->1P8H<)<273S?}H=ifuc)=(_jcCLIAr-n!|FYTMWH75L?vCfg&sSTR%bM6` zu9;C+rBSN`LqU`mA~)?|lZ06L4;oZ>Zf>qlombYi{l(Et2?j3iel2kQV@_pBwSKix zJXzZP4`HAES+BAJp+km185#Kb_qK@>)3UzR8!!E8e~jfbbx~Ruz6Wpnbzb(G>CVFL zMgE_&cWSej^yG-=zswNhiJi+Du16<+S%s^U+2VvD46Mk+w*7piaH%vmcj!0;&ouG? z@r+boQy%)2i!FKYKSO#;=8I&m{OzQ&Ph3Th%PE?&OF1#Tn%Uip^8>OyBB88sc+wTW zV2I??g96TGWS2-{O%T<7j8MY)pNoc~0~l!3cMf0%ZPKt(DdP;cT<#|GXDQ10y9mdT zTY(HZ1sp!_W|BJ>&aw%3j{LYo`h{c=Qgn=yg(^+xW~~}yR~j{+#qEILAZg&N?GIcMjPRNp#}HL-ue^Oy#-4+TZ0Lo#1{=)9)}z|fj&94e>M48DbQZSL|JGF( zk?ZZUp8H2{mI-2a08|-teAR8VRk?xfDj$gIuIhUGH@|p)w!$d?Xou|(_}|&;m`P;V zhfn%6TNQ0Px$Tx5Yv%hqnAH6#FAc?_+_lblLR!AxY_*e>-ea?^%?9v&2R6KtG0z0; zT&qS93N7_Y`gbOpkl*XpiF8*t+3t|q4`McOxu*l#JTCEs^vi0c1nYTLqDq<$&niMff!;gpn4TrH=&QYKB|x=J?A@%+T*?5(@zZMLoq%rT&h{v|aA( zx$J{ng*PQC>s?@}rJeMJ@t>c;8Y6;HksNus(nyw-tKAwNCR z`I(8mx}9fyWtZD;lhw>qYlQj&uHV90^d}2E{BIr9=MyfD5py1Ym&Kp-WnJLtVVgy# zN=_LnTXcLjL8A+uuh7Y}qx3d(;~P$FUQZReqE;qtvgkFj=ej7Ht_aFT7*o2?u_U^M3%5N(k7fta=H(1 zV%VOWMan_1{sRY+IZdTc(@>4YHCb29EA>{1-mE6Khg0}Gw)i=I_u6-4;~-_=+ml5@ zCiS(CuE-g~L#kWS>&WZn8HoYu$3?Dt`;+KoRPFeM(jhTO8}Yyw82KASAFruV?*%zN zDEFy#^qG9Bu_@)Unvux(>L3mJ`o`zW1ACA^GgYMXN#oQbSdf_Ys@kV#2Dhpaa2Fz% zmU>)56Vw012Jlurm~|}I3}>hFG{QleCl29V2sLq=XBLF10YY=ny<}p_UZQM7L9=2BM+# zBgYC=-^Ly-@;fjbi~J;x{cb58mi#4~b6Z~jvugf{Li-#x-D$QQv~-n%HF{Go?>^y) zsQYQ!*R=9-`ezgkGbQ;4)Pe)S3YTb2)V|h4=bzCNRyVMLZbSP#6w@C zg$1x2yYgo}+FV$(60oKlzvsB?HI?z$!VGxt5=(f7D4B)mry9RoLT!zX>8Sfe7XMTzi6Or}QJ2E-Wtm1r zZ;^cJkF3TPaIR=oTrxZHY4h8M^ie4>YY$c~3OANzwqKqqW+w@8SSL3_0d++r`Deo? zT==&lqD>R3c9L4>4_>2qLt?*4433R~yqCiD1XkY_J0?kL`%S+zznRi5yQea)eP=?U zHoYz&tx(6nce4$9}6|`!8A*8mHH$41y{MTdbyt0JPD%F+- zK{b7u?g^T{d_y%LiFdSvvVlBRPPonQRI z^u7dPZl}>7sssNvsym6vgWwL56~LiOujtdUvETgbyMqn1mWwtjY4NP%%qE@3)mvLezx$YG#|U`ngj}7eWYS zD!PH5zgv5JnV#=gEDe(45P$9Y4biFvu;OknLf1OqQ1po6>LGrJ&&~7}rv1vtRBc85 zH+K}!7!Na<;!ku)fE;Yb5pb=SHOK&=*BaY4&V7<@@ z@et9AsvFjM#d|34Eu`fb(ekF6kWI`<89Q=mu)cP$X_pz}lLA>iSw2u~_UbUbF@Lpx z8p+S9LRG3LFioJ4U|5Q%v`my>i9XpDa7Y#L%e*xjJaC4*a-uFfX7II1)6Y_x5vKAQ zFQ?$oTFxTG9%|NUq32f(&{tj7XBVep6TJGml?q#BY5L~T=uoF33j+r8`;6(vdK_lN8V8+O9-W&=iRNf?Lh zhjyn0TjhsxLP1S*xn}83`sH5wU>I0v@MVSv>chy3`!^xZtaLL361x z?F`1(ChOefT(@@{h*30m7up~9gk%Y8R{9&`O3g<8XdLHG_Q01wW@o*(iR_P{_aN8g zc((Mo$@j^*e{kA8J93AcR(c&BW|uj>6FRpaoO^RU|}xPV7bMpl^5}PH;ec>UY}*`ES;ChCj@z;i z=-+pf0)2Z}`B_r^t45cHw!4EDBIXHS4~@fxnZs|Y>u2YmO0o@-#o{XnL{?m{s+M8f3T5>ChS%uuoS(5JBMUYYeA$Pt!?c z<*Rp|{6^$rhd;@`I$0qHai(+V_WLI$1wVg|R{s@c?S32z`XqgWtYAVPnU?o_JRXBz zMf2L_NP5eS0p-`kQ`KA*zY13=%SGQ_ZbWMWes zNus6frL%dsH_OIczJW;mrlKdVJ8OM--#ow9xz`S1kEiE-^Wv=SQ>~1|qNO6c$7DWa z0Re~dm1nZ%Nx!)GXAA4=`rZaH8sTj~9Y`HmgMX{vWy^|Rt%qTA`D}64Pbf#F3*#*- zKEmAK`G@1J;C64R=NhhQH^$_EM$ire$!mpZ{Odk(%EJ9Sa8iS&7QQFKtTgz>amD<6 zNzs1ULqv3E8^nI`j&~8`N3!QKMVTW`K0QM}5`JCxC)WWpA#{dlgLG~be(SQagRjPd zm7V94QS$dJH|s3-OKA%|&azyi7M98x*}BPz&OoKG;V2;9GRotT!SakRBvuQ1STcA_ z1#MMmbMGkZHfwIGNSoS|I3rxd?|CzGV+LcsS@3wDwlk5sC!VH!6VvRM%xkkJfC_>% z`)wiI#b}Qf*$Fj=PDiL}9u6cfRdY?g$ayAQ&W9PhIbFCqGezi=K?pg7S_D(7_Y|*0 zpn`?|stgm$|Kt~;Q!lMowG1wE>+RbMsS+NUAGe2)>Di1Igo{GFm?Rzu`dz1Vs?io)czgHtYqAEjyT8yu;By#*?D zFqAg^^pBSb8C)2w)p(V3+!Wo#G63}u^%p>s?Cx#A)3art2ai;{+`QEMeiT-MqgHbU zal7^Np}`&VMDzOxPk8L%Cxh;tTvafm@CKuCO?7_D?5kL8wweHDHNO(C&}!1|e1w(N z9!l;$dUF&IG`J)vv0G{Ut6f(tXF}cKaj|Z#DMyX}2BRW$EJbCk?9jVge38h0qLM^z zGB6A%&RZ#DTy#4Y%0ayWfmv}u=o=415k{b%gZFQ*V#r?#lERo;TSMi>stPaoH#PrYg!c(kAi;l%8qsmC7po?O6IH4-zqj*(V_( zmRax0Hr^f#+=_fzkk+hxSxUi z)!ORlO%+aRx6Z_l!yrM|oy2*ac`F$Oy{^=1C;ySeOb%69zCB!if6QNW~VmEv=t%7r0Xc+DX}YetP-XiGca-uENC0H!V|*w53g{htY{S^%cs<$2E*c z5wf)f&KSyivBk1$@}&;n7Zic2{{-aoi%QJ@dQcO(7UQAk4qii>`cZq_hJ$5l&cajn zZvFsEFbZM1VqoDbRh1Yj^_su?+xaqKprQG}^YU~B4%^A`O<25GUNUNu)BOGNPqQj+ zWZ-&gdVB&tJ|-u~#NnX?4@1!Sr%$6j^)@)$$1w-ZF>&TiL#�rOA0JA%RX}dK3^D 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%0A@;ozrat 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

re1>M+7hqYw&%BGR^RF`5cBBd4K9O6Q*mks zhRk%SKyntF%;)S;MaC*CYZAM%peV}~Q?y+dwO044(?~fjN{}*+9rv%cX?8Uo!|_0B zee&xpi6$r=fCEGvXF%+Ah%z8ABXiX1s=Hho{%ku2NW)%DP=0YjpQWV(8_?9m@^$vo zM+J3Ar@CH)XVRR0~H=G03%(jMkpgu+TS;JX%x4d;zF+~IV9d{t{vEXEs%#U~b z;qRDSC8HCT*v<=z)96D2PAwGJXkcr8&mbL0BS5V=$zMBxHeZ%i`|F|SCzQmD+AVFx zmN`Ae#A@_ej{6Lr2LgA=d^isV_t_famGjFFcux;o3Rbwc#`-`Do~c~O7$Ugg5(u)^ zEc459M$K7yWFE-63Pr1sxbRcm9OiK_%ixJV@j{D9tDsQxsbV1|U@t5>SCqnW41clx z(HMgSeQsL@k&!KSB>RrGSRDstiUMMMdr>{#5oDiDsm-Ay|3rBYipEGw1G@&+-J$Z? zjTl-sa3^9j1uV3SwqT9Smyx*7{V9{0MWbfZXt3MGfezBn#9)@SO*z-dIV4MU6HOC>>_XtRgdiVx?(_?jbA-FXw=i|4BG zzsgkVTGBoQpZWY9 zh=a9}EM0aWI4yuWYP~^{j9=?}T$;w)p6!O8)JBhPw6Ph>1-zlpa$0L?Otbq!Gd=~c z0&_MaW!ohYJy`NVGOPz{D4WQxWHOt~q;cCdYA`t07)3_P9TKU`kpRE>bYI@iUZoa1 zDDSnb5x}NVIf4nb@wh&oJ+>&oL)%pe7VjXHPNjK5oU_|emy`xcVOgyX_@p5bJy4{d z8^Jz4yjYnJrX+#uJp~Z7)#lf30cl~}ygpZE7SKs&NgZ9xdzt~KqrZ7M=LWPCzYJ^1 z=F+*+(jzQ4BSwCWZ#pLliOO+>uB;mlz(S9q@GUg%?cXnS{ob-X6!-+~!RHC1yY>Hs zAjw!oazHgOOjbY2-z*R;;n(kM6N!$rdy0<94_C9Q)?$g(EVCDQ(~z-I;Bhr2;f}6 z;K>$qX@mZ(=j=ycFnK}qS8fenoT=D)l))NVwuF*wDwskM{L0ajDQCwHT3)uX$hw8@ zG=$VmVtUR^b=@OeZnrTHSpd=}k9DkGr;Ul}ZFI4>c#A5K7A$F;vpF|o%MRE$BWQ;VWF2CtNS(>@-C^#|wO2)qy&8YT+Q?Lm(3S zY^yUzyWt3SJ)5-eME9=EIwjtj7z59qDMGY8cVo=8$|C4GZB_h!=Zb4}fYMif^>PY5 z^!WqVsGQ)g1s|!)^(_zmWunYZe3t25a?qz*$9Rt{Y+JwxZJ8ODTjOi+u_R+A>ES#1 zwld$!`p9hT!znam1}mz{XjT8~oHHCYLiRe*Jbz8^z<#^GC!Otwt=q`;|(N>gZ0a+TQ6O!=fa@4C|nBt%!a)X@{J{0n$+ zg-udIX3?FP7AMtH6rqU??OQqB9vPf(XMhX+LCfVl!iaU5B@qbtj-_Ep-9HL zQxSpc?!Bf#MMVyH!csBOdS_ib4?mZ&NCv<^jVhb2$U-+u31Y$_sz@o>7V2M$ej6Im zk>+Q;JV?fL%$S^r=Hs8WQ`k@3YJ?L_0w&)?z!)SU8-bNMEK9-shQ0S32LEKKUoT493&;CGnzj9z<*^q@|fTL$fN?DYPiXOk7 z!llEcMIP1+U-a;qree6+`&+d@eY?;6{(fbXGCd;KV(O4ChrXwhBe-!mzuIl?CDr5` zguByoX*lIqT^VY+NV?`D{W{;qq^oq<@;RrGBe-U><$#yTzGMll_Z6)>ObS4b@_t%U=3zI*jiJ z_;}1xot)=F6aNE|tiSzrqCnWy807#+_g_o}xE0_Mq|2n>j$*a{aRQnbFiKnVl7^E& z0&etg<+XGE{n*`BqcZ*VI{*Cy5ClZv8}zZkjNpIcGr+tk*vEx>d#q1;p6Z{QZ@Pdk zzn$tk-0vU*2<m)j$*_pRTzBaxx)$?h;jI}dhC@WenZ z3(!@xGA>#cNXM8W^Hb+GIzRp1^;$1HEq6q#~Oj7ku~@{MmjnZAVv&mb?MKcb(2Rq zRPnSP*J|2kv;PYwGyF)LMcTA{Cj&?1X@HS>xKwp#SKq0?lAqi$rx8IskCd-lPBNdU zO&Kk_RsO#tGB)mii0q1o7>%HMxeY<{cGPp^RqZnGt6vI`ldL`VZ)YT&Gvhl%@#2kv z-JcM(xx3(-Et7|PX`?PPsgI-H7wu7qLxI|10PiFp%cFZ5V+(h{o7>P40Pp1ZF1LE1 zgzYE#6nB_tJQ9vC!%E)rL=T6AtFAN=EJm0_diXbKY=pc<7YBnC;U;4YBk7tXORZyh zsiFD^yglk=eR0=QCJx2Nl(NXL`+($`=h}9)@aE01qIqD$@8mo?kI^$yo)=HsRTkP6 zih7h1K#e_h^Y3;}Z+x(%p6U9WA}sTPmV4XB{lTqLm3}P7c=?#Chk4 zxw~3zfaif(_UMcEJbAJvVtkcW@32brO9{T;JCxw$Vd{@IxQ;if(5TQH!gIuEngGTX z?MT8-qDmcnE8`dvw^E?p+_IhBIp86C$5*mq5MPDIN;Aa9wUOM-|ET+Jr>5rK_3p@0 zHAhq*^3S;5+bhMO2>8Cn5yJUX>mT}~$W8-CYw6Gm6q_j$jy=gno1rlpLm#@T97Y>a zI%kCGTA79o3A;sX>RxMFB;O^xC#T`?Si{KSS~7^GXHTdg4U{qQR%J$x^dd*|cs+-O zKVNN^PTzm{ua(GG;r5%*vL8ifnd@dxc@20OR_afrbH{H5XtW?yUhYR9vw0S>v$@|8 z!nxo>tp8;1IYVD-z{jFrK>LUB7XD$pVd{{=3-#-}V%C+Z)R_p}t&~|0S^a*UUncfx zRK16OUdxYf%;&4E$e+QqYHCC1Qo9{vtRh3OMy`E?b-#?5qaz0P9J*~&m-^^pOwOXr zBV)tT>{bh~pPAv7n|0|5r}Qk7eH%o^FLCJ27kV*aJ?)qi3f8+_cl{|8X4+djQidxq z*c%Ot^g{LwM`E=WF!NfK!IhnRpFW*)97hccryos3!29i-q2yw!Ee^Rh3`MO8A3w0ywtm;WM%9wFdtjH$Ze4m`#^8C|5*%<6 z*cNi6In%;)a=1`)d=8@W6>zP`*32C0x?c&Ds|eepYI&Q#VnRy*0)gKW~t}h^QnkKyN@-)-C zT*@?I)=)N>XJ@Bv9H7ejB#U+XxiRYHhdyZ!kKqcha5v^C+&_%o3GCUBuYaie%-td#hV+ zZru9#U4BrK3Nga)>(nNIiYP3G$W(w7lfRsFoc26k+y{fcmS zC}le#XRk5b>+etGQz1G*;(1RyOG>=KsV%lwom`wL;bT44HPl2(_y#oOnahYRa2Y&T z!E_+((=TkAt>(;V5gV9*v}4{;a{58n^ue@S!Ir*-%SbX-e1sad&S_TA;@NqyZOSd# zW|7XU8yt=pc@{uFNS$8iT2O=BSom+~rLH&Nl!uJ4IuM3VmZz#GSgKu~o1Sw!F@f2* za<007)?|i18ZP&x5G($^(vX0Toh0YN-*+j1b4drQpKtEEdApWArn6(EZa|9C24}Fl z3yh&sd{Xv|o^pd3g0o6t59MH|#(-Y)EqhD66|$R%&X60e`5q;VE>~*?9VJuZe3omJ z@}3Wil}ij^(rLr0u1pmL+x4EfWNR_k6+&E~t?ePQx9W=f^Y-)Si#5*9{jxZBA?6ca zyuC)SEajJUCYcu??hM=4Be3k29p$r;CvG5xYlmE}fa>78u1>Yu2(V?+yZJ#@dwN+$ z1%dv*7#7CH{9Hz>wOeL{4!7NAcgqt30-}FMEz3xL7+W*UW>yQZPIF!H7zo%yMc=$x zv+JCz1O13VabV8JrEslfUq0TfFvM-g!j8Vtm4T%1mqtVF?8MEvn8n~rj@}AE@v0LR zA>Pv6R1Y>5<~Gf-M%H3KSZNvewj1<{eZs+|i#!CQ=yTRb&e4UH&371{a*Snqe9_b>wfd?)l;`VPr=$ke{EQ*XA0d zijsnW2sbc5sNPY0CY)V6I|Sz;uzF5*!o+y1XTb?I#3FfN-E3w@jaXP8_-F9~>{}HH zZ&p4HB}uJ_2u33BW`ts7X|{aJtqI$D77B@uqWn{UVLsv!unrF=5Q?#3-*p{RLq|mj4ODOwkYfcynf_ z@Lqj?LHN?l_M!^Rp>8cB-uB17_~_T=Ifn52q~2!hUApyP*7*SS4{L4aZ;{*?A^J;s z@Q!atg^p!o*2QbIn14Yye$(S2NdGGUmO(k@WgRYTtNmlfLhX;3v{-9UR#{x$XjNUp zMACU_1A12#SJd&^(DsnE52tKLL|Nz-?ill~+q|QNW{Y2u=esoBI%_+O2F&*zWsk5yLa_K* zyqid=dfTyZOHeaLb#@FK;tVye^rM)8wBm(G&CFTrArt-mlCAv-X{AE(n31J?$FU~S zqh7-NN)Sd^|mJ?FM{P;32PHnGgj1%>r7wch)%wkH|)EN;W2{bP(5ZW8xKAmsG){E(bZlC22~QB2yr?+~Dw4F3t)wqySR*;T54A-l)|PVtUC za*cNl`~c57wSIlLILRrxeCTDoh)qA!e1pLfNs$G45^A1&{ZgWhig~l-A%(?qP^^vA z+b}lf;I9_YS~!lIlBJf2sc~=ygdrVQI43-X(1oLNDhE@~mukftvSkt;nQ+?RyWfzU zbb2@qgMwKn@NS&Sj67QF_Lr@#SN{yN*s4!@|AW<~vl%_9WupHh~RS{e28c4;kB&5D2zmFAQ=RiI>P%~Jj z@3U^iF-KS!?)Dg{yPY$m3RmcVlDi@nQ0;h{uI)>s+&f@5c8eFncLA^}`deEZz@+;F z5U)Q=3b6RZIK-i64PZ*#%m19pdv_^&(%{6Ui`x@RM2jUB4wISG%*s4sP@`ttJt7>* zYdMWGRQr)d>QAB;1_7JYTk*+X5Hc*%G;+_3La;D2geYu8r(~GC)qlKK(nUodN|kbq zURj=1$EzGx=)Sm}OPV*PQQUDGq3HVr(alwCx7X%K?1PlXD0KPkIpQ&|il|AOscWW2 zBy2XVHMZWKc&qJus*9V>^}^}6V1voeFl`b=A-}&N!c=gwl`n}QT9@>g9x&%a=ir7Xj7@- zTwoyneBrHuJ1|9c!19^rSd2N|aPi07yj%Wol?rPn2wnu5yd-(h5M#t$E~={VPeeM3 zFkM7iG?o#!)>2RZ8*5#~3V?o-=wa`=I;9IlpXW@sKh$^%!&((QyL)fb9o{G@DaC*~ zZ%_P<;I-Dy3P<6w22D5D72)iVNGhL9@rP=)3>6VE(wj^tm;Z<0d834Q&v?OsUdQNv z>HFFO>5zuxgyJr3#x^1s~V|Fn8tav(ya z;{N>-Re;NzH|2Tuv$`&h1=H9g%L5=Fc+++)_F!L5PPvYV&)|zE^$ytE*i7zNZ;0|K zB6TEX`Tfh^F)iNL0-b29r`+q~*L!z`g_vLvz}FGM!$Q=e$h#`-W;cyDp#V4%~_Gp{4sYEjw=dQe=)Z_oA zB&f|pL|Czcib%2iprTB3QcVD6pVXGQeb%3Oo?LD<1Nc(=QBq6j$}8X7G_B%K_+=<+ zi{RM+ZxV)Y(ubw1To>=Q90Zkm{jnSoEi=zcz&tiyMRr^L<21hMQfuHSTLJVc$q6nA zbizY!?F1_Lh$1Yp7aCyAL>9EX9m>SBySP^7mRAbB4C@4!shK|W z72Zo=q3DmJqcP5B&2!QW!w3_vf71?>GmB8^=i%#%L1@QL2%bc75;^IoYv;0ss6#d- z*x{>;DB3Y!<*5(f>p0&!8B^~t3AE@YuHI(XPl+VftTeg1>17U5EMlL^OVSO@NIl&$ zAbx-h20zoXC6%JY=P!ehbfOlQuX0D(CNW{{DMlp~31N;8EF`O2WrAI0Z@J&SibpR` zjX30R5Vg{6n-(uhts<50olppmEltQ@-~aJi_YgD6@KDC!w|i12ek!8rmnn@pjn&DP zciM<9r1$*(lz^dPZ7~{$9-`yhUG_HuV-8sipbmKRXFDR+SL)zSa9;%{+#F3u)1`2M zw^_##hu|bl-B}fLQdIh;eCjDHEemJlzmHBYo65GFDT3NlDsnQ<5V041R+HY+V#PI&$H*xAqzS^6)*u_Z z*RL^59GL@mtmrwQp&GqO8%ZKB$DtV7x?Q_WC)4kp(4fpTsu3sls+dN)7w~m$--%^K z<6s%z9!A6&_wWzEClPTKQ^F1xE+$&67N%>cIiLlwXeAQQOE=LL8tAKA5j&r{peht- z7(NJpmw?xOQ^IHJ2{9SHvdfaUgo=;W zX@%b!v*4Mo;(o5XBybEbZ1-JcOxZ0`JDB$sRY(R6VTy`(fp&05Gpz*T=NAYrNuaLx zwpZrRN*JzhxA{MEcw7|HgbO-Eerlp9tBP=&oS|5VeY3|C35s)Bgte!{Zy6WRM;Y=k zd}(iZL&d_);6PvG9JYsIeA;id3*0ZB<~f;)!rSS1UWbI+90!EuJvBX zmW%jVl*b5NHKkly9mYl5_fty{8JF0scONEZb=9)D8s5!Tv>ILF<4}yl|FV0zgbOYQ zWX16%esT#@Fa=iZv)9?e^1HsW2T*{6IDyoY+TpXu!T%ojfr)pANxCfcx=m-Dn@Z?v zx~o6Y?-Fi6K%Q}g;Nn37OeHY>28AqDD+tADg9EE0QOm`tl#8|cWoW3*!@f0^4{haG z^soi*sqDFMuVl)at#3Vhx{%(Zv85;KL5k4&SE!xlj-Z-J7>jBpkJshUf-_cyK|Z+a zK{T24)E6@_1LRFW^z$up<>-Ls^V+8*igEW3;?nB0rElj@iANFZg=p^$w=y`64Rr}| z!x-t{&JH@ZK8jr1MKoF_i-te7S#PemK|w)xughf^$oFArgj{_8MZ@?1MZ*?J8xi(^ zbOnJxHqkoHJfB zs}97SGElDIX2;_K`12@=6)QQ_VV;7!x@ajZXqI>cv>Bt1s-&< z@K~PJ1Ul=*QrYRzOrs4@v7NGTV2wEj`BBF~!q|$Nzs<`B8rEyAZF--oqI zNxEwI92n0b6@@cW7v$!({4$mLW0oU`&7%olAL*WN(gX*Xukg>*^~&PS{H?uw^&+Q zku+~4w}oP3|6f~Y9TmsYEO3H`;FjPH!C43{fn{-r#hqZmJ-7sy;1Xc5 z009Dl1p+MYaB&S17T4hJ5Z)&De&4(2oj3o^oH|uCQ{DaRs;Q3q;A?x;@0&e#pMoiE zxx{C?w9oR9-w{_!;Gnt@W`8M}f^8SDr2=uCJRC69|A#~OuTyU_ts1L6GnC;jS$sKL z9?_-=?3(Nt4`|T{4z;fB?Nh|^;e3}|1_6ndQdC6CL_I27rF@EkM4k`LpB3Z4{ZR^Q zKBdf-w$nchSMUGQgD_8DezVvEy8oQF0u0blv?%OaPjkC9TVabaa(jZ9(sF9She{Dg zS)C-r_f1Me9~0JH8}pJsuMY(!!okyqrzc5wz@=-uGM(RE7egkWLC(_po%-NFZfk4% z35Pk4CMC2!A3qUC^a`GC0l0Ue`cKuD-AC!ah_ZbUH7C6>DmORD$3+!ZRVtHB^`)wQ~@;X|4s20;Vlcf zY;zG6px**iIRZ%K$~_~RMOEfLl3|~(Lgp+(A~pgF@Rp0lr^5X1JA?K8Z;unf8pN!} z4UW8$B^DIy2Q~LX_->X^Bg<2yXV*s%|iRjW^ib zLNHZ;Fka>$B7502Wm-hxDPnZit(scmOLEWddO)R0ESNe8ADQ@}e{xaFqKswzRaFfO z_DzPql_X=35iV?Puul_4+4ZFXrvAml1aX93At>~h(5w$ivTjfoP@($GOVvL}wF*>w zL_#9CR*(j21(Q9wbfx7bJswHe(i%_UyT&UsPdW`LI2S0Uj_3c1O=>!NOYu7N^|1el zKaf7!4za(9@?;NwwXG4la-)vQK?A6Q`b8i6(yd6wyhCS5Xnb!uF*K-H{F!%#t-*-# zbQ$gKe9BEU`+Ji+Pcu9C{!O{ZpMOoBqH3X1+L?n@eX9;u-lu8uTFdm(zE;31X_3)b zu?i|N=~YC$p)q^}GD?5|d8s7e`l+d@8)kBybk+p{0fGDLq88MLy#&b{>LA*isqm`9YupRZ4fcC+*{3^ye>s1Nwi`+E85NwYp&LYUl^q+d-W-^w{Vql$4a$JWNdC zG@QmNCIwLicK;_mT_P>1*N{ipQNlW!x@&o>E|n|hGu|E)|(wn zPzXuPet_7HXd#MS|CK|h-KL}ESm3T!%jg>Uy0GtkvL@rPH-n>FX|zg+sdS~ZPpVP( zN5ShLzinh4?X=z#iIb+m@L<$VjJLs14Ge#Km4eTuna|iZ46_wVq}|B}c$8l8v-_(k zrxw{pF^jYzO_0U$oFt_tJ$uI1rv5~O+N~4I=r8>{qr-5&){l|W<5ilbkS-K4XPkzhkfJz19 z9GarJABZAkTn^jKcS-w@L-}FBbz3D~v~4#xPAU+=Xx|qCs_EBZ%+IyRq0df~n$!bn z12y^X<+AwBg!tF|nW)aH0_XH7%L@ZvynaM!`YH@os6>X`>Cy6iY0z9sFfpd>m-jKv09sJ&aAtH`aD@$`Rv5cAeTV!)}21KD>l%}~4@FoV2;rS=SY_7gT^q$7aM?{p-6pD2=^NH~V@W0}r0;?Wv zO(P?PZ~_$PFEN&c$?ck+fn!vvPbBdR)$}}_)@Li>x<%msof(IQha;)Ro zHaBmy1NB$4w))y#8BU7++;J)&N?x?7eqZ4KlDcfevW3RfH89!WzkN!7L3to|u4u}S z@mMGSYPS(4hb1Q}HZ_3(US@uxK*j>-Xb$rpV>gu$520rl$SgCQYqTs&hgsv0nZo)m zwh90KLcFsPfsydac08NQ_-A@+9e>Zw`OefNI|^7+bG%RvZzo`JjXz{f&Yv(h;pIy+ zkP6nb!%si^c>MYN`2iNF3nMWu;;Tx^`mQhJz|hsPoC^H*eiV008aikLarBwy$s|Sd zaqxUP>*UGBJ(AG@3{7`Hscr2SAvSh=61J*}{%!tx!|j3AoDFptqOUutH1$Qxnh_PKVVR?J1M zRNhqyoAgkySJ@kprXNCLb%7KFI{*+=!l~PFa`ScqUwYU$^qb{4#8PI;yQKRtmZ-nK zHKBZmeTA-2*R1T2fy<8ixhYM2>Ym1R>pi(n15V$>r$~8O9xh5>vTuOS(mP#%0ub!*V?7Zt&X(O{q&Rc8Hru*X zVwC*~yUZY13q#pp8f$dN%8Pp!sX(%)19Mj8`7^pndZNy)RK|}(^|(IlCnn;5pb~vf zMn)DDAKzDP@mH127?Erz}Mk6hIns zU)0r`C9f3}@5b7Yg?)0|NX@<<4|;7I;?g~osF%wjn)s{(p+l!cdK=r(&o`Lz#2!7( z{&K7J`J24*=pzi^?@ANZ(@xR{3@+40F1tq3sy>;ik^fJ>tsz0x0 z5Y9HHG%My^I6|>Im~5e)&=~q?tVN<9dI>qDZ z?|o*?tBYF6th8UA)4)2)1K5ibf#NBgWqXYd4O%rx#TC`6+J-iXOj>B#gXr@A+k zYtb<|@mG+{>j@hIt>HKf_jj~P?xEfCrkeE`g+E;9#QbQpbDHx}s%@=>2*bo@y6==`Xw!>#02M&|ZVN4dup3vdS9Q4ZA(9P7Ioph* zO6tpM|G($J;B>@LVnB@JNB7}?)3Cl{WCX{e-^FgK80X#LLiE-MqGJc>`4-(I0nIMO%)Xt_51Hby68j-7ldZ4K^k8}L_+4Ipu^tnhrd=EQb|Kq zKk9sHFR$CcLANBm*a^s<7sSwgpkl8rYZ&C< zk$aIR7`*-p;Pzbz`^JMedvjMMx>P&+6wSf7dEKVLVh-QgW7@k-N# zcZ7X+x2p$4h^FqeoXR3aDn(0SWQMTt-h0Vn)VQEOA#MjmOw9%zWze!NZ(J-a5LY;H zwy--o3OaT$3LPaI6JrH$XB`(k246`{k8Ft#oPbIXMWS>an#PzQG!4k+HTu zKY1<5U&GH?HxK2CC&?dPDtC{paJ#C;+-a|@+%^V3GI|sr$7fNhO?3Mumxx&lSsVqesnGf)j?lG#;S?=a_r`*kdi#Q~QFM&IGLIU>E7-@crG-^Q zsc6WfdugB23^=R+Tb~n?2{h-q9w<=6IlDHA&9u>q6Hu(gZLJnISLr=JrDUl?=ebzziR$N!Y94z$ zd1m%5yy!w%;7oDm&zwEco^8p3#-@M8@RUQ@`ukVzuDl%*l)7SZNg|q9oR^(rh{>mt z&dGk=ShdVwJT)P2d2*E_ySm?|eSK%CHm8yKZ4V;E-K7`y((pi?^JtW6D5ajxE25;R zIc3(Ph3w`PvzUE!q*t2^RP~)^U|xQxUgPrEigmG3qKB^~9M2xF#gKKV!9Sx8)Dc5) z?OlrXm0jGw%yz-IhtT0!lWg_nOfs$`=v>?yNNSz<{@Hyep)V{@D3GAcR zD%=M{{q8S&a#dyY5r#sUG-*eu7u)jA`nFn}5@5=>OI4uHj75uaHSGnGQ3!_O8T|}o zdDd1-|10cFZ?j%=a$-JWW-xxJ)NV10C55L^%_f^Q=qZdZ0PEJzan>oOQra_OyI66i zEw?_~@(=m&BQu}tpTs;Cs5qYE2${S$ZgG|Fv0QHT(~TKQAKIMMC!M3Frq*k4p`&MD zARr=Q5SM1fb|cU{{SH>K&m*R$j*kW-Q@GUsOmCI~E{Vo;a3x%cD;?QhJ|6iNjUEQy z`!j72msdC+i4|8pJQQVOnHZa>SMI80%l7p&`Usfy2vX|0iKUh09#O z1K{mpSSRNaAN>cX6E#!sW|^N+^2^O$cx-8kG3!nE`dO&?| zoltD;Q%(YBMuG^~afrQ?LYVo|_b!E9f}lm|Soq=nELbpNA?qJiB#G!cm_ZB~Z_OQI zLGI5Z>HzgJ*HL|EoY<}c^%R|!)zAK=btx0V3-*{_+sd&D4bK=pIE;Ma>EquiewR-1 zxF!b%b*@|eVd&pR23nwI&FpanTBLOE^8RD>AAr8U#H@;JP8u}_U%eHav^B5$4_PC8 zqi&D9zgo%9>-4|8{l{Z=s)#u!>)Tq^zm!1;%b)qZ*!=$?%h>TnaL( K(v?zXA^!tBD_#Hq diff --git a/docs/XcodeOtherLinkerFlags_normal.png b/docs/XcodeOtherLinkerFlags_normal.png deleted file mode 100644 index f210ccfa8a7dd2404078a09bda63a84840b3cf48..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 67418 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

-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 Date: Wed, 31 Oct 2012 08:54:54 +0100 Subject: [PATCH 096/176] Prepare pod spec to 3.0 release --- HockeySDK.podspec | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/HockeySDK.podspec b/HockeySDK.podspec index b9600f43..a8e04358 100644 --- a/HockeySDK.podspec +++ b/HockeySDK.podspec @@ -1,25 +1,25 @@ Pod::Spec.new do |s| s.name = 'HockeySDK' - s.version = '2.5.5' + s.version = '3.0.0' s.license = 'MIT' - s.platform = :ios, '4.0' + s.platform = :ios, '5.0' s.summary = 'Distribute beta apps and collect crash reports with HockeyApp.' s.homepage = 'http://hockeyapp.net/' s.author = { 'Andreas Linde' => 'mail@andreaslinde.de', 'Thomas Dohmke' => "thomas@dohmke.de" } - s.source = { :git => 'https://github.com/bitstadium/HockeySDK-iOS.git', :tag => '2.5.5' } + s.source = { :git => 'https://github.com/bitstadium/HockeySDK-iOS.git', :tag => '3.0.0' } - s.description = 'HockeyApp is a server to distribute beta apps and collect crash reports. ' \ + s.description = 'HockeyApp is a server to distribute beta apps, collect crash reports and ' \ + 'communicate with your app users.' \ 'It improves the testing process dramatically and can be used for both beta ' \ - 'and App Store builds. Only beta builds will notify users about a new version ' \ - 'NOTE: You will need to add a dependency on JSONKit, SBJson or YAJL yourself. If you ' \ - 'want the framework to try again when a network is available, add a dependency ' \ + 'and App Store builds. Only beta builds will notify users about a new version. ' \ + 'NOTE: If you want the framework to try again when a network is available, add a dependency ' \ 'on Reachability and send a notification with the name `BITHockeyNetworkDidBecomeReachable` ' \ 'yourself when the network becomse reachable.' s.source_files = 'Classes' - s.requires_arc = false + s.requires_arc = true s.preserve_paths = 'Resources', 'Support', 'Vendor' - s.frameworks = 'QuartzCore', 'SystemConfiguration', 'CrashReporter', 'CoreGraphics', 'UIKit' + s.frameworks = 'CoreText', 'QuartzCore', 'SystemConfiguration', 'CrashReporter', 'CoreGraphics', 'UIKit' s.xcconfig = { 'FRAMEWORK_SEARCH_PATHS' => '"$(PODS_ROOT)/HockeySDK/Vendor"', 'GCC_PREPROCESSOR_DEFINITIONS' => %{BITHOCKEY_VERSION="@\\"#{s.version}\\""} } From 460e6eef46d562e6a66ba8fe30802060e759d178 Mon Sep 17 00:00:00 2001 From: Andreas Linde Date: Wed, 31 Oct 2012 08:57:28 +0100 Subject: [PATCH 097/176] Documentation updates --- Classes/BITFeedbackComposeViewController.h | 2 ++ Classes/BITFeedbackManager.h | 2 +- Classes/BITHockeyBaseManager.h | 4 ++++ 3 files changed, 7 insertions(+), 1 deletion(-) diff --git a/Classes/BITFeedbackComposeViewController.h b/Classes/BITFeedbackComposeViewController.h index 674ccb10..fe393cad 100644 --- a/Classes/BITFeedbackComposeViewController.h +++ b/Classes/BITFeedbackComposeViewController.h @@ -66,6 +66,8 @@ - NSURL These are automatically concatenated to one text string. + + @param items Array of data objects to prefill the feedback text message. */ - (void)prepareWithItems:(NSArray *)items; diff --git a/Classes/BITFeedbackManager.h b/Classes/BITFeedbackManager.h index a7afd0ca..5dbc5e99 100644 --- a/Classes/BITFeedbackManager.h +++ b/Classes/BITFeedbackManager.h @@ -189,7 +189,7 @@ typedef enum { @[@"Adding some example default text and also adding a link.", [NSURL URLWithString:@"http://hockeayyp.net/"]]]; - UINavigationController *navController = [[[UINavigationController alloc] initWithRootViewController:feedbackCompose] autorelease]; + UINavigationController *navController = [[UINavigationController alloc] initWithRootViewController:feedbackCompose]; navController.modalPresentationStyle = UIModalPresentationFormSheet; [self presentViewController:navController animated:YES completion:nil]; diff --git a/Classes/BITHockeyBaseManager.h b/Classes/BITHockeyBaseManager.h index 31a008d2..47950b90 100644 --- a/Classes/BITHockeyBaseManager.h +++ b/Classes/BITHockeyBaseManager.h @@ -10,6 +10,10 @@ #import +/** + The internal superclass for all component managers + + */ @interface BITHockeyBaseManager : NSObject From 154ef723f3725f0dff72b30bb3e16661d6cf095e Mon Sep 17 00:00:00 2001 From: Andreas Linde Date: Wed, 31 Oct 2012 17:54:38 +0100 Subject: [PATCH 098/176] Fix build script to include headers into the embedded framework and the readme --- Support/HockeySDK.xcodeproj/project.pbxproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Support/HockeySDK.xcodeproj/project.pbxproj b/Support/HockeySDK.xcodeproj/project.pbxproj index a4266d84..404f09ff 100644 --- a/Support/HockeySDK.xcodeproj/project.pbxproj +++ b/Support/HockeySDK.xcodeproj/project.pbxproj @@ -561,7 +561,7 @@ ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "# Sets the target folders and the final framework product.\nFMK_NAME=HockeySDK\nFMK_VERSION=A\nFMK_RESOURCE_BUNDLE=HockeySDKResources\n\n# Documentation\nHOCKEYSDK_DOCSET_VERSION_NAME=\"de.bitstadium.${HOCKEYSDK_DOCSET_NAME}-${VERSION_STRING}\"\n\n# Install dir will be the final output to the framework.\n# The following line create it in the root folder of the current project.\nPRODUCTS_DIR=${SRCROOT}/../Products\nTEMP_DIR=${PRODUCTS_DIR}/Temp\nINSTALL_DIR=${TEMP_DIR}/${FMK_NAME}.framework\n\n# Working dir will be deleted after the framework creation.\nWRK_DIR=build\nDEVICE_DIR=${WRK_DIR}/Release-iphoneos\nSIMULATOR_DIR=${WRK_DIR}/Release-iphonesimulator\nHEADERS_DIR=${WRK_DIR}/Release-iphoneos/usr/local/include\n\n# Building both architectures.\nxcodebuild -project \"HockeySDK.xcodeproj\" -configuration \"Release\" -target \"${FMK_NAME}\" -sdk iphoneos\nxcodebuild -project \"HockeySDK.xcodeproj\" -configuration \"Release\" -target \"${FMK_NAME}\" -sdk iphonesimulator\n\n# Cleaning the oldest.\nif [ -d \"${TEMP_DIR}\" ]\nthen\nrm -rf \"${TEMP_DIR}\"\nfi\n\n# Creates and renews the final product folder.\nmkdir -p \"${INSTALL_DIR}\"\nmkdir -p \"${INSTALL_DIR}/Versions\"\nmkdir -p \"${INSTALL_DIR}/Versions/${FMK_VERSION}\"\nmkdir -p \"${INSTALL_DIR}/Versions/${FMK_VERSION}/Resources\"\nmkdir -p \"${INSTALL_DIR}/Versions/${FMK_VERSION}/Headers\"\n\n# Creates the internal links.\n# It MUST uses relative path, otherwise will not work when the folder is copied/moved.\nln -s \"${FMK_VERSION}\" \"${INSTALL_DIR}/Versions/Current\"\nln -s \"Versions/Current/Headers\" \"${INSTALL_DIR}/Headers\"\nln -s \"Versions/Current/Resources\" \"${INSTALL_DIR}/Resources\"\nln -s \"Versions/Current/${FMK_NAME}\" \"${INSTALL_DIR}/${FMK_NAME}\"\n\n# Copies the headers and resources files to the final product folder.\ncp -R \"${HEADERS_DIR}/\" \"${INSTALL_DIR}/Versions/${FMK_VERSION}/Headers/\"\ncp -R \"${DEVICE_DIR}/${FMK_RESOURCE_BUNDLE}.bundle\" \"${INSTALL_DIR}/Versions/${FMK_VERSION}/Resources/\"\ncp -f \"${SRCROOT}/${FMK_NAME}.xcconfig\" \"${INSTALL_DIR}/Versions/${FMK_VERSION}/Resources/\"\n\n# Uses the Lipo Tool to merge both binary files (i386 + armv6/armv7) into one Universal final product.\nlipo -create \"${DEVICE_DIR}/lib${FMK_NAME}.a\" \"${SIMULATOR_DIR}/lib${FMK_NAME}.a\" -output \"${INSTALL_DIR}/Versions/${FMK_VERSION}/${FMK_NAME}\"\n\n# Combine the CrashReporter static library into a new Hockey static library file if they are not already present and copy the public headers too\nif [ -z $(otool -L \"${INSTALL_DIR}/Versions/${FMK_VERSION}/${FMK_NAME}\" | grep 'libCrashReporter') ]\nthen\nlibtool -static -o \"${INSTALL_DIR}/Versions/${FMK_VERSION}/${FMK_NAME}\" \"${INSTALL_DIR}/Versions/${FMK_VERSION}/${FMK_NAME}\" \"${SRCROOT}/../Vendor/CrashReporter.framework/Versions/A/CrashReporter\"\nfi\n\nrm -r \"${WRK_DIR}\"\n\n# build embeddedframework folder and move framework into it\nmkdir \"${INSTALL_DIR}/../${FMK_NAME}.embeddedframework\"\nmv \"${INSTALL_DIR}\" \"${INSTALL_DIR}/../${FMK_NAME}.embeddedframework/${FMK_NAME}.framework\"\n\n# link Resources\nNEW_INSTALL_DIR=${TEMP_DIR}/${FMK_NAME}.embeddedframework\nmkdir \"${NEW_INSTALL_DIR}/Resources\"\nln -s \"../${FMK_NAME}.framework/Resources/${FMK_RESOURCE_BUNDLE}.bundle\" \"${NEW_INSTALL_DIR}/Resources/${FMK_RESOURCE_BUNDLE}.bundle\"\nln -s \"../${FMK_NAME}.framework/Resources/${FMK_NAME}.xcconfig\" \"${NEW_INSTALL_DIR}/Resources/${FMK_NAME}.xcconfig\"\n\n# copy license, changelog, documentation\ncp -f \"${SRCROOT}/../Docs/Changelog-template.md\" \"${TEMP_DIR}/CHANGELOG\"\ncp -f \"${SRCROOT}/../LICENSE\" \"${TEMP_DIR}\"\nmkdir \"${TEMP_DIR}/${HOCKEYSDK_DOCSET_VERSION_NAME}.docset\"\ncp -R \"${SRCROOT}/../documentation/docset/Contents\" \"${TEMP_DIR}/${HOCKEYSDK_DOCSET_VERSION_NAME}.docset\"\n\n# build zip\ncd \"${PRODUCTS_DIR}\"\nrm -f \"${FMK_NAME}-iOS-${VERSION_STRING}.zip\"\ncd \"${TEMP_DIR}\"\nzip -yr \"../${FMK_NAME}-iOS-${VERSION_STRING}.zip\" \"./${FMK_NAME}.embeddedframework\" \"./CHANGELOG\" \"./LICENSE\" \"./${HOCKEYSDK_DOCSET_VERSION_NAME}.docset\" -x \\*/.*\n"; + shellScript = "# Sets the target folders and the final framework product.\nFMK_NAME=HockeySDK\nFMK_VERSION=A\nFMK_RESOURCE_BUNDLE=HockeySDKResources\n\n# Documentation\nHOCKEYSDK_DOCSET_VERSION_NAME=\"de.bitstadium.${HOCKEYSDK_DOCSET_NAME}-${VERSION_STRING}\"\n\n# Install dir will be the final output to the framework.\n# The following line create it in the root folder of the current project.\nPRODUCTS_DIR=${SRCROOT}/../Products\nTEMP_DIR=${PRODUCTS_DIR}/Temp\nINSTALL_DIR=${TEMP_DIR}/${FMK_NAME}.framework\n\n# Working dir will be deleted after the framework creation.\nWRK_DIR=build\nDEVICE_DIR=${WRK_DIR}/Release-iphoneos\nSIMULATOR_DIR=${WRK_DIR}/Release-iphonesimulator\nHEADERS_DIR=${WRK_DIR}/Release-iphoneos/usr/local/include\n\n# Building both architectures.\nxcodebuild -project \"HockeySDK.xcodeproj\" -configuration \"Release\" -target \"${FMK_NAME}\" -sdk iphoneos\nxcodebuild -project \"HockeySDK.xcodeproj\" -configuration \"Release\" -target \"${FMK_NAME}\" -sdk iphonesimulator\n\n# Cleaning the oldest.\nif [ -d \"${TEMP_DIR}\" ]\nthen\nrm -rf \"${TEMP_DIR}\"\nfi\n\n# Creates and renews the final product folder.\nmkdir -p \"${INSTALL_DIR}\"\nmkdir -p \"${INSTALL_DIR}/Versions\"\nmkdir -p \"${INSTALL_DIR}/Versions/${FMK_VERSION}\"\nmkdir -p \"${INSTALL_DIR}/Versions/${FMK_VERSION}/Resources\"\nmkdir -p \"${INSTALL_DIR}/Versions/${FMK_VERSION}/Headers\"\n\n# Creates the internal links.\n# It MUST uses relative path, otherwise will not work when the folder is copied/moved.\nln -s \"${FMK_VERSION}\" \"${INSTALL_DIR}/Versions/Current\"\nln -s \"Versions/Current/Headers\" \"${INSTALL_DIR}/Headers\"\nln -s \"Versions/Current/Resources\" \"${INSTALL_DIR}/Resources\"\nln -s \"Versions/Current/${FMK_NAME}\" \"${INSTALL_DIR}/${FMK_NAME}\"\n\n# Copies the headers and resources files to the final product folder.\ncp -R \"${SRCROOT}/build/Release-iphoneos/include/HockeySDK/\" \"${INSTALL_DIR}/Versions/${FMK_VERSION}/Headers/\"\ncp -R \"${DEVICE_DIR}/${FMK_RESOURCE_BUNDLE}.bundle\" \"${INSTALL_DIR}/Versions/${FMK_VERSION}/Resources/\"\ncp -f \"${SRCROOT}/${FMK_NAME}.xcconfig\" \"${INSTALL_DIR}/Versions/${FMK_VERSION}/Resources/\"\n\n# Uses the Lipo Tool to merge both binary files (i386 + armv6/armv7) into one Universal final product.\nlipo -create \"${DEVICE_DIR}/lib${FMK_NAME}.a\" \"${SIMULATOR_DIR}/lib${FMK_NAME}.a\" -output \"${INSTALL_DIR}/Versions/${FMK_VERSION}/${FMK_NAME}\"\n\n# Combine the CrashReporter static library into a new Hockey static library file if they are not already present and copy the public headers too\nif [ -z $(otool -L \"${INSTALL_DIR}/Versions/${FMK_VERSION}/${FMK_NAME}\" | grep 'libCrashReporter') ]\nthen\nlibtool -static -o \"${INSTALL_DIR}/Versions/${FMK_VERSION}/${FMK_NAME}\" \"${INSTALL_DIR}/Versions/${FMK_VERSION}/${FMK_NAME}\" \"${SRCROOT}/../Vendor/CrashReporter.framework/Versions/A/CrashReporter\"\nfi\n\nrm -r \"${WRK_DIR}\"\n\n# build embeddedframework folder and move framework into it\nmkdir \"${INSTALL_DIR}/../${FMK_NAME}.embeddedframework\"\nmv \"${INSTALL_DIR}\" \"${INSTALL_DIR}/../${FMK_NAME}.embeddedframework/${FMK_NAME}.framework\"\n\n# link Resources\nNEW_INSTALL_DIR=${TEMP_DIR}/${FMK_NAME}.embeddedframework\nmkdir \"${NEW_INSTALL_DIR}/Resources\"\nln -s \"../${FMK_NAME}.framework/Resources/${FMK_RESOURCE_BUNDLE}.bundle\" \"${NEW_INSTALL_DIR}/Resources/${FMK_RESOURCE_BUNDLE}.bundle\"\nln -s \"../${FMK_NAME}.framework/Resources/${FMK_NAME}.xcconfig\" \"${NEW_INSTALL_DIR}/Resources/${FMK_NAME}.xcconfig\"\n\n# copy license, changelog, documentation\ncp -f \"${SRCROOT}/../Docs/Changelog-template.md\" \"${TEMP_DIR}/CHANGELOG\"\ncp -f \"${SRCROOT}/../Docs/Guide-Installation-Setup-template.md\" \"${TEMP_DIR}/README.md\"\ncp -f \"${SRCROOT}/../LICENSE\" \"${TEMP_DIR}\"\nmkdir \"${TEMP_DIR}/${HOCKEYSDK_DOCSET_VERSION_NAME}.docset\"\ncp -R \"${SRCROOT}/../documentation/docset/Contents\" \"${TEMP_DIR}/${HOCKEYSDK_DOCSET_VERSION_NAME}.docset\"\n\n# build zip\ncd \"${PRODUCTS_DIR}\"\nrm -f \"${FMK_NAME}-iOS-${VERSION_STRING}.zip\"\ncd \"${TEMP_DIR}\"\nzip -yr \"../${FMK_NAME}-iOS-${VERSION_STRING}.zip\" \"./${FMK_NAME}.embeddedframework\" \"./CHANGELOG\" \"./README.md\" \"./LICENSE\" \"./${HOCKEYSDK_DOCSET_VERSION_NAME}.docset\" -x \\*/.*\n"; }; 1E8E66B215BC3D8200632A2E /* ShellScript */ = { isa = PBXShellScriptBuildPhase; From e638de5535de175bd46221a3f51c52b3a9773426 Mon Sep 17 00:00:00 2001 From: Andreas Linde Date: Wed, 31 Oct 2012 17:55:40 +0100 Subject: [PATCH 099/176] Bump SDK Version to 3.0.0 Beta 1 build 11 --- Support/buildnumber.xcconfig | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Support/buildnumber.xcconfig b/Support/buildnumber.xcconfig index 119cd859..b15ec4b7 100644 --- a/Support/buildnumber.xcconfig +++ b/Support/buildnumber.xcconfig @@ -1,5 +1,5 @@ #include "HockeySDK.xcconfig" -BUILD_NUMBER = 10 -VERSION_STRING = 3.0.0a1 -GCC_PREPROCESSOR_DEFINITIONS = $(inherited) BITHOCKEY_VERSION="@\"3.0.0a1\"" +BUILD_NUMBER = 11 +VERSION_STRING = 3.0.0b1 +GCC_PREPROCESSOR_DEFINITIONS = $(inherited) BITHOCKEY_VERSION="@\"3.0.0b1\"" From edf284bb35b03932083876c63c12dc3b62bd5fec Mon Sep 17 00:00:00 2001 From: Stephan Diederich Date: Sun, 4 Nov 2012 14:54:29 +0100 Subject: [PATCH 100/176] add missing newlines --- Classes/BITFeedbackComposeViewController.h | 2 +- Classes/BITFeedbackListViewController.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Classes/BITFeedbackComposeViewController.h b/Classes/BITFeedbackComposeViewController.h index fe393cad..ea9a1106 100644 --- a/Classes/BITFeedbackComposeViewController.h +++ b/Classes/BITFeedbackComposeViewController.h @@ -71,4 +71,4 @@ */ - (void)prepareWithItems:(NSArray *)items; -@end \ No newline at end of file +@end diff --git a/Classes/BITFeedbackListViewController.h b/Classes/BITFeedbackListViewController.h index 0af01569..49122898 100644 --- a/Classes/BITFeedbackListViewController.h +++ b/Classes/BITFeedbackListViewController.h @@ -46,4 +46,4 @@ @interface BITFeedbackListViewController : BITHockeyBaseViewController { } -@end \ No newline at end of file +@end From 5f1b1881a1435fe877743bcb23f90f64a609f004 Mon Sep 17 00:00:00 2001 From: Andreas Linde Date: Sun, 4 Nov 2012 23:43:36 +0100 Subject: [PATCH 101/176] Make Crash Reporting headers public *doh* --- Support/HockeySDK.xcodeproj/project.pbxproj | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Support/HockeySDK.xcodeproj/project.pbxproj b/Support/HockeySDK.xcodeproj/project.pbxproj index 404f09ff..92efd53e 100644 --- a/Support/HockeySDK.xcodeproj/project.pbxproj +++ b/Support/HockeySDK.xcodeproj/project.pbxproj @@ -86,9 +86,9 @@ 1E5955CF15B71C8600A03429 /* IconGradient.png in Resources */ = {isa = PBXBuildFile; fileRef = 1E5955C415B71C8600A03429 /* IconGradient.png */; }; 1E5955D015B71C8600A03429 /* IconGradient@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 1E5955C515B71C8600A03429 /* IconGradient@2x.png */; }; 1E5955FD15B7877B00A03429 /* BITHockeyManagerDelegate.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E5955FA15B7877A00A03429 /* BITHockeyManagerDelegate.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 1E754E5C1621FBB70070AB92 /* BITCrashManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E754E561621FBB70070AB92 /* BITCrashManager.h */; }; + 1E754E5C1621FBB70070AB92 /* BITCrashManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E754E561621FBB70070AB92 /* BITCrashManager.h */; settings = {ATTRIBUTES = (Public, ); }; }; 1E754E5D1621FBB70070AB92 /* BITCrashManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 1E754E571621FBB70070AB92 /* BITCrashManager.m */; }; - 1E754E5E1621FBB70070AB92 /* BITCrashManagerDelegate.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E754E581621FBB70070AB92 /* BITCrashManagerDelegate.h */; }; + 1E754E5E1621FBB70070AB92 /* BITCrashManagerDelegate.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E754E581621FBB70070AB92 /* BITCrashManagerDelegate.h */; settings = {ATTRIBUTES = (Public, ); }; }; 1E754E5F1621FBB70070AB92 /* BITCrashManagerPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E754E591621FBB70070AB92 /* BITCrashManagerPrivate.h */; }; 1E754E601621FBB70070AB92 /* BITCrashReportTextFormatter.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E754E5A1621FBB70070AB92 /* BITCrashReportTextFormatter.h */; }; 1E754E611621FBB70070AB92 /* BITCrashReportTextFormatter.m in Sources */ = {isa = PBXBuildFile; fileRef = 1E754E5B1621FBB70070AB92 /* BITCrashReportTextFormatter.m */; }; @@ -411,6 +411,8 @@ 1E59559B15B6FDA500A03429 /* HockeySDK.h in Headers */, 1E59559A15B6FDA500A03429 /* BITHockeyManager.h in Headers */, 1E5955FD15B7877B00A03429 /* BITHockeyManagerDelegate.h in Headers */, + 1E754E5C1621FBB70070AB92 /* BITCrashManager.h in Headers */, + 1E754E5E1621FBB70070AB92 /* BITCrashManagerDelegate.h in Headers */, 1E49A4731612226D00463151 /* BITUpdateManager.h in Headers */, 1E49A4791612226D00463151 /* BITUpdateManagerDelegate.h in Headers */, 1E49A44E1612223B00463151 /* BITFeedbackManager.h in Headers */, @@ -435,8 +437,6 @@ 1E49A4D0161222B900463151 /* BITWebTableViewCell.h in Headers */, 1E49A4D8161222D400463151 /* HockeySDKPrivate.h in Headers */, 1EC69F601615001500808FD9 /* BITHockeyManagerPrivate.h in Headers */, - 1E754E5C1621FBB70070AB92 /* BITCrashManager.h in Headers */, - 1E754E5E1621FBB70070AB92 /* BITCrashManagerDelegate.h in Headers */, 1E754E5F1621FBB70070AB92 /* BITCrashManagerPrivate.h in Headers */, 1E754E601621FBB70070AB92 /* BITCrashReportTextFormatter.h in Headers */, 1EACC97B162F041E007578C5 /* BITAttributedLabel.h in Headers */, From acc60ec98777e11443afa029849b0f4d348438bd Mon Sep 17 00:00:00 2001 From: Andreas Linde Date: Sun, 4 Nov 2012 23:47:35 +0100 Subject: [PATCH 102/176] Bump version to 3.0.0b2 Build 12 --- Support/buildnumber.xcconfig | 6 +++--- docs/Changelog-template.md | 7 +++++++ 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/Support/buildnumber.xcconfig b/Support/buildnumber.xcconfig index b15ec4b7..7ff5ab25 100644 --- a/Support/buildnumber.xcconfig +++ b/Support/buildnumber.xcconfig @@ -1,5 +1,5 @@ #include "HockeySDK.xcconfig" -BUILD_NUMBER = 11 -VERSION_STRING = 3.0.0b1 -GCC_PREPROCESSOR_DEFINITIONS = $(inherited) BITHOCKEY_VERSION="@\"3.0.0b1\"" +BUILD_NUMBER = 12 +VERSION_STRING = 3.0.0b2 +GCC_PREPROCESSOR_DEFINITIONS = $(inherited) BITHOCKEY_VERSION="@\"3.0.0b2\"" diff --git a/docs/Changelog-template.md b/docs/Changelog-template.md index 414ca0ae..53ef8fb8 100644 --- a/docs/Changelog-template.md +++ b/docs/Changelog-template.md @@ -1,3 +1,10 @@ +### Version 3.0.0b2 + +- General: + + - [BUGFIX] Add missing header files to the binary distribution + - [BUGFIX] Add missing new lines of two header files + ### Version 3.0.0b1 - General: From 8099d2ad3c5e819f18b05d06237c258a5f5bec73 Mon Sep 17 00:00:00 2001 From: Andreas Linde Date: Sun, 4 Nov 2012 23:58:02 +0100 Subject: [PATCH 103/176] Add two more missing public header files --- Support/HockeySDK.xcodeproj/project.pbxproj | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Support/HockeySDK.xcodeproj/project.pbxproj b/Support/HockeySDK.xcodeproj/project.pbxproj index 92efd53e..e5272cf8 100644 --- a/Support/HockeySDK.xcodeproj/project.pbxproj +++ b/Support/HockeySDK.xcodeproj/project.pbxproj @@ -56,10 +56,10 @@ 1E49A47F1612226D00463151 /* BITUpdateViewController.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E49A4681612226D00463151 /* BITUpdateViewController.h */; settings = {ATTRIBUTES = (Public, ); }; }; 1E49A4821612226D00463151 /* BITUpdateViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 1E49A4691612226D00463151 /* BITUpdateViewController.m */; }; 1E49A4851612226D00463151 /* BITUpdateViewControllerPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E49A46A1612226D00463151 /* BITUpdateViewControllerPrivate.h */; }; - 1E49A4AF161222B900463151 /* BITHockeyBaseManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E49A4A0161222B900463151 /* BITHockeyBaseManager.h */; }; + 1E49A4AF161222B900463151 /* BITHockeyBaseManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E49A4A0161222B900463151 /* BITHockeyBaseManager.h */; settings = {ATTRIBUTES = (Public, ); }; }; 1E49A4B2161222B900463151 /* BITHockeyBaseManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 1E49A4A1161222B900463151 /* BITHockeyBaseManager.m */; }; 1E49A4B5161222B900463151 /* BITHockeyBaseManagerPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E49A4A2161222B900463151 /* BITHockeyBaseManagerPrivate.h */; }; - 1E49A4B8161222B900463151 /* BITHockeyBaseViewController.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E49A4A3161222B900463151 /* BITHockeyBaseViewController.h */; }; + 1E49A4B8161222B900463151 /* BITHockeyBaseViewController.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E49A4A3161222B900463151 /* BITHockeyBaseViewController.h */; settings = {ATTRIBUTES = (Public, ); }; }; 1E49A4BB161222B900463151 /* BITHockeyBaseViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 1E49A4A4161222B900463151 /* BITHockeyBaseViewController.m */; }; 1E49A4BE161222B900463151 /* BITHockeyHelper.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E49A4A5161222B900463151 /* BITHockeyHelper.h */; }; 1E49A4C1161222B900463151 /* BITHockeyHelper.m in Sources */ = {isa = PBXBuildFile; fileRef = 1E49A4A6161222B900463151 /* BITHockeyHelper.m */; }; @@ -421,6 +421,8 @@ 1E49A43C1612223B00463151 /* BITFeedbackComposeViewController.h in Headers */, 1EF95CAA162CB314000AE3AD /* BITFeedbackComposeViewControllerDelegate.h in Headers */, 1EF95CA6162CB037000AE3AD /* BITFeedbackActivity.h in Headers */, + 1E49A4AF161222B900463151 /* BITHockeyBaseManager.h in Headers */, + 1E49A4B8161222B900463151 /* BITHockeyBaseViewController.h in Headers */, 1E49A4421612223B00463151 /* BITFeedbackListViewCell.h in Headers */, 1E49A4541612223B00463151 /* BITFeedbackManagerPrivate.h in Headers */, 1E49A4571612223B00463151 /* BITFeedbackMessage.h in Headers */, @@ -428,9 +430,7 @@ 1E49A46D1612226D00463151 /* BITAppVersionMetaInfo.h in Headers */, 1E49A47C1612226D00463151 /* BITUpdateManagerPrivate.h in Headers */, 1E49A4851612226D00463151 /* BITUpdateViewControllerPrivate.h in Headers */, - 1E49A4AF161222B900463151 /* BITHockeyBaseManager.h in Headers */, 1E49A4B5161222B900463151 /* BITHockeyBaseManagerPrivate.h in Headers */, - 1E49A4B8161222B900463151 /* BITHockeyBaseViewController.h in Headers */, 1E49A4BE161222B900463151 /* BITHockeyHelper.h in Headers */, 1E49A4C4161222B900463151 /* BITAppStoreHeader.h in Headers */, 1E49A4CA161222B900463151 /* BITStoreButton.h in Headers */, From a47c4b1bfdc50a0acc00a9b90132053e778cd7ce Mon Sep 17 00:00:00 2001 From: Andreas Linde Date: Wed, 7 Nov 2012 16:25:22 +0100 Subject: [PATCH 104/176] Fix compiler warnings --- Classes/BITCrashManager.h | 2 +- Classes/BITCrashManager.m | 2 ++ Classes/HockeySDK.h | 9 ++++----- Classes/HockeySDKPrivate.m | 3 +++ 4 files changed, 10 insertions(+), 6 deletions(-) diff --git a/Classes/BITCrashManager.h b/Classes/BITCrashManager.h index c49d2a10..769369df 100644 --- a/Classes/BITCrashManager.h +++ b/Classes/BITCrashManager.h @@ -39,7 +39,7 @@ typedef enum { BITCrashManagerStatusAlwaysAsk = 1, BITCrashManagerStatusAutoSend = 2 } BITCrashManagerStatus; -static NSString *kBITCrashManagerStatus = @"BITCrashManagerStatus"; +extern NSString *const kBITCrashManagerStatus; @protocol BITCrashManagerDelegate; diff --git a/Classes/BITCrashManager.m b/Classes/BITCrashManager.m index 6f1f0da8..0783512f 100644 --- a/Classes/BITCrashManager.m +++ b/Classes/BITCrashManager.m @@ -51,6 +51,8 @@ #define kBITCrashMetaUserID @"BITCrashMetaUserID" #define kBITCrashMetaApplicationLog @"BITCrashMetaApplicationLog" +NSString *const kBITCrashManagerStatus = @"BITCrashManagerStatus"; + @interface BITCrashManager () diff --git a/Classes/HockeySDK.h b/Classes/HockeySDK.h index a47d61f1..cbc16cf6 100644 --- a/Classes/HockeySDK.h +++ b/Classes/HockeySDK.h @@ -58,8 +58,7 @@ typedef enum { BITCrashAPIReceivedEmptyResponse, BITCrashAPIErrorWithStatusCode } BITCrashErrorReason; -static NSString *kBITCrashErrorDomain = @"BITCrashReporterErrorDomain"; - +extern NSString *const kBITCrashErrorDomain; // Update App Versions @@ -72,7 +71,7 @@ typedef enum { BITUpdateAPIClientAuthorizationMissingSecret, BITUpdateAPIClientCannotCreateConnection } BITUpdateErrorReason; -static NSString *kBITUpdateErrorDomain = @"BITUpdaterErrorDomain"; +extern NSString *const kBITUpdateErrorDomain; // Update App Versions @@ -86,7 +85,7 @@ typedef enum { BITFeedbackAPIClientAuthorizationMissingSecret, BITFeedbackAPIClientCannotCreateConnection } BITFeedbackErrorReason; -static NSString *kBITFeedbackErrorDomain = @"BITFeedbackErrorDomain"; +extern NSString *const kBITFeedbackErrorDomain; // HockeySDK @@ -96,7 +95,7 @@ typedef enum { BITHockeyErrorUnknown, HockeyAPIClientMissingJSONLibrary } BITHockeyErrorReason; -static NSString *kBITHockeyErrorDomain = @"BITHockeyErrorDomain"; +NSString *kBITHockeyErrorDomain = @"BITHockeyErrorDomain"; #endif diff --git a/Classes/HockeySDKPrivate.m b/Classes/HockeySDKPrivate.m index 2bcbf8ed..52c158d6 100644 --- a/Classes/HockeySDKPrivate.m +++ b/Classes/HockeySDKPrivate.m @@ -31,6 +31,9 @@ #import "HockeySDKPrivate.h" #include +NSString *const kBITCrashErrorDomain = @"BITCrashReporterErrorDomain"; +NSString *const kBITUpdateErrorDomain = @"BITUpdaterErrorDomain"; +NSString *const kBITFeedbackErrorDomain = @"BITFeedbackErrorDomain"; // Load the framework bundle. NSBundle *BITHockeyBundle(void) { From aa05de04a19dfb6558dd3b8bb87ef0c2b7528d57 Mon Sep 17 00:00:00 2001 From: Andreas Linde Date: Wed, 7 Nov 2012 16:37:07 +0100 Subject: [PATCH 105/176] Fix another one --- Classes/HockeySDK.h | 2 +- Classes/HockeySDKPrivate.m | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/Classes/HockeySDK.h b/Classes/HockeySDK.h index cbc16cf6..81e67293 100644 --- a/Classes/HockeySDK.h +++ b/Classes/HockeySDK.h @@ -95,7 +95,7 @@ typedef enum { BITHockeyErrorUnknown, HockeyAPIClientMissingJSONLibrary } BITHockeyErrorReason; -NSString *kBITHockeyErrorDomain = @"BITHockeyErrorDomain"; +extern NSString *const kBITHockeyErrorDomain; #endif diff --git a/Classes/HockeySDKPrivate.m b/Classes/HockeySDKPrivate.m index 52c158d6..dc0d1f9d 100644 --- a/Classes/HockeySDKPrivate.m +++ b/Classes/HockeySDKPrivate.m @@ -34,6 +34,7 @@ NSString *const kBITCrashErrorDomain = @"BITCrashReporterErrorDomain"; NSString *const kBITUpdateErrorDomain = @"BITUpdaterErrorDomain"; NSString *const kBITFeedbackErrorDomain = @"BITFeedbackErrorDomain"; +NSString *const kBITHockeyErrorDomain = @"BITHockeyErrorDomain"; // Load the framework bundle. NSBundle *BITHockeyBundle(void) { From 4dbbef38e2ec008627b1f79ba10a044ec9a2495c Mon Sep 17 00:00:00 2001 From: Andreas Linde Date: Fri, 9 Nov 2012 13:36:23 +0100 Subject: [PATCH 106/176] Format date and timestamp of crash reports to be always identical no matter what locale is set --- Classes/BITCrashReportTextFormatter.m | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/Classes/BITCrashReportTextFormatter.m b/Classes/BITCrashReportTextFormatter.m index 703ffcbf..fa416553 100644 --- a/Classes/BITCrashReportTextFormatter.m +++ b/Classes/BITCrashReportTextFormatter.m @@ -240,8 +240,14 @@ + (NSString *)stringValueForCrashReport:(PLCrashReport *)report { NSString *osBuild = @"???"; if (report.systemInfo.operatingSystemBuild != nil) osBuild = report.systemInfo.operatingSystemBuild; - - [text appendFormat: @"Date/Time: %@\n", report.systemInfo.timestamp]; + + NSLocale *enUSPOSIXLocale = [[NSLocale alloc] initWithLocaleIdentifier:@"en_US_POSIX"]; + NSDateFormatter *rfc3339Formatter = [[NSDateFormatter alloc] init]; + [rfc3339Formatter setLocale:enUSPOSIXLocale]; + [rfc3339Formatter setDateFormat:@"yyyy'-'MM'-'dd'T'HH':'mm':'ss'Z'"]; + [rfc3339Formatter setTimeZone:[NSTimeZone timeZoneForSecondsFromGMT:0]]; + + [text appendFormat: @"Date/Time: %@\n", [rfc3339Formatter stringFromDate:report.systemInfo.timestamp]]; [text appendFormat: @"OS Version: %@ %@ (%@)\n", osName, report.systemInfo.operatingSystemVersion, osBuild]; [text appendFormat: @"Report Version: 104\n"]; } From 89cc53735045be1efec395c9319e6a54862a5ea2 Mon Sep 17 00:00:00 2001 From: Andreas Linde Date: Thu, 15 Nov 2012 03:24:32 +0100 Subject: [PATCH 107/176] Fix missed out Prefix changed in TTTAttributedLabel / BITAttributedLabel --- Classes/BITAttributedLabel.h | 10 +++++----- Classes/BITAttributedLabel.m | 24 ++++++++++++------------ 2 files changed, 17 insertions(+), 17 deletions(-) diff --git a/Classes/BITAttributedLabel.h b/Classes/BITAttributedLabel.h index 9b898d58..3481bd9e 100755 --- a/Classes/BITAttributedLabel.h +++ b/Classes/BITAttributedLabel.h @@ -35,27 +35,27 @@ typedef enum { /** Determines whether the text to which this attribute applies has a strikeout drawn through itself. */ -extern NSString * const kTTTStrikeOutAttributeName; +extern NSString * const kBITStrikeOutAttributeName; /** The background fill color. Value must be a `CGColorRef`. Default value is `nil` (no fill). */ -extern NSString * const kTTTBackgroundFillColorAttributeName; +extern NSString * const kBITBackgroundFillColorAttributeName; /** The background stroke color. Value must be a `CGColorRef`. Default value is `nil` (no stroke). */ -extern NSString * const kTTTBackgroundStrokeColorAttributeName; +extern NSString * const kBITBackgroundStrokeColorAttributeName; /** The background stroke line width. Value must be an `NSNumber`. Default value is `1.0f`. */ -extern NSString * const kTTTBackgroundLineWidthAttributeName; +extern NSString * const kBITBackgroundLineWidthAttributeName; /** The background corner radius. Value must be an `NSNumber`. Default value is `5.0f`. */ -extern NSString * const kTTTBackgroundCornerRadiusAttributeName; +extern NSString * const kBITBackgroundCornerRadiusAttributeName; @protocol BITAttributedLabelDelegate; diff --git a/Classes/BITAttributedLabel.m b/Classes/BITAttributedLabel.m index 6baef416..31e5f417 100755 --- a/Classes/BITAttributedLabel.m +++ b/Classes/BITAttributedLabel.m @@ -22,16 +22,16 @@ #import "BITAttributedLabel.h" -#define kTTTLineBreakWordWrapTextWidthScalingFactor (M_PI / M_E) +#define kBITLineBreakWordWrapTextWidthScalingFactor (M_PI / M_E) #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wdeprecated-declarations" -NSString * const kTTTStrikeOutAttributeName = @"TTTStrikeOutAttribute"; -NSString * const kTTTBackgroundFillColorAttributeName = @"TTTBackgroundFillColor"; -NSString * const kTTTBackgroundStrokeColorAttributeName = @"TTTBackgroundStrokeColor"; -NSString * const kTTTBackgroundLineWidthAttributeName = @"TTTBackgroundLineWidth"; -NSString * const kTTTBackgroundCornerRadiusAttributeName = @"TTTBackgroundCornerRadius"; +NSString * const kBITStrikeOutAttributeName = @"BITStrikeOutAttribute"; +NSString * const kBITBackgroundFillColorAttributeName = @"BITBackgroundFillColor"; +NSString * const kBITBackgroundStrokeColorAttributeName = @"BITBackgroundStrokeColor"; +NSString * const kBITBackgroundLineWidthAttributeName = @"BITBackgroundLineWidth"; +NSString * const kBITBackgroundCornerRadiusAttributeName = @"BITBackgroundCornerRadius"; static inline CTTextAlignment CTTextAlignmentFromUITextAlignment(UITextAlignment alignment) { switch (alignment) { @@ -564,10 +564,10 @@ - (void)drawBackground:(CTFrameRef)frame inRect:(CGRect)rect context:(CGContextR for (id glyphRun in (__bridge NSArray *)CTLineGetGlyphRuns((__bridge CTLineRef)line)) { NSDictionary *attributes = (__bridge NSDictionary *)CTRunGetAttributes((__bridge CTRunRef) glyphRun); - CGColorRef strokeColor = (__bridge CGColorRef)[attributes objectForKey:kTTTBackgroundStrokeColorAttributeName]; - CGColorRef fillColor = (__bridge CGColorRef)[attributes objectForKey:kTTTBackgroundFillColorAttributeName]; - CGFloat cornerRadius = [[attributes objectForKey:kTTTBackgroundCornerRadiusAttributeName] floatValue]; - CGFloat lineWidth = [[attributes objectForKey:kTTTBackgroundLineWidthAttributeName] floatValue]; + CGColorRef strokeColor = (__bridge CGColorRef)[attributes objectForKey:kBITBackgroundStrokeColorAttributeName]; + CGColorRef fillColor = (__bridge CGColorRef)[attributes objectForKey:kBITBackgroundFillColorAttributeName]; + CGFloat cornerRadius = [[attributes objectForKey:kBITBackgroundCornerRadiusAttributeName] floatValue]; + CGFloat lineWidth = [[attributes objectForKey:kBITBackgroundLineWidthAttributeName] floatValue]; if (strokeColor || fillColor) { CGRect runBounds = CGRectZero; @@ -623,7 +623,7 @@ - (void)drawStrike:(CTFrameRef)frame inRect:(CGRect)rect context:(CGContextRef)c for (id glyphRun in (__bridge NSArray *)CTLineGetGlyphRuns((__bridge CTLineRef)line)) { NSDictionary *attributes = (__bridge NSDictionary *)CTRunGetAttributes((__bridge CTRunRef) glyphRun); - BOOL strikeOut = [[attributes objectForKey:kTTTStrikeOutAttributeName] boolValue]; + BOOL strikeOut = [[attributes objectForKey:kBITStrikeOutAttributeName] boolValue]; NSInteger superscriptStyle = [[attributes objectForKey:(id)kCTSuperscriptAttributeName] integerValue]; if (strikeOut) { @@ -788,7 +788,7 @@ - (void)drawTextInRect:(CGRect)rect { CGFloat textWidth = [self sizeThatFits:CGSizeZero].width; CGFloat availableWidth = self.frame.size.width * self.numberOfLines; if (self.numberOfLines > 1 && self.lineBreakMode == UILineBreakModeWordWrap) { - textWidth *= kTTTLineBreakWordWrapTextWidthScalingFactor; + textWidth *= kBITLineBreakWordWrapTextWidthScalingFactor; } if (textWidth > availableWidth && textWidth > 0.0f) { From dc7db231cbf084cce4e6062582aea30b533226f4 Mon Sep 17 00:00:00 2001 From: Andreas Linde Date: Thu, 15 Nov 2012 15:27:43 +0100 Subject: [PATCH 108/176] Bump version to 3.0.0b3 Build 13 --- Support/buildnumber.xcconfig | 6 +++--- docs/Changelog-template.md | 11 +++++++++++ 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/Support/buildnumber.xcconfig b/Support/buildnumber.xcconfig index 7ff5ab25..1b757ddc 100644 --- a/Support/buildnumber.xcconfig +++ b/Support/buildnumber.xcconfig @@ -1,5 +1,5 @@ #include "HockeySDK.xcconfig" -BUILD_NUMBER = 12 -VERSION_STRING = 3.0.0b2 -GCC_PREPROCESSOR_DEFINITIONS = $(inherited) BITHOCKEY_VERSION="@\"3.0.0b2\"" +BUILD_NUMBER = 13 +VERSION_STRING = 3.0.0b3 +GCC_PREPROCESSOR_DEFINITIONS = $(inherited) BITHOCKEY_VERSION="@\"3.0.0b3\"" diff --git a/docs/Changelog-template.md b/docs/Changelog-template.md index 53ef8fb8..c187be9e 100644 --- a/docs/Changelog-template.md +++ b/docs/Changelog-template.md @@ -1,3 +1,14 @@ +### Version 3.0.0b3 + +- General: + + - [BUGFIX] Exchange some more prefixes of TTTAttributedLabel class that have been missed out + - [BUGFIX] Fix some new compiler warnings + +- Crash Reporting: + + - [BUGFIX] Format timestamp in crash report to be always UTC in en_US locale + ### Version 3.0.0b2 - General: From 31e680400eccf979e1c140206242f1f4a7f9b8cb Mon Sep 17 00:00:00 2001 From: Andreas Linde Date: Fri, 16 Nov 2012 16:57:44 +0100 Subject: [PATCH 109/176] Fix potential crash if delegates return nil --- Classes/BITCrashManager.m | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Classes/BITCrashManager.m b/Classes/BITCrashManager.m index 0783512f..a17bf3df 100644 --- a/Classes/BITCrashManager.m +++ b/Classes/BITCrashManager.m @@ -250,7 +250,7 @@ - (NSString *)userIDForCrashReport { [[BITHockeyManager sharedHockeyManager].delegate respondsToSelector:@selector(userIDForHockeyManager:componentManager:)]) { userID = [[BITHockeyManager sharedHockeyManager].delegate userIDForHockeyManager:[BITHockeyManager sharedHockeyManager] - componentManager:self]; + componentManager:self] ?: @""; } return userID; @@ -262,13 +262,13 @@ - (NSString *)userNameForCrashReport { if (self.delegate && [self.delegate respondsToSelector:@selector(userNameForCrashManager:)]) { if (!self.isAppStoreEnvironment) NSLog(@"[HockeySDK] DEPRECATED: Please use BITHockeyManagerDelegate's userNameForHockeyManager:componentManager: or userIDForHockeyManager:componentManager: instead."); - username = [self.delegate userNameForCrashManager:self]; + username = [self.delegate userNameForCrashManager:self] ?: @""; } if ([BITHockeyManager sharedHockeyManager].delegate && [[BITHockeyManager sharedHockeyManager].delegate respondsToSelector:@selector(userNameForHockeyManager:componentManager:)]) { username = [[BITHockeyManager sharedHockeyManager].delegate userNameForHockeyManager:[BITHockeyManager sharedHockeyManager] - componentManager:self]; + componentManager:self] ?: @""; } return username; @@ -280,13 +280,13 @@ - (NSString *)userEmailForCrashReport { if (self.delegate && [self.delegate respondsToSelector:@selector(userEmailForCrashManager:)]) { if (!self.isAppStoreEnvironment) NSLog(@"[HockeySDK] DEPRECATED: Please use BITHockeyManagerDelegate's userEmailForHockeyManager:componentManager: instead."); - useremail = [self.delegate userEmailForCrashManager:self]; + useremail = [self.delegate userEmailForCrashManager:self] ?: @""; } if ([BITHockeyManager sharedHockeyManager].delegate && [[BITHockeyManager sharedHockeyManager].delegate respondsToSelector:@selector(userEmailForHockeyManager:componentManager:)]) { useremail = [[BITHockeyManager sharedHockeyManager].delegate userEmailForHockeyManager:[BITHockeyManager sharedHockeyManager] - componentManager:self]; + componentManager:self] ?: @""; } return useremail; From 06441b1260cfafe0b2c2efe5aaa72022527bbd73 Mon Sep 17 00:00:00 2001 From: Andreas Linde Date: Fri, 16 Nov 2012 21:02:18 +0100 Subject: [PATCH 110/176] Fix a problem showing the update UI animated if there TTNavigator class is present even though not being used --- Classes/BITHockeyBaseManager.m | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Classes/BITHockeyBaseManager.m b/Classes/BITHockeyBaseManager.m index 625b25e2..285f239e 100644 --- a/Classes/BITHockeyBaseManager.m +++ b/Classes/BITHockeyBaseManager.m @@ -146,7 +146,10 @@ - (void)showView:(UIViewController *)viewController { if (NSClassFromString(@"TTNavigator")) { #pragma clang diagnostic push #pragma clang diagnostic ignored "-Warc-performSelector-leaks" - parentViewController = [[NSClassFromString(@"TTNavigator") performSelector:(NSSelectorFromString(@"navigator"))] visibleViewController]; + UIViewController *ttParentViewController = nil; + ttParentViewController = [[NSClassFromString(@"TTNavigator") performSelector:(NSSelectorFromString(@"navigator"))] visibleViewController]; + if (ttParentViewController) + parentViewController = ttParentViewController; #pragma clang diagnostic pop } From 0285c61485e9b14c01eced1ea183d9cf9ccb2ad6 Mon Sep 17 00:00:00 2001 From: Andreas Linde Date: Sat, 17 Nov 2012 13:37:14 +0100 Subject: [PATCH 111/176] Fix user data UI not being presented as a form sheet on the iPad --- Classes/BITFeedbackComposeViewController.m | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Classes/BITFeedbackComposeViewController.m b/Classes/BITFeedbackComposeViewController.m index 82a6f3c5..655e0386 100644 --- a/Classes/BITFeedbackComposeViewController.m +++ b/Classes/BITFeedbackComposeViewController.m @@ -228,8 +228,9 @@ - (void)setUserDataAction { userController.delegate = self; UINavigationController *navController = [[UINavigationController alloc] initWithRootViewController:userController]; + navController.modalPresentationStyle = UIModalPresentationFormSheet; - [self.navigationController presentModalViewController:navController animated:YES]; + [self presentViewController:navController animated:YES completion:nil]; } - (void)dismissAction:(id)sender { From 1db48b1d25fb6523687a049e5656577ccbeed422 Mon Sep 17 00:00:00 2001 From: Andreas Linde Date: Sat, 17 Nov 2012 14:14:46 +0100 Subject: [PATCH 112/176] Bump version to 3.0.0b3 Build 13 And update documentation --- Support/buildnumber.xcconfig | 6 +++--- docs/Changelog-template.md | 14 ++++++++++++++ docs/Guide-Installation-Setup-Advanced-template.md | 14 +++++++++----- 3 files changed, 26 insertions(+), 8 deletions(-) diff --git a/Support/buildnumber.xcconfig b/Support/buildnumber.xcconfig index 1b757ddc..47a7eb00 100644 --- a/Support/buildnumber.xcconfig +++ b/Support/buildnumber.xcconfig @@ -1,5 +1,5 @@ #include "HockeySDK.xcconfig" -BUILD_NUMBER = 13 -VERSION_STRING = 3.0.0b3 -GCC_PREPROCESSOR_DEFINITIONS = $(inherited) BITHOCKEY_VERSION="@\"3.0.0b3\"" +BUILD_NUMBER = 14 +VERSION_STRING = 3.0.0b4 +GCC_PREPROCESSOR_DEFINITIONS = $(inherited) BITHOCKEY_VERSION="@\"3.0.0b4\"" diff --git a/docs/Changelog-template.md b/docs/Changelog-template.md index c187be9e..feb4aacc 100644 --- a/docs/Changelog-template.md +++ b/docs/Changelog-template.md @@ -1,3 +1,17 @@ +### Version 3.0.0b4 + +- Crash Reporting: + + - [BUGFIX] Fix a crash if `username`, `useremail` or `userid` delegate method returns `nil` and trying to send a crash report + +- Feedback: + + - [BUGFIX] Fix user data UI not always being presented as a form sheet on the iPad + +- Updating: + + - [BUGFIX] Fix a problem showing the update UI animated if there TTNavigator class is present even though not being used + ### Version 3.0.0b3 - General: diff --git a/docs/Guide-Installation-Setup-Advanced-template.md b/docs/Guide-Installation-Setup-Advanced-template.md index a829bc97..90a317ec 100644 --- a/docs/Guide-Installation-Setup-Advanced-template.md +++ b/docs/Guide-Installation-Setup-Advanced-template.md @@ -58,13 +58,17 @@ If you need support for iOS 3.x, please check out [HockeyKit](http://support.hoc -10. Select `Build Settings` +10. Expand `Copy Bundle Resource`. -11. Add the following `Header Search Path` +11. Drag `HockeySDKResources.bundle` from the `HockeySDK` sub-projects `Products` folder and drop into the `Copy Bundle Resource` section + +12. Select `Build Settings` + +13. Add the following `Header Search Path` `$(SRCROOT)/Vendor/HockeySDK/Classes` -12. Create a new `Project.xcconfig` file, if you don't already have one (You can give it any name) +14. Create a new `Project.xcconfig` file, if you don't already have one (You can give it any name) a. Select your project. @@ -76,9 +80,9 @@ If you need support for iOS 3.x, please check out [HockeyKit](http://support.hoc -13. Open `Project.xcconfig` in the editor +15. Open `Project.xcconfig` in the editor -14. Add the following line: +16. Add the following line: `#include "../Vendor/HockeySDK/Support/HockeySDK.xcconfig"` From 2285802865b524faabc225e5a38c25cb04278a24 Mon Sep 17 00:00:00 2001 From: Andreas Linde Date: Sat, 17 Nov 2012 17:01:57 +0100 Subject: [PATCH 113/176] Update documentation on how to add Lumberjack log data --- docs/HowTo-Add-Application-Log-template.md | 99 +++++++++++++++++++++- 1 file changed, 98 insertions(+), 1 deletion(-) diff --git a/docs/HowTo-Add-Application-Log-template.md b/docs/HowTo-Add-Application-Log-template.md index e091ccd6..dc426be0 100644 --- a/docs/HowTo-Add-Application-Log-template.md +++ b/docs/HowTo-Add-Application-Log-template.md @@ -58,7 +58,7 @@ This example code is based on CocoaLumberjack logging into log files: - (NSString *) getLogFilesContentWithMaxSize:(NSInteger)maxSize { NSMutableString *description = [NSMutableString string]; - NSArray *sortedLogFileInfos = [[[Logging fileLogger] logFileManager] sortedLogFileInfos]; + NSArray *sortedLogFileInfos = [[_fileLogger logFileManager] sortedLogFileInfos]; NSUInteger count = [sortedLogFileInfos count]; // we start from the last one @@ -96,3 +96,100 @@ This example code is based on CocoaLumberjack logging into log files: @end + +## Advanced HowTo + +If you want to restrict the log files to contain only the data from the last application run (from app start until it crashed, ignoring all suspend and resume actions), you follow these steps. (Thanks to Michael Tyson for this hint!) + +4. Adjust CocoaLumberjack to initialize a new log file per application start + + [_fileLogger performSelector:@selector(currentLogFileHandle)]; // init log file prior to rolling + [_fileLogger rollLogFile]; + [_fileLogger performSelector:@selector(currentLogFileHandle)]; // re-init log file to apply roll + +5. And when loading the prior (crashed) application run log file, stop the iteration over the log files before the most current one (which is the new session, the one after the crash): + + // we start from the last (oldest) one, and stop just before the newest (which is the log for the session after the crash) + for (int index = count - 1; index > 0; index--) { + + +## Example + + @interface BITAppDelegate () {} + @property (nonatomic) DDFileLogger *fileLogger; + @end + + + @implementation BITAppDelegate + + - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { + [self.window makeKeyAndVisible]; + + // initialize before HockeySDK, so the delegate can access the file logger! + _fileLogger = [[DDFileLogger alloc] init]; + _fileLogger.maximumFileSize = (1024 * 64); // 64 KByte + _fileLogger.logFileManager.maximumNumberOfLogFiles = 1; + [_fileLogger performSelector:@selector(currentLogFileHandle)]; // init log file prior to rolling + [_fileLogger rollLogFile]; + [_fileLogger performSelector:@selector(currentLogFileHandle)]; // re-init log file to apply roll + [DDLog addLogger:_fileLogger]; + + [[BITHockeyManager sharedHockeyManager] configureWithIdentifier:@"<>" + delegate:nil]; + + [[BITHockeyManager sharedHockeyManager] startManager]; + + // add Xcode console logger if not running in the App Store + if (![[BITHockeyManager sharedHockeyManager] isAppStoreEnvironment]) { + PSDDFormatter *psLogger = [[[PSDDFormatter alloc] init] autorelease]; + [[DDTTYLogger sharedInstance] setLogFormatter:psLogger]; + + [DDLog addLogger:[DDTTYLogger sharedInstance]]; + + [DDLog addLogger:[DDNSLoggerLogger sharedInstance]]; + } + + return YES; + } + + // get the log content with a maximum byte size + - (NSString *) getLogFilesContentWithMaxSize:(NSInteger)maxSize { + NSMutableString *description = [NSMutableString string]; + + NSArray *sortedLogFileInfos = [[_fileLogger logFileManager] sortedLogFileInfos]; + NSUInteger count = [sortedLogFileInfos count]; + + // we start from the last (oldest) one, and stop just before the newest (which is the log for the session after the crash) + for (int index = count - 1; index > 0; index--) { + DDLogFileInfo *logFileInfo = [sortedLogFileInfos objectAtIndex:index]; + + NSData *logData = [[NSFileManager defaultManager] contentsAtPath:[logFileInfo filePath]]; + if ([logData length] > 0) { + NSString *result = [[NSString alloc] initWithBytes:[logData bytes] + length:[logData length] + encoding: NSUTF8StringEncoding]; + + [description appendString:result]; + [result release]; + } + } + + if ([description length] > maxSize) { + description = (NSMutableString *)[description substringWithRange:NSMakeRange([description length]-maxSize-1, maxSize)]; + } + + return description; + } + + #pragma mark - BITCrashManagerDelegate + + - (NSString *)applicationLogForCrashManager:(BITCrashManager *)crashManager { + NSString *description = [self getLogFilesContentWithMaxSize:5000]; // 5000 bytes should be enough! + if ([description length] == 0) { + return nil; + } else { + return description; + } + } + + @end \ No newline at end of file From 4448bdba1f23c7861344164d5bce3e55a9da78f7 Mon Sep 17 00:00:00 2001 From: Andreas Linde Date: Sat, 17 Nov 2012 20:48:18 +0100 Subject: [PATCH 114/176] Update buttons in feedback views --- Classes/BITFeedbackListViewController.m | 24 ++++++++----- Resources/buttonRoundedDelete.png | Bin 0 -> 3416 bytes Resources/buttonRoundedDelete@2x.png | Bin 0 -> 4171 bytes Resources/buttonRoundedDeleteHighlighted.png | Bin 0 -> 3538 bytes .../buttonRoundedDeleteHighlighted@2x.png | Bin 0 -> 4699 bytes Resources/buttonRoundedRegular.png | Bin 0 -> 3355 bytes Resources/buttonRoundedRegular@2x.png | Bin 0 -> 4108 bytes Resources/buttonRoundedRegularHighlighted.png | Bin 0 -> 3605 bytes .../buttonRoundedRegularHighlighted@2x.png | Bin 0 -> 4717 bytes Support/HockeySDK.xcodeproj/project.pbxproj | 32 ++++++++++++++++++ 10 files changed, 47 insertions(+), 9 deletions(-) create mode 100644 Resources/buttonRoundedDelete.png create mode 100644 Resources/buttonRoundedDelete@2x.png create mode 100644 Resources/buttonRoundedDeleteHighlighted.png create mode 100644 Resources/buttonRoundedDeleteHighlighted@2x.png create mode 100644 Resources/buttonRoundedRegular.png create mode 100644 Resources/buttonRoundedRegular@2x.png create mode 100644 Resources/buttonRoundedRegularHighlighted.png create mode 100644 Resources/buttonRoundedRegularHighlighted@2x.png diff --git a/Classes/BITFeedbackListViewController.m b/Classes/BITFeedbackListViewController.m index 1b2b0310..ff0b36cb 100644 --- a/Classes/BITFeedbackListViewController.m +++ b/Classes/BITFeedbackListViewController.m @@ -48,12 +48,12 @@ #define BUTTON_BORDERCOLOR BIT_RGBCOLOR(175, 175, 175) #define BUTTON_BACKGROUNDCOLOR BIT_RGBCOLOR(225, 225, 225) #define BUTTON_TEXTCOLOR BIT_RGBCOLOR(58, 58, 58) -#define BUTTON_TEXTCOLOR_SHADOW BIT_RGBCOLOR(175, 175, 175) +#define BUTTON_TEXTCOLOR_SHADOW BIT_RGBCOLOR(255, 255, 255) #define BUTTON_DELETE_BORDERCOLOR BIT_RGBCOLOR(61, 61, 61) #define BUTTON_DELETE_BACKGROUNDCOLOR BIT_RGBCOLOR(225, 0, 0) #define BUTTON_DELETE_TEXTCOLOR BIT_RGBCOLOR(240, 240, 240) -#define BUTTON_DELETE_TEXTCOLOR_SHADOW BIT_RGBCOLOR(175, 175, 175) +#define BUTTON_DELETE_TEXTCOLOR_SHADOW BIT_RGBCOLOR(125, 0, 0) #define BORDER_COLOR BIT_RGBCOLOR(215, 215, 215) @@ -349,12 +349,14 @@ - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(N // button UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom]; button.autoresizingMask = UIViewAutoresizingFlexibleWidth; - [button.layer setCornerRadius:10.0f]; - [button.layer setBorderWidth:1]; - [button.layer setBackgroundColor:BUTTON_BACKGROUNDCOLOR.CGColor]; - [button.layer setBorderColor:BUTTON_BORDERCOLOR.CGColor]; - [button.layer setShadowOffset:CGSizeMake(-1, -1)]; + UIImage *stretchableButton = [bit_imageNamed(@"buttonRoundedRegular.png", BITHOCKEYSDK_BUNDLE) stretchableImageWithLeftCapWidth:10 topCapHeight:0]; + UIImage *stretchableHighlightedButton = [bit_imageNamed(@"buttonRoundedRegularHighlighted.png", BITHOCKEYSDK_BUNDLE) stretchableImageWithLeftCapWidth:10 topCapHeight:0]; + [button setBackgroundImage:stretchableButton forState:UIControlStateNormal]; + [button setBackgroundImage:stretchableHighlightedButton forState:UIControlStateHighlighted]; + + [[button titleLabel] setShadowOffset:CGSizeMake(0, 1)]; [[button titleLabel] setFont:[UIFont boldSystemFontOfSize:14.0]]; + [button setTitleColor:BUTTON_TEXTCOLOR forState:UIControlStateNormal]; [button setTitleShadowColor:BUTTON_TEXTCOLOR_SHADOW forState:UIControlStateNormal]; if (indexPath.section == 0) { @@ -385,8 +387,12 @@ - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(N [button addTarget:self action:@selector(setUserDataAction:) forControlEvents:UIControlEventTouchUpInside]; } else { topGap = 0.0f; - [button.layer setBackgroundColor:BUTTON_DELETE_BACKGROUNDCOLOR.CGColor]; - [button.layer setBorderColor:BUTTON_DELETE_BORDERCOLOR.CGColor]; + [[button titleLabel] setShadowOffset:CGSizeMake(0, -1)]; + UIImage *stretchableDeleteButton = [bit_imageNamed(@"buttonRoundedDelete.png", BITHOCKEYSDK_BUNDLE) stretchableImageWithLeftCapWidth:10 topCapHeight:0]; + UIImage *stretchableDeleteHighlightedButton = [bit_imageNamed(@"buttonRoundedDeleteHighlighted.png", BITHOCKEYSDK_BUNDLE) stretchableImageWithLeftCapWidth:10 topCapHeight:0]; + [button setBackgroundImage:stretchableDeleteButton forState:UIControlStateNormal]; + [button setBackgroundImage:stretchableDeleteHighlightedButton forState:UIControlStateHighlighted]; + [button setTitleColor:BUTTON_DELETE_TEXTCOLOR forState:UIControlStateNormal]; [button setTitleShadowColor:BUTTON_DELETE_TEXTCOLOR_SHADOW forState:UIControlStateNormal]; diff --git a/Resources/buttonRoundedDelete.png b/Resources/buttonRoundedDelete.png new file mode 100644 index 0000000000000000000000000000000000000000..355697a7640a05d66a4957c068c62c19fe831138 GIT binary patch literal 3416 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 literal 0 HcmV?d00001 diff --git a/Resources/buttonRoundedRegular@2x.png b/Resources/buttonRoundedRegular@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..a53f0efff62e867f0f2cf27a5d59bf87f30f746f GIT binary patch literal 4108 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 KMNUMnLSTaPb?$%w literal 0 HcmV?d00001 diff --git a/Resources/buttonRoundedRegularHighlighted.png b/Resources/buttonRoundedRegularHighlighted.png new file mode 100644 index 0000000000000000000000000000000000000000..7847917666bc3ee91eb47e3dda80c5b113c98dda GIT binary patch literal 3605 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 literal 0 HcmV?d00001 diff --git a/Support/HockeySDK.xcodeproj/project.pbxproj b/Support/HockeySDK.xcodeproj/project.pbxproj index e5272cf8..75bc72b1 100644 --- a/Support/HockeySDK.xcodeproj/project.pbxproj +++ b/Support/HockeySDK.xcodeproj/project.pbxproj @@ -33,6 +33,14 @@ /* End PBXAggregateTarget section */ /* Begin PBXBuildFile section */ + 1E1127C416580C87007067A2 /* buttonRoundedDelete.png in Resources */ = {isa = PBXBuildFile; fileRef = 1E1127BC16580C87007067A2 /* buttonRoundedDelete.png */; }; + 1E1127C516580C87007067A2 /* buttonRoundedDelete@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 1E1127BD16580C87007067A2 /* buttonRoundedDelete@2x.png */; }; + 1E1127C616580C87007067A2 /* buttonRoundedDeleteHighlighted.png in Resources */ = {isa = PBXBuildFile; fileRef = 1E1127BE16580C87007067A2 /* buttonRoundedDeleteHighlighted.png */; }; + 1E1127C716580C87007067A2 /* buttonRoundedDeleteHighlighted@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 1E1127BF16580C87007067A2 /* buttonRoundedDeleteHighlighted@2x.png */; }; + 1E1127C816580C87007067A2 /* buttonRoundedRegular.png in Resources */ = {isa = PBXBuildFile; fileRef = 1E1127C016580C87007067A2 /* buttonRoundedRegular.png */; }; + 1E1127C916580C87007067A2 /* buttonRoundedRegular@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 1E1127C116580C87007067A2 /* buttonRoundedRegular@2x.png */; }; + 1E1127CA16580C87007067A2 /* buttonRoundedRegularHighlighted.png in Resources */ = {isa = PBXBuildFile; fileRef = 1E1127C216580C87007067A2 /* buttonRoundedRegularHighlighted.png */; }; + 1E1127CB16580C87007067A2 /* buttonRoundedRegularHighlighted@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 1E1127C316580C87007067A2 /* buttonRoundedRegularHighlighted@2x.png */; }; 1E27EF2515BB5033000AE995 /* HockeySDK.strings in Resources */ = {isa = PBXBuildFile; fileRef = 1E59555F15B6F80E00A03429 /* HockeySDK.strings */; }; 1E49A43C1612223B00463151 /* BITFeedbackComposeViewController.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E49A42D1612223B00463151 /* BITFeedbackComposeViewController.h */; settings = {ATTRIBUTES = (Public, ); }; }; 1E49A43F1612223B00463151 /* BITFeedbackComposeViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 1E49A42E1612223B00463151 /* BITFeedbackComposeViewController.m */; }; @@ -122,6 +130,14 @@ /* End PBXContainerItemProxy section */ /* Begin PBXFileReference section */ + 1E1127BC16580C87007067A2 /* buttonRoundedDelete.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = buttonRoundedDelete.png; sourceTree = ""; }; + 1E1127BD16580C87007067A2 /* buttonRoundedDelete@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "buttonRoundedDelete@2x.png"; sourceTree = ""; }; + 1E1127BE16580C87007067A2 /* buttonRoundedDeleteHighlighted.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = buttonRoundedDeleteHighlighted.png; sourceTree = ""; }; + 1E1127BF16580C87007067A2 /* buttonRoundedDeleteHighlighted@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "buttonRoundedDeleteHighlighted@2x.png"; sourceTree = ""; }; + 1E1127C016580C87007067A2 /* buttonRoundedRegular.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = buttonRoundedRegular.png; sourceTree = ""; }; + 1E1127C116580C87007067A2 /* buttonRoundedRegular@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "buttonRoundedRegular@2x.png"; sourceTree = ""; }; + 1E1127C216580C87007067A2 /* buttonRoundedRegularHighlighted.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = buttonRoundedRegularHighlighted.png; sourceTree = ""; }; + 1E1127C316580C87007067A2 /* buttonRoundedRegularHighlighted@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "buttonRoundedRegularHighlighted@2x.png"; sourceTree = ""; }; 1E49A42D1612223B00463151 /* BITFeedbackComposeViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BITFeedbackComposeViewController.h; sourceTree = ""; }; 1E49A42E1612223B00463151 /* BITFeedbackComposeViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = BITFeedbackComposeViewController.m; sourceTree = ""; }; 1E49A42F1612223B00463151 /* BITFeedbackListViewCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BITFeedbackListViewCell.h; sourceTree = ""; }; @@ -241,6 +257,14 @@ 1E5955BF15B71C8600A03429 /* bg.png */, 1E5955C015B71C8600A03429 /* buttonHighlight.png */, 1E5955C115B71C8600A03429 /* buttonHighlight@2x.png */, + 1E1127BC16580C87007067A2 /* buttonRoundedDelete.png */, + 1E1127BD16580C87007067A2 /* buttonRoundedDelete@2x.png */, + 1E1127BE16580C87007067A2 /* buttonRoundedDeleteHighlighted.png */, + 1E1127BF16580C87007067A2 /* buttonRoundedDeleteHighlighted@2x.png */, + 1E1127C016580C87007067A2 /* buttonRoundedRegular.png */, + 1E1127C116580C87007067A2 /* buttonRoundedRegular@2x.png */, + 1E1127C216580C87007067A2 /* buttonRoundedRegularHighlighted.png */, + 1E1127C316580C87007067A2 /* buttonRoundedRegularHighlighted@2x.png */, 1E5955C415B71C8600A03429 /* IconGradient.png */, 1E5955C515B71C8600A03429 /* IconGradient@2x.png */, 1EAF20A4162DC0F600957B1D /* feedbackActivity@2x~ipad.png */, @@ -543,6 +567,14 @@ 1EAF20A9162DC0F600957B1D /* feedbackActivity~ipad.png in Resources */, 1EAF20AA162DC0F600957B1D /* feedbackActiviy.png in Resources */, 1EAF20AB162DC0F600957B1D /* feedbackActiviy@2x.png in Resources */, + 1E1127C416580C87007067A2 /* buttonRoundedDelete.png in Resources */, + 1E1127C516580C87007067A2 /* buttonRoundedDelete@2x.png in Resources */, + 1E1127C616580C87007067A2 /* buttonRoundedDeleteHighlighted.png in Resources */, + 1E1127C716580C87007067A2 /* buttonRoundedDeleteHighlighted@2x.png in Resources */, + 1E1127C816580C87007067A2 /* buttonRoundedRegular.png in Resources */, + 1E1127C916580C87007067A2 /* buttonRoundedRegular@2x.png in Resources */, + 1E1127CA16580C87007067A2 /* buttonRoundedRegularHighlighted.png in Resources */, + 1E1127CB16580C87007067A2 /* buttonRoundedRegularHighlighted@2x.png in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; From 756341a38674b7b541e4aa8f7a87115e7a30eae7 Mon Sep 17 00:00:00 2001 From: Andreas Linde Date: Sun, 18 Nov 2012 00:00:24 +0100 Subject: [PATCH 115/176] Fix some users own messages re-appearing after deleting them --- Classes/BITFeedbackManager.m | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Classes/BITFeedbackManager.m b/Classes/BITFeedbackManager.m index 68764135..87b7080b 100644 --- a/Classes/BITFeedbackManager.m +++ b/Classes/BITFeedbackManager.m @@ -634,14 +634,14 @@ - (void)updateMessageListFromResponse:(NSDictionary *)jsonDictionary { [self markSendInProgressMessagesAsPending]; + [self sortFeedbackList]; + [self updateLastMessageID]; + // we got a new incoming message, trigger user notification system if (newMessage) { // check if the latest message is from the users own email address, then don't show an alert since he answered using his own email BOOL latestMessageFromUser = NO; - [self sortFeedbackList]; - [self updateLastMessageID]; - BITFeedbackMessage *latestMessage = [self lastMessageHavingID]; if (self.userEmail && latestMessage.email && [self.userEmail compare:latestMessage.email] == NSOrderedSame) latestMessageFromUser = YES; From 12c092594c0fcc254fda418f957074b9d7fe5d68 Mon Sep 17 00:00:00 2001 From: Andreas Linde Date: Wed, 21 Nov 2012 15:49:59 +0100 Subject: [PATCH 116/176] Add check for newline at EOF and fix where it is missing --- Classes/BITFeedbackMessage.h | 2 +- Classes/BITFeedbackMessage.m | 2 +- Classes/BITFeedbackUserDataViewController.h | 2 +- Classes/BITHockeyBaseManagerPrivate.h | 2 +- Support/HockeySDK.xcodeproj/project.pbxproj | 2 ++ 5 files changed, 6 insertions(+), 4 deletions(-) diff --git a/Classes/BITFeedbackMessage.h b/Classes/BITFeedbackMessage.h index 336bfc54..371501fc 100644 --- a/Classes/BITFeedbackMessage.h +++ b/Classes/BITFeedbackMessage.h @@ -57,4 +57,4 @@ typedef enum { @property (nonatomic) BITFeedbackMessageStatus status; @property (nonatomic) BOOL userMessage; -@end \ No newline at end of file +@end diff --git a/Classes/BITFeedbackMessage.m b/Classes/BITFeedbackMessage.m index f6915278..745df7db 100644 --- a/Classes/BITFeedbackMessage.m +++ b/Classes/BITFeedbackMessage.m @@ -79,4 +79,4 @@ - (id)initWithCoder:(NSCoder *)decoder { return self; } -@end \ No newline at end of file +@end diff --git a/Classes/BITFeedbackUserDataViewController.h b/Classes/BITFeedbackUserDataViewController.h index 14824a0b..68bf2b46 100644 --- a/Classes/BITFeedbackUserDataViewController.h +++ b/Classes/BITFeedbackUserDataViewController.h @@ -48,4 +48,4 @@ // save action is invoked and all required data available - (void)userDataUpdateFinished; -@end \ No newline at end of file +@end diff --git a/Classes/BITHockeyBaseManagerPrivate.h b/Classes/BITHockeyBaseManagerPrivate.h index 81c5ad71..552c82b7 100644 --- a/Classes/BITHockeyBaseManagerPrivate.h +++ b/Classes/BITHockeyBaseManagerPrivate.h @@ -34,4 +34,4 @@ - (NSDate *)parseRFC3339Date:(NSString *)dateString; -@end \ No newline at end of file +@end diff --git a/Support/HockeySDK.xcodeproj/project.pbxproj b/Support/HockeySDK.xcodeproj/project.pbxproj index 75bc72b1..19cccc85 100644 --- a/Support/HockeySDK.xcodeproj/project.pbxproj +++ b/Support/HockeySDK.xcodeproj/project.pbxproj @@ -791,6 +791,7 @@ GCC_SYMBOLS_PRIVATE_EXTERN = NO; GCC_THUMB_SUPPORT = NO; GCC_VERSION = ""; + GCC_WARN_ABOUT_MISSING_NEWLINE = YES; GCC_WARN_ABOUT_MISSING_PROTOTYPES = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES; GCC_WARN_STRICT_SELECTOR_MATCH = YES; @@ -820,6 +821,7 @@ ); GCC_THUMB_SUPPORT = NO; GCC_VERSION = ""; + GCC_WARN_ABOUT_MISSING_NEWLINE = YES; GCC_WARN_ABOUT_MISSING_PROTOTYPES = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES; GCC_WARN_STRICT_SELECTOR_MATCH = YES; From 2c4dc33f36a808878c634aae47b861c5182d8c58 Mon Sep 17 00:00:00 2001 From: Andreas Linde Date: Mon, 26 Nov 2012 19:45:21 +0100 Subject: [PATCH 117/176] Call delegate also if a crash was detected but could not be read If PLCrashReporter wrote a crash report, that could not be read, no delegate was fired. That could make the app stay in the start up maintenance screen, if it handles crashes on startup. Though there was no report this ever happened, there is the theoretical chance this could. --- Classes/BITCrashManager.m | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/Classes/BITCrashManager.m b/Classes/BITCrashManager.m index a17bf3df..14d23514 100644 --- a/Classes/BITCrashManager.m +++ b/Classes/BITCrashManager.m @@ -398,8 +398,17 @@ - (BOOL)hasPendingCrashReport { if ([_crashFiles count] > 0) { BITHockeyLog(@"INFO: %i pending crash reports found.", [_crashFiles count]); return YES; - } else + } else { + if (_didCrashInLastSession) { + if (self.delegate != nil && [self.delegate respondsToSelector:@selector(crashManagerWillCancelSendingCrashReport:)]) { + [self.delegate crashManagerWillCancelSendingCrashReport:self]; + } + + _didCrashInLastSession = NO; + } + return NO; + } } From f211182f4951a656cc652a04e212e010b787d873 Mon Sep 17 00:00:00 2001 From: Andreas Linde Date: Tue, 27 Nov 2012 02:37:37 +0100 Subject: [PATCH 118/176] Add anonID to crash reports CrashReporter Key is actually an anonymous ID for each device/installation where the crash occurred --- Classes/BITCrashManager.m | 4 ++-- Classes/BITCrashReportTextFormatter.h | 2 +- Classes/BITCrashReportTextFormatter.m | 10 +++++++--- 3 files changed, 10 insertions(+), 6 deletions(-) diff --git a/Classes/BITCrashManager.m b/Classes/BITCrashManager.m index 14d23514..ff351ff5 100644 --- a/Classes/BITCrashManager.m +++ b/Classes/BITCrashManager.m @@ -566,7 +566,8 @@ - (void)performSendingCrashReports { if ([report respondsToSelector:@selector(reportInfo)]) { crashUUID = report.reportInfo.reportGUID ?: @""; } - NSString *crashLogString = [BITCrashReportTextFormatter stringValueForCrashReport:report]; + NSString *installString = bit_appAnonID() ?: @""; + NSString *crashLogString = [BITCrashReportTextFormatter stringValueForCrashReport:report crashReporterKey:installString]; if ([report.applicationInfo.applicationVersion compare:[[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleVersion"]] == NSOrderedSame) { _crashIdenticalCurrentVersion = YES; @@ -581,7 +582,6 @@ - (void)performSendingCrashReports { NSString *userid = @""; NSString *applicationLog = @""; NSString *description = @""; - NSString *installString = bit_appAnonID() ?: @""; NSString *errorString = nil; NSPropertyListFormat format; diff --git a/Classes/BITCrashReportTextFormatter.h b/Classes/BITCrashReportTextFormatter.h index ebaf38bb..4ff2743c 100644 --- a/Classes/BITCrashReportTextFormatter.h +++ b/Classes/BITCrashReportTextFormatter.h @@ -47,7 +47,7 @@ @interface BITCrashReportTextFormatter : NSObject { } -+ (NSString *)stringValueForCrashReport:(PLCrashReport *)report; ++ (NSString *)stringValueForCrashReport:(PLCrashReport *)report crashReporterKey:(NSString *)crashReporterKey; + (NSArray *)arrayOfAppUUIDsForCrashReport:(PLCrashReport *)report; @end diff --git a/Classes/BITCrashReportTextFormatter.m b/Classes/BITCrashReportTextFormatter.m index fa416553..bf86d2fa 100644 --- a/Classes/BITCrashReportTextFormatter.m +++ b/Classes/BITCrashReportTextFormatter.m @@ -76,7 +76,7 @@ @implementation BITCrashReportTextFormatter * * @return Returns the formatted result on success, or nil if an error occurs. */ -+ (NSString *)stringValueForCrashReport:(PLCrashReport *)report { ++ (NSString *)stringValueForCrashReport:(PLCrashReport *)report crashReporterKey:(NSString *)crashReporterKey { NSMutableString* text = [NSMutableString string]; boolean_t lp64 = true; // quiesce GCC uninitialized value warning @@ -178,13 +178,17 @@ + (NSString *)stringValueForCrashReport:(PLCrashReport *)report { if (report.hasReportInfo && report.reportInfo.reportGUID != nil) reportGUID = report.reportInfo.reportGUID; } - + + NSString *reporterKey = @"[TODO]"; + if (crashReporterKey) + reporterKey = crashReporterKey; + NSString *hardwareModel = @"???"; if (report.hasMachineInfo && report.machineInfo.modelName != nil) hardwareModel = report.machineInfo.modelName; [text appendFormat: @"Incident Identifier: %@\n", reportGUID]; - [text appendFormat: @"CrashReporter Key: [TODO]\n"]; + [text appendFormat: @"CrashReporter Key: %@\n", reporterKey]; [text appendFormat: @"Hardware Model: %@\n", hardwareModel]; } From 70e7c9114e2f494b7a9ceebd3e9c0913b31fc196 Mon Sep 17 00:00:00 2001 From: Andreas Linde Date: Tue, 27 Nov 2012 14:51:53 +0100 Subject: [PATCH 119/176] Add notice to advanced doc --- docs/Guide-Installation-Setup-Advanced-template.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/Guide-Installation-Setup-Advanced-template.md b/docs/Guide-Installation-Setup-Advanced-template.md index 90a317ec..d33a6a54 100644 --- a/docs/Guide-Installation-Setup-Advanced-template.md +++ b/docs/Guide-Installation-Setup-Advanced-template.md @@ -87,7 +87,8 @@ If you need support for iOS 3.x, please check out [HockeyKit](http://support.hoc `#include "../Vendor/HockeySDK/Support/HockeySDK.xcconfig"` (Adjust the path depending where the `Project.xcconfig` file is located related to the Xcode project package) - + + **Important note:** Check if you overwrite any of the build settings and add a missing `$(inherited)` entry on the projects build settings level, so the `HockeySDK.xcconfig` settings will be passed through successfully. From c754c9f68e802829370d2fcf00b29808612ed3d9 Mon Sep 17 00:00:00 2001 From: Andreas Linde Date: Tue, 27 Nov 2012 20:43:25 +0100 Subject: [PATCH 120/176] Move calculation of time interval between startup and crash further up in the code This allows the delegate, e.g. applicationLog, to know about the interval and e.g. include it in the log file --- Classes/BITCrashManager.m | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/Classes/BITCrashManager.m b/Classes/BITCrashManager.m index ff351ff5..416d32fa 100644 --- a/Classes/BITCrashManager.m +++ b/Classes/BITCrashManager.m @@ -316,6 +316,15 @@ - (void) handleCrashReport { if (crashData == nil) { BITHockeyLog(@"ERROR: Could not load crash report: %@", error); } else { + // get the startup timestamp from the crash report, and the file timestamp to calculate the timeinterval when the crash happened after startup + PLCrashReport *report = [[PLCrashReport alloc] initWithData:crashData error:&error]; + + if ([report.applicationInfo respondsToSelector:@selector(applicationStartupTimestamp)]) { + if (report.systemInfo.timestamp && report.applicationInfo.applicationStartupTimestamp) { + _timeintervalCrashInLastSessionOccured = [report.systemInfo.timestamp timeIntervalSinceDate:report.applicationInfo.applicationStartupTimestamp]; + } + } + [crashData writeToFile:[_crashesDir stringByAppendingPathComponent: cacheFilename] atomically:YES]; // write the meta file @@ -340,15 +349,6 @@ - (void) handleCrashReport { } else { BITHockeyLog(@"ERROR: Writing crash meta data failed. %@", error); } - - // get the startup timestamp from the crash report, and the file timestamp to calculate the timeinterval when the crash happened after startup - PLCrashReport *report = [[PLCrashReport alloc] initWithData:crashData error:&error]; - - if ([report.applicationInfo respondsToSelector:@selector(applicationStartupTimestamp)]) { - if (report.systemInfo.timestamp && report.applicationInfo.applicationStartupTimestamp) { - _timeintervalCrashInLastSessionOccured = [report.systemInfo.timestamp timeIntervalSinceDate:report.applicationInfo.applicationStartupTimestamp]; - } - } } } From 71c43cd6900edd34ceab0e21a7d014a3aaea2331 Mon Sep 17 00:00:00 2001 From: Andreas Linde Date: Tue, 27 Nov 2012 23:02:25 +0100 Subject: [PATCH 121/176] Improve documentation declare the AppDelegate interface as a HockeyProtocols category, to make it clear this does not need to be done in the header file. --- docs/Guide-Installation-Setup-Advanced-template.md | 2 +- docs/Guide-Installation-Setup-template.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/Guide-Installation-Setup-Advanced-template.md b/docs/Guide-Installation-Setup-Advanced-template.md index d33a6a54..41e3deac 100644 --- a/docs/Guide-Installation-Setup-Advanced-template.md +++ b/docs/Guide-Installation-Setup-Advanced-template.md @@ -102,7 +102,7 @@ If you need support for iOS 3.x, please check out [HockeyKit](http://support.hoc 3. Let the AppDelegate implement the protocols `BITHockeyManagerDelegate`, `BITUpdateManagerDelegate` and `BITCrashManagerDelegate`: - @interface AppDelegate() {} + @interface AppDelegate(HockeyProtocols) {} @end 4. Search for the method `application:didFinishLaunchingWithOptions:` diff --git a/docs/Guide-Installation-Setup-template.md b/docs/Guide-Installation-Setup-template.md index 5830fe72..4d4cdf46 100644 --- a/docs/Guide-Installation-Setup-template.md +++ b/docs/Guide-Installation-Setup-template.md @@ -72,7 +72,7 @@ If you need support for iOS 3.x, please check out [HockeyKit](http://support.hoc 3. Let the AppDelegate implement the protocols `BITHockeyManagerDelegate`, `BITUpdateManagerDelegate` and `BITCrashManagerDelegate`: - @interface AppDelegate() {} + @interface AppDelegate(HockeyProtocols) {} @end 4. Search for the method `application:didFinishLaunchingWithOptions:` From 6b948a8d1310555e1e993c8597a873a6501a32b3 Mon Sep 17 00:00:00 2001 From: Andreas Linde Date: Wed, 28 Nov 2012 19:02:37 +0100 Subject: [PATCH 122/176] Make sure json serialization never gets a nil value, otherwise it crashes --- Classes/BITFeedbackManager.m | 38 +++++++++--------- Classes/BITUpdateManager.m | 77 +++++++++++++++++++----------------- 2 files changed, 61 insertions(+), 54 deletions(-) diff --git a/Classes/BITFeedbackManager.m b/Classes/BITFeedbackManager.m index 87b7080b..9809bff7 100644 --- a/Classes/BITFeedbackManager.m +++ b/Classes/BITFeedbackManager.m @@ -784,26 +784,28 @@ - (void)sendNetworkRequestWithHTTPMethod:(NSString *)httpMethod withMessage:(BIT NSString *responseString = [[NSString alloc] initWithBytes:[responseData bytes] length:[responseData length] encoding: NSUTF8StringEncoding]; BITHockeyLog(@"INFO: Received API response: %@", responseString); - NSError *error = NULL; - - NSDictionary *feedDict = (NSDictionary *)[NSJSONSerialization JSONObjectWithData:[responseString dataUsingEncoding:NSUTF8StringEncoding] options:kNilOptions error:&error]; - - // server returned empty response? - if (error) { - [self reportError:error]; - } else if (![feedDict count]) { - [self reportError:[NSError errorWithDomain:kBITFeedbackErrorDomain - code:BITFeedbackAPIServerReturnedEmptyResponse - userInfo:[NSDictionary dictionaryWithObjectsAndKeys:@"Server returned empty response.", NSLocalizedDescriptionKey, nil]]]; - } else { - BITHockeyLog(@"INFO: Received API response: %@", responseString); - NSString *status = [feedDict objectForKey:@"status"]; - if ([status compare:@"success"] != NSOrderedSame) { + if (responseString && [responseString dataUsingEncoding:NSUTF8StringEncoding]) { + NSError *error = NULL; + + NSDictionary *feedDict = (NSDictionary *)[NSJSONSerialization JSONObjectWithData:[responseString dataUsingEncoding:NSUTF8StringEncoding] options:kNilOptions error:&error]; + + // server returned empty response? + if (error) { + [self reportError:error]; + } else if (![feedDict count]) { [self reportError:[NSError errorWithDomain:kBITFeedbackErrorDomain - code:BITFeedbackAPIServerReturnedInvalidStatus - userInfo:[NSDictionary dictionaryWithObjectsAndKeys:@"Server returned invalid status.", NSLocalizedDescriptionKey, nil]]]; + code:BITFeedbackAPIServerReturnedEmptyResponse + userInfo:[NSDictionary dictionaryWithObjectsAndKeys:@"Server returned empty response.", NSLocalizedDescriptionKey, nil]]]; } else { - [self updateMessageListFromResponse:feedDict]; + BITHockeyLog(@"INFO: Received API response: %@", responseString); + NSString *status = [feedDict objectForKey:@"status"]; + if ([status compare:@"success"] != NSOrderedSame) { + [self reportError:[NSError errorWithDomain:kBITFeedbackErrorDomain + code:BITFeedbackAPIServerReturnedInvalidStatus + userInfo:[NSDictionary dictionaryWithObjectsAndKeys:@"Server returned invalid status.", NSLocalizedDescriptionKey, nil]]]; + } else { + [self updateMessageListFromResponse:feedDict]; + } } } } diff --git a/Classes/BITUpdateManager.m b/Classes/BITUpdateManager.m index 0926b510..23d8403e 100644 --- a/Classes/BITUpdateManager.m +++ b/Classes/BITUpdateManager.m @@ -584,43 +584,45 @@ - (void)checkForAuthorization { if ([responseData length]) { NSString *responseString = [[NSString alloc] initWithBytes:[responseData bytes] length:[responseData length] encoding: NSUTF8StringEncoding]; - NSDictionary *feedDict = (NSDictionary *)[NSJSONSerialization JSONObjectWithData:[responseString dataUsingEncoding:NSUTF8StringEncoding] options:kNilOptions error:&error]; - - // server returned empty response? - if (![feedDict count]) { - [self reportError:[NSError errorWithDomain:kBITUpdateErrorDomain - code:BITUpdateAPIServerReturnedEmptyResponse - userInfo:[NSDictionary dictionaryWithObjectsAndKeys:@"Server returned empty response.", NSLocalizedDescriptionKey, nil]]]; - return; - } else { - BITHockeyLog(@"INFO: Received API response: %@", responseString); - NSString *token = [[feedDict objectForKey:@"authcode"] lowercaseString]; - failed = NO; - if ([[self authenticationToken] compare:token] == NSOrderedSame) { - // identical token, activate this version - - // store the new data - [[NSUserDefaults standardUserDefaults] setObject:[[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleVersion"] forKey:kBITUpdateAuthorizedVersion]; - [[NSUserDefaults standardUserDefaults] setObject:token forKey:kBITUpdateAuthorizedToken]; - [[NSUserDefaults standardUserDefaults] synchronize]; - - self.requireAuthorization = NO; - self.blockingView = nil; - - // now continue with an update check right away - if (self.checkForUpdateOnLaunch) { - [self checkForUpdate]; - } + if (responseString && [responseString dataUsingEncoding:NSUTF8StringEncoding]) { + NSDictionary *feedDict = (NSDictionary *)[NSJSONSerialization JSONObjectWithData:[responseString dataUsingEncoding:NSUTF8StringEncoding] options:kNilOptions error:&error]; + + // server returned empty response? + if (![feedDict count]) { + [self reportError:[NSError errorWithDomain:kBITUpdateErrorDomain + code:BITUpdateAPIServerReturnedEmptyResponse + userInfo:[NSDictionary dictionaryWithObjectsAndKeys:@"Server returned empty response.", NSLocalizedDescriptionKey, nil]]]; + return; } else { - // different token, block this version - BITHockeyLog(@"INFO: AUTH FAILURE: %@", [self authenticationToken]); - - // store the new data - [[NSUserDefaults standardUserDefaults] setObject:[[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleVersion"] forKey:kBITUpdateAuthorizedVersion]; - [[NSUserDefaults standardUserDefaults] setObject:token forKey:kBITUpdateAuthorizedToken]; - [[NSUserDefaults standardUserDefaults] synchronize]; - - [self showBlockingScreen:BITHockeyLocalizedString(@"UpdateAuthorizationDenied") image:@"authorize_denied.png"]; + BITHockeyLog(@"INFO: Received API response: %@", responseString); + NSString *token = [[feedDict objectForKey:@"authcode"] lowercaseString]; + failed = NO; + if ([[self authenticationToken] compare:token] == NSOrderedSame) { + // identical token, activate this version + + // store the new data + [[NSUserDefaults standardUserDefaults] setObject:[[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleVersion"] forKey:kBITUpdateAuthorizedVersion]; + [[NSUserDefaults standardUserDefaults] setObject:token forKey:kBITUpdateAuthorizedToken]; + [[NSUserDefaults standardUserDefaults] synchronize]; + + self.requireAuthorization = NO; + self.blockingView = nil; + + // now continue with an update check right away + if (self.checkForUpdateOnLaunch) { + [self checkForUpdate]; + } + } else { + // different token, block this version + BITHockeyLog(@"INFO: AUTH FAILURE: %@", [self authenticationToken]); + + // store the new data + [[NSUserDefaults standardUserDefaults] setObject:[[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleVersion"] forKey:kBITUpdateAuthorizedVersion]; + [[NSUserDefaults standardUserDefaults] setObject:token forKey:kBITUpdateAuthorizedToken]; + [[NSUserDefaults standardUserDefaults] synchronize]; + + [self showBlockingScreen:BITHockeyLocalizedString(@"UpdateAuthorizationDenied") image:@"authorize_denied.png"]; + } } } @@ -840,6 +842,9 @@ - (void)connectionDidFinishLoading:(NSURLConnection *)connection { NSString *responseString = [[NSString alloc] initWithBytes:[_receivedData bytes] length:[_receivedData length] encoding: NSUTF8StringEncoding]; BITHockeyLog(@"INFO: Received API response: %@", responseString); + if (!responseString || ![responseString dataUsingEncoding:NSUTF8StringEncoding]) + return; + NSError *error = nil; NSDictionary *json = (NSDictionary *)[NSJSONSerialization JSONObjectWithData:[responseString dataUsingEncoding:NSUTF8StringEncoding] options:kNilOptions error:&error]; From 4f02e73e4caeb97047efd3c4d5efa169ba7786fc Mon Sep 17 00:00:00 2001 From: Andreas Linde Date: Wed, 28 Nov 2012 19:02:58 +0100 Subject: [PATCH 123/176] Add croatian localization --- Resources/hr.lproj/HockeySDK.strings | 225 ++++++++++++++++++++ Support/HockeySDK.xcodeproj/project.pbxproj | 3 + 2 files changed, 228 insertions(+) create mode 100644 Resources/hr.lproj/HockeySDK.strings diff --git a/Resources/hr.lproj/HockeySDK.strings b/Resources/hr.lproj/HockeySDK.strings new file mode 100644 index 00000000..82eaf60e --- /dev/null +++ b/Resources/hr.lproj/HockeySDK.strings @@ -0,0 +1,225 @@ +/* General */ + +/* For dialogs yes buttons */ +"HockeyYes" = "Da"; + +/* For dialogs no buttons */ +"HockeyNo" = "Ne"; + +/* For dialogs ok buttons */ +"HockeyOK" = "U redu"; + +/* Replacement for app name, if it could not be detected */ +"HockeyAppNamePlaceholder" = "Ova aplikacija"; + +/* Crash */ + + +/* Crash dialog */ + +/* Title showing in the alert box when crash report data has been found */ +"CrashDataFoundTitle" = "%@ Neočekivani završetak"; + +/* Description explaining that crash data has been found and ask the user if the data might be uploaded to the developers server */ +"CrashDataFoundAnonymousDescription" = "Želite li poslati anonimno izviješće da možemo riješiti problem?"; + +/* Description explaining that crash data has been found and ask the user if the non anonymous data might be uplaoded to the developers server */ +"CrashDataFoundDescription" = "Želite li poslati izviješće da možemo riješiti problem?"; + +/* Alert box button if the users wants to send crash data always automatically */ +"CrashSendReportAlways" = "Uvijek šalji"; + +/* Alert box button to send the crash report once */ +"CrashSendReport" = "Pošalji izvijeće"; + +/* Alert box button to decline sending the report */ +"CrashDontSendReport" = "Ne šalji"; + +/* Text showing in a processing box that the crash data is being uploaded to the server */ +"CrashReportSending" = "Slanje…"; + + +/* Update */ + + +/* Update Alert view */ + +/* Update available */ +"UpdateAvailable" = "Dostupno je ažuriranje"; + +"UpdateAlertTextWithAppVersion" = "%@ je dostupno."; + +"UpdateAlertMandatoryTextWithAppVersion" = "%@ je dostupno i obavezno je ažuriranje!"; + +"UpdateIgnore" = "Zanemari"; + +"UpdateShow" = "Prikaz"; + +"UpdateInstall" = "Instaliraj"; + + +/* Update Details */ + +"UpdateScreenTitle" = "Ažuriranje"; + +"UpdateButtonCheck" = "PROVJERA"; + +"UpdateButtonSearching" = "PROVJERA"; + +"UpdateButtonUpdate" = "AŽURIRANJE"; + +"UpdateButtonInstalling" = "INSTALIRANJE"; + +"UpdateButtonOffline" = "VAN MREŽE"; + +"UpdateInstalled" = "INSTALIRANO"; + +"UpdateVersion" = "Verzija"; + +"UpdateShowPreviousVersions" = "Prikaz prethodnih verzija..."; + +"UpdateNoUpdateAvailableTitle" = "Ažuriranja nisu dostupna"; + +"UpdateNoUpdateAvailableMessage" = "%@ je već najnovija verzija."; + +"UpdateError" = "Greška"; + +"UpdateWarning" = "Upozorenje"; + +"UpdateNoReleaseNotesAvailable" = "Nisu dostupne bilješke izdanja."; + + +/* Update Authorization */ + +"UpdateAuthorizationProgress" = "Autorizacija..."; + +"UpdateAuthorizationOffline" = "Potrebna je internet veza!"; + +"UpdateAuthorizationDenied" = "Autorizacija je odbijena. Molimo obratite se developeru."; + + +/* Update Expiry */ + +"UpdateExpired" = "%@ je isteklo i ne može se više koristiti."; + + +/* Update Simulator Warning */ + +"UpdateSimulatorMessage" = "Hockey ažuriranje ne radi u Simulatoru.\nThe itms-services:// url scheme is implemented but nonfunctional."; + + +/* Feedback */ + + +/* New Message Alert */ + +/* Alert Title */ +"HockeyFeedbackNewMessageTitle" = "Novi odgovor na povratnu informaciju"; + +/* Alert Text */ +"HockeyFeedbackNewMessageText" = "Dostupan je novi odgovor na Vašu povratnu informaciju. Želite li ga pogledati?"; + +/* Alert Ignore Button */ +"HockeyFeedbackIgnore" = "Zanemari"; + +/* Alert Show Button */ +"HockeyFeedbackShow" = "Prikaži"; + + +/* List View */ + +/* Title */ +"HockeyFeedbackListTitle" = "Povratna informacija"; + +/* Last Updated */ +"HockeyFeedbackListLastUpdated" = "Zadnje ažuriranje: %@"; + +/* Never Updated */ +"HockeyFeedbackListNeverUpdated" = "Nikada"; + +/* Provide Feedback Button Title */ +"HockeyFeedbackListButonWriteFeedback" = "Osigurajte povratnu informaciju"; + +/* Add a Response Button Title */ +"HockeyFeedbackListButonWriteResponse" = "Dodaj odgovor"; + +/* User Data Set Name Button Title */ +"HockeyFeedbackListButonUserDataSetName" = "Postavite Vaše ime"; + +/* User Data Set Email Button Title */ +"HockeyFeedbackListButonUserDataSetEmail" = "Postavite Vaš Email"; + +/* User Data With Name Button Title */ +"HockeyFeedbackListButonUserDataWithName" = "Ime: %@"; + +/* User Data With Email Button Title */ +"HockeyFeedbackListButonUserDataWithEmail" = "Email: %@"; + +/* Button title for deleting all local messages*/ +"HockeyFeedbackListButonDeleteAllMessages" = "Obriši sve poruke"; + +/* Message pending to be send */ +"HockeyFeedbackListMessagePending" = "Čekanje"; + + +/* Delete All Messages Action Sheet / Alert View */ + +/* Title for the Action Sheet */ +"HockeyFeedbackListDeleteAllTitle" = "Ovo će obrisati sve poruke na ovom uređaju."; + +/* Button Title to perform delete action */ +"HockeyFeedbackListDeleteAllDelete" = "Obriši"; + +/* Button Title to cancel delete action */ +"HockeyFeedbackListDeleteAllCancel" = "Prekid"; + + +/* Open Link In Safari Action Sheet / Alert View */ + +/* Button Title to cancel */ +"HockeyFeedbackListLinkActionCancel" = "Prekid"; + +/* Button Title to Open the Link */ +"HockeyFeedbackListLinkActionOpen" = "Otvori"; + +/* Button Title to Copy the Link */ +"HockeyFeedbackListLinkActionCopy" = "Kopiraj"; + + +/* UIActivity */ + +/* Activity Sharing Button Title, App Name will be inserted */ +"HockeyFeedbackActivityButtonTitle" = "%@ Povratna informacija"; + +/* if there can no app name be found, use this instead for HockeyFeedbackActivityButtonTitle */ +"HockeyFeedbackActivityAppPlaceholder" = "Aplikacija"; + + +/* Compose Message */ + +/* Title */ +"HockeyFeedbackComposeTitle" = "Nova povratna informacija"; + +/* Send button */ +"HockeyFeedbackComposeSend" = "Šalji"; + + +/* Set User Data */ + +/* Title */ +"HockeyFeedbackUserDataTitle" = "Moj info"; + +/* Description On What Should Be Entered */ +"HockeyFeedbackUserDataDescription" = "Prije pisanja povratne informacije navedite svoje podatke."; + +/* Name Field */ +"HockeyFeedbackUserDataName" = "Ime"; + +/* Name Placeholder */ +"HockeyFeedbackUserDataNamePlaceHolder" = "John Doe"; + +/* Email Field */ +"HockeyFeedbackUserDataEmail" = "Email"; + +/* Email Placeholder */ +"HockeyFeedbackUserDataEmailPlaceholder" = "example@email.com"; diff --git a/Support/HockeySDK.xcodeproj/project.pbxproj b/Support/HockeySDK.xcodeproj/project.pbxproj index 19cccc85..b5df5842 100644 --- a/Support/HockeySDK.xcodeproj/project.pbxproj +++ b/Support/HockeySDK.xcodeproj/project.pbxproj @@ -138,6 +138,7 @@ 1E1127C116580C87007067A2 /* buttonRoundedRegular@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "buttonRoundedRegular@2x.png"; sourceTree = ""; }; 1E1127C216580C87007067A2 /* buttonRoundedRegularHighlighted.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = buttonRoundedRegularHighlighted.png; sourceTree = ""; }; 1E1127C316580C87007067A2 /* buttonRoundedRegularHighlighted@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "buttonRoundedRegularHighlighted@2x.png"; sourceTree = ""; }; + 1E36D8B816667611000B134C /* hr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = hr; path = hr.lproj/HockeySDK.strings; sourceTree = ""; }; 1E49A42D1612223B00463151 /* BITFeedbackComposeViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BITFeedbackComposeViewController.h; sourceTree = ""; }; 1E49A42E1612223B00463151 /* BITFeedbackComposeViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = BITFeedbackComposeViewController.m; sourceTree = ""; }; 1E49A42F1612223B00463151 /* BITFeedbackListViewCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BITFeedbackListViewCell.h; sourceTree = ""; }; @@ -534,6 +535,7 @@ zh_TW, "zh-Hans", "zh-Hant", + hr, ); mainGroup = E400560F148D79B500EB22B9; productRefGroup = E400561B148D79B500EB22B9 /* Products */; @@ -679,6 +681,7 @@ 1E59557615B6F85E00A03429 /* tr */, 1E59557815B6F86600A03429 /* zh_CN */, 1E59557A15B6F86E00A03429 /* zh_TW */, + 1E36D8B816667611000B134C /* hr */, ); name = HockeySDK.strings; sourceTree = ""; From 1712e8854b7d189f5155f9fde844ff15aec86094 Mon Sep 17 00:00:00 2001 From: Andreas Linde Date: Wed, 28 Nov 2012 23:21:20 +0100 Subject: [PATCH 124/176] Clean this up! Thanks @tewha :) --- Classes/BITHockeyManager.m | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/Classes/BITHockeyManager.m b/Classes/BITHockeyManager.m index 082cfb97..728a20af 100644 --- a/Classes/BITHockeyManager.m +++ b/Classes/BITHockeyManager.m @@ -103,14 +103,10 @@ - (id) init { _startManagerIsInvoked = NO; // check if we are really not in an app store environment - if ([[NSBundle mainBundle] pathForResource:@"embedded" ofType:@"mobileprovision"]) { - _appStoreEnvironment = NO; - } else { +#if !TARGET_IPHONE_SIMULATOR + if (![[NSBundle mainBundle] pathForResource:@"embedded" ofType:@"mobileprovision"]) { _appStoreEnvironment = YES; } - -#if TARGET_IPHONE_SIMULATOR - _appStoreEnvironment = NO; #endif [self performSelector:@selector(validateStartManagerIsInvoked) withObject:nil afterDelay:0.0f]; From 816bbb5dd91caa95345766b01aef307c2c77a469 Mon Sep 17 00:00:00 2001 From: Andreas Linde Date: Wed, 28 Nov 2012 23:21:33 +0100 Subject: [PATCH 125/176] Finish german localization --- Resources/de.lproj/HockeySDK.strings | 48 ++++++++++++++-------------- 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/Resources/de.lproj/HockeySDK.strings b/Resources/de.lproj/HockeySDK.strings index dd7227ed..8834821c 100755 --- a/Resources/de.lproj/HockeySDK.strings +++ b/Resources/de.lproj/HockeySDK.strings @@ -79,7 +79,7 @@ "UpdateShowPreviousVersions" = "Zeige frühere Versionen..."; -"UpdateNoUpdateAvailableTitle" = "Kein Update Verfügbar"; +"UpdateNoUpdateAvailableTitle" = "Kein Update verfügbar"; "UpdateNoUpdateAvailableMessage" = "%@ ist bereits die aktuellste Version."; @@ -117,16 +117,16 @@ /* New Message Alert */ /* Alert Title */ -"HockeyFeedbackNewMessageTitle" = "New Feedback Response"; +"HockeyFeedbackNewMessageTitle" = "Neue Antwort verfügbar"; /* Alert Text */ -"HockeyFeedbackNewMessageText" = "A new response to your feedback is available. Would you like to view it?"; +"HockeyFeedbackNewMessageText" = "Eine neue Antwort auf Ihr Feedback ist angekommen. Möchten Sie diese anschauen?"; /* Alert Ignore Button */ -"HockeyFeedbackIgnore" = "Ignore"; +"HockeyFeedbackIgnore" = "Ignorieren"; /* Alert Show Button */ -"HockeyFeedbackShow" = "Show"; +"HockeyFeedbackShow" = "Anzeigen"; /* List View */ @@ -135,22 +135,22 @@ "HockeyFeedbackListTitle" = "Feedback"; /* Last Updated */ -"HockeyFeedbackListLastUpdated" = "Last Updated: %@"; +"HockeyFeedbackListLastUpdated" = "Letzte Aktualisierung: %@"; /* Never Updated */ -"HockeyFeedbackListNeverUpdated" = "Never"; +"HockeyFeedbackListNeverUpdated" = "Nie"; /* Provide Feedback Button Title */ -"HockeyFeedbackListButonWriteFeedback" = "Provide Feedback"; +"HockeyFeedbackListButonWriteFeedback" = "Feedback schreiben"; /* Add a Response Button Title */ -"HockeyFeedbackListButonWriteResponse" = "Add a Response"; +"HockeyFeedbackListButonWriteResponse" = "Antwort hinzufügen"; /* User Data Set Name Button Title */ -"HockeyFeedbackListButonUserDataSetName" = "Set Your Name"; +"HockeyFeedbackListButonUserDataSetName" = "Ihren Name eintragen"; /* User Data Set Email Button Title */ -"HockeyFeedbackListButonUserDataSetEmail" = "Set Your Email"; +"HockeyFeedbackListButonUserDataSetEmail" = "Ihre Email eintragen"; /* User Data With Name Button Title */ "HockeyFeedbackListButonUserDataWithName" = "Name: %@"; @@ -159,7 +159,7 @@ "HockeyFeedbackListButonUserDataWithEmail" = "Email: %@"; /* Button title for deleting all local messages*/ -"HockeyFeedbackListButonDeleteAllMessages" = "Delete All Messages"; +"HockeyFeedbackListButonDeleteAllMessages" = "Alle Nachrichten löchen"; /* Message pending to be send */ "HockeyFeedbackListMessagePending" = "Pending"; @@ -168,25 +168,25 @@ /* Delete All Messages Action Sheet / Alert View */ /* Title for the Action Sheet */ -"HockeyFeedbackListDeleteAllTitle" = "This will delete all messages on this device."; +"HockeyFeedbackListDeleteAllTitle" = "Dies wird alle Nachrichten löschen."; /* Button Title to perform delete action */ -"HockeyFeedbackListDeleteAllDelete" = "Delete"; +"HockeyFeedbackListDeleteAllDelete" = "Löschen"; /* Button Title to cancel delete action */ -"HockeyFeedbackListDeleteAllCancel" = "Cancel"; +"HockeyFeedbackListDeleteAllCancel" = "Abbrechen"; /* Open/Copy Link In Safari Action Sheet / Alert View */ /* Button Title to cancel */ -"HockeyFeedbackListLinkActionCancel" = "Cancel"; +"HockeyFeedbackListLinkActionCancel" = "Abbrechen"; /* Button Title to Open the Link */ -"HockeyFeedbackListLinkActionOpen" = "Open"; +"HockeyFeedbackListLinkActionOpen" = "Öffnen"; /* Button Title to Copy the Link */ -"HockeyFeedbackListLinkActionCopy" = "Copy"; +"HockeyFeedbackListLinkActionCopy" = "Kopieren"; /* UIActivity */ @@ -201,28 +201,28 @@ /* Compose Message */ /* Title */ -"HockeyFeedbackComposeTitle" = "New Feedback"; +"HockeyFeedbackComposeTitle" = "Neues Feedback"; /* Send button */ -"HockeyFeedbackComposeSend" = "Send"; +"HockeyFeedbackComposeSend" = "Absenden"; /* Set User Data */ /* Title */ -"HockeyFeedbackUserDataTitle" = "My Info"; +"HockeyFeedbackUserDataTitle" = "Über mich"; /* Description On What Should Be Entered */ -"HockeyFeedbackUserDataDescription" = "Please provide your information before writing your feedback."; +"HockeyFeedbackUserDataDescription" = "Bitte tragen Sie ihre Daten ein bevor Sie eine Nachricht schreiben."; /* Name Field */ "HockeyFeedbackUserDataName" = "Name"; /* Name Placeholder */ -"HockeyFeedbackUserDataNamePlaceHolder" = "John Doe"; +"HockeyFeedbackUserDataNamePlaceHolder" = "Klaus Mustermann"; /* Email Field */ "HockeyFeedbackUserDataEmail" = "Email"; /* Email Placeholder */ -"HockeyFeedbackUserDataEmailPlaceholder" = "example@email.com"; +"HockeyFeedbackUserDataEmailPlaceholder" = "beispiel@email.com"; From 679112f3ccbf4a5fed0129f7d039d01ee070c880 Mon Sep 17 00:00:00 2001 From: Andreas Linde Date: Wed, 28 Nov 2012 23:26:08 +0100 Subject: [PATCH 126/176] Oh documentation *doh* --- Classes/BITHockeyManager.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Classes/BITHockeyManager.m b/Classes/BITHockeyManager.m index 728a20af..fb418bef 100644 --- a/Classes/BITHockeyManager.m +++ b/Classes/BITHockeyManager.m @@ -102,8 +102,8 @@ - (id) init { _appStoreEnvironment = NO; _startManagerIsInvoked = NO; - // check if we are really not in an app store environment #if !TARGET_IPHONE_SIMULATOR + // check if we are really in an app store environment if (![[NSBundle mainBundle] pathForResource:@"embedded" ofType:@"mobileprovision"]) { _appStoreEnvironment = YES; } From c9c66390ef91fbe48b2e00fff8058cab755b5578 Mon Sep 17 00:00:00 2001 From: Andreas Linde Date: Sun, 2 Dec 2012 02:00:13 +0100 Subject: [PATCH 127/176] Add usage of barStyle and tintColor to Activity, compose and user data views --- Classes/BITFeedbackActivity.m | 4 ++- Classes/BITFeedbackComposeViewController.m | 11 ++++-- Classes/BITFeedbackListViewController.m | 4 +++ Classes/BITFeedbackUserDataViewController.m | 38 ++++++++++++--------- 4 files changed, 37 insertions(+), 20 deletions(-) diff --git a/Classes/BITFeedbackActivity.m b/Classes/BITFeedbackActivity.m index 82c07dfc..269b5b94 100644 --- a/Classes/BITFeedbackActivity.m +++ b/Classes/BITFeedbackActivity.m @@ -92,7 +92,9 @@ - (UIViewController *)activityViewController { [composeViewController prepareWithItems:_items]; UINavigationController *navController = [[UINavigationController alloc] initWithRootViewController: composeViewController]; - navController.modalPresentationStyle = UIModalPresentationFormSheet; + navController.navigationBar.barStyle = [[[BITHockeyManager sharedHockeyManager] feedbackManager] barStyle]; + navController.navigationBar.tintColor = [[[BITHockeyManager sharedHockeyManager] feedbackManager] tintColor]; + navController.modalPresentationStyle = UIModalPresentationFormSheet; navController.modalTransitionStyle = UIModalTransitionStyleCrossDissolve; return navController; diff --git a/Classes/BITFeedbackComposeViewController.m b/Classes/BITFeedbackComposeViewController.m index 655e0386..9cc68345 100644 --- a/Classes/BITFeedbackComposeViewController.m +++ b/Classes/BITFeedbackComposeViewController.m @@ -37,15 +37,15 @@ #import "BITHockeyHelper.h" -@interface BITFeedbackComposeViewController () +@interface BITFeedbackComposeViewController () { + UIStatusBarStyle _statusBarStyle; +} @property (nonatomic, weak) BITFeedbackManager *manager; @property (nonatomic, strong) UITextView *textView; @property (nonatomic, strong) NSString *text; -- (void)setUserDataAction; - @end @@ -166,6 +166,7 @@ - (void)viewWillAppear:(BOOL)animated { [super viewWillAppear:animated]; + _statusBarStyle = [[UIApplication sharedApplication] statusBarStyle]; [[UIApplication sharedApplication] setStatusBarStyle:(self.navigationController.navigationBar.barStyle == UIBarStyleDefault) ? UIStatusBarStyleDefault : UIStatusBarStyleBlackOpaque]; [self.textView setFrame:self.view.frame]; @@ -199,6 +200,8 @@ - (void)viewWillDisappear:(BOOL)animated { self.manager.currentFeedbackComposeViewController = nil; [super viewWillDisappear:animated]; + + [[UIApplication sharedApplication] setStatusBarStyle:_statusBarStyle]; } - (void)viewDidDisappear:(BOOL)animated { @@ -228,6 +231,8 @@ - (void)setUserDataAction { userController.delegate = self; UINavigationController *navController = [[UINavigationController alloc] initWithRootViewController:userController]; + navController.navigationBar.barStyle = [self.manager barStyle]; + navController.navigationBar.tintColor = [self.manager tintColor]; navController.modalPresentationStyle = UIModalPresentationFormSheet; [self presentViewController:navController animated:YES completion:nil]; diff --git a/Classes/BITFeedbackListViewController.m b/Classes/BITFeedbackListViewController.m index ff0b36cb..4541de48 100644 --- a/Classes/BITFeedbackListViewController.m +++ b/Classes/BITFeedbackListViewController.m @@ -201,6 +201,8 @@ - (void)setUserDataAction:(id)sender { userController.delegate = self; UINavigationController *navController = [[UINavigationController alloc] initWithRootViewController:userController]; + navController.navigationBar.barStyle = [self.manager barStyle]; + navController.navigationBar.tintColor = [self.manager tintColor]; navController.modalPresentationStyle = UIModalPresentationFormSheet; [self presentViewController:navController animated:YES completion:nil]; @@ -210,6 +212,8 @@ - (void)newFeedbackAction:(id)sender { BITFeedbackComposeViewController *composeController = [[BITFeedbackComposeViewController alloc] init]; UINavigationController *navController = [[UINavigationController alloc] initWithRootViewController:composeController]; + navController.navigationBar.barStyle = [self.manager barStyle]; + navController.navigationBar.tintColor = [self.manager tintColor]; navController.modalPresentationStyle = UIModalPresentationFormSheet; [self presentViewController:navController animated:YES completion:nil]; diff --git a/Classes/BITFeedbackUserDataViewController.m b/Classes/BITFeedbackUserDataViewController.m index 346b341a..ca3cf08b 100644 --- a/Classes/BITFeedbackUserDataViewController.m +++ b/Classes/BITFeedbackUserDataViewController.m @@ -33,7 +33,10 @@ #import "BITFeedbackUserDataViewController.h" #import "BITFeedbackManagerPrivate.h" -@interface BITFeedbackUserDataViewController () +@interface BITFeedbackUserDataViewController () { + UIStatusBarStyle _statusBarStyle; +} + @property (nonatomic, weak) BITFeedbackManager *manager; @property (nonatomic, copy) NSString *name; @@ -62,25 +65,22 @@ - (void)viewDidLoad { [super viewDidLoad]; [self.tableView setScrollEnabled:NO]; - - // Do any additional setup after loading the view. - self.navigationItem.leftBarButtonItem = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemCancel - target:self - action:@selector(dismissAction:)]; - - self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemSave - target:self - action:@selector(saveAction:)]; -} - -- (void)viewDidUnload { - [super viewDidUnload]; - // Release any retained subviews of the main view. - // e.g. self.myOutlet = nil; } - (void)viewWillAppear:(BOOL)animated { [super viewWillAppear:animated]; + + _statusBarStyle = [[UIApplication sharedApplication] statusBarStyle]; + [[UIApplication sharedApplication] setStatusBarStyle:(self.navigationController.navigationBar.barStyle == UIBarStyleDefault) ? UIStatusBarStyleDefault : UIStatusBarStyleBlackOpaque]; + + // Do any additional setup after loading the view. + self.navigationItem.leftBarButtonItem = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemCancel + target:self + action:@selector(dismissAction:)]; + + self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemSave + target:self + action:@selector(saveAction:)]; if ([self.manager userName]) self.name = [self.manager userName]; @@ -93,6 +93,12 @@ - (void)viewWillAppear:(BOOL)animated { self.navigationItem.rightBarButtonItem.enabled = [self allRequiredFieldsEntered]; } +- (void)viewWillDisappear:(BOOL)animated { + [super viewWillDisappear:animated]; + + [[UIApplication sharedApplication] setStatusBarStyle:_statusBarStyle]; +} + #pragma mark - UIViewController Rotation - (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)orientation { From 90ecf7311d3b440878dac17f24218c096d1e6a6b Mon Sep 17 00:00:00 2001 From: Andreas Linde Date: Sun, 2 Dec 2012 02:01:10 +0100 Subject: [PATCH 128/176] On first feedback list view appearance, show the user data (if needed) and compose view automatically Instead of modal presentation, show them pushed on the navigation stack --- Classes/BITFeedbackListViewController.m | 53 ++++++++++++++++++++++--- 1 file changed, 48 insertions(+), 5 deletions(-) diff --git a/Classes/BITFeedbackListViewController.m b/Classes/BITFeedbackListViewController.m index 4541de48..ea5fb9f4 100644 --- a/Classes/BITFeedbackListViewController.m +++ b/Classes/BITFeedbackListViewController.m @@ -58,10 +58,11 @@ #define BORDER_COLOR BIT_RGBCOLOR(215, 215, 215) -@interface BITFeedbackListViewController () +@interface BITFeedbackListViewController () @property (nonatomic, weak) BITFeedbackManager *manager; @property (nonatomic, strong) NSDateFormatter *lastUpdateDateFormatter; +@property (nonatomic) BOOL userDataComposeFlow; @end @@ -77,6 +78,7 @@ - (id)init { _deleteButtonSection = -1; _userButtonSection = -1; + _userDataComposeFlow = NO; self.lastUpdateDateFormatter = [[NSDateFormatter alloc] init]; [self.lastUpdateDateFormatter setDateStyle:NSDateFormatterShortStyle]; @@ -169,7 +171,10 @@ - (void)updateList { CGPoint contentOffset = self.tableView.contentOffset; [self.tableView reloadData]; - if (contentSize.height > 0 && self.tableView.contentSize.height > contentSize.height && ![self isRefreshingWithNewControl]) + if (contentSize.height > 0 && + self.tableView.contentSize.height > self.tableView.frame.size.height && + self.tableView.contentSize.height > contentSize.height && + ![self isRefreshingWithNewControl]) [self.tableView setContentOffset:CGPointMake(contentOffset.x, self.tableView.contentSize.height - contentSize.height + contentOffset.y) animated:NO]; [self stopLoadingIndicator]; @@ -178,11 +183,27 @@ - (void)updateList { } - (void)viewWillAppear:(BOOL)animated { + if (self.userDataComposeFlow) { + self.userDataComposeFlow = NO; + } self.manager.currentFeedbackListViewController = self; [self.manager updateMessagesListIfRequired]; - [self.tableView reloadData]; + if ([self.manager numberOfMessages] == 0 && + [self.manager askManualUserDataAvailable] && + ([self.manager requireManualUserDataMissing] || + ![self.manager didAskUserData]) + ) { + self.userDataComposeFlow = YES; + + BITFeedbackUserDataViewController *userController = [[BITFeedbackUserDataViewController alloc] initWithStyle:UITableViewStyleGrouped]; + userController.delegate = self; + + [self.navigationController pushViewController:userController animated:NO]; + } else { + [self.tableView reloadData]; + } [super viewWillAppear:animated]; } @@ -251,13 +272,35 @@ - (void)deleteAllMessagesAction:(id)sender { #pragma mark - BITFeedbackUserDataDelegate -(void)userDataUpdateCancelled { - [self dismissViewControllerAnimated:YES completion:^(void){}]; + if (self.userDataComposeFlow) { + [self.navigationController popToViewController:self animated:YES]; + } else { + [self dismissViewControllerAnimated:YES completion:^(void){}]; + } } -(void)userDataUpdateFinished { [self.manager saveMessages]; - [self dismissViewControllerAnimated:YES completion:^(void){}]; + if (self.userDataComposeFlow) { + BITFeedbackComposeViewController *composeController = [[BITFeedbackComposeViewController alloc] init]; + composeController.delegate = self; + + [self.navigationController pushViewController:composeController animated:YES]; + } else { + [self dismissViewControllerAnimated:YES completion:^(void){}]; + } +} + + +#pragma mark - BITFeedbackComposeViewControllerDelegate + +- (void)feedbackComposeViewControllerDidFinish:(BITFeedbackComposeViewController *)composeViewController { + if (self.userDataComposeFlow) { + [self.navigationController popToViewController:self animated:YES]; + } else { + [self dismissViewControllerAnimated:YES completion:^(void){}]; + } } From 792ed5d5b23de919db32e2b2f58b1cafa80bf276 Mon Sep 17 00:00:00 2001 From: felixLam Date: Mon, 3 Dec 2012 16:07:46 +0100 Subject: [PATCH 129/176] Fixes validation of email addresses containing upper case characters --- Classes/BITFeedbackUserDataViewController.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Classes/BITFeedbackUserDataViewController.m b/Classes/BITFeedbackUserDataViewController.m index ca3cf08b..8aa54409 100644 --- a/Classes/BITFeedbackUserDataViewController.m +++ b/Classes/BITFeedbackUserDataViewController.m @@ -116,7 +116,7 @@ - (BOOL)validateEmail { @"]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-" @"9][0-9]?|[a-z0-9-]*[a-z0-9]:(?:[\\x01-\\x08\\x0b\\x0c\\x0e-\\x1f\\x21" @"-\\x5a\\x53-\\x7f]|\\\\[\\x01-\\x09\\x0b\\x0c\\x0e-\\x7f])+)\\])"; - NSPredicate *emailTest = [NSPredicate predicateWithFormat:@"SELF MATCHES %@", emailRegex]; + NSPredicate *emailTest = [NSPredicate predicateWithFormat:@"SELF MATCHES[c] %@", emailRegex]; return [emailTest evaluateWithObject:self.email]; } From b00db4e9e807e884b34fb35c1867355a19f4c68c Mon Sep 17 00:00:00 2001 From: Andreas Linde Date: Mon, 3 Dec 2012 16:58:46 +0100 Subject: [PATCH 130/176] Fix *doh* --- Classes/BITFeedbackManager.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Classes/BITFeedbackManager.m b/Classes/BITFeedbackManager.m index 9809bff7..d4d2212b 100644 --- a/Classes/BITFeedbackManager.m +++ b/Classes/BITFeedbackManager.m @@ -215,7 +215,7 @@ - (BOOL)updateUserIDUsingDelegate { NSString *userID = [[BITHockeyManager sharedHockeyManager].delegate userIDForHockeyManager:[BITHockeyManager sharedHockeyManager] componentManager:self]; - if (self.userID) { + if (userID) { self.userID = userID; availableViaDelegate = YES; } From 8857fcfecb0ce7e36e939c122677e6e0cb9b6026 Mon Sep 17 00:00:00 2001 From: Stephan Diederich Date: Tue, 4 Dec 2012 00:54:37 +0100 Subject: [PATCH 131/176] fix UIActionSheet now showing in UIScrollView if the BITFeedbackListViewController's view is contained in a scrollview, the UIActionSheet if offset by the contentOffset when presented. But as the action sheet is presented in a separate window, that offset moves it out of the view. Instead, show the action sheet in the window's rootViewController's view. --- Classes/BITFeedbackListViewController.m | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/Classes/BITFeedbackListViewController.m b/Classes/BITFeedbackListViewController.m index ea5fb9f4..6cc1bdff 100644 --- a/Classes/BITFeedbackListViewController.m +++ b/Classes/BITFeedbackListViewController.m @@ -255,7 +255,7 @@ - (void)deleteAllMessagesAction:(id)sender { ]; [deleteAction setTag:0]; [deleteAction setActionSheetStyle:UIActionSheetStyleBlackTranslucent]; - [deleteAction showInView:self.view]; + [deleteAction showInView:[self viewForShowingActionSheetOnPhone]]; } else { UIAlertView *deleteAction = [[UIAlertView alloc] initWithTitle:BITHockeyLocalizedString(@"HockeyFeedbackListButonDeleteAllMessages") message:BITHockeyLocalizedString(@"HockeyFeedbackListDeleteAllTitle") @@ -268,6 +268,18 @@ - (void)deleteAllMessagesAction:(id)sender { } } +- (UIView*) viewForShowingActionSheetOnPhone { + if(self.view.window.rootViewController) { + //try to show it in the rootviewcontroller's view + //so it covers the UITabBar or works if this + //controller is inside a UIScrollView + return self.view.window.rootViewController.view; + } else { + //hope for the best. Should work + //on simple view(controller) hierarchies + return self.view; + } +} #pragma mark - BITFeedbackUserDataDelegate @@ -552,7 +564,7 @@ - (void)attributedLabel:(BITAttributedLabel *)label didSelectLinkWithURL:(NSURL ]; [linkAction setTag:1]; [linkAction setActionSheetStyle:UIActionSheetStyleBlackTranslucent]; - [linkAction showInView:self.view]; + [linkAction showInView:[self viewForShowingActionSheetOnPhone]]; } else { UIAlertView *linkAction = [[UIAlertView alloc] initWithTitle:[url absoluteString] message:nil From 2de6ed5e8c3935ba60ac1a18472ab7c3f0ec2b82 Mon Sep 17 00:00:00 2001 From: Stephan Diederich Date: Tue, 4 Dec 2012 01:43:10 +0100 Subject: [PATCH 132/176] fix UIActionSheet rotation when presented modally if the BITFeedbackListViewController is presented modally (via a UINavigationController) the action sheet should show in that view. Basically search for the root- or topmost presented view controller. --- Classes/BITFeedbackListViewController.m | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/Classes/BITFeedbackListViewController.m b/Classes/BITFeedbackListViewController.m index 6cc1bdff..a8e42032 100644 --- a/Classes/BITFeedbackListViewController.m +++ b/Classes/BITFeedbackListViewController.m @@ -269,16 +269,21 @@ - (void)deleteAllMessagesAction:(id)sender { } - (UIView*) viewForShowingActionSheetOnPhone { - if(self.view.window.rootViewController) { - //try to show it in the rootviewcontroller's view - //so it covers the UITabBar or works if this - //controller is inside a UIScrollView - return self.view.window.rootViewController.view; - } else { + //find the topmost presented viewcontroller + //and use its view + UIViewController* topMostPresentedViewController = self.view.window.rootViewController; + while(topMostPresentedViewController.presentedViewController) { + topMostPresentedViewController = topMostPresentedViewController.presentedViewController; + } + UIView* view = topMostPresentedViewController.view; + + if(nil == view) { //hope for the best. Should work //on simple view(controller) hierarchies - return self.view; + view = self.view; } + + return view; } #pragma mark - BITFeedbackUserDataDelegate From baf36227ce60e65d8240e628a9f82735b91ba234 Mon Sep 17 00:00:00 2001 From: Andreas Linde Date: Tue, 4 Dec 2012 23:24:30 +0100 Subject: [PATCH 133/176] Fix feedback UI problems on the first appearance when shown in a navigation stack --- Classes/BITFeedbackListViewController.m | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Classes/BITFeedbackListViewController.m b/Classes/BITFeedbackListViewController.m index a8e42032..654d9cc3 100644 --- a/Classes/BITFeedbackListViewController.m +++ b/Classes/BITFeedbackListViewController.m @@ -182,7 +182,7 @@ - (void)updateList { [self.tableView flashScrollIndicators]; } -- (void)viewWillAppear:(BOOL)animated { +- (void)viewDidAppear:(BOOL)animated { if (self.userDataComposeFlow) { self.userDataComposeFlow = NO; } @@ -200,12 +200,12 @@ - (void)viewWillAppear:(BOOL)animated { BITFeedbackUserDataViewController *userController = [[BITFeedbackUserDataViewController alloc] initWithStyle:UITableViewStyleGrouped]; userController.delegate = self; - [self.navigationController pushViewController:userController animated:NO]; + [self.navigationController pushViewController:userController animated:YES]; } else { [self.tableView reloadData]; } - [super viewWillAppear:animated]; + [super viewDidAppear:animated]; } - (void)viewWillDisappear:(BOOL)animated { From a86d3e5ab5948c8593fa3c464a331ca748b863a5 Mon Sep 17 00:00:00 2001 From: Andreas Linde Date: Wed, 5 Dec 2012 13:53:14 +0100 Subject: [PATCH 134/176] Remove -ObjC from Other Linker flags, since it is not needed any more --- Support/HockeySDK.xcconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Support/HockeySDK.xcconfig b/Support/HockeySDK.xcconfig index f04fd8b4..395516fe 100644 --- a/Support/HockeySDK.xcconfig +++ b/Support/HockeySDK.xcconfig @@ -1,3 +1,3 @@ -OTHER_LDFLAGS=$(inherited) -ObjC -framework CoreText -framework CoreGraphics -framework Foundation -framework QuartzCore -framework SystemConfiguration -weak_framework UIKit +OTHER_LDFLAGS=$(inherited) -framework CoreText -framework CoreGraphics -framework Foundation -framework QuartzCore -framework SystemConfiguration -weak_framework UIKit HOCKEYSDK_DOCSET_NAME=HockeySDK-iOS GCC_PREPROCESSOR_DEFINITIONS=$(inherited) CONFIGURATION_$(CONFIGURATION) \ No newline at end of file From a6b9ddc63875ae8d4d5f06c7e8308d29f1c65ade Mon Sep 17 00:00:00 2001 From: Andreas Linde Date: Thu, 6 Dec 2012 18:12:27 +0100 Subject: [PATCH 135/176] Make sure crash reports incident identifier and key don't have special [] chars and some value The previously shows [] as part of [TODO], since PLCrashReporter didn't fill them out. Having the incident identifier showing a [ or ] char made it impossible to drag it into the Organizer to get it symbolicated in there --- Classes/BITCrashReportTextFormatter.m | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Classes/BITCrashReportTextFormatter.m b/Classes/BITCrashReportTextFormatter.m index bf86d2fa..93a16d66 100644 --- a/Classes/BITCrashReportTextFormatter.m +++ b/Classes/BITCrashReportTextFormatter.m @@ -173,14 +173,14 @@ + (NSString *)stringValueForCrashReport:(PLCrashReport *)report crashReporterKey } { - NSString *reportGUID = @"[TODO]"; + NSString *reportGUID = @"TODO"; if ([report respondsToSelector:@selector(reportInfo)]) { if (report.hasReportInfo && report.reportInfo.reportGUID != nil) reportGUID = report.reportInfo.reportGUID; } - NSString *reporterKey = @"[TODO]"; - if (crashReporterKey) + NSString *reporterKey = @"TODO"; + if (crashReporterKey && [crashReporterKey length] > 0) reporterKey = crashReporterKey; NSString *hardwareModel = @"???"; From 972387439eca56a4b10a4a9b508d305aa85ec098 Mon Sep 17 00:00:00 2001 From: Andreas Linde Date: Thu, 6 Dec 2012 18:56:19 +0100 Subject: [PATCH 136/176] Add shared Xcode schemes to the project --- .../HockeySDK Documentation.xcscheme | 59 +++++++++++++++++++ .../xcschemes/HockeySDK Framework.xcscheme | 59 +++++++++++++++++++ .../xcshareddata/xcschemes/HockeySDK.xcscheme | 59 +++++++++++++++++++ .../xcschemes/HockeySDKResources.xcscheme | 59 +++++++++++++++++++ 4 files changed, 236 insertions(+) create mode 100644 Support/HockeySDK.xcodeproj/xcshareddata/xcschemes/HockeySDK Documentation.xcscheme create mode 100644 Support/HockeySDK.xcodeproj/xcshareddata/xcschemes/HockeySDK Framework.xcscheme create mode 100644 Support/HockeySDK.xcodeproj/xcshareddata/xcschemes/HockeySDK.xcscheme create mode 100644 Support/HockeySDK.xcodeproj/xcshareddata/xcschemes/HockeySDKResources.xcscheme diff --git a/Support/HockeySDK.xcodeproj/xcshareddata/xcschemes/HockeySDK Documentation.xcscheme b/Support/HockeySDK.xcodeproj/xcshareddata/xcschemes/HockeySDK Documentation.xcscheme new file mode 100644 index 00000000..395bf79a --- /dev/null +++ b/Support/HockeySDK.xcodeproj/xcshareddata/xcschemes/HockeySDK Documentation.xcscheme @@ -0,0 +1,59 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Support/HockeySDK.xcodeproj/xcshareddata/xcschemes/HockeySDK Framework.xcscheme b/Support/HockeySDK.xcodeproj/xcshareddata/xcschemes/HockeySDK Framework.xcscheme new file mode 100644 index 00000000..c16899ce --- /dev/null +++ b/Support/HockeySDK.xcodeproj/xcshareddata/xcschemes/HockeySDK Framework.xcscheme @@ -0,0 +1,59 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Support/HockeySDK.xcodeproj/xcshareddata/xcschemes/HockeySDK.xcscheme b/Support/HockeySDK.xcodeproj/xcshareddata/xcschemes/HockeySDK.xcscheme new file mode 100644 index 00000000..d95ed48f --- /dev/null +++ b/Support/HockeySDK.xcodeproj/xcshareddata/xcschemes/HockeySDK.xcscheme @@ -0,0 +1,59 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Support/HockeySDK.xcodeproj/xcshareddata/xcschemes/HockeySDKResources.xcscheme b/Support/HockeySDK.xcodeproj/xcshareddata/xcschemes/HockeySDKResources.xcscheme new file mode 100644 index 00000000..37c5fbb0 --- /dev/null +++ b/Support/HockeySDK.xcodeproj/xcshareddata/xcschemes/HockeySDKResources.xcscheme @@ -0,0 +1,59 @@ + + + + + + + + + + + + + + + + + + + + + + + + + From 2e2342627f5b32530bf78bf26abff9d4bcff948f Mon Sep 17 00:00:00 2001 From: Andreas Linde Date: Thu, 6 Dec 2012 20:05:49 +0100 Subject: [PATCH 137/176] Bump version to 3.0.0b5 Build 15 --- Support/buildnumber.xcconfig | 6 ++--- docs/Changelog-template.md | 28 +++++++++++++++++++++++ docs/Guide-Installation-Setup-template.md | 6 ++--- 3 files changed, 34 insertions(+), 6 deletions(-) diff --git a/Support/buildnumber.xcconfig b/Support/buildnumber.xcconfig index 47a7eb00..d997159b 100644 --- a/Support/buildnumber.xcconfig +++ b/Support/buildnumber.xcconfig @@ -1,5 +1,5 @@ #include "HockeySDK.xcconfig" -BUILD_NUMBER = 14 -VERSION_STRING = 3.0.0b4 -GCC_PREPROCESSOR_DEFINITIONS = $(inherited) BITHOCKEY_VERSION="@\"3.0.0b4\"" +BUILD_NUMBER = 15 +VERSION_STRING = 3.0.0b5 +GCC_PREPROCESSOR_DEFINITIONS = $(inherited) BITHOCKEY_VERSION="@\"3.0.0b5\"" diff --git a/docs/Changelog-template.md b/docs/Changelog-template.md index feb4aacc..6ca736bf 100644 --- a/docs/Changelog-template.md +++ b/docs/Changelog-template.md @@ -1,3 +1,31 @@ +### Version 3.0.0b5 + +- General: + + - [NEW] Remove `-ObjC` from `Other Linker Flags`, since the SDK doesn't need it + - [NEW] Update localizations (german, croatian) + - [BUGFIX] Fix some new compiler warnings + - [BUGFIX] Fix some missing new lines at EOF + - [BUGFIX] Make sure sure JSON serialization doesn't crash if the string is nil + +- Crash Reporting: + + - [NEW] Add anonymous device ID to crash reports + - [BUGFIX] Move calculation of time interval between startup and crash further up in the code, so delegates can use this information e.g. to add it into a log file + - [BUGFIX] Call delegate also if a crash was detected but could not be read (if handling crashes on startup is implemented) + - [BUGFIX] Format timestamp in crash report to be always UTC in en_US locale + - [BUGFIX] Make sure crash reports incident identifier and key don't have special [] chars and some value + +- Feedback: + + - [NEW] Ask user details and show compose screen automatically on first opening feedback list view + - [BUGFIX] Fix some users own messages re-appearing after deleting them + - [BUGFIX] Problems displaying feedback list view in a navigation hierarchy + +- Updating: + + - [BUGFIX] Fix a problem showing the update UI animated if there TTNavigator class is present even though not being used + ### Version 3.0.0b4 - Crash Reporting: diff --git a/docs/Guide-Installation-Setup-template.md b/docs/Guide-Installation-Setup-template.md index 4d4cdf46..13086ee3 100644 --- a/docs/Guide-Installation-Setup-template.md +++ b/docs/Guide-Installation-Setup-template.md @@ -18,7 +18,7 @@ This document contains the following sections: The SDK runs on devices with iOS 5.0 or higher. -If you need support for iOS 4.x, please check out [HockeySDK v2.5.4](https://github.com/bitstadium/HockeySDK-iOS/downloads) +If you need support for iOS 4.x, please check out [HockeySDK v2.5.5](https://github.com/bitstadium/HockeySDK-iOS/downloads) If you need support for iOS 3.x, please check out [HockeyKit](http://support.hockeyapp.net/kb/client-integration/beta-distribution-on-ios-hockeykit) and [QuincyKit](http://support.hockeyapp.net/kb/client-integration/crash-reporting-on-ios-quincykit) @@ -34,7 +34,7 @@ If you need support for iOS 3.x, please check out [HockeyKit](http://support.hoc ## Set up Xcode -1. Drag & drop the `HockeySDK-iOS` folder from your project directory to your Xcode project. +1. Drag & drop `HockeySDK.embeddedframework` from your project directory to your Xcode project. 2. Similar to above, our projects have a group `Vendor`, so we drop it there. @@ -114,4 +114,4 @@ The Mac Desktop Uploader can provide easy uploading of your app versions to Hock This documentation provides integrated help in Xcode for all public APIs and a set of additional tutorials and HowTos. -1. Copy `de.bitstadium.HockeySDK-iOS-3.0.0b1.docset` into ~`/Library/Developer/Shared/Documentation/DocSet` +1. Copy `de.bitstadium.HockeySDK-iOS-3.0.0b5.docset` into ~`/Library/Developer/Shared/Documentation/DocSet` From 8a6cc49749726de0fff1ecbc17b103447e03761f Mon Sep 17 00:00:00 2001 From: Stephan Diederich Date: Wed, 12 Dec 2012 15:54:49 +0100 Subject: [PATCH 138/176] fix typo --- Resources/de.lproj/HockeySDK.strings | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Resources/de.lproj/HockeySDK.strings b/Resources/de.lproj/HockeySDK.strings index 8834821c..fc4b078e 100755 --- a/Resources/de.lproj/HockeySDK.strings +++ b/Resources/de.lproj/HockeySDK.strings @@ -159,7 +159,7 @@ "HockeyFeedbackListButonUserDataWithEmail" = "Email: %@"; /* Button title for deleting all local messages*/ -"HockeyFeedbackListButonDeleteAllMessages" = "Alle Nachrichten löchen"; +"HockeyFeedbackListButonDeleteAllMessages" = "Alle Nachrichten löschen"; /* Message pending to be send */ "HockeyFeedbackListMessagePending" = "Pending"; From 06974aeaccd423e6a11459bb09881ea920b8ea7b Mon Sep 17 00:00:00 2001 From: Andreas Linde Date: Fri, 14 Dec 2012 14:20:14 +0100 Subject: [PATCH 139/176] Update localizations --- Resources/de.lproj/HockeySDK.strings | 85 ++++---- Resources/en.lproj/HockeySDK.strings | 0 Resources/es.lproj/HockeySDK.strings | 131 ++++++------ Resources/fr.lproj/HockeySDK.strings | 129 ++++++----- Resources/it.lproj/HockeySDK.strings | 115 +++++----- Resources/ja.lproj/HockeySDK.strings | 131 ++++++------ Resources/pt-PT.lproj/HockeySDK.strings | 129 ++++++----- Resources/pt.lproj/HockeySDK.strings | 99 +++++---- Resources/ru.lproj/HockeySDK.strings | 123 ++++++----- Resources/sv.lproj/HockeySDK.strings | 226 -------------------- Resources/tr.lproj/HockeySDK.strings | 226 -------------------- Resources/zh.lproj/HockeySDK.strings | 225 +++++++++++++++++++ Resources/zh_CN.lproj/HockeySDK.strings | 226 -------------------- Resources/zh_TW.lproj/HockeySDK.strings | 226 -------------------- Support/HockeySDK.xcodeproj/project.pbxproj | 23 +- 15 files changed, 696 insertions(+), 1398 deletions(-) mode change 100755 => 100644 Resources/de.lproj/HockeySDK.strings mode change 100755 => 100644 Resources/en.lproj/HockeySDK.strings mode change 100755 => 100644 Resources/es.lproj/HockeySDK.strings mode change 100755 => 100644 Resources/fr.lproj/HockeySDK.strings mode change 100755 => 100644 Resources/it.lproj/HockeySDK.strings mode change 100755 => 100644 Resources/ja.lproj/HockeySDK.strings mode change 100755 => 100644 Resources/pt-PT.lproj/HockeySDK.strings mode change 100755 => 100644 Resources/pt.lproj/HockeySDK.strings mode change 100755 => 100644 Resources/ru.lproj/HockeySDK.strings delete mode 100755 Resources/sv.lproj/HockeySDK.strings delete mode 100644 Resources/tr.lproj/HockeySDK.strings create mode 100644 Resources/zh.lproj/HockeySDK.strings delete mode 100644 Resources/zh_CN.lproj/HockeySDK.strings delete mode 100644 Resources/zh_TW.lproj/HockeySDK.strings diff --git a/Resources/de.lproj/HockeySDK.strings b/Resources/de.lproj/HockeySDK.strings old mode 100755 new mode 100644 index 8834821c..661dd822 --- a/Resources/de.lproj/HockeySDK.strings +++ b/Resources/de.lproj/HockeySDK.strings @@ -1,4 +1,4 @@ -/* General */ +/* General */ /* For dialogs yes buttons */ "HockeyYes" = "Ja"; @@ -12,20 +12,19 @@ /* Replacement for app name, if it could not be detected */ "HockeyAppNamePlaceholder" = "Diese App"; - /* Crash */ /* Crash dialog */ /* Title showing in the alert box when crash report data has been found */ -"CrashDataFoundTitle" = "%@ unerwartet beendet"; +"CrashDataFoundTitle" = "%@ wurde unerwartet beendet."; -/* Description explaining that crash data has been found and ask the user if the anonymous data might be uplaoded to the developers server */ -"CrashDataFoundAnonymousDescription" = "Möchten Sie einen anonymen Absturzbericht senden, damit wir das Problem beheben können?"; +/* Description explaining that crash data has been found and ask the user if the data might be uploaded to the developers server */ +"CrashDataFoundAnonymousDescription" = "Möchten Sie einen Bericht mit anonymisierten Daten senden, sodass wir das Problem beheben können?"; /* Description explaining that crash data has been found and ask the user if the non anonymous data might be uplaoded to the developers server */ -"CrashDataFoundDescription" = "Möchten Sie einen Absturzbericht senden, damit wir das Problem beheben können?"; +"CrashDataFoundDescription" = "Möchten Sie einen Bericht senden, sodass wir das Problem beheben können?"; /* Alert box button if the users wants to send crash data always automatically */ "CrashSendReportAlways" = "Immer senden"; @@ -37,7 +36,7 @@ "CrashDontSendReport" = "Nicht senden"; /* Text showing in a processing box that the crash data is being uploaded to the server */ -"CrashReportSending" = "Senden…"; +"CrashReportSending" = "Senden …"; /* Update */ @@ -46,11 +45,11 @@ /* Update Alert view */ /* Update available */ -"UpdateAvailable" = "Aktualisierung verfügbar"; +"UpdateAvailable" = "Update verfügbar"; "UpdateAlertTextWithAppVersion" = "%@ ist verfügbar."; -"UpdateAlertMandatoryTextWithAppVersion" = "%@ ist verfügbar und muss installiert werden!"; +"UpdateAlertMandatoryTextWithAppVersion" = "%@ ist verfügbar. Dies ist ein verpflichtendes Update!"; "UpdateIgnore" = "Ignorieren"; @@ -61,15 +60,15 @@ /* Update Details */ -"UpdateScreenTitle" = "Aktualisierung"; +"UpdateScreenTitle" = "Update"; -"UpdateButtonCheck" = "PRÜFE"; +"UpdateButtonCheck" = "PRÜFEN"; "UpdateButtonSearching" = "PRÜFEN"; "UpdateButtonUpdate" = "UPDATE"; -"UpdateButtonInstalling" = "INSTALLIEREN"; +"UpdateButtonInstalling" = "INSTALLIEREN …"; "UpdateButtonOffline" = "OFFLINE"; @@ -77,38 +76,36 @@ "UpdateVersion" = "Version"; -"UpdateShowPreviousVersions" = "Zeige frühere Versionen..."; +"UpdateShowPreviousVersions" = "Vorherige Versionen anzeigen …"; "UpdateNoUpdateAvailableTitle" = "Kein Update verfügbar"; -"UpdateNoUpdateAvailableMessage" = "%@ ist bereits die aktuellste Version."; +"UpdateNoUpdateAvailableMessage" = "%@ ist die zurzeit aktuellste Version"; "UpdateError" = "Fehler"; -"UpdateWarning" = "Warnung"; +"UpdateWarning" = "Achtung"; -"UpdateNoReleaseNotesAvailable" = "Keine Release Notes verfügbar."; +"UpdateNoReleaseNotesAvailable" = "Keine Versionshinweise verfügbar."; /* Update Authorization */ -"UpdateAuthorizationProgress" = "Autorisierung..."; +"UpdateAuthorizationProgress" = "Autorisieren …"; -"UpdateAuthorizationOffline" = "Internet Verbindung wird benötigt!"; +"UpdateAuthorizationOffline" = "Internetverbindung erforderlich."; -"UpdateAuthorizationDenied" = "Autorisierung verweigert. Bitte kontaktieren Sie den Entwickler."; +"UpdateAuthorizationDenied" = "Autorisierung abgelehnt. Bitte wenden Sie sich an den Entwickler."; /* Update Expiry */ -"UpdateExpired" = "%@ ist abgelaufen und kann nicht weiter benutzt werden."; +"UpdateExpired" = "%@ ist abgelaufen und kann nicht mehr verwendet werden."; /* Update Simulator Warning */ -"UpdateSimulatorMessage" = "Hockey funktioniert nicht im Simulator."; - - +"UpdateSimulatorMessage" = "Hockey Update funktioniert im Simulator nicht.\nDas URL-Schema „itms-services://” ist zwar implementiert, hat aber keine Funktion."; /* Feedback */ @@ -117,10 +114,10 @@ /* New Message Alert */ /* Alert Title */ -"HockeyFeedbackNewMessageTitle" = "Neue Antwort verfügbar"; +"HockeyFeedbackNewMessageTitle" = "Neue Feedback-Antwort"; /* Alert Text */ -"HockeyFeedbackNewMessageText" = "Eine neue Antwort auf Ihr Feedback ist angekommen. Möchten Sie diese anschauen?"; +"HockeyFeedbackNewMessageText" = "Es liegt eine neue Antwort auf Ihr Feedback vor. Möchten Sie die Antwort lesen?"; /* Alert Ignore Button */ "HockeyFeedbackIgnore" = "Ignorieren"; @@ -135,40 +132,40 @@ "HockeyFeedbackListTitle" = "Feedback"; /* Last Updated */ -"HockeyFeedbackListLastUpdated" = "Letzte Aktualisierung: %@"; +"HockeyFeedbackListLastUpdated" = "Zuletzt aktualisiert: %@"; /* Never Updated */ -"HockeyFeedbackListNeverUpdated" = "Nie"; +"HockeyFeedbackListNeverUpdated" = "Noch nie"; /* Provide Feedback Button Title */ -"HockeyFeedbackListButonWriteFeedback" = "Feedback schreiben"; +"HockeyFeedbackListButonWriteFeedback" = "Feedback senden"; /* Add a Response Button Title */ -"HockeyFeedbackListButonWriteResponse" = "Antwort hinzufügen"; +"HockeyFeedbackListButonWriteResponse" = "Antworten"; /* User Data Set Name Button Title */ -"HockeyFeedbackListButonUserDataSetName" = "Ihren Name eintragen"; +"HockeyFeedbackListButonUserDataSetName" = "Namen eintragen"; /* User Data Set Email Button Title */ -"HockeyFeedbackListButonUserDataSetEmail" = "Ihre Email eintragen"; +"HockeyFeedbackListButonUserDataSetEmail" = "E-Mail-Adresse eintragen"; /* User Data With Name Button Title */ "HockeyFeedbackListButonUserDataWithName" = "Name: %@"; /* User Data With Email Button Title */ -"HockeyFeedbackListButonUserDataWithEmail" = "Email: %@"; +"HockeyFeedbackListButonUserDataWithEmail" = "E-Mail: %@"; /* Button title for deleting all local messages*/ -"HockeyFeedbackListButonDeleteAllMessages" = "Alle Nachrichten löchen"; +"HockeyFeedbackListButonDeleteAllMessages" = "Alle Mitteilungen löschen"; /* Message pending to be send */ -"HockeyFeedbackListMessagePending" = "Pending"; +"HockeyFeedbackListMessagePending" = "Versand ausstehend"; /* Delete All Messages Action Sheet / Alert View */ /* Title for the Action Sheet */ -"HockeyFeedbackListDeleteAllTitle" = "Dies wird alle Nachrichten löschen."; +"HockeyFeedbackListDeleteAllTitle" = "Diese Aktion löscht alle auf diesem Gerät befindlichen Mitteilungen."; /* Button Title to perform delete action */ "HockeyFeedbackListDeleteAllDelete" = "Löschen"; @@ -177,7 +174,7 @@ "HockeyFeedbackListDeleteAllCancel" = "Abbrechen"; -/* Open/Copy Link In Safari Action Sheet / Alert View */ +/* Open Link In Safari Action Sheet / Alert View */ /* Button Title to cancel */ "HockeyFeedbackListLinkActionCancel" = "Abbrechen"; @@ -192,7 +189,7 @@ /* UIActivity */ /* Activity Sharing Button Title, App Name will be inserted */ -"HockeyFeedbackActivityButtonTitle" = "%@ Feedback"; +"HockeyFeedbackActivityButtonTitle" = "Feedback zu %@"; /* if there can no app name be found, use this instead for HockeyFeedbackActivityButtonTitle */ "HockeyFeedbackActivityAppPlaceholder" = "App"; @@ -201,28 +198,28 @@ /* Compose Message */ /* Title */ -"HockeyFeedbackComposeTitle" = "Neues Feedback"; +"HockeyFeedbackComposeTitle" = "Neue Feedback-Meldung"; /* Send button */ -"HockeyFeedbackComposeSend" = "Absenden"; +"HockeyFeedbackComposeSend" = "Senden"; /* Set User Data */ /* Title */ -"HockeyFeedbackUserDataTitle" = "Über mich"; +"HockeyFeedbackUserDataTitle" = "Meine Infos"; /* Description On What Should Be Entered */ -"HockeyFeedbackUserDataDescription" = "Bitte tragen Sie ihre Daten ein bevor Sie eine Nachricht schreiben."; +"HockeyFeedbackUserDataDescription" = "Bitte geben Sie vor Verfassen Ihres Feedbacks Ihre Daten ein."; /* Name Field */ "HockeyFeedbackUserDataName" = "Name"; /* Name Placeholder */ -"HockeyFeedbackUserDataNamePlaceHolder" = "Klaus Mustermann"; +"HockeyFeedbackUserDataNamePlaceHolder" = "Max Mustermann"; /* Email Field */ -"HockeyFeedbackUserDataEmail" = "Email"; +"HockeyFeedbackUserDataEmail" = "E-Mail"; /* Email Placeholder */ -"HockeyFeedbackUserDataEmailPlaceholder" = "beispiel@email.com"; +"HockeyFeedbackUserDataEmailPlaceholder" = "Max@mustermann.de"; diff --git a/Resources/en.lproj/HockeySDK.strings b/Resources/en.lproj/HockeySDK.strings old mode 100755 new mode 100644 diff --git a/Resources/es.lproj/HockeySDK.strings b/Resources/es.lproj/HockeySDK.strings old mode 100755 new mode 100644 index 62584366..4ce030ae --- a/Resources/es.lproj/HockeySDK.strings +++ b/Resources/es.lproj/HockeySDK.strings @@ -1,17 +1,16 @@ -/* General */ +/* General */ /* For dialogs yes buttons */ -"HockeyYes" = "Yes"; +"HockeyYes" = "Sí"; /* For dialogs no buttons */ "HockeyNo" = "No"; /* For dialogs ok buttons */ -"HockeyOK" = "OK"; +"HockeyOK" = "Aceptar"; /* Replacement for app name, if it could not be detected */ -"HockeyAppNamePlaceholder" = "This app"; - +"HockeyAppNamePlaceholder" = "Esta aplicación"; /* Crash */ @@ -19,22 +18,22 @@ /* Crash dialog */ /* Title showing in the alert box when crash report data has been found */ -"CrashDataFoundTitle" = "Conflicto de datos detectado"; +"CrashDataFoundTitle" = "%@ se ha cerrado inesperadamente"; /* Description explaining that crash data has been found and ask the user if the data might be uploaded to the developers server */ -"CrashDataFoundAnonymousDescription" = "La aplicación fallo previamente. ¿Le gustaría proporcionar de manera anonima información relacionado con el fallo al programador para que este pueda solucionar el problema?"; +"CrashDataFoundAnonymousDescription" = "¿Desea enviar un informe anónimo para ayudarnos a solucionar el problema?"; /* Description explaining that crash data has been found and ask the user if the non anonymous data might be uplaoded to the developers server */ -"CrashDataFoundDescription" = "La aplicación fallo previamente. ¿Le gustaría proporcionar de manera información relacionado con el fallo al programador para que este pueda solucionar el problema?"; +"CrashDataFoundDescription" = "¿Desea enviar un informe para ayudarnos a solucionar el problema?"; /* Alert box button if the users wants to send crash data always automatically */ -"CrashSendReportAlways" = "Siempre"; +"CrashSendReportAlways" = "Enviar siempre"; /* Alert box button to send the crash report once */ -"CrashSendReport" = "Sí"; +"CrashSendReport" = "Enviar informe"; /* Alert box button to decline sending the report */ -"CrashDontSendReport" = "No"; +"CrashDontSendReport" = "No enviar"; /* Text showing in a processing box that the crash data is being uploaded to the server */ "CrashReportSending" = "Enviando…"; @@ -46,67 +45,67 @@ /* Update Alert view */ /* Update available */ -"UpdateAvailable" = "Update available"; +"UpdateAvailable" = "Actualización disponible"; -"UpdateAlertTextWithAppVersion" = "%@ is available."; +"UpdateAlertTextWithAppVersion" = "La versión %@ está disponible."; -"UpdateAlertMandatoryTextWithAppVersion" = "%@ is available and is a mandatory update!"; +"UpdateAlertMandatoryTextWithAppVersion" = "La versión %@ está disponible y es una actualización obligatoria."; -"UpdateIgnore" = "Ignore"; +"UpdateIgnore" = "Ignorar"; -"UpdateShow" = "Show"; +"UpdateShow" = "Mostrar"; -"UpdateInstall" = "Install"; +"UpdateInstall" = "Instalar"; /* Update Details */ -"UpdateScreenTitle" = "Update"; +"UpdateScreenTitle" = "Actualización"; -"UpdateButtonCheck" = "CHECK"; +"UpdateButtonCheck" = "COMPROBAR"; -"UpdateButtonSearching" = "CHECKING"; +"UpdateButtonSearching" = "COMPROBANDO"; -"UpdateButtonUpdate" = "UPDATE"; +"UpdateButtonUpdate" = "ACTUALIZAR"; -"UpdateButtonInstalling" = "INSTALLING"; +"UpdateButtonInstalling" = "INSTALANDO"; -"UpdateButtonOffline" = "OFFLINE"; +"UpdateButtonOffline" = "SIN CONEXIÓN"; -"UpdateInstalled" = "INSTALLED"; +"UpdateInstalled" = "INSTALADO"; -"UpdateVersion" = "Version"; +"UpdateVersion" = "Versión"; -"UpdateShowPreviousVersions" = "Show previous versions..."; +"UpdateShowPreviousVersions" = "Mostrar versiones anteriores..."; -"UpdateNoUpdateAvailableTitle" = "No Update Available"; +"UpdateNoUpdateAvailableTitle" = "No hay actualizaciones disponibles"; -"UpdateNoUpdateAvailableMessage" = "%@ is already the latest version."; +"UpdateNoUpdateAvailableMessage" = "La versión %@ es la más reciente."; "UpdateError" = "Error"; -"UpdateWarning" = "Warning"; +"UpdateWarning" = "Advertencia"; -"UpdateNoReleaseNotesAvailable" = "No release notes available."; +"UpdateNoReleaseNotesAvailable" = "No hay notas para esta versión."; /* Update Authorization */ -"UpdateAuthorizationProgress" = "Authorizing..."; +"UpdateAuthorizationProgress" = "Autorizando..."; -"UpdateAuthorizationOffline" = "Internet connection required!"; +"UpdateAuthorizationOffline" = "Se requiere conexión a Internet."; -"UpdateAuthorizationDenied" = "Authorizing denied. Please contact the developer."; +"UpdateAuthorizationDenied" = "Se ha denegado la autorización. Contacte con el desarrollador."; /* Update Expiry */ -"UpdateExpired" = "%@ is expired and can not be used any longer."; +"UpdateExpired" = "%@ ha caducado y ya no puede usarse."; /* Update Simulator Warning */ -"UpdateSimulatorMessage" = "Hockey Update does not work in the Simulator.\nThe itms-services:// url scheme is implemented but nonfunctional."; +"UpdateSimulatorMessage" = "Las actualizaciones de Hockey no funcionan en el Simulador.\nEl esquema URL itms-services:// está implementado pero no funciona."; /* Feedback */ @@ -115,112 +114,112 @@ /* New Message Alert */ /* Alert Title */ -"HockeyFeedbackNewMessageTitle" = "New Feedback Response"; +"HockeyFeedbackNewMessageTitle" = "Nueva respuesta al comentario"; /* Alert Text */ -"HockeyFeedbackNewMessageText" = "A new response to your feedback is available. Would you like to view it?"; +"HockeyFeedbackNewMessageText" = "Hay una nueva respuesta a su comentario. ¿Desea verla?"; /* Alert Ignore Button */ -"HockeyFeedbackIgnore" = "Ignore"; +"HockeyFeedbackIgnore" = "Ignorar"; /* Alert Show Button */ -"HockeyFeedbackShow" = "Show"; +"HockeyFeedbackShow" = "Mostrar"; /* List View */ /* Title */ -"HockeyFeedbackListTitle" = "Feedback"; +"HockeyFeedbackListTitle" = "Comentarios"; /* Last Updated */ -"HockeyFeedbackListLastUpdated" = "Last Updated: %@"; +"HockeyFeedbackListLastUpdated" = "Última actualización: %@"; /* Never Updated */ -"HockeyFeedbackListNeverUpdated" = "Never"; +"HockeyFeedbackListNeverUpdated" = "Nunca"; /* Provide Feedback Button Title */ -"HockeyFeedbackListButonWriteFeedback" = "Provide Feedback"; +"HockeyFeedbackListButonWriteFeedback" = "Dejar un comentario"; /* Add a Response Button Title */ -"HockeyFeedbackListButonWriteResponse" = "Add a Response"; +"HockeyFeedbackListButonWriteResponse" = "Añadir una respuesta"; /* User Data Set Name Button Title */ -"HockeyFeedbackListButonUserDataSetName" = "Set Your Name"; +"HockeyFeedbackListButonUserDataSetName" = "Indicar mi nombre"; /* User Data Set Email Button Title */ -"HockeyFeedbackListButonUserDataSetEmail" = "Set Your Email"; +"HockeyFeedbackListButonUserDataSetEmail" = "Indicar mi correo"; /* User Data With Name Button Title */ -"HockeyFeedbackListButonUserDataWithName" = "Name: %@"; +"HockeyFeedbackListButonUserDataWithName" = "Nombre: %@"; /* User Data With Email Button Title */ -"HockeyFeedbackListButonUserDataWithEmail" = "Email: %@"; +"HockeyFeedbackListButonUserDataWithEmail" = "Correo: %@"; /* Button title for deleting all local messages*/ -"HockeyFeedbackListButonDeleteAllMessages" = "Delete All Messages"; +"HockeyFeedbackListButonDeleteAllMessages" = "Eliminar todos los mensajes"; /* Message pending to be send */ -"HockeyFeedbackListMessagePending" = "Pending"; +"HockeyFeedbackListMessagePending" = "Pendiente"; /* Delete All Messages Action Sheet / Alert View */ /* Title for the Action Sheet */ -"HockeyFeedbackListDeleteAllTitle" = "This will delete all messages on this device."; +"HockeyFeedbackListDeleteAllTitle" = "Se eliminarán todos los mensajes en este dispositivo."; /* Button Title to perform delete action */ -"HockeyFeedbackListDeleteAllDelete" = "Delete"; +"HockeyFeedbackListDeleteAllDelete" = "Eliminar"; /* Button Title to cancel delete action */ -"HockeyFeedbackListDeleteAllCancel" = "Cancel"; +"HockeyFeedbackListDeleteAllCancel" = "Cancelar"; /* Open Link In Safari Action Sheet / Alert View */ /* Button Title to cancel */ -"HockeyFeedbackListLinkActionCancel" = "Cancel"; +"HockeyFeedbackListLinkActionCancel" = "Cancelar"; /* Button Title to Open the Link */ -"HockeyFeedbackListLinkActionOpen" = "Open"; +"HockeyFeedbackListLinkActionOpen" = "Abrir"; /* Button Title to Copy the Link */ -"HockeyFeedbackListLinkActionCopy" = "Copy"; +"HockeyFeedbackListLinkActionCopy" = "Copiar"; /* UIActivity */ /* Activity Sharing Button Title, App Name will be inserted */ -"HockeyFeedbackActivityButtonTitle" = "%@ Feedback"; +"HockeyFeedbackActivityButtonTitle" = "Comentar %@"; /* if there can no app name be found, use this instead for HockeyFeedbackActivityButtonTitle */ -"HockeyFeedbackActivityAppPlaceholder" = "App"; +"HockeyFeedbackActivityAppPlaceholder" = "Aplicación"; /* Compose Message */ /* Title */ -"HockeyFeedbackComposeTitle" = "New Feedback"; +"HockeyFeedbackComposeTitle" = "Nuevo comentario"; /* Send button */ -"HockeyFeedbackComposeSend" = "Send"; +"HockeyFeedbackComposeSend" = "Enviar"; /* Set User Data */ /* Title */ -"HockeyFeedbackUserDataTitle" = "My Info"; +"HockeyFeedbackUserDataTitle" = "Mis datos"; /* Description On What Should Be Entered */ -"HockeyFeedbackUserDataDescription" = "Please provide your information before writing your feedback."; +"HockeyFeedbackUserDataDescription" = "Indique sus datos antes de escribir el comentario."; /* Name Field */ -"HockeyFeedbackUserDataName" = "Name"; +"HockeyFeedbackUserDataName" = "Nombre"; /* Name Placeholder */ -"HockeyFeedbackUserDataNamePlaceHolder" = "John Doe"; +"HockeyFeedbackUserDataNamePlaceHolder" = "Juan García"; /* Email Field */ -"HockeyFeedbackUserDataEmail" = "Email"; +"HockeyFeedbackUserDataEmail" = "Correo"; /* Email Placeholder */ -"HockeyFeedbackUserDataEmailPlaceholder" = "example@email.com"; +"HockeyFeedbackUserDataEmailPlaceholder" = "ejemplo@correo.com"; diff --git a/Resources/fr.lproj/HockeySDK.strings b/Resources/fr.lproj/HockeySDK.strings old mode 100755 new mode 100644 index d94efc7a..134157e9 --- a/Resources/fr.lproj/HockeySDK.strings +++ b/Resources/fr.lproj/HockeySDK.strings @@ -1,4 +1,4 @@ -/* General */ +/* General */ /* For dialogs yes buttons */ "HockeyYes" = "Oui"; @@ -10,8 +10,7 @@ "HockeyOK" = "OK"; /* Replacement for app name, if it could not be detected */ -"HockeyAppNamePlaceholder" = "This app"; - +"HockeyAppNamePlaceholder" = "Cette application"; /* Crash */ @@ -19,25 +18,25 @@ /* Crash dialog */ /* Title showing in the alert box when crash report data has been found */ -"CrashDataFoundTitle" = "Rapport de plantage"; +"CrashDataFoundTitle" = "%@ a quitté inopinément."; /* Description explaining that crash data has been found and ask the user if the data might be uploaded to the developers server */ -"CrashDataFoundAnonymousDescription" = "%@ s’est fermé de façon inattendue. Souhaitez-vous envoyer un rapport d’incident anonyme pour nous aider à corriger le problème ?"; +"CrashDataFoundAnonymousDescription" = "Voulez-vous envoyer un rapport anonyme pour nous aider à corriger le problème ?"; /* Description explaining that crash data has been found and ask the user if the non anonymous data might be uplaoded to the developers server */ -"CrashDataFoundDescription" = "%@ s’est fermé de façon inattendue. Souhaitez-vous envoyer un rapport d’incident pour nous aider à corriger le problème ?"; +"CrashDataFoundDescription" = "Voulez-vous envoyer un rapport pour nous aider à corriger le problème ?"; /* Alert box button if the users wants to send crash data always automatically */ -"CrashSendReportAlways" = "Toujours"; +"CrashSendReportAlways" = "Toujours envoyer"; /* Alert box button to send the crash report once */ -"CrashSendReport" = "Oui"; +"CrashSendReport" = "Envoyer le rapport"; /* Alert box button to decline sending the report */ -"CrashDontSendReport" = "Non"; +"CrashDontSendReport" = "Ne pas envoyer"; /* Text showing in a processing box that the crash data is being uploaded to the server */ -"CrashReportSending" = "Envoyer…"; +"CrashReportSending" = "Envoi…"; /* Update */ @@ -46,67 +45,67 @@ /* Update Alert view */ /* Update available */ -"UpdateAvailable" = "Update available"; +"UpdateAvailable" = "Mise à jour disponible"; -"UpdateAlertTextWithAppVersion" = "%@ is available."; +"UpdateAlertTextWithAppVersion" = "%@ est disponible."; -"UpdateAlertMandatoryTextWithAppVersion" = "%@ is available and is a mandatory update!"; +"UpdateAlertMandatoryTextWithAppVersion" = "%@ est disponible. Cette mise à jour est obligatoire !"; -"UpdateIgnore" = "Ignore"; +"UpdateIgnore" = "Ignorer"; -"UpdateShow" = "Show"; +"UpdateShow" = "Afficher"; -"UpdateInstall" = "Install"; +"UpdateInstall" = "Installer"; /* Update Details */ -"UpdateScreenTitle" = "Update"; +"UpdateScreenTitle" = "Mise à jour"; -"UpdateButtonCheck" = "CHECK"; +"UpdateButtonCheck" = "RECHERCHER"; -"UpdateButtonSearching" = "CHECKING"; +"UpdateButtonSearching" = "RECHERCHE"; -"UpdateButtonUpdate" = "UPDATE"; +"UpdateButtonUpdate" = "MISE À JOUR"; -"UpdateButtonInstalling" = "INSTALLING"; +"UpdateButtonInstalling" = "INSTALLATION"; -"UpdateButtonOffline" = "OFFLINE"; +"UpdateButtonOffline" = "HORS LIGNE"; -"UpdateInstalled" = "INSTALLED"; +"UpdateInstalled" = "INSTALLÉE"; "UpdateVersion" = "Version"; -"UpdateShowPreviousVersions" = "Show previous versions..."; +"UpdateShowPreviousVersions" = "Afficher les versions précédentes…"; -"UpdateNoUpdateAvailableTitle" = "No Update Available"; +"UpdateNoUpdateAvailableTitle" = "Aucune mise à jour disponible"; -"UpdateNoUpdateAvailableMessage" = "%@ is already the latest version."; +"UpdateNoUpdateAvailableMessage" = "%@ est la dernière version."; -"UpdateError" = "Error"; +"UpdateError" = "Erreur"; -"UpdateWarning" = "Warning"; +"UpdateWarning" = "Avertissement"; -"UpdateNoReleaseNotesAvailable" = "No release notes available."; +"UpdateNoReleaseNotesAvailable" = "Aucune note de version."; /* Update Authorization */ -"UpdateAuthorizationProgress" = "Authorizing..."; +"UpdateAuthorizationProgress" = "Autorisation…"; -"UpdateAuthorizationOffline" = "Internet connection required!"; +"UpdateAuthorizationOffline" = "Connexion Internet requise !"; -"UpdateAuthorizationDenied" = "Authorizing denied. Please contact the developer."; +"UpdateAuthorizationDenied" = "Autorisation refusée. Contactez le développeur."; /* Update Expiry */ -"UpdateExpired" = "%@ is expired and can not be used any longer."; +"UpdateExpired" = "%@ a expiré et n'est plus utilisable."; /* Update Simulator Warning */ -"UpdateSimulatorMessage" = "Hockey Update does not work in the Simulator.\nThe itms-services:// url scheme is implemented but nonfunctional."; +"UpdateSimulatorMessage" = "Le service de mise à jour Hockey ne fonctionne pas dans le simulateur.\nLe modèle d'URL itms-services:// est implémenté mais n'est pas encore opérationnel."; /* Feedback */ @@ -115,112 +114,112 @@ /* New Message Alert */ /* Alert Title */ -"HockeyFeedbackNewMessageTitle" = "New Feedback Response"; +"HockeyFeedbackNewMessageTitle" = "Nouvelle réponse au commentaire"; /* Alert Text */ -"HockeyFeedbackNewMessageText" = "A new response to your feedback is available. Would you like to view it?"; +"HockeyFeedbackNewMessageText" = "Une nouvelle réponse à votre commentaire est disponible. Voulez-vous la consulter ?"; /* Alert Ignore Button */ -"HockeyFeedbackIgnore" = "Ignore"; +"HockeyFeedbackIgnore" = "Ignorer"; /* Alert Show Button */ -"HockeyFeedbackShow" = "Show"; +"HockeyFeedbackShow" = "Afficher"; /* List View */ /* Title */ -"HockeyFeedbackListTitle" = "Feedback"; +"HockeyFeedbackListTitle" = "Commentaire"; /* Last Updated */ -"HockeyFeedbackListLastUpdated" = "Last Updated: %@"; +"HockeyFeedbackListLastUpdated" = "Dernière mise à jour : %@"; /* Never Updated */ -"HockeyFeedbackListNeverUpdated" = "Never"; +"HockeyFeedbackListNeverUpdated" = "Jamais"; /* Provide Feedback Button Title */ -"HockeyFeedbackListButonWriteFeedback" = "Provide Feedback"; +"HockeyFeedbackListButonWriteFeedback" = "Émettre un commentaire"; /* Add a Response Button Title */ -"HockeyFeedbackListButonWriteResponse" = "Add a Response"; +"HockeyFeedbackListButonWriteResponse" = "Répondre"; /* User Data Set Name Button Title */ -"HockeyFeedbackListButonUserDataSetName" = "Set Your Name"; +"HockeyFeedbackListButonUserDataSetName" = "Spécifier votre nom"; /* User Data Set Email Button Title */ -"HockeyFeedbackListButonUserDataSetEmail" = "Set Your Email"; +"HockeyFeedbackListButonUserDataSetEmail" = "Spécifier votre adresse"; /* User Data With Name Button Title */ -"HockeyFeedbackListButonUserDataWithName" = "Name: %@"; +"HockeyFeedbackListButonUserDataWithName" = "Nom : %@"; /* User Data With Email Button Title */ -"HockeyFeedbackListButonUserDataWithEmail" = "Email: %@"; +"HockeyFeedbackListButonUserDataWithEmail" = "Adresse : %@"; /* Button title for deleting all local messages*/ -"HockeyFeedbackListButonDeleteAllMessages" = "Delete All Messages"; +"HockeyFeedbackListButonDeleteAllMessages" = "Supprimer les messages"; /* Message pending to be send */ -"HockeyFeedbackListMessagePending" = "Pending"; +"HockeyFeedbackListMessagePending" = "En attente"; /* Delete All Messages Action Sheet / Alert View */ /* Title for the Action Sheet */ -"HockeyFeedbackListDeleteAllTitle" = "This will delete all messages on this device."; +"HockeyFeedbackListDeleteAllTitle" = "Ceci supprime tous les messages présents sur l'appareil."; /* Button Title to perform delete action */ -"HockeyFeedbackListDeleteAllDelete" = "Delete"; +"HockeyFeedbackListDeleteAllDelete" = "Supprimer"; /* Button Title to cancel delete action */ -"HockeyFeedbackListDeleteAllCancel" = "Cancel"; +"HockeyFeedbackListDeleteAllCancel" = "Annuler"; /* Open Link In Safari Action Sheet / Alert View */ /* Button Title to cancel */ -"HockeyFeedbackListLinkActionCancel" = "Cancel"; +"HockeyFeedbackListLinkActionCancel" = "Annuler"; /* Button Title to Open the Link */ -"HockeyFeedbackListLinkActionOpen" = "Open"; +"HockeyFeedbackListLinkActionOpen" = "Ouvrir"; /* Button Title to Copy the Link */ -"HockeyFeedbackListLinkActionCopy" = "Copy"; +"HockeyFeedbackListLinkActionCopy" = "Copier"; /* UIActivity */ /* Activity Sharing Button Title, App Name will be inserted */ -"HockeyFeedbackActivityButtonTitle" = "%@ Feedback"; +"HockeyFeedbackActivityButtonTitle" = "Commentaire sur %@"; /* if there can no app name be found, use this instead for HockeyFeedbackActivityButtonTitle */ -"HockeyFeedbackActivityAppPlaceholder" = "App"; +"HockeyFeedbackActivityAppPlaceholder" = "Application"; /* Compose Message */ /* Title */ -"HockeyFeedbackComposeTitle" = "New Feedback"; +"HockeyFeedbackComposeTitle" = "Nouveau commentaire"; /* Send button */ -"HockeyFeedbackComposeSend" = "Send"; +"HockeyFeedbackComposeSend" = "Envoyer"; /* Set User Data */ /* Title */ -"HockeyFeedbackUserDataTitle" = "My Info"; +"HockeyFeedbackUserDataTitle" = "Mes infos"; /* Description On What Should Be Entered */ -"HockeyFeedbackUserDataDescription" = "Please provide your information before writing your feedback."; +"HockeyFeedbackUserDataDescription" = "Merci de fournir vos informations avant de rédiger votre commentaire."; /* Name Field */ -"HockeyFeedbackUserDataName" = "Name"; +"HockeyFeedbackUserDataName" = "Nom"; /* Name Placeholder */ -"HockeyFeedbackUserDataNamePlaceHolder" = "John Doe"; +"HockeyFeedbackUserDataNamePlaceHolder" = "Jean Dubois"; /* Email Field */ -"HockeyFeedbackUserDataEmail" = "Email"; +"HockeyFeedbackUserDataEmail" = "Adresse"; /* Email Placeholder */ -"HockeyFeedbackUserDataEmailPlaceholder" = "example@email.com"; +"HockeyFeedbackUserDataEmailPlaceholder" = "exemple@email.com"; diff --git a/Resources/it.lproj/HockeySDK.strings b/Resources/it.lproj/HockeySDK.strings old mode 100755 new mode 100644 index 5b64e830..fabbb475 --- a/Resources/it.lproj/HockeySDK.strings +++ b/Resources/it.lproj/HockeySDK.strings @@ -1,7 +1,7 @@ -/* General */ +/* General */ /* For dialogs yes buttons */ -"HockeyYes" = "Si"; +"HockeyYes" = "Sì"; /* For dialogs no buttons */ "HockeyNo" = "No"; @@ -10,8 +10,7 @@ "HockeyOK" = "OK"; /* Replacement for app name, if it could not be detected */ -"HockeyAppNamePlaceholder" = "This app"; - +"HockeyAppNamePlaceholder" = "Questa app"; /* Crash */ @@ -19,25 +18,25 @@ /* Crash dialog */ /* Title showing in the alert box when crash report data has been found */ -"CrashDataFoundTitle" = "Dati del crash trovati"; +"CrashDataFoundTitle" = "%@ si è chiusa inaspettatamente"; /* Description explaining that crash data has been found and ask the user if the data might be uploaded to the developers server */ -"CrashDataFoundAnonymousDescription" = "L'applicazione precedentemente ha avuto un crash. Vuoi inviare allo sviluppatore i dati anonimi del crash in modo che possa provare a sistemare il problema?"; +"CrashDataFoundAnonymousDescription" = "Vuoi inviare una segnalazione anonima per aiutarci a risolvere il problema?"; /* Description explaining that crash data has been found and ask the user if the non anonymous data might be uplaoded to the developers server */ -"CrashDataFoundDescription" = "L'applicazione precedentemente ha avuto un crash. Vuoi inviare allo sviluppatore i dati del crash in modo che possa provare a sistemare il problema?"; +"CrashDataFoundDescription" = "Vuoi inviare una segnalazione con i dettagli del crash per aiutarci a risolvere il problema?"; /* Alert box button if the users wants to send crash data always automatically */ -"CrashSendReportAlways" = "Sempre"; +"CrashSendReportAlways" = "Invia sempre"; /* Alert box button to send the crash report once */ -"CrashSendReport" = "Si"; +"CrashSendReport" = "Invia segnalazione"; /* Alert box button to decline sending the report */ -"CrashDontSendReport" = "No"; +"CrashDontSendReport" = "Non inviare"; /* Text showing in a processing box that the crash data is being uploaded to the server */ -"CrashReportSending" = "Invio…"; +"CrashReportSending" = "Invio..."; /* Update */ @@ -48,65 +47,65 @@ /* Update available */ "UpdateAvailable" = "Aggiornamento disponibile"; -"UpdateAlertTextWithAppVersion" = "%@ è disponibile."; +"UpdateAlertTextWithAppVersion" = "È disponibile %@."; -"UpdateAlertMandatoryTextWithAppVersion" = "%@ is available and is a mandatory update!"; +"UpdateAlertMandatoryTextWithAppVersion" = "È disponibile %@ ed è un aggiornamento obbligatorio!"; "UpdateIgnore" = "Ignora"; -"UpdateShow" = "Mostra"; +"UpdateShow" = "Visualizza"; "UpdateInstall" = "Installa"; /* Update Details */ -"UpdateScreenTitle" = "Aggiorna"; +"UpdateScreenTitle" = "Aggiornamento"; -"UpdateButtonCheck" = "CONTROLLA"; +"UpdateButtonCheck" = "VERIFICA"; -"UpdateButtonSearching" = "CONTROLLO"; +"UpdateButtonSearching" = "VERIFICO"; -"UpdateButtonUpdate" = "AGGIORNA"; +"UpdateButtonUpdate" = "AGGIORNAMENTO"; "UpdateButtonInstalling" = "INSTALLO"; "UpdateButtonOffline" = "OFFLINE"; -"UpdateInstalled" = "INSTALLATA"; +"UpdateInstalled" = "INSTALLATO"; "UpdateVersion" = "Versione"; -"UpdateShowPreviousVersions" = "Mostra le versioni precedenti..."; +"UpdateShowPreviousVersions" = "Visualizzo versioni precedenti..."; -"UpdateNoUpdateAvailableTitle" = "Nessun aggiornamento disponibile"; +"UpdateNoUpdateAvailableTitle" = "Aggiornamenti non disponibili"; -"UpdateNoUpdateAvailableMessage" = "%@ è aggiornata all'ultima versione."; +"UpdateNoUpdateAvailableMessage" = "%@ è già la versione attuale."; "UpdateError" = "Errore"; "UpdateWarning" = "Avviso"; -"UpdateNoReleaseNotesAvailable" = "Non sono disponibili note di rilascio."; +"UpdateNoReleaseNotesAvailable" = "Non sono disponibili note sulla release."; /* Update Authorization */ -"UpdateAuthorizationProgress" = "Attendo autorizzazione..."; +"UpdateAuthorizationProgress" = "Autorizzazione..."; -"UpdateAuthorizationOffline" = "E' richiesta la connessione internet!"; +"UpdateAuthorizationOffline" = "È necessario un collegamento a Internet!"; -"UpdateAuthorizationDenied" = "Autorizzazione negata, contattare lo sviluppatore."; +"UpdateAuthorizationDenied" = "Autorizzazione negata. Contattare lo sviluppatore."; /* Update Expiry */ -"UpdateExpired" = "%@ is expired and can not be used any longer."; +"UpdateExpired" = "%@ è scaduta e non può più essere utilizzata."; /* Update Simulator Warning */ -"UpdateSimulatorMessage" = "Hockey Update does not work in the Simulator.\nThe itms-services:// url scheme is implemented but nonfunctional."; +"UpdateSimulatorMessage" = "L'aggiornamento di Hockey non funziona nel Simulator.\nLo schema url tms-services:// è implementato ma non è funzionante."; /* Feedback */ @@ -115,82 +114,82 @@ /* New Message Alert */ /* Alert Title */ -"HockeyFeedbackNewMessageTitle" = "New Feedback Response"; +"HockeyFeedbackNewMessageTitle" = "Nuova risposta a un commento"; /* Alert Text */ -"HockeyFeedbackNewMessageText" = "A new response to your feedback is available. Would you like to view it?"; +"HockeyFeedbackNewMessageText" = "È presente una nuova risposta al tuo commento. Vuoi visualizzarla?"; /* Alert Ignore Button */ -"HockeyFeedbackIgnore" = "Ignore"; +"HockeyFeedbackIgnore" = "Ignora"; /* Alert Show Button */ -"HockeyFeedbackShow" = "Show"; +"HockeyFeedbackShow" = "Visualizza"; /* List View */ /* Title */ -"HockeyFeedbackListTitle" = "Feedback"; +"HockeyFeedbackListTitle" = "Commento"; /* Last Updated */ -"HockeyFeedbackListLastUpdated" = "Last Updated: %@"; +"HockeyFeedbackListLastUpdated" = "Ultimo aggiornamento: %@"; /* Never Updated */ -"HockeyFeedbackListNeverUpdated" = "Never"; +"HockeyFeedbackListNeverUpdated" = "Mai"; /* Provide Feedback Button Title */ -"HockeyFeedbackListButonWriteFeedback" = "Provide Feedback"; +"HockeyFeedbackListButonWriteFeedback" = "Commenta"; /* Add a Response Button Title */ -"HockeyFeedbackListButonWriteResponse" = "Add a Response"; +"HockeyFeedbackListButonWriteResponse" = "Aggiungi una risposta"; /* User Data Set Name Button Title */ -"HockeyFeedbackListButonUserDataSetName" = "Set Your Name"; +"HockeyFeedbackListButonUserDataSetName" = "Imposta il tuo nome"; /* User Data Set Email Button Title */ -"HockeyFeedbackListButonUserDataSetEmail" = "Set Your Email"; +"HockeyFeedbackListButonUserDataSetEmail" = "Imposta la tua e-mail"; /* User Data With Name Button Title */ -"HockeyFeedbackListButonUserDataWithName" = "Name: %@"; +"HockeyFeedbackListButonUserDataWithName" = "Nome: %@"; /* User Data With Email Button Title */ -"HockeyFeedbackListButonUserDataWithEmail" = "Email: %@"; +"HockeyFeedbackListButonUserDataWithEmail" = "E-mail: %@"; /* Button title for deleting all local messages*/ -"HockeyFeedbackListButonDeleteAllMessages" = "Delete All Messages"; +"HockeyFeedbackListButonDeleteAllMessages" = "Cancella tutti i messagi"; /* Message pending to be send */ -"HockeyFeedbackListMessagePending" = "Pending"; +"HockeyFeedbackListMessagePending" = "In attesa"; /* Delete All Messages Action Sheet / Alert View */ /* Title for the Action Sheet */ -"HockeyFeedbackListDeleteAllTitle" = "This will delete all messages on this device."; +"HockeyFeedbackListDeleteAllTitle" = "Tutti i messaggi presenti sul dispositivo verranno cancellati."; /* Button Title to perform delete action */ -"HockeyFeedbackListDeleteAllDelete" = "Delete"; +"HockeyFeedbackListDeleteAllDelete" = "Elimina"; /* Button Title to cancel delete action */ -"HockeyFeedbackListDeleteAllCancel" = "Cancel"; +"HockeyFeedbackListDeleteAllCancel" = "Annulla"; /* Open Link In Safari Action Sheet / Alert View */ /* Button Title to cancel */ -"HockeyFeedbackListLinkActionCancel" = "Cancel"; +"HockeyFeedbackListLinkActionCancel" = "Annulla"; /* Button Title to Open the Link */ -"HockeyFeedbackListLinkActionOpen" = "Open"; +"HockeyFeedbackListLinkActionOpen" = "Apri"; /* Button Title to Copy the Link */ -"HockeyFeedbackListLinkActionCopy" = "Copy"; +"HockeyFeedbackListLinkActionCopy" = "Copia"; /* UIActivity */ /* Activity Sharing Button Title, App Name will be inserted */ -"HockeyFeedbackActivityButtonTitle" = "%@ Feedback"; +"HockeyFeedbackActivityButtonTitle" = "Commento su %@ "; /* if there can no app name be found, use this instead for HockeyFeedbackActivityButtonTitle */ "HockeyFeedbackActivityAppPlaceholder" = "App"; @@ -199,28 +198,28 @@ /* Compose Message */ /* Title */ -"HockeyFeedbackComposeTitle" = "New Feedback"; +"HockeyFeedbackComposeTitle" = "Nuova commento"; /* Send button */ -"HockeyFeedbackComposeSend" = "Send"; +"HockeyFeedbackComposeSend" = "Invia"; /* Set User Data */ /* Title */ -"HockeyFeedbackUserDataTitle" = "My Info"; +"HockeyFeedbackUserDataTitle" = "Le mie info"; /* Description On What Should Be Entered */ -"HockeyFeedbackUserDataDescription" = "Please provide your information before writing your feedback."; +"HockeyFeedbackUserDataDescription" = "Prima di scrivere il commento inserisci i tuoi dati."; /* Name Field */ -"HockeyFeedbackUserDataName" = "Name"; +"HockeyFeedbackUserDataName" = "Nome"; /* Name Placeholder */ -"HockeyFeedbackUserDataNamePlaceHolder" = "John Doe"; +"HockeyFeedbackUserDataNamePlaceHolder" = "Mario Rossi"; /* Email Field */ -"HockeyFeedbackUserDataEmail" = "Email"; +"HockeyFeedbackUserDataEmail" = "E-mail"; /* Email Placeholder */ -"HockeyFeedbackUserDataEmailPlaceholder" = "example@email.com"; +"HockeyFeedbackUserDataEmailPlaceholder" = "esempio@email.com"; diff --git a/Resources/ja.lproj/HockeySDK.strings b/Resources/ja.lproj/HockeySDK.strings old mode 100755 new mode 100644 index 256b3086..af78fba5 --- a/Resources/ja.lproj/HockeySDK.strings +++ b/Resources/ja.lproj/HockeySDK.strings @@ -1,17 +1,16 @@ -/* General */ +/* General */ /* For dialogs yes buttons */ -"HockeyYes" = "Yes"; +"HockeyYes" = "はい"; /* For dialogs no buttons */ -"HockeyNo" = "No"; +"HockeyNo" = "いいえ"; /* For dialogs ok buttons */ -"HockeyOK" = "保存"; +"HockeyOK" = "OK"; /* Replacement for app name, if it could not be detected */ -"HockeyAppNamePlaceholder" = "This app"; - +"HockeyAppNamePlaceholder" = "この App"; /* Crash */ @@ -19,22 +18,22 @@ /* Crash dialog */ /* Title showing in the alert box when crash report data has been found */ -"CrashDataFoundTitle" = "クラッシュ時のデータを検知"; +"CrashDataFoundTitle" = "%@ が予期しない理由で終了"; /* Description explaining that crash data has been found and ask the user if the data might be uploaded to the developers server */ -"CrashDataFoundAnonymousDescription" = "%@ は不正に終了しました。問題の修正のため、匿名でクラッシュレポートを送信しますか?"; +"CrashDataFoundAnonymousDescription" = "問題が修正できるよう、匿名のレポートを送信しますか。"; /* Description explaining that crash data has been found and ask the user if the non anonymous data might be uplaoded to the developers server */ -"CrashDataFoundDescription" = "%@ は不正に終了しました。問題の修正のため、クラッシュレポートを送信しますか?"; +"CrashDataFoundDescription" = "問題が修正できるよう、レポートを送信しますか。"; /* Alert box button if the users wants to send crash data always automatically */ -"CrashSendReportAlways" = "いつも"; +"CrashSendReportAlways" = "常に送信"; /* Alert box button to send the crash report once */ -"CrashSendReport" = "はい"; +"CrashSendReport" = "レポートを送信"; /* Alert box button to decline sending the report */ -"CrashDontSendReport" = "いいえ"; +"CrashDontSendReport" = "送信しない"; /* Text showing in a processing box that the crash data is being uploaded to the server */ "CrashReportSending" = "送信中…"; @@ -46,67 +45,67 @@ /* Update Alert view */ /* Update available */ -"UpdateAvailable" = "Update available"; +"UpdateAvailable" = "アップデートあり"; -"UpdateAlertTextWithAppVersion" = "%@ is available."; +"UpdateAlertTextWithAppVersion" = "%@ が入手できます。"; -"UpdateAlertMandatoryTextWithAppVersion" = "%@ is available and is a mandatory update!"; +"UpdateAlertMandatoryTextWithAppVersion" = "必須アップデート%@が利用可能です!"; -"UpdateIgnore" = "Ignore"; +"UpdateIgnore" = "無視"; -"UpdateShow" = "Show"; +"UpdateShow" = "表示"; -"UpdateInstall" = "Install"; +"UpdateInstall" = "インストール"; /* Update Details */ -"UpdateScreenTitle" = "Update"; +"UpdateScreenTitle" = "アップデート"; -"UpdateButtonCheck" = "CHECK"; +"UpdateButtonCheck" = "確認"; -"UpdateButtonSearching" = "CHECKING"; +"UpdateButtonSearching" = "確認中"; -"UpdateButtonUpdate" = "UPDATE"; +"UpdateButtonUpdate" = "アップデート"; -"UpdateButtonInstalling" = "INSTALLING"; +"UpdateButtonInstalling" = "インストール中"; -"UpdateButtonOffline" = "OFFLINE"; +"UpdateButtonOffline" = "オフライン"; -"UpdateInstalled" = "INSTALLED"; +"UpdateInstalled" = "インストール済み"; -"UpdateVersion" = "Version"; +"UpdateVersion" = "バージョン"; -"UpdateShowPreviousVersions" = "Show previous versions..."; +"UpdateShowPreviousVersions" = "前のバージョンを表示…"; -"UpdateNoUpdateAvailableTitle" = "No Update Available"; +"UpdateNoUpdateAvailableTitle" = "アップデートなし"; -"UpdateNoUpdateAvailableMessage" = "%@ is already the latest version."; +"UpdateNoUpdateAvailableMessage" = "%@ は現在入手できる最新バージョンです。"; -"UpdateError" = "Error"; +"UpdateError" = "エラー"; -"UpdateWarning" = "Warning"; +"UpdateWarning" = "警告"; -"UpdateNoReleaseNotesAvailable" = "No release notes available."; +"UpdateNoReleaseNotesAvailable" = "リリースノートがありません。"; /* Update Authorization */ -"UpdateAuthorizationProgress" = "Authorizing..."; +"UpdateAuthorizationProgress" = "認証中…"; -"UpdateAuthorizationOffline" = "Internet connection required!"; +"UpdateAuthorizationOffline" = "インターネットへの接続が必要です。"; -"UpdateAuthorizationDenied" = "Authorizing denied. Please contact the developer."; +"UpdateAuthorizationDenied" = "認証が拒否されました。デベロッパに連絡してください。"; /* Update Expiry */ -"UpdateExpired" = "%@ is expired and can not be used any longer."; +"UpdateExpired" = "%@ の有効期限が切れたため、これ以上使用できません。"; /* Update Simulator Warning */ -"UpdateSimulatorMessage" = "Hockey Update does not work in the Simulator.\nThe itms-services:// url scheme is implemented but nonfunctional."; +"UpdateSimulatorMessage" = "Hockey のアップデートは Simulator では作動しません。\nitms-services:// url 方式は実装されていますが、機能しません。"; /* Feedback */ @@ -115,82 +114,82 @@ /* New Message Alert */ /* Alert Title */ -"HockeyFeedbackNewMessageTitle" = "New Feedback Response"; +"HockeyFeedbackNewMessageTitle" = "新規フィードバックの応答"; /* Alert Text */ -"HockeyFeedbackNewMessageText" = "A new response to your feedback is available. Would you like to view it?"; +"HockeyFeedbackNewMessageText" = "フィードバックに対する新しい応答があります。表示しますか。"; /* Alert Ignore Button */ -"HockeyFeedbackIgnore" = "Ignore"; +"HockeyFeedbackIgnore" = "無視"; /* Alert Show Button */ -"HockeyFeedbackShow" = "Show"; +"HockeyFeedbackShow" = "表示"; /* List View */ /* Title */ -"HockeyFeedbackListTitle" = "Feedback"; +"HockeyFeedbackListTitle" = "フィードバック"; /* Last Updated */ -"HockeyFeedbackListLastUpdated" = "Last Updated: %@"; +"HockeyFeedbackListLastUpdated" = "前回のアップデート:%@"; /* Never Updated */ -"HockeyFeedbackListNeverUpdated" = "Never"; +"HockeyFeedbackListNeverUpdated" = "しない"; /* Provide Feedback Button Title */ -"HockeyFeedbackListButonWriteFeedback" = "Provide Feedback"; +"HockeyFeedbackListButonWriteFeedback" = "フィードバックを送信"; /* Add a Response Button Title */ -"HockeyFeedbackListButonWriteResponse" = "Add a Response"; +"HockeyFeedbackListButonWriteResponse" = "応答を追加"; /* User Data Set Name Button Title */ -"HockeyFeedbackListButonUserDataSetName" = "Set Your Name"; +"HockeyFeedbackListButonUserDataSetName" = "名前を設定"; /* User Data Set Email Button Title */ -"HockeyFeedbackListButonUserDataSetEmail" = "Set Your Email"; +"HockeyFeedbackListButonUserDataSetEmail" = "メールを設定"; /* User Data With Name Button Title */ -"HockeyFeedbackListButonUserDataWithName" = "Name: %@"; +"HockeyFeedbackListButonUserDataWithName" = "名前:%@"; /* User Data With Email Button Title */ -"HockeyFeedbackListButonUserDataWithEmail" = "Email: %@"; +"HockeyFeedbackListButonUserDataWithEmail" = "メール:%@"; /* Button title for deleting all local messages*/ -"HockeyFeedbackListButonDeleteAllMessages" = "Delete All Messages"; +"HockeyFeedbackListButonDeleteAllMessages" = "すべてのメッセージを削除"; /* Message pending to be send */ -"HockeyFeedbackListMessagePending" = "Pending"; +"HockeyFeedbackListMessagePending" = "保留中"; /* Delete All Messages Action Sheet / Alert View */ /* Title for the Action Sheet */ -"HockeyFeedbackListDeleteAllTitle" = "This will delete all messages on this device."; +"HockeyFeedbackListDeleteAllTitle" = "この操作はこのデバイスのメッセージすべてを削除します。"; /* Button Title to perform delete action */ -"HockeyFeedbackListDeleteAllDelete" = "Delete"; +"HockeyFeedbackListDeleteAllDelete" = "消去"; /* Button Title to cancel delete action */ -"HockeyFeedbackListDeleteAllCancel" = "Cancel"; +"HockeyFeedbackListDeleteAllCancel" = "キャンセル"; /* Open Link In Safari Action Sheet / Alert View */ /* Button Title to cancel */ -"HockeyFeedbackListLinkActionCancel" = "Cancel"; +"HockeyFeedbackListLinkActionCancel" = "キャンセル"; /* Button Title to Open the Link */ -"HockeyFeedbackListLinkActionOpen" = "Open"; +"HockeyFeedbackListLinkActionOpen" = "開く"; /* Button Title to Copy the Link */ -"HockeyFeedbackListLinkActionCopy" = "Copy"; +"HockeyFeedbackListLinkActionCopy" = "コピー"; /* UIActivity */ /* Activity Sharing Button Title, App Name will be inserted */ -"HockeyFeedbackActivityButtonTitle" = "%@ Feedback"; +"HockeyFeedbackActivityButtonTitle" = "%@ フィードバック"; /* if there can no app name be found, use this instead for HockeyFeedbackActivityButtonTitle */ "HockeyFeedbackActivityAppPlaceholder" = "App"; @@ -199,28 +198,28 @@ /* Compose Message */ /* Title */ -"HockeyFeedbackComposeTitle" = "New Feedback"; +"HockeyFeedbackComposeTitle" = "新規フィードバック"; /* Send button */ -"HockeyFeedbackComposeSend" = "Send"; +"HockeyFeedbackComposeSend" = "送信"; /* Set User Data */ /* Title */ -"HockeyFeedbackUserDataTitle" = "My Info"; +"HockeyFeedbackUserDataTitle" = "自分の情報"; /* Description On What Should Be Entered */ -"HockeyFeedbackUserDataDescription" = "Please provide your information before writing your feedback."; +"HockeyFeedbackUserDataDescription" = "フィードバックを記入する前に情報を入力してください。"; /* Name Field */ -"HockeyFeedbackUserDataName" = "Name"; +"HockeyFeedbackUserDataName" = "名前"; /* Name Placeholder */ -"HockeyFeedbackUserDataNamePlaceHolder" = "John Doe"; +"HockeyFeedbackUserDataNamePlaceHolder" = "Hiromi Sato"; /* Email Field */ -"HockeyFeedbackUserDataEmail" = "Email"; +"HockeyFeedbackUserDataEmail" = "メール"; /* Email Placeholder */ "HockeyFeedbackUserDataEmailPlaceholder" = "example@email.com"; diff --git a/Resources/pt-PT.lproj/HockeySDK.strings b/Resources/pt-PT.lproj/HockeySDK.strings old mode 100755 new mode 100644 index ca0fd6c0..6d1a091f --- a/Resources/pt-PT.lproj/HockeySDK.strings +++ b/Resources/pt-PT.lproj/HockeySDK.strings @@ -1,4 +1,4 @@ -/* General */ +/* General */ /* For dialogs yes buttons */ "HockeyYes" = "Sim"; @@ -10,8 +10,7 @@ "HockeyOK" = "OK"; /* Replacement for app name, if it could not be detected */ -"HockeyAppNamePlaceholder" = "This app"; - +"HockeyAppNamePlaceholder" = "Esta aplicação"; /* Crash */ @@ -19,25 +18,25 @@ /* Crash dialog */ /* Title showing in the alert box when crash report data has been found */ -"CrashDataFoundTitle" = "Informação de falha encontrada"; +"CrashDataFoundTitle" = "%@ fechou inesperadamente"; /* Description explaining that crash data has been found and ask the user if the data might be uploaded to the developers server */ -"CrashDataFoundAnonymousDescription" = "A aplicação falhou anteriormente. Gostaria de enviar informação ao programador acerca da falha de forma a poderem resolver o problema?"; +"CrashDataFoundAnonymousDescription" = "Pretende enviar um relatório anónimo para que possamos resolver o problema?"; /* Description explaining that crash data has been found and ask the user if the non anonymous data might be uplaoded to the developers server */ -"CrashDataFoundDescription" = "A aplicação falhou anteriormente. Gostaria de enviar informação anónima ao programador acerca da falha de forma a poderem resolver o problema?"; +"CrashDataFoundDescription" = "Pretende enviar um relatório para que possamos resolver o problema?"; /* Alert box button if the users wants to send crash data always automatically */ -"CrashSendReportAlways" = "Sempre"; +"CrashSendReportAlways" = "Enviar sempre"; /* Alert box button to send the crash report once */ -"CrashSendReport" = "Sim"; +"CrashSendReport" = "Enviar relatório"; /* Alert box button to decline sending the report */ -"CrashDontSendReport" = "Não"; +"CrashDontSendReport" = "Não enviar"; /* Text showing in a processing box that the crash data is being uploaded to the server */ -"CrashReportSending" = "Enviando…"; +"CrashReportSending" = "A enviar..."; /* Update */ @@ -46,67 +45,67 @@ /* Update Alert view */ /* Update available */ -"UpdateAvailable" = "Update available"; +"UpdateAvailable" = "Actualização disponível"; -"UpdateAlertTextWithAppVersion" = "%@ is available."; +"UpdateAlertTextWithAppVersion" = "A versão %@ está disponível."; -"UpdateAlertMandatoryTextWithAppVersion" = "%@ is available and is a mandatory update!"; +"UpdateAlertMandatoryTextWithAppVersion" = "A versão %@ está disponível e é uma actualização obrigatória!"; -"UpdateIgnore" = "Ignore"; +"UpdateIgnore" = "Ignorar"; -"UpdateShow" = "Show"; +"UpdateShow" = "Mostrar"; -"UpdateInstall" = "Install"; +"UpdateInstall" = "Instalar"; /* Update Details */ -"UpdateScreenTitle" = "Update"; +"UpdateScreenTitle" = "Actualização"; -"UpdateButtonCheck" = "CHECK"; +"UpdateButtonCheck" = "VERIFICAR"; -"UpdateButtonSearching" = "CHECKING"; +"UpdateButtonSearching" = "VERIFICAR"; -"UpdateButtonUpdate" = "UPDATE"; +"UpdateButtonUpdate" = "ACTUALIZAR"; -"UpdateButtonInstalling" = "INSTALLING"; +"UpdateButtonInstalling" = "INSTALAR"; "UpdateButtonOffline" = "OFFLINE"; -"UpdateInstalled" = "INSTALLED"; +"UpdateInstalled" = "INSTALADO"; -"UpdateVersion" = "Version"; +"UpdateVersion" = "Versão"; -"UpdateShowPreviousVersions" = "Show previous versions..."; +"UpdateShowPreviousVersions" = "Mostrar versões anteriores..."; -"UpdateNoUpdateAvailableTitle" = "No Update Available"; +"UpdateNoUpdateAvailableTitle" = "Nenhuma actualização disponível"; -"UpdateNoUpdateAvailableMessage" = "%@ is already the latest version."; +"UpdateNoUpdateAvailableMessage" = "A versão %@ é a mais recente."; -"UpdateError" = "Error"; +"UpdateError" = "Erro"; -"UpdateWarning" = "Warning"; +"UpdateWarning" = "Aviso"; -"UpdateNoReleaseNotesAvailable" = "No release notes available."; +"UpdateNoReleaseNotesAvailable" = "Nenhuma nota de lançamento disponível."; /* Update Authorization */ -"UpdateAuthorizationProgress" = "Authorizing..."; +"UpdateAuthorizationProgress" = "A autorizar..."; -"UpdateAuthorizationOffline" = "Internet connection required!"; +"UpdateAuthorizationOffline" = "É necessária uma ligação à Internet!"; -"UpdateAuthorizationDenied" = "Authorizing denied. Please contact the developer."; +"UpdateAuthorizationDenied" = "Autorização negada. Contacte o programador."; /* Update Expiry */ -"UpdateExpired" = "%@ is expired and can not be used any longer."; +"UpdateExpired" = "%@ expirou e já não pode ser utilizada."; /* Update Simulator Warning */ -"UpdateSimulatorMessage" = "Hockey Update does not work in the Simulator.\nThe itms-services:// url scheme is implemented but nonfunctional."; +"UpdateSimulatorMessage" = "A actualização Hockey não funciona com o Simulador.\nO url scheme itms-services:// está implementado mas não funciona."; /* Feedback */ @@ -115,112 +114,112 @@ /* New Message Alert */ /* Alert Title */ -"HockeyFeedbackNewMessageTitle" = "New Feedback Response"; +"HockeyFeedbackNewMessageTitle" = "Nova resposta a comentário"; /* Alert Text */ -"HockeyFeedbackNewMessageText" = "A new response to your feedback is available. Would you like to view it?"; +"HockeyFeedbackNewMessageText" = "Está disponível uma nova resposta ao seu comentário. Pretende vê-la?"; /* Alert Ignore Button */ -"HockeyFeedbackIgnore" = "Ignore"; +"HockeyFeedbackIgnore" = "Ignorar"; /* Alert Show Button */ -"HockeyFeedbackShow" = "Show"; +"HockeyFeedbackShow" = "Mostrar"; /* List View */ /* Title */ -"HockeyFeedbackListTitle" = "Feedback"; +"HockeyFeedbackListTitle" = "Comentário"; /* Last Updated */ -"HockeyFeedbackListLastUpdated" = "Last Updated: %@"; +"HockeyFeedbackListLastUpdated" = "Última actualização: %@"; /* Never Updated */ -"HockeyFeedbackListNeverUpdated" = "Never"; +"HockeyFeedbackListNeverUpdated" = "Nunca"; /* Provide Feedback Button Title */ -"HockeyFeedbackListButonWriteFeedback" = "Provide Feedback"; +"HockeyFeedbackListButonWriteFeedback" = "Fornecer comentário"; /* Add a Response Button Title */ -"HockeyFeedbackListButonWriteResponse" = "Add a Response"; +"HockeyFeedbackListButonWriteResponse" = "Adicionar uma resposta"; /* User Data Set Name Button Title */ -"HockeyFeedbackListButonUserDataSetName" = "Set Your Name"; +"HockeyFeedbackListButonUserDataSetName" = "Definir o nome"; /* User Data Set Email Button Title */ -"HockeyFeedbackListButonUserDataSetEmail" = "Set Your Email"; +"HockeyFeedbackListButonUserDataSetEmail" = "Definir o e-mail"; /* User Data With Name Button Title */ -"HockeyFeedbackListButonUserDataWithName" = "Name: %@"; +"HockeyFeedbackListButonUserDataWithName" = "Nome: %@"; /* User Data With Email Button Title */ -"HockeyFeedbackListButonUserDataWithEmail" = "Email: %@"; +"HockeyFeedbackListButonUserDataWithEmail" = "E-mail: %@"; /* Button title for deleting all local messages*/ -"HockeyFeedbackListButonDeleteAllMessages" = "Delete All Messages"; +"HockeyFeedbackListButonDeleteAllMessages" = "Eliminar todas as mensagens"; /* Message pending to be send */ -"HockeyFeedbackListMessagePending" = "Pending"; +"HockeyFeedbackListMessagePending" = "Pendente"; /* Delete All Messages Action Sheet / Alert View */ /* Title for the Action Sheet */ -"HockeyFeedbackListDeleteAllTitle" = "This will delete all messages on this device."; +"HockeyFeedbackListDeleteAllTitle" = "Assim, todas as mensagens do dispositivo serão eliminadas."; /* Button Title to perform delete action */ -"HockeyFeedbackListDeleteAllDelete" = "Delete"; +"HockeyFeedbackListDeleteAllDelete" = "Eliminar"; /* Button Title to cancel delete action */ -"HockeyFeedbackListDeleteAllCancel" = "Cancel"; +"HockeyFeedbackListDeleteAllCancel" = "Cancelar"; /* Open Link In Safari Action Sheet / Alert View */ /* Button Title to cancel */ -"HockeyFeedbackListLinkActionCancel" = "Cancel"; +"HockeyFeedbackListLinkActionCancel" = "Cancelar"; /* Button Title to Open the Link */ -"HockeyFeedbackListLinkActionOpen" = "Open"; +"HockeyFeedbackListLinkActionOpen" = "Abrir"; /* Button Title to Copy the Link */ -"HockeyFeedbackListLinkActionCopy" = "Copy"; +"HockeyFeedbackListLinkActionCopy" = "Copiar"; /* UIActivity */ /* Activity Sharing Button Title, App Name will be inserted */ -"HockeyFeedbackActivityButtonTitle" = "%@ Feedback"; +"HockeyFeedbackActivityButtonTitle" = "Comentário de %@"; /* if there can no app name be found, use this instead for HockeyFeedbackActivityButtonTitle */ -"HockeyFeedbackActivityAppPlaceholder" = "App"; +"HockeyFeedbackActivityAppPlaceholder" = "Aplicação"; /* Compose Message */ /* Title */ -"HockeyFeedbackComposeTitle" = "New Feedback"; +"HockeyFeedbackComposeTitle" = "Novo comentário"; /* Send button */ -"HockeyFeedbackComposeSend" = "Send"; +"HockeyFeedbackComposeSend" = "Enviar"; /* Set User Data */ /* Title */ -"HockeyFeedbackUserDataTitle" = "My Info"; +"HockeyFeedbackUserDataTitle" = "Os meus dados"; /* Description On What Should Be Entered */ -"HockeyFeedbackUserDataDescription" = "Please provide your information before writing your feedback."; +"HockeyFeedbackUserDataDescription" = "Forneça os seus dados antes de escrever o comentário."; /* Name Field */ -"HockeyFeedbackUserDataName" = "Name"; +"HockeyFeedbackUserDataName" = "Nome"; /* Name Placeholder */ -"HockeyFeedbackUserDataNamePlaceHolder" = "John Doe"; +"HockeyFeedbackUserDataNamePlaceHolder" = "João Silva"; /* Email Field */ -"HockeyFeedbackUserDataEmail" = "Email"; +"HockeyFeedbackUserDataEmail" = "E-mail"; /* Email Placeholder */ -"HockeyFeedbackUserDataEmailPlaceholder" = "example@email.com"; +"HockeyFeedbackUserDataEmailPlaceholder" = "exemplo@email.com"; diff --git a/Resources/pt.lproj/HockeySDK.strings b/Resources/pt.lproj/HockeySDK.strings old mode 100755 new mode 100644 index f826ca0d..61f794f5 --- a/Resources/pt.lproj/HockeySDK.strings +++ b/Resources/pt.lproj/HockeySDK.strings @@ -1,4 +1,4 @@ -/* General */ +/* General */ /* For dialogs yes buttons */ "HockeyYes" = "Sim"; @@ -10,8 +10,7 @@ "HockeyOK" = "OK"; /* Replacement for app name, if it could not be detected */ -"HockeyAppNamePlaceholder" = "This app"; - +"HockeyAppNamePlaceholder" = "Este app"; /* Crash */ @@ -19,22 +18,22 @@ /* Crash dialog */ /* Title showing in the alert box when crash report data has been found */ -"CrashDataFoundTitle" = "Dados de falha encontrados"; +"CrashDataFoundTitle" = "%@ fechou repentinamente"; /* Description explaining that crash data has been found and ask the user if the data might be uploaded to the developers server */ -"CrashDataFoundAnonymousDescription" = "O aplicativo falhou anteriormente. Você gostaria de enviar ao desenvolvedor os dados sobre a falha do sistema, para que ele resolva o problema?"; +"CrashDataFoundAnonymousDescription" = "Gostaria de enviar um relatório anônimo para que possamos resolver o problema?"; /* Description explaining that crash data has been found and ask the user if the non anonymous data might be uplaoded to the developers server */ -"CrashDataFoundDescription" = "O aplicativo falhou anteriormente. Você gostaria de enviar ao desenvolvedor os dados sobre a falha do sistema, para que ele resolva o problema?"; +"CrashDataFoundDescription" = "Gostaria de enviar um relatório para que possamos resolver o problema?"; /* Alert box button if the users wants to send crash data always automatically */ -"CrashSendReportAlways" = "Sempre"; +"CrashSendReportAlways" = "Sempre enviar"; /* Alert box button to send the crash report once */ -"CrashSendReport" = "Sim"; +"CrashSendReport" = "Enviar relatório"; /* Alert box button to decline sending the report */ -"CrashDontSendReport" = "Não"; +"CrashDontSendReport" = "Não enviar"; /* Text showing in a processing box that the crash data is being uploaded to the server */ "CrashReportSending" = "Enviando…"; @@ -50,11 +49,11 @@ "UpdateAlertTextWithAppVersion" = "%@ está disponível."; -"UpdateAlertMandatoryTextWithAppVersion" = "%@ está disponível e é uma atualização obrigatória!"; +"UpdateAlertMandatoryTextWithAppVersion" = "%@ está disponível e é uma atualização obrigatória."; "UpdateIgnore" = "Ignorar"; -"UpdateShow" = "Mostrar"; +"UpdateShow" = "Exibir"; "UpdateInstall" = "Instalar"; @@ -65,13 +64,13 @@ "UpdateButtonCheck" = "VERIFICAR"; -"UpdateButtonSearching" = "BUSCANDO"; +"UpdateButtonSearching" = "VERIFICANDO"; "UpdateButtonUpdate" = "ATUALIZAR"; "UpdateButtonInstalling" = "INSTALANDO"; -"UpdateButtonOffline" = "DESCONECTADO"; +"UpdateButtonOffline" = "OFFLINE"; "UpdateInstalled" = "INSTALADO"; @@ -79,34 +78,34 @@ "UpdateShowPreviousVersions" = "Mostrar versões anteriores..."; -"UpdateNoUpdateAvailableTitle" = "Sem atualização disponível"; +"UpdateNoUpdateAvailableTitle" = "Não há atualização disponível"; -"UpdateNoUpdateAvailableMessage" = "%@ já é a última versão disponível."; +"UpdateNoUpdateAvailableMessage" = "%@ já é a versão mais recente."; "UpdateError" = "Erro"; -"UpdateWarning" = "Alerta"; +"UpdateWarning" = "Aviso"; -"UpdateNoReleaseNotesAvailable" = "Sem notas de atualização disponível."; +"UpdateNoReleaseNotesAvailable" = "Não há notas de versão disponíveis."; /* Update Authorization */ "UpdateAuthorizationProgress" = "Autorizando..."; -"UpdateAuthorizationOffline" = "É necessário conexão com a internet!"; +"UpdateAuthorizationOffline" = "É necessário ter conexão à internet."; -"UpdateAuthorizationDenied" = "Autorização negada. Contate o desenvolvedor."; +"UpdateAuthorizationDenied" = "Autorização recusada. Entre em contato com o desenvolvedor."; /* Update Expiry */ -"UpdateExpired" = "%@ is expired and can not be used any longer."; +"UpdateExpired" = "%@ expirou e não pode mais ser usado."; /* Update Simulator Warning */ -"UpdateSimulatorMessage" = "Hockey Update não funciona no Simulador.\nA url itms-services:// é implementada mas não é funcional."; +"UpdateSimulatorMessage" = "A atualização do Hockey não funciona no simulador.\nO protocolo itms-services:// está implementado, mas não funcional."; /* Feedback */ @@ -115,16 +114,16 @@ /* New Message Alert */ /* Alert Title */ -"HockeyFeedbackNewMessageTitle" = "New Feedback Response"; +"HockeyFeedbackNewMessageTitle" = "Nova resposta de feedback"; /* Alert Text */ -"HockeyFeedbackNewMessageText" = "A new response to your feedback is available. Would you like to view it?"; +"HockeyFeedbackNewMessageText" = "Uma nova resposta a seu feedback está disponível. Gostaria de vê-la?"; /* Alert Ignore Button */ -"HockeyFeedbackIgnore" = "Ignore"; +"HockeyFeedbackIgnore" = "Ignorar"; /* Alert Show Button */ -"HockeyFeedbackShow" = "Show"; +"HockeyFeedbackShow" = "Exibir"; /* List View */ @@ -133,64 +132,64 @@ "HockeyFeedbackListTitle" = "Feedback"; /* Last Updated */ -"HockeyFeedbackListLastUpdated" = "Last Updated: %@"; +"HockeyFeedbackListLastUpdated" = "Atualizado em: %@"; /* Never Updated */ -"HockeyFeedbackListNeverUpdated" = "Never"; +"HockeyFeedbackListNeverUpdated" = "Nunca"; /* Provide Feedback Button Title */ -"HockeyFeedbackListButonWriteFeedback" = "Provide Feedback"; +"HockeyFeedbackListButonWriteFeedback" = "Fornecer feedback"; /* Add a Response Button Title */ -"HockeyFeedbackListButonWriteResponse" = "Add a Response"; +"HockeyFeedbackListButonWriteResponse" = "Adicionar uma resposta"; /* User Data Set Name Button Title */ -"HockeyFeedbackListButonUserDataSetName" = "Set Your Name"; +"HockeyFeedbackListButonUserDataSetName" = "Informe seu nome"; /* User Data Set Email Button Title */ -"HockeyFeedbackListButonUserDataSetEmail" = "Set Your Email"; +"HockeyFeedbackListButonUserDataSetEmail" = "Informe seu e-mail"; /* User Data With Name Button Title */ -"HockeyFeedbackListButonUserDataWithName" = "Name: %@"; +"HockeyFeedbackListButonUserDataWithName" = "Nome: %@"; /* User Data With Email Button Title */ -"HockeyFeedbackListButonUserDataWithEmail" = "Email: %@"; +"HockeyFeedbackListButonUserDataWithEmail" = "E-mail: %@"; /* Button title for deleting all local messages*/ -"HockeyFeedbackListButonDeleteAllMessages" = "Delete All Messages"; +"HockeyFeedbackListButonDeleteAllMessages" = "Excluir todas as mensagens"; /* Message pending to be send */ -"HockeyFeedbackListMessagePending" = "Pending"; +"HockeyFeedbackListMessagePending" = "Pendente"; /* Delete All Messages Action Sheet / Alert View */ /* Title for the Action Sheet */ -"HockeyFeedbackListDeleteAllTitle" = "This will delete all messages on this device."; +"HockeyFeedbackListDeleteAllTitle" = "Todas as mensagens serão excluídas deste dispositivo."; /* Button Title to perform delete action */ -"HockeyFeedbackListDeleteAllDelete" = "Delete"; +"HockeyFeedbackListDeleteAllDelete" = "Excluir"; /* Button Title to cancel delete action */ -"HockeyFeedbackListDeleteAllCancel" = "Cancel"; +"HockeyFeedbackListDeleteAllCancel" = "Cancelar"; /* Open Link In Safari Action Sheet / Alert View */ /* Button Title to cancel */ -"HockeyFeedbackListLinkActionCancel" = "Cancel"; +"HockeyFeedbackListLinkActionCancel" = "Cancelar"; /* Button Title to Open the Link */ -"HockeyFeedbackListLinkActionOpen" = "Open"; +"HockeyFeedbackListLinkActionOpen" = "Abrir"; /* Button Title to Copy the Link */ -"HockeyFeedbackListLinkActionCopy" = "Copy"; +"HockeyFeedbackListLinkActionCopy" = "Copiar"; /* UIActivity */ /* Activity Sharing Button Title, App Name will be inserted */ -"HockeyFeedbackActivityButtonTitle" = "%@ Feedback"; +"HockeyFeedbackActivityButtonTitle" = "Feedback para %@"; /* if there can no app name be found, use this instead for HockeyFeedbackActivityButtonTitle */ "HockeyFeedbackActivityAppPlaceholder" = "App"; @@ -199,28 +198,28 @@ /* Compose Message */ /* Title */ -"HockeyFeedbackComposeTitle" = "New Feedback"; +"HockeyFeedbackComposeTitle" = "Novo feedback"; /* Send button */ -"HockeyFeedbackComposeSend" = "Send"; +"HockeyFeedbackComposeSend" = "Enviar"; /* Set User Data */ /* Title */ -"HockeyFeedbackUserDataTitle" = "My Info"; +"HockeyFeedbackUserDataTitle" = "Meus dados"; /* Description On What Should Be Entered */ -"HockeyFeedbackUserDataDescription" = "Please provide your information before writing your feedback."; +"HockeyFeedbackUserDataDescription" = "Informe seus dados antes de redigir seu feedback."; /* Name Field */ -"HockeyFeedbackUserDataName" = "Name"; +"HockeyFeedbackUserDataName" = "Nome"; /* Name Placeholder */ -"HockeyFeedbackUserDataNamePlaceHolder" = "John Doe"; +"HockeyFeedbackUserDataNamePlaceHolder" = "José da Silva"; /* Email Field */ -"HockeyFeedbackUserDataEmail" = "Email"; +"HockeyFeedbackUserDataEmail" = "E-mail"; /* Email Placeholder */ -"HockeyFeedbackUserDataEmailPlaceholder" = "example@email.com"; +"HockeyFeedbackUserDataEmailPlaceholder" = "exemplo@email.com"; diff --git a/Resources/ru.lproj/HockeySDK.strings b/Resources/ru.lproj/HockeySDK.strings old mode 100755 new mode 100644 index 89844ca9..ffceffb1 --- a/Resources/ru.lproj/HockeySDK.strings +++ b/Resources/ru.lproj/HockeySDK.strings @@ -1,4 +1,4 @@ -/* General */ +/* General */ /* For dialogs yes buttons */ "HockeyYes" = "Да"; @@ -10,8 +10,7 @@ "HockeyOK" = "OK"; /* Replacement for app name, if it could not be detected */ -"HockeyAppNamePlaceholder" = "This app"; - +"HockeyAppNamePlaceholder" = "Эта программа"; /* Crash */ @@ -19,25 +18,25 @@ /* Crash dialog */ /* Title showing in the alert box when crash report data has been found */ -"CrashDataFoundTitle" = "Обнаружена проблема"; +"CrashDataFoundTitle" = "Неожиданное завершение %@"; /* Description explaining that crash data has been found and ask the user if the data might be uploaded to the developers server */ -"CrashDataFoundAnonymousDescription" = "%@ программа неожиданно завершена. Хотите ли Вы отправить нам анонимное сообщение о неполадках, чтобы мы могли устранить проблему?"; +"CrashDataFoundAnonymousDescription" = "Пошлете ли вы анонимный отчет, чтобы мы могли исправить эту ошибку?"; /* Description explaining that crash data has been found and ask the user if the non anonymous data might be uplaoded to the developers server */ -"CrashDataFoundDescription" = "%@ программа неожиданно завершена. Хотите ли Вы отправить нам сообщение о неполадках, чтобы мы могли устранить проблему?"; +"CrashDataFoundDescription" = "Пошлете ли вы отчет, чтобы мы могли исправить эту ошибку?"; /* Alert box button if the users wants to send crash data always automatically */ -"CrashSendReportAlways" = "Всегда"; +"CrashSendReportAlways" = "Отправлять всегда"; /* Alert box button to send the crash report once */ -"CrashSendReport" = "Да"; +"CrashSendReport" = "Отправить отчет"; /* Alert box button to decline sending the report */ -"CrashDontSendReport" = "Нет"; +"CrashDontSendReport" = "Не отправлять"; /* Text showing in a processing box that the crash data is being uploaded to the server */ -"CrashReportSending" = "Отправить"; +"CrashReportSending" = "Отправка..."; /* Update */ @@ -46,67 +45,67 @@ /* Update Alert view */ /* Update available */ -"UpdateAvailable" = "Update available"; +"UpdateAvailable" = "Имеется обновление"; -"UpdateAlertTextWithAppVersion" = "%@ is available."; +"UpdateAlertTextWithAppVersion" = " Доступно: %@."; -"UpdateAlertMandatoryTextWithAppVersion" = "%@ is available and is a mandatory update!"; +"UpdateAlertMandatoryTextWithAppVersion" = "Доступно обязательное обновление %@!"; -"UpdateIgnore" = "Ignore"; +"UpdateIgnore" = "Игнорировать"; -"UpdateShow" = "Show"; +"UpdateShow" = "Показать"; -"UpdateInstall" = "Install"; +"UpdateInstall" = "Установить"; /* Update Details */ -"UpdateScreenTitle" = "Update"; +"UpdateScreenTitle" = "Обновить"; -"UpdateButtonCheck" = "CHECK"; +"UpdateButtonCheck" = "ПРОВЕРИТЬ"; -"UpdateButtonSearching" = "CHECKING"; +"UpdateButtonSearching" = "ПРОВЕРКА"; -"UpdateButtonUpdate" = "UPDATE"; +"UpdateButtonUpdate" = "ОБНОВИТЬ"; -"UpdateButtonInstalling" = "INSTALLING"; +"UpdateButtonInstalling" = "УСТАНОВКА"; -"UpdateButtonOffline" = "OFFLINE"; +"UpdateButtonOffline" = "ОФЛАЙН"; -"UpdateInstalled" = "INSTALLED"; +"UpdateInstalled" = "УСТАНОВЛЕНО"; -"UpdateVersion" = "Version"; +"UpdateVersion" = "Версия"; -"UpdateShowPreviousVersions" = "Show previous versions..."; +"UpdateShowPreviousVersions" = "Показать предыдущие версии..."; -"UpdateNoUpdateAvailableTitle" = "No Update Available"; +"UpdateNoUpdateAvailableTitle" = "Нет обновлений"; -"UpdateNoUpdateAvailableMessage" = "%@ is already the latest version."; +"UpdateNoUpdateAvailableMessage" = "%@: самая новая версия."; -"UpdateError" = "Error"; +"UpdateError" = "Ошибка"; -"UpdateWarning" = "Warning"; +"UpdateWarning" = "Предупреждение"; -"UpdateNoReleaseNotesAvailable" = "No release notes available."; +"UpdateNoReleaseNotesAvailable" = "Нет комментариев версии."; /* Update Authorization */ -"UpdateAuthorizationProgress" = "Authorizing..."; +"UpdateAuthorizationProgress" = "Авторизую..."; -"UpdateAuthorizationOffline" = "Internet connection required!"; +"UpdateAuthorizationOffline" = "Нужно подключить Интернет!"; -"UpdateAuthorizationDenied" = "Authorizing denied. Please contact the developer."; +"UpdateAuthorizationDenied" = "Отказано в авторизации. Свяжитесь с разработчиком."; /* Update Expiry */ -"UpdateExpired" = "%@ is expired and can not be used any longer."; +"UpdateExpired" = "Срок использования %@ истек, использование прекращено."; /* Update Simulator Warning */ -"UpdateSimulatorMessage" = "Hockey Update does not work in the Simulator.\nThe itms-services:// url scheme is implemented but nonfunctional."; +"UpdateSimulatorMessage" = "Hockey Update не работает в Simulator.\nСхема itms-services:// url применена, но не работает."; /* Feedback */ @@ -115,106 +114,106 @@ /* New Message Alert */ /* Alert Title */ -"HockeyFeedbackNewMessageTitle" = "New Feedback Response"; +"HockeyFeedbackNewMessageTitle" = "Новый ответ на отклик"; /* Alert Text */ -"HockeyFeedbackNewMessageText" = "A new response to your feedback is available. Would you like to view it?"; +"HockeyFeedbackNewMessageText" = "Поступил новый ответ на ваш отклик. Просмотреть его?"; /* Alert Ignore Button */ -"HockeyFeedbackIgnore" = "Ignore"; +"HockeyFeedbackIgnore" = "Игнорировать"; /* Alert Show Button */ -"HockeyFeedbackShow" = "Show"; +"HockeyFeedbackShow" = "Показать"; /* List View */ /* Title */ -"HockeyFeedbackListTitle" = "Feedback"; +"HockeyFeedbackListTitle" = "Отклик"; /* Last Updated */ -"HockeyFeedbackListLastUpdated" = "Last Updated: %@"; +"HockeyFeedbackListLastUpdated" = "Последнее обновление: %@"; /* Never Updated */ -"HockeyFeedbackListNeverUpdated" = "Never"; +"HockeyFeedbackListNeverUpdated" = "Никогда"; /* Provide Feedback Button Title */ -"HockeyFeedbackListButonWriteFeedback" = "Provide Feedback"; +"HockeyFeedbackListButonWriteFeedback" = "Дать отклик"; /* Add a Response Button Title */ -"HockeyFeedbackListButonWriteResponse" = "Add a Response"; +"HockeyFeedbackListButonWriteResponse" = "Добавить ответ"; /* User Data Set Name Button Title */ -"HockeyFeedbackListButonUserDataSetName" = "Set Your Name"; +"HockeyFeedbackListButonUserDataSetName" = "Уст. ваше имя"; /* User Data Set Email Button Title */ -"HockeyFeedbackListButonUserDataSetEmail" = "Set Your Email"; +"HockeyFeedbackListButonUserDataSetEmail" = "Уст. вашу email"; /* User Data With Name Button Title */ -"HockeyFeedbackListButonUserDataWithName" = "Name: %@"; +"HockeyFeedbackListButonUserDataWithName" = "Имя: %@"; /* User Data With Email Button Title */ "HockeyFeedbackListButonUserDataWithEmail" = "Email: %@"; /* Button title for deleting all local messages*/ -"HockeyFeedbackListButonDeleteAllMessages" = "Delete All Messages"; +"HockeyFeedbackListButonDeleteAllMessages" = "Удалить все сообщения"; /* Message pending to be send */ -"HockeyFeedbackListMessagePending" = "Pending"; +"HockeyFeedbackListMessagePending" = "Ожидание"; /* Delete All Messages Action Sheet / Alert View */ /* Title for the Action Sheet */ -"HockeyFeedbackListDeleteAllTitle" = "This will delete all messages on this device."; +"HockeyFeedbackListDeleteAllTitle" = "Этим действием будут стерты все сообщения на этом устройстве."; /* Button Title to perform delete action */ -"HockeyFeedbackListDeleteAllDelete" = "Delete"; +"HockeyFeedbackListDeleteAllDelete" = "Удалить"; /* Button Title to cancel delete action */ -"HockeyFeedbackListDeleteAllCancel" = "Cancel"; +"HockeyFeedbackListDeleteAllCancel" = "Отменить"; /* Open Link In Safari Action Sheet / Alert View */ /* Button Title to cancel */ -"HockeyFeedbackListLinkActionCancel" = "Cancel"; +"HockeyFeedbackListLinkActionCancel" = "Отменить"; /* Button Title to Open the Link */ -"HockeyFeedbackListLinkActionOpen" = "Open"; +"HockeyFeedbackListLinkActionOpen" = "Открыть"; /* Button Title to Copy the Link */ -"HockeyFeedbackListLinkActionCopy" = "Copy"; +"HockeyFeedbackListLinkActionCopy" = "Копировать"; /* UIActivity */ /* Activity Sharing Button Title, App Name will be inserted */ -"HockeyFeedbackActivityButtonTitle" = "%@ Feedback"; +"HockeyFeedbackActivityButtonTitle" = "Отклик на %@"; /* if there can no app name be found, use this instead for HockeyFeedbackActivityButtonTitle */ -"HockeyFeedbackActivityAppPlaceholder" = "App"; +"HockeyFeedbackActivityAppPlaceholder" = "Программа"; /* Compose Message */ /* Title */ -"HockeyFeedbackComposeTitle" = "New Feedback"; +"HockeyFeedbackComposeTitle" = "Новый отклик"; /* Send button */ -"HockeyFeedbackComposeSend" = "Send"; +"HockeyFeedbackComposeSend" = "Отправить"; /* Set User Data */ /* Title */ -"HockeyFeedbackUserDataTitle" = "My Info"; +"HockeyFeedbackUserDataTitle" = "Мои данные"; /* Description On What Should Be Entered */ -"HockeyFeedbackUserDataDescription" = "Please provide your information before writing your feedback."; +"HockeyFeedbackUserDataDescription" = "Перед отправкой отклика необходимо указать вашу информацию."; /* Name Field */ -"HockeyFeedbackUserDataName" = "Name"; +"HockeyFeedbackUserDataName" = "Имя"; /* Name Placeholder */ "HockeyFeedbackUserDataNamePlaceHolder" = "John Doe"; diff --git a/Resources/sv.lproj/HockeySDK.strings b/Resources/sv.lproj/HockeySDK.strings deleted file mode 100755 index 8ef42ee8..00000000 --- a/Resources/sv.lproj/HockeySDK.strings +++ /dev/null @@ -1,226 +0,0 @@ -/* General */ - -/* For dialogs yes buttons */ -"HockeyYes" = "Ja"; - -/* For dialogs no buttons */ -"HockeyNo" = "Nej"; - -/* For dialogs ok buttons */ -"HockeyOK" = "OK"; - -/* Replacement for app name, if it could not be detected */ -"HockeyAppNamePlaceholder" = "This app"; - - -/* Crash */ - - -/* Crash dialog */ - -/* Title showing in the alert box when crash report data has been found */ -"CrashDataFoundTitle" = "%@ kraschade"; - -/* Description explaining that crash data has been found and ask the user if the data might be uploaded to the developers server */ -"CrashDataFoundAnonymousDescription" = "Vill du skicka en anonym kraschrapport så att vi kan lösa felet?"; - -/* Description explaining that crash data has been found and ask the user if the non anonymous data might be uplaoded to the developers server */ -"CrashDataFoundDescription" = "Vill du skicka en kraschrapport så att vi kan lösa felet?"; - -/* Alert box button if the users wants to send crash data always automatically */ -"CrashSendReportAlways" = "Skicka alltid"; - -/* Alert box button to send the crash report once */ -"CrashSendReport" = "Skicka rapport"; - -/* Alert box button to decline sending the report */ -"CrashDontSendReport" = "Skicka inte"; - -/* Text showing in a processing box that the crash data is being uploaded to the server */ -"CrashReportSending" = "Skickar…"; - - -/* Update */ - - -/* Update Alert view */ - -/* Update available */ -"UpdateAvailable" = "Uppdatering tillgänglig"; - -"UpdateAlertTextWithAppVersion" = "%@ finns."; - -"UpdateAlertMandatoryTextWithAppVersion" = "%@ is available and is a mandatory update!"; - -"UpdateIgnore" = "Ignorera"; - -"UpdateShow" = "Visa"; - -"UpdateInstall" = "Installera"; - - -/* Update Details */ - -"UpdateScreenTitle" = "Uppdatera"; - -"UpdateButtonCheck" = "FRÅGA"; - -"UpdateButtonSearching" = "FRÅGAR"; - -"UpdateButtonUpdate" = "UPPDATERA"; - -"UpdateButtonInstalling" = "INSTALLERAR"; - -"UpdateButtonOffline" = "OFFLINE"; - -"UpdateInstalled" = "INSTALLERAD"; - -"UpdateVersion" = "Version"; - -"UpdateShowPreviousVersions" = "Se tidigare versioner..."; - -"UpdateNoUpdateAvailableTitle" = "Ingen uppdatering tillgänglig"; - -"UpdateNoUpdateAvailableMessage" = "%@ är den senaste versionen."; - -"UpdateError" = "Error"; - -"UpdateWarning" = "Varning"; - -"UpdateNoReleaseNotesAvailable" = "Inga releasenoteringar tillgängliga."; - - -/* Update Authorization */ - -"UpdateAuthorizationProgress" = "Auktoriserar..."; - -"UpdateAuthorizationOffline" = "Internetuppkoppling krävs!"; - -"UpdateAuthorizationDenied" = "Auktoriseringen nekades. Kontakta utvecklaren."; - - -/* Update Expiry */ - -"UpdateExpired" = "%@ is expired and can not be used any longer."; - - -/* Update Simulator Warning */ - -"UpdateSimulatorMessage" = "Hockey Update fungerar inte i Simulatorn.\nitms-services:// url schemat är implementerat men fungerar ej."; - - -/* Feedback */ - - -/* New Message Alert */ - -/* Alert Title */ -"HockeyFeedbackNewMessageTitle" = "New Feedback Response"; - -/* Alert Text */ -"HockeyFeedbackNewMessageText" = "A new response to your feedback is available. Would you like to view it?"; - -/* Alert Ignore Button */ -"HockeyFeedbackIgnore" = "Ignore"; - -/* Alert Show Button */ -"HockeyFeedbackShow" = "Show"; - - -/* List View */ - -/* Title */ -"HockeyFeedbackListTitle" = "Feedback"; - -/* Last Updated */ -"HockeyFeedbackListLastUpdated" = "Last Updated: %@"; - -/* Never Updated */ -"HockeyFeedbackListNeverUpdated" = "Never"; - -/* Provide Feedback Button Title */ -"HockeyFeedbackListButonWriteFeedback" = "Provide Feedback"; - -/* Add a Response Button Title */ -"HockeyFeedbackListButonWriteResponse" = "Add a Response"; - -/* User Data Set Name Button Title */ -"HockeyFeedbackListButonUserDataSetName" = "Set Your Name"; - -/* User Data Set Email Button Title */ -"HockeyFeedbackListButonUserDataSetEmail" = "Set Your Email"; - -/* User Data With Name Button Title */ -"HockeyFeedbackListButonUserDataWithName" = "Name: %@"; - -/* User Data With Email Button Title */ -"HockeyFeedbackListButonUserDataWithEmail" = "Email: %@"; - -/* Button title for deleting all local messages*/ -"HockeyFeedbackListButonDeleteAllMessages" = "Delete All Messages"; - -/* Message pending to be send */ -"HockeyFeedbackListMessagePending" = "Pending"; - - -/* Delete All Messages Action Sheet / Alert View */ - -/* Title for the Action Sheet */ -"HockeyFeedbackListDeleteAllTitle" = "This will delete all messages on this device."; - -/* Button Title to perform delete action */ -"HockeyFeedbackListDeleteAllDelete" = "Delete"; - -/* Button Title to cancel delete action */ -"HockeyFeedbackListDeleteAllCancel" = "Cancel"; - - -/* Open Link In Safari Action Sheet / Alert View */ - -/* Button Title to cancel */ -"HockeyFeedbackListLinkActionCancel" = "Cancel"; - -/* Button Title to Open the Link */ -"HockeyFeedbackListLinkActionOpen" = "Open"; - -/* Button Title to Copy the Link */ -"HockeyFeedbackListLinkActionCopy" = "Copy"; - - -/* UIActivity */ - -/* Activity Sharing Button Title, App Name will be inserted */ -"HockeyFeedbackActivityButtonTitle" = "%@ Feedback"; - -/* if there can no app name be found, use this instead for HockeyFeedbackActivityButtonTitle */ -"HockeyFeedbackActivityAppPlaceholder" = "App"; - - -/* Compose Message */ - -/* Title */ -"HockeyFeedbackComposeTitle" = "New Feedback"; - -/* Send button */ -"HockeyFeedbackComposeSend" = "Send"; - - -/* Set User Data */ - -/* Title */ -"HockeyFeedbackUserDataTitle" = "My Info"; - -/* Description On What Should Be Entered */ -"HockeyFeedbackUserDataDescription" = "Please provide your information before writing your feedback."; - -/* Name Field */ -"HockeyFeedbackUserDataName" = "Name"; - -/* Name Placeholder */ -"HockeyFeedbackUserDataNamePlaceHolder" = "John Doe"; - -/* Email Field */ -"HockeyFeedbackUserDataEmail" = "Email"; - -/* Email Placeholder */ -"HockeyFeedbackUserDataEmailPlaceholder" = "example@email.com"; diff --git a/Resources/tr.lproj/HockeySDK.strings b/Resources/tr.lproj/HockeySDK.strings deleted file mode 100644 index e1f1a158..00000000 --- a/Resources/tr.lproj/HockeySDK.strings +++ /dev/null @@ -1,226 +0,0 @@ -/* General */ - -/* For dialogs yes buttons */ -"HockeyYes" = "Evet"; - -/* For dialogs no buttons */ -"HockeyNo" = "Yok"; - -/* For dialogs ok buttons */ -"HockeyOK" = "Tamam"; - -/* Replacement for app name, if it could not be detected */ -"HockeyAppNamePlaceholder" = "This app"; - - -/* Crash */ - - -/* Crash dialog */ - -/* Title showing in the alert box when crash report data has been found */ -"CrashDataFoundTitle" = "Hata raporu bulundu"; - -/* Description explaining that crash data has been found and ask the user if the data might be uploaded to the developers server */ -"CrashDataFoundAnonymousDescription" = "%@ beklenmeyen bir şekilde kapanmış. Bu hatayı gidermemizi kolaylaştırmak için anonim bir hata raporu göndermek ister misiniz?"; - -/* Description explaining that crash data has been found and ask the user if the non anonymous data might be uplaoded to the developers server */ -"CrashDataFoundDescription" = "%@ beklenmeyen bir şekilde kapanmış. Bu hatayı gidermemizi kolaylaştırmak için bir hata raporu göndermek ister misiniz?"; - -/* Alert box button if the users wants to send crash data always automatically */ -"CrashSendReportAlways" = "Her seferinde gönder!"; - -/* Alert box button to send the crash report once */ -"CrashSendReport" = "Gönder!"; - -/* Alert box button to decline sending the report */ -"CrashDontSendReport" = "Hayır"; - -/* Text showing in a processing box that the crash data is being uploaded to the server */ -"CrashReportSending" = "Gönderiliyor…"; - - -/* Update */ - - -/* Update Alert view */ - -/* Update available */ -"UpdateAvailable" = "Update available"; - -"UpdateAlertTextWithAppVersion" = "%@ is available."; - -"UpdateAlertMandatoryTextWithAppVersion" = "%@ is available and is a mandatory update!"; - -"UpdateIgnore" = "Ignore"; - -"UpdateShow" = "Show"; - -"UpdateInstall" = "Install"; - - -/* Update Details */ - -"UpdateScreenTitle" = "Update"; - -"UpdateButtonCheck" = "CHECK"; - -"UpdateButtonSearching" = "CHECKING"; - -"UpdateButtonUpdate" = "UPDATE"; - -"UpdateButtonInstalling" = "INSTALLING"; - -"UpdateButtonOffline" = "OFFLINE"; - -"UpdateInstalled" = "INSTALLED"; - -"UpdateVersion" = "Version"; - -"UpdateShowPreviousVersions" = "Show previous versions..."; - -"UpdateNoUpdateAvailableTitle" = "No Update Available"; - -"UpdateNoUpdateAvailableMessage" = "%@ is already the latest version."; - -"UpdateError" = "Error"; - -"UpdateWarning" = "Warning"; - -"UpdateNoReleaseNotesAvailable" = "No release notes available."; - - -/* Update Authorization */ - -"UpdateAuthorizationProgress" = "Authorizing..."; - -"UpdateAuthorizationOffline" = "Internet connection required!"; - -"UpdateAuthorizationDenied" = "Authorizing denied. Please contact the developer."; - - -/* Update Expiry */ - -"UpdateExpired" = "%@ is expired and can not be used any longer."; - - -/* Update Simulator Warning */ - -"UpdateSimulatorMessage" = "Hockey Update does not work in the Simulator.\nThe itms-services:// url scheme is implemented but nonfunctional."; - - -/* Feedback */ - - -/* New Message Alert */ - -/* Alert Title */ -"HockeyFeedbackNewMessageTitle" = "New Feedback Response"; - -/* Alert Text */ -"HockeyFeedbackNewMessageText" = "A new response to your feedback is available. Would you like to view it?"; - -/* Alert Ignore Button */ -"HockeyFeedbackIgnore" = "Ignore"; - -/* Alert Show Button */ -"HockeyFeedbackShow" = "Show"; - - -/* List View */ - -/* Title */ -"HockeyFeedbackListTitle" = "Feedback"; - -/* Last Updated */ -"HockeyFeedbackListLastUpdated" = "Last Updated: %@"; - -/* Never Updated */ -"HockeyFeedbackListNeverUpdated" = "Never"; - -/* Provide Feedback Button Title */ -"HockeyFeedbackListButonWriteFeedback" = "Provide Feedback"; - -/* Add a Response Button Title */ -"HockeyFeedbackListButonWriteResponse" = "Add a Response"; - -/* User Data Set Name Button Title */ -"HockeyFeedbackListButonUserDataSetName" = "Set Your Name"; - -/* User Data Set Email Button Title */ -"HockeyFeedbackListButonUserDataSetEmail" = "Set Your Email"; - -/* User Data With Name Button Title */ -"HockeyFeedbackListButonUserDataWithName" = "Name: %@"; - -/* User Data With Email Button Title */ -"HockeyFeedbackListButonUserDataWithEmail" = "Email: %@"; - -/* Button title for deleting all local messages*/ -"HockeyFeedbackListButonDeleteAllMessages" = "Delete All Messages"; - -/* Message pending to be send */ -"HockeyFeedbackListMessagePending" = "Pending"; - - -/* Delete All Messages Action Sheet / Alert View */ - -/* Title for the Action Sheet */ -"HockeyFeedbackListDeleteAllTitle" = "This will delete all messages on this device."; - -/* Button Title to perform delete action */ -"HockeyFeedbackListDeleteAllDelete" = "Delete"; - -/* Button Title to cancel delete action */ -"HockeyFeedbackListDeleteAllCancel" = "Cancel"; - - -/* Open Link In Safari Action Sheet / Alert View */ - -/* Button Title to cancel */ -"HockeyFeedbackListLinkActionCancel" = "Cancel"; - -/* Button Title to Open the Link */ -"HockeyFeedbackListLinkActionOpen" = "Open"; - -/* Button Title to Copy the Link */ -"HockeyFeedbackListLinkActionCopy" = "Copy"; - - -/* UIActivity */ - -/* Activity Sharing Button Title, App Name will be inserted */ -"HockeyFeedbackActivityButtonTitle" = "%@ Feedback"; - -/* if there can no app name be found, use this instead for HockeyFeedbackActivityButtonTitle */ -"HockeyFeedbackActivityAppPlaceholder" = "App"; - - -/* Compose Message */ - -/* Title */ -"HockeyFeedbackComposeTitle" = "New Feedback"; - -/* Send button */ -"HockeyFeedbackComposeSend" = "Send"; - - -/* Set User Data */ - -/* Title */ -"HockeyFeedbackUserDataTitle" = "My Info"; - -/* Description On What Should Be Entered */ -"HockeyFeedbackUserDataDescription" = "Please provide your information before writing your feedback."; - -/* Name Field */ -"HockeyFeedbackUserDataName" = "Name"; - -/* Name Placeholder */ -"HockeyFeedbackUserDataNamePlaceHolder" = "John Doe"; - -/* Email Field */ -"HockeyFeedbackUserDataEmail" = "Email"; - -/* Email Placeholder */ -"HockeyFeedbackUserDataEmailPlaceholder" = "example@email.com"; diff --git a/Resources/zh.lproj/HockeySDK.strings b/Resources/zh.lproj/HockeySDK.strings new file mode 100644 index 00000000..5c198e9d --- /dev/null +++ b/Resources/zh.lproj/HockeySDK.strings @@ -0,0 +1,225 @@ +/* General */ + +/* For dialogs yes buttons */ +"HockeyYes" = "是"; + +/* For dialogs no buttons */ +"HockeyNo" = "无"; + +/* For dialogs ok buttons */ +"HockeyOK" = "确定"; + +/* Replacement for app name, if it could not be detected */ +"HockeyAppNamePlaceholder" = "这个 app"; + +/* Crash */ + + +/* Crash dialog */ + +/* Title showing in the alert box when crash report data has been found */ +"CrashDataFoundTitle" = "%@ 意外退出"; + +/* Description explaining that crash data has been found and ask the user if the data might be uploaded to the developers server */ +"CrashDataFoundAnonymousDescription" = "你想发送一个匿名报告,以便我们能够解决这个问题吗?"; + +/* Description explaining that crash data has been found and ask the user if the non anonymous data might be uplaoded to the developers server */ +"CrashDataFoundDescription" = "你想发送一个报告,以便我们能够解决这个问题吗?"; + +/* Alert box button if the users wants to send crash data always automatically */ +"CrashSendReportAlways" = "总是发送"; + +/* Alert box button to send the crash report once */ +"CrashSendReport" = "发送报告"; + +/* Alert box button to decline sending the report */ +"CrashDontSendReport" = "不发送"; + +/* Text showing in a processing box that the crash data is being uploaded to the server */ +"CrashReportSending" = "正在发送..."; + + +/* Update */ + + +/* Update Alert view */ + +/* Update available */ +"UpdateAvailable" = "更新已推出"; + +"UpdateAlertTextWithAppVersion" = "%@ 已可用。"; + +"UpdateAlertMandatoryTextWithAppVersion" = "%@ 已可用,并且是一个强制更新。"; + +"UpdateIgnore" = "忽略"; + +"UpdateShow" = "显示"; + +"UpdateInstall" = "安装"; + + +/* Update Details */ + +"UpdateScreenTitle" = "更新"; + +"UpdateButtonCheck" = "检查"; + +"UpdateButtonSearching" = "正在检查"; + +"UpdateButtonUpdate" = "更新"; + +"UpdateButtonInstalling" = "正在安装"; + +"UpdateButtonOffline" = "离线"; + +"UpdateInstalled" = "已安装"; + +"UpdateVersion" = "版本"; + +"UpdateShowPreviousVersions" = "显示之前版本..."; + +"UpdateNoUpdateAvailableTitle" = "无可用更新"; + +"UpdateNoUpdateAvailableMessage" = "%@ 已经是最新的版本了。"; + +"UpdateError" = "错误"; + +"UpdateWarning" = "警告"; + +"UpdateNoReleaseNotesAvailable" = "无发行说明。"; + + +/* Update Authorization */ + +"UpdateAuthorizationProgress" = "授权中..."; + +"UpdateAuthorizationOffline" = "需要 Internet 连接!"; + +"UpdateAuthorizationDenied" = "授权被拒绝。请与开发商联系。"; + + +/* Update Expiry */ + +"UpdateExpired" = "%@ 已过期,所以无法使用。"; + + +/* Update Simulator Warning */ + +"UpdateSimulatorMessage" = "Hockey 更新无法在仿真器中进行。\n这个 itms-services:// 网页连接架构已开始实施但无法正常工作。"; + + +/* Feedback */ + + +/* New Message Alert */ + +/* Alert Title */ +"HockeyFeedbackNewMessageTitle" = "新的意见反馈回应"; + +/* Alert Text */ +"HockeyFeedbackNewMessageText" = "你的反馈已有一个新的回应,想查看它吗?"; + +/* Alert Ignore Button */ +"HockeyFeedbackIgnore" = "忽略"; + +/* Alert Show Button */ +"HockeyFeedbackShow" = "显示"; + + +/* List View */ + +/* Title */ +"HockeyFeedbackListTitle" = "意见反馈"; + +/* Last Updated */ +"HockeyFeedbackListLastUpdated" = "上次更新: %@"; + +/* Never Updated */ +"HockeyFeedbackListNeverUpdated" = "从不"; + +/* Provide Feedback Button Title */ +"HockeyFeedbackListButonWriteFeedback" = "提供意见反馈"; + +/* Add a Response Button Title */ +"HockeyFeedbackListButonWriteResponse" = "添加一个回应"; + +/* User Data Set Name Button Title */ +"HockeyFeedbackListButonUserDataSetName" = "设置你的姓名"; + +/* User Data Set Email Button Title */ +"HockeyFeedbackListButonUserDataSetEmail" = "设置你的邮件"; + +/* User Data With Name Button Title */ +"HockeyFeedbackListButonUserDataWithName" = "姓名: %@"; + +/* User Data With Email Button Title */ +"HockeyFeedbackListButonUserDataWithEmail" = "邮件: %@"; + +/* Button title for deleting all local messages*/ +"HockeyFeedbackListButonDeleteAllMessages" = "删除全部信息"; + +/* Message pending to be send */ +"HockeyFeedbackListMessagePending" = "挂起"; + + +/* Delete All Messages Action Sheet / Alert View */ + +/* Title for the Action Sheet */ +"HockeyFeedbackListDeleteAllTitle" = "这将会删除此设备上的所有信息。"; + +/* Button Title to perform delete action */ +"HockeyFeedbackListDeleteAllDelete" = "删除"; + +/* Button Title to cancel delete action */ +"HockeyFeedbackListDeleteAllCancel" = "取消"; + + +/* Open Link In Safari Action Sheet / Alert View */ + +/* Button Title to cancel */ +"HockeyFeedbackListLinkActionCancel" = "取消"; + +/* Button Title to Open the Link */ +"HockeyFeedbackListLinkActionOpen" = "打开"; + +/* Button Title to Copy the Link */ +"HockeyFeedbackListLinkActionCopy" = "拷贝"; + + +/* UIActivity */ + +/* Activity Sharing Button Title, App Name will be inserted */ +"HockeyFeedbackActivityButtonTitle" = "%@ 意见反馈"; + +/* if there can no app name be found, use this instead for HockeyFeedbackActivityButtonTitle */ +"HockeyFeedbackActivityAppPlaceholder" = "App"; + + +/* Compose Message */ + +/* Title */ +"HockeyFeedbackComposeTitle" = "新的意见反馈"; + +/* Send button */ +"HockeyFeedbackComposeSend" = "发送"; + + +/* Set User Data */ + +/* Title */ +"HockeyFeedbackUserDataTitle" = "我的信息"; + +/* Description On What Should Be Entered */ +"HockeyFeedbackUserDataDescription" = "请提供你的信息,再写入意见反馈。"; + +/* Name Field */ +"HockeyFeedbackUserDataName" = "姓名"; + +/* Name Placeholder */ +"HockeyFeedbackUserDataNamePlaceHolder" = "张三"; + +/* Email Field */ +"HockeyFeedbackUserDataEmail" = "邮件"; + +/* Email Placeholder */ +"HockeyFeedbackUserDataEmailPlaceholder" = "example@email.com"; diff --git a/Resources/zh_CN.lproj/HockeySDK.strings b/Resources/zh_CN.lproj/HockeySDK.strings deleted file mode 100644 index af0ec4d7..00000000 --- a/Resources/zh_CN.lproj/HockeySDK.strings +++ /dev/null @@ -1,226 +0,0 @@ -/* General */ - -/* For dialogs yes buttons */ -"HockeyYes" = "Yes"; - -/* For dialogs no buttons */ -"HockeyNo" = "No"; - -/* For dialogs ok buttons */ -"HockeyOK" = "确定"; - -/* Replacement for app name, if it could not be detected */ -"HockeyAppNamePlaceholder" = "This app"; - - -/* Crash */ - - -/* Crash dialog */ - -/* Title showing in the alert box when crash report data has been found */ -"CrashDataFoundTitle" = "发现崩溃数据"; - -/* Description explaining that crash data has been found and ask the user if the data might be uploaded to the developers server */ -"CrashDataFoundAnonymousDescription" = "%@ 不正常退出。您能否匿名提供崩溃记录以帮助我们解决问题?"; - -/* Description explaining that crash data has been found and ask the user if the non anonymous data might be uplaoded to the developers server */ -"CrashDataFoundDescription" = "%@ 不正常退出。您能否提供崩溃记录以帮助我们解决问题?"; - -/* Alert box button if the users wants to send crash data always automatically */ -"CrashSendReportAlways" = "总是"; - -/* Alert box button to send the crash report once */ -"CrashSendReport" = "是"; - -/* Alert box button to decline sending the report */ -"CrashDontSendReport" = "否"; - -/* Text showing in a processing box that the crash data is being uploaded to the server */ -"CrashReportSending" = "发送中…"; - - -/* Update */ - - -/* Update Alert view */ - -/* Update available */ -"UpdateAvailable" = "Update available"; - -"UpdateAlertTextWithAppVersion" = "%@ is available."; - -"UpdateAlertMandatoryTextWithAppVersion" = "%@ is available and is a mandatory update!"; - -"UpdateIgnore" = "Ignore"; - -"UpdateShow" = "Show"; - -"UpdateInstall" = "Install"; - - -/* Update Details */ - -"UpdateScreenTitle" = "Update"; - -"UpdateButtonCheck" = "CHECK"; - -"UpdateButtonSearching" = "CHECKING"; - -"UpdateButtonUpdate" = "UPDATE"; - -"UpdateButtonInstalling" = "INSTALLING"; - -"UpdateButtonOffline" = "OFFLINE"; - -"UpdateInstalled" = "INSTALLED"; - -"UpdateVersion" = "Version"; - -"UpdateShowPreviousVersions" = "Show previous versions..."; - -"UpdateNoUpdateAvailableTitle" = "No Update Available"; - -"UpdateNoUpdateAvailableMessage" = "%@ is already the latest version."; - -"UpdateError" = "Error"; - -"UpdateWarning" = "Warning"; - -"UpdateNoReleaseNotesAvailable" = "No release notes available."; - - -/* Update Authorization */ - -"UpdateAuthorizationProgress" = "Authorizing..."; - -"UpdateAuthorizationOffline" = "Internet connection required!"; - -"UpdateAuthorizationDenied" = "Authorizing denied. Please contact the developer."; - - -/* Update Expiry */ - -"UpdateExpired" = "%@ is expired and can not be used any longer."; - - -/* Update Simulator Warning */ - -"UpdateSimulatorMessage" = "Hockey Update does not work in the Simulator.\nThe itms-services:// url scheme is implemented but nonfunctional."; - - -/* Feedback */ - - -/* New Message Alert */ - -/* Alert Title */ -"HockeyFeedbackNewMessageTitle" = "New Feedback Response"; - -/* Alert Text */ -"HockeyFeedbackNewMessageText" = "A new response to your feedback is available. Would you like to view it?"; - -/* Alert Ignore Button */ -"HockeyFeedbackIgnore" = "Ignore"; - -/* Alert Show Button */ -"HockeyFeedbackShow" = "Show"; - - -/* List View */ - -/* Title */ -"HockeyFeedbackListTitle" = "Feedback"; - -/* Last Updated */ -"HockeyFeedbackListLastUpdated" = "Last Updated: %@"; - -/* Never Updated */ -"HockeyFeedbackListNeverUpdated" = "Never"; - -/* Provide Feedback Button Title */ -"HockeyFeedbackListButonWriteFeedback" = "Provide Feedback"; - -/* Add a Response Button Title */ -"HockeyFeedbackListButonWriteResponse" = "Add a Response"; - -/* User Data Set Name Button Title */ -"HockeyFeedbackListButonUserDataSetName" = "Set Your Name"; - -/* User Data Set Email Button Title */ -"HockeyFeedbackListButonUserDataSetEmail" = "Set Your Email"; - -/* User Data With Name Button Title */ -"HockeyFeedbackListButonUserDataWithName" = "Name: %@"; - -/* User Data With Email Button Title */ -"HockeyFeedbackListButonUserDataWithEmail" = "Email: %@"; - -/* Button title for deleting all local messages*/ -"HockeyFeedbackListButonDeleteAllMessages" = "Delete All Messages"; - -/* Message pending to be send */ -"HockeyFeedbackListMessagePending" = "Pending"; - - -/* Delete All Messages Action Sheet / Alert View */ - -/* Title for the Action Sheet */ -"HockeyFeedbackListDeleteAllTitle" = "This will delete all messages on this device."; - -/* Button Title to perform delete action */ -"HockeyFeedbackListDeleteAllDelete" = "Delete"; - -/* Button Title to cancel delete action */ -"HockeyFeedbackListDeleteAllCancel" = "Cancel"; - - -/* Open Link In Safari Action Sheet / Alert View */ - -/* Button Title to cancel */ -"HockeyFeedbackListLinkActionCancel" = "Cancel"; - -/* Button Title to Open the Link */ -"HockeyFeedbackListLinkActionOpen" = "Open"; - -/* Button Title to Copy the Link */ -"HockeyFeedbackListLinkActionCopy" = "Copy"; - - -/* UIActivity */ - -/* Activity Sharing Button Title, App Name will be inserted */ -"HockeyFeedbackActivityButtonTitle" = "%@ Feedback"; - -/* if there can no app name be found, use this instead for HockeyFeedbackActivityButtonTitle */ -"HockeyFeedbackActivityAppPlaceholder" = "App"; - - -/* Compose Message */ - -/* Title */ -"HockeyFeedbackComposeTitle" = "New Feedback"; - -/* Send button */ -"HockeyFeedbackComposeSend" = "Send"; - - -/* Set User Data */ - -/* Title */ -"HockeyFeedbackUserDataTitle" = "My Info"; - -/* Description On What Should Be Entered */ -"HockeyFeedbackUserDataDescription" = "Please provide your information before writing your feedback."; - -/* Name Field */ -"HockeyFeedbackUserDataName" = "Name"; - -/* Name Placeholder */ -"HockeyFeedbackUserDataNamePlaceHolder" = "John Doe"; - -/* Email Field */ -"HockeyFeedbackUserDataEmail" = "Email"; - -/* Email Placeholder */ -"HockeyFeedbackUserDataEmailPlaceholder" = "example@email.com"; diff --git a/Resources/zh_TW.lproj/HockeySDK.strings b/Resources/zh_TW.lproj/HockeySDK.strings deleted file mode 100644 index 6773222b..00000000 --- a/Resources/zh_TW.lproj/HockeySDK.strings +++ /dev/null @@ -1,226 +0,0 @@ -/* General */ - -/* For dialogs yes buttons */ -"HockeyYes" = "Yes"; - -/* For dialogs no buttons */ -"HockeyNo" = "No"; - -/* For dialogs ok buttons */ -"HockeyOK" = "確定"; - -/* Replacement for app name, if it could not be detected */ -"HockeyAppNamePlaceholder" = "This app"; - - -/* Crash */ - - -/* Crash dialog */ - -/* Title showing in the alert box when crash report data has been found */ -"CrashDataFoundTitle" = "發現崩潰數據"; - -/* Description explaining that crash data has been found and ask the user if the data might be uploaded to the developers server */ -"CrashDataFoundAnonymousDescription" = "%@ 不正常退出。你能否匿名提供崩潰記錄以幫助我們解決問題?"; - -/* Description explaining that crash data has been found and ask the user if the non anonymous data might be uplaoded to the developers server */ -"CrashDataFoundDescription" = "%@ 不正常退出。你能否名提供崩潰記錄以幫助我們解決問題?"; - -/* Alert box button if the users wants to send crash data always automatically */ -"CrashSendReportAlways" = "總是"; - -/* Alert box button to send the crash report once */ -"CrashSendReport" = "是"; - -/* Alert box button to decline sending the report */ -"CrashDontSendReport" = "否"; - -/* Text showing in a processing box that the crash data is being uploaded to the server */ -"CrashReportSending" = "發送中…"; - - -/* Update */ - - -/* Update Alert view */ - -/* Update available */ -"UpdateAvailable" = "Update available"; - -"UpdateAlertTextWithAppVersion" = "%@ is available."; - -"UpdateAlertMandatoryTextWithAppVersion" = "%@ is available and is a mandatory update!"; - -"UpdateIgnore" = "Ignore"; - -"UpdateShow" = "Show"; - -"UpdateInstall" = "Install"; - - -/* Update Details */ - -"UpdateScreenTitle" = "Update"; - -"UpdateButtonCheck" = "CHECK"; - -"UpdateButtonSearching" = "CHECKING"; - -"UpdateButtonUpdate" = "UPDATE"; - -"UpdateButtonInstalling" = "INSTALLING"; - -"UpdateButtonOffline" = "OFFLINE"; - -"UpdateInstalled" = "INSTALLED"; - -"UpdateVersion" = "Version"; - -"UpdateShowPreviousVersions" = "Show previous versions..."; - -"UpdateNoUpdateAvailableTitle" = "No Update Available"; - -"UpdateNoUpdateAvailableMessage" = "%@ is already the latest version."; - -"UpdateError" = "Error"; - -"UpdateWarning" = "Warning"; - -"UpdateNoReleaseNotesAvailable" = "No release notes available."; - - -/* Update Authorization */ - -"UpdateAuthorizationProgress" = "Authorizing..."; - -"UpdateAuthorizationOffline" = "Internet connection required!"; - -"UpdateAuthorizationDenied" = "Authorizing denied. Please contact the developer."; - - -/* Update Expiry */ - -"UpdateExpired" = "%@ is expired and can not be used any longer."; - - -/* Update Simulator Warning */ - -"UpdateSimulatorMessage" = "Hockey Update does not work in the Simulator.\nThe itms-services:// url scheme is implemented but nonfunctional."; - - -/* Feedback */ - - -/* New Message Alert */ - -/* Alert Title */ -"HockeyFeedbackNewMessageTitle" = "New Feedback Response"; - -/* Alert Text */ -"HockeyFeedbackNewMessageText" = "A new response to your feedback is available. Would you like to view it?"; - -/* Alert Ignore Button */ -"HockeyFeedbackIgnore" = "Ignore"; - -/* Alert Show Button */ -"HockeyFeedbackShow" = "Show"; - - -/* List View */ - -/* Title */ -"HockeyFeedbackListTitle" = "Feedback"; - -/* Last Updated */ -"HockeyFeedbackListLastUpdated" = "Last Updated: %@"; - -/* Never Updated */ -"HockeyFeedbackListNeverUpdated" = "Never"; - -/* Provide Feedback Button Title */ -"HockeyFeedbackListButonWriteFeedback" = "Provide Feedback"; - -/* Add a Response Button Title */ -"HockeyFeedbackListButonWriteResponse" = "Add a Response"; - -/* User Data Set Name Button Title */ -"HockeyFeedbackListButonUserDataSetName" = "Set Your Name"; - -/* User Data Set Email Button Title */ -"HockeyFeedbackListButonUserDataSetEmail" = "Set Your Email"; - -/* User Data With Name Button Title */ -"HockeyFeedbackListButonUserDataWithName" = "Name: %@"; - -/* User Data With Email Button Title */ -"HockeyFeedbackListButonUserDataWithEmail" = "Email: %@"; - -/* Button title for deleting all local messages*/ -"HockeyFeedbackListButonDeleteAllMessages" = "Delete All Messages"; - -/* Message pending to be send */ -"HockeyFeedbackListMessagePending" = "Pending"; - - -/* Delete All Messages Action Sheet / Alert View */ - -/* Title for the Action Sheet */ -"HockeyFeedbackListDeleteAllTitle" = "This will delete all messages on this device."; - -/* Button Title to perform delete action */ -"HockeyFeedbackListDeleteAllDelete" = "Delete"; - -/* Button Title to cancel delete action */ -"HockeyFeedbackListDeleteAllCancel" = "Cancel"; - - -/* Open Link In Safari Action Sheet / Alert View */ - -/* Button Title to cancel */ -"HockeyFeedbackListLinkActionCancel" = "Cancel"; - -/* Button Title to Open the Link */ -"HockeyFeedbackListLinkActionOpen" = "Open"; - -/* Button Title to Copy the Link */ -"HockeyFeedbackListLinkActionCopy" = "Copy"; - - -/* UIActivity */ - -/* Activity Sharing Button Title, App Name will be inserted */ -"HockeyFeedbackActivityButtonTitle" = "%@ Feedback"; - -/* if there can no app name be found, use this instead for HockeyFeedbackActivityButtonTitle */ -"HockeyFeedbackActivityAppPlaceholder" = "App"; - - -/* Compose Message */ - -/* Title */ -"HockeyFeedbackComposeTitle" = "New Feedback"; - -/* Send button */ -"HockeyFeedbackComposeSend" = "Send"; - - -/* Set User Data */ - -/* Title */ -"HockeyFeedbackUserDataTitle" = "My Info"; - -/* Description On What Should Be Entered */ -"HockeyFeedbackUserDataDescription" = "Please provide your information before writing your feedback."; - -/* Name Field */ -"HockeyFeedbackUserDataName" = "Name"; - -/* Name Placeholder */ -"HockeyFeedbackUserDataNamePlaceHolder" = "John Doe"; - -/* Email Field */ -"HockeyFeedbackUserDataEmail" = "Email"; - -/* Email Placeholder */ -"HockeyFeedbackUserDataEmailPlaceholder" = "example@email.com"; diff --git a/Support/HockeySDK.xcodeproj/project.pbxproj b/Support/HockeySDK.xcodeproj/project.pbxproj index b5df5842..420305eb 100644 --- a/Support/HockeySDK.xcodeproj/project.pbxproj +++ b/Support/HockeySDK.xcodeproj/project.pbxproj @@ -41,7 +41,6 @@ 1E1127C916580C87007067A2 /* buttonRoundedRegular@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 1E1127C116580C87007067A2 /* buttonRoundedRegular@2x.png */; }; 1E1127CA16580C87007067A2 /* buttonRoundedRegularHighlighted.png in Resources */ = {isa = PBXBuildFile; fileRef = 1E1127C216580C87007067A2 /* buttonRoundedRegularHighlighted.png */; }; 1E1127CB16580C87007067A2 /* buttonRoundedRegularHighlighted@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 1E1127C316580C87007067A2 /* buttonRoundedRegularHighlighted@2x.png */; }; - 1E27EF2515BB5033000AE995 /* HockeySDK.strings in Resources */ = {isa = PBXBuildFile; fileRef = 1E59555F15B6F80E00A03429 /* HockeySDK.strings */; }; 1E49A43C1612223B00463151 /* BITFeedbackComposeViewController.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E49A42D1612223B00463151 /* BITFeedbackComposeViewController.h */; settings = {ATTRIBUTES = (Public, ); }; }; 1E49A43F1612223B00463151 /* BITFeedbackComposeViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 1E49A42E1612223B00463151 /* BITFeedbackComposeViewController.m */; }; 1E49A4421612223B00463151 /* BITFeedbackListViewCell.h in Headers */ = {isa = PBXBuildFile; fileRef = 1E49A42F1612223B00463151 /* BITFeedbackListViewCell.h */; }; @@ -184,14 +183,8 @@ 1E59556615B6F82300A03429 /* fr */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.strings; name = fr; path = fr.lproj/HockeySDK.strings; sourceTree = ""; }; 1E59556815B6F82A00A03429 /* it */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.strings; name = it; path = it.lproj/HockeySDK.strings; sourceTree = ""; }; 1E59556A15B6F83100A03429 /* ja */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.strings; name = ja; path = ja.lproj/HockeySDK.strings; sourceTree = ""; }; - 1E59556C15B6F83700A03429 /* nl */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.strings; name = nl; path = nl.lproj/HockeySDK.strings; sourceTree = ""; }; - 1E59556E15B6F84000A03429 /* pt-PT */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.strings; name = "pt-PT"; path = "pt-PT.lproj/HockeySDK.strings"; sourceTree = ""; }; 1E59557015B6F84700A03429 /* pt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.strings; name = pt; path = pt.lproj/HockeySDK.strings; sourceTree = ""; }; 1E59557215B6F84D00A03429 /* ru */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.strings; name = ru; path = ru.lproj/HockeySDK.strings; sourceTree = ""; }; - 1E59557415B6F85700A03429 /* sv */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.strings; name = sv; path = sv.lproj/HockeySDK.strings; sourceTree = ""; }; - 1E59557615B6F85E00A03429 /* tr */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.strings; name = tr; path = tr.lproj/HockeySDK.strings; sourceTree = ""; }; - 1E59557815B6F86600A03429 /* zh_CN */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.strings; name = zh_CN; path = zh_CN.lproj/HockeySDK.strings; sourceTree = ""; }; - 1E59557A15B6F86E00A03429 /* zh_TW */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.strings; name = zh_TW; path = zh_TW.lproj/HockeySDK.strings; sourceTree = ""; }; 1E5955BB15B71C8600A03429 /* authorize_denied.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = authorize_denied.png; sourceTree = ""; }; 1E5955BC15B71C8600A03429 /* authorize_denied@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "authorize_denied@2x.png"; sourceTree = ""; }; 1E5955BD15B71C8600A03429 /* authorize_request.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = authorize_request.png; sourceTree = ""; }; @@ -203,6 +196,8 @@ 1E5955C515B71C8600A03429 /* IconGradient@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "IconGradient@2x.png"; sourceTree = ""; }; 1E5955FA15B7877A00A03429 /* BITHockeyManagerDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BITHockeyManagerDelegate.h; sourceTree = ""; }; 1E66CA9115D4100500F35BED /* buildnumber.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = buildnumber.xcconfig; sourceTree = ""; }; + 1E6F044F167B5D9600ED1C86 /* zh */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = zh; path = zh.lproj/HockeySDK.strings; sourceTree = ""; }; + 1E6F0450167B5E5600ED1C86 /* pt-PT */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "pt-PT"; path = "pt-PT.lproj/HockeySDK.strings"; sourceTree = ""; }; 1E71509A15B5C76F004E88FF /* HockeySDK.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HockeySDK.h; sourceTree = ""; }; 1E754DC61621BC170070AB92 /* HockeySDK.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = HockeySDK.xcconfig; sourceTree = ""; }; 1E754E561621FBB70070AB92 /* BITCrashManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BITCrashManager.h; sourceTree = ""; }; @@ -531,11 +526,8 @@ ru, sv, tr, - zh_CN, - zh_TW, - "zh-Hans", - "zh-Hant", hr, + zh, ); mainGroup = E400560F148D79B500EB22B9; productRefGroup = E400561B148D79B500EB22B9 /* Products */; @@ -564,7 +556,6 @@ 1E5955CC15B71C8600A03429 /* buttonHighlight@2x.png in Resources */, 1E5955CF15B71C8600A03429 /* IconGradient.png in Resources */, 1E5955D015B71C8600A03429 /* IconGradient@2x.png in Resources */, - 1E27EF2515BB5033000AE995 /* HockeySDK.strings in Resources */, 1EAF20A8162DC0F600957B1D /* feedbackActivity@2x~ipad.png in Resources */, 1EAF20A9162DC0F600957B1D /* feedbackActivity~ipad.png in Resources */, 1EAF20AA162DC0F600957B1D /* feedbackActiviy.png in Resources */, @@ -673,15 +664,11 @@ 1E59556615B6F82300A03429 /* fr */, 1E59556815B6F82A00A03429 /* it */, 1E59556A15B6F83100A03429 /* ja */, - 1E59556C15B6F83700A03429 /* nl */, - 1E59556E15B6F84000A03429 /* pt-PT */, 1E59557015B6F84700A03429 /* pt */, 1E59557215B6F84D00A03429 /* ru */, - 1E59557415B6F85700A03429 /* sv */, - 1E59557615B6F85E00A03429 /* tr */, - 1E59557815B6F86600A03429 /* zh_CN */, - 1E59557A15B6F86E00A03429 /* zh_TW */, 1E36D8B816667611000B134C /* hr */, + 1E6F044F167B5D9600ED1C86 /* zh */, + 1E6F0450167B5E5600ED1C86 /* pt-PT */, ); name = HockeySDK.strings; sourceTree = ""; From cd9989bb093244642b2f75c73b0d9fa25c5f3881 Mon Sep 17 00:00:00 2001 From: Andreas Linde Date: Sun, 30 Dec 2012 17:07:18 +0100 Subject: [PATCH 140/176] Make sure connection is always cleared --- Classes/BITUpdateManager.m | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/Classes/BITUpdateManager.m b/Classes/BITUpdateManager.m index 23d8403e..3e4e7dc5 100644 --- a/Classes/BITUpdateManager.m +++ b/Classes/BITUpdateManager.m @@ -842,8 +842,11 @@ - (void)connectionDidFinishLoading:(NSURLConnection *)connection { NSString *responseString = [[NSString alloc] initWithBytes:[_receivedData bytes] length:[_receivedData length] encoding: NSUTF8StringEncoding]; BITHockeyLog(@"INFO: Received API response: %@", responseString); - if (!responseString || ![responseString dataUsingEncoding:NSUTF8StringEncoding]) + if (!responseString || ![responseString dataUsingEncoding:NSUTF8StringEncoding]) { + self.receivedData = nil; + self.urlConnection = nil; return; + } NSError *error = nil; NSDictionary *json = (NSDictionary *)[NSJSONSerialization JSONObjectWithData:[responseString dataUsingEncoding:NSUTF8StringEncoding] options:kNilOptions error:&error]; @@ -854,15 +857,14 @@ - (void)connectionDidFinishLoading:(NSURLConnection *)connection { if (![self isAppStoreEnvironment]) { NSArray *feedArray = (NSArray *)[json valueForKey:@"versions"]; - self.receivedData = nil; - self.urlConnection = nil; - // remember that we just checked the server self.lastCheck = [NSDate date]; // server returned empty response? if (![feedArray count]) { BITHockeyLog(@"WARNING: No versions available for download on HockeyApp."); + self.receivedData = nil; + self.urlConnection = nil; return; } else { _lastCheckFailed = NO; @@ -921,6 +923,8 @@ - (void)connectionDidFinishLoading:(NSURLConnection *)connection { code:BITUpdateAPIServerReturnedEmptyResponse userInfo:[NSDictionary dictionaryWithObjectsAndKeys:@"Server returned an empty response.", NSLocalizedDescriptionKey, nil]]]; } + self.receivedData = nil; + self.urlConnection = nil; } - (BOOL)hasNewerMandatoryVersion { From 3c168bc270e6097f137a7d6020ef349998e64886 Mon Sep 17 00:00:00 2001 From: Andreas Linde Date: Sun, 30 Dec 2012 17:07:47 +0100 Subject: [PATCH 141/176] Improve identifier cheek error logging in case live identifier is provided --- Classes/BITHockeyManager.m | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/Classes/BITHockeyManager.m b/Classes/BITHockeyManager.m index fb418bef..de15077e 100644 --- a/Classes/BITHockeyManager.m +++ b/Classes/BITHockeyManager.m @@ -71,7 +71,11 @@ - (BOOL)checkValidityOfAppIdentifier:(NSString *)identifier { - (void)logInvalidIdentifier:(NSString *)environment { if (!_appStoreEnvironment) { - NSLog(@"[HockeySDK] ERROR: The %@ is invalid! Please use the HockeyApp app identifier you find on the apps website on HockeyApp! The SDK is disabled!", environment); + if ([environment isEqualToString:@"liveIdentifier"]) { + NSLog(@"[HockeySDK] WARNING: The liveIdentifier is invalid! The SDK will be disabled when deployed to the App Store without setting a valid app identifier!"); + } else { + NSLog(@"[HockeySDK] ERROR: The %@ is invalid! Please use the HockeyApp app identifier you find on the apps website on HockeyApp! The SDK is disabled!", environment); + } } } From 367c192b95bc581298ca256de147b7794f5ad6c2 Mon Sep 17 00:00:00 2001 From: chitza Date: Fri, 4 Jan 2013 08:56:20 +0200 Subject: [PATCH 142/176] Romanian localization Resources for Romanian language --- Resources/ro.lproj/HockeySDK.strings | 225 ++++++++++++++++++++ Support/HockeySDK.xcodeproj/project.pbxproj | 3 + 2 files changed, 228 insertions(+) create mode 100755 Resources/ro.lproj/HockeySDK.strings diff --git a/Resources/ro.lproj/HockeySDK.strings b/Resources/ro.lproj/HockeySDK.strings new file mode 100755 index 00000000..f373f41d --- /dev/null +++ b/Resources/ro.lproj/HockeySDK.strings @@ -0,0 +1,225 @@ +/* General */ + +/* For dialogs yes buttons */ +"HockeyYes" = "Da"; + +/* For dialogs no buttons */ +"HockeyNo" = "Nu"; + +/* For dialogs ok buttons */ +"HockeyOK" = "OK"; + +/* Replacement for app name, if it could not be detected */ +"HockeyAppNamePlaceholder" = "Aplicația curentă"; + +/* Crash */ + + +/* Crash dialog */ + +/* Title showing in the alert box when crash report data has been found */ +"CrashDataFoundTitle" = "Raportare eroare"; + +/* Description explaining that crash data has been found and ask the user if the data might be uploaded to the developers server */ +"CrashDataFoundAnonymousDescription" = "Doriți să trimiteți un raport anonim ca să putem corecta problema?"; + +/* Description explaining that crash data has been found and ask the user if the non anonymous data might be uplaoded to the developers server */ +"CrashDataFoundDescription" = "Doriți să trimiteți un raport ca să putem corecta problema??"; + +/* Alert box button if the users wants to send crash data always automatically */ +"CrashSendReportAlways" = "Trimite mereu"; + +/* Alert box button to send the crash report once */ +"CrashSendReport" = "Trimite raport"; + +/* Alert box button to decline sending the report */ +"CrashDontSendReport" = "Nu trimite"; + +/* Text showing in a processing box that the crash data is being uploaded to the server */ +"CrashReportSending" = "Se trimite…"; + + +/* Update */ + + +/* Update Alert view */ + +/* Update available */ +"UpdateAvailable" = "Versiune nouă"; + +"UpdateAlertTextWithAppVersion" = "A apărut versiunea %@."; + +"UpdateAlertMandatoryTextWithAppVersion" = "A apărut versiunea %@ și actualizarea e obligatorie!"; + +"UpdateIgnore" = "Ignoră"; + +"UpdateShow" = "Arată"; + +"UpdateInstall" = "Instalează"; + + +/* Update Details */ + +"UpdateScreenTitle" = "Actualizare"; + +"UpdateButtonCheck" = "VERIFICĂ"; + +"UpdateButtonSearching" = "SE VERIFICĂ"; + +"UpdateButtonUpdate" = "ACTUALIZEAZĂ"; + +"UpdateButtonInstalling" = "SE INSTALEAZĂ"; + +"UpdateButtonOffline" = "OFFLINE"; + +"UpdateInstalled" = "INSTALAT"; + +"UpdateVersion" = "Versiune"; + +"UpdateShowPreviousVersions" = "Arată versiunile anterioare..."; + +"UpdateNoUpdateAvailableTitle" = "Nici o actualizare disponibilă"; + +"UpdateNoUpdateAvailableMessage" = "%@ e cea mai recentă versiune."; + +"UpdateError" = "Eroare"; + +"UpdateWarning" = "Avertisment"; + +"UpdateNoReleaseNotesAvailable" = "Nu există note."; + + +/* Update Authorization */ + +"UpdateAuthorizationProgress" = "Se authorizează..."; + +"UpdateAuthorizationOffline" = "Necesită conexiune la Internet!"; + +"UpdateAuthorizationDenied" = "Autorizare refuzată. Vă rugăm contactați dezvoltatorul."; + + +/* Update Expiry */ + +"UpdateExpired" = "%@ a expirat și nu mai poate fi folosită."; + + +/* Update Simulator Warning */ + +"UpdateSimulatorMessage" = "Hockey Update nu funcționează în simulator.\nSchema itms-services:// este implementată dar nefuncțională."; + + +/* Feedback */ + + +/* New Message Alert */ + +/* Alert Title */ +"HockeyFeedbackNewMessageTitle" = "Nou răspuns feedback"; + +/* Alert Text */ +"HockeyFeedbackNewMessageText" = "A apărut un nou răspuns la feedback-ul dvs. Doriți să îl vedeți?"; + +/* Alert Ignore Button */ +"HockeyFeedbackIgnore" = "Ignoră"; + +/* Alert Show Button */ +"HockeyFeedbackShow" = "Arată"; + + +/* List View */ + +/* Title */ +"HockeyFeedbackListTitle" = "Feedback"; + +/* Last Updated */ +"HockeyFeedbackListLastUpdated" = "Ultima actualizare: %@"; + +/* Never Updated */ +"HockeyFeedbackListNeverUpdated" = "Niciodată"; + +/* Provide Feedback Button Title */ +"HockeyFeedbackListButonWriteFeedback" = "Furnizează Feedback"; + +/* Add a Response Button Title */ +"HockeyFeedbackListButonWriteResponse" = "Adaugă un răspuns"; + +/* User Data Set Name Button Title */ +"HockeyFeedbackListButonUserDataSetName" = "Introduceți numele"; + +/* User Data Set Email Button Title */ +"HockeyFeedbackListButonUserDataSetEmail" = "Introduceți e-mail"; + +/* User Data With Name Button Title */ +"HockeyFeedbackListButonUserDataWithName" = "Nume: %@"; + +/* User Data With Email Button Title */ +"HockeyFeedbackListButonUserDataWithEmail" = "E-mail: %@"; + +/* Button title for deleting all local messages*/ +"HockeyFeedbackListButonDeleteAllMessages" = "Șterge toate mesajele"; + +/* Message pending to be send */ +"HockeyFeedbackListMessagePending" = "În aștepare"; + + +/* Delete All Messages Action Sheet / Alert View */ + +/* Title for the Action Sheet */ +"HockeyFeedbackListDeleteAllTitle" = "Toate mesajele de pe acest dispozitiv vor fi șterse."; + +/* Button Title to perform delete action */ +"HockeyFeedbackListDeleteAllDelete" = "Șterge"; + +/* Button Title to cancel delete action */ +"HockeyFeedbackListDeleteAllCancel" = "Anulează"; + + +/* Open Link In Safari Action Sheet / Alert View */ + +/* Button Title to cancel */ +"HockeyFeedbackListLinkActionCancel" = "Anulează"; + +/* Button Title to Open the Link */ +"HockeyFeedbackListLinkActionOpen" = "Deschide"; + +/* Button Title to Copy the Link */ +"HockeyFeedbackListLinkActionCopy" = "Copiază"; + + +/* UIActivity */ + +/* Activity Sharing Button Title, App Name will be inserted */ +"HockeyFeedbackActivityButtonTitle" = "Feedback pentru %@"; + +/* if there can no app name be found, use this instead for HockeyFeedbackActivityButtonTitle */ +"HockeyFeedbackActivityAppPlaceholder" = "Aplicație"; + + +/* Compose Message */ + +/* Title */ +"HockeyFeedbackComposeTitle" = "Nou feedback"; + +/* Send button */ +"HockeyFeedbackComposeSend" = "Trimite"; + + +/* Set User Data */ + +/* Title */ +"HockeyFeedbackUserDataTitle" = "Informațiile mele"; + +/* Description On What Should Be Entered */ +"HockeyFeedbackUserDataDescription" = "Vă rugăm introduceți informațiile despre dvs."; + +/* Name Field */ +"HockeyFeedbackUserDataName" = "Nume"; + +/* Name Placeholder */ +"HockeyFeedbackUserDataNamePlaceHolder" = "Ion Popescu"; + +/* Email Field */ +"HockeyFeedbackUserDataEmail" = "E-mail"; + +/* Email Placeholder */ +"HockeyFeedbackUserDataEmailPlaceholder" = "exemplu@email.ro"; diff --git a/Support/HockeySDK.xcodeproj/project.pbxproj b/Support/HockeySDK.xcodeproj/project.pbxproj index b5df5842..3a2d70ff 100644 --- a/Support/HockeySDK.xcodeproj/project.pbxproj +++ b/Support/HockeySDK.xcodeproj/project.pbxproj @@ -222,6 +222,7 @@ 1EF95CA4162CB036000AE3AD /* BITFeedbackActivity.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BITFeedbackActivity.h; sourceTree = ""; }; 1EF95CA5162CB036000AE3AD /* BITFeedbackActivity.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = BITFeedbackActivity.m; sourceTree = ""; }; 1EF95CA9162CB313000AE3AD /* BITFeedbackComposeViewControllerDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BITFeedbackComposeViewControllerDelegate.h; sourceTree = ""; }; + DA19F1D61696AE4F006885E7 /* ro */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ro; path = ro.lproj/HockeySDK.strings; sourceTree = ""; }; E400561D148D79B500EB22B9 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; E41EB465148D7BF50015DEDC /* BITHockeyManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BITHockeyManager.h; sourceTree = ""; }; E41EB466148D7BF50015DEDC /* BITHockeyManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = BITHockeyManager.m; sourceTree = ""; }; @@ -536,6 +537,7 @@ "zh-Hans", "zh-Hant", hr, + ro, ); mainGroup = E400560F148D79B500EB22B9; productRefGroup = E400561B148D79B500EB22B9 /* Products */; @@ -682,6 +684,7 @@ 1E59557815B6F86600A03429 /* zh_CN */, 1E59557A15B6F86E00A03429 /* zh_TW */, 1E36D8B816667611000B134C /* hr */, + DA19F1D61696AE4F006885E7 /* ro */, ); name = HockeySDK.strings; sourceTree = ""; From 70c9852a9925bcbb316075915dc2a80e22f28e40 Mon Sep 17 00:00:00 2001 From: Andreas Linde Date: Fri, 4 Jan 2013 14:33:33 +0100 Subject: [PATCH 143/176] Add hints to the documentation on what to do if the build settings don't get passed on --- docs/Guide-Installation-Setup-Advanced-template.md | 8 ++++++++ docs/Guide-Installation-Setup-template.md | 14 ++++++++++++-- 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/docs/Guide-Installation-Setup-Advanced-template.md b/docs/Guide-Installation-Setup-Advanced-template.md index 41e3deac..8b2f59b3 100644 --- a/docs/Guide-Installation-Setup-Advanced-template.md +++ b/docs/Guide-Installation-Setup-Advanced-template.md @@ -89,6 +89,14 @@ If you need support for iOS 3.x, please check out [HockeyKit](http://support.hoc (Adjust the path depending where the `Project.xcconfig` file is located related to the Xcode project package) **Important note:** Check if you overwrite any of the build settings and add a missing `$(inherited)` entry on the projects build settings level, so the `HockeySDK.xcconfig` settings will be passed through successfully. + +17. If you are getting build warnings, then the `.xcconfig` setting wasn't included successfully or its settings in `Other Linker Flags` get ignored because `$(interited)` is missing on project or target level. Either add `$(inherited)` or link the following frameworks manually in `Link Binary With Libraries` under `Build Phases`: + - `CoreText` + - `CoreGraphics` + - `Foundation` + - `QuartzCore` + - `SystemConfiguration` + - `UIKit` diff --git a/docs/Guide-Installation-Setup-template.md b/docs/Guide-Installation-Setup-template.md index 13086ee3..2e7c19c7 100644 --- a/docs/Guide-Installation-Setup-template.md +++ b/docs/Guide-Installation-Setup-template.md @@ -59,9 +59,19 @@ If you need support for iOS 3.x, please check out [HockeyKit](http://support.hoc `#include "../Vendor/HockeySDK/Support/HockeySDK.xcconfig"` (Adjust the path depending where the `Project.xcconfig` file is located related to the Xcode project package) + + **Important note:** Check if you overwrite any of the build settings and add a missing `$(inherited)` entry on the projects build settings level, so the `HockeySDK.xcconfig` settings will be passed through successfully. + +10. If you are getting build warnings, then the `.xcconfig` setting wasn't included successfully or its settings in `Other Linker Flags` get ignored because `$(interited)` is missing on project or target level. Either add `$(inherited)` or link the following frameworks manually in `Link Binary With Libraries` under `Build Phases`: + - `CoreText` + - `CoreGraphics` + - `Foundation` + - `QuartzCore` + - `SystemConfiguration` + - `UIKit` + - + ## Modify Code 1. Open your `AppDelegate.m` file. From 0de9a21de30b20d93df79bfcb60fbc44d9a98c96 Mon Sep 17 00:00:00 2001 From: Andreas Linde Date: Fri, 4 Jan 2013 14:34:07 +0100 Subject: [PATCH 144/176] More localization updates --- Resources/de.lproj/HockeySDK.strings | 8 +++---- Resources/es.lproj/HockeySDK.strings | 22 +++++++++---------- Resources/fr.lproj/HockeySDK.strings | 10 ++++----- Resources/it.lproj/HockeySDK.strings | 16 +++++++------- Resources/pt-PT.lproj/HockeySDK.strings | 18 +++++++-------- Resources/pt.lproj/HockeySDK.strings | 2 +- Resources/ru.lproj/HockeySDK.strings | 20 ++++++++--------- .../HockeySDK.strings | 2 +- Support/HockeySDK.xcodeproj/project.pbxproj | 11 ++++++---- 9 files changed, 56 insertions(+), 53 deletions(-) rename Resources/{zh.lproj => zh-Hans.lproj}/HockeySDK.strings (99%) diff --git a/Resources/de.lproj/HockeySDK.strings b/Resources/de.lproj/HockeySDK.strings index 661dd822..60a60a5f 100644 --- a/Resources/de.lproj/HockeySDK.strings +++ b/Resources/de.lproj/HockeySDK.strings @@ -68,7 +68,7 @@ "UpdateButtonUpdate" = "UPDATE"; -"UpdateButtonInstalling" = "INSTALLIEREN …"; +"UpdateButtonInstalling" = "INSTALLIEREN"; "UpdateButtonOffline" = "OFFLINE"; @@ -132,7 +132,7 @@ "HockeyFeedbackListTitle" = "Feedback"; /* Last Updated */ -"HockeyFeedbackListLastUpdated" = "Zuletzt aktualisiert: %@"; +"HockeyFeedbackListLastUpdated" = "Letztes Update: %@"; /* Never Updated */ "HockeyFeedbackListNeverUpdated" = "Noch nie"; @@ -198,7 +198,7 @@ /* Compose Message */ /* Title */ -"HockeyFeedbackComposeTitle" = "Neue Feedback-Meldung"; +"HockeyFeedbackComposeTitle" = "Neues Feedback"; /* Send button */ "HockeyFeedbackComposeSend" = "Senden"; @@ -222,4 +222,4 @@ "HockeyFeedbackUserDataEmail" = "E-Mail"; /* Email Placeholder */ -"HockeyFeedbackUserDataEmailPlaceholder" = "Max@mustermann.de"; +"HockeyFeedbackUserDataEmailPlaceholder" = "beispiel@email.de"; diff --git a/Resources/es.lproj/HockeySDK.strings b/Resources/es.lproj/HockeySDK.strings index 4ce030ae..205efcf0 100644 --- a/Resources/es.lproj/HockeySDK.strings +++ b/Resources/es.lproj/HockeySDK.strings @@ -47,9 +47,9 @@ /* Update available */ "UpdateAvailable" = "Actualización disponible"; -"UpdateAlertTextWithAppVersion" = "La versión %@ está disponible."; +"UpdateAlertTextWithAppVersion" = "%@ está disponible."; -"UpdateAlertMandatoryTextWithAppVersion" = "La versión %@ está disponible y es una actualización obligatoria."; +"UpdateAlertMandatoryTextWithAppVersion" = "%@ está disponible, y es una actualización obligatoria."; "UpdateIgnore" = "Ignorar"; @@ -80,7 +80,7 @@ "UpdateNoUpdateAvailableTitle" = "No hay actualizaciones disponibles"; -"UpdateNoUpdateAvailableMessage" = "La versión %@ es la más reciente."; +"UpdateNoUpdateAvailableMessage" = "%@ es la versión más reciente."; "UpdateError" = "Error"; @@ -114,10 +114,10 @@ /* New Message Alert */ /* Alert Title */ -"HockeyFeedbackNewMessageTitle" = "Nueva respuesta al comentario"; +"HockeyFeedbackNewMessageTitle" = "Nueva respuesta al mensaje"; /* Alert Text */ -"HockeyFeedbackNewMessageText" = "Hay una nueva respuesta a su comentario. ¿Desea verla?"; +"HockeyFeedbackNewMessageText" = "Hay una nueva respuesta a su mensaje. ¿Desea verla?"; /* Alert Ignore Button */ "HockeyFeedbackIgnore" = "Ignorar"; @@ -129,7 +129,7 @@ /* List View */ /* Title */ -"HockeyFeedbackListTitle" = "Comentarios"; +"HockeyFeedbackListTitle" = "Mensajes"; /* Last Updated */ "HockeyFeedbackListLastUpdated" = "Última actualización: %@"; @@ -138,16 +138,16 @@ "HockeyFeedbackListNeverUpdated" = "Nunca"; /* Provide Feedback Button Title */ -"HockeyFeedbackListButonWriteFeedback" = "Dejar un comentario"; +"HockeyFeedbackListButonWriteFeedback" = "Dejar un mensaje"; /* Add a Response Button Title */ "HockeyFeedbackListButonWriteResponse" = "Añadir una respuesta"; /* User Data Set Name Button Title */ -"HockeyFeedbackListButonUserDataSetName" = "Indicar mi nombre"; +"HockeyFeedbackListButonUserDataSetName" = "Introduzca su nombre"; /* User Data Set Email Button Title */ -"HockeyFeedbackListButonUserDataSetEmail" = "Indicar mi correo"; +"HockeyFeedbackListButonUserDataSetEmail" = "Introduzca su correo"; /* User Data With Name Button Title */ "HockeyFeedbackListButonUserDataWithName" = "Nombre: %@"; @@ -198,7 +198,7 @@ /* Compose Message */ /* Title */ -"HockeyFeedbackComposeTitle" = "Nuevo comentario"; +"HockeyFeedbackComposeTitle" = "Nuevo mensaje"; /* Send button */ "HockeyFeedbackComposeSend" = "Enviar"; @@ -210,7 +210,7 @@ "HockeyFeedbackUserDataTitle" = "Mis datos"; /* Description On What Should Be Entered */ -"HockeyFeedbackUserDataDescription" = "Indique sus datos antes de escribir el comentario."; +"HockeyFeedbackUserDataDescription" = "Indique sus datos antes de escribir el mensaje."; /* Name Field */ "HockeyFeedbackUserDataName" = "Nombre"; diff --git a/Resources/fr.lproj/HockeySDK.strings b/Resources/fr.lproj/HockeySDK.strings index 134157e9..8fef138c 100644 --- a/Resources/fr.lproj/HockeySDK.strings +++ b/Resources/fr.lproj/HockeySDK.strings @@ -30,7 +30,7 @@ "CrashSendReportAlways" = "Toujours envoyer"; /* Alert box button to send the crash report once */ -"CrashSendReport" = "Envoyer le rapport"; +"CrashSendReport" = "Envoyer un rapport"; /* Alert box button to decline sending the report */ "CrashDontSendReport" = "Ne pas envoyer"; @@ -66,13 +66,13 @@ "UpdateButtonSearching" = "RECHERCHE"; -"UpdateButtonUpdate" = "MISE À JOUR"; +"UpdateButtonUpdate" = "METTRE À JOUR"; "UpdateButtonInstalling" = "INSTALLATION"; "UpdateButtonOffline" = "HORS LIGNE"; -"UpdateInstalled" = "INSTALLÉE"; +"UpdateInstalled" = "INSTALLÉ"; "UpdateVersion" = "Version"; @@ -129,7 +129,7 @@ /* List View */ /* Title */ -"HockeyFeedbackListTitle" = "Commentaire"; +"HockeyFeedbackListTitle" = "Commentaires"; /* Last Updated */ "HockeyFeedbackListLastUpdated" = "Dernière mise à jour : %@"; @@ -198,7 +198,7 @@ /* Compose Message */ /* Title */ -"HockeyFeedbackComposeTitle" = "Nouveau commentaire"; +"HockeyFeedbackComposeTitle" = "Commentaire"; /* Send button */ "HockeyFeedbackComposeSend" = "Envoyer"; diff --git a/Resources/it.lproj/HockeySDK.strings b/Resources/it.lproj/HockeySDK.strings index fabbb475..f334f13e 100644 --- a/Resources/it.lproj/HockeySDK.strings +++ b/Resources/it.lproj/HockeySDK.strings @@ -45,7 +45,7 @@ /* Update Alert view */ /* Update available */ -"UpdateAvailable" = "Aggiornamento disponibile"; +"UpdateAvailable" = "Nuovo aggiornamento"; "UpdateAlertTextWithAppVersion" = "È disponibile %@."; @@ -62,11 +62,11 @@ "UpdateScreenTitle" = "Aggiornamento"; -"UpdateButtonCheck" = "VERIFICA"; +"UpdateButtonCheck" = "VERIFICO"; "UpdateButtonSearching" = "VERIFICO"; -"UpdateButtonUpdate" = "AGGIORNAMENTO"; +"UpdateButtonUpdate" = "AGGIORNA"; "UpdateButtonInstalling" = "INSTALLO"; @@ -78,7 +78,7 @@ "UpdateShowPreviousVersions" = "Visualizzo versioni precedenti..."; -"UpdateNoUpdateAvailableTitle" = "Aggiornamenti non disponibili"; +"UpdateNoUpdateAvailableTitle" = "Non sono presenti aggiornamenti"; "UpdateNoUpdateAvailableMessage" = "%@ è già la versione attuale."; @@ -117,7 +117,7 @@ "HockeyFeedbackNewMessageTitle" = "Nuova risposta a un commento"; /* Alert Text */ -"HockeyFeedbackNewMessageText" = "È presente una nuova risposta al tuo commento. Vuoi visualizzarla?"; +"HockeyFeedbackNewMessageText" = "C'è una nuova risposta al tuo commento. Vuoi visualizzarla?"; /* Alert Ignore Button */ "HockeyFeedbackIgnore" = "Ignora"; @@ -165,10 +165,10 @@ /* Delete All Messages Action Sheet / Alert View */ /* Title for the Action Sheet */ -"HockeyFeedbackListDeleteAllTitle" = "Tutti i messaggi presenti sul dispositivo verranno cancellati."; +"HockeyFeedbackListDeleteAllTitle" = "Tutti i messaggi presenti sul dispositivo saranno cancellati."; /* Button Title to perform delete action */ -"HockeyFeedbackListDeleteAllDelete" = "Elimina"; +"HockeyFeedbackListDeleteAllDelete" = "Cancella"; /* Button Title to cancel delete action */ "HockeyFeedbackListDeleteAllCancel" = "Annulla"; @@ -198,7 +198,7 @@ /* Compose Message */ /* Title */ -"HockeyFeedbackComposeTitle" = "Nuova commento"; +"HockeyFeedbackComposeTitle" = "Nuovo commento"; /* Send button */ "HockeyFeedbackComposeSend" = "Invia"; diff --git a/Resources/pt-PT.lproj/HockeySDK.strings b/Resources/pt-PT.lproj/HockeySDK.strings index 6d1a091f..f8883de8 100644 --- a/Resources/pt-PT.lproj/HockeySDK.strings +++ b/Resources/pt-PT.lproj/HockeySDK.strings @@ -47,9 +47,9 @@ /* Update available */ "UpdateAvailable" = "Actualização disponível"; -"UpdateAlertTextWithAppVersion" = "A versão %@ está disponível."; +"UpdateAlertTextWithAppVersion" = "%@ está disponível."; -"UpdateAlertMandatoryTextWithAppVersion" = "A versão %@ está disponível e é uma actualização obrigatória!"; +"UpdateAlertMandatoryTextWithAppVersion" = "%@ está disponível e é uma actualização obrigatória!"; "UpdateIgnore" = "Ignorar"; @@ -64,11 +64,11 @@ "UpdateButtonCheck" = "VERIFICAR"; -"UpdateButtonSearching" = "VERIFICAR"; +"UpdateButtonSearching" = "A VERIFICAR"; "UpdateButtonUpdate" = "ACTUALIZAR"; -"UpdateButtonInstalling" = "INSTALAR"; +"UpdateButtonInstalling" = "A INSTALAR"; "UpdateButtonOffline" = "OFFLINE"; @@ -80,7 +80,7 @@ "UpdateNoUpdateAvailableTitle" = "Nenhuma actualização disponível"; -"UpdateNoUpdateAvailableMessage" = "A versão %@ é a mais recente."; +"UpdateNoUpdateAvailableMessage" = "%@ é a mais recente."; "UpdateError" = "Erro"; @@ -105,7 +105,7 @@ /* Update Simulator Warning */ -"UpdateSimulatorMessage" = "A actualização Hockey não funciona com o Simulador.\nO url scheme itms-services:// está implementado mas não funciona."; +"UpdateSimulatorMessage" = "A actualização do Hockey não funciona com o Simulador.\nO url scheme itms-services:// está implementado mas não funciona."; /* Feedback */ @@ -144,10 +144,10 @@ "HockeyFeedbackListButonWriteResponse" = "Adicionar uma resposta"; /* User Data Set Name Button Title */ -"HockeyFeedbackListButonUserDataSetName" = "Definir o nome"; +"HockeyFeedbackListButonUserDataSetName" = "Definir nome"; /* User Data Set Email Button Title */ -"HockeyFeedbackListButonUserDataSetEmail" = "Definir o e-mail"; +"HockeyFeedbackListButonUserDataSetEmail" = "Definir e-mail"; /* User Data With Name Button Title */ "HockeyFeedbackListButonUserDataWithName" = "Nome: %@"; @@ -165,7 +165,7 @@ /* Delete All Messages Action Sheet / Alert View */ /* Title for the Action Sheet */ -"HockeyFeedbackListDeleteAllTitle" = "Assim, todas as mensagens do dispositivo serão eliminadas."; +"HockeyFeedbackListDeleteAllTitle" = "Todas as mensagens do dispositivo serão eliminadas."; /* Button Title to perform delete action */ "HockeyFeedbackListDeleteAllDelete" = "Eliminar"; diff --git a/Resources/pt.lproj/HockeySDK.strings b/Resources/pt.lproj/HockeySDK.strings index 61f794f5..6dbd0db2 100644 --- a/Resources/pt.lproj/HockeySDK.strings +++ b/Resources/pt.lproj/HockeySDK.strings @@ -210,7 +210,7 @@ "HockeyFeedbackUserDataTitle" = "Meus dados"; /* Description On What Should Be Entered */ -"HockeyFeedbackUserDataDescription" = "Informe seus dados antes de redigir seu feedback."; +"HockeyFeedbackUserDataDescription" = "Informe seus dados antes de redigir o feedback."; /* Name Field */ "HockeyFeedbackUserDataName" = "Nome"; diff --git a/Resources/ru.lproj/HockeySDK.strings b/Resources/ru.lproj/HockeySDK.strings index ffceffb1..30d47120 100644 --- a/Resources/ru.lproj/HockeySDK.strings +++ b/Resources/ru.lproj/HockeySDK.strings @@ -21,10 +21,10 @@ "CrashDataFoundTitle" = "Неожиданное завершение %@"; /* Description explaining that crash data has been found and ask the user if the data might be uploaded to the developers server */ -"CrashDataFoundAnonymousDescription" = "Пошлете ли вы анонимный отчет, чтобы мы могли исправить эту ошибку?"; +"CrashDataFoundAnonymousDescription" = "Пошлете анонимный отчет, чтобы мы могли исправить эту ошибку?"; /* Description explaining that crash data has been found and ask the user if the non anonymous data might be uplaoded to the developers server */ -"CrashDataFoundDescription" = "Пошлете ли вы отчет, чтобы мы могли исправить эту ошибку?"; +"CrashDataFoundDescription" = "Пошлете отчет, чтобы мы могли исправить эту ошибку?"; /* Alert box button if the users wants to send crash data always automatically */ "CrashSendReportAlways" = "Отправлять всегда"; @@ -60,7 +60,7 @@ /* Update Details */ -"UpdateScreenTitle" = "Обновить"; +"UpdateScreenTitle" = "Обновление"; "UpdateButtonCheck" = "ПРОВЕРИТЬ"; @@ -86,12 +86,12 @@ "UpdateWarning" = "Предупреждение"; -"UpdateNoReleaseNotesAvailable" = "Нет комментариев версии."; +"UpdateNoReleaseNotesAvailable" = "Нет комментариев по этой версии."; /* Update Authorization */ -"UpdateAuthorizationProgress" = "Авторизую..."; +"UpdateAuthorizationProgress" = "Авторизация..."; "UpdateAuthorizationOffline" = "Нужно подключить Интернет!"; @@ -138,16 +138,16 @@ "HockeyFeedbackListNeverUpdated" = "Никогда"; /* Provide Feedback Button Title */ -"HockeyFeedbackListButonWriteFeedback" = "Дать отклик"; +"HockeyFeedbackListButonWriteFeedback" = "Написать отклик"; /* Add a Response Button Title */ "HockeyFeedbackListButonWriteResponse" = "Добавить ответ"; /* User Data Set Name Button Title */ -"HockeyFeedbackListButonUserDataSetName" = "Уст. ваше имя"; +"HockeyFeedbackListButonUserDataSetName" = "Ввести ваше имя"; /* User Data Set Email Button Title */ -"HockeyFeedbackListButonUserDataSetEmail" = "Уст. вашу email"; +"HockeyFeedbackListButonUserDataSetEmail" = "Ввести ваш email"; /* User Data With Name Button Title */ "HockeyFeedbackListButonUserDataWithName" = "Имя: %@"; @@ -198,7 +198,7 @@ /* Compose Message */ /* Title */ -"HockeyFeedbackComposeTitle" = "Новый отклик"; +"HockeyFeedbackComposeTitle" = "Новый"; /* Send button */ "HockeyFeedbackComposeSend" = "Отправить"; @@ -210,7 +210,7 @@ "HockeyFeedbackUserDataTitle" = "Мои данные"; /* Description On What Should Be Entered */ -"HockeyFeedbackUserDataDescription" = "Перед отправкой отклика необходимо указать вашу информацию."; +"HockeyFeedbackUserDataDescription" = "Перед отправкой отклика необходимо ввести ваши личные данные."; /* Name Field */ "HockeyFeedbackUserDataName" = "Имя"; diff --git a/Resources/zh.lproj/HockeySDK.strings b/Resources/zh-Hans.lproj/HockeySDK.strings similarity index 99% rename from Resources/zh.lproj/HockeySDK.strings rename to Resources/zh-Hans.lproj/HockeySDK.strings index 5c198e9d..e17515a8 100644 --- a/Resources/zh.lproj/HockeySDK.strings +++ b/Resources/zh-Hans.lproj/HockeySDK.strings @@ -216,7 +216,7 @@ "HockeyFeedbackUserDataName" = "姓名"; /* Name Placeholder */ -"HockeyFeedbackUserDataNamePlaceHolder" = "张三"; +"HockeyFeedbackUserDataNamePlaceHolder" = "姓名"; /* Email Field */ "HockeyFeedbackUserDataEmail" = "邮件"; diff --git a/Support/HockeySDK.xcodeproj/project.pbxproj b/Support/HockeySDK.xcodeproj/project.pbxproj index 420305eb..143d44d1 100644 --- a/Support/HockeySDK.xcodeproj/project.pbxproj +++ b/Support/HockeySDK.xcodeproj/project.pbxproj @@ -105,6 +105,7 @@ 1EAF20A9162DC0F600957B1D /* feedbackActivity~ipad.png in Resources */ = {isa = PBXBuildFile; fileRef = 1EAF20A5162DC0F600957B1D /* feedbackActivity~ipad.png */; }; 1EAF20AA162DC0F600957B1D /* feedbackActiviy.png in Resources */ = {isa = PBXBuildFile; fileRef = 1EAF20A6162DC0F600957B1D /* feedbackActiviy.png */; }; 1EAF20AB162DC0F600957B1D /* feedbackActiviy@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 1EAF20A7162DC0F600957B1D /* feedbackActiviy@2x.png */; }; + 1EB52FD5167B766100C801D5 /* HockeySDK.strings in Resources */ = {isa = PBXBuildFile; fileRef = 1E59555F15B6F80E00A03429 /* HockeySDK.strings */; }; 1EC69F601615001500808FD9 /* BITHockeyManagerPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 1EC69F5D1615001500808FD9 /* BITHockeyManagerPrivate.h */; }; 1EF95CA6162CB037000AE3AD /* BITFeedbackActivity.h in Headers */ = {isa = PBXBuildFile; fileRef = 1EF95CA4162CB036000AE3AD /* BITFeedbackActivity.h */; settings = {ATTRIBUTES = (Public, ); }; }; 1EF95CA7162CB037000AE3AD /* BITFeedbackActivity.m in Sources */ = {isa = PBXBuildFile; fileRef = 1EF95CA5162CB036000AE3AD /* BITFeedbackActivity.m */; }; @@ -178,7 +179,6 @@ 1E5954F215B6F24A00A03429 /* libHockeySDK.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libHockeySDK.a; sourceTree = BUILT_PRODUCTS_DIR; }; 1E59550A15B6F45800A03429 /* HockeySDKResources.bundle */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = HockeySDKResources.bundle; sourceTree = BUILT_PRODUCTS_DIR; }; 1E59556015B6F80E00A03429 /* de */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.strings; name = de; path = de.lproj/HockeySDK.strings; sourceTree = ""; }; - 1E59556215B6F81500A03429 /* en */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/HockeySDK.strings; sourceTree = ""; }; 1E59556415B6F81C00A03429 /* es */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.strings; name = es; path = es.lproj/HockeySDK.strings; sourceTree = ""; }; 1E59556615B6F82300A03429 /* fr */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.strings; name = fr; path = fr.lproj/HockeySDK.strings; sourceTree = ""; }; 1E59556815B6F82A00A03429 /* it */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.strings; name = it; path = it.lproj/HockeySDK.strings; sourceTree = ""; }; @@ -196,7 +196,6 @@ 1E5955C515B71C8600A03429 /* IconGradient@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "IconGradient@2x.png"; sourceTree = ""; }; 1E5955FA15B7877A00A03429 /* BITHockeyManagerDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BITHockeyManagerDelegate.h; sourceTree = ""; }; 1E66CA9115D4100500F35BED /* buildnumber.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = buildnumber.xcconfig; sourceTree = ""; }; - 1E6F044F167B5D9600ED1C86 /* zh */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = zh; path = zh.lproj/HockeySDK.strings; sourceTree = ""; }; 1E6F0450167B5E5600ED1C86 /* pt-PT */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "pt-PT"; path = "pt-PT.lproj/HockeySDK.strings"; sourceTree = ""; }; 1E71509A15B5C76F004E88FF /* HockeySDK.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HockeySDK.h; sourceTree = ""; }; 1E754DC61621BC170070AB92 /* HockeySDK.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = HockeySDK.xcconfig; sourceTree = ""; }; @@ -206,12 +205,14 @@ 1E754E591621FBB70070AB92 /* BITCrashManagerPrivate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BITCrashManagerPrivate.h; sourceTree = ""; }; 1E754E5A1621FBB70070AB92 /* BITCrashReportTextFormatter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BITCrashReportTextFormatter.h; sourceTree = ""; }; 1E754E5B1621FBB70070AB92 /* BITCrashReportTextFormatter.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = BITCrashReportTextFormatter.m; sourceTree = ""; }; + 1EA512DF167F7EF000FC9FBA /* zh-Hans */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "zh-Hans"; path = "zh-Hans.lproj/HockeySDK.strings"; sourceTree = ""; }; 1EACC979162F041E007578C5 /* BITAttributedLabel.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BITAttributedLabel.h; sourceTree = ""; }; 1EACC97A162F041E007578C5 /* BITAttributedLabel.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = BITAttributedLabel.m; sourceTree = ""; }; 1EAF20A4162DC0F600957B1D /* feedbackActivity@2x~ipad.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "feedbackActivity@2x~ipad.png"; sourceTree = ""; }; 1EAF20A5162DC0F600957B1D /* feedbackActivity~ipad.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "feedbackActivity~ipad.png"; sourceTree = ""; }; 1EAF20A6162DC0F600957B1D /* feedbackActiviy.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = feedbackActiviy.png; sourceTree = ""; }; 1EAF20A7162DC0F600957B1D /* feedbackActiviy@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "feedbackActiviy@2x.png"; sourceTree = ""; }; + 1EB52FC3167B73D400C801D5 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/HockeySDK.strings; sourceTree = ""; }; 1EC69F5D1615001500808FD9 /* BITHockeyManagerPrivate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BITHockeyManagerPrivate.h; sourceTree = ""; }; 1EDA60CF15C2C1450032D10B /* HockeySDK-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "HockeySDK-Info.plist"; sourceTree = ""; }; 1EF95CA4162CB036000AE3AD /* BITFeedbackActivity.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BITFeedbackActivity.h; sourceTree = ""; }; @@ -528,6 +529,7 @@ tr, hr, zh, + "zh-Hans", ); mainGroup = E400560F148D79B500EB22B9; productRefGroup = E400561B148D79B500EB22B9 /* Products */; @@ -568,6 +570,7 @@ 1E1127C916580C87007067A2 /* buttonRoundedRegular@2x.png in Resources */, 1E1127CA16580C87007067A2 /* buttonRoundedRegularHighlighted.png in Resources */, 1E1127CB16580C87007067A2 /* buttonRoundedRegularHighlighted@2x.png in Resources */, + 1EB52FD5167B766100C801D5 /* HockeySDK.strings in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -659,7 +662,6 @@ isa = PBXVariantGroup; children = ( 1E59556015B6F80E00A03429 /* de */, - 1E59556215B6F81500A03429 /* en */, 1E59556415B6F81C00A03429 /* es */, 1E59556615B6F82300A03429 /* fr */, 1E59556815B6F82A00A03429 /* it */, @@ -667,8 +669,9 @@ 1E59557015B6F84700A03429 /* pt */, 1E59557215B6F84D00A03429 /* ru */, 1E36D8B816667611000B134C /* hr */, - 1E6F044F167B5D9600ED1C86 /* zh */, 1E6F0450167B5E5600ED1C86 /* pt-PT */, + 1EB52FC3167B73D400C801D5 /* en */, + 1EA512DF167F7EF000FC9FBA /* zh-Hans */, ); name = HockeySDK.strings; sourceTree = ""; From 9f2f40bc067d5e687ff59c51b0068600d22831d8 Mon Sep 17 00:00:00 2001 From: Andreas Linde Date: Fri, 4 Jan 2013 14:44:44 +0100 Subject: [PATCH 145/176] Update copyright --- Classes/BITAppStoreHeader.h | 2 +- Classes/BITAppStoreHeader.m | 2 +- Classes/BITAppVersionMetaInfo.h | 2 +- Classes/BITAppVersionMetaInfo.m | 2 +- Classes/BITCrashManager.h | 2 +- Classes/BITCrashManager.m | 2 +- Classes/BITCrashManagerDelegate.h | 2 +- Classes/BITCrashManagerPrivate.h | 2 +- Classes/BITCrashReportTextFormatter.h | 4 ++-- Classes/BITCrashReportTextFormatter.m | 4 ++-- Classes/BITFeedbackComposeViewController.h | 2 +- Classes/BITFeedbackComposeViewController.m | 2 +- Classes/BITFeedbackListViewCell.h | 2 +- Classes/BITFeedbackListViewCell.m | 2 +- Classes/BITFeedbackListViewController.h | 2 +- Classes/BITFeedbackListViewController.m | 2 +- Classes/BITFeedbackManager.h | 2 +- Classes/BITFeedbackManager.m | 2 +- Classes/BITFeedbackManagerPrivate.h | 2 +- Classes/BITFeedbackMessage.h | 2 +- Classes/BITFeedbackMessage.m | 2 +- Classes/BITFeedbackUserDataViewController.h | 2 +- Classes/BITFeedbackUserDataViewController.m | 2 +- Classes/BITHockeyHelper.h | 2 +- Classes/BITHockeyHelper.m | 2 +- Classes/BITHockeyManager.h | 2 +- Classes/BITHockeyManager.m | 2 +- Classes/BITHockeyManagerDelegate.h | 2 +- Classes/BITHockeyManagerPrivate.h | 2 +- Classes/BITStoreButton.h | 2 +- Classes/BITStoreButton.m | 2 +- Classes/BITUpdateManager.h | 2 +- Classes/BITUpdateManager.m | 2 +- Classes/BITUpdateManagerDelegate.h | 2 +- Classes/BITUpdateManagerPrivate.h | 2 +- Classes/BITUpdateViewController.h | 2 +- Classes/BITUpdateViewController.m | 2 +- Classes/BITUpdateViewControllerPrivate.h | 2 +- Classes/BITWebTableViewCell.h | 2 +- Classes/BITWebTableViewCell.m | 2 +- Classes/HockeySDK.h | 2 +- Classes/HockeySDKPrivate.h | 2 +- Classes/HockeySDKPrivate.m | 2 +- LICENSE | 6 +++--- 44 files changed, 48 insertions(+), 48 deletions(-) diff --git a/Classes/BITAppStoreHeader.h b/Classes/BITAppStoreHeader.h index 5b5f8873..272d86ae 100644 --- a/Classes/BITAppStoreHeader.h +++ b/Classes/BITAppStoreHeader.h @@ -2,7 +2,7 @@ * Author: Andreas Linde * Peter Steinberger * - * Copyright (c) 2012 HockeyApp, Bit Stadium GmbH. + * Copyright (c) 2012-2013 HockeyApp, Bit Stadium GmbH. * Copyright (c) 2011-2012 Peter Steinberger. * All rights reserved. * diff --git a/Classes/BITAppStoreHeader.m b/Classes/BITAppStoreHeader.m index 40eea590..dbee1fcd 100644 --- a/Classes/BITAppStoreHeader.m +++ b/Classes/BITAppStoreHeader.m @@ -2,7 +2,7 @@ * Author: Andreas Linde * Peter Steinberger * - * Copyright (c) 2012 HockeyApp, Bit Stadium GmbH. + * Copyright (c) 2012-2013 HockeyApp, Bit Stadium GmbH. * Copyright (c) 2011-2012 Peter Steinberger. * All rights reserved. * diff --git a/Classes/BITAppVersionMetaInfo.h b/Classes/BITAppVersionMetaInfo.h index 7c1db67f..f514a688 100644 --- a/Classes/BITAppVersionMetaInfo.h +++ b/Classes/BITAppVersionMetaInfo.h @@ -1,7 +1,7 @@ /* * Author: Peter Steinberger * - * Copyright (c) 2012 HockeyApp, Bit Stadium GmbH. + * Copyright (c) 2012-2013 HockeyApp, Bit Stadium GmbH. * Copyright (c) 2011 Andreas Linde, Peter Steinberger. * All rights reserved. * diff --git a/Classes/BITAppVersionMetaInfo.m b/Classes/BITAppVersionMetaInfo.m index 7b1394fd..0d3a3137 100644 --- a/Classes/BITAppVersionMetaInfo.m +++ b/Classes/BITAppVersionMetaInfo.m @@ -1,7 +1,7 @@ /* * Author: Peter Steinberger * - * Copyright (c) 2012 HockeyApp, Bit Stadium GmbH. + * Copyright (c) 2012-2013 HockeyApp, Bit Stadium GmbH. * Copyright (c) 2011 Andreas Linde, Peter Steinberger. * All rights reserved. * diff --git a/Classes/BITCrashManager.h b/Classes/BITCrashManager.h index 769369df..66d91836 100644 --- a/Classes/BITCrashManager.h +++ b/Classes/BITCrashManager.h @@ -2,7 +2,7 @@ * Author: Andreas Linde * Kent Sutherland * - * Copyright (c) 2012 HockeyApp, Bit Stadium GmbH. + * Copyright (c) 2012-2013 HockeyApp, Bit Stadium GmbH. * Copyright (c) 2011 Andreas Linde & Kent Sutherland. * All rights reserved. * diff --git a/Classes/BITCrashManager.m b/Classes/BITCrashManager.m index 416d32fa..8ade9ec4 100644 --- a/Classes/BITCrashManager.m +++ b/Classes/BITCrashManager.m @@ -2,7 +2,7 @@ * Author: Andreas Linde * Kent Sutherland * - * Copyright (c) 2012 HockeyApp, Bit Stadium GmbH. + * Copyright (c) 2012-2013 HockeyApp, Bit Stadium GmbH. * Copyright (c) 2011 Andreas Linde & Kent Sutherland. * All rights reserved. * diff --git a/Classes/BITCrashManagerDelegate.h b/Classes/BITCrashManagerDelegate.h index 243f4299..16bb2e58 100644 --- a/Classes/BITCrashManagerDelegate.h +++ b/Classes/BITCrashManagerDelegate.h @@ -1,7 +1,7 @@ /* * Author: Andreas Linde * - * Copyright (c) 2012 HockeyApp, Bit Stadium GmbH. + * Copyright (c) 2012-2013 HockeyApp, Bit Stadium GmbH. * All rights reserved. * * Permission is hereby granted, free of charge, to any person diff --git a/Classes/BITCrashManagerPrivate.h b/Classes/BITCrashManagerPrivate.h index b3960c4f..3bf53490 100644 --- a/Classes/BITCrashManagerPrivate.h +++ b/Classes/BITCrashManagerPrivate.h @@ -2,7 +2,7 @@ * Author: Andreas Linde * Kent Sutherland * - * Copyright (c) 2012 HockeyApp, Bit Stadium GmbH. + * Copyright (c) 2012-2013 HockeyApp, Bit Stadium GmbH. * Copyright (c) 2011 Andreas Linde & Kent Sutherland. * All rights reserved. * diff --git a/Classes/BITCrashReportTextFormatter.h b/Classes/BITCrashReportTextFormatter.h index 4ff2743c..786cd2d9 100644 --- a/Classes/BITCrashReportTextFormatter.h +++ b/Classes/BITCrashReportTextFormatter.h @@ -4,9 +4,9 @@ * Damian Morris * Andreas Linde * - * Copyright (c) 2008-2012 Plausible Labs Cooperative, Inc. + * Copyright (c) 2008-2013 Plausible Labs Cooperative, Inc. * Copyright (c) 2010 MOSO Corporation, Pty Ltd. - * Copyright (c) 2012 HockeyApp, Bit Stadium GmbH. + * Copyright (c) 2012-2013 HockeyApp, Bit Stadium GmbH. * All rights reserved. * * Permission is hereby granted, free of charge, to any person diff --git a/Classes/BITCrashReportTextFormatter.m b/Classes/BITCrashReportTextFormatter.m index 93a16d66..be8f5b91 100644 --- a/Classes/BITCrashReportTextFormatter.m +++ b/Classes/BITCrashReportTextFormatter.m @@ -4,9 +4,9 @@ * Damian Morris * Andreas Linde * - * Copyright (c) 2008-2012 Plausible Labs Cooperative, Inc. + * Copyright (c) 2008-2013 Plausible Labs Cooperative, Inc. * Copyright (c) 2010 MOSO Corporation, Pty Ltd. - * Copyright (c) 2012 HockeyApp, Bit Stadium GmbH. + * Copyright (c) 2012-2013 HockeyApp, Bit Stadium GmbH. * All rights reserved. * * Permission is hereby granted, free of charge, to any person diff --git a/Classes/BITFeedbackComposeViewController.h b/Classes/BITFeedbackComposeViewController.h index ea9a1106..e3fa96a6 100644 --- a/Classes/BITFeedbackComposeViewController.h +++ b/Classes/BITFeedbackComposeViewController.h @@ -1,7 +1,7 @@ /* * Author: Andreas Linde * - * Copyright (c) 2012 HockeyApp, Bit Stadium GmbH. + * Copyright (c) 2012-2013 HockeyApp, Bit Stadium GmbH. * All rights reserved. * * Permission is hereby granted, free of charge, to any person diff --git a/Classes/BITFeedbackComposeViewController.m b/Classes/BITFeedbackComposeViewController.m index 9cc68345..aee0bb0a 100644 --- a/Classes/BITFeedbackComposeViewController.m +++ b/Classes/BITFeedbackComposeViewController.m @@ -1,7 +1,7 @@ /* * Author: Andreas Linde * - * Copyright (c) 2012 HockeyApp, Bit Stadium GmbH. + * Copyright (c) 2012-2013 HockeyApp, Bit Stadium GmbH. * All rights reserved. * * Permission is hereby granted, free of charge, to any person diff --git a/Classes/BITFeedbackListViewCell.h b/Classes/BITFeedbackListViewCell.h index 082d7fba..575f93b4 100644 --- a/Classes/BITFeedbackListViewCell.h +++ b/Classes/BITFeedbackListViewCell.h @@ -1,7 +1,7 @@ /* * Author: Andreas Linde * - * Copyright (c) 2012 HockeyApp, Bit Stadium GmbH. + * Copyright (c) 2012-2013 HockeyApp, Bit Stadium GmbH. * All rights reserved. * * Permission is hereby granted, free of charge, to any person diff --git a/Classes/BITFeedbackListViewCell.m b/Classes/BITFeedbackListViewCell.m index b4c63457..084f58e8 100644 --- a/Classes/BITFeedbackListViewCell.m +++ b/Classes/BITFeedbackListViewCell.m @@ -1,7 +1,7 @@ /* * Author: Andreas Linde * - * Copyright (c) 2012 HockeyApp, Bit Stadium GmbH. + * Copyright (c) 2012-2013 HockeyApp, Bit Stadium GmbH. * All rights reserved. * * Permission is hereby granted, free of charge, to any person diff --git a/Classes/BITFeedbackListViewController.h b/Classes/BITFeedbackListViewController.h index 49122898..28373bf7 100644 --- a/Classes/BITFeedbackListViewController.h +++ b/Classes/BITFeedbackListViewController.h @@ -1,7 +1,7 @@ /* * Author: Andreas Linde * - * Copyright (c) 2012 HockeyApp, Bit Stadium GmbH. + * Copyright (c) 2012-2013 HockeyApp, Bit Stadium GmbH. * All rights reserved. * * Permission is hereby granted, free of charge, to any person diff --git a/Classes/BITFeedbackListViewController.m b/Classes/BITFeedbackListViewController.m index 654d9cc3..f81f56ae 100644 --- a/Classes/BITFeedbackListViewController.m +++ b/Classes/BITFeedbackListViewController.m @@ -1,7 +1,7 @@ /* * Author: Andreas Linde * - * Copyright (c) 2012 HockeyApp, Bit Stadium GmbH. + * Copyright (c) 2012-2013 HockeyApp, Bit Stadium GmbH. * All rights reserved. * * Permission is hereby granted, free of charge, to any person diff --git a/Classes/BITFeedbackManager.h b/Classes/BITFeedbackManager.h index 5dbc5e99..dd59cd86 100644 --- a/Classes/BITFeedbackManager.h +++ b/Classes/BITFeedbackManager.h @@ -1,7 +1,7 @@ /* * Author: Andreas Linde * - * Copyright (c) 2012 HockeyApp, Bit Stadium GmbH. + * Copyright (c) 2012-2013 HockeyApp, Bit Stadium GmbH. * All rights reserved. * * Permission is hereby granted, free of charge, to any person diff --git a/Classes/BITFeedbackManager.m b/Classes/BITFeedbackManager.m index d4d2212b..2825dd17 100644 --- a/Classes/BITFeedbackManager.m +++ b/Classes/BITFeedbackManager.m @@ -1,7 +1,7 @@ /* * Author: Andreas Linde * - * Copyright (c) 2012 HockeyApp, Bit Stadium GmbH. + * Copyright (c) 2012-2013 HockeyApp, Bit Stadium GmbH. * All rights reserved. * * Permission is hereby granted, free of charge, to any person diff --git a/Classes/BITFeedbackManagerPrivate.h b/Classes/BITFeedbackManagerPrivate.h index ff38bb98..cd8bd314 100644 --- a/Classes/BITFeedbackManagerPrivate.h +++ b/Classes/BITFeedbackManagerPrivate.h @@ -2,7 +2,7 @@ * Author: Andreas Linde * Kent Sutherland * - * Copyright (c) 2012 HockeyApp, Bit Stadium GmbH. + * Copyright (c) 2012-2013 HockeyApp, Bit Stadium GmbH. * Copyright (c) 2011 Andreas Linde & Kent Sutherland. * All rights reserved. * diff --git a/Classes/BITFeedbackMessage.h b/Classes/BITFeedbackMessage.h index 371501fc..e71f3f92 100644 --- a/Classes/BITFeedbackMessage.h +++ b/Classes/BITFeedbackMessage.h @@ -1,7 +1,7 @@ /* * Author: Andreas Linde * - * Copyright (c) 2012 HockeyApp, Bit Stadium GmbH. + * Copyright (c) 2012-2013 HockeyApp, Bit Stadium GmbH. * All rights reserved. * * Permission is hereby granted, free of charge, to any person diff --git a/Classes/BITFeedbackMessage.m b/Classes/BITFeedbackMessage.m index 745df7db..21f7b406 100644 --- a/Classes/BITFeedbackMessage.m +++ b/Classes/BITFeedbackMessage.m @@ -1,7 +1,7 @@ /* * Author: Andreas Linde * - * Copyright (c) 2012 HockeyApp, Bit Stadium GmbH. + * Copyright (c) 2012-2013 HockeyApp, Bit Stadium GmbH. * All rights reserved. * * Permission is hereby granted, free of charge, to any person diff --git a/Classes/BITFeedbackUserDataViewController.h b/Classes/BITFeedbackUserDataViewController.h index 68bf2b46..6c301b5a 100644 --- a/Classes/BITFeedbackUserDataViewController.h +++ b/Classes/BITFeedbackUserDataViewController.h @@ -1,7 +1,7 @@ /* * Author: Andreas Linde * - * Copyright (c) 2012 HockeyApp, Bit Stadium GmbH. + * Copyright (c) 2012-2013 HockeyApp, Bit Stadium GmbH. * All rights reserved. * * Permission is hereby granted, free of charge, to any person diff --git a/Classes/BITFeedbackUserDataViewController.m b/Classes/BITFeedbackUserDataViewController.m index 8aa54409..e47a7876 100644 --- a/Classes/BITFeedbackUserDataViewController.m +++ b/Classes/BITFeedbackUserDataViewController.m @@ -1,7 +1,7 @@ /* * Author: Andreas Linde * - * Copyright (c) 2012 HockeyApp, Bit Stadium GmbH. + * Copyright (c) 2012-2013 HockeyApp, Bit Stadium GmbH. * All rights reserved. * * Permission is hereby granted, free of charge, to any person diff --git a/Classes/BITHockeyHelper.h b/Classes/BITHockeyHelper.h index b9b484ff..211c5298 100644 --- a/Classes/BITHockeyHelper.h +++ b/Classes/BITHockeyHelper.h @@ -1,7 +1,7 @@ /* * Author: Andreas Linde * - * Copyright (c) 2012 HockeyApp, Bit Stadium GmbH. + * Copyright (c) 2012-2013 HockeyApp, Bit Stadium GmbH. * All rights reserved. * * Permission is hereby granted, free of charge, to any person diff --git a/Classes/BITHockeyHelper.m b/Classes/BITHockeyHelper.m index 5df67095..3f3db5ed 100644 --- a/Classes/BITHockeyHelper.m +++ b/Classes/BITHockeyHelper.m @@ -1,7 +1,7 @@ /* * Author: Andreas Linde * - * Copyright (c) 2012 HockeyApp, Bit Stadium GmbH. + * Copyright (c) 2012-2013 HockeyApp, Bit Stadium GmbH. * All rights reserved. * * Permission is hereby granted, free of charge, to any person diff --git a/Classes/BITHockeyManager.h b/Classes/BITHockeyManager.h index 5a0088ec..28942597 100644 --- a/Classes/BITHockeyManager.h +++ b/Classes/BITHockeyManager.h @@ -2,7 +2,7 @@ * Author: Andreas Linde * Kent Sutherland * - * Copyright (c) 2012 HockeyApp, Bit Stadium GmbH. + * Copyright (c) 2012-2013 HockeyApp, Bit Stadium GmbH. * All rights reserved. * * Permission is hereby granted, free of charge, to any person diff --git a/Classes/BITHockeyManager.m b/Classes/BITHockeyManager.m index fb418bef..f5e40c56 100644 --- a/Classes/BITHockeyManager.m +++ b/Classes/BITHockeyManager.m @@ -2,7 +2,7 @@ * Author: Andreas Linde * Kent Sutherland * - * Copyright (c) 2012 HockeyApp, Bit Stadium GmbH. + * Copyright (c) 2012-2013 HockeyApp, Bit Stadium GmbH. * All rights reserved. * * Permission is hereby granted, free of charge, to any person diff --git a/Classes/BITHockeyManagerDelegate.h b/Classes/BITHockeyManagerDelegate.h index b33e77e4..7c052831 100644 --- a/Classes/BITHockeyManagerDelegate.h +++ b/Classes/BITHockeyManagerDelegate.h @@ -1,7 +1,7 @@ /* * Author: Andreas Linde * - * Copyright (c) 2012 HockeyApp, Bit Stadium GmbH. + * Copyright (c) 2012-2013 HockeyApp, Bit Stadium GmbH. * All rights reserved. * * Permission is hereby granted, free of charge, to any person diff --git a/Classes/BITHockeyManagerPrivate.h b/Classes/BITHockeyManagerPrivate.h index 1b0c9e0d..7ac35c41 100644 --- a/Classes/BITHockeyManagerPrivate.h +++ b/Classes/BITHockeyManagerPrivate.h @@ -1,7 +1,7 @@ /* * Author: Andreas Linde * - * Copyright (c) 2012 HockeyApp, Bit Stadium GmbH. + * Copyright (c) 2012-2013 HockeyApp, Bit Stadium GmbH. * All rights reserved. * * Permission is hereby granted, free of charge, to any person diff --git a/Classes/BITStoreButton.h b/Classes/BITStoreButton.h index 81906b09..0e5d0976 100644 --- a/Classes/BITStoreButton.h +++ b/Classes/BITStoreButton.h @@ -2,7 +2,7 @@ * Author: Andreas Linde * Peter Steinberger * - * Copyright (c) 2012 HockeyApp, Bit Stadium GmbH. + * Copyright (c) 2012-2013 HockeyApp, Bit Stadium GmbH. * Copyright (c) 2011-2012 Peter Steinberger. * All rights reserved. * diff --git a/Classes/BITStoreButton.m b/Classes/BITStoreButton.m index 0f69eff7..98eb3bde 100644 --- a/Classes/BITStoreButton.m +++ b/Classes/BITStoreButton.m @@ -2,7 +2,7 @@ * Author: Andreas Linde * Peter Steinberger * - * Copyright (c) 2012 HockeyApp, Bit Stadium GmbH. + * Copyright (c) 2012-2013 HockeyApp, Bit Stadium GmbH. * Copyright (c) 2011-2012 Peter Steinberger. * All rights reserved. * diff --git a/Classes/BITUpdateManager.h b/Classes/BITUpdateManager.h index b9ccb4c4..d0de33d8 100644 --- a/Classes/BITUpdateManager.h +++ b/Classes/BITUpdateManager.h @@ -2,7 +2,7 @@ * Author: Andreas Linde * Peter Steinberger * - * Copyright (c) 2012 HockeyApp, Bit Stadium GmbH. + * Copyright (c) 2012-2013 HockeyApp, Bit Stadium GmbH. * Copyright (c) 2011 Andreas Linde. * All rights reserved. * diff --git a/Classes/BITUpdateManager.m b/Classes/BITUpdateManager.m index 23d8403e..117f0376 100644 --- a/Classes/BITUpdateManager.m +++ b/Classes/BITUpdateManager.m @@ -2,7 +2,7 @@ * Author: Andreas Linde * Peter Steinberger * - * Copyright (c) 2012 HockeyApp, Bit Stadium GmbH. + * Copyright (c) 2012-2013 HockeyApp, Bit Stadium GmbH. * Copyright (c) 2011 Andreas Linde. * All rights reserved. * diff --git a/Classes/BITUpdateManagerDelegate.h b/Classes/BITUpdateManagerDelegate.h index a9ce21c8..ef86d376 100644 --- a/Classes/BITUpdateManagerDelegate.h +++ b/Classes/BITUpdateManagerDelegate.h @@ -1,7 +1,7 @@ /* * Author: Andreas Linde * - * Copyright (c) 2012 HockeyApp, Bit Stadium GmbH. + * Copyright (c) 2012-2013 HockeyApp, Bit Stadium GmbH. * All rights reserved. * * Permission is hereby granted, free of charge, to any person diff --git a/Classes/BITUpdateManagerPrivate.h b/Classes/BITUpdateManagerPrivate.h index 65f8ffa3..00e545f2 100644 --- a/Classes/BITUpdateManagerPrivate.h +++ b/Classes/BITUpdateManagerPrivate.h @@ -2,7 +2,7 @@ * Author: Andreas Linde * Peter Steinberger * - * Copyright (c) 2012 HockeyApp, Bit Stadium GmbH. + * Copyright (c) 2012-2013 HockeyApp, Bit Stadium GmbH. * Copyright (c) 2011 Andreas Linde. * All rights reserved. * diff --git a/Classes/BITUpdateViewController.h b/Classes/BITUpdateViewController.h index b24708a9..9f100f19 100644 --- a/Classes/BITUpdateViewController.h +++ b/Classes/BITUpdateViewController.h @@ -2,7 +2,7 @@ * Author: Andreas Linde * Peter Steinberger * - * Copyright (c) 2012 HockeyApp, Bit Stadium GmbH. + * Copyright (c) 2012-2013 HockeyApp, Bit Stadium GmbH. * Copyright (c) 2011 Andreas Linde, Peter Steinberger. * All rights reserved. * diff --git a/Classes/BITUpdateViewController.m b/Classes/BITUpdateViewController.m index aa783d93..46dc1a11 100644 --- a/Classes/BITUpdateViewController.m +++ b/Classes/BITUpdateViewController.m @@ -2,7 +2,7 @@ * Author: Andreas Linde * Peter Steinberger * - * Copyright (c) 2012 HockeyApp, Bit Stadium GmbH. + * Copyright (c) 2012-2013 HockeyApp, Bit Stadium GmbH. * Copyright (c) 2011 Andreas Linde, Peter Steinberger. * All rights reserved. * diff --git a/Classes/BITUpdateViewControllerPrivate.h b/Classes/BITUpdateViewControllerPrivate.h index cf6ecb0e..d8c36727 100644 --- a/Classes/BITUpdateViewControllerPrivate.h +++ b/Classes/BITUpdateViewControllerPrivate.h @@ -2,7 +2,7 @@ * Author: Andreas Linde * Peter Steinberger * - * Copyright (c) 2012 HockeyApp, Bit Stadium GmbH. + * Copyright (c) 2012-2013 HockeyApp, Bit Stadium GmbH. * Copyright (c) 2011 Andreas Linde, Peter Steinberger. * All rights reserved. * diff --git a/Classes/BITWebTableViewCell.h b/Classes/BITWebTableViewCell.h index f2bcf0e1..2c9a980f 100644 --- a/Classes/BITWebTableViewCell.h +++ b/Classes/BITWebTableViewCell.h @@ -2,7 +2,7 @@ * Author: Andreas Linde * Peter Steinberger * - * Copyright (c) 2012 HockeyApp, Bit Stadium GmbH. + * Copyright (c) 2012-2013 HockeyApp, Bit Stadium GmbH. * Copyright (c) 2011-2012 Peter Steinberger. * All rights reserved. * diff --git a/Classes/BITWebTableViewCell.m b/Classes/BITWebTableViewCell.m index f6adf07b..8b58aa5a 100644 --- a/Classes/BITWebTableViewCell.m +++ b/Classes/BITWebTableViewCell.m @@ -2,7 +2,7 @@ * Author: Andreas Linde * Peter Steinberger * - * Copyright (c) 2012 HockeyApp, Bit Stadium GmbH. + * Copyright (c) 2012-2013 HockeyApp, Bit Stadium GmbH. * Copyright (c) 2011-2012 Peter Steinberger. * All rights reserved. * diff --git a/Classes/HockeySDK.h b/Classes/HockeySDK.h index 81e67293..c7e6c449 100644 --- a/Classes/HockeySDK.h +++ b/Classes/HockeySDK.h @@ -1,7 +1,7 @@ /* * Author: Andreas Linde * - * Copyright (c) 2012 HockeyApp, Bit Stadium GmbH. + * Copyright (c) 2012-2013 HockeyApp, Bit Stadium GmbH. * Copyright (c) 2011 Andreas Linde. * All rights reserved. * diff --git a/Classes/HockeySDKPrivate.h b/Classes/HockeySDKPrivate.h index 346482d7..6fe6c507 100644 --- a/Classes/HockeySDKPrivate.h +++ b/Classes/HockeySDKPrivate.h @@ -2,7 +2,7 @@ * Author: Andreas Linde * Kent Sutherland * - * Copyright (c) 2012 HockeyApp, Bit Stadium GmbH. + * Copyright (c) 2012-2013 HockeyApp, Bit Stadium GmbH. * Copyright (c) 2011 Andreas Linde & Kent Sutherland. * All rights reserved. * diff --git a/Classes/HockeySDKPrivate.m b/Classes/HockeySDKPrivate.m index dc0d1f9d..d5846d8e 100644 --- a/Classes/HockeySDKPrivate.m +++ b/Classes/HockeySDKPrivate.m @@ -1,7 +1,7 @@ /* * Author: Andreas Linde * - * Copyright (c) 2012 HockeyApp, Bit Stadium GmbH. + * Copyright (c) 2012-2013 HockeyApp, Bit Stadium GmbH. * Copyright (c) 2011 Andreas Linde. * All rights reserved. * diff --git a/LICENSE b/LICENSE index fe73ef79..dfa06530 100755 --- a/LICENSE +++ b/LICENSE @@ -3,7 +3,7 @@ The Hockey SDK is provided under the following license: The MIT License - Copyright (c) 2012 HockeyApp, Bit Stadium GmbH. + Copyright (c) 2012-2013 HockeyApp, Bit Stadium GmbH. All rights reserved. Permission is hereby granted, free of charge, to any person @@ -30,8 +30,8 @@ The Hockey SDK is provided under the following license: Except as noted below, PLCrashReporter is provided under the following license: - Copyright (c) 2008 - 2012 Plausible Labs Cooperative, Inc. - Copyright (c) 2012 HockeyApp, Bit Stadium GmbH. + Copyright (c) 2008 - 2013 Plausible Labs Cooperative, Inc. + Copyright (c) 2012 - 2013 HockeyApp, Bit Stadium GmbH. All rights reserved. Permission is hereby granted, free of charge, to any person From 4a02c8c82f9c8690c3f104a530bdecc4b3eed46f Mon Sep 17 00:00:00 2001 From: Andreas Linde Date: Wed, 9 Jan 2013 16:51:28 +0100 Subject: [PATCH 146/176] Update localizations provided by wordcrafts.de --- Resources/de.lproj/HockeySDK.strings | 15 +++++++++++---- Resources/en.lproj/HockeySDK.strings | 9 ++++++++- Resources/es.lproj/HockeySDK.strings | 9 ++++++++- Resources/fr.lproj/HockeySDK.strings | 7 +++++++ Resources/hr.lproj/HockeySDK.strings | 5 +++++ Resources/it.lproj/HockeySDK.strings | 7 +++++++ Resources/ja.lproj/HockeySDK.strings | 11 +++++++++-- Resources/pt-PT.lproj/HockeySDK.strings | 7 +++++++ Resources/pt.lproj/HockeySDK.strings | 7 +++++++ Resources/ru.lproj/HockeySDK.strings | 11 +++++++++-- Resources/zh-Hans.lproj/HockeySDK.strings | 9 ++++++++- 11 files changed, 86 insertions(+), 11 deletions(-) diff --git a/Resources/de.lproj/HockeySDK.strings b/Resources/de.lproj/HockeySDK.strings index 60a60a5f..02dcead2 100644 --- a/Resources/de.lproj/HockeySDK.strings +++ b/Resources/de.lproj/HockeySDK.strings @@ -1,3 +1,10 @@ +/* + Localization provided by Wordcrafts + The Mac OS X and iOS localization experts. + http://www.wordcrafts.de + */ + + /* General */ /* For dialogs yes buttons */ @@ -80,7 +87,7 @@ "UpdateNoUpdateAvailableTitle" = "Kein Update verfügbar"; -"UpdateNoUpdateAvailableMessage" = "%@ ist die zurzeit aktuellste Version"; +"UpdateNoUpdateAvailableMessage" = "%@ ist die derzeit aktuellste Version"; "UpdateError" = "Fehler"; @@ -144,10 +151,10 @@ "HockeyFeedbackListButonWriteResponse" = "Antworten"; /* User Data Set Name Button Title */ -"HockeyFeedbackListButonUserDataSetName" = "Namen eintragen"; +"HockeyFeedbackListButonUserDataSetName" = "Namen eingeben"; /* User Data Set Email Button Title */ -"HockeyFeedbackListButonUserDataSetEmail" = "E-Mail-Adresse eintragen"; +"HockeyFeedbackListButonUserDataSetEmail" = "E-Mail-Adresse eingeben"; /* User Data With Name Button Title */ "HockeyFeedbackListButonUserDataWithName" = "Name: %@"; @@ -165,7 +172,7 @@ /* Delete All Messages Action Sheet / Alert View */ /* Title for the Action Sheet */ -"HockeyFeedbackListDeleteAllTitle" = "Diese Aktion löscht alle auf diesem Gerät befindlichen Mitteilungen."; +"HockeyFeedbackListDeleteAllTitle" = "Diese Aktion löscht alle auf diesem Gerät befindlichen HockeyApp-Mitteilungen."; /* Button Title to perform delete action */ "HockeyFeedbackListDeleteAllDelete" = "Löschen"; diff --git a/Resources/en.lproj/HockeySDK.strings b/Resources/en.lproj/HockeySDK.strings index 8bab3935..b317db72 100644 --- a/Resources/en.lproj/HockeySDK.strings +++ b/Resources/en.lproj/HockeySDK.strings @@ -1,4 +1,11 @@ -/* General */ +/* + Localization provided by Wordcrafts + The Mac OS X and iOS localization experts. + http://www.wordcrafts.de + */ + + +/* General */ /* For dialogs yes buttons */ "HockeyYes" = "Yes"; diff --git a/Resources/es.lproj/HockeySDK.strings b/Resources/es.lproj/HockeySDK.strings index 205efcf0..af2b780f 100644 --- a/Resources/es.lproj/HockeySDK.strings +++ b/Resources/es.lproj/HockeySDK.strings @@ -1,3 +1,10 @@ +/* + Localization provided by Wordcrafts + The Mac OS X and iOS localization experts. + http://www.wordcrafts.de + */ + + /* General */ /* For dialogs yes buttons */ @@ -27,7 +34,7 @@ "CrashDataFoundDescription" = "¿Desea enviar un informe para ayudarnos a solucionar el problema?"; /* Alert box button if the users wants to send crash data always automatically */ -"CrashSendReportAlways" = "Enviar siempre"; +"CrashSendReportAlways" = "Enviarlo siempre"; /* Alert box button to send the crash report once */ "CrashSendReport" = "Enviar informe"; diff --git a/Resources/fr.lproj/HockeySDK.strings b/Resources/fr.lproj/HockeySDK.strings index 8fef138c..d29e3efc 100644 --- a/Resources/fr.lproj/HockeySDK.strings +++ b/Resources/fr.lproj/HockeySDK.strings @@ -1,3 +1,10 @@ +/* + Localization provided by Wordcrafts + The Mac OS X and iOS localization experts. + http://www.wordcrafts.de + */ + + /* General */ /* For dialogs yes buttons */ diff --git a/Resources/hr.lproj/HockeySDK.strings b/Resources/hr.lproj/HockeySDK.strings index 82eaf60e..8de9a2ee 100644 --- a/Resources/hr.lproj/HockeySDK.strings +++ b/Resources/hr.lproj/HockeySDK.strings @@ -1,3 +1,8 @@ +/* + Localization provided by Alen Bajo + */ + + /* General */ /* For dialogs yes buttons */ diff --git a/Resources/it.lproj/HockeySDK.strings b/Resources/it.lproj/HockeySDK.strings index f334f13e..39b3243f 100644 --- a/Resources/it.lproj/HockeySDK.strings +++ b/Resources/it.lproj/HockeySDK.strings @@ -1,3 +1,10 @@ +/* + Localization provided by Wordcrafts + The Mac OS X and iOS localization experts. + http://www.wordcrafts.de + */ + + /* General */ /* For dialogs yes buttons */ diff --git a/Resources/ja.lproj/HockeySDK.strings b/Resources/ja.lproj/HockeySDK.strings index af78fba5..c0617bd6 100644 --- a/Resources/ja.lproj/HockeySDK.strings +++ b/Resources/ja.lproj/HockeySDK.strings @@ -1,3 +1,10 @@ +/* + Localization provided by Wordcrafts + The Mac OS X and iOS localization experts. + http://www.wordcrafts.de + */ + + /* General */ /* For dialogs yes buttons */ @@ -49,7 +56,7 @@ "UpdateAlertTextWithAppVersion" = "%@ が入手できます。"; -"UpdateAlertMandatoryTextWithAppVersion" = "必須アップデート%@が利用可能です!"; +"UpdateAlertMandatoryTextWithAppVersion" = "必須アップデート %@ が利用可能です!"; "UpdateIgnore" = "無視"; @@ -105,7 +112,7 @@ /* Update Simulator Warning */ -"UpdateSimulatorMessage" = "Hockey のアップデートは Simulator では作動しません。\nitms-services:// url 方式は実装されていますが、機能しません。"; +"UpdateSimulatorMessage" = "Hockey のアップデートは Simulator では作動しません。\nitms-services:// のURL方式は実装されていますが、機能しません。"; /* Feedback */ diff --git a/Resources/pt-PT.lproj/HockeySDK.strings b/Resources/pt-PT.lproj/HockeySDK.strings index f8883de8..9dc5f1cb 100644 --- a/Resources/pt-PT.lproj/HockeySDK.strings +++ b/Resources/pt-PT.lproj/HockeySDK.strings @@ -1,3 +1,10 @@ +/* + Localization provided by Wordcrafts + The Mac OS X and iOS localization experts. + http://www.wordcrafts.de + */ + + /* General */ /* For dialogs yes buttons */ diff --git a/Resources/pt.lproj/HockeySDK.strings b/Resources/pt.lproj/HockeySDK.strings index 6dbd0db2..eafea553 100644 --- a/Resources/pt.lproj/HockeySDK.strings +++ b/Resources/pt.lproj/HockeySDK.strings @@ -1,3 +1,10 @@ +/* + Localization provided by Wordcrafts + The Mac OS X and iOS localization experts. + http://www.wordcrafts.de + */ + + /* General */ /* For dialogs yes buttons */ diff --git a/Resources/ru.lproj/HockeySDK.strings b/Resources/ru.lproj/HockeySDK.strings index 30d47120..434bb7ac 100644 --- a/Resources/ru.lproj/HockeySDK.strings +++ b/Resources/ru.lproj/HockeySDK.strings @@ -1,3 +1,10 @@ +/* + Localization provided by Wordcrafts + The Mac OS X and iOS localization experts. + http://www.wordcrafts.de + */ + + /* General */ /* For dialogs yes buttons */ @@ -135,7 +142,7 @@ "HockeyFeedbackListLastUpdated" = "Последнее обновление: %@"; /* Never Updated */ -"HockeyFeedbackListNeverUpdated" = "Никогда"; +"HockeyFeedbackListNeverUpdated" = "Не было"; /* Provide Feedback Button Title */ "HockeyFeedbackListButonWriteFeedback" = "Написать отклик"; @@ -216,7 +223,7 @@ "HockeyFeedbackUserDataName" = "Имя"; /* Name Placeholder */ -"HockeyFeedbackUserDataNamePlaceHolder" = "John Doe"; +"HockeyFeedbackUserDataNamePlaceHolder" = "Имя"; /* Email Field */ "HockeyFeedbackUserDataEmail" = "Email"; diff --git a/Resources/zh-Hans.lproj/HockeySDK.strings b/Resources/zh-Hans.lproj/HockeySDK.strings index e17515a8..ed4bbf8c 100644 --- a/Resources/zh-Hans.lproj/HockeySDK.strings +++ b/Resources/zh-Hans.lproj/HockeySDK.strings @@ -1,3 +1,10 @@ +/* + Localization provided by Wordcrafts + The Mac OS X and iOS localization experts. + http://www.wordcrafts.de + */ + + /* General */ /* For dialogs yes buttons */ @@ -159,7 +166,7 @@ "HockeyFeedbackListButonDeleteAllMessages" = "删除全部信息"; /* Message pending to be send */ -"HockeyFeedbackListMessagePending" = "挂起"; +"HockeyFeedbackListMessagePending" = "待定"; /* Delete All Messages Action Sheet / Alert View */ From b1fd3274778c9e16d4727f034779b4f5b5c5660d Mon Sep 17 00:00:00 2001 From: Andreas Linde Date: Wed, 9 Jan 2013 23:42:25 +0100 Subject: [PATCH 147/176] Add romanian localization to the project - Add the credit of the localizer to the header of the file - Correct one localization bug - Add the localization to the actual Xcode project --- Resources/ro.lproj/HockeySDK.strings | 9 +++++++-- Support/HockeySDK.xcodeproj/project.pbxproj | 3 +++ 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/Resources/ro.lproj/HockeySDK.strings b/Resources/ro.lproj/HockeySDK.strings index f373f41d..147e2cbe 100755 --- a/Resources/ro.lproj/HockeySDK.strings +++ b/Resources/ro.lproj/HockeySDK.strings @@ -1,4 +1,9 @@ -/* General */ +/* + Localization provided by Cristi Paraschiv + */ + + +/* General */ /* For dialogs yes buttons */ "HockeyYes" = "Da"; @@ -91,7 +96,7 @@ /* Update Authorization */ -"UpdateAuthorizationProgress" = "Se authorizează..."; +"UpdateAuthorizationProgress" = "Se autorizeaza..."; "UpdateAuthorizationOffline" = "Necesită conexiune la Internet!"; diff --git a/Support/HockeySDK.xcodeproj/project.pbxproj b/Support/HockeySDK.xcodeproj/project.pbxproj index 143d44d1..6dd9c593 100644 --- a/Support/HockeySDK.xcodeproj/project.pbxproj +++ b/Support/HockeySDK.xcodeproj/project.pbxproj @@ -196,6 +196,7 @@ 1E5955C515B71C8600A03429 /* IconGradient@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "IconGradient@2x.png"; sourceTree = ""; }; 1E5955FA15B7877A00A03429 /* BITHockeyManagerDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BITHockeyManagerDelegate.h; sourceTree = ""; }; 1E66CA9115D4100500F35BED /* buildnumber.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = buildnumber.xcconfig; sourceTree = ""; }; + 1E6DDCEE169E290C0076C65D /* ro */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ro; path = ro.lproj/HockeySDK.strings; sourceTree = ""; }; 1E6F0450167B5E5600ED1C86 /* pt-PT */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "pt-PT"; path = "pt-PT.lproj/HockeySDK.strings"; sourceTree = ""; }; 1E71509A15B5C76F004E88FF /* HockeySDK.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HockeySDK.h; sourceTree = ""; }; 1E754DC61621BC170070AB92 /* HockeySDK.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = HockeySDK.xcconfig; sourceTree = ""; }; @@ -530,6 +531,7 @@ hr, zh, "zh-Hans", + ro, ); mainGroup = E400560F148D79B500EB22B9; productRefGroup = E400561B148D79B500EB22B9 /* Products */; @@ -672,6 +674,7 @@ 1E6F0450167B5E5600ED1C86 /* pt-PT */, 1EB52FC3167B73D400C801D5 /* en */, 1EA512DF167F7EF000FC9FBA /* zh-Hans */, + 1E6DDCEE169E290C0076C65D /* ro */, ); name = HockeySDK.strings; sourceTree = ""; From 8dab0e1d3a859d059f8921c477762bf2069d4b92 Mon Sep 17 00:00:00 2001 From: Andreas Linde Date: Tue, 15 Jan 2013 16:03:50 +0100 Subject: [PATCH 148/176] Binary UUID fetching may not return nil, otherwise could lead to a crash. Return an empty string instead --- Classes/BITHockeyBaseManager.m | 1 + 1 file changed, 1 insertion(+) diff --git a/Classes/BITHockeyBaseManager.m b/Classes/BITHockeyBaseManager.m index 285f239e..977b7727 100644 --- a/Classes/BITHockeyBaseManager.m +++ b/Classes/BITHockeyBaseManager.m @@ -101,6 +101,7 @@ - (NSString *)executableUUID { } } return nil; + return @""; } - (UIWindow *)findVisibleWindow { From 78b2127a927944308d5bf085edfaa99054e9dc98 Mon Sep 17 00:00:00 2001 From: Andreas Linde Date: Tue, 15 Jan 2013 16:07:17 +0100 Subject: [PATCH 149/176] Exclude UUID fetching from simulator builds (workaround to get unit test targets build without problems) - This now requires the testing of this feature to be done on an actual device, since it returns always empty strings on the simulator - Once there is a better solution to get unit test targets build without problems this should be changed again, so testing of this feature is also possible using the simulator --- Classes/BITHockeyBaseManager.m | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/Classes/BITHockeyBaseManager.m b/Classes/BITHockeyBaseManager.m index 977b7727..2da44b84 100644 --- a/Classes/BITHockeyBaseManager.m +++ b/Classes/BITHockeyBaseManager.m @@ -18,8 +18,9 @@ #import "BITHockeyManagerPrivate.h" #import +#if !TARGET_IPHONE_SIMULATOR #import - +#endif @implementation BITHockeyBaseManager { UINavigationController *_navController; @@ -84,6 +85,12 @@ - (NSString *)getDevicePlatform { } - (NSString *)executableUUID { + // This now requires the testing of this feature to be done on an actual device, since it returns always empty strings on the simulator + // Once there is a better solution to get unit test targets build without problems this should be changed again, so testing of this + // feature is also possible using the simulator + // See: http://support.hockeyapp.net/discussions/problems/2306-integrating-hockeyapp-with-test-bundle-target-i386-issues + // http://support.hockeyapp.net/discussions/problems/4113-linking-hockeysdk-to-test-bundle-target +#if !TARGET_IPHONE_SIMULATOR const uint8_t *command = (const uint8_t *)(&_mh_execute_header + 1); for (uint32_t idx = 0; idx < _mh_execute_header.ncmds; ++idx) { const struct load_command *load_command = (const struct load_command *)command; @@ -100,7 +107,7 @@ - (NSString *)executableUUID { command += load_command->cmdsize; } } - return nil; +#endif return @""; } From 98003682ea76da2fb2aa3ffdd32e6234d88e90dd Mon Sep 17 00:00:00 2001 From: Kyle Fleming Date: Thu, 17 Jan 2013 18:26:03 -0800 Subject: [PATCH 150/176] Fix for preprocessor definitions using cocoapods --- HockeySDK.podspec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/HockeySDK.podspec b/HockeySDK.podspec index a8e04358..f9eb7c32 100644 --- a/HockeySDK.podspec +++ b/HockeySDK.podspec @@ -21,7 +21,7 @@ Pod::Spec.new do |s| s.preserve_paths = 'Resources', 'Support', 'Vendor' s.frameworks = 'CoreText', 'QuartzCore', 'SystemConfiguration', 'CrashReporter', 'CoreGraphics', 'UIKit' s.xcconfig = { 'FRAMEWORK_SEARCH_PATHS' => '"$(PODS_ROOT)/HockeySDK/Vendor"', - 'GCC_PREPROCESSOR_DEFINITIONS' => %{BITHOCKEY_VERSION="@\\"#{s.version}\\""} } + 'GCC_PREPROCESSOR_DEFINITIONS' => %{$(inherited) BITHOCKEY_VERSION="@\\"#{s.version}\\""} } def s.post_install(target_installer) puts "\nGenerating HockeySDK resources bundle\n".yellow if config.verbose? From 01050ea4079acbc73cc126dd2261fc5dd0bec7d3 Mon Sep 17 00:00:00 2001 From: Andreas Linde Date: Fri, 18 Jan 2013 23:37:03 +0100 Subject: [PATCH 151/176] Fix bugs when changing require setters of BITFeedbackManager after the setup If the userName and userEmail delegates are implemented and the requireUserEmail or requireUserName are changed after that, then the user interface is shown even though the delegates define the values and the user shouldn't be able to change that. --- Classes/BITFeedbackManager.m | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/Classes/BITFeedbackManager.m b/Classes/BITFeedbackManager.m index 2825dd17..f76b65a0 100644 --- a/Classes/BITFeedbackManager.m +++ b/Classes/BITFeedbackManager.m @@ -216,8 +216,8 @@ - (BOOL)updateUserIDUsingDelegate { userIDForHockeyManager:[BITHockeyManager sharedHockeyManager] componentManager:self]; if (userID) { - self.userID = userID; availableViaDelegate = YES; + self.userID = userID; } } @@ -251,8 +251,8 @@ - (BOOL)updateUserEmailUsingDelegate { userEmailForHockeyManager:[BITHockeyManager sharedHockeyManager] componentManager:self]; if (userEmail) { - self.userEmail = userEmail; availableViaDelegate = YES; + self.userEmail = userEmail; self.requireUserEmail = BITFeedbackUserDataElementDontShow; } } @@ -264,6 +264,12 @@ - (void)updateAppDefinedUserData { [self updateUserIDUsingDelegate]; [self updateUserNameUsingDelegate]; [self updateUserEmailUsingDelegate]; + + // if both values are shown via the delegates, we never ever did ask and will never ever ask for user data + if (self.requireUserName == BITFeedbackUserDataElementDontShow && + self.requireUserEmail == BITFeedbackUserDataElementDontShow) { + self.didAskUserData = NO; + } } #pragma mark - Local Storage @@ -508,6 +514,8 @@ - (void)deleteAllMessages { #pragma mark - User - (BOOL)askManualUserDataAvailable { + [self updateAppDefinedUserData]; + if (self.requireUserName == BITFeedbackUserDataElementDontShow && self.requireUserEmail == BITFeedbackUserDataElementDontShow) return NO; @@ -516,6 +524,8 @@ - (BOOL)askManualUserDataAvailable { } - (BOOL)requireManualUserDataMissing { + [self updateAppDefinedUserData]; + if (self.requireUserName == BITFeedbackUserDataElementRequired && !self.userName) return YES; @@ -526,6 +536,8 @@ - (BOOL)requireManualUserDataMissing { } - (BOOL)isManualUserDataAvailable { + [self updateAppDefinedUserData]; + if ((self.requireUserName != BITFeedbackUserDataElementDontShow && self.userName) || (self.requireUserEmail != BITFeedbackUserDataElementDontShow && self.userEmail)) return YES; From fd6208b533c042d922cfd05ddde7f1ec1a49d1bf Mon Sep 17 00:00:00 2001 From: Andreas Linde Date: Fri, 18 Jan 2013 23:42:37 +0100 Subject: [PATCH 152/176] Only push the user details view automatically onto the feedback list stack once at max If the required manual user data is missing and the feedback list view appears the user detail view is automatically pushed. Now if the user cancels and goes back to the feedback list, it gets pushed again and so the user can never exit. Instead push this at maximum once. When providing feedback it will ask the missing user details again anyway. --- Classes/BITFeedbackListViewController.m | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Classes/BITFeedbackListViewController.m b/Classes/BITFeedbackListViewController.m index f81f56ae..5f3b70cf 100644 --- a/Classes/BITFeedbackListViewController.m +++ b/Classes/BITFeedbackListViewController.m @@ -192,8 +192,8 @@ - (void)viewDidAppear:(BOOL)animated { if ([self.manager numberOfMessages] == 0 && [self.manager askManualUserDataAvailable] && - ([self.manager requireManualUserDataMissing] || - ![self.manager didAskUserData]) + [self.manager requireManualUserDataMissing] && + ![self.manager didAskUserData] ) { self.userDataComposeFlow = YES; From 92cb2d6dcf467e8dfdcee54983a13c6aac047f56 Mon Sep 17 00:00:00 2001 From: Andreas Linde Date: Fri, 18 Jan 2013 23:44:10 +0100 Subject: [PATCH 153/176] Show proper missing name or email in the feedback list view button instead of "(null)" string --- Classes/BITFeedbackListViewController.m | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Classes/BITFeedbackListViewController.m b/Classes/BITFeedbackListViewController.m index 5f3b70cf..78830dd0 100644 --- a/Classes/BITFeedbackListViewController.m +++ b/Classes/BITFeedbackListViewController.m @@ -437,11 +437,11 @@ - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(N if ([self.manager requireUserName] == BITFeedbackUserDataElementRequired || ([self.manager requireUserName] == BITFeedbackUserDataElementOptional && [self.manager userName] != nil) ) { - title = [NSString stringWithFormat:BITHockeyLocalizedString(@"HockeyFeedbackListButonUserDataWithName"), [self.manager userName]]; + title = [NSString stringWithFormat:BITHockeyLocalizedString(@"HockeyFeedbackListButonUserDataWithName"), [self.manager userName] ?: @"-"]; } else if ([self.manager requireUserEmail] == BITFeedbackUserDataElementRequired || ([self.manager requireUserEmail] == BITFeedbackUserDataElementOptional && [self.manager userEmail] != nil) ) { - title = [NSString stringWithFormat:BITHockeyLocalizedString(@"HockeyFeedbackListButonUserDataWithEmail"), [self.manager userEmail]]; + title = [NSString stringWithFormat:BITHockeyLocalizedString(@"HockeyFeedbackListButonUserDataWithEmail"), [self.manager userEmail] ?: @"-"]; } else if ([self.manager requireUserName] == BITFeedbackUserDataElementOptional) { title = BITHockeyLocalizedString(@"HockeyFeedbackListButonUserDataSetName"); } else { From a0633d68cd3ab16a78c40214305775f100308203 Mon Sep 17 00:00:00 2001 From: Andreas Linde Date: Fri, 18 Jan 2013 23:54:11 +0100 Subject: [PATCH 154/176] Weak linking UIKit is not needed any more --- Support/HockeySDK.xcconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Support/HockeySDK.xcconfig b/Support/HockeySDK.xcconfig index 395516fe..64886740 100644 --- a/Support/HockeySDK.xcconfig +++ b/Support/HockeySDK.xcconfig @@ -1,3 +1,3 @@ -OTHER_LDFLAGS=$(inherited) -framework CoreText -framework CoreGraphics -framework Foundation -framework QuartzCore -framework SystemConfiguration -weak_framework UIKit +OTHER_LDFLAGS=$(inherited) -framework CoreText -framework CoreGraphics -framework Foundation -framework QuartzCore -framework SystemConfiguration -framework UIKit HOCKEYSDK_DOCSET_NAME=HockeySDK-iOS GCC_PREPROCESSOR_DEFINITIONS=$(inherited) CONFIGURATION_$(CONFIGURATION) \ No newline at end of file From 20b078e7f641ae4d97a8c45dd5af19f4ccff470f Mon Sep 17 00:00:00 2001 From: Andreas Linde Date: Fri, 18 Jan 2013 23:54:25 +0100 Subject: [PATCH 155/176] Some documentation updates for the setup process --- docs/Guide-Installation-Setup-Advanced-template.md | 4 +++- docs/Guide-Installation-Setup-template.md | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/docs/Guide-Installation-Setup-Advanced-template.md b/docs/Guide-Installation-Setup-Advanced-template.md index 8b2f59b3..d17ebc2d 100644 --- a/docs/Guide-Installation-Setup-Advanced-template.md +++ b/docs/Guide-Installation-Setup-Advanced-template.md @@ -70,6 +70,8 @@ If you need support for iOS 3.x, please check out [HockeyKit](http://support.hoc 14. Create a new `Project.xcconfig` file, if you don't already have one (You can give it any name) + **Note:** You can also add the required frameworks manually to your targets `Build Phases` an continue with step `17.` instead. + a. Select your project. b. Select the tab `Info`. @@ -140,7 +142,7 @@ If you only want crash reporting, you can skip this step. If you want to use Hoc return nil; } -The method only returns the UDID when the build is not targeted to the App Sore. This assumes that a preprocessor macro name CONFIGURATION_AppStore exists and is set for App Store builds. The macros are already defined in `HockeySDK.xcconfig`. +The method only returns the UDID when the build is not targeted to the App Sore. This assumes that a preprocessor macro name CONFIGURATION_AppStore exists and is set for App Store builds. The macros are already defined in `HockeySDK.xcconfig` or can be set manually by setting `GCC_PREPROCESSOR_DEFINITIONS` in your build configurations to `CONFIGURATION_$(CONFIGURATION)`. ## Mac Desktop Uploader diff --git a/docs/Guide-Installation-Setup-template.md b/docs/Guide-Installation-Setup-template.md index 2e7c19c7..6671015f 100644 --- a/docs/Guide-Installation-Setup-template.md +++ b/docs/Guide-Installation-Setup-template.md @@ -53,6 +53,8 @@ If you need support for iOS 3.x, please check out [HockeyKit](http://support.hoc 8. Select `HockeySDK.xcconfig` for all your configurations (if you don't already use a `.xcconfig` file) + + **Note:** You can also add the required frameworks manually to your targets `Build Phases` an continue with step `10.` instead. 9. If you are already using a `.xcconfig` file, simply add the following line to it @@ -112,7 +114,7 @@ If you only want crash reporting, you can skip this step. If you want to use Hoc return nil; } -The method only returns the UDID when the build is not targeted to the App Sore. This assumes that a preprocessor macro name CONFIGURATION_AppStore exists and is set for App Store builds. The macros are already defined in `HockeySDK.xcconfig`. +The method only returns the UDID when the build is not targeted to the App Sore. This assumes that a preprocessor macro name CONFIGURATION_AppStore exists and is set for App Store builds. The macros are already defined in `HockeySDK.xcconfig` or can be set manually by setting `GCC_PREPROCESSOR_DEFINITIONS` in your build configurations to `CONFIGURATION_$(CONFIGURATION)`. ## Mac Desktop Uploader From bba439df789a52b137090beee3111dd811ab64b9 Mon Sep 17 00:00:00 2001 From: Andreas Linde Date: Sat, 19 Jan 2013 00:48:18 +0100 Subject: [PATCH 156/176] Some more class documentation improvements --- Classes/BITFeedbackManager.h | 10 ++++++++++ Classes/BITHockeyManager.h | 9 +++++++-- 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/Classes/BITFeedbackManager.h b/Classes/BITFeedbackManager.h index dd59cd86..1bda3dfc 100644 --- a/Classes/BITFeedbackManager.h +++ b/Classes/BITFeedbackManager.h @@ -110,7 +110,12 @@ typedef enum { The default value is `BITFeedbackUserDataElementOptional`. + @warning If you provide a non nil value for the `BITFeedbackManager` class via + `[BITHockeyManagerDelegate userNameForHockeyManager:componentManager:]` then this + property will automatically be set to `BITFeedbackUserDataElementDontShow` + @see requireUserEmail + @see `[BITHockeyManagerDelegate userNameForHockeyManager:componentManager:]` */ @property (nonatomic, readwrite) BITFeedbackUserDataElement requireUserName; @@ -127,7 +132,12 @@ typedef enum { The default value is `BITFeedbackUserDataElementOptional`. + @warning If you provide a non nil value for the `BITFeedbackManager` class via + `[BITHockeyManagerDelegate userEmailForHockeyManager:componentManager:]` then this + property will automatically be set to `BITFeedbackUserDataElementDontShow` + @see requireUserName + @see `[BITHockeyManagerDelegate userEmailForHockeyManager:componentManager:]` */ @property (nonatomic, readwrite) BITFeedbackUserDataElement requireUserEmail; diff --git a/Classes/BITHockeyManager.h b/Classes/BITHockeyManager.h index 28942597..a37bb044 100644 --- a/Classes/BITHockeyManager.h +++ b/Classes/BITHockeyManager.h @@ -44,8 +44,11 @@ This is the principal SDK class. It represents the entry point for the HockeySDK. The main promises of the class are initializing the SDK modules, providing access to global properties and to all modules. Initialization is divided into several distinct phases: 1. Setup the [HockeyApp](http://hockeyapp.net/) app identifier and the optional delegate: This is the least required information on setting up the SDK and using it. It does some simple validation of the app identifier and checks if the app is running from the App Store or not. If the [Atlassian JMC framework](http://www.atlassian.com/jmc/) is found, it will disable its Crash Reporting module and configure it with the Jira configuration data from [HockeyApp](http://hockeyapp.net/). - 2. Provides access to the SDK modules `BITCrashManager` and `BITUpdateManager`. This way all modules can be further configured to personal needs, if the defaults don't fit the requirements. - 3. Start up all modules. + 2. Provides access to the SDK modules `BITCrashManager`, `BITUpdateManager`, and `BITFeedbackManager`. This way all modules can be further configured to personal needs, if the defaults don't fit the requirements. + 3. Configure each module. + 4. Start up all modules. + + @warning You should **NOT** change any module configuration after calling `startManager`! Example: [[BITHockeyManager sharedHockeyManager] @@ -104,6 +107,7 @@ @see BITHockeyManagerDelegate @see BITCrashManagerDelegate @see BITUpdateManagerDelegate + @see BITFeedbackManagerDelegate @param appIdentifier The app identifier that should be used. @param delegate `nil` or the class implementing the option protocols */ @@ -138,6 +142,7 @@ @see BITHockeyManagerDelegate @see BITCrashManagerDelegate @see BITUpdateManagerDelegate + @see BITFeedbackManagerDelegate @param betaIdentifier The app identifier for the _non_ app store (beta) configurations @param liveIdentifier The app identifier for the app store configurations. @param delegate `nil` or the class implementing the optional protocols From 7f935df4c5f5fe7518445b8de93749a23c70b32a Mon Sep 17 00:00:00 2001 From: Andreas Linde Date: Sat, 19 Jan 2013 01:17:00 +0100 Subject: [PATCH 157/176] Add a note to the advanced setup documentation what can be found in which branch --- docs/Guide-Installation-Setup-Advanced-template.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/Guide-Installation-Setup-Advanced-template.md b/docs/Guide-Installation-Setup-Advanced-template.md index d17ebc2d..3d54fa35 100644 --- a/docs/Guide-Installation-Setup-Advanced-template.md +++ b/docs/Guide-Installation-Setup-Advanced-template.md @@ -33,6 +33,8 @@ If you need support for iOS 3.x, please check out [HockeyKit](http://support.hoc 4. Add the submodule: `git submodule add git://github.com/BitStadium/HockeySDK-iOS.git Vendor/HockeySDK`. This would add the submodule into the `Vendor/HockeySDK` subfolder. Change this to the folder you prefer. +5. Releases are always in the `master` branch while the `develop` branch provides the latest in development source code (Using the git flow branching concept). We recommend using the `master` branch! + ## Set up Xcode From 2c7728bcb7e09fad6024de49e505e460b4c00ccd Mon Sep 17 00:00:00 2001 From: Peter Steinberger Date: Sun, 20 Jan 2013 15:26:08 +0500 Subject: [PATCH 158/176] Fixes "variable name is shadowed" warnings --- Classes/BITAttributedLabel.m | 4 ++-- Classes/BITFeedbackManager.m | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Classes/BITAttributedLabel.m b/Classes/BITAttributedLabel.m index 31e5f417..87d8ba62 100755 --- a/Classes/BITAttributedLabel.m +++ b/Classes/BITAttributedLabel.m @@ -587,8 +587,8 @@ - (void)drawBackground:(CTFrameRef)frame inRect:(CGRect)rect context:(CGContextR runBounds.size.width = CGRectGetWidth(lineBounds); } - CGRect rect = CGRectInset(CGRectInset(runBounds, -1.0f, -3.0f), lineWidth, lineWidth); - CGPathRef path = [[UIBezierPath bezierPathWithRoundedRect:rect cornerRadius:cornerRadius] CGPath]; + CGRect newRect = CGRectInset(CGRectInset(runBounds, -1.0f, -3.0f), lineWidth, lineWidth); + CGPathRef path = [[UIBezierPath bezierPathWithRoundedRect:newRect cornerRadius:cornerRadius] CGPath]; CGContextSetLineJoin(c, kCGLineJoinRound); diff --git a/Classes/BITFeedbackManager.m b/Classes/BITFeedbackManager.m index f76b65a0..76a4345b 100644 --- a/Classes/BITFeedbackManager.m +++ b/Classes/BITFeedbackManager.m @@ -610,13 +610,13 @@ - (void)updateMessageListFromResponse:(NSDictionary *)jsonDictionary { // TODO: match messages in state conflict - [messagesSendInProgress enumerateObjectsUsingBlock:^(id objSendInProgressMessage, NSUInteger messagesSendInProgressIdx, BOOL *stop) { + [messagesSendInProgress enumerateObjectsUsingBlock:^(id objSendInProgressMessage, NSUInteger messagesSendInProgressIdx, BOOL *stop2) { if ([[(NSDictionary *)objMessage objectForKey:@"token"] isEqualToString:[(BITFeedbackMessage *)objSendInProgressMessage token]]) { matchingSendInProgressOrInConflictMessage = objSendInProgressMessage; - *stop = YES; + *stop2 = YES; } }]; - + if (matchingSendInProgressOrInConflictMessage) { matchingSendInProgressOrInConflictMessage.date = [self parseRFC3339Date:[(NSDictionary *)objMessage objectForKey:@"created_at"]]; matchingSendInProgressOrInConflictMessage.id = messageID; From e1d6515b2a9a6d631596f29ecff52e1ceb6690cd Mon Sep 17 00:00:00 2001 From: Peter Steinberger Date: Sun, 20 Jan 2013 15:25:52 +0500 Subject: [PATCH 159/176] Fixes several typos. --- Classes/BITAttributedLabel.h | 8 ++++---- Classes/BITCrashManager.h | 2 +- Classes/BITFeedbackManager.m | 2 +- Classes/BITHockeyManager.h | 6 +++--- Classes/BITUpdateManager.m | 4 ++-- Classes/BITUpdateManagerPrivate.h | 2 +- 6 files changed, 12 insertions(+), 12 deletions(-) diff --git a/Classes/BITAttributedLabel.h b/Classes/BITAttributedLabel.h index 3481bd9e..d84caec8 100755 --- a/Classes/BITAttributedLabel.h +++ b/Classes/BITAttributedLabel.h @@ -111,7 +111,7 @@ extern NSString * const kBITBackgroundCornerRadiusAttributeName; /** A dictionary containing the `NSAttributedString` attributes to be applied to links detected or manually added to the label text. The default link style is blue and underlined. - @warning You must specify `linkAttributes` before setting autodecting or manually-adding links for these attributes to be applied. + @warning You must specify `linkAttributes` before setting autodetecting or manually-adding links for these attributes to be applied. */ @property (nonatomic, strong) NSDictionary *linkAttributes; @@ -121,7 +121,7 @@ extern NSString * const kBITBackgroundCornerRadiusAttributeName; @property (nonatomic, strong) NSDictionary *activeLinkAttributes; ///--------------------------------------- -/// @name Acccessing Text Style Attributes +/// @name Accessing Text Style Attributes ///--------------------------------------- /** @@ -130,7 +130,7 @@ extern NSString * const kBITBackgroundCornerRadiusAttributeName; @property (nonatomic, assign) CGFloat shadowRadius; ///-------------------------------------------- -/// @name Acccessing Paragraph Style Attributes +/// @name Accessing Paragraph Style Attributes ///-------------------------------------------- /** @@ -303,7 +303,7 @@ extern NSString * const kBITBackgroundCornerRadiusAttributeName; Tells the delegate that the user did select a link to a date. @param label The label whose link was selected. - @param date The datefor the selected link. + @param date The date for the selected link. */ - (void)attributedLabel:(BITAttributedLabel *)label didSelectLinkWithDate:(NSDate *)date; diff --git a/Classes/BITCrashManager.h b/Classes/BITCrashManager.h index 66d91836..f2fe77d8 100644 --- a/Classes/BITCrashManager.h +++ b/Classes/BITCrashManager.h @@ -61,7 +61,7 @@ extern NSString *const kBITCrashManagerStatus; Crashes are send the next time the app starts. If `crashManagerStatus` is set to `BITCrashManagerStatusAutoSend`, crashes will be send without any user interaction, otherwise an alert will appear allowing the users to decide - wether they want to send the report or not. This module is not sending the reports right when the crash happens + whether they want to send the report or not. This module is not sending the reports right when the crash happens deliberately, because if is not safe to implement such a mechanism while being async-safe (any Objective-C code is _NOT_ async-safe!) and not causing more danger like a deadlock of the device, than helping. We found that users do start the app again because most don't know what happened, and you will get by far most of the reports. diff --git a/Classes/BITFeedbackManager.m b/Classes/BITFeedbackManager.m index 76a4345b..24d35d4e 100644 --- a/Classes/BITFeedbackManager.m +++ b/Classes/BITFeedbackManager.m @@ -903,7 +903,7 @@ - (void)submitMessageWithText:(NSString *)text { #pragma mark - UIAlertViewDelegate -// invoke the selected action from the actionsheet for a location element +// invoke the selected action from the action sheet for a location element - (void)alertView:(UIAlertView *)alertView didDismissWithButtonIndex:(NSInteger)buttonIndex { _incomingMessagesAlertShowing = NO; diff --git a/Classes/BITHockeyManager.h b/Classes/BITHockeyManager.h index a37bb044..e2f69f85 100644 --- a/Classes/BITHockeyManager.h +++ b/Classes/BITHockeyManager.h @@ -190,7 +190,7 @@ /** - Flag the determines wether the Crash Manager should be disabled + Flag the determines whether the Crash Manager should be disabled If this flag is enabled, then crash reporting is disabled and no crashes will be send. @@ -216,7 +216,7 @@ /** - Flag the determines wether the Update Manager should be disabled + Flag the determines whether the Update Manager should be disabled If this flag is enabled, then checking for updates and submitting beta usage analytics will be turned off! @@ -242,7 +242,7 @@ /** - Flag the determines wether the Feedback Manager should be disabled + Flag the determines whether the Feedback Manager should be disabled If this flag is enabled, then letting the user give feedback and get responses will be turned off! diff --git a/Classes/BITUpdateManager.m b/Classes/BITUpdateManager.m index 5557ab11..e2b69d5d 100644 --- a/Classes/BITUpdateManager.m +++ b/Classes/BITUpdateManager.m @@ -731,7 +731,7 @@ - (BOOL)initiateAppDownload { } -// checks wether this app version is authorized +// checks whether this app version is authorized - (BOOL)appVersionIsAuthorized { if (self.requireAuthorization && !_authenticationSecret) { [self reportError:[NSError errorWithDomain:kBITUpdateErrorDomain @@ -999,7 +999,7 @@ - (void)setBlockingView:(UIView *)anBlockingView { #pragma mark - UIAlertViewDelegate -// invoke the selected action from the actionsheet for a location element +// invoke the selected action from the action sheet for a location element - (void)alertView:(UIAlertView *)alertView didDismissWithButtonIndex:(NSInteger)buttonIndex { if ([alertView tag] == 2) { (void)[self initiateAppDownload]; diff --git a/Classes/BITUpdateManagerPrivate.h b/Classes/BITUpdateManagerPrivate.h index 00e545f2..dd6dc98a 100644 --- a/Classes/BITUpdateManagerPrivate.h +++ b/Classes/BITUpdateManagerPrivate.h @@ -72,7 +72,7 @@ // initiates app-download call. displays an system UIAlertView - (BOOL)initiateAppDownload; -// checks wether this app version is authorized +// checks whether this app version is authorized - (BOOL)appVersionIsAuthorized; // start checking for an authorization key From ef25b216953b5dd524d615abd1f5ebdd6dc132dd Mon Sep 17 00:00:00 2001 From: Andreas Linde Date: Mon, 21 Jan 2013 20:42:38 +0100 Subject: [PATCH 160/176] Bump version to 3.0.0RC1 Build 16 --- README.md | 163 ++---------------- Support/buildnumber.xcconfig | 6 +- docs/Changelog-template.md | 43 ++++- ...de-Installation-Setup-Advanced-template.md | 7 +- docs/Guide-Installation-Setup-template.md | 5 +- docs/index.md | 15 +- 6 files changed, 79 insertions(+), 160 deletions(-) diff --git a/README.md b/README.md index 46f24498..8a2870ec 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,8 @@ +## Version 3.0.0 RC1 + +- [Changelog](http://www.hockeyapp.net/help/sdk/ios/3.0.0RC1/docs/docs/Changelog.html) + + ## Introduction HockeySDK-iOS implements support for using HockeyApp in your iOS applications. @@ -8,20 +13,22 @@ The following features are currently supported: 2. **Collect crash reports:** If you app crashes, a crash log with the same format as from the Apple Crash Reporter is written to the device's storage. If the user starts the app again, he is asked to submit the crash report to HockeyApp. This works for both beta and live apps, i.e. those submitted to the App Store! +3. **Feedback:** Collect feedback from your users from within your app and communicate directly with them using the HockeyApp backend. + The main SDK class is `BITHockeyManager`. It initializes all modules and provides access to them, so they can be further adjusted if required. Additionally all modules provide their own protocols. ## Prerequisites 1. Before you integrate HockeySDK into your own app, you should add the app to HockeyApp if you haven't already. Read [this how-to](http://support.hockeyapp.net/kb/how-tos/how-to-create-a-new-app) on how to do it. 2. We also assume that you already have a project in Xcode and that this project is opened in Xcode 4. -3. The SDK supports iOS 4.0 or newer. +3. The SDK supports iOS 5.0 or newer. ## Installation & Setup -- [Installation & Setup](http://support.hockeyapp.net/kb/client-integration/hockeyapp-for-ios-hockeysdk) (Recommended) -- [Installation & Setup Advanced](http://support.hockeyapp.net/kb/client-integration/hockeyapp-for-ios-hockeysdk-advanced) (Using Git submodule and Xcode sub-project) -- [Migration from HockeyKit & QuincyKit](http://support.hockeyapp.net/kb/client-integration/migrate-from-hockeykit-quincykit-to-hockeysdk-for-ios) +- [Installation & Setup](http://www.hockeyapp.net/help/sdk/ios/3.0.0RC1/docs/docs/Guide-Installation-Setup.html) (Recommended) +- [Installation & Setup Advanced](http://www.hockeyapp.net/help/sdk/ios/3.0.0RC1/docs/docs/Guide-Installation-Setup-Advanced.html) (Using Git submodule and Xcode sub-project) +- [Migration from HockeyKit & QuincyKit](http://www.hockeyapp.net/help/sdk/ios/3.0.0RC1/docs/docs/Guide-Migration-Kits.html) - [Mac Desktop Uploader](http://support.hockeyapp.net/kb/how-tos/how-to-upload-to-hockeyapp-on-a-mac) @@ -29,154 +36,10 @@ The main SDK class is `BITHockeyManager`. It initializes all modules and provide This documentation provides integrated help in Xcode for all public APIs and a set of additional tutorials and HowTos. -1. Download the latest [HockeySDK-iOS documentation](https://github.com/bitstadium/HockeySDK-iOS/downloads). +1. Download the [HockeySDK-iOS documentation](http://hockeyapp.net/releases/). 2. Unzip the file. A new folder `HockeySDK-iOS-documentation` is created. 3. Copy the content into ~`/Library/Developer/Shared/Documentation/DocSet` - -## Changelog - -### Version 2.5.4 - -- General: - - - Declared as final release, since everything in 2.5.4b3 is working as expected - -### Version 2.5.4b3 - -- General: - - - [NEW] Atlassian JMC support disabled (Use subproject integration if you want it) - -### Version 2.5.4b2 - -- Crash Reporting: - - - [UPDATE] Migrate pre v2.5 auto send user setting - - [BUGFIX] The alert option 'Auto Send' did not persist correctly - -- Updating: - - - [BUGFIX] Authorization option did not persist correctly and caused authorization to re-appear on every cold app start - -### Version 2.5.4b1 - -- General: - - - [NEW] JMC support is removed from binary distribution, requires the compiler preprocessor definition `JIRA_MOBILE_CONNECT_SUPPORT_ENABLED=1` to be linked. Enabled when using the subproject - - [BUGFIX] Fix compiler warnings when using Cocoapods - -- Updating: - - - [BUGFIX] `expiryDate` property not working correctly - -### Version 2.5.3 - -- General: - - - [BUGFIX] Fix checking validity of live identifier not working correctly - -### Version 2.5.2 - -- General: - - - Declared as final release, since everything in 2.5.2b2 is working as expected - -### Version 2.5.2b2 - -- General: - - - [NEW] Added support for armv7s architecture - -- Updating: - - - [BUGFIX] Fix update checks not done when the app becomes active again - - -### Version 2.5.2b1 - -- General: - - - [NEW] Replace categories with C functions, so the `Other Linker Flag` `-ObjC` and `-all_load` won't not be needed for integration - - [BUGFIX] Some code style fixes and missing new lines in headers at EOF - -- Crash Reporting: - - - [NEW] PLCrashReporter framework now linked into the HockeySDK framework, so that won't be needed to be added separately any more - - [NEW] Add some error handler detection to optionally notify the developer of multiple handlers that could cause crashes not to be reported to HockeyApp - - [NEW] Show an error in the console if an older version of PLCrashReporter is linked - - [NEW] Make sure the app doesn't crash if the developer forgot to delete the old PLCrashReporter version and the framework search path is still pointing to it - -- Updating: - - - [BUGFIX] Fix disabling usage tracking and expiry check not working if `checkForUpdateOnLaunch` is set to NO - - [BUGFIX] `disableUpdateManager` wasn't working correctly - - [BUGFIX] If the server doesn't return any app versions, don't handle this as an error, but show a warning in the console when `debugLogging` is enabled - - -### Version 2.5.1 - -- General: - - - [BUGFIX] Typo in delegate `shouldUseLiveIdentifier` of `BITHockeyManagerDelegate` - - [BUGFIX] Default updateManager delegate wasn't set - -- Crash Reporting: - - - [BUGFIX] Crash when developer sends the notification `BITHockeyNetworkDidBecomeReachableNotification` - - -### Version 2.5.0 - -- General: - - - [NEW] Unified SDK for accessing HockeyApp on iOS - - - Requires iOS 4.0 or newer - - - Replaces the previous separate SDKs for iOS: HockeyKit and QuincyKit. - - The previous SDKs are still available and are still working. But future - HockeyApp features will only be integrated in this new unified SDK. - - - Integration either as framework or Xcode subproject using the sourcecode - - Check out [Installation & Setup](Guide-Installation-Setup) - - - [NEW] Cleaned up public interfaces and internal processing all across the SDK - - - [NEW] [AppleDoc](http://gentlebytes.com/appledoc/) based documentation and HowTos - - This allows the documentation to be generated into HTML or DocSet. - -- Crash Reporting: - - - [NEW] Workflow to handle crashes that happen on startup. - - Check out [How to handle crashes on startup](HowTo-Handle-Crashes-On-Startup) for more details. - - - [NEW] Symbolicate iOS calls async-safe on the device - - - [NEW] Single property/option to deactivate, require user to agree submitting and autosubmit - - E.g. implement a settings screen with the three options and set - `[BITCrashManager crashManagerStatus]` to the desired user value. - - - [UPDATED] Updated [PLCrashReporter](https://code.google.com/p/plcrashreporter/) with updates and bugfixes (source available on [GitHub](https://github.com/bitstadium/PLCrashReporter)) - - - [REMOVED] Feedback for Crash Groups Status - - Please keep using QuincyKit for now if you want this feature. This feature needs to be - redesigned on SDK and server side to be more efficient and easier to use. - -- Updating: - - - [NEW] Expire beta versions with a given date - - - [REMOVED] Settings screen - - If you want users to be able not to send analytics data, implement the - `[BITUpdateManagerDelegate updateManagerShouldSendUsageData:]` delegate and return - the value depending on what the user defines in your settings UI. +The documentation is also available via the following URL: [http://hockeyapp.net/help/sdk/ios/3.0.0RC1/](http://hockeyapp.net/help/sdk/ios/3.0.0RC1/) diff --git a/Support/buildnumber.xcconfig b/Support/buildnumber.xcconfig index d997159b..89aa7300 100644 --- a/Support/buildnumber.xcconfig +++ b/Support/buildnumber.xcconfig @@ -1,5 +1,5 @@ #include "HockeySDK.xcconfig" -BUILD_NUMBER = 15 -VERSION_STRING = 3.0.0b5 -GCC_PREPROCESSOR_DEFINITIONS = $(inherited) BITHOCKEY_VERSION="@\"3.0.0b5\"" +BUILD_NUMBER = 16 +VERSION_STRING = 3.0.0RC1 +GCC_PREPROCESSOR_DEFINITIONS = $(inherited) BITHOCKEY_VERSION="@\"3.0.0RC1\"" diff --git a/docs/Changelog-template.md b/docs/Changelog-template.md index 6ca736bf..b2ffd83a 100644 --- a/docs/Changelog-template.md +++ b/docs/Changelog-template.md @@ -1,3 +1,22 @@ +### Version 3.0.0 RC 1 + +- General: + + - [NEW] Added localizations provided by [Wordcrafts.de](http://wordcrafts.de): + Chinese, English, French, German, Italian, Japanese, Portuguese, Brazilian-Portuguese, Russian, Spanish + - [NEW] Added Romanian localization + - [UPDATE] Documentation improvements + - [UPDATE] Exclude binary UUID check from simulator builds, so unit test targets will work. But functionality based on binary UUID cannot be tested in the simulator, e.g. update without changing build version. + - [BUGFIX] Cocoapods bugfix for preprocessor definitions + - [BUGFIX] Various additional minor fixes + +- Feedback: + + - [UPDATE] Only push user details screen automatically onto the list view once + - [BUGFIX] Show proper missing user name or email instead of showing `(null)` in a button + - [BUGFIX] Various fixes to changing the `requireUserEmail` and `requireUserName` values + + ### Version 3.0.0b5 - General: @@ -81,7 +100,25 @@ - [UPDATE] Update UI shows the company name next to the app name if defined in the backend -### Version 2.5.4 +## Version 2.5.5 + +- General: + + - [BUGFIX] Fix some new compiler warnings + +- Crash Reporting: + + - [NEW] Add anonymous device ID to crash reports + - [BUGFIX] Move calculation of time interval between startup and crash further up in the code, so delegates can use this information e.g. to add it into a log file + - [BUGFIX] Call delegate also if a crash was detected but could not be read (if handling crashes on startup is implemented) + - [BUGFIX] Format timestamp in crash report to be always UTC in en_US locale + - [BUGFIX] Make sure crash reports incident identifier and key don't have special [] chars and some value + +- Updating: + + - [BUGFIX] Fix a problem showing the update UI animated if there TTNavigator class is present even though not being used + +## Version 2.5.4 - General: @@ -115,13 +152,13 @@ - [BUGFIX] `expiryDate` property not working correctly -### Version 2.5.3 +## Version 2.5.3 - General: - [BUGFIX] Fix checking validity of live identifier not working correctly -### Version 2.5.2 +## Version 2.5.2 - General: diff --git a/docs/Guide-Installation-Setup-Advanced-template.md b/docs/Guide-Installation-Setup-Advanced-template.md index 3d54fa35..328e538c 100644 --- a/docs/Guide-Installation-Setup-Advanced-template.md +++ b/docs/Guide-Installation-Setup-Advanced-template.md @@ -1,3 +1,6 @@ +## Version 3.0.0 RC1 + +- [Changelog](http://www.hockeyapp.net/help/sdk/ios/3.0.0RC1/docs/docs/Changelog.html) ## Introduction @@ -156,8 +159,10 @@ The Mac Desktop Uploader can provide easy uploading of your app versions to Hock This documentation provides integrated help in Xcode for all public APIs and a set of additional tutorials and HowTos. -1. Download the latest [HockeySDK-iOS documentation](https://github.com/bitstadium/HockeySDK-iOS/downloads). +1. Download the [HockeySDK-iOS documentation](http://hockeyapp.net/releases/). 2. Unzip the file. A new folder `HockeySDK-iOS-documentation` is created. 3. Copy the content into ~`/Library/Developer/Shared/Documentation/DocSet` + +The documentation is also available via the following URL: [http://hockeyapp.net/help/sdk/ios/3.0.0RC1/](http://hockeyapp.net/help/sdk/ios/3.0.0RC1/) diff --git a/docs/Guide-Installation-Setup-template.md b/docs/Guide-Installation-Setup-template.md index 6671015f..89b99321 100644 --- a/docs/Guide-Installation-Setup-template.md +++ b/docs/Guide-Installation-Setup-template.md @@ -1,3 +1,6 @@ +## Version 3.0.0 RC1 + +- [Changelog](http://www.hockeyapp.net/help/sdk/ios/3.0.0RC1/docs/docs/Changelog.html) ## Introduction @@ -126,4 +129,4 @@ The Mac Desktop Uploader can provide easy uploading of your app versions to Hock This documentation provides integrated help in Xcode for all public APIs and a set of additional tutorials and HowTos. -1. Copy `de.bitstadium.HockeySDK-iOS-3.0.0b5.docset` into ~`/Library/Developer/Shared/Documentation/DocSet` +1. Copy `de.bitstadium.HockeySDK-iOS-3.0.0RC1.docset` into ~`/Library/Developer/Shared/Documentation/DocSet` diff --git a/docs/index.md b/docs/index.md index 05551a90..d243fb09 100644 --- a/docs/index.md +++ b/docs/index.md @@ -8,13 +8,15 @@ The following features are currently supported: 2. **Collect crash reports:** If you app crashes, a crash log with the same format as from the Apple Crash Reporter is written to the device's storage. If the user starts the app again, he is asked to submit the crash report to HockeyApp. This works for both beta and live apps, i.e. those submitted to the App Store! +3. **Feedback:** Collect feedback from your users from within your app and communicate directly with them using the HockeyApp backend. + The main SDK class is `BITHockeyManager`. It initializes all modules and provides access to them, so they can be further adjusted if required. Additionally all modules provide their own protocols. ## Prerequisites 1. Before you integrate HockeySDK into your own app, you should add the app to HockeyApp if you haven't already. Read [this how-to](http://support.hockeyapp.net/kb/how-tos/how-to-create-a-new-app) on how to do it. 2. We also assume that you already have a project in Xcode and that this project is opened in Xcode 4. -3. The SDK supports iOS 4.0 or newer. +3. The SDK supports iOS 5.0 or newer. ## Release Notes @@ -35,8 +37,17 @@ The main SDK class is `BITHockeyManager`. It initializes all modules and provide - [How to add application specific log data](HowTo-Add-Application-Log) - [How to integrate Atlassian JMC](HowTo-Integrate-Atlassian-JMC) - ## Troubleshooting - [Symbolication doesn't work](Symbolication-Doesnt-Work) (Or the rules of binary UUIDs and dSYMs) - [Crash Reporting is not working](Troubleshooting-Crash-Reporting-Not-Working) + +## Xcode Documentation + +This documentation provides integrated help in Xcode for all public APIs and a set of additional tutorials and HowTos. + +1. Download the [HockeySDK-iOS documentation](http://hockeyapp.net/releases/). + +2. Unzip the file. A new folder `HockeySDK-iOS-documentation` is created. + +3. Copy the content into ~`/Library/Developer/Shared/Documentation/DocSet` From ddb8b69ada676a468d2628e81586fe6bdd104aed Mon Sep 17 00:00:00 2001 From: Andreas Linde Date: Mon, 28 Jan 2013 18:36:53 +0100 Subject: [PATCH 161/176] Small documentation improvements --- Classes/BITHockeyManager.h | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/Classes/BITHockeyManager.h b/Classes/BITHockeyManager.h index e2f69f85..7c5778c3 100644 --- a/Classes/BITHockeyManager.h +++ b/Classes/BITHockeyManager.h @@ -179,12 +179,13 @@ /** Reference to the initialized BITCrashManager module + + Returns the BITCrashManager instance initialized by BITHockeyManager @see configureWithIdentifier:delegate: @see configureWithBetaIdentifier:liveIdentifier:delegate: @see startManager @see disableCrashManager - @return The BITCrashManager instance initialized by BITHockeyManager */ @property (nonatomic, strong, readonly) BITCrashManager *crashManager; @@ -206,11 +207,12 @@ /** Reference to the initialized BITUpdateManager module + Returns the BITUpdateManager instance initialized by BITHockeyManager + @see configureWithIdentifier:delegate: @see configureWithBetaIdentifier:liveIdentifier:delegate: @see startManager @see disableUpdateManager - @return The BITUpdateManager instance initialized by BITHockeyManager */ @property (nonatomic, strong, readonly) BITUpdateManager *updateManager; @@ -232,11 +234,12 @@ /** Reference to the initialized BITFeedbackManager module + Returns the BITFeedbackManager instance initialized by BITHockeyManager + @see configureWithIdentifier:delegate: @see configureWithBetaIdentifier:liveIdentifier:delegate: @see startManager @see disableFeedbackManager - @return The BITFeedbackManager instance initialized by BITHockeyManager */ @property (nonatomic, strong, readonly) BITFeedbackManager *feedbackManager; @@ -263,8 +266,8 @@ Flag that determines whether the application is installed and running from an App Store installation. - @return YES if the app is installed and running from the App Store - @return NO if the app is installed via debug, ad-hoc or enterprise distribution + Returns _YES_ if the app is installed and running from the App Store + Returns _NO_ if the app is installed via debug, ad-hoc or enterprise distribution */ @property (nonatomic, readonly, getter=isAppStoreEnvironment) BOOL appStoreEnvironment; From 1e053cf91e6d3a62df1d3e24ffbeba9fefa2f242 Mon Sep 17 00:00:00 2001 From: Andreas Linde Date: Mon, 28 Jan 2013 18:37:26 +0100 Subject: [PATCH 162/176] Mark deprecated delegates as deprecated And not only mention it in the documentation --- Classes/BITCrashManagerDelegate.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Classes/BITCrashManagerDelegate.h b/Classes/BITCrashManagerDelegate.h index 16bb2e58..fb3e88f5 100644 --- a/Classes/BITCrashManagerDelegate.h +++ b/Classes/BITCrashManagerDelegate.h @@ -63,7 +63,7 @@ @warning When returning a non nil value, crash reports are not anonymous any more and the alerts will not show the "anonymous" word! */ --(NSString *)userNameForCrashManager:(BITCrashManager *)crashManager; +-(NSString *)userNameForCrashManager:(BITCrashManager *)crashManager DEPRECATED_ATTRIBUTE; @@ -76,7 +76,7 @@ @warning When returning a non nil value, crash reports are not anonymous any more and the alerts will not show the "anonymous" word! */ --(NSString *)userEmailForCrashManager:(BITCrashManager *)crashManager; +-(NSString *)userEmailForCrashManager:(BITCrashManager *)crashManager DEPRECATED_ATTRIBUTE; From 764222995141df6c4445dff9d3bced1c07cf8365 Mon Sep 17 00:00:00 2001 From: Skylar Schipper Date: Mon, 28 Jan 2013 16:06:51 -0800 Subject: [PATCH 163/176] Added `__attribute__((unused))` to a few properties to suppress unused warning in external variable definitions in Xcode 4.6 --- Classes/HockeySDK.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Classes/HockeySDK.h b/Classes/HockeySDK.h index c7e6c449..fb660145 100644 --- a/Classes/HockeySDK.h +++ b/Classes/HockeySDK.h @@ -58,7 +58,7 @@ typedef enum { BITCrashAPIReceivedEmptyResponse, BITCrashAPIErrorWithStatusCode } BITCrashErrorReason; -extern NSString *const kBITCrashErrorDomain; +extern NSString *const __attribute__((unused)) kBITCrashErrorDomain; // Update App Versions @@ -71,7 +71,7 @@ typedef enum { BITUpdateAPIClientAuthorizationMissingSecret, BITUpdateAPIClientCannotCreateConnection } BITUpdateErrorReason; -extern NSString *const kBITUpdateErrorDomain; +extern NSString *const __attribute__((unused)) kBITUpdateErrorDomain; // Update App Versions @@ -85,7 +85,7 @@ typedef enum { BITFeedbackAPIClientAuthorizationMissingSecret, BITFeedbackAPIClientCannotCreateConnection } BITFeedbackErrorReason; -extern NSString *const kBITFeedbackErrorDomain; +extern NSString *const __attribute__((unused)) kBITFeedbackErrorDomain; // HockeySDK @@ -95,7 +95,7 @@ typedef enum { BITHockeyErrorUnknown, HockeyAPIClientMissingJSONLibrary } BITHockeyErrorReason; -extern NSString *const kBITHockeyErrorDomain; +extern NSString *const __attribute__((unused)) kBITHockeyErrorDomain; #endif From 14e63a75ce2f85654c6d4fc1a4cff3ff64230c62 Mon Sep 17 00:00:00 2001 From: Kevin Smith Date: Fri, 1 Feb 2013 11:20:38 -0800 Subject: [PATCH 164/176] Ignore any build folder Before build folders under Support wouldn't get ignored. --- .gitignore | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.gitignore b/.gitignore index d0f3b76e..ebc78fd0 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,5 @@ # Xcode -build/* +build *.pbxuser !default.pbxuser *.mode?v3 @@ -20,4 +20,4 @@ profile profile documentation/ -Products/ \ No newline at end of file +Products/ From 3e18ac13b3ba02e633eba4ba5bc8549743c4e939 Mon Sep 17 00:00:00 2001 From: Andreas Linde Date: Thu, 7 Feb 2013 14:58:39 +0100 Subject: [PATCH 165/176] Fix some issues with building documentation - Add a redirect html page to docs so generated HTML output pages always work - Ignore Products directory, otherwise appledoc will use that content too and double process lots of header files --- Support/HockeySDK.xcodeproj/project.pbxproj | 2 +- docs/index.html | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) create mode 100644 docs/index.html diff --git a/Support/HockeySDK.xcodeproj/project.pbxproj b/Support/HockeySDK.xcodeproj/project.pbxproj index 6dd9c593..a61274b0 100644 --- a/Support/HockeySDK.xcodeproj/project.pbxproj +++ b/Support/HockeySDK.xcodeproj/project.pbxproj @@ -604,7 +604,7 @@ ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "/usr/local/bin/appledoc \\\n --output \"${SOURCE_ROOT}/../documentation\" \\\n --ignore Vendor \\\n --ignore .m \\\n --create-html \\\n --create-docset \\\n --install-docset \\\n --keep-intermediate-files \\\n --project-name \"${HOCKEYSDK_DOCSET_NAME} ${VERSION_STRING}\" \\\n --project-version \"${VERSION_STRING}\" \\\n --project-company \"BitStadium GmbH\" \\\n --company-id \"de.bitstadium\" \\\n --docset-bundle-name \"${HOCKEYSDK_DOCSET_NAME} ${VERSION_STRING}\" \\\n --docset-feed-name \"${HOCKEYSDK_DOCSET_NAME}\" \\\n --docset-platform-family \"iphoneos\" \\\n --index-desc \"${SOURCE_ROOT}/../docs/index.md\" \\\n --include \"${SOURCE_ROOT}/../docs/\" \\\n --merge-categories \\\n --no-repeat-first-par \\\n --warn-undocumented-object \\\n --warn-undocumented-member \\\n --warn-empty-description \\\n --warn-unknown-directive \\\n --warn-invalid-crossref \\\n --warn-missing-arg \\\n --logformat xcode \\\n --exit-threshold 2 \\\n \"${SOURCE_ROOT}/../\" \\\n"; + shellScript = "/usr/local/bin/appledoc \\\n --output \"${SOURCE_ROOT}/../documentation\" \\\n --ignore Vendor \\\n --ignore Products \\\n --ignore .m \\\n --create-html \\\n --create-docset \\\n --install-docset \\\n --keep-intermediate-files \\\n --project-name \"${HOCKEYSDK_DOCSET_NAME} ${VERSION_STRING}\" \\\n --project-version \"${VERSION_STRING}\" \\\n --project-company \"BitStadium GmbH\" \\\n --company-id \"de.bitstadium\" \\\n --docset-bundle-name \"${HOCKEYSDK_DOCSET_NAME} ${VERSION_STRING}\" \\\n --docset-feed-name \"${HOCKEYSDK_DOCSET_NAME}\" \\\n --docset-desc \"\" \\\n --docset-platform-family \"iphoneos\" \\\n --index-desc \"${SOURCE_ROOT}/../docs/index.md\" \\\n --include \"${SOURCE_ROOT}/../docs/index.html\" \\\n --include \"${SOURCE_ROOT}/../docs/\" \\\n --merge-categories \\\n --no-repeat-first-par \\\n --warn-undocumented-object \\\n --warn-undocumented-member \\\n --warn-empty-description \\\n --warn-unknown-directive \\\n --warn-invalid-crossref \\\n --warn-missing-arg \\\n --logformat xcode \\\n --exit-threshold 2 \\\n \"${SOURCE_ROOT}/../\"\n"; }; /* End PBXShellScriptBuildPhase section */ diff --git a/docs/index.html b/docs/index.html new file mode 100644 index 00000000..e961280e --- /dev/null +++ b/docs/index.html @@ -0,0 +1,3 @@ + + + From e5f58960ac902457cafd56b13d55b2a8f2fdd014 Mon Sep 17 00:00:00 2001 From: Andreas Linde Date: Thu, 7 Feb 2013 14:59:15 +0100 Subject: [PATCH 166/176] Some more documentation improvements --- Classes/BITCrashManager.h | 3 +++ Classes/BITHockeyManager.h | 7 +++++++ 2 files changed, 10 insertions(+) diff --git a/Classes/BITCrashManager.h b/Classes/BITCrashManager.h index f2fe77d8..dc9f2907 100644 --- a/Classes/BITCrashManager.h +++ b/Classes/BITCrashManager.h @@ -146,6 +146,9 @@ extern NSString *const kBITCrashManagerStatus; Use this on startup, to check if the app starts the first time after it crashed previously. You can use this also to disable specific events, like asking the user to rate your app. + + @warning This property only has a correct value, once `[BITHockeyManager startManager]` was + invoked! */ @property (nonatomic, readonly) BOOL didCrashInLastSession; diff --git a/Classes/BITHockeyManager.h b/Classes/BITHockeyManager.h index 7c5778c3..6dc033fa 100644 --- a/Classes/BITHockeyManager.h +++ b/Classes/BITHockeyManager.h @@ -48,6 +48,13 @@ 3. Configure each module. 4. Start up all modules. + The SDK is optimized to defer everything possible to a later time while making sure e.g. crashes on startup can also be catched and each module executes other code with a delay some seconds. This ensures that applicationDidFinishLaunching will process as fast as possible and the SDK will not block the startup sequence resulting in a possible kill by the watchdog process. + + All modules do **NOT** show any user interface if the module is not activated or not integrated. + `BITCrashManager`: Shows an alert on startup asking the user if he/she agrees on sending the crash report, if `[BITCrashManager crashManagerStatus]` is set to `BITCrashManagerStatusAlwaysAsk` (default) + `BITUpdateManager`: Is automatically deactivated when the SDK detects it is running from a build distributed via the App Store. Otherwise if it is not deactivated manually, it will show an alert after startup informing the user about a pending update, if one is available. If the user then decides to view the update another screen is presented with further details and an option to install the update. + `BITFeedbackManager`: If this module is deactivated or the user interface is nowhere added into the app, this module will not do anything. It will not fetch the server for data or show any user interface. If it is integrated, activated, and the user already used it to provide feedback, it will show an alert after startup if a new answer has been received from the server with the option to view it. + @warning You should **NOT** change any module configuration after calling `startManager`! Example: From c375241ac615d4e35744a3c20f9ee115d87c7170 Mon Sep 17 00:00:00 2001 From: Andreas Linde Date: Thu, 7 Feb 2013 14:59:27 +0100 Subject: [PATCH 167/176] Update migration documentation --- docs/Guide-Migration-Kits-template.md | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/docs/Guide-Migration-Kits-template.md b/docs/Guide-Migration-Kits-template.md index c9f45469..60a242ab 100644 --- a/docs/Guide-Migration-Kits-template.md +++ b/docs/Guide-Migration-Kits-template.md @@ -27,10 +27,14 @@ In Xcode open the `Project Navigator` (⌘+1). In the search field at the bottom All of them should be in one folder/group in Xcode. Remove that folder. -### HockeySDK-iOS +### HockeySDK-iOS before v2.5 In Xcode open the `Project Navigator` (⌘+1). In the search field at the bottom enter "CNSHockeyManager". If search returns any results you have the first release of our unified SDK added to your project. Even if you added it as a git submodule we would suggest you remove it first. +### HockeySDK-iOS v2.5.x + +In Xcode open the `Project Navigator` (⌘+1). In the search field at the bottom enter `HockeySDK.framework`. If search returns any results you have the first release of our unified SDK added to your project. Even if you added it as a git submodule we would suggest you remove it first. Repeat the same for `CrashReporter.framework` and `HockeySDKResources.bundle`. + ### Final Steps Search again in the `Project Navigator` (⌘+1) for "CrashReporter.framework". You shouldn't get any results now. If not, remove the CrashReporter.framework from your project. @@ -78,7 +82,7 @@ Now follow the steps described in our [setup guide](http://support.hockeyapp.net After you have finished the setup guide make sure everything works as expected and then delete the out commented lines from above. -### HockeySDK-iOS +### HockeySDK-iOS before 2.5 In your application delegate (for example `AppDelegate.m`) search for the following lines: @@ -100,6 +104,16 @@ Now follow the steps described in our [setup guide](http://support.hockeyapp.net After you have finished the setup guide make sure everything works as expected and then delete the out commented lines from above. +### HockeySDK-iOS 2.5.x + +THere are no changes to the SDK setup code required. Some delegates methods are deprecated and should be replaced as soon as feasible. + +The following delegates in `BITCrashManagerDelegate` moved to `BITHockeyManagerDelegate`: + +- `- (NSString *)userNameForCrashManager:(BITCrashManager *)crashManager;` is now `- (NSString *)userNameForHockeyManager:(BITHockeyManager *)hockeyManager componentManager:(BITHockeyBaseManager *)componentManager;` +- `- (NSString *)userEmailForCrashManager:(BITCrashManager *)crashManager;` is now `- (NSString *)userEmailForHockeyManager:(BITHockeyManager *)hockeyManager componentManager:(BITHockeyBaseManager *)componentManager;` + + ## Troubleshooting ### ld: warning: directory not found for option '....QuincyKit.....' From 7fd08e5ddc1dc24b7ccc044dfc38aa07b8b9107e Mon Sep 17 00:00:00 2001 From: Andreas Linde Date: Thu, 7 Feb 2013 16:45:05 +0100 Subject: [PATCH 168/176] Fix animation glitch and blurred font in Update View --- Classes/BITAppStoreHeader.m | 33 ++++++++++++++++++--------------- 1 file changed, 18 insertions(+), 15 deletions(-) diff --git a/Classes/BITAppStoreHeader.m b/Classes/BITAppStoreHeader.m index dbee1fcd..7647bdd2 100644 --- a/Classes/BITAppStoreHeader.m +++ b/Classes/BITAppStoreHeader.m @@ -43,7 +43,10 @@ #define kImageTopMargin 12 #define kTextRow kImageTopMargin*2 + kImageHeight -@implementation BITAppStoreHeader +@implementation BITAppStoreHeader { + UILabel *_headerLabelView; + UILabel *_middleLabelView; +} #pragma mark - NSObject @@ -87,22 +90,22 @@ - (void)layoutSubviews { UIFont *mainFont = [UIFont boldSystemFontOfSize:15]; UIFont *secondaryFont = [UIFont systemFontOfSize:10]; - UILabel *headerLabelView = [[UILabel alloc] init]; - [headerLabelView setFont:mainFont]; - [headerLabelView setFrame:CGRectMake(kTextRow, kImageTopMargin, globalWidth-kTextRow, 20)]; - [headerLabelView setTextColor:mainTextColor]; - [headerLabelView setBackgroundColor:[UIColor clearColor]]; - [headerLabelView setText:_headerLabel]; - [self addSubview:headerLabelView]; + if (!_headerLabelView) _headerLabelView = [[UILabel alloc] init]; + [_headerLabelView setFont:mainFont]; + [_headerLabelView setFrame:CGRectMake(kTextRow, kImageTopMargin, globalWidth-kTextRow, 20)]; + [_headerLabelView setTextColor:mainTextColor]; + [_headerLabelView setBackgroundColor:[UIColor clearColor]]; + [_headerLabelView setText:_headerLabel]; + [self addSubview:_headerLabelView]; // middle - UILabel *middleLabelView = [[UILabel alloc] init]; - [middleLabelView setFont:secondaryFont]; - [middleLabelView setFrame:CGRectMake(kTextRow, kImageTopMargin + 17, globalWidth-kTextRow, 20)]; - [middleLabelView setTextColor:secondaryTextColor]; - [middleLabelView setBackgroundColor:[UIColor clearColor]]; - [middleLabelView setText:_subHeaderLabel]; - [self addSubview:middleLabelView]; + if (!_middleLabelView) _middleLabelView = [[UILabel alloc] init]; + [_middleLabelView setFont:secondaryFont]; + [_middleLabelView setFrame:CGRectMake(kTextRow, kImageTopMargin + 17, globalWidth-kTextRow, 20)]; + [_middleLabelView setTextColor:secondaryTextColor]; + [_middleLabelView setBackgroundColor:[UIColor clearColor]]; + [_middleLabelView setText:_subHeaderLabel]; + [self addSubview:_middleLabelView]; } From e0d17bdbed11318532db2ce47d0e122d26f96f96 Mon Sep 17 00:00:00 2001 From: Andreas Linde Date: Thu, 7 Feb 2013 16:46:08 +0100 Subject: [PATCH 169/176] Use a better property name in update view for the title texts --- Classes/BITAppStoreHeader.h | 4 ++-- Classes/BITAppStoreHeader.m | 16 ++++++++-------- Classes/BITUpdateViewController.m | 4 ++-- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/Classes/BITAppStoreHeader.h b/Classes/BITAppStoreHeader.h index 272d86ae..d97739b7 100644 --- a/Classes/BITAppStoreHeader.h +++ b/Classes/BITAppStoreHeader.h @@ -33,8 +33,8 @@ @interface BITAppStoreHeader : UIView -@property (nonatomic, copy) NSString *headerLabel; -@property (nonatomic, copy) NSString *subHeaderLabel; +@property (nonatomic, copy) NSString *headerText; +@property (nonatomic, copy) NSString *subHeaderText; @property (nonatomic, strong) UIImage *iconImage; @end diff --git a/Classes/BITAppStoreHeader.m b/Classes/BITAppStoreHeader.m index 7647bdd2..8c6f41cf 100644 --- a/Classes/BITAppStoreHeader.m +++ b/Classes/BITAppStoreHeader.m @@ -95,7 +95,7 @@ - (void)layoutSubviews { [_headerLabelView setFrame:CGRectMake(kTextRow, kImageTopMargin, globalWidth-kTextRow, 20)]; [_headerLabelView setTextColor:mainTextColor]; [_headerLabelView setBackgroundColor:[UIColor clearColor]]; - [_headerLabelView setText:_headerLabel]; + [_headerLabelView setText:_headerText]; [self addSubview:_headerLabelView]; // middle @@ -104,23 +104,23 @@ - (void)layoutSubviews { [_middleLabelView setFrame:CGRectMake(kTextRow, kImageTopMargin + 17, globalWidth-kTextRow, 20)]; [_middleLabelView setTextColor:secondaryTextColor]; [_middleLabelView setBackgroundColor:[UIColor clearColor]]; - [_middleLabelView setText:_subHeaderLabel]; + [_middleLabelView setText:_subHeaderText]; [self addSubview:_middleLabelView]; } #pragma mark - Properties -- (void)setHeaderLabel:(NSString *)anHeaderLabel { - if (_headerLabel != anHeaderLabel) { - _headerLabel = [anHeaderLabel copy]; +- (void)setHeaderText:(NSString *)anHeaderText { + if (_headerText != anHeaderText) { + _headerText = [anHeaderText copy]; [self setNeedsDisplay]; } } -- (void)setSubHeaderLabel:(NSString *)aSubHeaderLabel { - if (_subHeaderLabel != aSubHeaderLabel) { - _subHeaderLabel = [aSubHeaderLabel copy]; +- (void)setSubHeaderText:(NSString *)aSubHeaderText { + if (_subHeaderText != aSubHeaderText) { + _subHeaderText = [aSubHeaderText copy]; [self setNeedsDisplay]; } } diff --git a/Classes/BITUpdateViewController.m b/Classes/BITUpdateViewController.m index 46dc1a11..4551f37b 100644 --- a/Classes/BITUpdateViewController.m +++ b/Classes/BITUpdateViewController.m @@ -75,8 +75,8 @@ - (void)restoreStoreButtonStateAnimated:(BOOL)animated { - (void)updateAppStoreHeader { BITAppVersionMetaInfo *appVersion = _updateManager.newestAppVersion; - _appStoreHeader.headerLabel = appVersion.name; - _appStoreHeader.subHeaderLabel = _updateManager.companyName; + _appStoreHeader.headerText = appVersion.name; + _appStoreHeader.subHeaderText = _updateManager.companyName; } - (void)appDidBecomeActive { From bf688bfbba509d424442fc63ea644652f6a598a1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=A1bor=20Varga?= Date: Fri, 8 Feb 2013 11:46:40 +0100 Subject: [PATCH 170/176] Hungarian localization. --- Resources/hu.lproj/HockeySDK.strings | 230 +++++++++++++++++++++++++++ 1 file changed, 230 insertions(+) create mode 100644 Resources/hu.lproj/HockeySDK.strings diff --git a/Resources/hu.lproj/HockeySDK.strings b/Resources/hu.lproj/HockeySDK.strings new file mode 100644 index 00000000..0a27a031 --- /dev/null +++ b/Resources/hu.lproj/HockeySDK.strings @@ -0,0 +1,230 @@ +/* + Hungarian localization provided by Gábor Varga at Sanoma Media Budapest Zrt. + */ + + +/* General */ + +/* For dialogs yes buttons */ +"HockeyYes" = "Igen"; + +/* For dialogs no buttons */ +"HockeyNo" = "Nem"; + +/* For dialogs ok buttons */ +"HockeyOK" = "OK"; + +/* Replacement for app name, if it could not be detected */ +"HockeyAppNamePlaceholder" = "Az alkalmazás"; + +/* Crash */ + + +/* Crash dialog */ + +/* Title showing in the alert box when crash report data has been found */ +"CrashDataFoundTitle" = "%@ váratlanul kilépett"; + +/* Description explaining that crash data has been found and ask the user if the data might be uploaded to the developers server */ +"CrashDataFoundAnonymousDescription" = "Szeretne hibajelentést küldeni, hogy javíthassuk a problémát? A küldés névtelenül történik."; + +/* Description explaining that crash data has been found and ask the user if the non anonymous data might be uplaoded to the developers server */ +"CrashDataFoundDescription" = "Szeretne hibajelentést küldeni, hogy javíthassuk a problémát?"; + +/* Alert box button if the users wants to send crash data always automatically */ +"CrashSendReportAlways" = "Mindig küldjön"; + +/* Alert box button to send the crash report once */ +"CrashSendReport" = "Jelentés küldése"; + +/* Alert box button to decline sending the report */ +"CrashDontSendReport" = "Ne küldjön"; + +/* Text showing in a processing box that the crash data is being uploaded to the server */ +"CrashReportSending" = "Küldés…"; + + +/* Update */ + + +/* Update Alert view */ + +/* Update available */ +"UpdateAvailable" = "Frissítés elérhető"; + +"UpdateAlertTextWithAppVersion" = "%@ elérhető."; + +"UpdateAlertMandatoryTextWithAppVersion" = "%@ elérhető, és szükséges frissíteni!"; + +"UpdateIgnore" = "Most nem"; + +"UpdateShow" = "Megjelenítés"; + +"UpdateInstall" = "Telepítés"; + + +/* Update Details */ + +"UpdateScreenTitle" = "Frissítés"; + +"UpdateButtonCheck" = "ELLENŐRZÉS"; + +"UpdateButtonSearching" = "KERESÉS"; + +"UpdateButtonUpdate" = "FRISSÍTÉS"; + +"UpdateButtonInstalling" = "TELEPÍTÉS"; + +"UpdateButtonOffline" = "NINCS KAPCSOLAT"; + +"UpdateInstalled" = "TELEPÍTVE"; + +"UpdateVersion" = "verzió"; + +"UpdateShowPreviousVersions" = "Korábbi verziók megtekintése…"; + +"UpdateNoUpdateAvailableTitle" = "Nincs elérhető frissítés"; + +"UpdateNoUpdateAvailableMessage" = "%@ már a legfrissebb verzió."; + +"UpdateError" = "Hiba"; + +"UpdateWarning" = "Figyelmeztetés"; + +"UpdateNoReleaseNotesAvailable" = "Nem elérhető a változások listája."; + + +/* Update Authorization */ + +"UpdateAuthorizationProgress" = "Engedélyezés…"; + +"UpdateAuthorizationOffline" = "Internetkapcsolat szükséges!"; + +"UpdateAuthorizationDenied" = "Engedélyezés megtagadva. Lépjen kapcsolatba a fejlesztővel."; + + +/* Update Expiry */ + +"UpdateExpired" = "%@ érvényessége lejárt, és már nem használható."; + + +/* Update Simulator Warning */ + +"UpdateSimulatorMessage" = "A Hockey Update nem használható a szimulátorban.\nAz itms-services:// URL séma elérhető, de nem működőképes."; + + +/* Feedback */ + + +/* New Message Alert */ + +/* Alert Title */ +"HockeyFeedbackNewMessageTitle" = "Új válasz"; + +/* Alert Text */ +"HockeyFeedbackNewMessageText" = "Új válasz érkezett az Ön visszajelzésére. Kívánja most megtekinteni?"; + +/* Alert Ignore Button */ +"HockeyFeedbackIgnore" = "Most nem"; + +/* Alert Show Button */ +"HockeyFeedbackShow" = "Megtekintés"; + + +/* List View */ + +/* Title */ +"HockeyFeedbackListTitle" = "Visszajelzés"; + +/* Last Updated */ +"HockeyFeedbackListLastUpdated" = "Utolsó frissítés: %@"; + +/* Never Updated */ +"HockeyFeedbackListNeverUpdated" = "Soha"; + +/* Provide Feedback Button Title */ +"HockeyFeedbackListButonWriteFeedback" = "Visszajelzés küldése"; + +/* Add a Response Button Title */ +"HockeyFeedbackListButonWriteResponse" = "Válasz küldése"; + +/* User Data Set Name Button Title */ +"HockeyFeedbackListButonUserDataSetName" = "Adja meg a nevét"; + +/* User Data Set Email Button Title */ +"HockeyFeedbackListButonUserDataSetEmail" = "Adja meg az e-mail címét"; + +/* User Data With Name Button Title */ +"HockeyFeedbackListButonUserDataWithName" = "Név: %@"; + +/* User Data With Email Button Title */ +"HockeyFeedbackListButonUserDataWithEmail" = "E-mail: %@"; + +/* Button title for deleting all local messages*/ +"HockeyFeedbackListButonDeleteAllMessages" = "Összes üzenet törlése"; + +/* Message pending to be send */ +"HockeyFeedbackListMessagePending" = "Folyamatban"; + + +/* Delete All Messages Action Sheet / Alert View */ + +/* Title for the Action Sheet */ +"HockeyFeedbackListDeleteAllTitle" = "Minden üzenet törlődni fog erről az eszközről."; + +/* Button Title to perform delete action */ +"HockeyFeedbackListDeleteAllDelete" = "Törlés"; + +/* Button Title to cancel delete action */ +"HockeyFeedbackListDeleteAllCancel" = "Mégsem"; + + +/* Open Link In Safari Action Sheet / Alert View */ + +/* Button Title to cancel */ +"HockeyFeedbackListLinkActionCancel" = "Mégsem"; + +/* Button Title to Open the Link */ +"HockeyFeedbackListLinkActionOpen" = "Megnyitás"; + +/* Button Title to Copy the Link */ +"HockeyFeedbackListLinkActionCopy" = "Másolás"; + + +/* UIActivity */ + +/* Activity Sharing Button Title, App Name will be inserted */ +"HockeyFeedbackActivityButtonTitle" = "Visszajelzés: %@"; + +/* if there can no app name be found, use this instead for HockeyFeedbackActivityButtonTitle */ +"HockeyFeedbackActivityAppPlaceholder" = "az alkalmazásról"; + + +/* Compose Message */ + +/* Title */ +"HockeyFeedbackComposeTitle" = "Új visszajelzés"; + +/* Send button */ +"HockeyFeedbackComposeSend" = "Küldés"; + + +/* Set User Data */ + +/* Title */ +"HockeyFeedbackUserDataTitle" = "Felhasználói adatok"; + +/* Description On What Should Be Entered */ +"HockeyFeedbackUserDataDescription" = "Kérjük, adja meg néhány adatát, mielőtt megírja a visszajelzést."; + +/* Name Field */ +"HockeyFeedbackUserDataName" = "Név"; + +/* Name Placeholder */ +"HockeyFeedbackUserDataNamePlaceHolder" = "Gipsz Jakab"; + +/* Email Field */ +"HockeyFeedbackUserDataEmail" = "E-mail"; + +/* Email Placeholder */ +"HockeyFeedbackUserDataEmailPlaceholder" = "example@email.com"; From 9b59cca3160ec1f9cb888d8500ef953767be78f0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=A1bor=20Varga?= Date: Fri, 8 Feb 2013 12:44:14 +0100 Subject: [PATCH 171/176] Add the Hungarian localization to the project. --- Support/HockeySDK.xcodeproj/project.pbxproj | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Support/HockeySDK.xcodeproj/project.pbxproj b/Support/HockeySDK.xcodeproj/project.pbxproj index a61274b0..c4577f4f 100644 --- a/Support/HockeySDK.xcodeproj/project.pbxproj +++ b/Support/HockeySDK.xcodeproj/project.pbxproj @@ -219,6 +219,7 @@ 1EF95CA4162CB036000AE3AD /* BITFeedbackActivity.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BITFeedbackActivity.h; sourceTree = ""; }; 1EF95CA5162CB036000AE3AD /* BITFeedbackActivity.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = BITFeedbackActivity.m; sourceTree = ""; }; 1EF95CA9162CB313000AE3AD /* BITFeedbackComposeViewControllerDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BITFeedbackComposeViewControllerDelegate.h; sourceTree = ""; }; + BEE0207C16C5107E004426EA /* hu */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = hu; path = hu.lproj/HockeySDK.strings; sourceTree = ""; }; E400561D148D79B500EB22B9 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; E41EB465148D7BF50015DEDC /* BITHockeyManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BITHockeyManager.h; sourceTree = ""; }; E41EB466148D7BF50015DEDC /* BITHockeyManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = BITHockeyManager.m; sourceTree = ""; }; @@ -532,6 +533,7 @@ zh, "zh-Hans", ro, + hu, ); mainGroup = E400560F148D79B500EB22B9; productRefGroup = E400561B148D79B500EB22B9 /* Products */; @@ -675,6 +677,7 @@ 1EB52FC3167B73D400C801D5 /* en */, 1EA512DF167F7EF000FC9FBA /* zh-Hans */, 1E6DDCEE169E290C0076C65D /* ro */, + BEE0207C16C5107E004426EA /* hu */, ); name = HockeySDK.strings; sourceTree = ""; From b490ae61446e715eae6abaf24e9d174f300a66ec Mon Sep 17 00:00:00 2001 From: Andreas Linde Date: Sun, 10 Feb 2013 18:15:34 +0100 Subject: [PATCH 172/176] More documentation updates preparing 3.0 release --- Classes/BITHockeyManager.h | 2 +- README.md | 12 +++--- docs/Changelog-template.md | 42 +++++++++++++++++++ ...de-Installation-Setup-Advanced-template.md | 2 + docs/Guide-Installation-Setup-template.md | 3 ++ 5 files changed, 54 insertions(+), 7 deletions(-) diff --git a/Classes/BITHockeyManager.h b/Classes/BITHockeyManager.h index 6dc033fa..c29653e4 100644 --- a/Classes/BITHockeyManager.h +++ b/Classes/BITHockeyManager.h @@ -48,7 +48,7 @@ 3. Configure each module. 4. Start up all modules. - The SDK is optimized to defer everything possible to a later time while making sure e.g. crashes on startup can also be catched and each module executes other code with a delay some seconds. This ensures that applicationDidFinishLaunching will process as fast as possible and the SDK will not block the startup sequence resulting in a possible kill by the watchdog process. + The SDK is optimized to defer everything possible to a later time while making sure e.g. crashes on startup can also be caught and each module executes other code with a delay some seconds. This ensures that applicationDidFinishLaunching will process as fast as possible and the SDK will not block the startup sequence resulting in a possible kill by the watchdog process. All modules do **NOT** show any user interface if the module is not activated or not integrated. `BITCrashManager`: Shows an alert on startup asking the user if he/she agrees on sending the crash report, if `[BITCrashManager crashManagerStatus]` is set to `BITCrashManagerStatusAlwaysAsk` (default) diff --git a/README.md b/README.md index 8a2870ec..e0ff5508 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ -## Version 3.0.0 RC1 +## Version 3.0.0 -- [Changelog](http://www.hockeyapp.net/help/sdk/ios/3.0.0RC1/docs/docs/Changelog.html) +- [Changelog](http://www.hockeyapp.net/help/sdk/ios/3.0.0/docs/docs/Changelog.html) ## Introduction @@ -26,9 +26,9 @@ The main SDK class is `BITHockeyManager`. It initializes all modules and provide ## Installation & Setup -- [Installation & Setup](http://www.hockeyapp.net/help/sdk/ios/3.0.0RC1/docs/docs/Guide-Installation-Setup.html) (Recommended) -- [Installation & Setup Advanced](http://www.hockeyapp.net/help/sdk/ios/3.0.0RC1/docs/docs/Guide-Installation-Setup-Advanced.html) (Using Git submodule and Xcode sub-project) -- [Migration from HockeyKit & QuincyKit](http://www.hockeyapp.net/help/sdk/ios/3.0.0RC1/docs/docs/Guide-Migration-Kits.html) +- [Installation & Setup](http://www.hockeyapp.net/help/sdk/ios/3.0.0/docs/docs/Guide-Installation-Setup.html) (Recommended) +- [Installation & Setup Advanced](http://www.hockeyapp.net/help/sdk/ios/3.0.0/docs/docs/Guide-Installation-Setup-Advanced.html) (Using Git submodule and Xcode sub-project) +- [Migration from HockeyKit & QuincyKit](http://www.hockeyapp.net/help/sdk/ios/3.0.0/docs/docs/Guide-Migration-Kits.html) - [Mac Desktop Uploader](http://support.hockeyapp.net/kb/how-tos/how-to-upload-to-hockeyapp-on-a-mac) @@ -42,4 +42,4 @@ This documentation provides integrated help in Xcode for all public APIs and a s 3. Copy the content into ~`/Library/Developer/Shared/Documentation/DocSet` -The documentation is also available via the following URL: [http://hockeyapp.net/help/sdk/ios/3.0.0RC1/](http://hockeyapp.net/help/sdk/ios/3.0.0RC1/) +The documentation is also available via the following URL: [http://hockeyapp.net/help/sdk/ios/3.0.0/](http://hockeyapp.net/help/sdk/ios/3.0.0/) diff --git a/docs/Changelog-template.md b/docs/Changelog-template.md index b2ffd83a..e3e19a75 100644 --- a/docs/Changelog-template.md +++ b/docs/Changelog-template.md @@ -1,3 +1,45 @@ +### Version 3.0.0 + +- General: + - [NEW] Added new Feedback module + - [NEW] Minimum iOS Deployment version is now iOS 5.0 + - [NEW] Migrated to use ARC + - [NEW] Added localizations provided by [Wordcrafts.de](http://wordcrafts.de): + Chinese, English, French, German, Italian, Japanese, Portuguese, Brazilian-Portuguese, Russian, Spanish + - [NEW] Added Romanian, Hungarian localization + - [UPDATE] Using embedded.framework for binary distribution containing everything needed in one package + - [UPDATE] Improved Xcode project setup to only use one static library + - [UPDATE] Providing build settings as `HockeySDK.xcconfig` file for easier setup + - [UPDATE] Remove `-ObjC` from `Other Linker Flags`, since the SDK doesn't need it + - [UPDATE] Documentation improvements + - [UPDATE] Exclude binary UUID check from simulator builds, so unit test targets will work. But functionality based on binary UUID cannot be tested in the simulator, e.g. update without changing build version. + - [BUGFIX] Fix some new compiler warnings + - [BUGFIX] Fix some missing new lines at EOF + - [BUGFIX] Make sure sure JSON serialization doesn't crash if the string is nil + - [BUGFIX] Various additional minor fixes + +- Crash Reporting: + - [NEW] Add anonymous device ID to crash reports + - [UPDATE] The following delegates in `BITCrashManagerDelegate` moved to `BITHockeyManagerDelegate`: + - `- (NSString *)userNameForCrashManager:(BITCrashManager *)crashManager;` is now `- (NSString *)userNameForHockeyManager:(BITHockeyManager *)hockeyManager componentManager:(BITHockeyBaseManager *)componentManager;` + - `- (NSString *)userEmailForCrashManager:(BITCrashManager *)crashManager;` is now `- (NSString *)userEmailForHockeyManager:(BITHockeyManager *)hockeyManager componentManager:(BITHockeyBaseManager *)componentManager;` + - [BUGFIX] Move calculation of time interval between startup and crash further up in the code, so delegates can use this information e.g. to add it into a log file + - [BUGFIX] Call delegate also if a crash was detected but could not be read (if handling crashes on startup is implemented) + - [BUGFIX] Format timestamp in crash report to be always UTC in en_US locale + - [BUGFIX] Make sure crash reports incident identifier and key don't have special [] chars and some value + +- Feedback: + - [NEW] User feedback interface for direct communication with your users + - [NEW] iOS 6 UIActivity component for integrating feedback + - [NEW] Ask user details and show compose screen automatically on first opening feedback list view + +- Updating: + - [NEW] Support for In-App updates without changing `CFBundleVersion` + - [UPDATE] Update UI modified to be more iOS 6 alike + - [UPDATE] Update UI shows the company name next to the app name if defined in the backend + - [BUGFIX] Fix a problem showing the update UI animated if there TTNavigator class is present even though not being used + + ### Version 3.0.0 RC 1 - General: diff --git a/docs/Guide-Installation-Setup-Advanced-template.md b/docs/Guide-Installation-Setup-Advanced-template.md index 328e538c..47430604 100644 --- a/docs/Guide-Installation-Setup-Advanced-template.md +++ b/docs/Guide-Installation-Setup-Advanced-template.md @@ -133,6 +133,8 @@ If you need support for iOS 3.x, please check out [HockeyKit](http://support.hoc 7. Replace `LIVE_IDENTIFIER` with the app identifier of your release app. We suggest to setup different apps on HockeyApp for your test and production builds. You usually will have way more test versions, but your production version usually has way more crash reports. This helps to keep data separated, getting a better overview and less trouble setting the right app versions downloadable for your beta users. +*Note:* The SDK is optimized to defer everything possible to a later time while making sure e.g. crashes on startup can also be caught and each module executes other code with a delay some seconds. This ensures that applicationDidFinishLaunching will process as fast as possible and the SDK will not block the startup sequence resulting in a possible kill by the watchdog process. + ## Submit the UDID diff --git a/docs/Guide-Installation-Setup-template.md b/docs/Guide-Installation-Setup-template.md index 89b99321..aea4881d 100644 --- a/docs/Guide-Installation-Setup-template.md +++ b/docs/Guide-Installation-Setup-template.md @@ -103,6 +103,9 @@ If you need support for iOS 3.x, please check out [HockeyKit](http://support.hoc 7. Replace `LIVE_IDENTIFIER` with the app identifier of your release app. We suggest to setup different apps on HockeyApp for your test and production builds. You usually will have way more test versions, but your production version usually has way more crash reports. This helps to keep data separated, getting a better overview and less trouble setting the right app versions downloadable for your beta users. +*Note:* The SDK is optimized to defer everything possible to a later time while making sure e.g. crashes on startup can also be caught and each module executes other code with a delay some seconds. This ensures that applicationDidFinishLaunching will process as fast as possible and the SDK will not block the startup sequence resulting in a possible kill by the watchdog process. + + ## Submit the UDID From 9e51b1cd89e1b220c5925d21d15888487f81b32e Mon Sep 17 00:00:00 2001 From: Kevin Rohling Date: Sun, 10 Feb 2013 14:21:19 -0800 Subject: [PATCH 173/176] Updating script to copy artifact to output dir --- Support/HockeySDK.xcodeproj/project.pbxproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Support/HockeySDK.xcodeproj/project.pbxproj b/Support/HockeySDK.xcodeproj/project.pbxproj index c4577f4f..fc38c242 100644 --- a/Support/HockeySDK.xcodeproj/project.pbxproj +++ b/Support/HockeySDK.xcodeproj/project.pbxproj @@ -593,7 +593,7 @@ ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "# Sets the target folders and the final framework product.\nFMK_NAME=HockeySDK\nFMK_VERSION=A\nFMK_RESOURCE_BUNDLE=HockeySDKResources\n\n# Documentation\nHOCKEYSDK_DOCSET_VERSION_NAME=\"de.bitstadium.${HOCKEYSDK_DOCSET_NAME}-${VERSION_STRING}\"\n\n# Install dir will be the final output to the framework.\n# The following line create it in the root folder of the current project.\nPRODUCTS_DIR=${SRCROOT}/../Products\nTEMP_DIR=${PRODUCTS_DIR}/Temp\nINSTALL_DIR=${TEMP_DIR}/${FMK_NAME}.framework\n\n# Working dir will be deleted after the framework creation.\nWRK_DIR=build\nDEVICE_DIR=${WRK_DIR}/Release-iphoneos\nSIMULATOR_DIR=${WRK_DIR}/Release-iphonesimulator\nHEADERS_DIR=${WRK_DIR}/Release-iphoneos/usr/local/include\n\n# Building both architectures.\nxcodebuild -project \"HockeySDK.xcodeproj\" -configuration \"Release\" -target \"${FMK_NAME}\" -sdk iphoneos\nxcodebuild -project \"HockeySDK.xcodeproj\" -configuration \"Release\" -target \"${FMK_NAME}\" -sdk iphonesimulator\n\n# Cleaning the oldest.\nif [ -d \"${TEMP_DIR}\" ]\nthen\nrm -rf \"${TEMP_DIR}\"\nfi\n\n# Creates and renews the final product folder.\nmkdir -p \"${INSTALL_DIR}\"\nmkdir -p \"${INSTALL_DIR}/Versions\"\nmkdir -p \"${INSTALL_DIR}/Versions/${FMK_VERSION}\"\nmkdir -p \"${INSTALL_DIR}/Versions/${FMK_VERSION}/Resources\"\nmkdir -p \"${INSTALL_DIR}/Versions/${FMK_VERSION}/Headers\"\n\n# Creates the internal links.\n# It MUST uses relative path, otherwise will not work when the folder is copied/moved.\nln -s \"${FMK_VERSION}\" \"${INSTALL_DIR}/Versions/Current\"\nln -s \"Versions/Current/Headers\" \"${INSTALL_DIR}/Headers\"\nln -s \"Versions/Current/Resources\" \"${INSTALL_DIR}/Resources\"\nln -s \"Versions/Current/${FMK_NAME}\" \"${INSTALL_DIR}/${FMK_NAME}\"\n\n# Copies the headers and resources files to the final product folder.\ncp -R \"${SRCROOT}/build/Release-iphoneos/include/HockeySDK/\" \"${INSTALL_DIR}/Versions/${FMK_VERSION}/Headers/\"\ncp -R \"${DEVICE_DIR}/${FMK_RESOURCE_BUNDLE}.bundle\" \"${INSTALL_DIR}/Versions/${FMK_VERSION}/Resources/\"\ncp -f \"${SRCROOT}/${FMK_NAME}.xcconfig\" \"${INSTALL_DIR}/Versions/${FMK_VERSION}/Resources/\"\n\n# Uses the Lipo Tool to merge both binary files (i386 + armv6/armv7) into one Universal final product.\nlipo -create \"${DEVICE_DIR}/lib${FMK_NAME}.a\" \"${SIMULATOR_DIR}/lib${FMK_NAME}.a\" -output \"${INSTALL_DIR}/Versions/${FMK_VERSION}/${FMK_NAME}\"\n\n# Combine the CrashReporter static library into a new Hockey static library file if they are not already present and copy the public headers too\nif [ -z $(otool -L \"${INSTALL_DIR}/Versions/${FMK_VERSION}/${FMK_NAME}\" | grep 'libCrashReporter') ]\nthen\nlibtool -static -o \"${INSTALL_DIR}/Versions/${FMK_VERSION}/${FMK_NAME}\" \"${INSTALL_DIR}/Versions/${FMK_VERSION}/${FMK_NAME}\" \"${SRCROOT}/../Vendor/CrashReporter.framework/Versions/A/CrashReporter\"\nfi\n\nrm -r \"${WRK_DIR}\"\n\n# build embeddedframework folder and move framework into it\nmkdir \"${INSTALL_DIR}/../${FMK_NAME}.embeddedframework\"\nmv \"${INSTALL_DIR}\" \"${INSTALL_DIR}/../${FMK_NAME}.embeddedframework/${FMK_NAME}.framework\"\n\n# link Resources\nNEW_INSTALL_DIR=${TEMP_DIR}/${FMK_NAME}.embeddedframework\nmkdir \"${NEW_INSTALL_DIR}/Resources\"\nln -s \"../${FMK_NAME}.framework/Resources/${FMK_RESOURCE_BUNDLE}.bundle\" \"${NEW_INSTALL_DIR}/Resources/${FMK_RESOURCE_BUNDLE}.bundle\"\nln -s \"../${FMK_NAME}.framework/Resources/${FMK_NAME}.xcconfig\" \"${NEW_INSTALL_DIR}/Resources/${FMK_NAME}.xcconfig\"\n\n# copy license, changelog, documentation\ncp -f \"${SRCROOT}/../Docs/Changelog-template.md\" \"${TEMP_DIR}/CHANGELOG\"\ncp -f \"${SRCROOT}/../Docs/Guide-Installation-Setup-template.md\" \"${TEMP_DIR}/README.md\"\ncp -f \"${SRCROOT}/../LICENSE\" \"${TEMP_DIR}\"\nmkdir \"${TEMP_DIR}/${HOCKEYSDK_DOCSET_VERSION_NAME}.docset\"\ncp -R \"${SRCROOT}/../documentation/docset/Contents\" \"${TEMP_DIR}/${HOCKEYSDK_DOCSET_VERSION_NAME}.docset\"\n\n# build zip\ncd \"${PRODUCTS_DIR}\"\nrm -f \"${FMK_NAME}-iOS-${VERSION_STRING}.zip\"\ncd \"${TEMP_DIR}\"\nzip -yr \"../${FMK_NAME}-iOS-${VERSION_STRING}.zip\" \"./${FMK_NAME}.embeddedframework\" \"./CHANGELOG\" \"./README.md\" \"./LICENSE\" \"./${HOCKEYSDK_DOCSET_VERSION_NAME}.docset\" -x \\*/.*\n"; + shellScript = "# Sets the target folders and the final framework product.\nFMK_NAME=HockeySDK\nFMK_VERSION=A\nFMK_RESOURCE_BUNDLE=HockeySDKResources\n\n# Documentation\nHOCKEYSDK_DOCSET_VERSION_NAME=\"de.bitstadium.${HOCKEYSDK_DOCSET_NAME}-${VERSION_STRING}\"\n\n# Install dir will be the final output to the framework.\n# The following line create it in the root folder of the current project.\nPRODUCTS_DIR=${SRCROOT}/../Products\nTEMP_DIR=${PRODUCTS_DIR}/Temp\nINSTALL_DIR=${TEMP_DIR}/${FMK_NAME}.framework\n\n# Working dir will be deleted after the framework creation.\nWRK_DIR=build\nDEVICE_DIR=${WRK_DIR}/Release-iphoneos\nSIMULATOR_DIR=${WRK_DIR}/Release-iphonesimulator\nHEADERS_DIR=${WRK_DIR}/Release-iphoneos/usr/local/include\n\n# Building both architectures.\nxcodebuild -project \"HockeySDK.xcodeproj\" -configuration \"Release\" -target \"${FMK_NAME}\" -sdk iphoneos\nxcodebuild -project \"HockeySDK.xcodeproj\" -configuration \"Release\" -target \"${FMK_NAME}\" -sdk iphonesimulator\n\n# Cleaning the oldest.\nif [ -d \"${TEMP_DIR}\" ]\nthen\nrm -rf \"${TEMP_DIR}\"\nfi\n\n# Creates and renews the final product folder.\nmkdir -p \"${INSTALL_DIR}\"\nmkdir -p \"${INSTALL_DIR}/Versions\"\nmkdir -p \"${INSTALL_DIR}/Versions/${FMK_VERSION}\"\nmkdir -p \"${INSTALL_DIR}/Versions/${FMK_VERSION}/Resources\"\nmkdir -p \"${INSTALL_DIR}/Versions/${FMK_VERSION}/Headers\"\n\n# Creates the internal links.\n# It MUST uses relative path, otherwise will not work when the folder is copied/moved.\nln -s \"${FMK_VERSION}\" \"${INSTALL_DIR}/Versions/Current\"\nln -s \"Versions/Current/Headers\" \"${INSTALL_DIR}/Headers\"\nln -s \"Versions/Current/Resources\" \"${INSTALL_DIR}/Resources\"\nln -s \"Versions/Current/${FMK_NAME}\" \"${INSTALL_DIR}/${FMK_NAME}\"\n\n# Copies the headers and resources files to the final product folder.\ncp -R \"${SRCROOT}/build/Release-iphoneos/include/HockeySDK/\" \"${INSTALL_DIR}/Versions/${FMK_VERSION}/Headers/\"\ncp -R \"${DEVICE_DIR}/${FMK_RESOURCE_BUNDLE}.bundle\" \"${INSTALL_DIR}/Versions/${FMK_VERSION}/Resources/\"\ncp -f \"${SRCROOT}/${FMK_NAME}.xcconfig\" \"${INSTALL_DIR}/Versions/${FMK_VERSION}/Resources/\"\n\n# Uses the Lipo Tool to merge both binary files (i386 + armv6/armv7) into one Universal final product.\nlipo -create \"${DEVICE_DIR}/lib${FMK_NAME}.a\" \"${SIMULATOR_DIR}/lib${FMK_NAME}.a\" -output \"${INSTALL_DIR}/Versions/${FMK_VERSION}/${FMK_NAME}\"\n\n# Combine the CrashReporter static library into a new Hockey static library file if they are not already present and copy the public headers too\nif [ -z $(otool -L \"${INSTALL_DIR}/Versions/${FMK_VERSION}/${FMK_NAME}\" | grep 'libCrashReporter') ]\nthen\nlibtool -static -o \"${INSTALL_DIR}/Versions/${FMK_VERSION}/${FMK_NAME}\" \"${INSTALL_DIR}/Versions/${FMK_VERSION}/${FMK_NAME}\" \"${SRCROOT}/../Vendor/CrashReporter.framework/Versions/A/CrashReporter\"\nfi\n\nrm -r \"${WRK_DIR}\"\n\n# build embeddedframework folder and move framework into it\nmkdir \"${INSTALL_DIR}/../${FMK_NAME}.embeddedframework\"\nmv \"${INSTALL_DIR}\" \"${INSTALL_DIR}/../${FMK_NAME}.embeddedframework/${FMK_NAME}.framework\"\n\n# link Resources\nNEW_INSTALL_DIR=${TEMP_DIR}/${FMK_NAME}.embeddedframework\nmkdir \"${NEW_INSTALL_DIR}/Resources\"\nln -s \"../${FMK_NAME}.framework/Resources/${FMK_RESOURCE_BUNDLE}.bundle\" \"${NEW_INSTALL_DIR}/Resources/${FMK_RESOURCE_BUNDLE}.bundle\"\nln -s \"../${FMK_NAME}.framework/Resources/${FMK_NAME}.xcconfig\" \"${NEW_INSTALL_DIR}/Resources/${FMK_NAME}.xcconfig\"\n\n# copy license, changelog, documentation\ncp -f \"${SRCROOT}/../Docs/Changelog-template.md\" \"${TEMP_DIR}/CHANGELOG\"\ncp -f \"${SRCROOT}/../Docs/Guide-Installation-Setup-template.md\" \"${TEMP_DIR}/README.md\"\ncp -f \"${SRCROOT}/../LICENSE\" \"${TEMP_DIR}\"\nmkdir \"${TEMP_DIR}/${HOCKEYSDK_DOCSET_VERSION_NAME}.docset\"\ncp -R \"${SRCROOT}/../documentation/docset/Contents\" \"${TEMP_DIR}/${HOCKEYSDK_DOCSET_VERSION_NAME}.docset\"\n\n# build zip\ncd \"${PRODUCTS_DIR}\"\nrm -f \"${FMK_NAME}-iOS-${VERSION_STRING}.zip\"\ncd \"${TEMP_DIR}\"\nzip -yr \"../${FMK_NAME}-iOS-${VERSION_STRING}.zip\" \"./${FMK_NAME}.embeddedframework\" \"./CHANGELOG\" \"./README.md\" \"./LICENSE\" \"./${HOCKEYSDK_DOCSET_VERSION_NAME}.docset\" -x \\*/.*\n\n#copy to output dir on cisimple\nif [ $CISIMPLE ]; then\n if [ ! -d \"${CONFIGURATION_BUILD_DIR}\" ]; then\n mkdir \"${CONFIGURATION_BUILD_DIR}\"\n fi\n cd \"${PRODUCTS_DIR}\"\n cp \"${FMK_NAME}-iOS-${VERSION_STRING}.zip\" \"${CONFIGURATION_BUILD_DIR}/${FMK_NAME}-iOS-${VERSION_STRING}.zip\"\nfi"; }; 1E8E66B215BC3D8200632A2E /* ShellScript */ = { isa = PBXShellScriptBuildPhase; From 2b47c325ccbcaf74a5c1de7be44fb7cbed506793 Mon Sep 17 00:00:00 2001 From: Thomas Dohmke Date: Mon, 11 Feb 2013 18:30:55 +0100 Subject: [PATCH 174/176] Update docs/Changelog-template.md --- docs/Changelog-template.md | 92 +++++++++++++++++++++----------------- 1 file changed, 51 insertions(+), 41 deletions(-) diff --git a/docs/Changelog-template.md b/docs/Changelog-template.md index e3e19a75..b4b9b638 100644 --- a/docs/Changelog-template.md +++ b/docs/Changelog-template.md @@ -1,44 +1,54 @@ -### Version 3.0.0 - -- General: - - [NEW] Added new Feedback module - - [NEW] Minimum iOS Deployment version is now iOS 5.0 - - [NEW] Migrated to use ARC - - [NEW] Added localizations provided by [Wordcrafts.de](http://wordcrafts.de): - Chinese, English, French, German, Italian, Japanese, Portuguese, Brazilian-Portuguese, Russian, Spanish - - [NEW] Added Romanian, Hungarian localization - - [UPDATE] Using embedded.framework for binary distribution containing everything needed in one package - - [UPDATE] Improved Xcode project setup to only use one static library - - [UPDATE] Providing build settings as `HockeySDK.xcconfig` file for easier setup - - [UPDATE] Remove `-ObjC` from `Other Linker Flags`, since the SDK doesn't need it - - [UPDATE] Documentation improvements - - [UPDATE] Exclude binary UUID check from simulator builds, so unit test targets will work. But functionality based on binary UUID cannot be tested in the simulator, e.g. update without changing build version. - - [BUGFIX] Fix some new compiler warnings - - [BUGFIX] Fix some missing new lines at EOF - - [BUGFIX] Make sure sure JSON serialization doesn't crash if the string is nil - - [BUGFIX] Various additional minor fixes - -- Crash Reporting: - - [NEW] Add anonymous device ID to crash reports - - [UPDATE] The following delegates in `BITCrashManagerDelegate` moved to `BITHockeyManagerDelegate`: - - `- (NSString *)userNameForCrashManager:(BITCrashManager *)crashManager;` is now `- (NSString *)userNameForHockeyManager:(BITHockeyManager *)hockeyManager componentManager:(BITHockeyBaseManager *)componentManager;` - - `- (NSString *)userEmailForCrashManager:(BITCrashManager *)crashManager;` is now `- (NSString *)userEmailForHockeyManager:(BITHockeyManager *)hockeyManager componentManager:(BITHockeyBaseManager *)componentManager;` - - [BUGFIX] Move calculation of time interval between startup and crash further up in the code, so delegates can use this information e.g. to add it into a log file - - [BUGFIX] Call delegate also if a crash was detected but could not be read (if handling crashes on startup is implemented) - - [BUGFIX] Format timestamp in crash report to be always UTC in en_US locale - - [BUGFIX] Make sure crash reports incident identifier and key don't have special [] chars and some value - -- Feedback: - - [NEW] User feedback interface for direct communication with your users - - [NEW] iOS 6 UIActivity component for integrating feedback - - [NEW] Ask user details and show compose screen automatically on first opening feedback list view - -- Updating: - - [NEW] Support for In-App updates without changing `CFBundleVersion` - - [UPDATE] Update UI modified to be more iOS 6 alike - - [UPDATE] Update UI shows the company name next to the app name if defined in the backend - - [BUGFIX] Fix a problem showing the update UI animated if there TTNavigator class is present even though not being used - +## Version 3.0.0 + +- General + + - [NEW] Added new Feedback module + - [NEW] Minimum iOS Deployment version is now iOS 5.0 + - [NEW] Migrated to use ARC + - [NEW] Added localizations provided by [Wordcrafts.de](http://wordcrafts.de): + Chinese, English, French, German, Italian, Japanese, Portuguese, Brazilian-Portuguese, Russian, Spanish + - [NEW] Added Romanian, Hungarian localization + - [UPDATE] Using embedded.framework for binary distribution containing everything needed in one package + - [UPDATE] Improved Xcode project setup to only use one static library + - [UPDATE] Providing build settings as `HockeySDK.xcconfig` file for easier setup + - [UPDATE] Remove `-ObjC` from `Other Linker Flags`, since the SDK doesn't need it anymore + - [UPDATE] Improved documentation + - [UPDATE] Excluded binary UUID check from simulator builds, so unit test targets will work. But functionality based on binary UUID cannot be tested in the simulator, e.g. update without changing build version. + - [BUGFIX] Fixed some new compiler warnings + - [BUGFIX] Fixed some missing new lines at EOF + - [BUGFIX] Make sure sure JSON serialization doesn't crash if the string is nil + - [BUGFIX] Various additional minor fixes +

+ +- Crash Reporting + + - [NEW] Added anonymous device ID to crash reports + - [UPDATE] The following delegates in `BITCrashManagerDelegate` moved to `BITHockeyManagerDelegate`: + - `- (NSString *)userNameForCrashManager:(BITCrashManager *)crashManager;` is now `- (NSString *)userNameForHockeyManager:(BITHockeyManager *)hockeyManager componentManager:(BITHockeyBaseManager *)componentManager;` + - `- (NSString *)userEmailForCrashManager:(BITCrashManager *)crashManager;` is now `- (NSString *)userEmailForHockeyManager:(BITHockeyManager *)hockeyManager componentManager:(BITHockeyBaseManager *)componentManager;` + - [BUGFIX] Moved calculation of time interval between startup and crash further up in the code, so delegates can use this information e.g. to add it into a log file + - [BUGFIX] If a crash was detected but could not be read (if handling crashes on startup is implemented), the delegate is still called + - [BUGFIX] Timestamp in crash report is now always UTC in en_US locale + - [BUGFIX] Make sure crash reports incident identifier and key don't have special [] chars and some value +

+ +- Feedback + + - [NEW] User feedback interface for direct communication with your users + - [NEW] iOS 6 UIActivity component for integrating feedback + - [NEW] When first opening the feedback list view, user details and show compose screen are automatically shown +

+ +- Updating + + - [NEW] Support for In-App updates without changing `CFBundleVersion` + - [UPDATE] Update UI modified to be more iOS 6 alike + - [UPDATE] Update UI shows the company name next to the app name if defined in the backend + - [UPDATE] Updated integration and migration documentation: [Installation & Setup](http://www.hockeyapp.net/help/sdk/ios/3.0.0/docs/docs/Guide-Installation-Setup.html) (Recommended), [Installation & Setup Advanced](http://www.hockeyapp.net/help/sdk/ios/3.0.0/docs/docs/Guide-Installation-Setup-Advanced.html) (Using Git submodule and Xcode sub-project), [Migration from previous SDK Versions](http://www.hockeyapp.net/help/sdk/ios/3.0.0/docs/docs/Guide-Migration-Kits.html) + + - [BUGFIX] Fixed a problem showing the update UI animated if there TTNavigator class is present even though not being used + +--- ### Version 3.0.0 RC 1 From f25d27aa73a1fbb0e2becb98a91003c68c553307 Mon Sep 17 00:00:00 2001 From: Andreas Linde Date: Tue, 12 Feb 2013 15:02:21 +0100 Subject: [PATCH 175/176] More documentation improvements --- Classes/HockeySDK.h | 11 +++-------- README.md | 2 +- docs/Changelog-template.md | 4 ++++ docs/Guide-Migration-Kits-template.md | 4 ++-- 4 files changed, 10 insertions(+), 11 deletions(-) diff --git a/Classes/HockeySDK.h b/Classes/HockeySDK.h index fb660145..7480fa95 100644 --- a/Classes/HockeySDK.h +++ b/Classes/HockeySDK.h @@ -51,7 +51,7 @@ #define BITHockeyNetworkDidBecomeReachableNotification @"BITHockeyNetworkDidBecomeReachable" -// hockey api error domain +// hockey crash reporting api error domain typedef enum { BITCrashErrorUnknown, BITCrashAPIAppVersionRejected, @@ -60,9 +60,7 @@ typedef enum { } BITCrashErrorReason; extern NSString *const __attribute__((unused)) kBITCrashErrorDomain; -// Update App Versions - -// hockey api error domain +// hockey update api error domain typedef enum { BITUpdateErrorUnknown, BITUpdateAPIServerReturnedInvalidStatus, @@ -74,9 +72,7 @@ typedef enum { extern NSString *const __attribute__((unused)) kBITUpdateErrorDomain; -// Update App Versions - -// hockey api error domain +// hockey feedback api error domain typedef enum { BITFeedbackErrorUnknown, BITFeedbackAPIServerReturnedInvalidStatus, @@ -90,7 +86,6 @@ extern NSString *const __attribute__((unused)) kBITFeedbackErrorDomain; // HockeySDK -// hockey api error domain typedef enum { BITHockeyErrorUnknown, HockeyAPIClientMissingJSONLibrary diff --git a/README.md b/README.md index e0ff5508..378b4075 100644 --- a/README.md +++ b/README.md @@ -28,7 +28,7 @@ The main SDK class is `BITHockeyManager`. It initializes all modules and provide - [Installation & Setup](http://www.hockeyapp.net/help/sdk/ios/3.0.0/docs/docs/Guide-Installation-Setup.html) (Recommended) - [Installation & Setup Advanced](http://www.hockeyapp.net/help/sdk/ios/3.0.0/docs/docs/Guide-Installation-Setup-Advanced.html) (Using Git submodule and Xcode sub-project) -- [Migration from HockeyKit & QuincyKit](http://www.hockeyapp.net/help/sdk/ios/3.0.0/docs/docs/Guide-Migration-Kits.html) +- [Migration from previous SDK Versions](http://www.hockeyapp.net/help/sdk/ios/3.0.0/docs/docs/Guide-Migration-Kits.html) - [Mac Desktop Uploader](http://support.hockeyapp.net/kb/how-tos/how-to-upload-to-hockeyapp-on-a-mac) diff --git a/docs/Changelog-template.md b/docs/Changelog-template.md index b4b9b638..a5939cdd 100644 --- a/docs/Changelog-template.md +++ b/docs/Changelog-template.md @@ -8,6 +8,10 @@ - [NEW] Added localizations provided by [Wordcrafts.de](http://wordcrafts.de): Chinese, English, French, German, Italian, Japanese, Portuguese, Brazilian-Portuguese, Russian, Spanish - [NEW] Added Romanian, Hungarian localization + - [UPDATE] Updated integration and migration documentation + - [Installation & Setup](http://www.hockeyapp.net/help/sdk/ios/3.0.0/docs/docs/Guide-Installation-Setup.html) (Recommended) + - [Installation & Setup Advanced](http://www.hockeyapp.net/help/sdk/ios/3.0.0/docs/docs/Guide-Installation-Setup-Advanced.html) (Using Git submodule and Xcode sub-project) + - [Migration from previous SDK Versions](http://www.hockeyapp.net/help/sdk/ios/3.0.0/docs/docs/Guide-Migration-Kits.html) - [UPDATE] Using embedded.framework for binary distribution containing everything needed in one package - [UPDATE] Improved Xcode project setup to only use one static library - [UPDATE] Providing build settings as `HockeySDK.xcconfig` file for easier setup diff --git a/docs/Guide-Migration-Kits-template.md b/docs/Guide-Migration-Kits-template.md index 60a242ab..0d732ec6 100644 --- a/docs/Guide-Migration-Kits-template.md +++ b/docs/Guide-Migration-Kits-template.md @@ -10,7 +10,7 @@ First of all you should remove all files from prior versions of either QuincyKit ### QuincyKit -In Xcode open the `Project Navigator` (⌘+1). In the search field at the bottom enter "Quincy". Search should find the following files: +In Xcode open the `Project Navigator` (⌘+1). In the search field at the bottom enter "Quincy". QuincyKit is installed, if search finds the following files: * BWQuincyManager.h * BWQuincyManager.m @@ -20,7 +20,7 @@ Delete them all ("Move to Trash"). Or if you have them grouped into a folder (fo ### HockeyKit -In Xcode open the `Project Navigator` (⌘+1). In the search field at the bottom enter "Hockey". You should find different files with the string "Hockey" in it, for example: +In Xcode open the `Project Navigator` (⌘+1). In the search field at the bottom enter "Hockey". HockeyKit is installed, if search finds for example: * BWHockeyManager.h * Hockey.bundle From 2fc559403e38d00beb9bf9419805b174d08aaba6 Mon Sep 17 00:00:00 2001 From: Andreas Linde Date: Tue, 12 Feb 2013 16:28:47 +0100 Subject: [PATCH 176/176] Bump version to 3.0.0 build 17 --- Support/buildnumber.xcconfig | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Support/buildnumber.xcconfig b/Support/buildnumber.xcconfig index 89aa7300..665c3220 100644 --- a/Support/buildnumber.xcconfig +++ b/Support/buildnumber.xcconfig @@ -1,5 +1,5 @@ #include "HockeySDK.xcconfig" -BUILD_NUMBER = 16 -VERSION_STRING = 3.0.0RC1 -GCC_PREPROCESSOR_DEFINITIONS = $(inherited) BITHOCKEY_VERSION="@\"3.0.0RC1\"" +BUILD_NUMBER = 17 +VERSION_STRING = 3.0.0 +GCC_PREPROCESSOR_DEFINITIONS = $(inherited) BITHOCKEY_VERSION="@\"3.0.0\""