diff --git a/Signal/Images.xcassets/audio_pause_white_large.imageset/Contents.json b/Signal/Images.xcassets/audio_pause_white_large.imageset/Contents.json new file mode 100644 index 000000000..ae1d595fd --- /dev/null +++ b/Signal/Images.xcassets/audio_pause_white_large.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "audio_pause_white_large@1x.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "audio_pause_white_large@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "audio_pause_white_large@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Signal/Images.xcassets/audio_pause_white_large.imageset/audio_pause_white_large@1x.png b/Signal/Images.xcassets/audio_pause_white_large.imageset/audio_pause_white_large@1x.png new file mode 100644 index 000000000..4539bc0c1 Binary files /dev/null and b/Signal/Images.xcassets/audio_pause_white_large.imageset/audio_pause_white_large@1x.png differ diff --git a/Signal/Images.xcassets/audio_pause_white_large.imageset/audio_pause_white_large@2x.png b/Signal/Images.xcassets/audio_pause_white_large.imageset/audio_pause_white_large@2x.png new file mode 100644 index 000000000..27c7a8376 Binary files /dev/null and b/Signal/Images.xcassets/audio_pause_white_large.imageset/audio_pause_white_large@2x.png differ diff --git a/Signal/Images.xcassets/audio_pause_white_large.imageset/audio_pause_white_large@3x.png b/Signal/Images.xcassets/audio_pause_white_large.imageset/audio_pause_white_large@3x.png new file mode 100644 index 000000000..abdc8097e Binary files /dev/null and b/Signal/Images.xcassets/audio_pause_white_large.imageset/audio_pause_white_large@3x.png differ diff --git a/Signal/Images.xcassets/audio_play_white_large.imageset/Contents.json b/Signal/Images.xcassets/audio_play_white_large.imageset/Contents.json new file mode 100644 index 000000000..349353a52 --- /dev/null +++ b/Signal/Images.xcassets/audio_play_white_large.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "audio_play_white_large@1x.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "audio_play_white_large@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "audio_play_white_large@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Signal/Images.xcassets/audio_play_white_large.imageset/audio_play_white_large@1x.png b/Signal/Images.xcassets/audio_play_white_large.imageset/audio_play_white_large@1x.png new file mode 100644 index 000000000..af18c795e Binary files /dev/null and b/Signal/Images.xcassets/audio_play_white_large.imageset/audio_play_white_large@1x.png differ diff --git a/Signal/Images.xcassets/audio_play_white_large.imageset/audio_play_white_large@2x.png b/Signal/Images.xcassets/audio_play_white_large.imageset/audio_play_white_large@2x.png new file mode 100644 index 000000000..c14e50fd0 Binary files /dev/null and b/Signal/Images.xcassets/audio_play_white_large.imageset/audio_play_white_large@2x.png differ diff --git a/Signal/Images.xcassets/audio_play_white_large.imageset/audio_play_white_large@3x.png b/Signal/Images.xcassets/audio_play_white_large.imageset/audio_play_white_large@3x.png new file mode 100644 index 000000000..da1178b12 Binary files /dev/null and b/Signal/Images.xcassets/audio_play_white_large.imageset/audio_play_white_large@3x.png differ diff --git a/Signal/src/Signal-Bridging-Header.h b/Signal/src/Signal-Bridging-Header.h index ea74aff40..dce5e82ca 100644 --- a/Signal/src/Signal-Bridging-Header.h +++ b/Signal/src/Signal-Bridging-Header.h @@ -10,6 +10,7 @@ #import "FLAnimatedImage.h" #import "NotificationsManager.h" #import "OWSAnyTouchGestureRecognizer.h" +#import "OWSAudioAttachmentPlayer.h" #import "OWSCallNotificationsAdaptee.h" #import "OWSContactAvatarBuilder.h" #import "OWSContactsManager.h" diff --git a/Signal/src/ViewControllers/AttachmentApprovalViewController.swift b/Signal/src/ViewControllers/AttachmentApprovalViewController.swift index 1e6e536e1..c8b7d464c 100644 --- a/Signal/src/ViewControllers/AttachmentApprovalViewController.swift +++ b/Signal/src/ViewControllers/AttachmentApprovalViewController.swift @@ -5,7 +5,7 @@ import Foundation import MediaPlayer -class AttachmentApprovalViewController: UIViewController { +class AttachmentApprovalViewController: UIViewController, OWSAudioAttachmentPlayerDelegate { let TAG = "[AttachmentApprovalViewController]" @@ -17,6 +17,11 @@ class AttachmentApprovalViewController: UIViewController { var videoPlayer: MPMoviePlayerController? + var audioPlayer: OWSAudioAttachmentPlayer? + var audioPlayButton: UIButton? + var isAudioPlayingFlag = false + var isAudioPaused = false + // MARK: Initializers @available(*, unavailable, message:"use attachment: constructor instead.") @@ -89,9 +94,63 @@ class AttachmentApprovalViewController: UIViewController { } } + private func wrapViewsInVerticalStack(subviews: [UIView]) -> UIView { + assert(subviews.count > 0) + + let stackView = UIView() + + var lastView: UIView? + for subview in subviews { + + stackView.addSubview(subview) + subview.autoHCenterInSuperview() + + if lastView == nil { + subview.autoPinEdge(toSuperviewEdge:.top) + } else { + subview.autoPinEdge(.top, to:.bottom, of:lastView!, withOffset:10) + } + + lastView = subview + } + + lastView?.autoPinEdge(toSuperviewEdge:.bottom) + + return stackView + } + private func createAudioPreview(attachmentPreviewView: UIView) { - // TODO: Add audio player. - createGenericPreview(attachmentPreviewView:attachmentPreviewView) + guard let dataUrl = attachment.getTemporaryDataUrl() else { + createGenericPreview(attachmentPreviewView:attachmentPreviewView) + return + } + + audioPlayer = OWSAudioAttachmentPlayer(mediaUrl: dataUrl, delegate: self) + + var subviews = [UIView]() + + let audioPlayButton = UIButton() + self.audioPlayButton = audioPlayButton + setAudioIconToPlay() + audioPlayButton.imageView?.layer.minificationFilter = kCAFilterTrilinear + audioPlayButton.imageView?.layer.magnificationFilter = kCAFilterTrilinear + audioPlayButton.addTarget(self, action:#selector(audioPlayButtonPressed), for:.touchUpInside) + let buttonSize = createHeroViewSize() + audioPlayButton.autoSetDimension(.width, toSize:buttonSize) + audioPlayButton.autoSetDimension(.height, toSize:buttonSize) + subviews.append(audioPlayButton) + + if let fileExtensionLabel = createFileExtensionLabel() { + subviews.append(fileExtensionLabel) + } + + let fileSizeLabel = createFileSizeLabel() + subviews.append(fileSizeLabel) + + let stackView = wrapViewsInVerticalStack(subviews:subviews) + attachmentPreviewView.addSubview(stackView) + stackView.autoPinWidthToSuperview() + stackView.autoVCenterInSuperview() } private func createAnimatedPreview(attachmentPreviewView: UIView) { @@ -148,42 +207,63 @@ class AttachmentApprovalViewController: UIViewController { } private func createGenericPreview(attachmentPreviewView: UIView) { - let stackView = UIView() + var subviews = [UIView]() + + let imageView = createHeroImageView(imageName: "file-icon-large") + subviews.append(imageView) + + if let fileExtensionLabel = createFileExtensionLabel() { + subviews.append(fileExtensionLabel) + } + + let fileSizeLabel = createFileSizeLabel() + subviews.append(fileSizeLabel) + + let stackView = wrapViewsInVerticalStack(subviews:subviews) attachmentPreviewView.addSubview(stackView) - stackView.autoCenterInSuperview() + stackView.autoPinWidthToSuperview() + stackView.autoVCenterInSuperview() + } + + private func createHeroViewSize() -> CGFloat { + return ScaleFromIPhone5To7Plus(175, 225) + } - let imageSize = ScaleFromIPhone5To7Plus(175, 225) - let image = UIImage(named:"file-icon-large") + private func createHeroImageView(imageName: String) -> UIView { + let imageSize = createHeroViewSize() + let image = UIImage(named:imageName) 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 + return imageView + } - let labelFont = UIFont.ows_regularFont(withSize:ScaleFromIPhone5To7Plus(18, 24)) + private func labelFont() -> UIFont { + return 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) + private func createFileExtensionLabel() -> UIView? { + guard let fileExtension = attachment.fileExtension else { + return nil + } - fileExtensionLabel.textColor = UIColor.white - fileExtensionLabel.font = labelFont - fileExtensionLabel.textAlignment = .center - stackView.addSubview(fileExtensionLabel) - fileExtensionLabel.autoHCenterInSuperview() - fileExtensionLabel.autoPinEdge(.top, to:.bottom, of:lastView, withOffset:10) + 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) - lastView = fileExtensionLabel - } + fileExtensionLabel.textColor = UIColor.white + fileExtensionLabel.font = labelFont() + fileExtensionLabel.textAlignment = .center + return fileExtensionLabel + } + + private func createFileSizeLabel() -> UIView { let numberFormatter = NumberFormatter() numberFormatter.numberStyle = NumberFormatter.Style.decimal let fileSizeLabel = UILabel() @@ -200,12 +280,10 @@ class AttachmentApprovalViewController: UIViewController { fileSizeText) fileSizeLabel.textColor = UIColor.white - fileSizeLabel.font = labelFont + fileSizeLabel.font = labelFont() fileSizeLabel.textAlignment = .center - stackView.addSubview(fileSizeLabel) - fileSizeLabel.autoHCenterInSuperview() - fileSizeLabel.autoPinEdge(.top, to:.bottom, of:lastView, withOffset:10) - fileSizeLabel.autoPinEdge(toSuperviewEdge:.bottom) + + return fileSizeLabel } private func createButtonRow(attachmentPreviewView: UIView) { @@ -282,4 +360,42 @@ class AttachmentApprovalViewController: UIViewController { successCompletion?() }) } + + func audioPlayButtonPressed(sender: UIButton) { + audioPlayer?.togglePlayState() + } + + // MARK: - OWSAudioAttachmentPlayerDelegate + + public func isAudioPlaying() -> Bool { + return isAudioPlayingFlag + } + + public func setIsAudioPlaying(_ isAudioPlaying: Bool) { + isAudioPlayingFlag = isAudioPlaying + } + + public func isPaused() -> Bool { + return isAudioPaused + } + + public func setIsPaused(_ isPaused: Bool) { + isAudioPaused = isPaused + } + + public func setAudioProgressFrom(_ progress: Float) { + // Ignore + } + + public func setAudioIconToPlay() { + let image = UIImage(named:"audio_play_white_large") + assert(image != nil) + audioPlayButton?.setImage(image, for:.normal) + } + + public func setAudioIconToPause() { + let image = UIImage(named:"audio_pause_white_large") + assert(image != nil) + audioPlayButton?.setImage(image, for:.normal) + } }