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-23 08:16:55 +01:00
label . textColor = . black
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-23 08:16:55 +01:00
label . textColor = . black
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 )
2021-02-22 10:48:44 +01:00
tapGestureRecognizer . addTarget ( self , action : #selector ( tapGestureRecognizerHandler ) )
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:37:13 +01:00
2021-02-22 09:20:44 +01:00
self . scrollView . contentInset . bottom = padding + 16
self . scrollView . verticalScrollIndicatorInsets . bottom = padding + 16
2021-02-22 09:37:13 +01:00
if self . passwordTextField . isFirstResponder {
let contentFrame = self . scrollView . convert ( self . signUpButton . frame , to : nil )
let labelPadding = contentFrame . maxY - endFrame . minY
let contentOffsetY = self . scrollView . contentOffset . y
DispatchQueue . main . async {
self . scrollView . setContentOffset ( CGPoint ( x : 0 , y : contentOffsetY + labelPadding + 16.0 ) , animated : true )
}
}
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-22 10:48:44 +01:00
viewModel . usernameValidateState
2021-02-20 10:13:16 +01:00
. receive ( on : DispatchQueue . main )
2021-02-22 10:48:44 +01:00
. sink { [ weak self ] validateState in
2021-02-20 10:13:16 +01:00
guard let self = self else { return }
2021-02-22 10:48:44 +01:00
self . setTextFieldValidAppearance ( self . usernameTextField , validateState : validateState )
2021-02-20 10:13:16 +01:00
}
. store ( in : & disposeBag )
2021-02-22 10:48:44 +01:00
viewModel . displayNameValidateState
2021-02-20 11:24:23 +01:00
. receive ( on : DispatchQueue . main )
2021-02-22 10:48:44 +01:00
. sink { [ weak self ] validateState in
2021-02-20 11:24:23 +01:00
guard let self = self else { return }
2021-02-22 10:48:44 +01:00
self . setTextFieldValidAppearance ( self . displayNameTextField , validateState : validateState )
2021-02-20 11:24:23 +01:00
}
. store ( in : & disposeBag )
2021-02-22 10:48:44 +01:00
viewModel . emailValidateState
2021-02-20 11:24:23 +01:00
. receive ( on : DispatchQueue . main )
2021-02-22 10:48:44 +01:00
. sink { [ weak self ] validateState in
2021-02-20 11:24:23 +01:00
guard let self = self else { return }
2021-02-22 10:48:44 +01:00
self . setTextFieldValidAppearance ( self . emailTextField , validateState : validateState )
2021-02-20 11:24:23 +01:00
}
. store ( in : & disposeBag )
2021-02-22 10:48:44 +01:00
viewModel . passwordValidateState
2021-02-20 11:24:23 +01:00
. receive ( on : DispatchQueue . main )
2021-02-22 10:48:44 +01:00
. sink { [ weak self ] validateState in
2021-02-20 11:24:23 +01:00
guard let self = self else { return }
2021-02-22 10:48:44 +01:00
self . setTextFieldValidAppearance ( self . passwordTextField , validateState : validateState )
self . passwordCheckLabel . attributedText = self . viewModel . attributeStringForPassword ( eightCharacters : validateState = = . valid )
2021-02-20 11:24:23 +01:00
}
. store ( in : & disposeBag )
2021-02-20 10:13:16 +01:00
2021-02-22 10:48:44 +01:00
viewModel . isAllValid
2021-02-20 11:24:23 +01:00
. receive ( on : DispatchQueue . main )
2021-02-22 10:48:44 +01:00
. sink { [ weak self ] isAllValid in
2021-02-20 11:24:23 +01:00
guard let self = self else { return }
2021-02-22 10:48:44 +01:00
self . signUpButton . isEnabled = isAllValid
2021-02-20 11:24:23 +01:00
}
. 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-22 10:48:44 +01:00
NotificationCenter . default
. publisher ( for : UITextField . textDidChangeNotification , object : usernameTextField )
. receive ( on : DispatchQueue . main )
. sink { [ weak self ] _ in
guard let self = self else { return }
self . viewModel . username . value = self . usernameTextField . text ? . trimmingCharacters ( in : . whitespacesAndNewlines ) ? ? " "
}
. store ( in : & disposeBag )
NotificationCenter . default
. publisher ( for : UITextField . textDidChangeNotification , object : displayNameTextField )
. receive ( on : DispatchQueue . main )
. sink { [ weak self ] _ in
guard let self = self else { return }
self . viewModel . displayName . value = self . displayNameTextField . text ? . trimmingCharacters ( in : . whitespacesAndNewlines ) ? ? " "
}
. store ( in : & disposeBag )
NotificationCenter . default
. publisher ( for : UITextField . textDidChangeNotification , object : emailTextField )
. receive ( on : DispatchQueue . main )
. sink { [ weak self ] _ in
guard let self = self else { return }
self . viewModel . email . value = self . emailTextField . text ? . trimmingCharacters ( in : . whitespacesAndNewlines ) ? ? " "
}
. store ( in : & disposeBag )
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 }
2021-02-22 10:48:44 +01:00
self . viewModel . password . value = self . passwordTextField . text ? . trimmingCharacters ( in : . whitespacesAndNewlines ) ? ? " "
2021-02-20 06:55:06 +01:00
}
. 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 {
2021-02-22 09:37:13 +01:00
// FIXME: k e y b o a r d l i s t e n e r t r i g g e r w h e n s w i t c h b e t w e e n t e x t f i e l d s . M a y b e c o u l d r e m o v e i t
// f u n c t e x t F i e l d D i d B e g i n E d i t i n g ( _ t e x t F i e l d : U I T e x t F i e l d ) {
// / / 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
// i f t e x t F i e l d = = = p a s s w o r d T e x t F i e l d ,
// K e y b o a r d R e s p o n d e r S e r v i c e . s h a r e d . i s S h o w . v a l u e ,
// K e y b o a r d R e s p o n d e r S e r v i c e . s h a r e d . s t a t e . v a l u e = = . d o c k
// {
// l e t e n d F r a m e = K e y b o a r d R e s p o n d e r S e r v i c e . s h a r e d . w i l l E n d F r a m e . v a l u e
// l e t c o n t e n t F r a m e = s c r o l l V i e w . c o n v e r t ( s i g n U p B u t t o n . f r a m e , t o : n i l )
// l e t p a d d i n g = c o n t e n t F r a m e . m a x Y - e n d F r a m e . m i n Y
// i f p a d d i n g > 0 {
// l e t c o n t e n t O f f s e t Y = s c r o l l V i e w . c o n t e n t O f f s e t . y
// D i s p a t c h Q u e u e . m a i n . a s y n c {
// s e l f . s c r o l l V i e w . s e t C o n t e n t O f f s e t ( C G P o i n t ( x : 0 , y : c o n t e n t O f f s e t Y + p a d d i n g + 1 6 . 0 ) , a n i m a t e d : t r u e )
// }
// }
// }
// }
2021-02-22 10:48:44 +01:00
func textFieldDidBeginEditing ( _ textField : UITextField ) {
let text = textField . text ? . trimmingCharacters ( in : . whitespacesAndNewlines ) ? ? " "
2021-02-20 10:13:16 +01:00
switch textField {
case usernameTextField :
2021-02-22 10:48:44 +01:00
viewModel . username . value = text
2021-02-20 11:24:23 +01:00
case displayNameTextField :
2021-02-22 10:48:44 +01:00
viewModel . displayName . value = text
2021-02-20 11:24:23 +01:00
case emailTextField :
2021-02-22 10:48:44 +01:00
viewModel . email . value = text
2021-02-20 11:24:23 +01:00
case passwordTextField :
2021-02-22 10:48:44 +01:00
viewModel . password . value = 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-22 10:48:44 +01:00
private func setTextFieldValidAppearance ( _ textField : UITextField , validateState : MastodonRegisterViewModel . ValidateState ) {
switch validateState {
case . empty :
showShadowWithColor ( color : textField . isFirstResponder ? Asset . Colors . TextField . highlight . color : . clear , textField : textField )
case . valid :
showShadowWithColor ( color : Asset . Colors . TextField . valid . color , textField : textField )
case . invalid :
showShadowWithColor ( color : Asset . Colors . TextField . invalid . color , textField : textField )
2021-02-20 10:13:16 +01:00
}
}
2021-02-20 06:55:06 +01:00
}
extension MastodonRegisterViewController {
2021-02-22 10:48:44 +01:00
@objc private func tapGestureRecognizerHandler ( _ sender : UITapGestureRecognizer ) {
view . endEditing ( true )
2021-02-20 06:55:06 +01:00
}
@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-22 10:48:44 +01:00
guard viewModel . isAllValid . value else { return }
2021-02-05 10:53:00 +01:00
guard ! viewModel . isRegistering . value else { return }
viewModel . isRegistering . value = true
2021-02-22 10:48:44 +01:00
let username = viewModel . username . value
let email = viewModel . email . value
let password = viewModel . password . value
2021-02-05 10:53:00 +01:00
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 }
2021-02-23 08:38:05 +01:00
let viewModel = MastodonConfirmEmailViewModel ( context : self . context , email : email )
self . coordinator . present ( scene : . mastodonConfirmEmail ( viewModel : viewModel ) , from : self , transition : . show )
2021-02-05 10:53:00 +01:00
}
alertController . addAction ( okAction )
self . coordinator . present ( scene : . alertController ( alertController : alertController ) , from : self , transition : . alertController ( animated : true , completion : nil ) )
}
. store ( in : & disposeBag )
}
2021-02-22 10:48:44 +01:00
2021-02-05 10:53:00 +01:00
}