diff --git a/.gitmodules b/.gitmodules index 34a6177f..8826ade3 100644 --- a/.gitmodules +++ b/.gitmodules @@ -7,3 +7,6 @@ [submodule "External/iCloudStoreManager"] path = External/iCloudStoreManager url = git://github.com/alekseyn/iCloudStoreManager.git +[submodule "External/apptentive"] + path = External/apptentive + url = git://github.com/apptentive/apptentive-ios.git diff --git a/Apptentive/Apptentive.plist b/Apptentive/Apptentive.plist new file mode 100644 index 00000000..efa55526 --- /dev/null +++ b/Apptentive/Apptentive.plist @@ -0,0 +1,8 @@ + + + + + API Key + + + diff --git a/External/Pearl b/External/Pearl index fea9295f..f92b0b14 160000 --- a/External/Pearl +++ b/External/Pearl @@ -1 +1 @@ -Subproject commit fea9295f84e16534f70b616e622946bdd518f27e +Subproject commit f92b0b1490e483d1bd4b8b6d1b9482c7ecfd4e44 diff --git a/External/apptentive b/External/apptentive new file mode 160000 index 00000000..3b6635e1 --- /dev/null +++ b/External/apptentive @@ -0,0 +1 @@ +Subproject commit 3b6635e131d19f049fec1fd943afd89855185d39 diff --git a/MasterPassword-iOS.xcodeproj/project.pbxproj b/MasterPassword-iOS.xcodeproj/project.pbxproj index 990a4420..9595b487 100644 --- a/MasterPassword-iOS.xcodeproj/project.pbxproj +++ b/MasterPassword-iOS.xcodeproj/project.pbxproj @@ -74,6 +74,10 @@ DA95D5F614DF0B9F008D1B94 /* IASKPSTextFieldSpecifierViewCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = DA95D5CC14DF0691008D1B94 /* IASKPSTextFieldSpecifierViewCell.xib */; }; DA95D5F714DF0B9F008D1B94 /* IASKPSToggleSwitchSpecifierViewCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = DA95D5CD14DF0691008D1B94 /* IASKPSToggleSwitchSpecifierViewCell.xib */; }; DA95D5F814DF0B9F008D1B94 /* IASKSpecifierValuesView.xib in Resources */ = {isa = PBXBuildFile; fileRef = DA95D5CE14DF0691008D1B94 /* IASKSpecifierValuesView.xib */; }; + DAAC35DB156BD62F00C5FD93 /* libApptentiveConnect.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DAAC35D2156BD51600C5FD93 /* libApptentiveConnect.a */; }; + DAAC35DC156BD66800C5FD93 /* ApptentiveResources.bundle in Resources */ = {isa = PBXBuildFile; fileRef = DAAC35D6156BD51600C5FD93 /* ApptentiveResources.bundle */; }; + DAAC35DE156BD77D00C5FD93 /* CoreTelephony.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DAAC35DD156BD77D00C5FD93 /* CoreTelephony.framework */; }; + DAAC35E4156BDBA700C5FD93 /* Apptentive.plist in Resources */ = {isa = PBXBuildFile; fileRef = DAAC35E2156BDBA700C5FD93 /* Apptentive.plist */; }; DAB8D45D15036BCF00CED3BC /* MasterPassword.xcdatamodeld in Sources */ = {isa = PBXBuildFile; fileRef = DAB8D43C15036BCF00CED3BC /* MasterPassword.xcdatamodeld */; }; DAB8D45E15036BCF00CED3BC /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = DAB8D43F15036BCF00CED3BC /* InfoPlist.strings */; }; DAB8D45F15036BCF00CED3BC /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = DAB8D44115036BCF00CED3BC /* main.m */; }; @@ -858,6 +862,41 @@ remoteGlobalIDString = DA67FE5D14E4834300DB7CC9; remoteInfo = util; }; + DAAC35D1156BD51600C5FD93 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = DAAC35C8156BD51500C5FD93 /* ApptentiveConnect.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = 496DC37F1333D35600743F65; + remoteInfo = ApptentiveConnect; + }; + DAAC35D3156BD51600C5FD93 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = DAAC35C8156BD51500C5FD93 /* ApptentiveConnect.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = 496DC38C1333D35600743F65; + remoteInfo = ApptentiveConnectTests; + }; + DAAC35D5156BD51600C5FD93 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = DAAC35C8156BD51500C5FD93 /* ApptentiveConnect.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = 49D1118C13341A7C00603373; + remoteInfo = ApptentiveResources; + }; + DAAC35D7156BD61D00C5FD93 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = DAAC35C8156BD51500C5FD93 /* ApptentiveConnect.xcodeproj */; + proxyType = 1; + remoteGlobalIDString = 496DC37E1333D35600743F65; + remoteInfo = ApptentiveConnect; + }; + DAAC35D9156BD61D00C5FD93 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = DAAC35C8156BD51500C5FD93 /* ApptentiveConnect.xcodeproj */; + proxyType = 1; + remoteGlobalIDString = 49D1118B13341A7C00603373; + remoteInfo = ApptentiveResources; + }; DAC63283148681200075AEA5 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = DA5BFA3B147E415C00F98B1E /* Project object */; @@ -943,6 +982,11 @@ DA95D5CD14DF0691008D1B94 /* IASKPSToggleSwitchSpecifierViewCell.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = IASKPSToggleSwitchSpecifierViewCell.xib; sourceTree = ""; }; DA95D5CE14DF0691008D1B94 /* IASKSpecifierValuesView.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = IASKSpecifierValuesView.xib; sourceTree = ""; }; DA95D5F014DF0B1E008D1B94 /* MessageUI.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = MessageUI.framework; path = System/Library/Frameworks/MessageUI.framework; sourceTree = SDKROOT; }; + DAAC35C8156BD51500C5FD93 /* ApptentiveConnect.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = ApptentiveConnect.xcodeproj; path = External/apptentive/ApptentiveConnect/ApptentiveConnect.xcodeproj; sourceTree = ""; }; + DAAC35DD156BD77D00C5FD93 /* CoreTelephony.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreTelephony.framework; path = System/Library/Frameworks/CoreTelephony.framework; sourceTree = SDKROOT; }; + DAAC35E2156BDBA700C5FD93 /* Apptentive.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Apptentive.plist; sourceTree = ""; }; + DAAC35E5156BDBC100C5FD93 /* ATConnect.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ATConnect.h; path = ../External/apptentive/ApptentiveConnect/source/ATConnect.h; sourceTree = ""; }; + DAAC35E6156BDF0E00C5FD93 /* ATAppRatingFlow.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ATAppRatingFlow.h; path = "../External/apptentive/ApptentiveConnect/source/Rating Flow/ATAppRatingFlow.h"; sourceTree = ""; }; DAB8D43D15036BCF00CED3BC /* MasterPassword.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = MasterPassword.xcdatamodel; sourceTree = ""; }; DAB8D44015036BCF00CED3BC /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = ""; }; DAB8D44115036BCF00CED3BC /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; @@ -1731,6 +1775,8 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + DAAC35DE156BD77D00C5FD93 /* CoreTelephony.framework in Frameworks */, + DAAC35DB156BD62F00C5FD93 /* libApptentiveConnect.a in Frameworks */, DA44260A1557D9E40052177D /* libiCloudStoreManager.a in Frameworks */, DAD312C21552A22700A3F9ED /* libsqlite3.dylib in Frameworks */, DAD312BF1552A1BD00A3F9ED /* libLocalytics.a in Frameworks */, @@ -1810,6 +1856,7 @@ DA5BFA39147E415C00F98B1E = { isa = PBXGroup; children = ( + DAAC35C8156BD51500C5FD93 /* ApptentiveConnect.xcodeproj */, DA79A9BD1557DDC700BAA07A /* scrypt.xcodeproj */, DA5BFA50147E415C00F98B1E /* MasterPassword */, DAB8D46F15036BF600CED3BC /* Resources */, @@ -1821,6 +1868,7 @@ DAD3125E15528C9C00A3F9ED /* Crashlytics */, DAD3126115528C9C00A3F9ED /* TestFlight */, DAD3127315528CD200A3F9ED /* Localytics */, + DAAC35E0156BDBA700C5FD93 /* Apptentive */, DA4425D71557BF260052177D /* iCloudStoreManager */, DA5BFA47147E415C00F98B1E /* Frameworks */, DA5BFA45147E415C00F98B1E /* Products */, @@ -1844,6 +1892,7 @@ DA5BFA47147E415C00F98B1E /* Frameworks */ = { isa = PBXGroup; children = ( + DAAC35DD156BD77D00C5FD93 /* CoreTelephony.framework */, DAD312C01552A20800A3F9ED /* libsqlite3.dylib */, DA95D5F014DF0B1E008D1B94 /* MessageUI.framework */, DABB981515100B4000B05417 /* SystemConfiguration.framework */, @@ -1973,6 +2022,26 @@ path = External/InAppSettingsKit/InAppSettingsKit/Xibs; sourceTree = SOURCE_ROOT; }; + DAAC35C9156BD51500C5FD93 /* Products */ = { + isa = PBXGroup; + children = ( + DAAC35D2156BD51600C5FD93 /* libApptentiveConnect.a */, + DAAC35D4156BD51600C5FD93 /* ApptentiveConnectTests.octest */, + DAAC35D6156BD51600C5FD93 /* ApptentiveResources.bundle */, + ); + name = Products; + sourceTree = ""; + }; + DAAC35E0156BDBA700C5FD93 /* Apptentive */ = { + isa = PBXGroup; + children = ( + DAAC35E6156BDF0E00C5FD93 /* ATAppRatingFlow.h */, + DAAC35E5156BDBC100C5FD93 /* ATConnect.h */, + DAAC35E2156BDBA700C5FD93 /* Apptentive.plist */, + ); + path = Apptentive; + sourceTree = ""; + }; DAB8D43E15036BCF00CED3BC /* iOS */ = { isa = PBXGroup; children = ( @@ -3073,6 +3142,8 @@ buildRules = ( ); dependencies = ( + DAAC35D8156BD61D00C5FD93 /* PBXTargetDependency */, + DAAC35DA156BD61D00C5FD93 /* PBXTargetDependency */, ); name = MasterPassword; productName = MasterPassword; @@ -3189,6 +3260,10 @@ productRefGroup = DA5BFA45147E415C00F98B1E /* Products */; projectDirPath = ""; projectReferences = ( + { + ProductGroup = DAAC35C9156BD51500C5FD93 /* Products */; + ProjectRef = DAAC35C8156BD51500C5FD93 /* ApptentiveConnect.xcodeproj */; + }, { ProductGroup = DA79A9BE1557DDC700BAA07A /* Products */; ProjectRef = DA79A9BD1557DDC700BAA07A /* scrypt.xcodeproj */; @@ -3229,6 +3304,27 @@ remoteRef = DA79A9D11557DDC800BAA07A /* PBXContainerItemProxy */; sourceTree = BUILT_PRODUCTS_DIR; }; + DAAC35D2156BD51600C5FD93 /* libApptentiveConnect.a */ = { + isa = PBXReferenceProxy; + fileType = archive.ar; + path = libApptentiveConnect.a; + remoteRef = DAAC35D1156BD51600C5FD93 /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; + DAAC35D4156BD51600C5FD93 /* ApptentiveConnectTests.octest */ = { + isa = PBXReferenceProxy; + fileType = wrapper.cfbundle; + path = ApptentiveConnectTests.octest; + remoteRef = DAAC35D3156BD51600C5FD93 /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; + DAAC35D6156BD51600C5FD93 /* ApptentiveResources.bundle */ = { + isa = PBXReferenceProxy; + fileType = wrapper.cfbundle; + path = ApptentiveResources.bundle; + remoteRef = DAAC35D5156BD51600C5FD93 /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; /* End PBXReferenceProxy section */ /* Begin PBXResourcesBuildPhase section */ @@ -3237,6 +3333,7 @@ buildActionMask = 2147483647; files = ( DAB8D97C1503718B00CED3BC /* jquery-1.6.1.min.js in Resources */, + DAAC35DC156BD66800C5FD93 /* ApptentiveResources.bundle in Resources */, DA95D5F314DF0B9B008D1B94 /* IASKAppSettingsView.xib in Resources */, DA95D5F414DF0B9F008D1B94 /* IASKAppSettingsWebView.xib in Resources */, DA95D5F514DF0B9F008D1B94 /* IASKPSSliderSpecifierViewCell.xib in Resources */, @@ -3897,6 +3994,7 @@ DA0A1D1215690AD40092735D /* tip_arrow_wood.png in Resources */, DA0A1D1515690AF40092735D /* Icon-72@2x.png in Resources */, DA0A1D1615690AF40092735D /* Icon-Small-50@2x.png in Resources */, + DAAC35E4156BDBA700C5FD93 /* Apptentive.plist in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -4065,6 +4163,16 @@ name = "Makefile-scrypt"; targetProxy = DA4DA1D71564470200F6F596 /* PBXContainerItemProxy */; }; + DAAC35D8156BD61D00C5FD93 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = ApptentiveConnect; + targetProxy = DAAC35D7156BD61D00C5FD93 /* PBXContainerItemProxy */; + }; + DAAC35DA156BD61D00C5FD93 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = ApptentiveResources; + targetProxy = DAAC35D9156BD61D00C5FD93 /* PBXContainerItemProxy */; + }; DAC63284148681200075AEA5 /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = DAC6325C1486805C0075AEA5 /* uicolor-utilities */; diff --git a/MasterPassword/iOS/MPAppDelegate.m b/MasterPassword/iOS/MPAppDelegate.m index 6128bc7f..c208cba5 100644 --- a/MasterPassword/iOS/MPAppDelegate.m +++ b/MasterPassword/iOS/MPAppDelegate.m @@ -15,6 +15,8 @@ #import "LocalyticsSession.h" #import "TestFlight.h" #import +#import "ATConnect.h" +#import "ATAppRatingFlow.h" @interface MPAppDelegate () @@ -24,6 +26,9 @@ - (NSString *)crashlyticsInfo; - (NSString *)crashlyticsAPIKey; +- (NSString *)apptentiveInfo; +- (NSString *)apptentiveAPIKey; + - (NSString *)localyticsInfo; - (NSString *)localyticsKey; @@ -143,8 +148,8 @@ - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { -#ifndef DEBUG dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^{ +#ifndef DEBUG @try { NSString *testFlightToken = [self testFlightToken]; if ([testFlightToken length]) { @@ -200,9 +205,22 @@ @catch (NSException *exception) { err(@"Localytics exception: %@", exception); } - }); #endif - + }); + + @try { + NSString *apptentiveAPIKey = [self apptentiveAPIKey]; + if ([apptentiveAPIKey length]) { + dbg(@"Initializing Apptentive"); + ATConnect *connection = [ATConnect sharedConnection]; + connection.shouldTakeScreenshot = NO; + connection.apiKey = apptentiveAPIKey; + } + } + @catch (NSException *exception) { + err(@"Apptentive: %@", exception); + } + UIImage *navBarImage = [[UIImage imageNamed:@"ui_navbar_container"] resizableImageWithCapInsets:UIEdgeInsetsMake(0, 5, 0, 5)]; [[UINavigationBar appearance] setBackgroundImage:navBarImage forBarMetrics:UIBarMetricsDefault]; [[UINavigationBar appearance] setBackgroundImage:navBarImage forBarMetrics:UIBarMetricsLandscapePhone]; @@ -270,11 +288,19 @@ @"https://youtrack.lyndir.com\n" viewStyle:UIAlertViewStyleDefault tappedButtonBlock:nil cancelTitle:nil otherTitles:[PearlStrings get].commonButtonOkay, nil]; +#else + @try { + ATAppRatingFlow *sharedFlow = [ATAppRatingFlow sharedRatingFlowWithAppID:[PearlConfig get].iTunesID]; + [sharedFlow appDidLaunch:YES viewController:self.navigationController]; + } + @catch (NSException *exception) { + err(@"Apptentive: %@", exception); + } #endif [[UIApplication sharedApplication] setStatusBarHidden:NO withAnimation:UIStatusBarAnimationSlide]; - + return [super application:application didFinishLaunchingWithOptions:launchOptions]; } @@ -351,6 +377,11 @@ } [TestFlight passCheckpoint:MPTestFlightCheckpointActivated]; + + ATAppRatingFlow *sharedFlow = [ATAppRatingFlow sharedRatingFlowWithAppID:[PearlConfig get].iTunesID]; + [sharedFlow appDidEnterForeground:YES viewController:self.navigationController]; + + [super applicationDidBecomeActive:application]; } - (void)applicationDidEnterBackground:(UIApplication *)application { @@ -502,6 +533,25 @@ } +#pragma mark - Apptentive + + +- (NSDictionary *)apptentiveInfo { + + static NSDictionary *apptentiveInfo = nil; + if (apptentiveInfo == nil) + apptentiveInfo = [[NSDictionary alloc] initWithContentsOfURL: + [[NSBundle mainBundle] URLForResource:@"Apptentive" withExtension:@"plist"]]; + + return apptentiveInfo; +} + +- (NSString *)apptentiveAPIKey { + + return NullToNil([[self apptentiveInfo] valueForKeyPath:@"API Key"]); +} + + #pragma mark - Localytics diff --git a/MasterPassword/iOS/MPMainViewController.m b/MasterPassword/iOS/MPMainViewController.m index 3e740180..3b8d4a28 100644 --- a/MasterPassword/iOS/MPMainViewController.m +++ b/MasterPassword/iOS/MPMainViewController.m @@ -13,6 +13,7 @@ #import "MPElementGeneratedEntity.h" #import "MPElementStoredEntity.h" #import "IASKAppSettingsViewController.h" +#import "ATConnect.h" #import @@ -393,36 +394,43 @@ return; switch (buttonIndex - [sheet firstOtherButtonIndex]) { - case 0: + case 0: { [self toggleHelpAnimated:YES]; break; + } case 1: { [self setHelpChapter:@"faq"]; [self setHelpHidden:NO animated:YES]; break; } - case 2: + case 2: { [[MPAppDelegate get] showGuide]; break; - case 3: - { + } + case 3: { IASKAppSettingsViewController *settingsVC = [IASKAppSettingsViewController new]; settingsVC.delegate = self; [self.navigationController pushViewController:settingsVC animated:YES]; break; } - case 4: + case 4: { [[MPAppDelegate get] export]; break; + } #ifdef ADHOC - case 5: + case 5: { [TestFlight openFeedbackView]; break; - case 6: + } + case 6: { #else - case 5: + case 5: { + ATConnect *connection = [ATConnect sharedConnection]; + [connection presentFeedbackControllerFromViewController:self]; + break; + } + case 6: { #endif - { [[MPAppDelegate get] signOut:self]; [[MPAppDelegate get] loadKey:YES]; break; @@ -433,9 +441,7 @@ } cancelTitle:[PearlStrings get].commonButtonCancel destructiveTitle:nil otherTitles: [self isHelpVisible]? @"Hide Help": @"Show Help", @"FAQ", @"Tutorial", @"Settings", @"Export", -#ifdef ADHOC @"Feedback", -#endif @"Sign Out", nil]; }