2
0

Improve notification registration and cleanup + fix removal of site questions.

This commit is contained in:
Maarten Billemont 2014-09-27 01:27:05 -04:00
parent 44f91e0618
commit 5db083bf7c
14 changed files with 226 additions and 339 deletions

2
External/Pearl vendored

@ -1 +1 @@
Subproject commit fb7562df9c3a59e8ac21e492b8eac0abcf5aa46e Subproject commit c4620deda26475ae4320d9af5b2df4ff96c9093e

View File

@ -192,22 +192,19 @@ PearlAssociatedObjectProperty( NSManagedObjectContext*, MainManagedObjectContext
}]; }];
#if TARGET_OS_IPHONE #if TARGET_OS_IPHONE
[[NSNotificationCenter defaultCenter] addObserverForName:UIApplicationWillTerminateNotification object:UIApp PearlAddNotificationObserver( UIApplicationWillTerminateNotification, UIApp, [NSOperationQueue mainQueue],
queue:[NSOperationQueue mainQueue] usingBlock: ^(MPAppDelegate_Shared *self, NSNotification *note) {
^(NSNotification *note) { [self.mainManagedObjectContext saveToStore];
[self.mainManagedObjectContext saveToStore]; } );
}]; PearlAddNotificationObserver( UIApplicationDidEnterBackgroundNotification, UIApp, [NSOperationQueue mainQueue],
[[NSNotificationCenter defaultCenter] addObserverForName:UIApplicationDidEnterBackgroundNotification object:UIApp ^(MPAppDelegate_Shared *self, NSNotification *note) {
queue:[NSOperationQueue mainQueue] usingBlock: [self.mainManagedObjectContext saveToStore];
^(NSNotification *note) { } );
[self.mainManagedObjectContext saveToStore];
}];
#else #else
[[NSNotificationCenter defaultCenter] addObserverForName:NSApplicationWillTerminateNotification object:NSApp PearlAddNotificationObserver( NSApplicationWillTerminateNotification, NSApp, [NSOperationQueue mainQueue],
queue:[NSOperationQueue mainQueue] usingBlock: ^(MPAppDelegate_Shared *self, NSNotification *note) {
^(NSNotification *note) { [self.mainManagedObjectContext saveToStore];
[self.mainManagedObjectContext saveToStore]; } );
}];
#endif #endif
// Perform a data sanity check on the newly loaded store to find and fix any issues. // Perform a data sanity check on the newly loaded store to find and fix any issues.
@ -528,7 +525,7 @@ PearlAssociatedObjectProperty( NSManagedObjectContext*, MainManagedObjectContext
return MPImportResultMalformedInput; return MPImportResultMalformedInput;
} }
NSTextCheckingResult *headerSites = [[headerPattern matchesInString:importedSiteLine options:(NSMatchingOptions)0 NSTextCheckingResult *headerSites = [[headerPattern matchesInString:importedSiteLine options:(NSMatchingOptions)0
range:NSMakeRange( 0, [importedSiteLine length] )] lastObject]; range:NSMakeRange( 0, [importedSiteLine length] )] lastObject];
NSString *headerName = [importedSiteLine substringWithRange:[headerSites rangeAtIndex:1]]; NSString *headerName = [importedSiteLine substringWithRange:[headerSites rangeAtIndex:1]];
NSString *headerValue = [importedSiteLine substringWithRange:[headerSites rangeAtIndex:2]]; NSString *headerValue = [importedSiteLine substringWithRange:[headerSites rangeAtIndex:2]];
if ([headerName isEqualToString:@"User Name"]) { if ([headerName isEqualToString:@"User Name"]) {

View File

@ -13,6 +13,6 @@
@interface MPStoredSiteEntity : MPSiteEntity @interface MPStoredSiteEntity : MPSiteEntity
@property (nonatomic, retain) id contentObject; @property (nonatomic, retain) NSData *contentObject;
@end @end

View File

@ -14,6 +14,7 @@
#import "MPPasswordsViewController.h" #import "MPPasswordsViewController.h"
#import "MPCoachmarkViewController.h" #import "MPCoachmarkViewController.h"
#import "MPSiteQuestionEntity.h" #import "MPSiteQuestionEntity.h"
#import "MPOverlayViewController.h"
@interface MPAnswersViewController() @interface MPAnswersViewController()
@ -35,6 +36,25 @@
self.view.backgroundColor = [UIColor clearColor]; self.view.backgroundColor = [UIColor clearColor];
} }
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
PearlAddNotificationObserver( MPSignedOutNotification, nil, [NSOperationQueue mainQueue], ^(NSNotification *note) {
if (![note.userInfo[@"animated"] boolValue])
[UIView setAnimationsEnabled:NO];
[[MPOverlaySegue dismissViewController:self] perform];
[UIView setAnimationsEnabled:YES];
} );
}
- (void)viewWillDisappear:(BOOL)animated {
[super viewWillDisappear:animated];
PearlRemoveNotificationObservers();
}
- (UIStatusBarStyle)preferredStatusBarStyle { - (UIStatusBarStyle)preferredStatusBarStyle {
return UIStatusBarStyleLightContent; return UIStatusBarStyleLightContent;
@ -147,7 +167,10 @@
[MPiOSAppDelegate managedObjectContextPerformBlock:^(NSManagedObjectContext *context) { [MPiOSAppDelegate managedObjectContextPerformBlock:^(NSManagedObjectContext *context) {
MPSiteEntity *site_ = [self siteInContext:context]; MPSiteEntity *site_ = [self siteInContext:context];
[site_ removeQuestions:site_.questions]; NSOrderedSet *questions = [site_.questions copy];
for (MPSiteQuestionEntity *question in questions)
[context deleteObject:question];
[site_ removeQuestions:questions];
[context saveToStore]; [context saveToStore];
[self setMultiple:NO animated:YES]; [self setMultiple:NO animated:YES];
}]; }];

View File

@ -22,9 +22,7 @@
#import "MPEmergencyViewController.h" #import "MPEmergencyViewController.h"
#import "MPPasswordsSegue.h" #import "MPPasswordsSegue.h"
@implementation MPCombinedViewController { @implementation MPCombinedViewController
NSArray *_notificationObservers;
}
#pragma mark - Life #pragma mark - Life
@ -47,14 +45,22 @@
[super viewDidAppear:animated]; [super viewDidAppear:animated];
[self registerObservers]; Weakify( self );
PearlAddNotificationObserver( MPSignedInNotification, nil, [NSOperationQueue mainQueue], ^(NSNotification *note) {
Strongify( self );
[self setMode:MPCombinedModePasswordSelection];
} );
PearlAddNotificationObserver( MPSignedOutNotification, nil, [NSOperationQueue mainQueue], ^(NSNotification *note) {
Strongify( self );
[self setMode:MPCombinedModeUserSelection animated:[note.userInfo[@"animated"] boolValue]];
} );
} }
- (void)viewWillDisappear:(BOOL)animated { - (void)viewWillDisappear:(BOOL)animated {
[super viewWillDisappear:animated]; [super viewWillDisappear:animated];
[self removeObservers]; PearlRemoveNotificationObservers();
} }
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender { - (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
@ -142,35 +148,4 @@
#pragma mark - Private #pragma mark - Private
- (void)registerObservers {
if ([_notificationObservers count])
return;
Weakify( self );
_notificationObservers = @[
[[NSNotificationCenter defaultCenter]
addObserverForName:MPSignedInNotification object:nil
queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *note) {
Strongify( self );
[self setMode:MPCombinedModePasswordSelection];
}],
[[NSNotificationCenter defaultCenter]
addObserverForName:MPSignedOutNotification object:nil
queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *note) {
Strongify( self );
[self setMode:MPCombinedModeUserSelection animated:[note.userInfo[@"animated"] boolValue]];
}],
];
}
- (void)removeObservers {
for (id observer in _notificationObservers)
[[NSNotificationCenter defaultCenter] removeObserver:observer];
_notificationObservers = nil;
}
@end @end

