mirror of https://github.com/oxen-io/session-ios
				
				
				
			
			You cannot select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
	
	
		
			86 lines
		
	
	
		
			2.9 KiB
		
	
	
	
		
			Swift
		
	
		
		
			
		
	
	
			86 lines
		
	
	
		
			2.9 KiB
		
	
	
	
		
			Swift
		
	
| 
											5 years ago
										 | 
 | ||
|  | // Assumptions | ||
|  | // • We'll never encounter an outgoing typing indicator. | ||
|  | // • Typing indicators are only sent in contact threads. | ||
|  | 
 | ||
| 
											5 years ago
										 | final class TypingIndicatorCell : MessageCell { | ||
| 
											5 years ago
										 | 
 | ||
|  |     private var positionInCluster: Position? { | ||
|  |         guard let viewItem = viewItem else { return nil } | ||
|  |         if viewItem.isFirstInCluster { return .top } | ||
|  |         if viewItem.isLastInCluster { return .bottom } | ||
|  |         return .middle | ||
|  |     } | ||
|  |      | ||
|  |     private var isOnlyMessageInCluster: Bool { viewItem?.isFirstInCluster == true && viewItem?.isLastInCluster == true } | ||
|  | 
 | ||
|  |     // MARK: UI Components | ||
|  |     private lazy var bubbleView: UIView = { | ||
|  |         let result = UIView() | ||
|  |         result.layer.cornerRadius = VisibleMessageCell.smallCornerRadius | ||
|  |         result.backgroundColor = Colors.receivedMessageBackground | ||
|  |         return result | ||
|  |     }() | ||
|  | 
 | ||
|  |     private let bubbleViewMaskLayer = CAShapeLayer() | ||
|  | 
 | ||
|  |     private lazy var typingIndicatorView = TypingIndicatorView() | ||
|  | 
 | ||
|  |     // MARK: Settings | ||
|  |     override class var identifier: String { "TypingIndicatorCell" } | ||
|  | 
 | ||
|  |     // MARK: Direction & Position | ||
|  |     enum Position { case top, middle, bottom } | ||
|  | 
 | ||
|  |     // MARK: Lifecycle | ||
|  |     override func setUpViewHierarchy() { | ||
|  |         super.setUpViewHierarchy() | ||
|  |         // Bubble view | ||
|  |         addSubview(bubbleView) | ||
|  |         bubbleView.pin(.left, to: .left, of: self, withInset: VisibleMessageCell.contactThreadHSpacing) | ||
|  |         bubbleView.pin(.top, to: .top, of: self, withInset: 1) | ||
|  |         // Typing indicator view | ||
|  |         bubbleView.addSubview(typingIndicatorView) | ||
|  |         typingIndicatorView.pin(to: bubbleView, withInset: 12) | ||
|  |     } | ||
|  | 
 | ||
|  |     // MARK: Updating | ||
|  |     override func update() { | ||
|  |         guard let viewItem = viewItem, viewItem.interaction is TypingIndicatorInteraction else { return } | ||
|  |         // Bubble view | ||
|  |         updateBubbleViewCorners() | ||
|  |         // Typing indicator view | ||
|  |         typingIndicatorView.startAnimation() | ||
|  |     } | ||
|  | 
 | ||
|  |     override func layoutSubviews() { | ||
|  |         super.layoutSubviews() | ||
|  |         updateBubbleViewCorners() | ||
|  |     } | ||
|  | 
 | ||
|  |     private func updateBubbleViewCorners() { | ||
|  |         let maskPath = UIBezierPath(roundedRect: bubbleView.bounds, byRoundingCorners: getCornersToRound(), | ||
|  |             cornerRadii: CGSize(width: VisibleMessageCell.largeCornerRadius, height: VisibleMessageCell.largeCornerRadius)) | ||
|  |         bubbleViewMaskLayer.path = maskPath.cgPath | ||
|  |         bubbleView.layer.mask = bubbleViewMaskLayer | ||
|  |     } | ||
|  | 
 | ||
|  |     override func prepareForReuse() { | ||
|  |         super.prepareForReuse() | ||
|  |         typingIndicatorView.stopAnimation() | ||
|  |     } | ||
|  | 
 | ||
|  |     // MARK: Convenience | ||
|  |     private func getCornersToRound() -> UIRectCorner { | ||
|  |         guard !isOnlyMessageInCluster else { return .allCorners } | ||
|  |         let result: UIRectCorner | ||
|  |         switch positionInCluster { | ||
|  |         case .top: result = [ .topLeft, .topRight, .bottomRight ] | ||
|  |         case .middle: result = [ .topRight, .bottomRight ] | ||
|  |         case .bottom: result = [ .topRight, .bottomRight, .bottomLeft ] | ||
|  |         case nil: result = .allCorners | ||
|  |         } | ||
|  |         return result | ||
|  |     } | ||
|  | } |