2
0

Added "Other Apps".

[REMOVED]   Cleaned up some check points that weren't really useful.
[ADDED]     Added a few new checkpoints with new functionality.
[ADDED]     An "other apps" page that introduces Gorillas and DeBlock.
[IMPROVED]  Help is now toggled with a drag handle instead of an action
            button.
This commit is contained in:
Maarten Billemont
2012-09-01 14:57:55 +02:00
parent aa2d9eb202
commit d75ec5c689
24 changed files with 795 additions and 315 deletions

View File

@@ -64,9 +64,6 @@ static NSDictionary *keyQuery(MPUserEntity *user) {
inf(@"Removed key from keychain for: %@", user.userID);
[[NSNotificationCenter defaultCenter] postNotificationName:MPNotificationKeyForgotten object:self];
#ifdef TESTFLIGHT_SDK_VERSION
[TestFlight passCheckpoint:MPCheckpointForgetSavedKey];
#endif
}
}
}
@@ -130,9 +127,7 @@ static NSDictionary *keyQuery(MPUserEntity *user) {
if (password) {
inf(@"Login failed for: %@", user.userID);
#ifdef TESTFLIGHT_SDK_VERSION
[TestFlight passCheckpoint:MPCheckpointSignInFailed];
#endif
[[LocalyticsSession sharedLocalyticsSession] tagEvent:MPCheckpointSignInFailed attributes:nil];
}
@@ -163,11 +158,8 @@ static NSDictionary *keyQuery(MPUserEntity *user) {
[[MPAppDelegate_Shared get] saveContext];
[[NSNotificationCenter defaultCenter] postNotificationName:MPNotificationSignedIn object:self];
#ifdef TESTFLIGHT_SDK_VERSION
[TestFlight passCheckpoint:MPCheckpointSignedIn];
#endif
[[LocalyticsSession sharedLocalyticsSession] tagEvent:MPCheckpointSignedIn
attributes:nil];
[[LocalyticsSession sharedLocalyticsSession] tagEvent:MPCheckpointSignedIn attributes:nil];
return YES;
}

View File

@@ -136,9 +136,7 @@
iCloudEnabled = manager.iCloudEnabled;
inf(@"Using iCloud? %@", iCloudEnabled? @"YES": @"NO");
#ifdef TESTFLIGHT_SDK_VERSION
[TestFlight passCheckpoint:iCloudEnabled? MPCheckpointCloudEnabled: MPCheckpointCloudDisabled];
#endif
[[LocalyticsSession sharedLocalyticsSession] tagEvent:MPCheckpointCloud attributes:@{
@"enabled": iCloudEnabled? @"YES": @"NO"
}];
@@ -151,9 +149,12 @@
err(@"StoreManager: cause=%d, context=%@, error=%@", cause, context, error);
#ifdef TESTFLIGHT_SDK_VERSION
[TestFlight passCheckpoint:PearlString(@"MPCheckpointMPErrorUbiquity_%d", cause)];
#endif
[TestFlight passCheckpoint:PearlString(MPCheckpointMPErrorUbiquity @"_%d", cause)];
[[LocalyticsSession sharedLocalyticsSession] tagEvent:MPCheckpointMPErrorUbiquity attributes:@{
@"cause": @(cause),
@"error.domain": error.domain,
@"error.code": @(error.code)
}];
switch (cause) {
case UbiquityStoreManagerErrorCauseDeleteStore:
@@ -167,16 +168,14 @@
if (error.code == NSMigrationMissingSourceModelError) {
wrn(@"Resetting the local store.");
#ifdef TESTFLIGHT_SDK_VERSION
[TestFlight passCheckpoint:MPCheckpointLocalStoreIncompatible];
#endif
[[LocalyticsSession sharedLocalyticsSession] tagEvent:MPCheckpointLocalStoreIncompatible attributes:nil];
[TestFlight passCheckpoint:MPCheckpointLocalStoreReset];
[[LocalyticsSession sharedLocalyticsSession] tagEvent:MPCheckpointLocalStoreReset attributes:nil];
manager.hardResetEnabled = YES;
[manager hardResetLocalStorage];
Throw(@"Local store was reset, application must be restarted to use it.");
} else
// Try again.
// Try again.
[[self storeManager] persistentStoreCoordinator];
}
case UbiquityStoreManagerErrorCauseOpenCloudStore: {
@@ -185,15 +184,13 @@
if (error.code == NSMigrationMissingSourceModelError) {
wrn(@"Resetting the iCloud store.");
#ifdef TESTFLIGHT_SDK_VERSION
[TestFlight passCheckpoint:MPCheckpointCloudStoreIncompatible];
#endif
[[LocalyticsSession sharedLocalyticsSession] tagEvent:MPCheckpointCloudStoreIncompatible attributes:nil];
[TestFlight passCheckpoint:MPCheckpointCloudStoreReset];
[[LocalyticsSession sharedLocalyticsSession] tagEvent:MPCheckpointCloudStoreReset attributes:nil];
manager.hardResetEnabled = YES;
[manager hardResetCloudStorage];
break;
} else
// Try again.
// Try again.
[[self storeManager] persistentStoreCoordinator];
}
}
@@ -419,9 +416,7 @@
[self saveContext];
success = YES;
inf(@"Import completed successfully.");
#ifdef TESTFLIGHT_SDK_VERSION
[TestFlight passCheckpoint:MPCheckpointSitesImported];
#endif
[[LocalyticsSession sharedLocalyticsSession] tagEvent:MPCheckpointSitesImported attributes:nil];
return MPImportResultSuccess;
@@ -484,9 +479,7 @@
? content: @""];
}
#ifdef TESTFLIGHT_SDK_VERSION
[TestFlight passCheckpoint:MPCheckpointSitesExported];
#endif
[[LocalyticsSession sharedLocalyticsSession] tagEvent:MPCheckpointSitesExported attributes:nil];
return export;

