2020-04-14 07:07:37 +02:00
final class PNModeVC : BaseVC , OptionViewDelegate {
private var optionViews : [ OptionView ] {
[ apnsOptionView , backgroundPollingOptionView , noPNsOptionView ]
}
private var selectedOptionView : OptionView ? {
return optionViews . first { $0 . isSelected }
}
// MARK: C o m p o n e n t s
private lazy var apnsOptionView = OptionView ( title : " Apple Push Notification Service " , explanation : " The app will use the Apple Push Notification Service. You'll be notified of new messages immediately. This mode entails a slight privacy sacrifice as Apple will know your IP. The contents of your messages will still be fully encrypted, your data will still be stored in a decentralized manner and your messages will still be onion routed. " , delegate : self )
private lazy var backgroundPollingOptionView = OptionView ( title : " Background Polling " , explanation : " The app will occassionally check for new messages when it's in the background. This provides full privacy but notifications may be significantly delayed. " , delegate : self )
private lazy var noPNsOptionView = OptionView ( title : " No Push Notifications " , explanation : " You will not be notified of new messages when the app is closed. This provides full privacy. " , delegate : self )
// MARK: L i f e c y c l e
override func viewDidLoad ( ) {
super . viewDidLoad ( )
// S e t g r a d i e n t b a c k g r o u n d
view . backgroundColor = . clear
let gradient = Gradients . defaultLokiBackground
view . setGradient ( gradient )
// S e t u p n a v i g a t i o n b a r
let navigationBar = navigationController ! . navigationBar
navigationBar . setBackgroundImage ( UIImage ( ) , for : UIBarMetrics . default )
navigationBar . shadowImage = UIImage ( )
navigationBar . isTranslucent = false
navigationBar . barTintColor = Colors . navigationBarBackground
// S e t u p l o g o i m a g e v i e w
let logoImageView = UIImageView ( )
logoImageView . image = # imageLiteral ( resourceName : " SessionGreen32 " )
logoImageView . contentMode = . scaleAspectFit
logoImageView . set ( . width , to : 32 )
logoImageView . set ( . height , to : 32 )
navigationItem . titleView = logoImageView
// S e t u p t i t l e l a b e l
let titleLabel = UILabel ( )
titleLabel . textColor = Colors . text
titleLabel . font = . boldSystemFont ( ofSize : isSmallScreen ? Values . largeFontSize : Values . veryLargeFontSize )
titleLabel . text = " Push Notifications "
titleLabel . numberOfLines = 0
titleLabel . lineBreakMode = . byWordWrapping
// S e t u p e x p l a n a t i o n l a b e l
let explanationLabel = UILabel ( )
explanationLabel . textColor = Colors . text
explanationLabel . font = . systemFont ( ofSize : Values . smallFontSize )
explanationLabel . text = " Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. "
explanationLabel . numberOfLines = 0
explanationLabel . lineBreakMode = . byWordWrapping
// S e t u p s p a c e r s
let topSpacer = UIView . vStretchingSpacer ( )
let bottomSpacer = UIView . vStretchingSpacer ( )
let registerButtonBottomOffsetSpacer = UIView ( )
registerButtonBottomOffsetSpacer . set ( . height , to : Values . onboardingButtonBottomOffset )
// S e t u p r e g i s t e r b u t t o n
let registerButton = Button ( style : . prominentFilled , size : . large )
registerButton . setTitle ( NSLocalizedString ( " Continue " , comment : " " ) , for : UIControl . State . normal )
registerButton . titleLabel ! . font = . boldSystemFont ( ofSize : Values . mediumFontSize )
registerButton . addTarget ( self , action : #selector ( register ) , for : UIControl . Event . touchUpInside )
// S e t u p r e g i s t e r b u t t o n c o n t a i n e r
let registerButtonContainer = UIView ( wrapping : registerButton , withInsets : UIEdgeInsets ( top : 0 , leading : Values . massiveSpacing , bottom : 0 , trailing : Values . massiveSpacing ) )
// S e t u p o p t i o n s s t a c k v i e w
let optionsStackView = UIStackView ( arrangedSubviews : optionViews )
optionsStackView . axis = . vertical
optionsStackView . spacing = Values . smallSpacing
optionsStackView . alignment = . fill
// S e t u p t o p s t a c k v i e w
let topStackView = UIStackView ( arrangedSubviews : [ titleLabel , explanationLabel , optionsStackView ] )
topStackView . axis = . vertical
topStackView . spacing = isSmallScreen ? Values . smallSpacing : Values . veryLargeSpacing
topStackView . alignment = . fill
// S e t u p t o p s t a c k v i e w c o n t a i n e r
let topStackViewContainer = UIView ( wrapping : topStackView , withInsets : UIEdgeInsets ( top : 0 , leading : Values . veryLargeSpacing , bottom : 0 , trailing : Values . veryLargeSpacing ) )
// S e t u p m a i n s t a c k v i e w
let mainStackView = UIStackView ( arrangedSubviews : [ topSpacer , topStackViewContainer , bottomSpacer , registerButtonContainer , registerButtonBottomOffsetSpacer ] )
mainStackView . axis = . vertical
mainStackView . alignment = . fill
view . addSubview ( mainStackView )
mainStackView . pin ( to : view )
topSpacer . heightAnchor . constraint ( equalTo : bottomSpacer . heightAnchor , multiplier : 1 ) . isActive = true
}
// MARK: I n t e r a c t i o n
fileprivate func optionViewDidActivate ( _ optionView : OptionView ) {
optionViews . filter { $0 != optionView } . forEach { $0 . isSelected = false }
}
@objc private func register ( ) {
2020-04-14 08:57:32 +02:00
guard selectedOptionView != nil else {
let title = NSLocalizedString ( " Please Pick an Option " , comment : " " )
let alert = UIAlertController ( title : title , message : nil , preferredStyle : . alert )
alert . addAction ( UIAlertAction ( title : NSLocalizedString ( " OK " , comment : " " ) , style : . default , handler : nil ) )
return present ( alert , animated : true , completion : nil )
}
2020-04-14 08:32:10 +02:00
UserDefaults . standard [ . isUsingFullAPNs ] = ( selectedOptionView = = apnsOptionView )
2020-04-14 08:11:22 +02:00
TSAccountManager . sharedInstance ( ) . didRegister ( )
let homeVC = HomeVC ( )
navigationController ! . setViewControllers ( [ homeVC ] , animated : true )
2020-04-14 07:07:37 +02:00
}
}
// MARK: O p t i o n V i e w
private extension PNModeVC {
final class OptionView : UIView {
private let title : String
private let explanation : String
private let delegate : OptionViewDelegate
var isSelected = false { didSet { handleIsSelectedChanged ( ) } }
init ( title : String , explanation : String , delegate : OptionViewDelegate ) {
self . title = title
self . explanation = explanation
self . delegate = delegate
super . init ( frame : CGRect . zero )
setUpViewHierarchy ( )
}
override init ( frame : CGRect ) {
preconditionFailure ( " Use init(string:explanation:) instead. " )
}
required init ? ( coder : NSCoder ) {
preconditionFailure ( " Use init(string:explanation:) instead. " )
}
private func setUpViewHierarchy ( ) {
backgroundColor = Colors . pnOptionBackground
// R o u n d c o r n e r s
layer . cornerRadius = Values . pnOptionCornerRadius
// S e t u p b o r d e r
layer . borderWidth = Values . borderThickness
layer . borderColor = Colors . pnOptionBorder . cgColor
// S e t u p s h a d o w
layer . shadowColor = UIColor . black . cgColor
layer . shadowOffset = CGSize ( width : 0 , height : 0.8 )
layer . shadowOpacity = isLightMode ? 0.4 : 1
layer . shadowRadius = isLightMode ? 4 : 6
// S e t u p t i t l e l a b e l
let titleLabel = UILabel ( )
titleLabel . textColor = Colors . text
titleLabel . font = . boldSystemFont ( ofSize : Values . mediumFontSize )
titleLabel . text = title
titleLabel . numberOfLines = 0
titleLabel . lineBreakMode = . byWordWrapping
// S e t u p e x p l a n a t i o n l a b e l
let explanationLabel = UILabel ( )
explanationLabel . textColor = Colors . text
explanationLabel . font = . systemFont ( ofSize : Values . verySmallFontSize )
explanationLabel . text = explanation
explanationLabel . numberOfLines = 0
explanationLabel . lineBreakMode = . byWordWrapping
// S e t u p s t a c k v i e w
let stackView = UIStackView ( arrangedSubviews : [ titleLabel , explanationLabel ] )
stackView . axis = . vertical
stackView . alignment = . fill
addSubview ( stackView )
stackView . pin ( . leading , to : . leading , of : self , withInset : 12 )
stackView . pin ( . top , to : . top , of : self , withInset : 12 )
self . pin ( . trailing , to : . trailing , of : stackView , withInset : 12 )
self . pin ( . bottom , to : . bottom , of : stackView , withInset : 12 )
// S e t u p t a p g e s t u r e r e c o g n i z e r
let tapGestureRecognizer = UITapGestureRecognizer ( target : self , action : #selector ( handleTap ) )
addGestureRecognizer ( tapGestureRecognizer )
}
@objc private func handleTap ( ) {
isSelected = ! isSelected
}
private func handleIsSelectedChanged ( ) {
let animationDuration : TimeInterval = 0.25
2020-04-14 08:11:22 +02:00
// A n i m a t e b o r d e r c o l o r
let newBorderColor = isSelected ? Colors . accent . cgColor : Colors . pnOptionBorder . cgColor
let borderAnimation = CABasicAnimation ( keyPath : " borderColor " )
borderAnimation . fromValue = layer . shadowColor
borderAnimation . toValue = newBorderColor
borderAnimation . duration = animationDuration
layer . add ( borderAnimation , forKey : borderAnimation . keyPath )
layer . borderColor = newBorderColor
// A n i m a t e s h a d o w c o l o r
2020-04-14 07:07:37 +02:00
let newShadowColor = isSelected ? Colors . newConversationButtonShadow . cgColor : UIColor . black . cgColor
let shadowAnimation = CABasicAnimation ( keyPath : " shadowColor " )
shadowAnimation . fromValue = layer . shadowColor
shadowAnimation . toValue = newShadowColor
shadowAnimation . duration = animationDuration
layer . add ( shadowAnimation , forKey : shadowAnimation . keyPath )
layer . shadowColor = newShadowColor
2020-04-14 08:11:22 +02:00
// N o t i f y d e l e g a t e
2020-04-14 07:07:37 +02:00
if isSelected { delegate . optionViewDidActivate ( self ) }
}
}
}
// MARK: O p t i o n V i e w D e l e g a t e
private protocol OptionViewDelegate {
func optionViewDidActivate ( _ optionView : PNModeVC . OptionView )
}