View File

@ -1,12 +1,12 @@
/** /**
* Copyright Maarten Billemont (http://www.lhunath.com, lhunath@lyndir.com) * Copyright Maarten Billemont (http://www.lhunath.com, lhunath@lyndir.com)
* *
* See the enclosed file LICENSE for license information (LGPLv3). If you did * 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 * not receive this file, see http://www.gnu.org/licenses/lgpl-3.0.txt
* *
* @author Maarten Billemont <lhunath@lyndir.com> * @author Maarten Billemont <lhunath@lyndir.com>
* @license http://www.gnu.org/licenses/lgpl-3.0.txt * @license http://www.gnu.org/licenses/lgpl-3.0.txt
*/ */
// //
// MPCombinedViewController.h // MPCombinedViewController.h
@ -23,7 +23,6 @@
MPKey *_key; MPKey *_key;
NSOperationQueue *_emergencyKeyQueue; NSOperationQueue *_emergencyKeyQueue;
NSOperationQueue *_emergencyPasswordQueue; NSOperationQueue *_emergencyPasswordQueue;
NSArray *_notificationObservers;
} }
- (void)viewDidLoad { - (void)viewDidLoad {
@ -42,14 +41,17 @@
[super viewWillAppear:animated]; [super viewWillAppear:animated];
[self reset]; [self reset];
[self registerObservers]; PearlAddNotificationObserver( UIApplicationWillResignActiveNotification, nil, [NSOperationQueue mainQueue],
^(MPEmergencyViewController *self, NSNotification *note) {
[self performSegueWithIdentifier:@"unwind-popover" sender:self];
} );
} }
- (void)viewDidDisappear:(BOOL)animated { - (void)viewDidDisappear:(BOOL)animated {
[super viewDidDisappear:animated]; [super viewDidDisappear:animated];
[self removeObservers]; PearlRemoveNotificationObservers();
[self reset]; [self reset];
} }
@ -154,7 +156,7 @@
case 5: case 5:
return MPSiteTypeGeneratedPIN; return MPSiteTypeGeneratedPIN;
default: default:
Throw(@"Unsupported type index: %ld", (long)self.typeControl.selectedSegmentIndex); Throw( @"Unsupported type index: %ld", (long)self.typeControl.selectedSegmentIndex );
} }
} }
@ -168,28 +170,4 @@
[self updateKey]; [self updateKey];
} }
- (void)registerObservers {
if ([_notificationObservers count])
return;
Weakify(self);
_notificationObservers = @[
[[NSNotificationCenter defaultCenter]
addObserverForName:UIApplicationWillResignActiveNotification object:nil
queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *note) {
Strongify(self);
[self performSegueWithIdentifier:@"unwind-popover" sender:self];
}],
];
}
- (void)removeObservers {
for (id observer in _notificationObservers)
[[NSNotificationCenter defaultCenter] removeObserver:observer];
_notificationObservers = nil;
}
@end @end

View File

