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.
		
		
		
		
		
			
		
			
	
	
		
			175 lines
		
	
	
		
			6.9 KiB
		
	
	
	
		
			Swift
		
	
		
		
			
		
	
	
			175 lines
		
	
	
		
			6.9 KiB
		
	
	
	
		
			Swift
		
	
| 
											5 years ago
										 | import NVActivityIndicatorView | ||
| 
											5 years ago
										 | 
 | ||
| 
											5 years ago
										 | final class LinkPreviewView : UIView { | ||
| 
											5 years ago
										 |     private let viewItem: ConversationViewItem? | ||
| 
											5 years ago
										 |     private let maxWidth: CGFloat | ||
| 
											5 years ago
										 |     private let delegate: LinkPreviewViewDelegate | ||
| 
											5 years ago
										 |     var linkPreviewState: LinkPreviewState? { didSet { update() } } | ||
| 
											5 years ago
										 |     private lazy var imageViewContainerWidthConstraint = imageView.set(.width, to: 100) | ||
|  |     private lazy var imageViewContainerHeightConstraint = imageView.set(.height, to: 100) | ||
| 
											5 years ago
										 | 
 | ||
| 
											5 years ago
										 |     private lazy var sentLinkPreviewTextColor: UIColor = { | ||
|  |         let isOutgoing = (viewItem!.interaction.interactionType() == .outgoingMessage) | ||
| 
											5 years ago
										 |         switch (isOutgoing, AppModeManager.shared.currentAppMode) { | ||
|  |         case (true, .dark), (false, .light): return .black | ||
|  |         default: return .white | ||
|  |         } | ||
| 
											5 years ago
										 |     }() | ||
| 
											5 years ago
										 | 
 | ||
|  |     // MARK: UI Components | ||
|  |     private lazy var imageView: UIImageView = { | ||
|  |         let result = UIImageView() | ||
|  |         result.contentMode = .scaleAspectFill | ||
|  |         return result | ||
|  |     }() | ||
|  | 
 | ||
| 
											5 years ago
										 |     private lazy var imageViewContainer: UIView = { | ||
|  |         let result = UIView() | ||
|  |         result.clipsToBounds = true | ||
|  |         return result | ||
|  |     }() | ||
|  | 
 | ||
|  |     private lazy var loader: NVActivityIndicatorView = { | ||
|  |         let color: UIColor = isLightMode ? .black : .white | ||
|  |         return NVActivityIndicatorView(frame: CGRect.zero, type: .circleStrokeSpin, color: color, padding: nil) | ||
|  |     }() | ||
|  | 
 | ||
| 
											5 years ago
										 |     private lazy var titleLabel: UILabel = { | ||
|  |         let result = UILabel() | ||
|  |         result.font = .boldSystemFont(ofSize: Values.smallFontSize) | ||
|  |         result.numberOfLines = 0 | ||
|  |         return result | ||
|  |     }() | ||
|  | 
 | ||
|  |     private lazy var bodyTextViewContainer = UIView() | ||
|  | 
 | ||
| 
											5 years ago
										 |     private lazy var hStackViewContainer = UIView() | ||
|  | 
 | ||
| 
											5 years ago
										 |     private lazy var hStackView = UIStackView() | ||
|  | 
 | ||
|  |     private lazy var cancelButton: UIButton = { | ||
|  |         let result = UIButton(type: .custom) | ||
|  |         let tint: UIColor = isLightMode ? .black : .white | ||
|  |         result.setImage(UIImage(named: "X")?.withTint(tint), for: UIControl.State.normal) | ||
| 
											5 years ago
										 |         let cancelButtonSize = LinkPreviewView.cancelButtonSize | ||
| 
											5 years ago
										 |         result.set(.width, to: cancelButtonSize) | ||
|  |         result.set(.height, to: cancelButtonSize) | ||
|  |         result.addTarget(self, action: #selector(cancel), for: UIControl.Event.touchUpInside) | ||
|  |         return result | ||
|  |     }() | ||
|  | 
 | ||
| 
											5 years ago
										 |     // MARK: Settings | ||
| 
											5 years ago
										 |     private static let loaderSize: CGFloat = 24 | ||
| 
											5 years ago
										 |     private static let cancelButtonSize: CGFloat = 45 | ||
| 
											5 years ago
										 | 
 | ||
|  |     // MARK: Lifecycle | ||
| 
											5 years ago
										 |     init(for viewItem: ConversationViewItem?, maxWidth: CGFloat, delegate: LinkPreviewViewDelegate) { | ||
| 
											5 years ago
										 |         self.viewItem = viewItem | ||
| 
											5 years ago
										 |         self.maxWidth = maxWidth | ||
|  |         self.delegate = delegate | ||
| 
											5 years ago
										 |         super.init(frame: CGRect.zero) | ||
|  |         setUpViewHierarchy() | ||
|  |     } | ||
|  |      | ||
|  |     override init(frame: CGRect) { | ||
| 
											5 years ago
										 |         preconditionFailure("Use init(for:maxWidth:delegate:) instead.") | ||
| 
											5 years ago
										 |     } | ||
|  |      | ||
|  |     required init?(coder: NSCoder) { | ||
| 
											5 years ago
										 |         preconditionFailure("Use init(for:maxWidth:delegate:) instead.") | ||
| 
											5 years ago
										 |     } | ||
|  |      | ||
|  |     private func setUpViewHierarchy() { | ||
| 
											5 years ago
										 |         // Image view | ||
| 
											5 years ago
										 |         imageViewContainerWidthConstraint.isActive = true | ||
|  |         imageViewContainerHeightConstraint.isActive = true | ||
| 
											5 years ago
										 |         imageViewContainer.addSubview(imageView) | ||
|  |         imageView.pin(to: imageViewContainer) | ||
| 
											5 years ago
										 |         // Title label | ||
| 
											5 years ago
										 |         let titleLabelContainer = UIView() | ||
|  |         titleLabelContainer.addSubview(titleLabel) | ||
|  |         titleLabel.pin(to: titleLabelContainer, withInset: Values.smallSpacing) | ||
| 
											5 years ago
										 |         // Horizontal stack view | ||
| 
											5 years ago
										 |         hStackView.addArrangedSubview(imageViewContainer) | ||
|  |         hStackView.addArrangedSubview(titleLabelContainer) | ||
| 
											5 years ago
										 |         hStackView.axis = .horizontal | ||
|  |         hStackView.alignment = .center | ||
|  |         hStackViewContainer.addSubview(hStackView) | ||
|  |         hStackView.pin(to: hStackViewContainer) | ||
|  |         // Vertical stack view | ||
|  |         let vStackView = UIStackView(arrangedSubviews: [ hStackViewContainer, bodyTextViewContainer ]) | ||
| 
											5 years ago
										 |         vStackView.axis = .vertical | ||
|  |         addSubview(vStackView) | ||
|  |         vStackView.pin(to: self) | ||
| 
											5 years ago
										 |         // Loader | ||
|  |         addSubview(loader) | ||
| 
											5 years ago
										 |         let loaderSize = LinkPreviewView.loaderSize | ||
| 
											5 years ago
										 |         loader.set(.width, to: loaderSize) | ||
|  |         loader.set(.height, to: loaderSize) | ||
|  |         loader.center(in: self) | ||
| 
											5 years ago
										 |     } | ||
| 
											5 years ago
										 | 
 | ||
|  |     // MARK: Updating | ||
|  |     private func update() { | ||
| 
											5 years ago
										 |         cancelButton.removeFromSuperview() | ||
| 
											5 years ago
										 |         guard let linkPreviewState = linkPreviewState else { return } | ||
| 
											5 years ago
										 |         var image = linkPreviewState.image() | ||
|  |         if image == nil && (linkPreviewState is LinkPreviewDraft || linkPreviewState is LinkPreviewSent) { | ||
|  |             image = UIImage(named: "Link")?.withTint(isLightMode ? .black : .white) | ||
|  |         } | ||
| 
											5 years ago
										 |         // Image view | ||
| 
											5 years ago
										 |         let imageViewContainerSize: CGFloat = (linkPreviewState is LinkPreviewSent) ? 100 : 80 | ||
|  |         imageViewContainerWidthConstraint.constant = imageViewContainerSize | ||
|  |         imageViewContainerHeightConstraint.constant = imageViewContainerSize | ||
|  |         imageViewContainer.layer.cornerRadius = (linkPreviewState is LinkPreviewSent) ? 0 : 8 | ||
|  |         if linkPreviewState is LinkPreviewLoading { | ||
|  |             imageViewContainer.backgroundColor = .clear | ||
|  |         } else { | ||
|  |             imageViewContainer.backgroundColor = isDarkMode ? .black : UIColor.black.withAlphaComponent(0.06) | ||
|  |         } | ||
| 
											5 years ago
										 |         imageView.image = image | ||
|  |         imageView.contentMode = (linkPreviewState.image() == nil) ? .center : .scaleAspectFill | ||
| 
											5 years ago
										 |         // Loader | ||
| 
											5 years ago
										 |         loader.alpha = (image != nil) ? 0 : 1 | ||
|  |         if image != nil { loader.stopAnimating() } else { loader.startAnimating() } | ||
| 
											5 years ago
										 |         // Title | ||
| 
											5 years ago
										 |         let isSent = (linkPreviewState is LinkPreviewSent) | ||
|  |         let isOutgoing = (viewItem?.interaction.interactionType() == .outgoingMessage) | ||
|  |         let textColor: UIColor | ||
|  |         if isSent && isOutgoing && isLightMode { | ||
|  |             textColor = .white | ||
|  |         } else { | ||
|  |             textColor = isDarkMode ? .white : .black | ||
| 
											5 years ago
										 |         } | ||
| 
											5 years ago
										 |         titleLabel.textColor = textColor | ||
| 
											5 years ago
										 |         titleLabel.text = linkPreviewState.title() | ||
| 
											5 years ago
										 |         // Horizontal stack view | ||
|  |         switch linkPreviewState { | ||
|  |         case is LinkPreviewSent: hStackViewContainer.backgroundColor = isDarkMode ? .black : UIColor.black.withAlphaComponent(0.06) | ||
|  |         default: hStackViewContainer.backgroundColor = nil | ||
|  |         } | ||
| 
											5 years ago
										 |         // Body text view | ||
|  |         bodyTextViewContainer.subviews.forEach { $0.removeFromSuperview() } | ||
|  |         if let viewItem = viewItem { | ||
| 
											5 years ago
										 |             let bodyTextView = VisibleMessageCell.getBodyTextView(for: viewItem, with: maxWidth, textColor: sentLinkPreviewTextColor, searchText: delegate.lastSearchedText, delegate: delegate) | ||
| 
											5 years ago
										 |             bodyTextViewContainer.addSubview(bodyTextView) | ||
|  |             bodyTextView.pin(to: bodyTextViewContainer, withInset: 12) | ||
|  |         } | ||
| 
											5 years ago
										 |         if linkPreviewState is LinkPreviewDraft { | ||
|  |             hStackView.addArrangedSubview(cancelButton) | ||
|  |         } | ||
|  |     } | ||
|  | 
 | ||
|  |     // MARK: Interaction | ||
|  |     @objc private func cancel() { | ||
|  |         delegate.handleLinkPreviewCanceled() | ||
| 
											5 years ago
										 |     } | ||
| 
											5 years ago
										 | } | ||
| 
											5 years ago
										 | 
 | ||
|  | // MARK: Delegate | ||
| 
											5 years ago
										 | protocol LinkPreviewViewDelegate : UITextViewDelegate & BodyTextViewDelegate { | ||
| 
											5 years ago
										 |     var lastSearchedText: String? { get } | ||
| 
											5 years ago
										 | 
 | ||
|  |     func handleLinkPreviewCanceled() | ||
|  | } |