2019-12-06 04:42:43 +01:00
final class FakeChatView : UIView {
private let spacing = Values . mediumSpacing
2019-12-09 01:50:45 +01:00
var contentOffset : CGPoint {
get { return scrollView . contentOffset }
set { scrollView . contentOffset = newValue }
}
2019-12-06 04:42:43 +01:00
private lazy var chatBubbles = [
2019-12-13 05:02:05 +01:00
getChatBubble ( withText : NSLocalizedString ( " What's Loki Messenger? " , comment : " " ) , wasSentByCurrentUser : true ) ,
getChatBubble ( withText : NSLocalizedString ( " It's a secure, decentralized cross-platform private messaging app " , comment : " " ) , wasSentByCurrentUser : false ) ,
getChatBubble ( withText : NSLocalizedString ( " So it doesn't collect my personal information or my conversation metadata? How's it work? " , comment : " " ) , wasSentByCurrentUser : true ) ,
getChatBubble ( withText : NSLocalizedString ( " Using a combination of advanced anonymous routing and end-to-end encryption technologies. " , comment : " " ) , wasSentByCurrentUser : false ) ,
getChatBubble ( withText : NSLocalizedString ( " Friends don't let friends use compromised messengers. You're welcome. " , comment : " " ) , wasSentByCurrentUser : false )
2019-12-06 04:42:43 +01:00
]
private lazy var scrollView : UIScrollView = {
let result = UIScrollView ( )
2019-12-09 00:01:10 +01:00
result . showsHorizontalScrollIndicator = false
2019-12-06 04:42:43 +01:00
result . showsVerticalScrollIndicator = false
return result
} ( )
override init ( frame : CGRect ) {
super . init ( frame : frame )
setUpViewHierarchy ( )
animate ( )
}
required init ? ( coder : NSCoder ) {
super . init ( coder : coder )
setUpViewHierarchy ( )
animate ( )
}
private func setUpViewHierarchy ( ) {
let stackView = UIStackView ( arrangedSubviews : chatBubbles )
stackView . axis = . vertical
stackView . spacing = spacing
stackView . alignment = . fill
stackView . set ( . width , to : UIScreen . main . bounds . width )
stackView . layoutMargins = UIEdgeInsets ( top : 8 , leading : Values . veryLargeSpacing , bottom : 8 , trailing : Values . veryLargeSpacing )
stackView . isLayoutMarginsRelativeArrangement = true
scrollView . addSubview ( stackView )
stackView . pin ( to : scrollView )
addSubview ( scrollView )
scrollView . pin ( to : self )
}
private func getChatBubble ( withText text : String , wasSentByCurrentUser : Bool ) -> UIView {
let result = UIView ( )
let bubbleView = UIView ( )
bubbleView . set ( . width , to : Values . fakeChatBubbleWidth )
bubbleView . layer . cornerRadius = Values . fakeChatBubbleCornerRadius
2019-12-06 06:42:28 +01:00
bubbleView . layer . shadowColor = UIColor . black . cgColor
bubbleView . layer . shadowRadius = 8
bubbleView . layer . shadowOpacity = 0.64
2019-12-13 05:02:05 +01:00
let backgroundColor = wasSentByCurrentUser ? Colors . fakeChatBubbleBackground : Colors . accent
2019-12-06 04:42:43 +01:00
bubbleView . backgroundColor = backgroundColor
let label = UILabel ( )
2019-12-13 05:02:05 +01:00
let textColor = wasSentByCurrentUser ? Colors . text : Colors . fakeChatBubbleText
2019-12-06 04:42:43 +01:00
label . textColor = textColor
label . font = . boldSystemFont ( ofSize : Values . mediumFontSize )
label . numberOfLines = 0
label . lineBreakMode = . byWordWrapping
label . text = text
bubbleView . addSubview ( label )
2019-12-06 06:42:28 +01:00
label . pin ( to : bubbleView , withInset : 12 )
2019-12-06 04:42:43 +01:00
result . addSubview ( bubbleView )
bubbleView . pin ( . top , to : . top , of : result )
result . pin ( . bottom , to : . bottom , of : bubbleView )
if wasSentByCurrentUser {
2019-12-13 05:02:05 +01:00
bubbleView . pin ( . trailing , to : . trailing , of : result )
2019-12-06 04:42:43 +01:00
} else {
2019-12-13 05:02:05 +01:00
result . pin ( . leading , to : . leading , of : bubbleView )
2019-12-06 04:42:43 +01:00
}
return result
}
private func animate ( ) {
let animationDuration = Values . fakeChatAnimationDuration
let delayBetweenMessages = Values . fakeChatDelay
chatBubbles . forEach { $0 . alpha = 0 }
Timer . scheduledTimer ( withTimeInterval : Values . fakeChatStartDelay , repeats : false ) { [ weak self ] _ in
self ? . showChatBubble ( at : 0 )
2019-12-13 05:02:05 +01:00
Timer . scheduledTimer ( withTimeInterval : 1.5 * delayBetweenMessages , repeats : false ) { _ in
2019-12-06 04:42:43 +01:00
self ? . showChatBubble ( at : 1 )
2019-12-09 00:01:10 +01:00
Timer . scheduledTimer ( withTimeInterval : 1.5 * delayBetweenMessages , repeats : false ) { _ in
2019-12-06 04:42:43 +01:00
self ? . showChatBubble ( at : 2 )
UIView . animate ( withDuration : animationDuration ) {
guard let self = self else { return }
self . scrollView . contentOffset = CGPoint ( x : 0 , y : self . chatBubbles [ 0 ] . height ( ) + self . spacing )
}
2019-12-13 05:02:05 +01:00
Timer . scheduledTimer ( withTimeInterval : 1.5 * delayBetweenMessages , repeats : false ) { _ in
2019-12-06 04:42:43 +01:00
self ? . showChatBubble ( at : 3 )
UIView . animate ( withDuration : animationDuration ) {
guard let self = self else { return }
self . scrollView . contentOffset = CGPoint ( x : 0 , y : self . chatBubbles [ 0 ] . height ( ) + self . spacing + self . chatBubbles [ 1 ] . height ( ) + self . spacing )
}
2019-12-13 05:02:05 +01:00
Timer . scheduledTimer ( withTimeInterval : delayBetweenMessages , repeats : false ) { _ in
self ? . showChatBubble ( at : 4 )
UIView . animate ( withDuration : animationDuration ) {
guard let self = self else { return }
self . scrollView . contentOffset = CGPoint ( x : 0 , y : self . chatBubbles [ 0 ] . height ( ) + self . spacing + self . chatBubbles [ 1 ] . height ( ) + self . spacing + self . chatBubbles [ 2 ] . height ( ) + self . spacing )
}
}
2019-12-06 04:42:43 +01:00
}
}
}
}
}
private func showChatBubble ( at index : Int ) {
let chatBubble = chatBubbles [ index ]
UIView . animate ( withDuration : Values . fakeChatAnimationDuration ) {
chatBubble . alpha = 1
}
let scale = Values . fakeChatMessagePopAnimationStartScale
chatBubble . transform = CGAffineTransform ( scaleX : scale , y : scale )
UIView . animate ( withDuration : Values . fakeChatAnimationDuration , delay : 0 , usingSpringWithDamping : 0.68 , initialSpringVelocity : 4 , options : . curveEaseInOut , animations : {
chatBubble . transform = CGAffineTransform ( scaleX : 1 , y : 1 )
} , completion : nil )
}
}