Files
keyboard/keyBoard/Class/Login/VC/KBLoginVC.m

425 lines
17 KiB
Mathematica
Raw Normal View History

2025-12-02 18:29:04 +08:00
//
// KBLoginVC.m
// keyBoard
//
// Created by Mac on 2025/12/2.
//
#import "KBLoginVC.h"
#import <AuthenticationServices/AuthenticationServices.h>
2025-12-02 19:19:25 +08:00
#import "KBLoginVM.h"
2025-12-03 13:31:02 +08:00
#import "AppDelegate.h"
2025-12-02 18:29:04 +08:00
2025-12-02 19:19:25 +08:00
@interface KBLoginVC () <UITextViewDelegate>
2025-12-02 18:29:04 +08:00
//
@property (nonatomic, strong) UIImageView *bgImageView; // login_bg_icon
@property (nonatomic, strong) UIImageView *topRightImageView; // login_jianp_icon
// 26
@property (nonatomic, strong) UIView *contentContainerView;
//
@property (nonatomic, strong) UILabel *titleLabel;
//
@property (nonatomic, strong) UIControl *appleLoginButton; // Apple iOS13
@property (nonatomic, strong) UIButton *emailLoginButton; //
// &
2025-12-02 19:19:25 +08:00
@property (nonatomic, strong) UITextView *agreementTextView; //
2025-12-02 18:29:04 +08:00
@property (nonatomic, strong) UILabel *noAccountLabel; // Don't Have An Account?
@property (nonatomic, strong) UIButton *signUpButton; // Sign Up
@property (nonatomic, strong) UIButton *forgotPasswordButton; // Forgot Password?
@end
@implementation KBLoginVC
- (void)viewDidLoad {
[super viewDidLoad];
// 使
self.kb_enableCustomNavBar = NO;
self.view.backgroundColor = [UIColor whiteColor];
[self setupUI];
}
- (void)viewDidLayoutSubviews {
[super viewDidLayoutSubviews];
// 26
if (!CGRectIsEmpty(self.contentContainerView.bounds)) {
UIRectCorner corners = UIRectCornerTopLeft | UIRectCornerTopRight;
UIBezierPath *path = [UIBezierPath bezierPathWithRoundedRect:self.contentContainerView.bounds
byRoundingCorners:corners
cornerRadii:CGSizeMake(26, 26)];
CAShapeLayer *mask = [CAShapeLayer layer];
mask.frame = self.contentContainerView.bounds;
mask.path = path.CGPath;
self.contentContainerView.layer.mask = mask;
}
2025-12-02 19:19:25 +08:00
// + 50稿
// if (self.emailLoginButton.currentImage && self.emailLoginButton.currentTitle.length > 0) {
// [self kb_centerImageAndTitleForButton:self.emailLoginButton spacing:KBFit(50)];
// }
2025-12-02 18:29:04 +08:00
}
#pragma mark - UI
- (void)setupUI {
//
[self.view addSubview:self.bgImageView];
[self.bgImageView mas_makeConstraints:^(MASConstraintMaker *make) {
make.edges.equalTo(self.view);
}];
//
[self.view addSubview:self.topRightImageView];
[self.topRightImageView mas_makeConstraints:^(MASConstraintMaker *make) {
make.top.equalTo(self.view).offset(KB_StatusBarHeight() + KBFit(24));
make.right.equalTo(self.view).offset(-KBFit(20));
make.width.mas_equalTo(KBFit(244));
make.height.mas_equalTo(KBFit(224));
}];
//
[self.view addSubview:self.contentContainerView];
[self.contentContainerView mas_makeConstraints:^(MASConstraintMaker *make) {
make.left.right.bottom.equalTo(self.view);
// 稿
2025-12-02 19:19:25 +08:00
make.top.equalTo(self.view).offset(KBFit(272));
2025-12-02 18:29:04 +08:00
}];
//
[self.contentContainerView addSubview:self.titleLabel];
[self.titleLabel mas_makeConstraints:^(MASConstraintMaker *make) {
2025-12-02 19:19:25 +08:00
make.top.equalTo(self.contentContainerView).offset(27);
2025-12-02 18:29:04 +08:00
make.centerX.equalTo(self.contentContainerView);
}];
// Apple
[self.contentContainerView addSubview:self.appleLoginButton];
[self.appleLoginButton mas_makeConstraints:^(MASConstraintMaker *make) {
make.top.equalTo(self.titleLabel.mas_bottom).offset(24);
make.left.equalTo(self.contentContainerView).offset(30);
make.right.equalTo(self.contentContainerView).offset(-30);
make.height.mas_equalTo(52);
}];
//
[self.contentContainerView addSubview:self.emailLoginButton];
[self.emailLoginButton mas_makeConstraints:^(MASConstraintMaker *make) {
2025-12-02 19:19:25 +08:00
make.top.equalTo(self.appleLoginButton.mas_bottom).offset(15);
2025-12-02 18:29:04 +08:00
make.left.right.height.equalTo(self.appleLoginButton);
}];
2025-12-02 19:19:25 +08:00
// terms/privacy
[self.contentContainerView addSubview:self.agreementTextView];
[self.agreementTextView mas_makeConstraints:^(MASConstraintMaker *make) {
2025-12-02 20:33:17 +08:00
// 30 textAlignmentCenter
make.left.equalTo(self.contentContainerView).offset(30);
make.right.equalTo(self.contentContainerView).offset(-30);
2025-12-02 18:29:04 +08:00
make.bottom.equalTo(self.contentContainerView).offset(-KB_SAFE_BOTTOM - 84);
}];
//
UIButton *forgot = self.forgotPasswordButton;
[self.contentContainerView addSubview:forgot];
[forgot mas_makeConstraints:^(MASConstraintMaker *make) {
make.centerX.equalTo(self.contentContainerView);
2025-12-02 20:33:17 +08:00
make.bottom.equalTo(self.contentContainerView).offset(-KB_SAFE_BOTTOM - 10);
2025-12-02 18:29:04 +08:00
}];
UIView *accountLine = [UIView new];
[self.contentContainerView addSubview:accountLine];
[accountLine mas_makeConstraints:^(MASConstraintMaker *make) {
make.centerX.equalTo(self.contentContainerView);
2025-12-02 20:33:17 +08:00
make.bottom.equalTo(forgot.mas_top).offset(-2);
2025-12-02 18:29:04 +08:00
}];
[accountLine addSubview:self.noAccountLabel];
[accountLine addSubview:self.signUpButton];
[self.noAccountLabel mas_makeConstraints:^(MASConstraintMaker *make) {
make.top.left.bottom.equalTo(accountLine);
}];
[self.signUpButton mas_makeConstraints:^(MASConstraintMaker *make) {
make.left.equalTo(self.noAccountLabel.mas_right).offset(4);
make.right.equalTo(accountLine);
make.centerY.equalTo(self.noAccountLabel);
}];
}
#pragma mark - Actions
- (void)onTapAppleLogin {
2025-12-02 19:19:25 +08:00
KBLOG(@"onTapAppleLogin");
[[KBLoginVM shared] signInWithAppleFromViewController:KB_CURRENT_NAV completion:^(BOOL success, NSError * _Nullable error) {
if (success) {
[KBHUD showInfo:KBLocalized(@"Signed in successfully")];
2025-12-03 13:31:02 +08:00
// TabBar
dispatch_async(dispatch_get_main_queue(), ^{
id<UIApplicationDelegate> appDelegate = UIApplication.sharedApplication.delegate;
if ([appDelegate respondsToSelector:@selector(setupRootVC)]) {
AppDelegate *delegate = (AppDelegate *)appDelegate;
[delegate setupRootVC];
}
});
2025-12-02 19:19:25 +08:00
} else {
NSString *msg = error.localizedDescription ?: KBLocalized(@"Sign-in failed");
[KBHUD showInfo:msg];
}
}];
2025-12-02 18:29:04 +08:00
}
- (void)onTapEmailLogin {
//
2025-12-02 19:19:25 +08:00
KBLOG(@"onTapEmailLogin");
2025-12-02 18:29:04 +08:00
}
- (void)onTapPolicy {
// /
2025-12-02 19:19:25 +08:00
KBLOG(@"onTapPolicy");
2025-12-02 18:29:04 +08:00
}
- (void)onTapSignUp {
//
2025-12-02 19:19:25 +08:00
KBLOG(@"onTapSignUp");
2025-12-02 18:29:04 +08:00
}
- (void)onTapForgotPassword {
//
2025-12-02 19:19:25 +08:00
KBLOG(@"onTapForgotPassword");
2025-12-02 18:29:04 +08:00
}
#pragma mark - Lazy UI
- (UIImageView *)bgImageView {
if (!_bgImageView) {
_bgImageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"login_bg_icon"]];
_bgImageView.contentMode = UIViewContentModeScaleAspectFill;
_bgImageView.clipsToBounds = YES;
}
return _bgImageView;
}
- (UIImageView *)topRightImageView {
if (!_topRightImageView) {
_topRightImageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"login_jianp_icon"]];
_topRightImageView.contentMode = UIViewContentModeScaleAspectFit;
_topRightImageView.clipsToBounds = YES;
}
return _topRightImageView;
}
- (UIView *)contentContainerView {
if (!_contentContainerView) {
_contentContainerView = [UIView new];
_contentContainerView.backgroundColor = [UIColor whiteColor];
}
return _contentContainerView;
}
- (UILabel *)titleLabel {
if (!_titleLabel) {
_titleLabel = [UILabel new];
_titleLabel.text = KBLocalized(@"Log In To Key Of Love");
_titleLabel.textColor = [UIColor colorWithHex:KBBlackValue];
_titleLabel.font = [KBFont bold:18];
_titleLabel.textAlignment = NSTextAlignmentCenter;
}
return _titleLabel;
}
- (UIControl *)appleLoginButton {
if (!_appleLoginButton) {
ASAuthorizationAppleIDButton *btn = [ASAuthorizationAppleIDButton buttonWithType:ASAuthorizationAppleIDButtonTypeSignIn
style:ASAuthorizationAppleIDButtonStyleWhite];
[btn addTarget:self action:@selector(onTapAppleLogin) forControlEvents:UIControlEventTouchUpInside];
btn.cornerRadius = 10.0;
btn.layer.borderColor = [UIColor colorWithHex:0xE5E5E5].CGColor;
btn.layer.borderWidth = 1;
2025-12-02 19:19:25 +08:00
btn.layer.cornerRadius = 10.0;
btn.layer.masksToBounds = true;
2025-12-02 18:29:04 +08:00
_appleLoginButton = btn;
}
return _appleLoginButton;
}
- (UIButton *)emailLoginButton {
if (!_emailLoginButton) {
_emailLoginButton = [UIButton buttonWithType:UIButtonTypeCustom];
[_emailLoginButton setTitle:KBLocalized(@"Continue Via Email") forState:UIControlStateNormal];
[_emailLoginButton setTitleColor:[UIColor colorWithHex:KBBlackValue] forState:UIControlStateNormal];
2025-12-02 20:33:17 +08:00
_emailLoginButton.titleLabel.font = [KBFont medium:19];
2025-12-02 19:19:25 +08:00
// _emailLoginButton.backgroundColor = [UIColor colorWithHex:0xF7F7F7];
2025-12-02 18:29:04 +08:00
_emailLoginButton.layer.cornerRadius = 10.0;
_emailLoginButton.layer.masksToBounds = YES;
2025-12-02 19:19:25 +08:00
_emailLoginButton.layer.borderColor = [UIColor colorWithHex:0xE5E5E5].CGColor;
_emailLoginButton.layer.borderWidth = 1;
_emailLoginButton.imageEdgeInsets = UIEdgeInsetsMake(0, 0, 0, 0);
_emailLoginButton.titleEdgeInsets = UIEdgeInsetsMake(0, 15, 0, 0);
2025-12-02 18:29:04 +08:00
UIImage *icon = [UIImage imageNamed:@"login_email_icon"];
if (icon) {
2025-12-02 19:19:25 +08:00
// Apple
CGFloat targetHeight = 12; //
CGFloat scale = targetHeight / icon.size.height;
CGSize targetSize = CGSizeMake(icon.size.width * scale, targetHeight);
UIGraphicsBeginImageContextWithOptions(targetSize, NO, 0.0);
[icon drawInRect:CGRectMake(0, 0, targetSize.width, targetSize.height)];
UIImage *scaledIcon = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
[_emailLoginButton setImage:scaledIcon forState:UIControlStateNormal];
2025-12-02 18:29:04 +08:00
}
[_emailLoginButton addTarget:self action:@selector(onTapEmailLogin) forControlEvents:UIControlEventTouchUpInside];
}
return _emailLoginButton;
}
2025-12-02 19:19:25 +08:00
- (UITextView *)agreementTextView {
if (!_agreementTextView) {
_agreementTextView = [UITextView new];
_agreementTextView.backgroundColor = [UIColor clearColor];
_agreementTextView.editable = NO; //
_agreementTextView.selectable = NO; //
_agreementTextView.scrollEnabled = NO;
_agreementTextView.textAlignment = NSTextAlignmentCenter;
_agreementTextView.textContainerInset = UIEdgeInsetsZero;
_agreementTextView.textContainer.lineFragmentPadding = 0;
// terms of service / privacy policy #717171
NSString *fullText = @"By continuing, you agree to our terms of service and confirm that you have read our privacy policy";
NSString *termsText = @"terms of service";
NSString *privacyText = @"privacy policy";
2025-12-02 20:33:17 +08:00
NSMutableParagraphStyle *paragraph = [[NSMutableParagraphStyle alloc] init];
paragraph.alignment = NSTextAlignmentCenter; //
2025-12-02 19:19:25 +08:00
NSMutableAttributedString *attr = [[NSMutableAttributedString alloc] initWithString:fullText
attributes:@{
2025-12-02 20:33:17 +08:00
NSFontAttributeName : [KBFont regular:10],
NSForegroundColorAttributeName : [UIColor colorWithHex:0x717171],
NSParagraphStyleAttributeName : paragraph
2025-12-02 19:19:25 +08:00
}];
NSString *lowerFull = fullText.lowercaseString;
NSRange termsRange = [lowerFull rangeOfString:termsText.lowercaseString];
if (termsRange.location != NSNotFound) {
[attr addAttributes:@{
NSForegroundColorAttributeName : [UIColor colorWithHex:KBBlackValue],
NSUnderlineStyleAttributeName : @(NSUnderlineStyleNone)
} range:termsRange];
}
2025-12-02 18:29:04 +08:00
2025-12-02 19:19:25 +08:00
NSRange privacyRange = [lowerFull rangeOfString:privacyText.lowercaseString];
if (privacyRange.location != NSNotFound) {
[attr addAttributes:@{
NSForegroundColorAttributeName : [UIColor colorWithHex:KBBlackValue],
NSUnderlineStyleAttributeName : @(NSUnderlineStyleNone)
} range:privacyRange];
}
_agreementTextView.linkTextAttributes = @{
NSForegroundColorAttributeName : [UIColor colorWithHex:KBBlackValue],
NSUnderlineStyleAttributeName : @(NSUnderlineStyleNone)
};
_agreementTextView.attributedText = attr;
// /
UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(kb_handleAgreementTap:)];
_agreementTextView.userInteractionEnabled = YES;
[_agreementTextView addGestureRecognizer:tap];
2025-12-02 18:29:04 +08:00
}
2025-12-02 19:19:25 +08:00
return _agreementTextView;
2025-12-02 18:29:04 +08:00
}
- (UILabel *)noAccountLabel {
if (!_noAccountLabel) {
_noAccountLabel = [UILabel new];
_noAccountLabel.text = KBLocalized(@"Don't Have An Account?");
2025-12-02 20:33:17 +08:00
_noAccountLabel.font = [KBFont regular:10];
_noAccountLabel.textColor = [UIColor colorWithHex:KBBlackValue];
2025-12-02 18:29:04 +08:00
}
return _noAccountLabel;
}
- (UIButton *)signUpButton {
if (!_signUpButton) {
_signUpButton = [UIButton buttonWithType:UIButtonTypeCustom];
[_signUpButton setTitle:KBLocalized(@"Sign Up") forState:UIControlStateNormal];
[_signUpButton setTitleColor:[UIColor colorWithHex:KBColorValue] forState:UIControlStateNormal];
2025-12-02 20:33:17 +08:00
_signUpButton.titleLabel.font = [KBFont medium:10];
2025-12-02 18:29:04 +08:00
[_signUpButton addTarget:self action:@selector(onTapSignUp) forControlEvents:UIControlEventTouchUpInside];
}
return _signUpButton;
}
- (UIButton *)forgotPasswordButton {
if (!_forgotPasswordButton) {
_forgotPasswordButton = [UIButton buttonWithType:UIButtonTypeCustom];
[_forgotPasswordButton setTitle:KBLocalized(@"Forgot Password?") forState:UIControlStateNormal];
[_forgotPasswordButton setTitleColor:[UIColor colorWithHex:KBColorValue] forState:UIControlStateNormal];
2025-12-02 20:33:17 +08:00
_forgotPasswordButton.titleLabel.font = [KBFont regular:10];
2025-12-02 18:29:04 +08:00
[_forgotPasswordButton addTarget:self action:@selector(onTapForgotPassword) forControlEvents:UIControlEventTouchUpInside];
}
return _forgotPasswordButton;
}
2025-12-02 19:19:25 +08:00
#pragma mark - Helper
/// spacing 稿 KBFit
- (void)kb_centerImageAndTitleForButton:(UIButton *)button spacing:(CGFloat)spacing {
if (!button.currentImage || button.currentTitle.length == 0) { return; }
button.contentHorizontalAlignment = UIControlContentHorizontalAlignmentCenter;
CGSize imageSize = button.imageView.image.size;
CGSize titleSize = button.titleLabel.intrinsicContentSize;
CGFloat totalWidth = imageSize.width + spacing + titleSize.width;
CGFloat imageOffsetX = -(totalWidth / 2.0 - imageSize.width / 2.0);
CGFloat titleOffsetX = totalWidth / 2.0 - titleSize.width / 2.0;
button.imageEdgeInsets = UIEdgeInsetsMake(0, imageOffsetX, 0, -imageOffsetX);
button.titleEdgeInsets = UIEdgeInsetsMake(0, titleOffsetX, 0, -titleOffsetX);
}
#pragma mark - Agreement Tap
- (void)kb_handleAgreementTap:(UITapGestureRecognizer *)tap {
UITextView *textView = self.agreementTextView;
CGPoint point = [tap locationInView:textView];
// textContainer
CGPoint location = point;
location.x -= textView.textContainerInset.left;
location.y -= textView.textContainerInset.top;
NSLayoutManager *layoutManager = textView.layoutManager;
NSTextContainer *textContainer = textView.textContainer;
NSUInteger glyphIndex = [layoutManager glyphIndexForPoint:location
inTextContainer:textContainer];
if (glyphIndex >= textView.textStorage.length) { return; }
NSUInteger charIndex = [layoutManager characterIndexForGlyphAtIndex:glyphIndex];
NSString *lowerFull = textView.text.lowercaseString ?: @"";
NSRange termsRange = [lowerFull rangeOfString:@"terms of service"];
NSRange privacyRange = [lowerFull rangeOfString:@"privacy policy"];
BOOL hitTerms = (termsRange.location != NSNotFound && NSLocationInRange(charIndex, termsRange));
BOOL hitPrivacy = (privacyRange.location != NSNotFound && NSLocationInRange(charIndex, privacyRange));
if (hitTerms || hitPrivacy) {
[self onTapPolicy];
}
}
2025-12-02 18:29:04 +08:00
@end