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
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								}
							 |