mirror of
https://github.com/oxen-io/session-ios.git
synced 2023-12-13 21:30:14 +01:00
Play video inline in approval view
Previously we launched the MPMoviePlayerController // FREEBIE
This commit is contained in:
parent
0c6a42003f
commit
94d58b88b8
|
@ -247,7 +247,6 @@
|
|||
452D1EE81DCA90D100A57EC4 /* MesssagesBubblesSizeCalculatorTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 452D1EE71DCA90D100A57EC4 /* MesssagesBubblesSizeCalculatorTest.swift */; };
|
||||
452EA09E1EA7ABE00078744B /* AttachmentPointerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 452EA09D1EA7ABE00078744B /* AttachmentPointerView.swift */; };
|
||||
452ECA4D1E087E7200E2F016 /* MessageFetcherJob.swift in Sources */ = {isa = PBXBuildFile; fileRef = 452ECA4C1E087E7200E2F016 /* MessageFetcherJob.swift */; };
|
||||
453034AB200289F50018945D /* VideoPlayerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 453034AA200289F50018945D /* VideoPlayerView.swift */; };
|
||||
4535186B1FC635DD00210559 /* ShareViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4535186A1FC635DD00210559 /* ShareViewController.swift */; };
|
||||
4535186E1FC635DD00210559 /* MainInterface.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 4535186C1FC635DD00210559 /* MainInterface.storyboard */; };
|
||||
453518721FC635DD00210559 /* SignalShareExtension.appex in Embed App Extensions */ = {isa = PBXBuildFile; fileRef = 453518681FC635DD00210559 /* SignalShareExtension.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };
|
||||
|
@ -271,6 +270,7 @@
|
|||
455AC69E1F4F8B0300134004 /* ImageCacheTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 455AC69D1F4F8B0300134004 /* ImageCacheTest.swift */; };
|
||||
45638BDC1F3DD0D400128435 /* DebugUICalling.swift in Sources */ = {isa = PBXBuildFile; fileRef = 45638BDB1F3DD0D400128435 /* DebugUICalling.swift */; };
|
||||
45638BDF1F3DDB2200128435 /* MessageSender+Promise.swift in Sources */ = {isa = PBXBuildFile; fileRef = 45638BDE1F3DDB2200128435 /* MessageSender+Promise.swift */; };
|
||||
4565ED06200EA29900C46DBB /* VideoPlayerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 453034AA200289F50018945D /* VideoPlayerView.swift */; };
|
||||
45666F581D9B2880008FE134 /* OWSScrubbingLogFormatterTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 45666F571D9B2880008FE134 /* OWSScrubbingLogFormatterTest.m */; };
|
||||
456C38961DC7B882007536A7 /* PromiseKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 451DE9F11DC1585F00810E42 /* PromiseKit.framework */; };
|
||||
456F6E2F1E261D1000FD2210 /* PeerConnectionClientTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 456F6E2E1E261D1000FD2210 /* PeerConnectionClientTest.swift */; };
|
||||
|
@ -1571,6 +1571,7 @@
|
|||
34D913491F62D4A500722898 /* SignalAttachment.swift */,
|
||||
34CA1C281F7164F700E51C51 /* MediaMessageView.swift */,
|
||||
45BC829C1FD9C4B400011CF3 /* ShareViewDelegate.swift */,
|
||||
453034AA200289F50018945D /* VideoPlayerView.swift */,
|
||||
);
|
||||
path = attachments;
|
||||
sourceTree = "<group>";
|
||||
|
@ -1748,7 +1749,6 @@
|
|||
76EB052B18170B33006006FC /* Views */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
453034AA200289F50018945D /* VideoPlayerView.swift */,
|
||||
45E5A6981F61E6DD001E4A8A /* MarqueeLabel.swift */,
|
||||
452EA09D1EA7ABE00078744B /* AttachmentPointerView.swift */,
|
||||
34E3E5671EC4B19400495BAC /* AudioProgressView.swift */,
|
||||
|
@ -2795,6 +2795,7 @@
|
|||
454A965A1FD6017E008D2A0E /* SignalAttachment.swift in Sources */,
|
||||
454A965B1FD601BF008D2A0E /* MediaMessageView.swift in Sources */,
|
||||
45BC829D1FD9C4B400011CF3 /* ShareViewDelegate.swift in Sources */,
|
||||
4565ED06200EA29900C46DBB /* VideoPlayerView.swift in Sources */,
|
||||
3461295B1FD1D74C00532771 /* Environment.m in Sources */,
|
||||
346129D51FD20ADC00532771 /* UIViewController+OWS.m in Sources */,
|
||||
451F8A431FD714FE005CB9DA /* AvatarImageView.swift in Sources */,
|
||||
|
@ -2925,7 +2926,6 @@
|
|||
34B3F8771E8DF1700035BE1A /* ContactsPicker.swift in Sources */,
|
||||
45C0DC1B1E68FE9000E04C47 /* UIApplication+OWS.swift in Sources */,
|
||||
45638BDF1F3DDB2200128435 /* MessageSender+Promise.swift in Sources */,
|
||||
453034AB200289F50018945D /* VideoPlayerView.swift in Sources */,
|
||||
45FBC5C81DF8575700E9B410 /* CallKitCallManager.swift in Sources */,
|
||||
34B3F8911E8DF1710035BE1A /* ShowGroupMembersViewController.m in Sources */,
|
||||
4539B5861F79348F007141FF /* PushRegistrationManager.swift in Sources */,
|
||||
|
|
|
@ -332,7 +332,6 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
[playVideoButton autoCenterInSuperview];
|
||||
}
|
||||
|
||||
|
||||
// Don't show footer bar after tapping approval-view
|
||||
if (self.viewItem) {
|
||||
UIToolbar *footerBar = [UIToolbar new];
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
//
|
||||
|
||||
import Foundation
|
||||
import AVFoundation
|
||||
import MediaPlayer
|
||||
|
||||
@objc
|
||||
|
@ -12,7 +13,7 @@ public protocol AttachmentApprovalViewControllerDelegate: class {
|
|||
}
|
||||
|
||||
@objc
|
||||
public class AttachmentApprovalViewController: OWSViewController, CaptioningToolbarDelegate {
|
||||
public class AttachmentApprovalViewController: OWSViewController, CaptioningToolbarDelegate, PlayerProgressBarDelegate {
|
||||
|
||||
let TAG = "[AttachmentApprovalViewController]"
|
||||
weak var delegate: AttachmentApprovalViewControllerDelegate?
|
||||
|
@ -26,10 +27,13 @@ public class AttachmentApprovalViewController: OWSViewController, CaptioningTool
|
|||
// MARK: Properties
|
||||
|
||||
let attachment: SignalAttachment
|
||||
private var videoPlayer: AVPlayer?
|
||||
|
||||
private(set) var bottomToolbar: UIView!
|
||||
private(set) var mediaMessageView: MediaMessageView!
|
||||
private(set) var scrollView: UIScrollView!
|
||||
private(set) var contentContainer: UIView!
|
||||
private(set) var playVideoButton: UIView?
|
||||
|
||||
// MARK: Initializers
|
||||
|
||||
|
@ -97,10 +101,15 @@ public class AttachmentApprovalViewController: OWSViewController, CaptioningTool
|
|||
|
||||
self.mediaMessageView = MediaMessageView(attachment: attachment, mode: .attachmentApproval)
|
||||
|
||||
// Anything that should be shrunk when user pops keyboard lives in the contentContainer.
|
||||
let contentContainer = UIView()
|
||||
self.contentContainer = contentContainer
|
||||
view.addSubview(contentContainer)
|
||||
contentContainer.autoPinEdgesToSuperviewEdges()
|
||||
|
||||
// Scroll View - used to zoom/pan on images and video
|
||||
scrollView = UIScrollView()
|
||||
view.addSubview(scrollView)
|
||||
|
||||
contentContainer.addSubview(scrollView)
|
||||
scrollView.delegate = self
|
||||
scrollView.showsHorizontalScrollIndicator = false
|
||||
scrollView.showsVerticalScrollIndicator = false
|
||||
|
@ -139,23 +148,6 @@ public class AttachmentApprovalViewController: OWSViewController, CaptioningTool
|
|||
topGradient.autoSetDimension(.height, toSize: ScaleFromIPhone5(60))
|
||||
}
|
||||
|
||||
// Hide the play button embedded in the MediaView and replace it with our own.
|
||||
// This allows us to zoom in on the media view without zooming in on the button
|
||||
if attachment.isVideo {
|
||||
self.mediaMessageView.videoPlayButton?.isHidden = true
|
||||
let playButton = UIButton()
|
||||
playButton.accessibilityLabel = NSLocalizedString("PLAY_BUTTON_ACCESSABILITY_LABEL", comment: "accessability label for button to start media playback")
|
||||
playButton.setBackgroundImage(#imageLiteral(resourceName: "play_button"), for: .normal)
|
||||
playButton.contentMode = .scaleAspectFit
|
||||
|
||||
let playButtonWidth = ScaleFromIPhone5(70)
|
||||
playButton.autoSetDimensions(to: CGSize(width: playButtonWidth, height: playButtonWidth))
|
||||
self.view.addSubview(playButton)
|
||||
|
||||
playButton.addTarget(self, action: #selector(playButtonTapped), for: .touchUpInside)
|
||||
playButton.autoCenterInSuperview()
|
||||
}
|
||||
|
||||
// Top Toolbar
|
||||
let topToolbar = makeClearToolbar()
|
||||
|
||||
|
@ -173,6 +165,67 @@ public class AttachmentApprovalViewController: OWSViewController, CaptioningTool
|
|||
let captioningToolbar = CaptioningToolbar()
|
||||
captioningToolbar.captioningToolbarDelegate = self
|
||||
self.bottomToolbar = captioningToolbar
|
||||
|
||||
// Hide the play button embedded in the MediaView and replace it with our own.
|
||||
// This allows us to zoom in on the media view without zooming in on the button
|
||||
if attachment.isVideo {
|
||||
|
||||
if #available(iOS 9.0, *) {
|
||||
guard let videoURL = attachment.dataUrl else {
|
||||
owsFail("Missing videoURL")
|
||||
return
|
||||
}
|
||||
|
||||
let player = AVPlayer(url: videoURL)
|
||||
self.videoPlayer = player
|
||||
|
||||
NotificationCenter.default.addObserver(self,
|
||||
selector: #selector(playerItemDidPlayToCompletion(_:)),
|
||||
name: NSNotification.Name.AVPlayerItemDidPlayToEndTime,
|
||||
object: player.currentItem)
|
||||
|
||||
let playerView = VideoPlayerView()
|
||||
playerView.player = player
|
||||
self.mediaMessageView.addSubview(playerView)
|
||||
playerView.autoPinEdgesToSuperviewEdges()
|
||||
|
||||
let pauseGesture = UITapGestureRecognizer(target: self, action: #selector(didTapPlayerView(_:)))
|
||||
playerView.addGestureRecognizer(pauseGesture)
|
||||
|
||||
let progressBar = PlayerProgressBar()
|
||||
progressBar.player = player
|
||||
progressBar.delegate = self
|
||||
|
||||
// we don't want the progress bar to zoom during "pinch-to-zoom"
|
||||
// but we do want it to shrink with the media content when the user
|
||||
// pops the keyboard.
|
||||
contentContainer.addSubview(progressBar)
|
||||
|
||||
progressBar.autoPinEdge(.top, to: .bottom, of: topToolbar)
|
||||
progressBar.autoPinWidthToSuperview()
|
||||
progressBar.autoSetDimension(.height, toSize: 44)
|
||||
}
|
||||
|
||||
self.mediaMessageView.videoPlayButton?.isHidden = true
|
||||
let playButton = UIButton()
|
||||
self.playVideoButton = playButton
|
||||
playButton.accessibilityLabel = NSLocalizedString("PLAY_BUTTON_ACCESSABILITY_LABEL", comment: "accessability label for button to start media playback")
|
||||
playButton.setBackgroundImage(#imageLiteral(resourceName: "play_button"), for: .normal)
|
||||
playButton.contentMode = .scaleAspectFit
|
||||
|
||||
let playButtonWidth = ScaleFromIPhone5(70)
|
||||
playButton.autoSetDimensions(to: CGSize(width: playButtonWidth, height: playButtonWidth))
|
||||
self.contentContainer.addSubview(playButton)
|
||||
|
||||
playButton.addTarget(self, action: #selector(playButtonTapped), for: .touchUpInside)
|
||||
playButton.autoCenterInSuperview()
|
||||
}
|
||||
}
|
||||
|
||||
@available(iOS 9, *)
|
||||
public func didTapPlayerView(_ gestureRecognizer: UIGestureRecognizer) {
|
||||
assert(self.videoPlayer != nil)
|
||||
self.pauseVideo()
|
||||
}
|
||||
|
||||
override public var inputAccessoryView: UIView? {
|
||||
|
@ -202,8 +255,7 @@ public class AttachmentApprovalViewController: OWSViewController, CaptioningTool
|
|||
|
||||
@objc
|
||||
public func playButtonTapped() {
|
||||
// FIXME - use built in AVPlayer controls like MediaDetailViewController
|
||||
// mediaMessageView.playVideo()
|
||||
self.playVideo()
|
||||
}
|
||||
|
||||
func cancelPressed(sender: UIButton) {
|
||||
|
@ -228,6 +280,120 @@ public class AttachmentApprovalViewController: OWSViewController, CaptioningTool
|
|||
Logger.info("Changed height: \(newHeight)")
|
||||
}
|
||||
|
||||
// MARK: Video
|
||||
|
||||
private func playVideo() {
|
||||
Logger.info("\(TAG) in \(#function)")
|
||||
|
||||
if #available(iOS 9, *) {
|
||||
guard let videoPlayer = self.videoPlayer else {
|
||||
owsFail("\(TAG) video player was unexpectedly nil")
|
||||
return
|
||||
}
|
||||
|
||||
guard let playVideoButton = self.playVideoButton else {
|
||||
owsFail("\(TAG) playVideoButton was unexpectedly nil")
|
||||
return
|
||||
}
|
||||
UIView.animate(withDuration: 0.1) {
|
||||
playVideoButton.alpha = 0.0
|
||||
}
|
||||
|
||||
guard let item = videoPlayer.currentItem else {
|
||||
owsFail("\(TAG) video player item was unexpectedly nil")
|
||||
return
|
||||
}
|
||||
|
||||
if item.currentTime() == item.duration {
|
||||
// Rewind for repeated plays, but only if it previously played to end.
|
||||
videoPlayer.seek(to: kCMTimeZero)
|
||||
}
|
||||
|
||||
videoPlayer.play()
|
||||
} else {
|
||||
self.playLegacyVideo()
|
||||
}
|
||||
}
|
||||
|
||||
private func playLegacyVideo() {
|
||||
if #available(iOS 9, *) {
|
||||
owsFail("should only use legacy video on iOS8")
|
||||
}
|
||||
|
||||
guard let videoURL = self.attachment.dataUrl else {
|
||||
owsFail("videoURL was unexpectedly nil")
|
||||
return
|
||||
}
|
||||
|
||||
guard let playerVC = MPMoviePlayerViewController(contentURL: videoURL) else {
|
||||
owsFail("failed to init legacy video player")
|
||||
return
|
||||
}
|
||||
|
||||
self.present(playerVC, animated: true)
|
||||
}
|
||||
|
||||
@available(iOS 9, *)
|
||||
private func pauseVideo() {
|
||||
guard let videoPlayer = self.videoPlayer else {
|
||||
owsFail("\(TAG) video player was unexpectedly nil")
|
||||
return
|
||||
}
|
||||
|
||||
videoPlayer.pause()
|
||||
guard let playVideoButton = self.playVideoButton else {
|
||||
owsFail("\(TAG) playVideoButton was unexpectedly nil")
|
||||
return
|
||||
}
|
||||
UIView.animate(withDuration: 0.1) {
|
||||
playVideoButton.alpha = 1.0
|
||||
}
|
||||
}
|
||||
|
||||
@objc
|
||||
private func playerItemDidPlayToCompletion(_ notification: Notification) {
|
||||
guard let playVideoButton = self.playVideoButton else {
|
||||
owsFail("\(TAG) playVideoButton was unexpectedly nil")
|
||||
return
|
||||
}
|
||||
UIView.animate(withDuration: 0.1) {
|
||||
playVideoButton.alpha = 1.0
|
||||
}
|
||||
}
|
||||
|
||||
@available(iOS 9.0, *)
|
||||
public func playerProgressBarDidStartScrubbing(_ playerProgressBar: PlayerProgressBar) {
|
||||
// [self.videoPlayer pause];
|
||||
guard let videoPlayer = self.videoPlayer else {
|
||||
owsFail("\(TAG) video player was unexpectedly nil")
|
||||
return
|
||||
}
|
||||
videoPlayer.pause()
|
||||
}
|
||||
|
||||
@available(iOS 9.0, *)
|
||||
public func playerProgressBar(_ playerProgressBar: PlayerProgressBar, scrubbedToTime time: CMTime) {
|
||||
guard let videoPlayer = self.videoPlayer else {
|
||||
owsFail("\(TAG) video player was unexpectedly nil")
|
||||
return
|
||||
}
|
||||
|
||||
videoPlayer.seek(to: time)
|
||||
}
|
||||
|
||||
@available(iOS 9.0, *)
|
||||
public func playerProgressBar(_ playerProgressBar: PlayerProgressBar, didFinishScrubbingAtTime time: CMTime, shouldResumePlayback: Bool) {
|
||||
guard let videoPlayer = self.videoPlayer else {
|
||||
owsFail("\(TAG) video player was unexpectedly nil")
|
||||
return
|
||||
}
|
||||
|
||||
videoPlayer.seek(to: time)
|
||||
if (shouldResumePlayback) {
|
||||
videoPlayer.play()
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: Helpers
|
||||
|
||||
var isZoomable: Bool {
|
||||
|
@ -252,9 +418,9 @@ public class AttachmentApprovalViewController: OWSViewController, CaptioningTool
|
|||
|
||||
private func scaleAttachmentView(_ fit: AttachmentViewScale) {
|
||||
guard shouldAllowAttachmentViewResizing else {
|
||||
if self.scrollView.transform != CGAffineTransform.identity {
|
||||
if self.contentContainer.transform != CGAffineTransform.identity {
|
||||
UIView.animate(withDuration: 0.2) {
|
||||
self.scrollView.transform = CGAffineTransform.identity
|
||||
self.contentContainer.transform = CGAffineTransform.identity
|
||||
}
|
||||
}
|
||||
return
|
||||
|
@ -263,7 +429,7 @@ public class AttachmentApprovalViewController: OWSViewController, CaptioningTool
|
|||
switch fit {
|
||||
case .fullsize:
|
||||
UIView.animate(withDuration: 0.2) {
|
||||
self.scrollView.transform = CGAffineTransform.identity
|
||||
self.contentContainer.transform = CGAffineTransform.identity
|
||||
}
|
||||
case .compact:
|
||||
UIView.animate(withDuration: 0.2) {
|
||||
|
@ -277,7 +443,7 @@ public class AttachmentApprovalViewController: OWSViewController, CaptioningTool
|
|||
let heightDelta = originalHeight * (1 - kScaleFactor)
|
||||
let translate = CGAffineTransform(translationX: 0, y: -heightDelta / 2)
|
||||
|
||||
self.scrollView.transform = scale.concatenating(translate)
|
||||
self.contentContainer.transform = scale.concatenating(translate)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -32,9 +32,6 @@ public class MediaMessageView: UIView, OWSAudioAttachmentPlayerDelegate {
|
|||
@objc
|
||||
public let attachment: SignalAttachment
|
||||
|
||||
@objc
|
||||
public var videoPlayer: MPMoviePlayerController?
|
||||
|
||||
@objc
|
||||
public var audioPlayer: OWSAudioAttachmentPlayer?
|
||||
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
//
|
||||
|
||||
import Foundation
|
||||
import AVFoundation
|
||||
|
||||
@available(iOS 9.0, *)
|
||||
@objc
|
Loading…
Reference in a new issue