@ -1,12 +1,12 @@
/** /**
* Copyright Maarten Billemont (http://www.lhunath.com, lhunath@lyndir.com) * Copyright Maarten Billemont (http://www.lhunath.com, lhunath@lyndir.com)
* *
* See the enclosed file LICENSE for license information (LGPLv3). If you did * 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 * not receive this file, see http://www.gnu.org/licenses/lgpl-3.0.txt
* *
* @author Maarten Billemont <lhunath@lyndir.com> * @author Maarten Billemont <lhunath@lyndir.com>
* @license http://www.gnu.org/licenses/lgpl-3.0.txt * @license http://www.gnu.org/licenses/lgpl-3.0.txt
*/ */
// //
// MPLogsViewController.h // MPLogsViewController.h
@ -27,18 +27,17 @@
[super viewDidLoad]; [super viewDidLoad];
self.view.backgroundColor = [UIColor clearColor]; self.view.backgroundColor = [UIColor clearColor];
[[NSNotificationCenter defaultCenter] addObserverForName:NSUserDefaultsDidChangeNotification object:nil
queue:[NSOperationQueue mainQueue] usingBlock:
^(NSNotification *note) {
self.levelControl.selectedSegmentIndex = [[MPiOSConfig get].traceMode boolValue]? 1: 0;
}];
} }
- (void)viewWillAppear:(BOOL)animated { - (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated]; [super viewWillAppear:animated];
PearlAddNotificationObserver( NSUserDefaultsDidChangeNotification, nil, [NSOperationQueue mainQueue],
^(MPLogsViewController *self, NSNotification *note) {
self.levelControl.selectedSegmentIndex = [[MPiOSConfig get].traceMode boolValue]? 1: 0;
} );
self.logView.contentInset = UIEdgeInsetsMake( 64, 0, 93, 0 ); self.logView.contentInset = UIEdgeInsetsMake( 64, 0, 93, 0 );
[self refresh:nil]; [self refresh:nil];
@ -46,13 +45,20 @@
self.levelControl.selectedSegmentIndex = [[MPiOSConfig get].traceMode boolValue]? 1: 0; self.levelControl.selectedSegmentIndex = [[MPiOSConfig get].traceMode boolValue]? 1: 0;
} }
- (void)viewWillDisappear:(BOOL)animated {
[super viewWillDisappear:animated];
PearlRemoveNotificationObservers();
}
- (IBAction)toggleLevelControl:(UISegmentedControl *)sender { - (IBAction)toggleLevelControl:(UISegmentedControl *)sender {
BOOL traceEnabled = (BOOL)self.levelControl.selectedSegmentIndex; BOOL traceEnabled = (BOOL)self.levelControl.selectedSegmentIndex;
if (traceEnabled) { if (traceEnabled) {
[PearlAlert showAlertWithTitle:@"Enable Trace Mode?" message: [PearlAlert showAlertWithTitle:@"Enable Trace Mode?" message:
@"Trace mode will log the internal operation of the application.\n" @"Trace mode will log the internal operation of the application.\n"
@"Unless you're looking for the cause of a problem, you should leave this off to save memory." @"Unless you're looking for the cause of a problem, you should leave this off to save memory."
viewStyle:UIAlertViewStyleDefault initAlert:nil viewStyle:UIAlertViewStyleDefault initAlert:nil
tappedButtonBlock:^(UIAlertView *alert, NSInteger buttonIndex) { tappedButtonBlock:^(UIAlertView *alert, NSInteger buttonIndex) {
if (buttonIndex == [alert cancelButtonIndex]) if (buttonIndex == [alert cancelButtonIndex])
@ -74,8 +80,8 @@
if ([[MPiOSConfig get].traceMode boolValue]) { if ([[MPiOSConfig get].traceMode boolValue]) {
[PearlAlert showAlertWithTitle:@"Hiding Trace Messages" message: [PearlAlert showAlertWithTitle:@"Hiding Trace Messages" message:
@"Trace-level log messages will not be mailed. " @"Trace-level log messages will not be mailed. "
@"These messages contain sensitive and personal information." @"These messages contain sensitive and personal information."
viewStyle:UIAlertViewStyleDefault initAlert:nil viewStyle:UIAlertViewStyleDefault initAlert:nil
tappedButtonBlock:^(UIAlertView *alert, NSInteger buttonIndex) { tappedButtonBlock:^(UIAlertView *alert, NSInteger buttonIndex) {
[[MPiOSAppDelegate get] openFeedbackWithLogs:YES forVC:self]; [[MPiOSAppDelegate get] openFeedbackWithLogs:YES forVC:self];

View File

@ -23,4 +23,7 @@
@end @end
@interface MPOverlaySegue : UIStoryboardSegue @interface MPOverlaySegue : UIStoryboardSegue
+ (instancetype)dismissViewController:(UIViewController *)viewController;
@end @end

View File

@ -52,17 +52,20 @@
return [[MPOverlaySegue alloc] initWithIdentifier:identifier source:fromViewController destination:toViewController]; return [[MPOverlaySegue alloc] initWithIdentifier:identifier source:fromViewController destination:toViewController];
} }
- (void)addDismissButtonForSegue:(MPOverlaySegue *)segue { - (UIView *)addDismissButtonForSegue:(MPOverlaySegue *)segue {
UIButton *dismissButton = [UIButton buttonWithType:UIButtonTypeCustom]; UIButton *dismissButton = [UIButton buttonWithType:UIButtonTypeCustom];
[dismissButton addTarget:self action:@selector( dismissOverlay: ) forControlEvents:UIControlEventTouchUpInside]; [dismissButton addTarget:self action:@selector( dismissOverlay: ) forControlEvents:UIControlEventTouchUpInside];
dismissButton.backgroundColor = [UIColor colorWithWhite:0 alpha:0.3f]; dismissButton.backgroundColor = [UIColor colorWithWhite:0 alpha:0.5f];
dismissButton.alpha = 0;
dismissButton.frame = self.view.bounds; dismissButton.frame = self.view.bounds;
dismissButton.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; dismissButton.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
_dismissSegueByButton[[NSValue valueWithNonretainedObject:dismissButton]] = _dismissSegueByButton[[NSValue valueWithNonretainedObject:dismissButton]] =
[[MPOverlaySegue alloc] initWithIdentifier:@"dismiss-overlay" [[MPOverlaySegue alloc] initWithIdentifier:@"dismiss-overlay"
source:segue.destinationViewController destination:segue.sourceViewController]; source:segue.destinationViewController destination:segue.sourceViewController];
[self.view addSubview:dismissButton]; [self.view addSubview:dismissButton];
return dismissButton;
} }
- (void)dismissOverlay:(UIButton *)dismissButton { - (void)dismissOverlay:(UIButton *)dismissButton {
@ -96,6 +99,11 @@
@implementation MPOverlaySegue @implementation MPOverlaySegue
+ (instancetype)dismissViewController:(UIViewController *)viewController {
return [[self alloc] initWithIdentifier:nil source:viewController destination:viewController];
}
- (void)perform { - (void)perform {
UIViewController *sourceViewController = self.sourceViewController; UIViewController *sourceViewController = self.sourceViewController;
@ -109,6 +117,7 @@
if (!destinationViewController.parentViewController) { if (!destinationViewController.parentViewController) {
// Winding // Winding
[containerViewController addChildViewController:destinationViewController]; [containerViewController addChildViewController:destinationViewController];
UIView *dismissButton = [containerViewController addDismissButtonForSegue:self];
destinationViewController.view.frame = containerViewController.view.bounds; destinationViewController.view.frame = containerViewController.view.bounds;
destinationViewController.view.translatesAutoresizingMaskIntoConstraints = YES; destinationViewController.view.translatesAutoresizingMaskIntoConstraints = YES;
@ -125,6 +134,7 @@
destinationViewController.view.transform = CGAffineTransformIdentity; destinationViewController.view.transform = CGAffineTransformIdentity;
CGRectSetY( destinationViewController.view.frame, 0 ); CGRectSetY( destinationViewController.view.frame, 0 );
destinationViewController.view.alpha = 1; destinationViewController.view.alpha = 1;
dismissButton.alpha = 1;
} completion:^(BOOL finished) { } completion:^(BOOL finished) {
[destinationViewController didMoveToParentViewController:containerViewController]; [destinationViewController didMoveToParentViewController:containerViewController];
[containerViewController setNeedsStatusBarAppearanceUpdate]; [containerViewController setNeedsStatusBarAppearanceUpdate];

View File

@ -22,7 +22,6 @@
#import "MPPopdownSegue.h" #import "MPPopdownSegue.h"
#import "MPAppDelegate_Key.h" #import "MPAppDelegate_Key.h"
#import "MPPasswordCell.h" #import "MPPasswordCell.h"
#import "UICollectionView+PearlReloadFromArray.h"
#import "MPAnswersViewController.h" #import "MPAnswersViewController.h"
@interface MPPasswordsViewController()<NSFetchedResultsControllerDelegate> @interface MPPasswordsViewController()<NSFetchedResultsControllerDelegate>
@ -33,10 +32,6 @@
@end @end
@implementation MPPasswordsViewController { @implementation MPPasswordsViewController {
__weak id _storeChangingObserver;
__weak id _storeChangedObserver;
__weak id _mocObserver;
NSArray *_notificationObservers;
__weak UITapGestureRecognizer *_passwordsDismissRecognizer; __weak UITapGestureRecognizer *_passwordsDismissRecognizer;
NSFetchedResultsController *_fetchedResultsController; NSFetchedResultsController *_fetchedResultsController;
UIColor *_backgroundColor; UIColor *_backgroundColor;
@ -69,7 +64,6 @@
[super viewWillAppear:animated]; [super viewWillAppear:animated];
[self registerObservers]; [self registerObservers];
[self observeStore];
[self updateConfigKey:nil]; [self updateConfigKey:nil];
[self updatePasswords]; [self updatePasswords];
} }
@ -90,8 +84,7 @@
[super viewWillDisappear:animated]; [super viewWillDisappear:animated];
[self removeObservers]; PearlRemoveNotificationObservers();
[self stopObservingStore];
} }
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender { - (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
@ -280,97 +273,49 @@ referenceSizeForHeaderInSection:(NSInteger)section {
- (void)registerObservers { - (void)registerObservers {
if ([_notificationObservers count]) PearlRemoveNotificationObservers();
return; PearlAddNotificationObserver( UIApplicationDidEnterBackgroundNotification, nil, [NSOperationQueue mainQueue],
^(MPPasswordsViewController *self, NSNotification *note) {
Weakify( self ); self.passwordSelectionContainer.alpha = 0;
_notificationObservers = @[ } );
[[NSNotificationCenter defaultCenter] PearlAddNotificationObserver( UIApplicationWillEnterForegroundNotification, nil, [NSOperationQueue mainQueue],
addObserverForName:UIApplicationDidEnterBackgroundNotification object:nil ^(MPPasswordsViewController *self, NSNotification *note) {
queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *note) { [self updatePasswords];
Strongify( self ); } );
PearlAddNotificationObserver( UIApplicationDidBecomeActiveNotification, nil, [NSOperationQueue mainQueue],
self.passwordSelectionContainer.alpha = 0; ^(MPPasswordsViewController *self, NSNotification *note) {
}], [UIView animateWithDuration:0.7f animations:^{
[[NSNotificationCenter defaultCenter] self.passwordSelectionContainer.alpha = 1;
addObserverForName:UIApplicationWillEnterForegroundNotification object:nil }];
queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *note) { } );
Strongify( self ); PearlAddNotificationObserver( MPSignedOutNotification, nil, [NSOperationQueue mainQueue],
^(MPPasswordsViewController *self, NSNotification *note) {
[self updatePasswords]; _fetchedResultsController = nil;
}], self.passwordsSearchBar.text = nil;
[[NSNotificationCenter defaultCenter] [self.passwordCollectionView reloadData];
addObserverForName:UIApplicationDidBecomeActiveNotification object:nil } );
queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *note) { PearlAddNotificationObserver( MPCheckConfigNotification, nil, [NSOperationQueue mainQueue],
Strongify( self ); ^(MPPasswordsViewController *self, NSNotification *note) {
[self updateConfigKey:note.object];
[UIView animateWithDuration:0.7f animations:^{ } );
self.passwordSelectionContainer.alpha = 1; PearlAddNotificationObserver( NSPersistentStoreCoordinatorStoresWillChangeNotification, nil, nil,
}]; ^(MPPasswordsViewController *self, NSNotification *note) {
}], self->_fetchedResultsController = nil;
[[NSNotificationCenter defaultCenter] [self.passwordCollectionView reloadData];
addObserverForName:MPSignedOutNotification object:nil } );
queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *note) { PearlAddNotificationObserver( NSPersistentStoreCoordinatorStoresDidChangeNotification, nil, nil,
Strongify( self ); ^(MPPasswordsViewController *self, NSNotification *note) {
[self updatePasswords];
_fetchedResultsController = nil; [self registerObservers];
self.passwordsSearchBar.text = nil; } );
[self.passwordCollectionView reloadData];
}],
[[NSNotificationCenter defaultCenter]
addObserverForName:MPCheckConfigNotification object:nil
queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *note) {
[self updateConfigKey:note.object];
}],
];
}
- (void)removeObservers {
for (id observer in _notificationObservers)
[[NSNotificationCenter defaultCenter] removeObserver:observer];
_notificationObservers = nil;
}
- (void)observeStore {
Weakify( self );
NSManagedObjectContext *mainContext = [MPiOSAppDelegate managedObjectContextForMainThreadIfReady]; NSManagedObjectContext *mainContext = [MPiOSAppDelegate managedObjectContextForMainThreadIfReady];
if (!_mocObserver && mainContext) if (mainContext)
_mocObserver = [[NSNotificationCenter defaultCenter] PearlAddNotificationObserver( NSManagedObjectContextDidSaveNotification, mainContext, nil,
addObserverForName:NSManagedObjectContextDidSaveNotification object:mainContext ^(MPPasswordsViewController *self, NSNotification *note) {
queue:nil usingBlock:^(NSNotification *note) { if (![[MPiOSAppDelegate get] activeUserInContext:note.object])
if (![[MPiOSAppDelegate get] activeUserInContext:mainContext])
[[MPiOSAppDelegate get] signOutAnimated:YES]; [[MPiOSAppDelegate get] signOutAnimated:YES];
}]; } );
if (!_storeChangingObserver)
_storeChangingObserver = [[NSNotificationCenter defaultCenter]
addObserverForName:NSPersistentStoreCoordinatorStoresWillChangeNotification object:nil
queue:nil usingBlock:^(NSNotification *note) {
Strongify( self );
self->_fetchedResultsController = nil;
if (self->_mocObserver)
[[NSNotificationCenter defaultCenter] removeObserver:self->_mocObserver];
[self.passwordCollectionView reloadData];
}];
if (!_storeChangedObserver)
_storeChangedObserver = [[NSNotificationCenter defaultCenter]
addObserverForName:NSPersistentStoreCoordinatorStoresDidChangeNotification object:nil
queue:nil usingBlock:^(NSNotification *note) {
Strongify( self );
[self updatePasswords];
}];
}
- (void)stopObservingStore {
if (_mocObserver)
[[NSNotificationCenter defaultCenter] removeObserver:_mocObserver];
if (_storeChangingObserver)
[[NSNotificationCenter defaultCenter] removeObserver:_storeChangingObserver];
if (_storeChangedObserver)
[[NSNotificationCenter defaultCenter] removeObserver:_storeChangedObserver];
} }
- (void)updateConfigKey:(NSString *)key { - (void)updateConfigKey:(NSString *)key {
@ -454,7 +399,7 @@ referenceSizeForHeaderInSection:(NSInteger)section {
initWithFetchRequest:fetchRequest managedObjectContext:mainContext sectionNameKeyPath:nil cacheName:nil]; initWithFetchRequest:fetchRequest managedObjectContext:mainContext sectionNameKeyPath:nil cacheName:nil];
_fetchedResultsController.delegate = self; _fetchedResultsController.delegate = self;
}]; }];
[self observeStore]; [self registerObservers];
} }
return _fetchedResultsController; return _fetchedResultsController;

View File

@ -50,15 +50,22 @@ PearlEnum( MPDevelopmentFuelConsumption,
} }
}]; }];
[[NSNotificationCenter defaultCenter] addObserverForName:NSUserDefaultsDidChangeNotification object:nil PearlAddNotificationObserver( NSUserDefaultsDidChangeNotification, nil, [NSOperationQueue mainQueue],
queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *note) { ^(MPStoreViewController *self, NSNotification *note) {
[self updateProducts]; [self updateProducts];
[self updateFuel]; [self updateFuel];
}]; } );
[[MPiOSAppDelegate get] registerProductsObserver:self]; [[MPiOSAppDelegate get] registerProductsObserver:self];
[self updateFuel]; [self updateFuel];
} }
- (void)viewWillDisappear:(BOOL)animated {
[super viewWillDisappear:animated];
PearlRemoveNotificationObservers();
}
#pragma mark - UITableViewDelegate #pragma mark - UITableViewDelegate
- (MPStoreProductCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { - (MPStoreProductCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
@ -221,7 +228,7 @@ PearlEnum( MPDevelopmentFuelConsumption,
} }
CGFloat fuelRatio = weeklyFuelConsumption == 0? 0: fuel / weeklyFuelConsumption; /* x weeks worth of fuel left */ CGFloat fuelRatio = weeklyFuelConsumption == 0? 0: fuel / weeklyFuelConsumption; /* x weeks worth of fuel left */
[self.fuelMeterConstraint updateConstant:MIN(0.5f, fuelRatio - 0.5f) * 160]; /* -80pt = 0 weeks left, 80pt = >=1 week left */ [self.fuelMeterConstraint updateConstant:MIN( 0.5f, fuelRatio - 0.5f ) * 160]; /* -80pt = 0 weeks left, 80pt = >=1 week left */
} }
- (CGFloat)weeklyFuelConsumption { - (CGFloat)weeklyFuelConsumption {

View File

@ -22,9 +22,7 @@
#import "MPiOSAppDelegate.h" #import "MPiOSAppDelegate.h"
#import "MPAppDelegate_Store.h" #import "MPAppDelegate_Store.h"
#import "MPAppDelegate_Key.h" #import "MPAppDelegate_Key.h"
#import "PearlSizedTextView.h"
#import "MPWebViewController.h" #import "MPWebViewController.h"
#import "UIView+FontScale.h"
typedef NS_ENUM( NSUInteger, MPActiveUserState ) { typedef NS_ENUM( NSUInteger, MPActiveUserState ) {
/** The users are all inactive */ /** The users are all inactive */
@ -51,10 +49,6 @@ typedef NS_ENUM( NSUInteger, MPActiveUserState ) {
@end @end
@implementation MPUsersViewController { @implementation MPUsersViewController {
__weak id _storeChangingObserver;
__weak id _storeChangedObserver;
__weak id _mocObserver;
NSArray *_notificationObservers;
NSString *_masterPasswordChoice; NSString *_masterPasswordChoice;
NSOperationQueue *_afterUpdates; NSOperationQueue *_afterUpdates;
} }
@ -89,8 +83,7 @@ typedef NS_ENUM( NSUInteger, MPActiveUserState ) {
[super viewWillDisappear:animated]; [super viewWillDisappear:animated];
[self removeObservers]; PearlRemoveNotificationObservers();
[self stopObservingStore];
[self.marqueeTipTimer invalidate]; [self.marqueeTipTimer invalidate];
} }
@ -99,7 +92,6 @@ typedef NS_ENUM( NSUInteger, MPActiveUserState ) {
[super viewDidAppear:animated]; [super viewDidAppear:animated];
[self observeStore];
[self registerObservers]; [self registerObservers];
[self reloadUsers]; [self reloadUsers];
@ -475,15 +467,15 @@ referenceSizeForFooterInSection:(NSInteger)section {
if ([nextMarqueeString isEqualToString:[self.marqueeButton titleForState:UIControlStateNormal]]) if ([nextMarqueeString isEqualToString:[self.marqueeButton titleForState:UIControlStateNormal]])
return; return;
[UIView animateWithDuration:timer? 0.5: 0 animations:^{ [UIView animateWithDuration:timer? 0.5f: 0 animations:^{
self.marqueeButton.alpha = 0; self.marqueeButton.alpha = 0;
} completion:^(BOOL finished) { } completion:^(BOOL finished) {
if (!finished) if (!finished)
return; return;
[self.marqueeButton setTitle:nextMarqueeString forState:UIControlStateNormal]; [self.marqueeButton setTitle:nextMarqueeString forState:UIControlStateNormal];
[UIView animateWithDuration:timer? 0.5: 0 animations:^{ [UIView animateWithDuration:timer? 0.5f: 0 animations:^{
self.marqueeButton.alpha = 0.5; self.marqueeButton.alpha = 0.5f;
}]; }];
}]; }];
} }
@ -586,54 +578,27 @@ referenceSizeForFooterInSection:(NSInteger)section {
- (void)registerObservers { - (void)registerObservers {
if ([_notificationObservers count]) [self removeKeyPathObservers];
return;
Weakify( self );
_notificationObservers = @[
[[NSNotificationCenter defaultCenter]
addObserverForName:UIApplicationDidEnterBackgroundNotification object:nil
queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *note) {
Strongify( self );
self.userSelectionContainer.alpha = 0;
}],
[[NSNotificationCenter defaultCenter]
addObserverForName:UIApplicationWillEnterForegroundNotification object:nil
queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *note) {
Strongify( self );
[self reloadUsers];
}],
[[NSNotificationCenter defaultCenter]
addObserverForName:UIApplicationDidBecomeActiveNotification object:nil
queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *note) {
Strongify( self );
[UIView animateWithDuration:0.7f animations:^{
self.userSelectionContainer.alpha = 1;
}];
}],
];
[self observeKeyPath:@"avatarCollectionView.contentOffset" withBlock: [self observeKeyPath:@"avatarCollectionView.contentOffset" withBlock:
^(id from, id to, NSKeyValueChange cause, MPUsersViewController *_self) { ^(id from, id to, NSKeyValueChange cause, MPUsersViewController *_self) {
[_self updateAvatarVisibility]; [_self updateAvatarVisibility];
}]; }];
}
- (void)removeObservers { PearlRemoveNotificationObservers();
PearlAddNotificationObserver( UIApplicationDidEnterBackgroundNotification, nil, [NSOperationQueue mainQueue],
for (id observer in _notificationObservers) ^(MPUsersViewController *self, NSNotification *note) {
[[NSNotificationCenter defaultCenter] removeObserver:observer]; self.userSelectionContainer.alpha = 0;
_notificationObservers = nil; } );
PearlAddNotificationObserver( UIApplicationWillEnterForegroundNotification, nil, [NSOperationQueue mainQueue],
[self removeKeyPathObservers]; ^(MPUsersViewController *self, NSNotification *note) {
} [self reloadUsers];
} );
- (void)observeStore { PearlAddNotificationObserver( UIApplicationDidBecomeActiveNotification, nil, [NSOperationQueue mainQueue],
^(MPUsersViewController *self, NSNotification *note) {
Weakify( self ); [UIView animateWithDuration:0.5f animations:^{
self.userSelectionContainer.alpha = 1;
}];
} );
NSManagedObjectContext *mainContext = [MPiOSAppDelegate managedObjectContextForMainThreadIfReady]; NSManagedObjectContext *mainContext = [MPiOSAppDelegate managedObjectContextForMainThreadIfReady];
[UIView animateWithDuration:0.3f animations:^{ [UIView animateWithDuration:0.3f animations:^{
@ -644,51 +609,31 @@ referenceSizeForFooterInSection:(NSInteger)section {
if (!mainContext && !self.storeLoadingActivity.isAnimating) if (!mainContext && !self.storeLoadingActivity.isAnimating)
[self.storeLoadingActivity startAnimating]; [self.storeLoadingActivity startAnimating];
if (!_mocObserver && mainContext) if (mainContext)
_mocObserver = [[NSNotificationCenter defaultCenter] PearlAddNotificationObserver( NSManagedObjectContextObjectsDidChangeNotification, mainContext, [NSOperationQueue mainQueue],
addObserverForName:NSManagedObjectContextObjectsDidChangeNotification object:mainContext ^(MPUsersViewController *self, NSNotification *note) {
queue:nil usingBlock:^(NSNotification *note) { NSSet *insertedObjects = note.userInfo[NSInsertedObjectsKey];
Strongify( self ); NSSet *deletedObjects = note.userInfo[NSDeletedObjectsKey];
NSSet *insertedObjects = note.userInfo[NSInsertedObjectsKey]; if ([[NSSetUnion( insertedObjects, deletedObjects )
NSSet *deletedObjects = note.userInfo[NSDeletedObjectsKey]; filteredSetUsingPredicate:[NSPredicate predicateWithBlock:^BOOL(id evaluatedObject, NSDictionary *bindings) {
if ([[NSSetUnion( insertedObjects, deletedObjects ) return [evaluatedObject isKindOfClass:[MPUserEntity class]];
filteredSetUsingPredicate:[NSPredicate predicateWithBlock:^BOOL(id evaluatedObject, NSDictionary *bindings) { }]] count])
return [evaluatedObject isKindOfClass:[MPUserEntity class]];
}]] count])
[self reloadUsers];
}];
if (!_storeChangingObserver)
_storeChangingObserver = [[NSNotificationCenter defaultCenter]
addObserverForName:NSPersistentStoreCoordinatorStoresWillChangeNotification object:nil
queue:nil usingBlock:^(NSNotification *note) {
Strongify( self );
if (self->_mocObserver)
[[NSNotificationCenter defaultCenter] removeObserver:self->_mocObserver];
self.userIDs = nil;
}];
if (!_storeChangedObserver)
_storeChangedObserver = [[NSNotificationCenter defaultCenter]
addObserverForName:NSPersistentStoreCoordinatorStoresDidChangeNotification object:nil
queue:nil usingBlock:^(NSNotification *note) {
Strongify( self );
[self reloadUsers]; [self reloadUsers];
}]; } );
} PearlAddNotificationObserver( NSPersistentStoreCoordinatorStoresWillChangeNotification, nil, [NSOperationQueue mainQueue],
^(MPUsersViewController *self, NSNotification *note) {
- (void)stopObservingStore { self.userIDs = nil;
} );
if (_mocObserver) PearlAddNotificationObserver( NSPersistentStoreCoordinatorStoresDidChangeNotification, nil, [NSOperationQueue mainQueue],
[[NSNotificationCenter defaultCenter] removeObserver:_mocObserver]; ^(MPUsersViewController *self, NSNotification *note) {
if (_storeChangingObserver) [self registerObservers];
[[NSNotificationCenter defaultCenter] removeObserver:_storeChangingObserver]; [self reloadUsers];
if (_storeChangedObserver) } );
[[NSNotificationCenter defaultCenter] removeObserver:_storeChangedObserver];
} }
- (void)reloadUsers { - (void)reloadUsers {
[self afterUpdatesMainQueue:^{ [self afterUpdatesMainQueue:^{
[self observeStore];
if (![MPiOSAppDelegate managedObjectContextForMainThreadPerformBlockAndWait:^(NSManagedObjectContext *mainContext) { if (![MPiOSAppDelegate managedObjectContextForMainThreadPerformBlockAndWait:^(NSManagedObjectContext *mainContext) {
NSError *error = nil; NSError *error = nil;
NSFetchRequest *fetchRequest = [NSFetchRequest fetchRequestWithEntityName:NSStringFromClass( [MPUserEntity class] )]; NSFetchRequest *fetchRequest = [NSFetchRequest fetchRequestWithEntityName:NSStringFromClass( [MPUserEntity class] )];

View File

@ -69,18 +69,15 @@
err( @"During Analytics Setup: %@", exception ); err( @"During Analytics Setup: %@", exception );
} }
@try { @try {
[[NSNotificationCenter defaultCenter] addObserverForName:MPCheckConfigNotification object:nil queue:[NSOperationQueue mainQueue] PearlAddNotificationObserver( MPCheckConfigNotification, nil, [NSOperationQueue mainQueue], ^(id self, NSNotification *note) {
usingBlock:^(NSNotification *note) { [self updateConfigKey:note.object];
[self updateConfigKey:note.object]; } );
}]; PearlAddNotificationObserver( kIASKAppSettingChanged, nil, nil, ^(id self, NSNotification *note) {
[[NSNotificationCenter defaultCenter] addObserverForName:kIASKAppSettingChanged object:nil queue:nil usingBlock: [[NSNotificationCenter defaultCenter] postNotificationName:MPCheckConfigNotification object:note.object];
^(NSNotification *note) { } );
[[NSNotificationCenter defaultCenter] postNotificationName:MPCheckConfigNotification object:note.object]; PearlAddNotificationObserver( NSUserDefaultsDidChangeNotification, nil, nil, ^(id self, NSNotification *note) {
}]; [[NSNotificationCenter defaultCenter] postNotificationName:MPCheckConfigNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserverForName:NSUserDefaultsDidChangeNotification object:nil queue:nil usingBlock: } );
^(NSNotification *note) {
[[NSNotificationCenter defaultCenter] postNotificationName:MPCheckConfigNotification object:nil];
}];
#ifdef ADHOC #ifdef ADHOC
[PearlAlert showAlertWithTitle:@"Welcome, tester!" message: [PearlAlert showAlertWithTitle:@"Welcome, tester!" message:
@ -106,28 +103,27 @@
@try { @try {
inf( @"Started up with device identifier: %@", [PearlKeyChain deviceIdentifier] ); inf( @"Started up with device identifier: %@", [PearlKeyChain deviceIdentifier] );
[[NSNotificationCenter defaultCenter] addObserverForName:MPFoundInconsistenciesNotification object:nil queue:nil usingBlock: PearlAddNotificationObserver( MPFoundInconsistenciesNotification, nil, nil, ^(id self, NSNotification *note) {
^(NSNotification *note) { switch ((MPFixableResult)[note.userInfo[MPInconsistenciesFixResultUserKey] unsignedIntegerValue]) {
switch ((MPFixableResult)[note.userInfo[MPInconsistenciesFixResultUserKey] unsignedIntegerValue]) {
case MPFixableResultNoProblems: case MPFixableResultNoProblems:
break; break;
case MPFixableResultProblemsFixed: case MPFixableResultProblemsFixed:
[PearlAlert showAlertWithTitle:@"Inconsistencies Fixed" message: [PearlAlert showAlertWithTitle:@"Inconsistencies Fixed" message:
@"Some inconsistencies were detected in your sites.\n" @"Some inconsistencies were detected in your sites.\n"
@"All issues were fixed." @"All issues were fixed."
viewStyle:UIAlertViewStyleDefault initAlert:nil viewStyle:UIAlertViewStyleDefault initAlert:nil
tappedButtonBlock:nil cancelTitle:[PearlStrings get].commonButtonOkay otherTitles:nil]; tappedButtonBlock:nil cancelTitle:[PearlStrings get].commonButtonOkay otherTitles:nil];
break; break;
case MPFixableResultProblemsNotFixed: case MPFixableResultProblemsNotFixed:
[PearlAlert showAlertWithTitle:@"Inconsistencies Found" message: [PearlAlert showAlertWithTitle:@"Inconsistencies Found" message:
@"Some inconsistencies were detected in your sites.\n" @"Some inconsistencies were detected in your sites.\n"
@"Not all issues could be fixed. Try signing in to each user or checking the logs." @"Not all issues could be fixed. Try signing in to each user or checking the logs."
viewStyle:UIAlertViewStyleDefault initAlert:nil viewStyle:UIAlertViewStyleDefault initAlert:nil
tappedButtonBlock:nil cancelTitle:[PearlStrings get].commonButtonOkay otherTitles:nil]; tappedButtonBlock:nil cancelTitle:[PearlStrings get].commonButtonOkay otherTitles:nil];
break; break;
} }
}]; } );
PearlMainQueue( ^{ PearlMainQueue( ^{
if ([[MPiOSConfig get].showSetup boolValue]) if ([[MPiOSConfig get].showSetup boolValue])

View File

@ -433,6 +433,7 @@
93D39156E806BB78E04F78B9 /* PearlSizedTextView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PearlSizedTextView.m; sourceTree = "<group>"; }; 93D39156E806BB78E04F78B9 /* PearlSizedTextView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PearlSizedTextView.m; sourceTree = "<group>"; };
93D3916C1D8F1427DFBDEBCA /* MPAppSettingsViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPAppSettingsViewController.m; sourceTree = "<group>"; }; 93D3916C1D8F1427DFBDEBCA /* MPAppSettingsViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPAppSettingsViewController.m; sourceTree = "<group>"; };
93D391943675426839501BB8 /* MPLogsViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPLogsViewController.h; sourceTree = "<group>"; }; 93D391943675426839501BB8 /* MPLogsViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPLogsViewController.h; sourceTree = "<group>"; };
93D391AA32F24290C424438E /* NSNotificationCenter+PearlEasyCleanup.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSNotificationCenter+PearlEasyCleanup.h"; sourceTree = "<group>"; };
93D39246FC21C6E63E35D615 /* UICollectionView+PearlReloadFromArray.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UICollectionView+PearlReloadFromArray.h"; sourceTree = "<group>"; }; 93D39246FC21C6E63E35D615 /* UICollectionView+PearlReloadFromArray.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UICollectionView+PearlReloadFromArray.h"; sourceTree = "<group>"; };
93D3924D6F77E6BF41AC32D3 /* MPRootSegue.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPRootSegue.h; sourceTree = "<group>"; }; 93D3924D6F77E6BF41AC32D3 /* MPRootSegue.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPRootSegue.h; sourceTree = "<group>"; };
93D3924EE15017F8A12CB436 /* MPPasswordsViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPPasswordsViewController.m; sourceTree = "<group>"; }; 93D3924EE15017F8A12CB436 /* MPPasswordsViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPPasswordsViewController.m; sourceTree = "<group>"; };
@ -2632,6 +2633,7 @@
DAFE45F915039823003ABA7C /* Resources */, DAFE45F915039823003ABA7C /* Resources */,
93D39F9106F2CCFB94283188 /* NSError+PearlFullDescription.m */, 93D39F9106F2CCFB94283188 /* NSError+PearlFullDescription.m */,
93D398C95847261903D781D3 /* NSError+PearlFullDescription.h */, 93D398C95847261903D781D3 /* NSError+PearlFullDescription.h */,
93D391AA32F24290C424438E /* NSNotificationCenter+PearlEasyCleanup.h */,
); );
path = Pearl; path = Pearl;
sourceTree = "<group>"; sourceTree = "<group>";