Files
leanote-ios/Leanote/controller/auth/LoginViewController.m
2015-08-22 12:17:22 +08:00

986 lines
36 KiB
Objective-C
Executable File

//
// LoginViewController.m
// Leanote
//
// Created by life
//
#import "LoginViewController.h"
#import "WPNUXHelpBadgeLabel.h"
#import "WPWalkthroughTextField.h"
#import "WPNUXMainButton.h"
#import "WPNUXSecondaryButton.h"
#import "RegisterController.h"
#import "WPWalkthroughOverlayView.h"
#import <WordPress-iOS-Shared/WPFontManager.h>
#import <WordPress-iOS-Shared/UIColor+Helpers.h>
#import <WordPress-iOS-Shared/WPNUXUtility.h>
#import <WordPress-iOS-Shared/WPStyleGuide.h>
#import "ReachabilityUtils.h"
#import "LeaAlert.h"
#import "UserService.h"
// 一些常量 与UI相关
static CGFloat const GeneralWalkthroughStandardOffset = 15.0;
static CGFloat const GeneralWalkthroughMaxTextWidth = 290.0;
static CGSize const GeneralWalkthroughTextFieldSize = {320.0, 44.0};
static CGFloat const GeneralWalkthroughTextFieldOverlapY = 1.0;
static CGSize const GeneralWalkthroughButtonSize = {290.0, 41.0};
static CGFloat const GeneralWalkthroughSecondaryButtonHeight = 33.0;
static CGFloat const GeneralWalkthroughStatusBarOffset = 20.0;
static NSTimeInterval const GeneralWalkthroughAnimationDuration = 0.3f;
static CGFloat const GeneralWalkthroughAlphaHidden = 0.0f;
static CGFloat const GeneralWalkthroughAlphaDisabled = 0.5f;
static CGFloat const GeneralWalkthroughAlphaEnabled = 1.0f;
static CGPoint const LoginOnePasswordPadding = {9.0, 0.0f};
static NSInteger const LoginVerificationCodeNumberOfLines = 2;
@interface LoginViewController ()<UITextFieldDelegate>
@property (nonatomic, assign) BOOL isFromAddAccount;
// views
@property (nonatomic, strong) UIView *mainView;
@property (nonatomic, strong) UITapGestureRecognizer *tapGestureRecognizer;
@property (nonatomic, strong) WPNUXSecondaryButton *skipToCreateAccount;
@property (nonatomic, strong) WPNUXSecondaryButton *toggleSelfHost;
@property (nonatomic, strong) WPNUXSecondaryButton *forgotPassword;
@property (nonatomic, strong) UIButton *helpButton;
@property (nonatomic, strong) WPNUXHelpBadgeLabel *helpBadge;
@property (nonatomic, strong) UIImageView *icon;
@property (nonatomic, strong) WPWalkthroughTextField *usernameText;
@property (nonatomic, strong) WPWalkthroughTextField *passwordText;
@property (nonatomic, strong) UIButton *onePasswordButton;
@property (nonatomic, strong) WPWalkthroughTextField *multifactorText;
@property (nonatomic, strong) WPWalkthroughTextField *siteUrlText;
@property (nonatomic, strong) WPNUXMainButton *signInButton;
@property (nonatomic, strong) WPNUXSecondaryButton *sendVerificationCodeButton;
@property (nonatomic, strong) WPNUXSecondaryButton *cancelButton;
@property (nonatomic, strong) UILabel *statusLabel;
// Measurements
@property (nonatomic, assign) CGFloat keyboardOffset;
@property (nonatomic, assign) BOOL userIsDotCom;
@property (nonatomic, assign) BOOL hasDefaultAccount;
@property (nonatomic, assign) BOOL shouldDisplayMultifactor;
@property (nonatomic, assign) BOOL authenticating;
@property (nonatomic, strong) void (^loginOkCb)();
@end
@implementation LoginViewController
// 从添加帐户按钮中跳到该界面
-(void)fromAddAccount:(BOOL)ok loginOkCb:(void (^)())loginOkCb
{
self.isFromAddAccount = ok;
self.loginOkCb = loginOkCb;
}
- (void)viewDidLoad
{
[super viewDidLoad];
self.userIsDotCom = YES;
self.view.backgroundColor = [WPStyleGuide wordPressBlue];
[self addMainView];
[self addControls];
[self reloadInterface];
}
-(void)viewDidAppear:(BOOL)animated {
[super viewWillAppear:animated];
[self.navigationController setNavigationBarHidden:YES animated:animated];
NSNotificationCenter *nc = [NSNotificationCenter defaultCenter];
[nc addObserver:self selector:@selector(keyboardWillShow:) name:UIKeyboardWillShowNotification object:nil];
[nc addObserver:self selector:@selector(keyboardWillHide:) name:UIKeyboardWillHideNotification object:nil];
// [nc addObserver:self selector:@selector(helpshiftUnreadCountUpdated:) name:HelpshiftUnreadCountUpdatedNotification object:nil];
[nc addObserver:self selector:@selector(textFieldDidChange:) name:UITextFieldTextDidChangeNotification object:nil];
// reload
// [self reloadInterface];
return;
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#pragma mark LoginView
- (void)addMainView
{
NSAssert(self.view, @"The view should be loaded by now");
UIView *mainView = [[UIView alloc] initWithFrame:self.view.bounds];
mainView.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth;
// 手势
/*
UITapGestureRecognizer *gestureRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(backgroundTapGestureAction:)];
gestureRecognizer.numberOfTapsRequired = 1;
gestureRecognizer.cancelsTouchesInView = YES;
[mainView addGestureRecognizer:gestureRecognizer];
self.tapGestureRecognizer = gestureRecognizer;
*/
// Attach + Keep the Reference
[self.view addSubview:mainView];
self.mainView = mainView;
}
// 都是用代码来实现的啊
- (void)addControls
{
NSAssert(self.view, @"The view should be loaded by now");
NSAssert(self.mainView, @"Please, initialize the mainView first");
// Add Icon
UIImageView *icon = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"leanote-icon-circle"]]; // icon-wp
icon.autoresizingMask = UIViewAutoresizingFlexibleRightMargin | UIViewAutoresizingFlexibleLeftMargin;
// Add Info button
UIImage *infoButtonImage = [UIImage imageNamed:@"btn-help"];
UIButton *helpButton = [UIButton buttonWithType:UIButtonTypeCustom];
helpButton.accessibilityLabel = NSLocalizedString(@"Help", @"Help button");
[helpButton setImage:infoButtonImage forState:UIControlStateNormal];
helpButton.frame = CGRectMake(GeneralWalkthroughStandardOffset, GeneralWalkthroughStandardOffset, infoButtonImage.size.width, infoButtonImage.size.height);
helpButton.autoresizingMask = UIViewAutoresizingFlexibleRightMargin | UIViewAutoresizingFlexibleLeftMargin;
[helpButton addTarget:self action:@selector(helpButtonAction:) forControlEvents:UIControlEventTouchUpInside];
[helpButton sizeToFit];
[helpButton setExclusiveTouch:YES];
// 帮助按钮隐藏
helpButton.hidden = YES;
// Help badge, 小圆点(未读消息)
WPNUXHelpBadgeLabel *helpBadge = [[WPNUXHelpBadgeLabel alloc] initWithFrame:CGRectMake(0, 0, 12, 10)];
helpBadge.layer.masksToBounds = YES;
helpBadge.layer.cornerRadius = 6;
helpBadge.textAlignment = NSTextAlignmentCenter;
helpBadge.backgroundColor = [UIColor UIColorFromHex:0xdd3d36];
helpBadge.textColor = [UIColor whiteColor];
helpBadge.font = [WPFontManager openSansRegularFontOfSize:8.0];
helpBadge.hidden = YES;
// Add Username
WPWalkthroughTextField *usernameText = [[WPWalkthroughTextField alloc] initWithLeftViewImage:[UIImage imageNamed:@"icon-username-field"]];
usernameText.backgroundColor = [UIColor whiteColor];
usernameText.placeholder = NSLocalizedString(@"Username / Email", @"NUX First Walkthrough Page 2 Username Placeholder");
usernameText.font = [WPNUXUtility textFieldFont];
usernameText.adjustsFontSizeToFitWidth = YES;
usernameText.returnKeyType = UIReturnKeyNext;
usernameText.delegate = self;
usernameText.autocorrectionType = UITextAutocorrectionTypeNo;
usernameText.autocapitalizationType = UITextAutocapitalizationTypeNone;
usernameText.autoresizingMask = UIViewAutoresizingFlexibleRightMargin | UIViewAutoresizingFlexibleLeftMargin;
usernameText.accessibilityIdentifier = @"Username / Email";
// Add OnePassword ??
/*
UIButton *onePasswordButton = [UIButton buttonWithType:UIButtonTypeCustom];
[onePasswordButton setImage:[UIImage imageNamed:@"onepassword-button"] forState:UIControlStateNormal];
[onePasswordButton addTarget:self action:@selector(findLoginFromOnePassword:) forControlEvents:UIControlEventTouchUpInside];
[onePasswordButton sizeToFit];
usernameText.rightView = onePasswordButton;
usernameText.rightViewPadding = LoginOnePasswordPadding;
*/
// Add Password
WPWalkthroughTextField *passwordText = [[WPWalkthroughTextField alloc] initWithLeftViewImage:[UIImage imageNamed:@"icon-password-field"]];
passwordText.backgroundColor = [UIColor whiteColor];
passwordText.placeholder = NSLocalizedString(@"Password", nil);
passwordText.font = [WPNUXUtility textFieldFont];
passwordText.delegate = self;
passwordText.secureTextEntry = YES;
passwordText.returnKeyType = self.userIsDotCom ? UIReturnKeyDone : UIReturnKeyNext;
passwordText.showSecureTextEntryToggle = YES;
passwordText.showTopLineSeparator = YES;
passwordText.autoresizingMask = UIViewAutoresizingFlexibleRightMargin | UIViewAutoresizingFlexibleLeftMargin;
passwordText.accessibilityIdentifier = @"Password";
// Add Site Url
// 自建服务输入框
WPWalkthroughTextField *siteUrlText = [[WPWalkthroughTextField alloc] initWithLeftViewImage:[UIImage imageNamed:@"icon-url-field"]];
siteUrlText.backgroundColor = [UIColor whiteColor];
siteUrlText.placeholder = NSLocalizedString(@"Site Address (URL)", @"NUX First Walkthrough Page 2 Site Address Placeholder");
siteUrlText.font = [WPNUXUtility textFieldFont];
siteUrlText.adjustsFontSizeToFitWidth = YES;
siteUrlText.delegate = self;
siteUrlText.keyboardType = UIKeyboardTypeURL;
siteUrlText.returnKeyType = UIReturnKeyDone;
siteUrlText.autocorrectionType = UITextAutocorrectionTypeNo;
siteUrlText.autocapitalizationType = UITextAutocapitalizationTypeNone;
siteUrlText.showTopLineSeparator = YES;
siteUrlText.autoresizingMask = UIViewAutoresizingFlexibleRightMargin | UIViewAutoresizingFlexibleLeftMargin;
siteUrlText.accessibilityIdentifier = @"Site Address (URL)";
// Add Sign In Button
WPNUXMainButton *signInButton = [[WPNUXMainButton alloc] init];
[signInButton addTarget:self action:@selector(signInButtonAction:) forControlEvents:UIControlEventTouchUpInside];
signInButton.autoresizingMask = UIViewAutoresizingFlexibleRightMargin | UIViewAutoresizingFlexibleLeftMargin;
signInButton.accessibilityIdentifier = @"Sign In";
/*
// Text: Verification Code SMS
// 短信, 没用
NSString *codeText = NSLocalizedString(@"Enter the code on your authenticator app or ", @"Message displayed when a verification code is needed");
NSMutableAttributedString *attributedCodeText = [[NSMutableAttributedString alloc] initWithString:codeText];
NSString *smsText = NSLocalizedString(@"send the code via text message.", @"Sends an SMS with the Multifactor Auth Code");
NSMutableAttributedString *attributedSmsText = [[NSMutableAttributedString alloc] initWithString:smsText];
[attributedSmsText applyUnderline];
[attributedCodeText appendAttributedString:attributedSmsText];
[attributedCodeText applyFont:[WPNUXUtility confirmationLabelFont]];
[attributedCodeText applyForegroundColor:[UIColor whiteColor]];
NSMutableAttributedString *attributedCodeHighlighted = [attributedCodeText mutableCopy];
[attributedCodeHighlighted applyForegroundColor:[WPNUXUtility confirmationLabelColor]];
// Add Verification Code SMS Button
WPNUXSecondaryButton *sendVerificationCodeButton = [[WPNUXSecondaryButton alloc] init];
sendVerificationCodeButton.autoresizingMask = UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleRightMargin | UIViewAutoresizingFlexibleBottomMargin;
sendVerificationCodeButton.titleLabel.lineBreakMode = NSLineBreakByWordWrapping;
sendVerificationCodeButton.titleLabel.textAlignment = NSTextAlignmentCenter;
sendVerificationCodeButton.titleLabel.numberOfLines = LoginVerificationCodeNumberOfLines;
[sendVerificationCodeButton setAttributedTitle:attributedCodeText forState:UIControlStateNormal];
[sendVerificationCodeButton setAttributedTitle:attributedCodeHighlighted forState:UIControlStateHighlighted];
[sendVerificationCodeButton addTarget:self action:@selector(sendVerificationCode:) forControlEvents:UIControlEventTouchUpInside];
// Add Multifactor 验证码, 没用
WPWalkthroughTextField *multifactorText = [[WPWalkthroughTextField alloc] init];
multifactorText.backgroundColor = [UIColor whiteColor];
multifactorText.placeholder = NSLocalizedString(@"Verification Code", nil);
multifactorText.font = [WPNUXUtility textFieldFont];
multifactorText.delegate = self;
multifactorText.keyboardType = UIKeyboardTypeNumberPad;
multifactorText.textAlignment = NSTextAlignmentCenter;
multifactorText.returnKeyType = UIReturnKeyDone;
multifactorText.showTopLineSeparator = YES;
multifactorText.autoresizingMask = UIViewAutoresizingFlexibleRightMargin | UIViewAutoresizingFlexibleLeftMargin;
multifactorText.accessibilityIdentifier = @"Verification Code";
*/
// Add Cancel Button
WPNUXSecondaryButton *cancelButton = [[WPNUXSecondaryButton alloc] init];
[cancelButton setTitle:NSLocalizedString(@"Cancel", nil) forState:UIControlStateNormal];
[cancelButton addTarget:self action:@selector(cancelButtonAction) forControlEvents:UIControlEventTouchUpInside];
[cancelButton setExclusiveTouch:YES];
[cancelButton sizeToFit];
// Add status label
UILabel *statusLabel = [[UILabel alloc] init];
statusLabel.font = [WPNUXUtility confirmationLabelFont];
statusLabel.textColor = [WPNUXUtility confirmationLabelColor];
statusLabel.textAlignment = NSTextAlignmentCenter;
statusLabel.lineBreakMode = NSLineBreakByTruncatingTail;
statusLabel.autoresizingMask = UIViewAutoresizingFlexibleRightMargin | UIViewAutoresizingFlexibleLeftMargin;
// Add Account type toggle
WPNUXSecondaryButton *toggleSelfHost = [[WPNUXSecondaryButton alloc] init];
[toggleSelfHost addTarget:self action:@selector(toggleSelfHostAction:) forControlEvents:UIControlEventTouchUpInside];
toggleSelfHost.autoresizingMask = UIViewAutoresizingFlexibleRightMargin | UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleTopMargin;
// Add Skip to Create Account Button
// 添加帐户
WPNUXSecondaryButton *skipToCreateAccount = [[WPNUXSecondaryButton alloc] init];
skipToCreateAccount.autoresizingMask = UIViewAutoresizingFlexibleRightMargin | UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleTopMargin;
[skipToCreateAccount setTitle:NSLocalizedString(@"Create Account", nil) forState:UIControlStateNormal];
[skipToCreateAccount addTarget:self action:@selector(skipToCreateAction:) forControlEvents:UIControlEventTouchUpInside];
// Add Lost Password Button
WPNUXSecondaryButton *forgotPassword = [[WPNUXSecondaryButton alloc] init];
forgotPassword.autoresizingMask = UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleRightMargin | UIViewAutoresizingFlexibleBottomMargin;
[forgotPassword setTitle:NSLocalizedString(@"Lost your password?", nil) forState:UIControlStateNormal];
[forgotPassword addTarget:self action:@selector(forgotPassword:) forControlEvents:UIControlEventTouchUpInside];
forgotPassword.titleLabel.font = [WPNUXUtility tosLabelFont];
[forgotPassword setTitleColor:[WPNUXUtility tosLabelColor] forState:UIControlStateNormal];
// Attach Subviews
[self.view addSubview:cancelButton];
[self.mainView addSubview:icon];
[self.mainView addSubview:helpButton];
[self.mainView addSubview:helpBadge];
[self.mainView addSubview:usernameText];
[self.mainView addSubview:passwordText];
// [self.mainView addSubview:multifactorText];
// [self.mainView addSubview:sendVerificationCodeButton];
[self.mainView addSubview:siteUrlText];
[self.mainView addSubview:signInButton];
[self.mainView addSubview:statusLabel];
[self.mainView addSubview:toggleSelfHost];
[self.mainView addSubview:skipToCreateAccount];
[self.mainView addSubview:forgotPassword];
// Keep the references!
self.cancelButton = cancelButton;
self.icon = icon;
self.helpButton = helpButton;
self.helpBadge = helpBadge;
self.usernameText = usernameText;
self.passwordText = passwordText;
// self.onePasswordButton = onePasswordButton;
// self.multifactorText = multifactorText;
// self.sendVerificationCodeButton = sendVerificationCodeButton;
self.siteUrlText = siteUrlText;
self.signInButton = signInButton;
self.statusLabel = statusLabel;
self.toggleSelfHost = toggleSelfHost;
self.skipToCreateAccount = skipToCreateAccount;
self.forgotPassword = forgotPassword;
}
- (void)reloadInterface
{
[self updateControls];
[self layoutControls];
}
- (void)updateControls
{
// Spinner!
[self.signInButton showActivityIndicator:self.authenticating];
// One Password
// BOOL isOnePasswordAvailable = [[OnePasswordExtension sharedExtension] isAppExtensionAvailable];
// self.usernameText.rightViewMode = isOnePasswordAvailable ? UITextFieldViewModeAlways : UITextFieldViewModeNever;
// TextFields
self.usernameText.alpha = self.usernameAlpha;
self.passwordText.alpha = self.passwordAlpha;
self.siteUrlText.alpha = self.siteAlpha;
// self.multifactorText.alpha = self.multifactorAlpha;
self.usernameText.enabled = self.isUsernameEnabled;
self.passwordText.enabled = self.isPasswordEnabled;
self.siteUrlText.enabled = self.isSiteUrlEnabled;
// self.multifactorText.enabled = self.isMultifactorEnabled;
// Buttons
self.cancelButton.hidden = !self.isFromAddAccount;
NSLog(self.isFromAddAccount ? @"isFromAddAccount" : @"NO");
self.forgotPassword.hidden = self.isForgotPasswordHidden;
// self.sendVerificationCodeButton.hidden = self.isSendCodeHidden;
self.skipToCreateAccount.hidden = self.isAccountCreationHidden;
// SignIn Button
NSString *signInTitle = self.signInButtonTitle;
self.signInButton.enabled = self.isSignInEnabled;
self.signInButton.accessibilityIdentifier = signInTitle;
[self.signInButton setTitle:signInTitle forState:UIControlStateNormal];
// Dotcom / SelfHosted Button
NSString *toggleTitle = self.toggleAddSelfHostTitle;
self.toggleSelfHost.accessibilityIdentifier = toggleTitle;
[self.toggleSelfHost setTitle:toggleTitle forState:UIControlStateNormal];
}
- (void)layoutControls
{
CGFloat viewWidth = CGRectGetWidth(self.view.bounds);
CGFloat viewHeight = CGRectGetHeight(self.view.bounds);
CGFloat textFieldX = (viewWidth - GeneralWalkthroughTextFieldSize.width) * 0.5f;
CGFloat textLabelX = (viewWidth - GeneralWalkthroughMaxTextWidth) * 0.5f;
CGFloat buttonX = (viewWidth - GeneralWalkthroughButtonSize.width) * 0.5f;
// Layout Help Button
CGFloat helpButtonX = viewWidth - CGRectGetWidth(self.helpButton.frame) - GeneralWalkthroughStandardOffset;
CGFloat helpButtonY = 0.5 * GeneralWalkthroughStandardOffset + GeneralWalkthroughStatusBarOffset;
self.helpButton.frame = CGRectIntegral(CGRectMake(helpButtonX, helpButtonY, CGRectGetWidth(self.helpButton.frame), GeneralWalkthroughButtonSize.height));
// layout help badge
/*
CGFloat helpBadgeX = viewWidth - CGRectGetWidth(self.helpBadge.frame) - GeneralWalkthroughStandardOffset + 5;
CGFloat helpBadgeY = 0.5 * GeneralWalkthroughStandardOffset + GeneralWalkthroughStatusBarOffset + CGRectGetHeight(self.helpBadge.frame) - 5;
self.helpBadge.frame = CGRectIntegral(CGRectMake(helpBadgeX, helpBadgeY, CGRectGetWidth(self.helpBadge.frame), CGRectGetHeight(self.helpBadge.frame)));
*/
// Layout Cancel Button
CGFloat cancelButtonX = 0;
CGFloat cancelButtonY = helpButtonY; // 0.5 * GeneralWalkthroughStandardOffset + GeneralWalkthroughStatusBarOffset;
self.cancelButton.frame = CGRectIntegral(CGRectMake(cancelButtonX, cancelButtonY, CGRectGetWidth(self.cancelButton.frame), GeneralWalkthroughButtonSize.height));
// Calculate total height and starting Y origin of controls
CGFloat heightOfControls = CGRectGetHeight(self.icon.frame) + GeneralWalkthroughStandardOffset + (self.userIsDotCom ? 2 : 3) * GeneralWalkthroughTextFieldSize.height + GeneralWalkthroughStandardOffset + GeneralWalkthroughButtonSize.height;
// 开始Y位置
CGFloat startingYForCenteredControls = floorf((viewHeight - 2 * GeneralWalkthroughSecondaryButtonHeight - heightOfControls)/2.0);
// icon
CGFloat iconX = (viewWidth - CGRectGetWidth(self.icon.frame)) * 0.5f; // 居中之
CGFloat iconY = startingYForCenteredControls;
self.icon.frame = CGRectIntegral(CGRectMake(iconX, iconY, CGRectGetWidth(self.icon.frame), CGRectGetHeight(self.icon.frame)));
// Layout Username CGRectGetMaxY 返回矩形底部y坐标, 基于icon坐标+offset
CGFloat usernameTextY = CGRectGetMaxY(self.icon.frame) + GeneralWalkthroughStandardOffset;
self.usernameText.frame = CGRectIntegral(CGRectMake(textFieldX, usernameTextY,
GeneralWalkthroughTextFieldSize.width,
GeneralWalkthroughTextFieldSize.height));
// Layout Password
CGFloat passwordTextY = CGRectGetMaxY(self.usernameText.frame) - GeneralWalkthroughTextFieldOverlapY;
self.passwordText.frame = CGRectIntegral(CGRectMake(textFieldX, passwordTextY,
GeneralWalkthroughTextFieldSize.width,
GeneralWalkthroughTextFieldSize.height));
// Layout Site URL
// 自建服务
CGFloat siteUrlTextY = CGRectGetMaxY(self.passwordText.frame) - GeneralWalkthroughTextFieldOverlapY;
self.siteUrlText.frame = CGRectIntegral(CGRectMake(textFieldX, siteUrlTextY, GeneralWalkthroughTextFieldSize.width, GeneralWalkthroughTextFieldSize.height));
// Layout Sign in Button, 在最后一个textFiled下面
CGFloat signInButtonY = [self lastTextfieldMaxY] + GeneralWalkthroughStandardOffset;
self.signInButton.frame = CGRectIntegral(CGRectMake(buttonX, signInButtonY, GeneralWalkthroughButtonSize.width, GeneralWalkthroughButtonSize.height));
// Layout Lost password Button
CGFloat forgotPasswordY = CGRectGetMaxY(self.signInButton.frame) + 0.5 * GeneralWalkthroughStandardOffset;
CGFloat forgotPasswordHeight = [self.forgotPassword.titleLabel.text sizeWithAttributes:@{NSFontAttributeName:self.forgotPassword.titleLabel.font}].height;
self.forgotPassword.frame = CGRectIntegral(CGRectMake(buttonX, forgotPasswordY, GeneralWalkthroughButtonSize.width, forgotPasswordHeight));
// Layout Skip to Create Account Button
// 相对于底部而言的位置
CGFloat skipToCreateAccountY = viewHeight - GeneralWalkthroughStandardOffset - GeneralWalkthroughSecondaryButtonHeight;
self.skipToCreateAccount.frame = CGRectIntegral(CGRectMake(buttonX, skipToCreateAccountY, GeneralWalkthroughButtonSize.width, GeneralWalkthroughSecondaryButtonHeight));
// Layout Status Label
CGFloat statusLabelY = CGRectGetMaxY(self.signInButton.frame) + 0.5 * GeneralWalkthroughStandardOffset;
self.statusLabel.frame = CGRectIntegral(CGRectMake(textLabelX, statusLabelY, GeneralWalkthroughMaxTextWidth, self.statusLabel.font.lineHeight));
// Layout Toggle Button
CGFloat toggleSignInY = CGRectGetMinY(self.skipToCreateAccount.frame) - 0.5 * GeneralWalkthroughStandardOffset - GeneralWalkthroughSecondaryButtonHeight;
self.toggleSelfHost.frame = CGRectIntegral(CGRectMake(textLabelX, toggleSignInY, GeneralWalkthroughMaxTextWidth, GeneralWalkthroughSecondaryButtonHeight));
}
// 关闭
- (void)cancelButtonAction {
[self dismissViewControllerAnimated:YES completion:nil];
}
#pragma mark - Validation Helpers
- (BOOL)areFieldsValid
{
if ([self areSelfHostedFieldsFilled] && !self.userIsDotCom) {
return [self isUrlValid];
}
return [self areDotComFieldsFilled];
}
- (BOOL)isUsernameFilled
{
return [[self trim:self.usernameText.text] length] != 0;
}
- (NSString *) trim:(NSString *) t {
[t stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];
return t;
}
- (BOOL)isPasswordFilled
{
return [[self trim:self.passwordText.text] length] != 0;
}
- (BOOL)isSiteUrlFilled
{
return [[self trim:self.siteUrlText.text] length] != 0;
}
// leanote.com要输入的用户名和密码是否都输完
- (BOOL)areDotComFieldsFilled
{
BOOL areCredentialsFilled = [self isUsernameFilled] && [self isPasswordFilled];
return areCredentialsFilled;
}
- (BOOL)areSelfHostedFieldsFilled
{
return [self areDotComFieldsFilled] && [self isSiteUrlFilled];
}
- (BOOL)isUrlValid
{
NSString *url = self.siteUrlText.text;
if (url.length == 0) {
return NO;
}
// 判断是否合法 http://leanote.com
// http://www.no-ip.biz
NSString *urlRegEx = @"(http|https)://((\\w)*([0-9]*)|([-|_])*)+\\.([\\w0-9\\-|_\\./:])*";
NSPredicate *urlTest = [NSPredicate predicateWithFormat:@"SELF MATCHES %@", urlRegEx];
return [urlTest evaluateWithObject:url];
// NSURL *siteURL = [NSURL URLWithString:[NSURL IDNEncodedURL:self.siteUrlText.text]];
// return siteURL != nil;
}
- (BOOL)isUserNameReserved
{
if (!self.userIsDotCom) {
return NO;
}
// NSString *username = [[self.usernameText.text trim] lowercaseString];
// NSArray *reservedUserNames = @[@"admin",@"administrator",@"root"];
// return [reservedUserNames containsObject:username];
}
#pragma mark - Interface Helpers: TextFields
- (BOOL)isUsernameEnabled
{
return !self.shouldDisplayMultifactor;
}
- (BOOL)isPasswordEnabled
{
return !self.shouldDisplayMultifactor;
}
- (BOOL)isSiteUrlEnabled
{
return !self.userIsDotCom;
}
- (BOOL)isMultifactorEnabled
{
return self.shouldDisplayMultifactor;
}
- (CGFloat)usernameAlpha
{
return self.isUsernameEnabled ? GeneralWalkthroughAlphaEnabled : GeneralWalkthroughAlphaDisabled;
}
- (CGFloat)passwordAlpha
{
return self.isPasswordEnabled ? GeneralWalkthroughAlphaEnabled : GeneralWalkthroughAlphaDisabled;
}
// 添加自建服务是否隐藏
- (CGFloat)siteAlpha
{
if (self.isSiteUrlEnabled) {
return self.isMultifactorEnabled ? GeneralWalkthroughAlphaDisabled : GeneralWalkthroughAlphaEnabled;
}
return GeneralWalkthroughAlphaHidden;
}
#pragma mark - Interface Helpers: Buttons
- (BOOL)isSignInEnabled
{
return self.userIsDotCom ? [self areDotComFieldsFilled] : [self areSelfHostedFieldsFilled];
}
- (BOOL)isSignInToggleHidden
{
// return self.onlyDotComAllowed || self.hasDefaultAccount || self.authenticating;
return NO;
}
- (BOOL)isAccountCreationHidden
{
return self.hasDefaultAccount || self.authenticating;
}
- (BOOL)isForgotPasswordHidden
{
BOOL isEnabled = self.userIsDotCom || self.isUrlValid;
return !isEnabled || self.authenticating || self.shouldDisplayMultifactor;
}
#pragma mark - Text Helpers
- (NSString *)signInButtonTitle
{
if (self.shouldDisplayMultifactor) {
return NSLocalizedString(@"Verify", @"Button title for Two Factor code verification");
} else if (self.userIsDotCom) {
return NSLocalizedString(@"Sign In", @"Button title for Sign In Action");
}
return NSLocalizedString(@"Add Site", @"Button title for Add SelfHosted Site");
}
- (NSString *)toggleAddSelfHostTitle
{
if (self.userIsDotCom) {
return NSLocalizedString(@"Add Self-Hosted Service", @"Button title for Toggle Sign Mode (Self Hosted vs DotCom");
}
return NSLocalizedString(@"Sign in to Leanote.com", @"Button title for Toggle Sign Mode (Self Hosted vs DotCom");
}
// sign in按钮是在最后一个input后面
- (CGFloat)lastTextfieldMaxY
{
if (self.userIsDotCom) {
return CGRectGetMaxY(self.passwordText.frame);
}
return CGRectGetMaxY(self.siteUrlText.frame);
}
// 编辑模式下至少要显示sign button
- (CGFloat)editionModeMaxY
{
UIView *bottomView = self.signInButton;
return CGRectGetMaxY(bottomView.frame);
}
#pragma mark - Auth Helpers
- (void)startedAuthenticatingWithMessage:(NSString *)status
{
[self setAuthenticating:YES status:status];
}
- (void)finishedAuthenticating
{
[self setAuthenticating:NO status:nil];
}
- (void)setAuthenticating:(BOOL)authenticating status:(NSString *)status
{
self.authenticating = authenticating;
self.statusLabel.hidden = !(status.length > 0);
self.statusLabel.text = status;
self.view.userInteractionEnabled = !authenticating;
[self updateControls];
}
#pragma mark - UITextField delegate methods
- (BOOL)textFieldShouldReturn:(UITextField *)textField
{
if (textField == self.usernameText) {
[self.passwordText becomeFirstResponder];
}
else if (textField == self.passwordText) {
if (self.userIsDotCom) {
[self signInButtonAction:nil];
} else {
[self.siteUrlText becomeFirstResponder];
}
}
else if (textField == self.siteUrlText) {
if (self.signInButton.enabled) {
[self signInButtonAction:nil];
}
}
return YES;
}
- (BOOL)textFieldShouldBeginEditing:(UITextField *)textField
{
return YES;
}
- (BOOL)textFieldShouldEndEditing:(UITextField *)textField
{
return YES;
}
- (void)textFieldDidChange:(NSNotification *)note
{
[self updateControls];
}
#pragma mark - Keyboard Handling 链接显示时要移动view
- (void)keyboardWillShow:(NSNotification *)notification
{
NSDictionary *keyboardInfo = notification.userInfo;
CGFloat animationDuration = [[keyboardInfo objectForKey:UIKeyboardAnimationDurationUserInfoKey] floatValue];
CGRect keyboardFrame = [[[notification userInfo] objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue];
keyboardFrame = [self.view convertRect:keyboardFrame fromView:nil];
CGFloat newKeyboardOffset = (self.editionModeMaxY - CGRectGetMinY(keyboardFrame)) + GeneralWalkthroughStandardOffset;
if (newKeyboardOffset < 0) {
return;
}
[UIView animateWithDuration:animationDuration animations:^{
for (UIControl *control in [self controlsToHideWithKeyboardOffset:newKeyboardOffset]) {
control.alpha = GeneralWalkthroughAlphaHidden;
}
// 每一个控制都移下位置, 向上移动
for (UIControl *control in [self controlsToMoveForTextEntry]) {
CGRect frame = control.frame;
frame.origin.y -= newKeyboardOffset;
control.frame = frame;
}
} completion:^(BOOL finished) {
self.keyboardOffset += newKeyboardOffset;
}];
}
- (void)keyboardWillHide:(NSNotification *)notification
{
NSDictionary *keyboardInfo = notification.userInfo;
CGFloat animationDuration = [[keyboardInfo objectForKey:UIKeyboardAnimationDurationUserInfoKey] floatValue];
CGFloat currentKeyboardOffset = self.keyboardOffset;
self.keyboardOffset = 0;
[UIView animateWithDuration:animationDuration animations:^{
for (UIControl *control in [self controlsToHideWithKeyboardOffset:currentKeyboardOffset]) {
control.alpha = GeneralWalkthroughAlphaEnabled;
}
for (UIControl *control in [self controlsToMoveForTextEntry]) {
CGRect frame = control.frame;
frame.origin.y += currentKeyboardOffset;
control.frame = frame;
}
}];
}
- (NSArray *)controlsToMoveForTextEntry
{
return @[ self.icon, self.usernameText, self.passwordText, self.siteUrlText, self.signInButton, self.statusLabel ];
}
// 显示键盘时, help按钮隐藏掉
- (NSArray *)controlsToHideWithKeyboardOffset:(CGFloat)offset
{
// Always hide the Help + Badge
NSMutableArray *controlsToHide = [NSMutableArray array];
[controlsToHide addObjectsFromArray:@[ self.helpButton, self.helpBadge ]];
// Find controls that fall off the screen
for (UIView *control in self.controlsToMoveForTextEntry) {
if (control.frame.origin.y - offset <= 0) {
[controlsToHide addObject:control];
}
}
return controlsToHide;
}
# pragma 动作
- (IBAction)forgotPassword:(id)sender
{
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:@"https://leanote.com/findPassword"]];
}
// 自建服务按钮
- (IBAction)toggleSelfHostAction:(id)sender
{
self.userIsDotCom = !self.userIsDotCom;
self.passwordText.returnKeyType = self.userIsDotCom ? UIReturnKeyDone : UIReturnKeyNext;
// 重新relayout, 有动画
// Controls are layed out in initializeView. Calling this method in an animation block will animate the controls
// to their new positions.
[UIView animateWithDuration:GeneralWalkthroughAnimationDuration
animations:^{
[self reloadInterface];
}];
}
// 登录
- (IBAction)signInButtonAction:(id)sender
{
[self.view endEditing:YES];
// 是否有网络
if (![ReachabilityUtils isInternetReachable]) {
[ReachabilityUtils showAlertNoInternetConnection];
return;
}
if ([self areSelfHostedFieldsFilled] && !self.userIsDotCom) {
if(![self isUrlValid]) {
[LeaAlert showAlertWithTitle:NSLocalizedString(@"Error", nil) message:NSLocalizedString(@"Self hosted url is invalid", nil) withSupportButton:NO];
return;
}
}
if (![self areDotComFieldsFilled]) {
[self displayErrorMessages];
return;
}
/*
if ([self isUserNameReserved]) {
[self displayReservedNameErrorMessage];
[self toggleSignInFormAction:nil];
[self.siteUrlText becomeFirstResponder];
return;
}
*/
[self signIn];
}
- (void)signIn
{
NSString *username = self.usernameText.text;
NSString *password = self.passwordText.text;
NSString *siteUrl = self.siteUrlText.text;
[self startedAuthenticatingWithMessage:NSLocalizedString(@"Authenticating", nil)];
[UserService login:username pwd: password host: siteUrl success:^(id ret) {
[self finishedAuthenticating];
if(!self.isFromAddAccount) {
self.loginOkCb();
// 跳到首页
// [self.delegate WidgetsVC:self loginOK:nil];
}
else {
self.loginOkCb();
// [self cancelButtonAction];
}
} fail:^{
[self displayRemoteError];
[self finishedAuthenticating];
}];
// [self.userIsDotCom];
/*
WordPressComOAuthClient *client = [WordPressComOAuthClient client];
[client authenticateWithUsername:username
password:password
multifactorCode:multifactor
success:^(NSString *authToken) {
[self finishedAuthenticating];
[self removeLegacyAccountIfNeeded:username];
[self createWordPressComAccountForUsername:username authToken:authToken];
} failure:^(NSError *error) {
// Remove the Spinner + Status Message
[self finishedAuthenticating];
// If needed, show the multifactor field
if (error.code == WordPressComOAuthErrorNeedsMultifactorCode) {
[self displayMultifactorTextfield];
} else {
NSDictionary *properties = @{ @"multifactor" : @(self.shouldDisplayMultifactor) };
[WPAnalytics track:WPAnalyticsStatLoginFailed withProperties:properties];
[self displayRemoteError:error];
}
}];
*/
/*
void (^guessXMLRPCURLSuccess)(NSURL *) = ^(NSURL *xmlRPCURL) {
WordPressXMLRPCApi *api = [WordPressXMLRPCApi apiWithXMLRPCEndpoint:xmlRPCURL username:username password:password];
[api getBlogOptionsWithSuccess:^(id options){
[self finishedAuthenticating];
if ([options objectForKey:@"wordpress.com"] != nil) {
[self signInWithWPComForUsername:username password:password multifactor:multifactor];
} else {
NSString *xmlrpc = [xmlRPCURL absoluteString];
[self createSelfHostedAccountAndBlogWithUsername:username password:password xmlrpc:xmlrpc options:options];
}
} failure:^(NSError *error){
[WPAnalytics track:WPAnalyticsStatLoginFailed];
[self finishedAuthenticating];
[self displayRemoteError:error];
}];
};
void (^guessXMLRPCURLFailure)(NSError *) = ^(NSError *error){
[WPAnalytics track:WPAnalyticsStatLoginFailedToGuessXMLRPC];
[self handleGuessXMLRPCURLFailure:error];
};
[self startedAuthenticatingWithMessage:NSLocalizedString(@"Authenticating", nil)];
NSString *siteUrl = [NSURL IDNEncodedURL:self.siteUrlText.text];
[WordPressXMLRPCApi guessXMLRPCURLForSite:siteUrl success:guessXMLRPCURLSuccess failure:guessXMLRPCURLFailure];
*/
}
- (IBAction)skipToCreateAction:(id)sender
{
[self register];
}
- (void) register {
NSLog(@"skipToCreateAction");
// TestViewController.h
RegisterController *createAccountViewController = [[RegisterController alloc] init];
[createAccountViewController cb:^{
self.loginOkCb();
}];
[self.navigationController pushViewController:createAccountViewController animated:YES];
}
#pragma mark - Displaying of Error Messages
- (void)displayErrorMessages
{
[LeaAlert showAlertWithTitle:NSLocalizedString(@"Error", nil) message:NSLocalizedString(@"Please fill out all the fields", nil) withSupportButton:NO];
}
- (void)showError:(NSString *)message
{
WPWalkthroughOverlayView *overlayView = [[WPWalkthroughOverlayView alloc] initWithFrame:self.view.bounds];
overlayView.overlayTitle = NSLocalizedString(@"Error", nil);
overlayView.overlayDescription = message;
overlayView.dismissCompletionBlock = ^(WPWalkthroughOverlayView *overlayView){
[overlayView dismiss];
};
[self.view addSubview:overlayView];
}
- (void)displayRemoteError
{
NSString *errorMessage = NSLocalizedString(@"Username or password is not valid", nil);
[self showError:NSLocalizedString(errorMessage, nil)];
}
@end