2021-02-05 10:53:00 +01:00
//
// M a s t o d o n R e g i s t e r V i e w C o n t r o l l e r . s w i f t
// M a s t o d o n
//
// C r e a t e d b y M a i n a s u K C i r n o o n 2 0 2 1 - 2 - 5 .
//
import Combine
import MastodonSDK
2021-02-20 06:55:06 +01:00
import os . log
import UIKit
2021-02-05 10:53:00 +01:00
import UITextField_Shake
final class MastodonRegisterViewController : UIViewController , NeedsDependency {
var disposeBag = Set < AnyCancellable > ( )
weak var context : AppContext ! { willSet { precondition ( ! isViewLoaded ) } }
weak var coordinator : SceneCoordinator ! { willSet { precondition ( ! isViewLoaded ) } }
var viewModel : MastodonRegisterViewModel !
2021-02-20 06:55:06 +01:00
let tapGestureRecognizer = UITapGestureRecognizer . singleTapGestureRecognizer
2021-02-22 09:20:44 +01:00
let statusBarBackground : UIView = {
let view = UIView ( )
view . backgroundColor = Asset . Colors . Background . onboardingBackground . color
return view
} ( )
let scrollView : UIScrollView = {
2021-02-20 06:55:06 +01:00
let scrollview = UIScrollView ( )
scrollview . showsVerticalScrollIndicator = false
scrollview . translatesAutoresizingMaskIntoConstraints = false
2021-02-20 12:54:08 +01:00
scrollview . keyboardDismissMode = . interactive
2021-02-22 09:20:44 +01:00
scrollview . clipsToBounds = false // m a k e c o n t e n t c o u l d d i s p l a y o v e r b l e e d i n g
2021-02-20 06:55:06 +01:00
return scrollview
} ( )
2021-02-05 10:53:00 +01:00
2021-02-20 06:55:06 +01:00
let largeTitleLabel : UILabel = {
let label = UILabel ( )
2021-02-20 11:24:23 +01:00
label . font = UIFontMetrics ( forTextStyle : . largeTitle ) . scaledFont ( for : UIFont . boldSystemFont ( ofSize : 34 ) )
2021-02-20 06:55:06 +01:00
label . textColor = Asset . Colors . Label . black . color
2021-02-22 09:20:44 +01:00
label . text = L10n . Scene . Register . title
2021-02-20 06:55:06 +01:00
return label
} ( )
let photoView : UIView = {
let view = UIView ( )
view . backgroundColor = . clear
return view
} ( )
let photoButton : UIButton = {
let button = UIButton ( type : . custom )
let boldFont = UIFont . systemFont ( ofSize : 42 )
let configuration = UIImage . SymbolConfiguration ( font : boldFont )
let image = UIImage ( systemName : " person.fill.viewfinder " , withConfiguration : configuration )
button . setImage ( image ? . withRenderingMode ( UIImage . RenderingMode . alwaysTemplate ) , for : UIControl . State . normal )
button . imageView ? . tintColor = Asset . Colors . Icon . photo . color
button . backgroundColor = . white
button . layer . cornerRadius = 45
button . clipsToBounds = true
return button
} ( )
2021-02-20 11:24:23 +01:00
let plusIconBackground : UIImageView = {
let icon = UIImageView ( )
let boldFont = UIFont . systemFont ( ofSize : 24 )
let configuration = UIImage . SymbolConfiguration ( font : boldFont )
let image = UIImage ( systemName : " plus.circle " , withConfiguration : configuration )
icon . image = image
icon . tintColor = . white
return icon
} ( )
2021-02-20 06:55:06 +01:00
let plusIcon : UIImageView = {
let icon = UIImageView ( )
let boldFont = UIFont . systemFont ( ofSize : 24 )
let configuration = UIImage . SymbolConfiguration ( font : boldFont )
let image = UIImage ( systemName : " plus.circle.fill " , withConfiguration : configuration )
icon . image = image
icon . tintColor = Asset . Colors . Icon . plus . color
return icon
} ( )
let domainLabel : UILabel = {
2021-02-05 10:53:00 +01:00
let label = UILabel ( )
label . font = . preferredFont ( forTextStyle : . headline )
2021-02-20 06:55:06 +01:00
label . textColor = Asset . Colors . Label . black . color
2021-02-05 10:53:00 +01:00
return label
} ( )
let usernameTextField : UITextField = {
let textField = UITextField ( )
2021-02-20 06:55:06 +01:00
2021-02-05 10:53:00 +01:00
textField . autocapitalizationType = . none
textField . autocorrectionType = . no
2021-02-20 06:55:06 +01:00
textField . backgroundColor = . white
textField . textColor = . black
2021-02-22 09:20:44 +01:00
textField . attributedPlaceholder = NSAttributedString ( string : L10n . Scene . Register . Input . Username . placeholder ,
2021-02-20 06:55:06 +01:00
attributes : [ NSAttributedString . Key . foregroundColor : Asset . Colors . lightSecondaryText . color ,
NSAttributedString . Key . font : UIFont . preferredFont ( forTextStyle : . headline ) ] )
textField . borderStyle = UITextField . BorderStyle . roundedRect
let paddingView = UIView ( frame : CGRect ( x : 0 , y : 0 , width : 5 , height : textField . frame . height ) )
textField . leftView = paddingView
textField . leftViewMode = . always
2021-02-05 10:53:00 +01:00
return textField
} ( )
2021-02-20 06:55:06 +01:00
let usernameIsTakenLabel : UILabel = {
2021-02-05 10:53:00 +01:00
let label = UILabel ( )
return label
} ( )
2021-02-20 06:55:06 +01:00
let displayNameTextField : UITextField = {
let textField = UITextField ( )
textField . autocapitalizationType = . none
textField . autocorrectionType = . no
textField . backgroundColor = . white
textField . textColor = . black
2021-02-22 09:20:44 +01:00
textField . attributedPlaceholder = NSAttributedString ( string : L10n . Scene . Register . Input . DisplayName . placeholder ,
2021-02-20 06:55:06 +01:00
attributes : [ NSAttributedString . Key . foregroundColor : Asset . Colors . lightSecondaryText . color ,
NSAttributedString . Key . font : UIFont . preferredFont ( forTextStyle : . headline ) ] )
textField . borderStyle = UITextField . BorderStyle . roundedRect
let paddingView = UIView ( frame : CGRect ( x : 0 , y : 0 , width : 5 , height : textField . frame . height ) )
textField . leftView = paddingView
textField . leftViewMode = . always
return textField
} ( )
2021-02-05 10:53:00 +01:00
let emailTextField : UITextField = {
let textField = UITextField ( )
textField . autocapitalizationType = . none
textField . autocorrectionType = . no
textField . keyboardType = . emailAddress
2021-02-20 06:55:06 +01:00
textField . backgroundColor = . white
textField . textColor = . black
2021-02-22 09:20:44 +01:00
textField . attributedPlaceholder = NSAttributedString ( string : L10n . Scene . Register . Input . Email . placeholder ,
2021-02-20 06:55:06 +01:00
attributes : [ NSAttributedString . Key . foregroundColor : Asset . Colors . lightSecondaryText . color ,
NSAttributedString . Key . font : UIFont . preferredFont ( forTextStyle : . headline ) ] )
textField . borderStyle = UITextField . BorderStyle . roundedRect
let paddingView = UIView ( frame : CGRect ( x : 0 , y : 0 , width : 5 , height : textField . frame . height ) )
textField . leftView = paddingView
textField . leftViewMode = . always
2021-02-05 10:53:00 +01:00
return textField
} ( )
2021-02-20 06:55:06 +01:00
let passwordCheckLabel : UILabel = {
2021-02-05 10:53:00 +01:00
let label = UILabel ( )
2021-02-22 05:51:35 +01:00
label . numberOfLines = 0
2021-02-05 10:53:00 +01:00
return label
} ( )
let passwordTextField : UITextField = {
let textField = UITextField ( )
textField . autocapitalizationType = . none
textField . autocorrectionType = . no
textField . keyboardType = . asciiCapable
textField . isSecureTextEntry = true
2021-02-20 06:55:06 +01:00
textField . backgroundColor = . white
textField . textColor = . black
2021-02-22 09:20:44 +01:00
textField . attributedPlaceholder = NSAttributedString ( string : L10n . Scene . Register . Input . Password . placeholder ,
2021-02-20 06:55:06 +01:00
attributes : [ NSAttributedString . Key . foregroundColor : Asset . Colors . lightSecondaryText . color ,
NSAttributedString . Key . font : UIFont . preferredFont ( forTextStyle : . headline ) ] )
textField . borderStyle = UITextField . BorderStyle . roundedRect
let paddingView = UIView ( frame : CGRect ( x : 0 , y : 0 , width : 5 , height : textField . frame . height ) )
textField . leftView = paddingView
textField . leftViewMode = . always
2021-02-05 10:53:00 +01:00
return textField
} ( )
let signUpButton : UIButton = {
let button = UIButton ( type : . system )
button . titleLabel ? . font = . preferredFont ( forTextStyle : . headline )
2021-02-20 06:55:06 +01:00
button . setBackgroundImage ( UIImage . placeholder ( color : Asset . Colors . lightBrandBlue . color ) , for : . normal )
button . setBackgroundImage ( UIImage . placeholder ( color : Asset . Colors . lightDisabled . color ) , for : . disabled )
button . isEnabled = false
2021-02-05 10:53:00 +01:00
button . setTitleColor ( Asset . Colors . Label . primary . color , for : . normal )
2021-02-22 09:20:44 +01:00
button . setTitle ( L10n . Common . Controls . Actions . continue , for : . normal )
2021-02-05 10:53:00 +01:00
button . layer . masksToBounds = true
button . layer . cornerRadius = 8
button . layer . cornerCurve = . continuous
return button
} ( )
let signUpActivityIndicatorView : UIActivityIndicatorView = {
let activityIndicatorView = UIActivityIndicatorView ( style : . medium )
activityIndicatorView . hidesWhenStopped = true
return activityIndicatorView
} ( )
}
extension MastodonRegisterViewController {
2021-02-22 09:20:44 +01:00
2021-02-05 10:53:00 +01:00
override func viewDidLoad ( ) {
super . viewDidLoad ( )
2021-02-22 09:20:44 +01:00
overrideUserInterfaceStyle = . light
view . backgroundColor = Asset . Colors . Background . onboardingBackground . color
2021-02-20 06:55:06 +01:00
domainLabel . text = " @ " + viewModel . domain + " "
domainLabel . sizeToFit ( )
passwordCheckLabel . attributedText = viewModel . attributeStringForPassword ( )
usernameTextField . rightView = domainLabel
usernameTextField . rightViewMode = . always
usernameTextField . delegate = self
displayNameTextField . delegate = self
emailTextField . delegate = self
passwordTextField . delegate = self
2021-02-05 10:53:00 +01:00
2021-02-20 06:55:06 +01:00
// g e s t u r e
view . addGestureRecognizer ( tapGestureRecognizer )
tapGestureRecognizer . addTarget ( self , action : #selector ( _resignFirstResponder ) )
2021-02-05 10:53:00 +01:00
2021-02-20 06:55:06 +01:00
// s t a c k v i e w
let stackView = UIStackView ( )
2021-02-05 10:53:00 +01:00
stackView . axis = . vertical
2021-02-20 06:55:06 +01:00
stackView . distribution = . fill
stackView . spacing = 40
2021-02-22 09:26:50 +01:00
stackView . layoutMargins = UIEdgeInsets ( top : 20 , left : 0 , bottom : 26 , right : 0 )
2021-02-20 06:55:06 +01:00
stackView . isLayoutMarginsRelativeArrangement = true
stackView . addArrangedSubview ( largeTitleLabel )
stackView . addArrangedSubview ( photoView )
2021-02-05 10:53:00 +01:00
stackView . addArrangedSubview ( usernameTextField )
2021-02-20 06:55:06 +01:00
stackView . addArrangedSubview ( displayNameTextField )
2021-02-05 10:53:00 +01:00
stackView . addArrangedSubview ( emailTextField )
stackView . addArrangedSubview ( passwordTextField )
2021-02-20 06:55:06 +01:00
stackView . addArrangedSubview ( passwordCheckLabel )
2021-02-22 09:20:44 +01:00
// s c r o l l V i e w
view . addSubview ( scrollView )
2021-02-20 06:55:06 +01:00
NSLayoutConstraint . activate ( [
2021-02-22 09:20:44 +01:00
scrollView . frameLayoutGuide . topAnchor . constraint ( equalTo : view . layoutMarginsGuide . topAnchor ) ,
scrollView . frameLayoutGuide . leadingAnchor . constraint ( equalTo : view . readableContentGuide . leadingAnchor ) ,
view . readableContentGuide . trailingAnchor . constraint ( equalTo : scrollView . frameLayoutGuide . trailingAnchor ) ,
scrollView . frameLayoutGuide . bottomAnchor . constraint ( equalTo : view . layoutMarginsGuide . bottomAnchor ) ,
scrollView . frameLayoutGuide . widthAnchor . constraint ( equalTo : scrollView . contentLayoutGuide . widthAnchor ) ,
2021-02-20 06:55:06 +01:00
] )
2021-02-20 12:54:08 +01:00
2021-02-20 06:55:06 +01:00
// s t a c k v i e w
2021-02-22 09:20:44 +01:00
scrollView . addSubview ( stackView )
2021-02-20 06:55:06 +01:00
stackView . translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint . activate ( [
2021-02-22 09:20:44 +01:00
stackView . topAnchor . constraint ( equalTo : scrollView . contentLayoutGuide . topAnchor ) ,
stackView . leadingAnchor . constraint ( equalTo : scrollView . contentLayoutGuide . leadingAnchor ) ,
stackView . trailingAnchor . constraint ( equalTo : scrollView . contentLayoutGuide . trailingAnchor ) ,
stackView . widthAnchor . constraint ( equalTo : scrollView . contentLayoutGuide . widthAnchor ) ,
scrollView . contentLayoutGuide . bottomAnchor . constraint ( equalTo : stackView . bottomAnchor ) ,
] )
statusBarBackground . translatesAutoresizingMaskIntoConstraints = false
view . addSubview ( statusBarBackground )
NSLayoutConstraint . activate ( [
statusBarBackground . topAnchor . constraint ( equalTo : view . topAnchor ) ,
statusBarBackground . leadingAnchor . constraint ( equalTo : view . leadingAnchor ) ,
statusBarBackground . trailingAnchor . constraint ( equalTo : view . trailingAnchor ) ,
statusBarBackground . bottomAnchor . constraint ( equalTo : view . layoutMarginsGuide . topAnchor ) ,
2021-02-20 06:55:06 +01:00
] )
// p h o t o v i e w
photoView . translatesAutoresizingMaskIntoConstraints = false
photoView . addSubview ( photoButton )
NSLayoutConstraint . activate ( [
photoView . heightAnchor . constraint ( equalToConstant : 90 ) . priority ( . defaultHigh ) ,
] )
photoButton . translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint . activate ( [
photoButton . heightAnchor . constraint ( equalToConstant : 90 ) . priority ( . defaultHigh ) ,
photoButton . widthAnchor . constraint ( equalToConstant : 90 ) . priority ( . defaultHigh ) ,
photoButton . centerXAnchor . constraint ( equalTo : photoView . centerXAnchor ) ,
photoButton . centerYAnchor . constraint ( equalTo : photoView . centerYAnchor ) ,
] )
2021-02-20 11:24:23 +01:00
plusIconBackground . translatesAutoresizingMaskIntoConstraints = false
photoView . addSubview ( plusIconBackground )
NSLayoutConstraint . activate ( [
plusIconBackground . trailingAnchor . constraint ( equalTo : photoButton . trailingAnchor ) ,
plusIconBackground . bottomAnchor . constraint ( equalTo : photoButton . bottomAnchor ) ,
] )
2021-02-20 06:55:06 +01:00
plusIcon . translatesAutoresizingMaskIntoConstraints = false
photoView . addSubview ( plusIcon )
NSLayoutConstraint . activate ( [
plusIcon . trailingAnchor . constraint ( equalTo : photoButton . trailingAnchor ) ,
plusIcon . bottomAnchor . constraint ( equalTo : photoButton . bottomAnchor ) ,
] )
2021-02-20 12:54:08 +01:00
2021-02-20 06:55:06 +01:00
// t e x t f i e l d
NSLayoutConstraint . activate ( [
usernameTextField . heightAnchor . constraint ( equalToConstant : 50 ) . priority ( . defaultHigh ) ,
displayNameTextField . heightAnchor . constraint ( equalToConstant : 50 ) . priority ( . defaultHigh ) ,
emailTextField . heightAnchor . constraint ( equalToConstant : 50 ) . priority ( . defaultHigh ) ,
passwordTextField . heightAnchor . constraint ( equalToConstant : 50 ) . priority ( . defaultHigh ) ,
] )
// p a s s w o r d
stackView . setCustomSpacing ( 6 , after : passwordTextField )
stackView . setCustomSpacing ( 32 , after : passwordCheckLabel )
2021-02-20 12:54:08 +01:00
2021-02-20 06:55:06 +01:00
// b u t t o n
2021-02-05 10:53:00 +01:00
signUpButton . translatesAutoresizingMaskIntoConstraints = false
stackView . addArrangedSubview ( signUpButton )
NSLayoutConstraint . activate ( [
2021-02-22 09:20:44 +01:00
signUpButton . heightAnchor . constraint ( equalToConstant : 46 ) . priority ( . defaultHigh ) ,
2021-02-05 10:53:00 +01:00
] )
2021-02-20 12:54:08 +01:00
2021-02-05 10:53:00 +01:00
signUpActivityIndicatorView . translatesAutoresizingMaskIntoConstraints = false
2021-02-22 09:20:44 +01:00
scrollView . addSubview ( signUpActivityIndicatorView )
2021-02-05 10:53:00 +01:00
NSLayoutConstraint . activate ( [
signUpActivityIndicatorView . centerXAnchor . constraint ( equalTo : signUpButton . centerXAnchor ) ,
signUpActivityIndicatorView . centerYAnchor . constraint ( equalTo : signUpButton . centerYAnchor ) ,
] )
2021-02-20 12:54:08 +01:00
2021-02-22 05:51:35 +01:00
Publishers . CombineLatest (
2021-02-20 12:54:08 +01:00
KeyboardResponderService . shared . state . eraseToAnyPublisher ( ) ,
2021-02-22 05:51:35 +01:00
KeyboardResponderService . shared . willEndFrame . eraseToAnyPublisher ( )
2021-02-20 12:54:08 +01:00
)
2021-02-22 05:51:35 +01:00
. sink ( receiveValue : { [ weak self ] state , endFrame in
2021-02-20 12:54:08 +01:00
guard let self = self else { return }
2021-02-22 05:51:35 +01:00
guard state = = . dock else {
2021-02-22 09:20:44 +01:00
self . scrollView . contentInset . bottom = 0.0
self . scrollView . verticalScrollIndicatorInsets . bottom = 0.0
2021-02-20 12:54:08 +01:00
return
2021-02-20 06:55:06 +01:00
}
2021-02-20 12:54:08 +01:00
2021-02-22 09:20:44 +01:00
let contentFrame = self . view . convert ( self . scrollView . frame , to : nil )
2021-02-20 12:54:08 +01:00
let padding = contentFrame . maxY - endFrame . minY
guard padding > 0 else {
2021-02-22 09:20:44 +01:00
self . scrollView . contentInset . bottom = 0.0
self . scrollView . verticalScrollIndicatorInsets . bottom = 0.0
2021-02-20 12:54:08 +01:00
return
}
2021-02-22 09:20:44 +01:00
self . scrollView . contentInset . bottom = padding + 16
self . scrollView . verticalScrollIndicatorInsets . bottom = padding + 16
2021-02-20 12:54:08 +01:00
} )
. store ( in : & disposeBag )
2021-02-05 10:53:00 +01:00
viewModel . isRegistering
. receive ( on : DispatchQueue . main )
. sink { [ weak self ] isRegistering in
guard let self = self else { return }
isRegistering ? self . signUpActivityIndicatorView . startAnimating ( ) : self . signUpActivityIndicatorView . stopAnimating ( )
2021-02-22 09:20:44 +01:00
self . signUpButton . setTitle ( isRegistering ? " " : L10n . Common . Controls . Actions . continue , for : . normal )
2021-02-05 10:53:00 +01:00
self . signUpButton . isEnabled = ! isRegistering
}
. store ( in : & disposeBag )
2021-02-20 12:54:08 +01:00
2021-02-20 10:13:16 +01:00
viewModel . isUsernameValid
. receive ( on : DispatchQueue . main )
. sink { [ weak self ] isValid in
guard let self = self else { return }
self . setTextFieldValidAppearance ( self . usernameTextField , isValid : isValid )
}
. store ( in : & disposeBag )
2021-02-20 11:24:23 +01:00
viewModel . isDisplaynameValid
. receive ( on : DispatchQueue . main )
. sink { [ weak self ] isValid in
guard let self = self else { return }
self . setTextFieldValidAppearance ( self . displayNameTextField , isValid : isValid )
}
. store ( in : & disposeBag )
viewModel . isEmailValid
. receive ( on : DispatchQueue . main )
. sink { [ weak self ] isValid in
guard let self = self else { return }
self . setTextFieldValidAppearance ( self . emailTextField , isValid : isValid )
}
. store ( in : & disposeBag )
viewModel . isPasswordValid
. receive ( on : DispatchQueue . main )
. sink { [ weak self ] isValid in
guard let self = self else { return }
self . setTextFieldValidAppearance ( self . passwordTextField , isValid : isValid )
}
. store ( in : & disposeBag )
2021-02-20 10:13:16 +01:00
2021-02-20 11:24:23 +01:00
Publishers . CombineLatest4 (
viewModel . isUsernameValid ,
viewModel . isDisplaynameValid ,
viewModel . isEmailValid ,
viewModel . isPasswordValid
)
. receive ( on : DispatchQueue . main )
. sink { [ weak self ] isUsernameValid , isDisplaynameValid , isEmailValid , isPasswordValid in
guard let self = self else { return }
self . signUpButton . isEnabled = isUsernameValid ? ? false && isDisplaynameValid ? ? false && isEmailValid ? ? false && isPasswordValid ? ? false
}
. store ( in : & disposeBag )
2021-02-20 12:54:08 +01:00
2021-02-05 10:53:00 +01:00
viewModel . error
. compactMap { $0 }
. receive ( on : DispatchQueue . main )
. sink { [ weak self ] error in
guard let self = self else { return }
let alertController = UIAlertController ( error , preferredStyle : . alert )
2021-02-22 09:20:44 +01:00
let okAction = UIAlertAction ( title : L10n . Common . Controls . Actions . ok , style : . default , handler : nil )
2021-02-05 10:53:00 +01:00
alertController . addAction ( okAction )
self . coordinator . present (
scene : . alertController ( alertController : alertController ) ,
from : nil ,
transition : . alertController ( animated : true , completion : nil )
)
}
. store ( in : & disposeBag )
2021-02-20 12:54:08 +01:00
2021-02-20 06:55:06 +01:00
NotificationCenter . default
. publisher ( for : UITextField . textDidChangeNotification , object : passwordTextField )
. receive ( on : DispatchQueue . main )
. sink { [ weak self ] _ in
guard let self = self else { return }
guard let text = self . passwordTextField . text else { return }
let validations = self . viewModel . validatePassword ( text : text )
self . passwordCheckLabel . attributedText = self . viewModel . attributeStringForPassword ( eightCharacters : validations . 0 , oneNumber : validations . 1 , oneSpecialCharacter : validations . 2 )
}
. store ( in : & disposeBag )
2021-02-20 12:54:08 +01:00
2021-02-05 10:53:00 +01:00
signUpButton . addTarget ( self , action : #selector ( MastodonRegisterViewController . signUpButtonPressed ( _ : ) ) , for : . touchUpInside )
}
2021-02-22 09:20:44 +01:00
override func viewWillAppear ( _ animated : Bool ) {
super . viewWillAppear ( animated )
navigationController ? . setNavigationBarHidden ( true , animated : false )
}
2021-02-05 10:53:00 +01:00
}
2021-02-20 06:55:06 +01:00
extension MastodonRegisterViewController : UITextFieldDelegate {
func textFieldDidBeginEditing ( _ textField : UITextField ) {
2021-02-20 12:54:08 +01:00
// a l i g n t o p a s s w o r d l a b e l w h e n o v e r l a p
if textField = = = passwordTextField ,
KeyboardResponderService . shared . isShow . value ,
2021-02-22 05:51:35 +01:00
KeyboardResponderService . shared . state . value = = . dock
{
let endFrame = KeyboardResponderService . shared . willEndFrame . value
2021-02-22 09:26:50 +01:00
let contentFrame = scrollView . convert ( passwordCheckLabel . frame , to : nil )
2021-02-20 12:54:08 +01:00
let padding = contentFrame . maxY - endFrame . minY
if padding > 0 {
2021-02-22 09:20:44 +01:00
let contentOffsetY = scrollView . contentOffset . y
2021-02-20 12:54:08 +01:00
DispatchQueue . main . async {
2021-02-22 09:20:44 +01:00
self . scrollView . setContentOffset ( CGPoint ( x : 0 , y : contentOffsetY + padding + 16.0 ) , animated : true )
2021-02-20 12:54:08 +01:00
}
}
2021-02-20 06:55:06 +01:00
}
}
func textFieldDidEndEditing ( _ textField : UITextField ) {
2021-02-20 10:13:16 +01:00
switch textField {
case usernameTextField :
viewModel . username . value = textField . text
2021-02-20 11:24:23 +01:00
case displayNameTextField :
viewModel . displayname . value = textField . text
case emailTextField :
viewModel . email . value = textField . text
case passwordTextField :
viewModel . password . value = textField . text
default : break
2021-02-20 06:55:06 +01:00
}
}
func showShadowWithColor ( color : UIColor , textField : UITextField ) {
// T o a p p l y S h a d o w
textField . layer . shadowOpacity = 1
textField . layer . shadowRadius = 2.0
2021-02-20 11:24:23 +01:00
textField . layer . shadowOffset = CGSize . zero
2021-02-20 06:55:06 +01:00
textField . layer . shadowColor = color . cgColor
2021-02-20 10:13:16 +01:00
textField . layer . shadowPath = UIBezierPath ( roundedRect : textField . bounds , byRoundingCorners : . allCorners , cornerRadii : CGSize ( width : 2.0 , height : 2.0 ) ) . cgPath
2021-02-20 06:55:06 +01:00
}
2021-02-20 11:24:23 +01:00
2021-02-20 06:55:06 +01:00
func validateAllTextField ( ) -> Bool {
2021-02-20 11:24:23 +01:00
return viewModel . isUsernameValid . value ? ? false && viewModel . isDisplaynameValid . value ? ? false && viewModel . isEmailValid . value ? ? false && viewModel . isPasswordValid . value ? ? false
2021-02-20 06:55:06 +01:00
}
2021-02-20 10:13:16 +01:00
private func setTextFieldValidAppearance ( _ textField : UITextField , isValid : Bool ? ) {
guard let isValid = isValid else {
showShadowWithColor ( color : . clear , textField : textField )
return
}
if isValid {
showShadowWithColor ( color : Asset . Colors . TextField . successGreen . color , textField : textField )
} else {
textField . shake ( )
showShadowWithColor ( color : Asset . Colors . lightDangerRed . color , textField : textField )
}
}
2021-02-20 06:55:06 +01:00
}
extension MastodonRegisterViewController {
@objc private func _resignFirstResponder ( ) {
usernameTextField . resignFirstResponder ( )
displayNameTextField . resignFirstResponder ( )
emailTextField . resignFirstResponder ( )
passwordTextField . resignFirstResponder ( )
}
@objc private func signUpButtonPressed ( _ sender : UIButton ) {
os_log ( . info , log : . debug , " %{public}s[%{public}ld], %{public}s " , ( #file as NSString ) . lastPathComponent , #line , #function )
2021-02-20 12:54:08 +01:00
guard validateAllTextField ( ) ,
let username = viewModel . username . value ,
let email = viewModel . email . value ,
let password = viewModel . password . value else {
2021-02-05 10:53:00 +01:00
return
}
guard ! viewModel . isRegistering . value else { return }
viewModel . isRegistering . value = true
2021-02-22 09:20:44 +01:00
if let rules = viewModel . instance . rules , ! rules . isEmpty {
let mastodonServerRulesViewModel = MastodonServerRulesViewModel (
context : context ,
domain : viewModel . domain ,
rules : rules
)
coordinator . present ( scene : . mastodonServerRules ( viewModel : mastodonServerRulesViewModel ) , from : self , transition : . show )
return
}
2021-02-05 10:53:00 +01:00
let query = Mastodon . API . Account . RegisterQuery (
2021-02-19 10:40:05 +01:00
reason : nil ,
2021-02-20 12:54:08 +01:00
username : username ,
email : email ,
password : password ,
2021-02-20 06:55:06 +01:00
agreement : true , // TODO:
locale : " en " // TODO:
2021-02-05 10:53:00 +01:00
)
context . apiService . accountRegister (
domain : viewModel . domain ,
query : query ,
authorization : viewModel . applicationAuthorization
)
. receive ( on : DispatchQueue . main )
. sink { [ weak self ] completion in
guard let self = self else { return }
self . viewModel . isRegistering . value = false
switch completion {
case . failure ( let error ) :
self . viewModel . error . send ( error )
case . finished :
break
}
} receiveValue : { [ weak self ] response in
guard let self = self else { return }
2021-02-20 06:55:06 +01:00
_ = response . value
2021-02-05 10:53:00 +01:00
// TODO:
let alertController = UIAlertController ( title : " Success " , message : " Regsiter request sent. Please check your email. \n (Auto sign in not implement yet.) " , preferredStyle : . alert )
2021-02-22 09:20:44 +01:00
let okAction = UIAlertAction ( title : L10n . Common . Controls . Actions . ok , style : . default ) { [ weak self ] _ in
2021-02-05 10:53:00 +01:00
guard let self = self else { return }
self . navigationController ? . popViewController ( animated : true )
}
alertController . addAction ( okAction )
self . coordinator . present ( scene : . alertController ( alertController : alertController ) , from : self , transition : . alertController ( animated : true , completion : nil ) )
}
. store ( in : & disposeBag )
}
}