|
|
|
//
|
|
|
|
// Copyright (c) 2017 Open Whisper Systems. All rights reserved.
|
|
|
|
//
|
|
|
|
|
|
|
|
import Foundation
|
|
|
|
import MediaPlayer
|
|
|
|
|
|
|
|
class AttachmentApprovalViewController: UIViewController {
|
|
|
|
|
|
|
|
let TAG = "[AttachmentApprovalViewController]"
|
|
|
|
|
|
|
|
// MARK: Properties
|
|
|
|
|
|
|
|
let attachment: SignalAttachment
|
|
|
|
|
|
|
|
var successCompletion : (() -> Void)?
|
|
|
|
|
|
|
|
var videoPlayer: MPMoviePlayerController?
|
|
|
|
|
|
|
|
// MARK: Initializers
|
|
|
|
|
|
|
|
@available(*, unavailable, message:"use attachment: constructor instead.")
|
|
|
|
required init?(coder aDecoder: NSCoder) {
|
|
|
|
self.attachment = SignalAttachment.genericAttachment(data: nil,
|
|
|
|
dataUTI: kUTTypeContent as String)
|
|
|
|
super.init(coder: aDecoder)
|
|
|
|
assertionFailure()
|
|
|
|
}
|
|
|
|
|
|
|
|
required init(attachment: SignalAttachment, successCompletion : @escaping () -> Void) {
|
|
|
|
assert(!attachment.hasError)
|
|
|
|
self.attachment = attachment
|
|
|
|
self.successCompletion = successCompletion
|
|
|
|
super.init(nibName: nil, bundle: nil)
|
|
|
|
}
|
|
|
|
|
|
|
|
// MARK: View Lifecycle
|
|
|
|
|
|
|
|
override func viewDidLoad() {
|
|
|
|
super.viewDidLoad()
|
|
|
|
|
|
|
|
view.backgroundColor = UIColor.black
|
|
|
|
|
|
|
|
self.navigationItem.leftBarButtonItem = UIBarButtonItem(barButtonSystemItem:.stop,
|
|
|
|
target:self,
|
|
|
|
action:#selector(donePressed))
|
|
|
|
self.navigationItem.title = NSLocalizedString("ATTACHMENT_APPROVAL_DIALOG_TITLE",
|
|
|
|
comment: "Title for the 'attachment approval' dialog.")
|
|
|
|
|
|
|
|
createViews()
|
|
|
|
}
|
|
|
|
|
|
|
|
// MARK: - Create Views
|
|
|
|
|
|
|
|
private func createViews() {
|
|
|
|
let previewTopMargin: CGFloat = 30
|
|
|
|
let previewHMargin: CGFloat = 20
|
|
|
|
|
|
|
|
let attachmentPreviewView = UIView()
|
|
|
|
self.view.addSubview(attachmentPreviewView)
|
|
|
|
attachmentPreviewView.autoPinWidthToSuperview(withMargin:previewHMargin)
|
|
|
|
attachmentPreviewView.autoPin(toTopLayoutGuideOf: self, withInset:previewTopMargin)
|
|
|
|
|
|
|
|
createButtonRow(attachmentPreviewView:attachmentPreviewView)
|
|
|
|
|
|
|
|
if attachment.isAnimatedImage {
|
|
|
|
createAnimatedPreview(attachmentPreviewView:attachmentPreviewView)
|
|
|
|
} else if attachment.isImage {
|
|
|
|
createImagePreview(attachmentPreviewView:attachmentPreviewView)
|
|
|
|
} else if attachment.isVideo {
|
|
|
|
createVideoPreview(attachmentPreviewView:attachmentPreviewView)
|
|
|
|
} else {
|
|
|
|
createGenericPreview(attachmentPreviewView:attachmentPreviewView)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private func createAnimatedPreview(attachmentPreviewView: UIView) {
|
|
|
|
// Use Flipboard FLAnimatedImage library to display gifs
|
|
|
|
guard let animatedImage = FLAnimatedImage(gifData:attachment.data) else {
|
|
|
|
createGenericPreview(attachmentPreviewView:attachmentPreviewView)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
let animatedImageView = FLAnimatedImageView()
|
|
|
|
animatedImageView.animatedImage = animatedImage
|
|
|
|
animatedImageView.contentMode = .scaleAspectFit
|
|
|
|
attachmentPreviewView.addSubview(animatedImageView)
|
|
|
|
animatedImageView.autoPinWidthToSuperview()
|
|
|
|
animatedImageView.autoPinHeightToSuperview()
|
|
|
|
}
|
|
|
|
|
|
|
|
private func createImagePreview(attachmentPreviewView: UIView) {
|
|
|
|
var image = attachment.image
|
|
|
|
if image == nil {
|
|
|
|
image = UIImage(data:attachment.data)
|
|
|
|
}
|
|
|
|
guard image != nil else {
|
|
|
|
createGenericPreview(attachmentPreviewView:attachmentPreviewView)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
let imageView = UIImageView(image:image)
|
|
|
|
imageView.layer.minificationFilter = kCAFilterTrilinear
|
|
|
|
imageView.layer.magnificationFilter = kCAFilterTrilinear
|
|
|
|
imageView.contentMode = .scaleAspectFit
|
|
|
|
attachmentPreviewView.addSubview(imageView)
|
|
|
|
imageView.autoPinWidthToSuperview()
|
|
|
|
imageView.autoPinHeightToSuperview()
|
|
|
|
}
|
|
|
|
|
|
|
|
private func createVideoPreview(attachmentPreviewView: UIView) {
|
|
|
|
guard let dataUrl = attachment.getTemporaryDataUrl() else {
|
|
|
|
createGenericPreview(attachmentPreviewView:attachmentPreviewView)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
guard let videoPlayer = MPMoviePlayerController(contentURL:dataUrl) else {
|
|
|
|
createGenericPreview(attachmentPreviewView:attachmentPreviewView)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
videoPlayer.prepareToPlay()
|
|
|
|
|
|
|
|
videoPlayer.controlStyle = .default
|
|
|
|
videoPlayer.shouldAutoplay = false
|
|
|
|
|
|
|
|
attachmentPreviewView.addSubview(videoPlayer.view)
|
|
|
|
self.videoPlayer = videoPlayer
|
|
|
|
videoPlayer.view.autoPinWidthToSuperview()
|
|
|
|
videoPlayer.view.autoPinHeightToSuperview()
|
|
|
|
}
|
|
|
|
|
|
|
|
private func createGenericPreview(attachmentPreviewView: UIView) {
|
|
|
|
let stackView = UIView()
|
|
|
|
attachmentPreviewView.addSubview(stackView)
|
|
|
|
stackView.autoCenterInSuperview()
|
|
|
|
|
|
|
|
let imageSize = ScaleFromIPhone5To7Plus(175, 225)
|
|
|
|
let image = UIImage(named:"file-icon-large")
|
|
|
|
assert(image != nil)
|
|
|
|
let imageView = UIImageView(image:image)
|
|
|
|
imageView.layer.minificationFilter = kCAFilterTrilinear
|
|
|
|
imageView.layer.magnificationFilter = kCAFilterTrilinear
|
|
|
|
stackView.addSubview(imageView)
|
|
|
|
imageView.autoHCenterInSuperview()
|
|
|
|
imageView.autoPinEdge(toSuperviewEdge:.top)
|
|
|
|
imageView.autoSetDimension(.width, toSize:imageSize)
|
|
|
|
imageView.autoSetDimension(.height, toSize:imageSize)
|
|
|
|
|
|
|
|
var lastView: UIView = imageView
|
|
|
|
|
|
|
|
let labelFont = UIFont.ows_regularFont(withSize:ScaleFromIPhone5To7Plus(18, 24))
|
|
|
|
|
|
|
|
if let fileExtension = attachment.fileExtension {
|
|
|
|
let fileExtensionLabel = UILabel()
|
|
|
|
fileExtensionLabel.text = String(format:NSLocalizedString("ATTACHMENT_APPROVAL_FILE_EXTENSION_FORMAT",
|
|
|
|
comment: "Format string for file extension label in call interstitial view"),
|
|
|
|
fileExtension.capitalized)
|
|
|
|
|
|
|
|
fileExtensionLabel.textColor = UIColor.white
|
|
|
|
fileExtensionLabel.font = labelFont
|
|
|
|
fileExtensionLabel.textAlignment = .center
|
|
|
|
stackView.addSubview(fileExtensionLabel)
|
|
|
|
fileExtensionLabel.autoHCenterInSuperview()
|
|
|
|
fileExtensionLabel.autoPinEdge(.top, to:.bottom, of:lastView, withOffset:10)
|
|
|
|
|
|
|
|
lastView = fileExtensionLabel
|
|
|
|
}
|
|
|
|
|
|
|
|
let numberFormatter = NumberFormatter()
|
|
|
|
numberFormatter.numberStyle = NumberFormatter.Style.decimal
|
|
|
|
let fileSizeLabel = UILabel()
|
|
|
|
fileSizeLabel.text = String(format:NSLocalizedString("ATTACHMENT_APPROVAL_FILE_SIZE_FORMAT",
|
|
|
|
comment: "Format string for file size label in call interstitial view"),
|
|
|
|
numberFormatter.string(from: NSNumber(value: attachment.data.count))!)
|
|
|
|
|
|
|
|
fileSizeLabel.textColor = UIColor.white
|
|
|
|
fileSizeLabel.font = labelFont
|
|
|
|
fileSizeLabel.textAlignment = .center
|
|
|
|
stackView.addSubview(fileSizeLabel)
|
|
|
|
fileSizeLabel.autoHCenterInSuperview()
|
|
|
|
fileSizeLabel.autoPinEdge(.top, to:.bottom, of:lastView, withOffset:10)
|
|
|
|
fileSizeLabel.autoPinEdge(toSuperviewEdge:.bottom)
|
|
|
|
}
|
|
|
|
|
|
|
|
private func createButtonRow(attachmentPreviewView: UIView) {
|
|
|
|
let buttonTopMargin = ScaleFromIPhone5To7Plus(30, 40)
|
|
|
|
let buttonBottomMargin = ScaleFromIPhone5To7Plus(25, 40)
|
|
|
|
let buttonHSpacing = ScaleFromIPhone5To7Plus(20, 30)
|
|
|
|
|
|
|
|
let buttonRow = UIView()
|
|
|
|
self.view.addSubview(buttonRow)
|
|
|
|
buttonRow.autoPinWidthToSuperview()
|
|
|
|
buttonRow.autoPinEdge(toSuperviewEdge:.bottom, withInset:buttonBottomMargin)
|
|
|
|
buttonRow.autoPinEdge(.top, to:.bottom, of:attachmentPreviewView, withOffset:buttonTopMargin)
|
|
|
|
|
|
|
|
// We use this invisible subview to ensure that the buttons are centered
|
|
|
|
// horizontally.
|
|
|
|
let buttonSpacer = UIView()
|
|
|
|
buttonRow.addSubview(buttonSpacer)
|
|
|
|
// Vertical positioning of this view doesn't matter.
|
|
|
|
buttonSpacer.autoPinEdge(toSuperviewEdge:.top)
|
|
|
|
buttonSpacer.autoSetDimension(.width, toSize:buttonHSpacing)
|
|
|
|
buttonSpacer.autoHCenterInSuperview()
|
|
|
|
|
|
|
|
let cancelButton = createButton(title: NSLocalizedString("TXT_CANCEL_TITLE",
|
|
|
|
comment: ""),
|
|
|
|
color : UIColor(rgbHex:0xff3B30),
|
|
|
|
action: #selector(cancelPressed))
|
|
|
|
buttonRow.addSubview(cancelButton)
|
|
|
|
cancelButton.autoPinEdge(toSuperviewEdge:.top)
|
|
|
|
cancelButton.autoPinEdge(toSuperviewEdge:.bottom)
|
|
|
|
cancelButton.autoPinEdge(.right, to:.left, of:buttonSpacer)
|
|
|
|
|
|
|
|
let sendButton = createButton(title: NSLocalizedString("ATTACHMENT_APPROVAL_SEND_BUTTON",
|
|
|
|
comment: "Label for 'send' button in the 'attachment approval' dialog."),
|
|
|
|
color : UIColor(rgbHex:0x4CD964),
|
|
|
|
action: #selector(sendPressed))
|
|
|
|
buttonRow.addSubview(sendButton)
|
|
|
|
sendButton.autoPinEdge(toSuperviewEdge:.top)
|
|
|
|
sendButton.autoPinEdge(toSuperviewEdge:.bottom)
|
|
|
|
sendButton.autoPinEdge(.left, to:.right, of:buttonSpacer)
|
|
|
|
}
|
|
|
|
|
|
|
|
private func createButton(title: String, color: UIColor, action: Selector) -> UIButton {
|
|
|
|
let buttonFont = UIFont.ows_mediumFont(withSize:ScaleFromIPhone5To7Plus(18, 22))
|
|
|
|
let buttonCornerRadius = ScaleFromIPhone5To7Plus(4, 5)
|
|
|
|
let buttonWidth = ScaleFromIPhone5To7Plus(110, 140)
|
|
|
|
let buttonHeight = ScaleFromIPhone5To7Plus(35, 45)
|
|
|
|
|
|
|
|
let button = UIButton()
|
|
|
|
button.setTitle(title, for:.normal)
|
|
|
|
button.setTitleColor(UIColor.white, for:.normal)
|
|
|
|
button.titleLabel!.font = buttonFont
|
|
|
|
button.backgroundColor = color
|
|
|
|
button.layer.cornerRadius = buttonCornerRadius
|
|
|
|
button.clipsToBounds = true
|
|
|
|
button.addTarget(self, action:action, for:.touchUpInside)
|
|
|
|
button.autoSetDimension(.width, toSize:buttonWidth)
|
|
|
|
button.autoSetDimension(.height, toSize:buttonHeight)
|
|
|
|
return button
|
|
|
|
}
|
|
|
|
|
|
|
|
// MARK: - Event Handlers
|
|
|
|
|
|
|
|
func donePressed(sender: UIButton) {
|
|
|
|
dismiss(animated: true, completion:nil)
|
|
|
|
}
|
|
|
|
|
|
|
|
func cancelPressed(sender: UIButton) {
|
|
|
|
dismiss(animated: true, completion:nil)
|
|
|
|
}
|
|
|
|
|
|
|
|
func sendPressed(sender: UIButton) {
|
|
|
|
let successCompletion = self.successCompletion
|
|
|
|
dismiss(animated: true, completion: {
|
|
|
|
successCompletion?()
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|