View File

@@ -40,7 +40,6 @@ typedef enum {
MPElementTypeStoredDevicePrivate = 0x1 | MPElementTypeClassStored | MPElementFeatureDevicePrivate,
} MPElementType;
#define MPCheckpointAction @"MPCheckpointAction"
#define MPCheckpointHelpChapter @"MPCheckpointHelpChapter"
#define MPCheckpointCopyToPasteboard @"MPCheckpointCopyToPasteboard"
#define MPCheckpointCopyLoginNameToPasteboard @"MPCheckpointCopyLoginNameToPasteboard"
@@ -48,21 +47,13 @@ typedef enum {
#define MPCheckpointIncrementPasswordCounter @"MPCheckpointIncrementPasswordCounter"
#define MPCheckpointEditPassword @"MPCheckpointEditPassword"
#define MPCheckpointEditLoginName @"MPCheckpointEditLoginName"
#define MPCheckpointCloseAlert @"MPCheckpointCloseAlert"
#define MPCheckpointCloseOutdatedAlert @"MPCheckpointCloseOutdatedAlert"
#define MPCheckpointUseType @"MPCheckpointUseType"
#define MPCheckpointDeleteElement @"MPCheckpointDeleteElement"
#define MPCheckpointCancelSearch @"MPCheckpointCancelSearch"
#define MPCheckpointExternalLink @"MPCheckpointExternalLink"
#define MPCheckpointLaunched @"MPCheckpointLaunched"
#define MPCheckpointActivated @"MPCheckpointActivated"
#define MPCheckpointDeactivated @"MPCheckpointDeactivated"
#define MPCheckpointTerminated @"MPCheckpointTerminated"
#define MPCheckpointShowGuide @"MPCheckpointShowGuide"
#define MPCheckpointForgetSavedKey @"MPCheckpointForgetSavedKey"
#define MPCheckpointChangeMP @"MPCheckpointChangeMP"
#define MPCheckpointLocalStoreIncompatible @"MPCheckpointLocalStoreIncompatible"
#define MPCheckpointCloudStoreIncompatible @"MPCheckpointCloudStoreIncompatible"
#define MPCheckpointMPErrorUbiquity @"MPCheckpointMPErrorUbiquity"
#define MPCheckpointLocalStoreReset @"MPCheckpointLocalStoreReset"
#define MPCheckpointCloudStoreReset @"MPCheckpointCloudStoreReset"
#define MPCheckpointSignInFailed @"MPCheckpointSignInFailed"
#define MPCheckpointSignedIn @"MPCheckpointSignedIn"
#define MPCheckpointConfig @"MPCheckpointConfig"
@@ -72,6 +63,10 @@ typedef enum {
#define MPCheckpointSitesImported @"MPCheckpointSitesImported"
#define MPCheckpointSitesExported @"MPCheckpointSitesExported"
#define MPCheckpointExplicitMigration @"MPCheckpointExplicitMigration"
#define MPCheckpointReview @"MPCheckpointReview"
#define MPCheckpointApps @"MPCheckpointApps"
#define MPCheckpointAppGorillas @"MPCheckpointAppGorillas"
#define MPCheckpointAppDeBlock @"MPCheckpointAppDeBlock"
#define MPNotificationSignedIn @"MPNotificationKeySet"
#define MPNotificationSignedOut @"MPNotificationKeyUnset"

View File

@@ -215,8 +215,6 @@
[super application:application didFinishLaunchingWithOptions:launchOptions];
inf(@"Started up with device identifier: %@", [PearlKeyChain deviceIdentifier]);
[TestFlight passCheckpoint:MPCheckpointLaunched];
[[LocalyticsSession sharedLocalyticsSession] tagEvent:MPCheckpointLaunched];
return YES;
}
@@ -341,8 +339,6 @@
inf(@"Re-activated");
[[MPAppDelegate get] checkConfig];
[TestFlight passCheckpoint:MPCheckpointActivated];
if (FBSession.activeSession.state == FBSessionStateCreatedOpening)
// An old Facebook Login session that wasn't finished. Clean it up.
[FBSession.activeSession close];
@@ -370,8 +366,6 @@
[self saveContext];
[TestFlight passCheckpoint:MPCheckpointTerminated];
[[LocalyticsSession sharedLocalyticsSession] close];
[[LocalyticsSession sharedLocalyticsSession] upload];
@@ -387,8 +381,6 @@
if (![[MPiOSConfig get].rememberLogin boolValue])
[self signOutAnimated:NO];
[TestFlight passCheckpoint:MPCheckpointDeactivated];
}
#pragma mark - Behavior
@@ -456,11 +448,20 @@
[self.navigationController performSegueWithIdentifier:@"MP_Guide" sender:self];
[TestFlight passCheckpoint:MPCheckpointShowGuide];
[[LocalyticsSession sharedLocalyticsSession] tagEvent:MPCheckpointShowGuide attributes:nil];
}
- (void)showFeedback {
[self showFeedbackWithLogs:YES forVC:nil];
[self showFeedbackWithLogs:NO forVC:nil];
}
- (void)showReview {
[TestFlight passCheckpoint:MPCheckpointReview];
[[LocalyticsSession sharedLocalyticsSession] tagEvent:MPCheckpointReview attributes:nil];
[super showReview];
}
- (void)showFeedbackWithLogs:(BOOL)logs forVC:(UIViewController *)viewController {

View File

@@ -0,0 +1,26 @@
/**
* Copyright Maarten Billemont (http://www.lhunath.com, lhunath@lyndir.com)
*
* See the enclosed file LICENSE for license information (LGPLv3). If you did
* not receive this file, see http://www.gnu.org/licenses/lgpl-3.0.txt
*
* @author Maarten Billemont <lhunath@lyndir.com>
* @license http://www.gnu.org/licenses/lgpl-3.0.txt
*/
//
// MPAppViewController
//
// Created by Maarten Billemont on 2012-08-31.
// Copyright 2012 lhunath (Maarten Billemont). All rights reserved.
//
#import <Foundation/Foundation.h>
@interface MPAppViewController : UIViewController
- (IBAction)gorillas:(UIButton *)sender;
- (IBAction)deblock:(UIButton *)sender;
@end

View File

@@ -0,0 +1,43 @@
/**
* Copyright Maarten Billemont (http://www.lhunath.com, lhunath@lyndir.com)
*
* See the enclosed file LICENSE for license information (LGPLv3). If you did
* not receive this file, see http://www.gnu.org/licenses/lgpl-3.0.txt
*
* @author Maarten Billemont <lhunath@lyndir.com>
* @license http://www.gnu.org/licenses/lgpl-3.0.txt
*/
//
// MPAppViewController
//
// Created by Maarten Billemont on 2012-08-31.
// Copyright 2012 lhunath (Maarten Billemont). All rights reserved.
//
#import "MPAppViewController.h"
#import "LocalyticsSession.h"
@implementation MPAppViewController {
}
- (IBAction)gorillas:(UIButton *)sender {
[TestFlight passCheckpoint:MPCheckpointAppGorillas];
[[LocalyticsSession sharedLocalyticsSession] tagEvent:MPCheckpointAppGorillas attributes:nil];
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:@"http://itunes.apple.com/app/lyndir/gorillas/id302275459?mt=8"]];
}
- (IBAction)deblock:(UIButton *)sender {
[TestFlight passCheckpoint:MPCheckpointAppDeBlock];
[[LocalyticsSession sharedLocalyticsSession] tagEvent:MPCheckpointAppDeBlock attributes:nil];
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:@"http://itunes.apple.com/app/lyndir/deblock/id325058485?mt=8"]];
}
@end

