@ -5,6 +5,7 @@
import Foundation
import MediaPlayer
import YYImage
import NVActivityIndicatorView
import SessionUIKit
@ -52,6 +53,8 @@ public class MediaMessageView: UIView, OWSAudioPlayerDelegate {
@objc
public var contentView : UIView ?
private var linkPreviewInfo : ( url : String , draft : OWSLinkPreviewDraft ? ) ?
// MARK: I n i t i a l i z e r s
@ -89,6 +92,10 @@ public class MediaMessageView: UIView, OWSAudioPlayerDelegate {
createVideoPreview ( )
} else if attachment . isAudio {
createAudioPreview ( )
} else if attachment . isUrl {
createUrlPreview ( )
} else if attachment . isText {
// D o n o t h i n g a s w e w i l l j u s t p u t t h e t e x t i n t h e ' m e s s a g e ' i n p u t
} else {
createGenericPreview ( )
}
@ -118,6 +125,31 @@ public class MediaMessageView: UIView, OWSAudioPlayerDelegate {
return stackView
}
private func wrapViewsInHorizontalStack ( subviews : [ UIView ] ) -> UIView {
assert ( subviews . count > 0 )
let stackView = UIView ( )
var lastView : UIView ?
for subview in subviews {
stackView . addSubview ( subview )
subview . autoVCenterInSuperview ( )
if lastView = = nil {
subview . autoPinEdge ( toSuperviewEdge : . left )
} else {
subview . autoPinEdge ( . left , to : . right , of : lastView ! , withOffset : stackSpacing ( ) )
}
lastView = subview
}
lastView ? . autoPinEdge ( toSuperviewEdge : . right )
return stackView
}
private func stackSpacing ( ) -> CGFloat {
switch mode {
@ -265,6 +297,120 @@ public class MediaMessageView: UIView, OWSAudioPlayerDelegate {
videoPlayButton . autoSetDimension ( . height , toSize : 72 )
}
}
private func createUrlPreview ( ) {
// I f l i n k p r e v i e w s a r e n ' t e n a b l e d t h e n u s e a f a l l b a c k s t a t e
guard let linkPreviewURL : String = OWSLinkPreview . previewURL ( forRawBodyText : attachment . text ( ) ) else {
createGenericPreview ( )
return
}
linkPreviewInfo = ( url : linkPreviewURL , draft : nil )
var subviews = [ UIView ] ( )
let color : UIColor = isLightMode ? . black : . white
let loadingView = NVActivityIndicatorView ( frame : CGRect . zero , type : . circleStrokeSpin , color : color , padding : nil )
loadingView . set ( . width , to : 24 )
loadingView . set ( . height , to : 24 )
loadingView . startAnimating ( )
subviews . append ( loadingView )
let imageViewContainer = UIView ( )
imageViewContainer . clipsToBounds = true
imageViewContainer . contentMode = . center
imageViewContainer . alpha = 0
imageViewContainer . layer . cornerRadius = 8
subviews . append ( imageViewContainer )
let imageView = createHeroImageView ( imageName : " FileLarge " )
imageViewContainer . addSubview ( imageView )
imageView . pin ( to : imageViewContainer )
let titleLabel = UILabel ( )
titleLabel . text = linkPreviewURL
titleLabel . textColor = controlTintColor
titleLabel . font = labelFont ( )
titleLabel . textAlignment = . center
titleLabel . lineBreakMode = . byTruncatingMiddle
subviews . append ( titleLabel )
let stackView = wrapViewsInVerticalStack ( subviews : subviews )
self . addSubview ( stackView )
titleLabel . autoPinWidthToSuperview ( withMargin : 32 )
NSLayoutConstraint . activate ( [
imageView . widthAnchor . constraint ( equalToConstant : 80 ) ,
imageView . heightAnchor . constraint ( equalToConstant : 80 )
] )
// B u i l d t h e l i n k p r e v i e w
OWSLinkPreview . tryToBuildPreviewInfo ( previewUrl : linkPreviewURL ) . done { [ weak self ] draft in
// L o a d e r
loadingView . alpha = 0
loadingView . stopAnimating ( )
self ? . linkPreviewInfo = ( url : linkPreviewURL , draft : draft )
// TODO: L o o k a t r e f a c t o r i n g t h i s b e h a v i o u r t o c o n s o l i d a t e a t t a c h m e n t m u t a t i o n s
self ? . attachment . linkPreviewDraft = draft
let image : UIImage ?
if let jpegImageData : Data = draft . jpegImageData , let loadedImage : UIImage = UIImage ( data : jpegImageData ) {
image = loadedImage
imageView . contentMode = . scaleAspectFill
}
else {
image = UIImage ( named : " Link " ) ? . withTint ( isLightMode ? . black : . white )
imageView . contentMode = . center
}
// I m a g e v i e w
( imageView as ? UIImageView ) ? . image = image
imageViewContainer . alpha = 1
imageViewContainer . backgroundColor = isDarkMode ? . black : UIColor . black . withAlphaComponent ( 0.06 )
// T i t l e
if let title = draft . title {
titleLabel . font = . boldSystemFont ( ofSize : Values . smallFontSize )
titleLabel . text = title
titleLabel . textAlignment = . left
titleLabel . numberOfLines = 2
}
guard let hStackView = self ? . wrapViewsInHorizontalStack ( subviews : subviews ) else {
// TODO: F a l l b a c k
return
}
stackView . removeFromSuperview ( )
self ? . addSubview ( hStackView )
// W e w a n t t o c e n t e r t h e s t a c k V i e w i n i t ' s s u p e r v i e w w h i l e a l s o e n s u r i n g
// i t ' s s u p e r v i e w i s b i g e n o u g h t o c o n t a i n i t .
hStackView . autoPinWidthToSuperview ( withMargin : 32 )
hStackView . autoVCenterInSuperview ( )
NSLayoutConstraint . autoSetPriority ( UILayoutPriority . defaultLow ) {
hStackView . autoPinHeightToSuperview ( )
}
hStackView . autoPinEdge ( toSuperviewEdge : . top , withInset : 0 , relation : . greaterThanOrEqual )
hStackView . autoPinEdge ( toSuperviewEdge : . bottom , withInset : 0 , relation : . greaterThanOrEqual )
} . catch { _ in
// TODO: F a l l b a c k
loadingView . stopAnimating ( )
} . retainUntilComplete ( )
// W e w a n t t o c e n t e r t h e s t a c k V i e w i n i t ' s s u p e r v i e w w h i l e a l s o e n s u r i n g
// i t ' s s u p e r v i e w i s b i g e n o u g h t o c o n t a i n i t .
stackView . autoPinWidthToSuperview ( )
stackView . autoVCenterInSuperview ( )
NSLayoutConstraint . autoSetPriority ( UILayoutPriority . defaultLow ) {
stackView . autoPinHeightToSuperview ( )
}
stackView . autoPinEdge ( toSuperviewEdge : . top , withInset : 0 , relation : . greaterThanOrEqual )
stackView . autoPinEdge ( toSuperviewEdge : . bottom , withInset : 0 , relation : . greaterThanOrEqual )
}
private func createGenericPreview ( ) {
var subviews = [ UIView ] ( )