2
0

Small fixes and privacy policy.

[UPDATED]   Reload users if the selected user can't be found.
[ADDED]     Privacy policy to the website.
[UPDATED]   Pearl - PearlOverlay from main thread.
This commit is contained in:
Maarten Billemont 2013-11-16 16:35:14 -05:00
parent 8432932cb7
commit 6074547f64
5 changed files with 221 additions and 12 deletions

2
External/LoveLyndir vendored

@ -1 +1 @@
Subproject commit c2c0d1e45adfcea88c95dfe8f5793654508d9fb2 Subproject commit fbb540d8e8ea00896bb6c08a08d3080ad3eeed4e

2
External/Pearl vendored

@ -1 +1 @@
Subproject commit 04d8ca58b5f01c985b7d32dfb2248328d1ca0130 Subproject commit 66fe13f25f6ee09dc8ba48030ea2baaa11781ef5

View File

@ -7,7 +7,6 @@
// //
#import <Social/Social.h> #import <Social/Social.h>
#import <QuartzCore/QuartzCore.h>
#import "MPUnlockViewController.h" #import "MPUnlockViewController.h"
#import "MPiOSAppDelegate.h" #import "MPiOSAppDelegate.h"
@ -26,12 +25,18 @@
@property(nonatomic, strong) NSTimer *marqueeTipTimer; @property(nonatomic, strong) NSTimer *marqueeTipTimer;
@property(nonatomic) NSUInteger marqueeTipTextIndex; @property(nonatomic) NSUInteger marqueeTipTextIndex;
@property(nonatomic, strong) NSArray *marqueeTipTexts; @property(nonatomic, strong) NSArray *marqueeTipTexts;
@property(nonatomic, strong) id mocObserver;
@end @end
@implementation MPUnlockViewController { @implementation MPUnlockViewController {
NSManagedObjectID *_selectedUserOID; NSManagedObjectID *_selectedUserOID;
} }
- (void)dealloc {
if (self.mocObserver)
[[NSNotificationCenter defaultCenter] removeObserver:self.mocObserver];
}
- (void)initializeAvatarAlert:(UIAlertView *)alert forUser:(MPUserEntity *)user inContext:(NSManagedObjectContext *)moc { - (void)initializeAvatarAlert:(UIAlertView *)alert forUser:(MPUserEntity *)user inContext:(NSManagedObjectContext *)moc {
UIScrollView *alertAvatarScrollView = [[UIScrollView alloc] initWithFrame:CGRectMake( 12, 30, 260, 150 )]; UIScrollView *alertAvatarScrollView = [[UIScrollView alloc] initWithFrame:CGRectMake( 12, 30, 260, 150 )];
@ -240,7 +245,7 @@
[UIView animateWithDuration:1 animations:^{ [UIView animateWithDuration:1 animations:^{
self.uiContainer.alpha = 1; self.uiContainer.alpha = 1;
} completion:^(BOOL finished) { } completion:^(BOOL finished) {
if (finished) if (finished)
[UIView animateWithDuration:1 animations:^{ [UIView animateWithDuration:1 animations:^{
self.shareContainer.alpha = 1; self.shareContainer.alpha = 1;
@ -310,6 +315,17 @@
- (void)updateUsers { - (void)updateUsers {
NSManagedObjectContext *mainContext = [MPiOSAppDelegate managedObjectContextForMainThreadIfReady];
if (mainContext) {
if (self.mocObserver)
[[NSNotificationCenter defaultCenter] removeObserver:self.mocObserver];
self.mocObserver = [[NSNotificationCenter defaultCenter]
addObserverForName:NSManagedObjectContextObjectsDidChangeNotification object:mainContext
queue:nil usingBlock:^(NSNotification *note) {
[self updateUsers];
}];
}
[MPiOSAppDelegate managedObjectContextPerformBlockAndWait:^(NSManagedObjectContext *context) { [MPiOSAppDelegate managedObjectContextPerformBlockAndWait:^(NSManagedObjectContext *context) {
NSError *error = nil; NSError *error = nil;
NSFetchRequest *fetchRequest = [NSFetchRequest fetchRequestWithEntityName:NSStringFromClass( [MPUserEntity class] )]; NSFetchRequest *fetchRequest = [NSFetchRequest fetchRequestWithEntityName:NSStringFromClass( [MPUserEntity class] )];
@ -367,7 +383,6 @@
[self didSelectNewUserAvatar:avatar]; [self didSelectNewUserAvatar:avatar];
else if ([self setSelectedUser:user]) else if ([self setSelectedUser:user])
[self didToggleUserSelection]; [self didToggleUserSelection];
} options:0]; } options:0];
(self.avatarToUserOID)[[NSValue valueWithNonretainedObject:avatar]] = NilToNSNull([user objectID]); (self.avatarToUserOID)[[NSValue valueWithNonretainedObject:avatar]] = NilToNSNull([user objectID]);
@ -432,7 +447,7 @@
[PearlAlert showAlertWithTitle:@"Name Is Required" message:nil viewStyle:UIAlertViewStyleDefault initAlert:nil [PearlAlert showAlertWithTitle:@"Name Is Required" message:nil viewStyle:UIAlertViewStyleDefault initAlert:nil
tappedButtonBlock:^(UIAlertView *alert_, NSInteger buttonIndex_) { tappedButtonBlock:^(UIAlertView *alert_, NSInteger buttonIndex_) {
[self showNewUserNameAlertFor:newUser saveInContext:context completion:completion]; [self showNewUserNameAlertFor:newUser saveInContext:context completion:completion];
} cancelTitle:@"Try Again" otherTitles:nil]; } cancelTitle:@"Try Again" otherTitles:nil];
return; return;
} }
@ -457,7 +472,7 @@
// Okay // Okay
[self showNewUserConfirmationAlertFor:newUser saveInContext:context completion:completion]; [self showNewUserConfirmationAlertFor:newUser saveInContext:context completion:completion];
} cancelTitle:nil otherTitles:[PearlStrings get].commonButtonOkay, nil]; } cancelTitle:nil otherTitles:[PearlStrings get].commonButtonOkay, nil];
} }
- (void)showNewUserConfirmationAlertFor:(MPUserEntity *)newUser saveInContext:(NSManagedObjectContext *)context - (void)showNewUserConfirmationAlertFor:(MPUserEntity *)newUser saveInContext:(NSManagedObjectContext *)context
@ -740,7 +755,7 @@
if (![avatar.layer animationForKey:@"targetedShadow"]) { if (![avatar.layer animationForKey:@"targetedShadow"]) {
CABasicAnimation *toShadowColorAnimation = [CABasicAnimation animationWithKeyPath:@"shadowColor"]; CABasicAnimation *toShadowColorAnimation = [CABasicAnimation animationWithKeyPath:@"shadowColor"];
toShadowColorAnimation.toValue = (__bridge id)(avatar.selected? self.avatarTemplate.backgroundColor toShadowColorAnimation.toValue = (__bridge id)(avatar.selected? self.avatarTemplate.backgroundColor
: [UIColor whiteColor]).CGColor; : [UIColor whiteColor]).CGColor;
toShadowColorAnimation.beginTime = 0.0f; toShadowColorAnimation.beginTime = 0.0f;
toShadowColorAnimation.duration = 0.5f; toShadowColorAnimation.duration = 0.5f;
toShadowColorAnimation.fillMode = kCAFillModeForwards; toShadowColorAnimation.fillMode = kCAFillModeForwards;
@ -1194,8 +1209,11 @@
NSError *error; NSError *error;
MPUserEntity *selectedUser = (MPUserEntity *)[moc existingObjectWithID:_selectedUserOID error:&error]; MPUserEntity *selectedUser = (MPUserEntity *)[moc existingObjectWithID:_selectedUserOID error:&error];
if (!selectedUser) if (!selectedUser) {
err(@"Failed to retrieve selected user: %@", error); err(@"Failed to retrieve selected user: %@", error);
_selectedUserOID = nil;
[self updateUsers];
}
return selectedUser; return selectedUser;
} }
@ -1207,8 +1225,11 @@
NSError *error = nil; NSError *error = nil;
if (selectedUser.objectID.isTemporaryID && if (selectedUser.objectID.isTemporaryID &&
![selectedUser.managedObjectContext obtainPermanentIDsForObjects:@[ selectedUser ] error:&error]) ![selectedUser.managedObjectContext obtainPermanentIDsForObjects:@[ selectedUser ] error:&error]) {
err(@"Failed to obtain a permanent object ID after setting selected user: %@", error); err(@"Failed to obtain a permanent object ID after setting selected user: %@", error);
_selectedUserOID = nil;
[self updateUsers];
}
_selectedUserOID = selectedUser.objectID; _selectedUserOID = selectedUser.objectID;
return YES; return YES;

Binary file not shown.

After

Width:  |  Height:  |  Size: 669 KiB

188
Site/2013-05/privacy.html Normal file
View File

@ -0,0 +1,188 @@
<!DOCTYPE html>
<html class="no-js" itemscope itemtype="http://schema.org/Product">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<title itemprop="name">Master Password &mdash; Secure your life, forget your passwords.</title>
<meta itemprop="description" content="Master Password is an ingenious password solution that makes your passwords truly impossible to lose." />
<meta itemprop="image" content="http://masterpassword.lyndir.com/img/iTunesArtwork-Rounded.png" />
<meta name="apple-itunes-app" content="app-id=510296984" />
<meta name="viewport" content="width=device-width">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="icon" href="img/favicon.png" type="image/x-png" />
<link rel="shortcut icon" href="img/favicon.png" type="image/x-png" />
<link rel="stylesheet" href="css/bootstrap.min.css">
<link rel="stylesheet" href="css/bootstrap-responsive.min.css">
<link rel="stylesheet" href="css/main.css">
<script src="js/vendor/modernizr-2.6.2.min.js"></script>
<script src="js/vendor/prefixfree.min.js"></script>
</head>
<body itemscope itemtype="http://schema.org/MobileSoftwareApplication" id="privacy">
<!--[if lt IE 7]>
<p class="chromeframe">You are using an <strong>outdated</strong> browser. Please <a href="http://browsehappy.com/">upgrade your browser</a> or <a href="http://www.google.com/chromeframe/?redirect=true">activate Google Chrome Frame</a> to improve your experience.</p>
<![endif]-->
<nav class="navbar navbar-fixed-top">
<div class="navbar-inner">
<div class="container">
<button type="button" class="btn btn-navbar" data-toggle="collapse" data-target=".nav-collapse">
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a class="brand" href="./">●●●|</a>
<div class="nav-collapse collapse">
<ul class="nav">
<li><a href="./">App</a></li>
<li><a href="algorithm.html">Algorithm</a></li>
<li class="active"><a href="support.html">Support</a></li>
<li><a href="http://github.com/Lyndir/MasterPassword">Source</a></li>
</ul>
<ul class="nav pull-right">
<li class="divider-vertical"></li>
<li><a href="MasterPassword_PressKit.zip" onclick="_gaq.push(['_trackPageview', '/outbound/presskit']);">⬇ Press Kit</a></li>
<li><a href="http://itunes.apple.com/app/id510296984" onclick="goog_report_conversion('index-fixed-header');_gaq.push(['_trackPageview', '/outbound/itunes']);" class="img"><img src="img/appstore.svg" /></a></li>
</ul>
</div><!--/.nav-collapse -->
</div>
</div>
</nav>
<header>
<img class="background" src="img/mp-process-angled.png" data-stellar-ratio="2.5" />
<div class="container">
<!-- <div class="box effect-8">
iframe id="ytplayer" type="text/html" width="640" height="360" frameborder="0"
src="http://www.youtube.com/embed/QTfA0O7YnHQ?origin=http://masterpassword.lyndir.com&autohide=1&autoplay=0&rel=0&showinfo=0&theme=light&color=white"></iframe
<iframe width="640" height="360" frameborder="0" webkitAllowFullScreen mozallowfullscreen allowFullScreen
src="http://player.vimeo.com/video/45803664?title=0&amp;byline=0&amp;portrait=0&amp;color=ffffff"></iframe>
</div> -->
<div class="content">
<h2>Privacy Policy</h2>
</div>
</div>
</header>
<section><div class="content">
<p>We take personal satisfaction and your security very seriously. If you have any questions about features, usability, technical details, or any other topic, don't hesitate to get in touch with us. We try to give <b>thorough, detailed and personal assistance to everyone</b>.
<div class="thumb clearfix">
<h1>Your Privacy</h1>
<p>When you use Master Password for iOS, the app records some annonymous usage data for the purpose of troubleshooting. This includes logs which can be viewed using the Log Viewer, stack traces of running threads when the app crashes, and usage metrics. Any logged data has been carefully anonymized either by pruning user-specific information or cryptographically hashing it, making it impossible to reverse. Some of this data may be sent over the network, such as in the
case of app crashes, to provide us with the information necessary to resolve any issues in a timely manner.</p>
<h2>Love Lyndir</h2>
<p>Master Password is made available under the Love Lyndir campaign. This means it is now free of charge for everyone and offers a completely optional in-app way for people to contribute.</p>
<p>If you choose to contribute to the Love Lyndir campaign, you will need to make an in-app purchase via the app, which will bill your iTunes account. Additionally, our servers keep track of your active subscription with us, so that we can unlock your contribution level across all of Lyndir's apps. To do this, you'll be asked for your email address as an identifier to link your subscriptions to. This email address is currently only used as a unique identifier, but may be
used to notify subscribed users of changes or updates with regards to the Love Lyndir campaign. The email address will never be shared with any external parties.</p>
</div>
<div class="thumb clearfix">
<h1>Contact Us</h1>
<p>If you have any concerns or questions, please send us a message at <a href="mailto:masterpassword@lyndir.com">masterpassword@lyndir.com</a>. You should get a personal reply within the hour if not in minutes.</p>
</div>
</div></section>
<footer><div class="muted content">
<p><em>Master Password is a security product and algorithm by <a href="http://www.lhunath.com">Maarten Billemont</a>, <a href="http://www.lyndir.com">Lyndir</a>.</em></p>
<p><a href="http://gorillas.lyndir.com">Gorillas</a><a href="http://deblock.lyndir.com">DeBlock</a><a href="http://github.com/Lyndir">GitHub</a></p>
</div></footer>
<!-- Scripts -->
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<script>window.jQuery || document.write('<script src="js/vendor/jquery-1.9.1.min.js"><\/script>')</script>
<script src="js/vendor/bootstrap.min.js"></script>
<script src="js/plugins.js"></script>
<script src="js/main.js"></script>
<!-- Google Analytics -->
<script>
var _gaq=[['_setAccount','UA-90535-15'],['_trackPageview']];
(function(d,t){var g=d.createElement(t),s=d.getElementsByTagName(t)[0];
g.src=('https:'==location.protocol?'//ssl':'//www')+'.google-analytics.com/ga.js';
s.parentNode.insertBefore(g,s)}(document,'script'));
</script>
<!-- Google +1 -->
<script type="text/javascript" src="https://apis.google.com/js/plusone.js"></script>
<!-- Get Satisfaction -->
<!--script type="text/javascript" charset="utf-8">
var is_ssl = ("https:" == document.location.protocol);
var asset_host = is_ssl ? "https://d3rdqalhjaisuu.cloudfront.net/" : "http://d3rdqalhjaisuu.cloudfront.net/";
document.write(unescape("%3Cscript src='" + asset_host + "javascripts/feedback-v2.js' type='text/javascript'%3E%3C/script%3E"));
</script>
<script type="text/javascript" charset="utf-8">
var feedback_widget_options = {};
feedback_widget_options.display = "overlay";
feedback_widget_options.company = "lyndir";
feedback_widget_options.placement = "right";
feedback_widget_options.color = "#222";
feedback_widget_options.style = "question";
var feedback_widget = new GSFN.feedback_widget(feedback_widget_options);
</script-->
<!-- UserEcho -->
<script type='text/javascript'>
var _ues = {
host:'support.lyndir.com',
forum:'13031',
lang:'en',
tab_icon_show:false,
tab_corner_radius:5,
tab_font_size:20,
tab_image_hash:'RmVlZGJhY2s%3D',
tab_alignment:'right',
tab_text_color:'#FFFFFF',
tab_bg_color:'#DDDDDD',
tab_hover_color:'#CCCCCC'
};
(function() {
var _ue = document.createElement('script'); _ue.type = 'text/javascript'; _ue.async = true;
_ue.src = ('https:' == document.location.protocol ? 'https://s3.amazonaws.com/' : 'http://') + 'cdn.userecho.com/js/widget-1.4.gz.js';
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(_ue, s);
})();
</script>
<!-- AdWords -->
<script type="text/javascript">
/* <![CDATA[ */
goog_snippet_vars = function() {
var w = window;
w.google_conversion_id = 1015576061;
w.google_conversion_label = "PcXqCPPz5AIQ_euh5AM";
w.google_conversion_value = 4;
}
goog_report_conversion = function(url) {
goog_snippet_vars();
window.google_conversion_format = "3";
window.google_is_call = true;
var opt = new Object();
opt.onload_callback = function() {
if (typeof(url) != 'undefined') {
window.location = url;
}
}
var conv_handler = window['google_trackConversion'];
if (typeof(conv_handler) == 'function') {
conv_handler(opt);
}
}
/* ]]> */
</script>
<script type="text/javascript" src="http://www.googleadservices.com/pagead/conversion_async.js"></script>
</body>
</html>