View File

@@ -0,0 +1,27 @@
/**
* Copyright Maarten Billemont (http://www.lhunath.com, lhunath@lyndir.com)
*
* See the enclosed file LICENSE for license information (LGPLv3). If you did
* not receive this file, see http://www.gnu.org/licenses/lgpl-3.0.txt
*
* @author Maarten Billemont <lhunath@lyndir.com>
* @license http://www.gnu.org/licenses/lgpl-3.0.txt
*/
//
// MPAppsViewController
//
// Created by Maarten Billemont on 2012-08-31.
// Copyright 2012 lhunath (Maarten Billemont). All rights reserved.
//
#import <Foundation/Foundation.h>
@interface MPAppsViewController : UIViewController <UIPageViewControllerDataSource, UIPageViewControllerDelegate>
@property (weak, nonatomic) IBOutlet UIImageView *pagePositionView;
- (IBAction)exit;
@end

View File

@@ -0,0 +1,115 @@
/**
* Copyright Maarten Billemont (http://www.lhunath.com, lhunath@lyndir.com)
*
* See the enclosed file LICENSE for license information (LGPLv3). If you did
* not receive this file, see http://www.gnu.org/licenses/lgpl-3.0.txt
*
* @author Maarten Billemont <lhunath@lyndir.com>
* @license http://www.gnu.org/licenses/lgpl-3.0.txt
*/
//
// MPAppsViewController
//
// Created by Maarten Billemont on 2012-08-31.
// Copyright 2012 lhunath (Maarten Billemont). All rights reserved.
//
#import "MPAppsViewController.h"
#import "LocalyticsSession.h"
@interface MPAppsViewController ()
@property (nonatomic, strong) NSMutableArray *pageVCs;
@property (nonatomic, strong) UIPageViewController *pageViewController;
@end
@implementation MPAppsViewController {
}
@synthesize pagePositionView = _pagePositionView;
@synthesize pageVCs = _pageVCs;
@synthesize pageViewController = _pageViewController;
- (void)viewDidLoad {
self.pageVCs = [NSMutableArray array];
UIViewController *vc;
@try {
for (NSUInteger p = 0;
(vc = [self.storyboard instantiateViewControllerWithIdentifier:PearlString(@"MPAppViewController_%u", p)]);
++p)
[self.pageVCs addObject:vc];
}
@catch (NSException *e) {
if (![e.name isEqualToString:NSInvalidArgumentException])
[e raise];
}
self.pageViewController = [[UIPageViewController alloc] initWithTransitionStyle:UIPageViewControllerTransitionStylePageCurl
navigationOrientation:UIPageViewControllerNavigationOrientationHorizontal
options:nil];
self.pageViewController.dataSource = self;
self.pageViewController.delegate = self;
[self addChildViewController:self.pageViewController];
[self.view addSubview:self.pageViewController.view];
self.pageViewController.view.frame = self.pagePositionView.frame;
[self.pagePositionView removeFromSuperview];
[self.pageViewController didMoveToParentViewController:self];
[self.pageViewController setViewControllers:@[[self.pageVCs objectAtIndex:0]] direction:UIPageViewControllerNavigationDirectionForward
animated:NO completion:nil];
[super viewDidLoad];
}
- (void)viewWillAppear:(BOOL)animated {
[[UIApplication sharedApplication] setStatusBarHidden:YES withAnimation:UIStatusBarAnimationSlide];
[TestFlight passCheckpoint:MPCheckpointApps];
[[LocalyticsSession sharedLocalyticsSession] tagEvent:MPCheckpointApps attributes:nil];
[super viewWillAppear:animated];
}
- (void)viewWillDisappear:(BOOL)animated {
[[UIApplication sharedApplication] setStatusBarHidden:NO withAnimation:UIStatusBarAnimationSlide];
[super viewWillDisappear:animated];
}
- (UIViewController *)pageViewController:(UIPageViewController *)pageViewController
viewControllerBeforeViewController:(UIViewController *)viewController {
NSUInteger vcIndex = [self.pageVCs indexOfObject:viewController];
return [self.pageVCs objectAtIndex:(vcIndex + [self.pageVCs count] - 1) % self.pageVCs.count];
}
- (UIViewController *)pageViewController:(UIPageViewController *)pageViewController
viewControllerAfterViewController:(UIViewController *)viewController {
NSUInteger vcIndex = [self.pageVCs indexOfObject:viewController];
UIPageViewController *vc = [self.pageVCs objectAtIndex:(vcIndex + 1) % self.pageVCs.count];
return vc;
}
- (void)viewDidUnload {
[self setPagePositionView:nil];
[super viewDidUnload];
}
- (IBAction)exit {
[self dismissViewControllerAnimated:YES completion:nil];
}
@end

View File

@@ -46,6 +46,8 @@
@property (weak, nonatomic) IBOutlet UIView *outdatedAlertContainer;
@property (weak, nonatomic) IBOutlet UIImageView *outdatedAlertBack;
@property (weak, nonatomic) IBOutlet UIButton *outdatedAlertCloseButton;
@property (weak, nonatomic) IBOutlet UIImageView *pullUpView;
@property (weak, nonatomic) IBOutlet UIImageView *pullDownView;
@property (copy, nonatomic) void (^contentTipCleanup)(BOOL finished);
@@ -67,5 +69,7 @@
- (void)toggleHelpAnimated:(BOOL)animated;
- (void)setHelpHidden:(BOOL)hidden animated:(BOOL)animated;
- (void)setHelpChapter:(NSString *)chapter;
- (IBAction)panHelpDown:(UIPanGestureRecognizer *)sender;
- (IBAction)panHelpUp:(UIPanGestureRecognizer *)sender;
@end

View File

@@ -46,6 +46,8 @@
@synthesize outdatedAlertContainer = _outdatedAlertContainer;
@synthesize outdatedAlertBack = _outdatedAlertBack;
@synthesize outdatedAlertCloseButton = _outdatedAlertCloseButton;
@synthesize pullUpView = _pullUpView;
@synthesize pullDownView = _pullDownView;
@synthesize contentField = _contentField;
@synthesize contentTipCleanup = _contentTipCleanup, toolTipCleanup = _toolTipCleanup;
@@ -241,6 +243,8 @@
[self setOutdatedAlertContainer:nil];
[self setOutdatedAlertCloseButton:nil];
[self setOutdatedAlertBack:nil];
[self setPullUpView:nil];
[self setPullDownView:nil];
[super viewDidUnload];
}
@@ -324,13 +328,15 @@
return;
}
self.pullUpView.hidden = ![[MPiOSConfig get].helpHidden boolValue];
self.pullDownView.hidden = [[MPiOSConfig get].helpHidden boolValue];
if ([[MPiOSConfig get].helpHidden boolValue]) {
self.contentContainer.frame = CGRectSetHeight(self.contentContainer.frame, self.view.bounds.size.height - 44 /* search bar */);
self.helpContainer.frame = CGRectSetY(self.helpContainer.frame,
self.view.bounds.size.height + 20 /* view moves up a bit when search appears. */);
self.helpContainer.frame = CGRectSetY(self.helpContainer.frame, self.view.bounds.size.height - 20);
} else {
self.contentContainer.frame = CGRectSetHeight(self.contentContainer.frame, 225);
self.helpContainer.frame = CGRectSetY(self.helpContainer.frame, 266);
self.helpContainer.frame = CGRectSetY(self.helpContainer.frame, 246);
}
}
@@ -366,6 +372,7 @@
- (void)setHelpChapter:(NSString *)chapter {
[TestFlight passCheckpoint:PearlString(MPCheckpointHelpChapter @"_%@", chapter)];
[[LocalyticsSession sharedLocalyticsSession] tagEvent:MPCheckpointHelpChapter attributes:@{@"chapter": chapter}];
dispatch_async(dispatch_get_main_queue(), ^{
NSURL *url = [NSURL URLWithString:[@"#" stringByAppendingString:chapter]
@@ -374,6 +381,36 @@
});
}
- (IBAction)panHelpDown:(UIPanGestureRecognizer *)sender {
CGFloat targetY = MIN(self.view.bounds.size.height - 20, 246 + [sender translationInView:self.helpContainer].y);
BOOL hideHelp = YES;
if (targetY <= 246) {
hideHelp = NO;
targetY = 246;
}
self.helpContainer.frame = CGRectSetY(self.helpContainer.frame, targetY);
if (sender.state == UIGestureRecognizerStateEnded)
[self setHelpHidden:hideHelp animated:YES];
}
- (IBAction)panHelpUp:(UIPanGestureRecognizer *)sender {
CGFloat targetY = MAX(246, self.view.bounds.size.height - 20 + [sender translationInView:self.helpContainer].y);
BOOL hideHelp = NO;
if (targetY >= self.view.bounds.size.height - 20) {
hideHelp = YES;
targetY = self.view.bounds.size.height - 20 ;
}
self.helpContainer.frame = CGRectSetY(self.helpContainer.frame, targetY);
if (sender.state == UIGestureRecognizerStateEnded)
[self setHelpHidden:hideHelp animated:YES];
}
- (void)webViewDidFinishLoad:(UIWebView *)webView {
NSString *error = [self.helpView stringByEvaluatingJavaScriptFromString:
@@ -655,8 +692,6 @@
if (finished)
self.alertBody.text = nil;
}];
[TestFlight passCheckpoint:MPCheckpointCloseAlert];
}
- (IBAction)closeOutdatedAlert {
@@ -664,8 +699,6 @@
[UIView animateWithDuration:0.3f animations:^{
self.outdatedAlertContainer.alpha = 0;
}];
[TestFlight passCheckpoint:MPCheckpointCloseOutdatedAlert];
}
- (IBAction)infoOutdatedAlert {
@@ -686,26 +719,26 @@
switch (buttonIndex - [sheet firstOtherButtonIndex]) {
case 0: {
inf(@"Action: Toggle Help");
[self toggleHelpAnimated:YES];
break;
}
case 1: {
inf(@"Action: FAQ");
[self setHelpChapter:@"faq"];
[self setHelpHidden:NO animated:YES];
break;
}
case 2: {
case 1: {
inf(@"Action: Guide");
[[MPAppDelegate get] showGuide];
break;
}
case 3: {
case 2: {
inf(@"Action: Preferences");
[self performSegueWithIdentifier:@"UserProfile" sender:self];
break;
}
case 3: {
inf(@"Action: Other Apps");
[self performSegueWithIdentifier:@"OtherApps" sender:self];
break;
}
#ifdef ADHOC
case 4: {
inf(@"Action: Feedback via TestFlight");
@@ -732,11 +765,9 @@
break;
}
}
[TestFlight passCheckpoint:MPCheckpointAction];
}
cancelTitle:[PearlStrings get].commonButtonCancel destructiveTitle:nil otherTitles:
[[MPiOSConfig get].helpHidden boolValue]? @"Show Help": @"Hide Help", @"FAQ", @"Tutorial", @"Preferences", @"Feedback", @"Sign Out",
@"FAQ", @"Tutorial", @"Preferences", @"Other Apps", @"Feedback", @"Sign Out",
nil];
}
@@ -872,8 +903,6 @@
return NO;
}
[TestFlight passCheckpoint:MPCheckpointExternalLink];
[[UIApplication sharedApplication] openURL:[request URL]];
return NO;
}

View File

@@ -90,8 +90,6 @@
- (void)searchBarCancelButtonClicked:(UISearchBar *)searchBar {
[TestFlight passCheckpoint:MPCheckpointCancelSearch];
[self.delegate didSelectElement:nil];
}

File diff suppressed because it is too large Load Diff