Integrating streaming video into basic sheet

This commit is contained in:
Ilya Yelagov 2022-11-25 22:18:54 +04:00
parent 21e432bc0c
commit a9ed9202a6
2 changed files with 83 additions and 18 deletions

View File

@ -517,7 +517,7 @@ private final class ToolbarComponent: CombinedComponent {
}
}
public final class MediaStreamComponent: CombinedComponent {
public final class _MediaStreamComponent: CombinedComponent {
struct OriginInfo: Equatable {
var title: String
var memberCount: Int
@ -531,7 +531,7 @@ public final class MediaStreamComponent: CombinedComponent {
self.call = call
}
public static func ==(lhs: MediaStreamComponent, rhs: MediaStreamComponent) -> Bool {
public static func ==(lhs: _MediaStreamComponent, rhs: _MediaStreamComponent) -> Bool {
if lhs.call !== rhs.call {
return false
}
@ -569,6 +569,9 @@ public final class MediaStreamComponent: CombinedComponent {
let deactivatePictureInPictureIfVisible = StoredActionSlot(Void.self)
// MARK: - Added
var videoHiddenForPip = false
init(call: PresentationGroupCallImpl) {
self.call = call
@ -711,6 +714,8 @@ public final class MediaStreamComponent: CombinedComponent {
let navigationBar = Child(NavigationBarComponent.self)
let toolbar = Child(ToolbarComponent.self)
let sheet = Child(StreamSheetComponent.self)
let activatePictureInPicture = StoredActionSlot(Action<Void>.self)
let deactivatePictureInPicture = StoredActionSlot(Void.self)
let moreButtonTag = GenericComponentViewTag()
@ -724,7 +729,7 @@ public final class MediaStreamComponent: CombinedComponent {
}
let background = background.update(
component: Rectangle(color: .black),
component: Rectangle(color: .black.withAlphaComponent(0.12)),
availableSize: context.availableSize,
transition: context.transition
)
@ -740,6 +745,8 @@ public final class MediaStreamComponent: CombinedComponent {
if controller.view.window == nil {
return
}
state.videoHiddenForPip = false
state.updated(transition: .easeInOut(duration: 3))
deactivatePictureInPicture.invoke(Void())
}
@ -759,7 +766,7 @@ public final class MediaStreamComponent: CombinedComponent {
}
call.accountContext.sharedContext.mainWindow?.inCallNavigate?()
// TODO: bring up sheet
completed()
},
pictureInPictureClosed: { [weak call] in
@ -770,8 +777,22 @@ public final class MediaStreamComponent: CombinedComponent {
transition: context.transition
)
let sheet = sheet.update(
component: StreamSheetComponent(
leftItem: AnyComponent(Button(
content: AnyComponent(Text(text: environment.strings.Common_Close, font: Font.regular(17.0), color: .white)),
action: { [weak call] in
let _ = call?.leave(terminateIfPossible: false)
})
)
),
availableSize: context.availableSize,
transition: context.transition
)
var navigationRightItems: [AnyComponentWithIdentity<Empty>] = []
if context.state.isPictureInPictureSupported, context.state.hasVideo {
let contextView = context.view
if /*true || context.state.isPictureInPictureSupported,*/ context.state.hasVideo {
navigationRightItems.append(AnyComponentWithIdentity(id: "pip", component: AnyComponent(Button(
content: AnyComponent(BundleIconComponent(
name: "Media Gallery/PictureInPictureButton",
@ -782,7 +803,15 @@ public final class MediaStreamComponent: CombinedComponent {
guard let controller = controller() as? MediaStreamComponentController else {
return
}
controller.dismiss(closing: false, manual: true)
state.videoHiddenForPip = true
UIView.animate(withDuration: 5, animations: {
contextView.alpha = 0
}, completion: { _ in
state.videoHiddenForPip = true
state.updateDismissOffset(value: 2000, interactive: false)
controller.dismiss(closing: false, manual: true)
contextView.alpha = 1
})
})
}
).minSize(CGSize(width: 44.0, height: 44.0)))))
@ -1115,6 +1144,7 @@ public final class MediaStreamComponent: CombinedComponent {
case let .updated(offset):
state.updateDismissOffset(value: offset.y, interactive: true)
case let .ended(velocity):
// TODO: Dismiss sheet depending on velocity
if abs(velocity.y) > 200.0 {
activatePictureInPicture.invoke(Action { [weak state] in
guard let state = state, let controller = controller() as? MediaStreamComponentController else {
@ -1130,6 +1160,13 @@ public final class MediaStreamComponent: CombinedComponent {
})
)
let sheetHeight: CGFloat = 300
let sheetOffset: CGFloat = context.availableSize.height - sheetHeight + context.state.dismissOffset
// TODO: work with sheet here
context.add(sheet
.position(.init(x: context.availableSize.width / 2.0, y: sheetOffset))
)
print("DismissOffset: \(context.state.dismissOffset)")
context.add(video
.position(CGPoint(x: context.availableSize.width / 2.0, y: context.availableSize.height / 2.0 + context.state.dismissOffset))
)
@ -1149,7 +1186,7 @@ public final class MediaStreamComponent: CombinedComponent {
}
}
public final class MediaStreamComponentController: ViewControllerComponentContainer, VoiceChatController {
public final class _MediaStreamComponentController: ViewControllerComponentContainer, VoiceChatController {
private let context: AccountContext
public let call: PresentationGroupCall
public private(set) var currentOverlayController: VoiceChatOverlayController? = nil
@ -1162,6 +1199,10 @@ public final class MediaStreamComponentController: ViewControllerComponentContai
private let inviteLinksPromise = Promise<GroupCallInviteLinks?>(nil)
public convenience init(sharedContext: SharedAccountContext, accountContext: AccountContext, call: PresentationGroupCall) {
self.init(call: call)
}
public init(call: PresentationGroupCall) {
self.context = call.accountContext
self.call = call
@ -1210,6 +1251,7 @@ public final class MediaStreamComponentController: ViewControllerComponentContai
}
strongSelf.view.layer.allowsGroupOpacity = false
})
// self.view.backgroundColor = .cyan
}
override public func viewDidDisappear(_ animated: Bool) {
@ -1377,3 +1419,5 @@ public final class MediaStreamComponentController: ViewControllerComponentContai
})
}
}
public typealias MediaStreamComponentController = _MediaStreamComponentController

View File

@ -7,7 +7,9 @@ import AVKit
import MultilineTextComponent
import Display
final class MediaStreamVideoComponent: Component {
typealias MediaStreamVideoComponent = _MediaStreamVideoComponent
final class _MediaStreamVideoComponent: Component {
let call: PresentationGroupCallImpl
let hasVideo: Bool
let isVisible: Bool
@ -40,7 +42,7 @@ final class MediaStreamVideoComponent: Component {
self.pictureInPictureClosed = pictureInPictureClosed
}
public static func ==(lhs: MediaStreamVideoComponent, rhs: MediaStreamVideoComponent) -> Bool {
public static func ==(lhs: _MediaStreamVideoComponent, rhs: _MediaStreamVideoComponent) -> Bool {
if lhs.call !== rhs.call {
return false
}
@ -70,7 +72,7 @@ final class MediaStreamVideoComponent: Component {
return State()
}
public final class View: UIScrollView, AVPictureInPictureControllerDelegate, ComponentTaggedView {
public final class View: UIView, AVPictureInPictureControllerDelegate, ComponentTaggedView {
public final class Tag {
}
@ -83,7 +85,7 @@ final class MediaStreamVideoComponent: Component {
private var pictureInPictureController: AVPictureInPictureController?
private var component: MediaStreamVideoComponent?
private var component: _MediaStreamVideoComponent?
private var hadVideo: Bool = false
private var requestedExpansion: Bool = false
@ -96,9 +98,9 @@ final class MediaStreamVideoComponent: Component {
override init(frame: CGRect) {
self.blurTintView = UIView()
self.blurTintView.backgroundColor = UIColor(white: 0.0, alpha: 0.55)
super.init(frame: frame)
// self.backgroundColor = UIColor.green.withAlphaComponent(0.4)
self.isUserInteractionEnabled = false
self.clipsToBounds = true
@ -123,10 +125,18 @@ final class MediaStreamVideoComponent: Component {
}
}
func update(component: MediaStreamVideoComponent, availableSize: CGSize, state: State, transition: Transition) -> CGSize {
// let sheetView = UIView()
// let sheetBackdropView = UIView()
// var sheetTop: CGFloat = 0
// var sheetHeight: CGFloat = 0
func update(component: _MediaStreamVideoComponent, availableSize: CGSize, state: State, transition: Transition) -> CGSize {
self.state = state
if component.hasVideo, self.videoView == nil {
// self.addSubview(sheetBackdropView)
// self.addSubview(sheetView)
if let input = component.call.video(endpointId: "unified") {
if let videoBlurView = self.videoRenderingContext.makeView(input: input, blur: true) {
self.videoBlurView = videoBlurView
@ -142,8 +152,7 @@ final class MediaStreamVideoComponent: Component {
if #available(iOS 13.0, *) {
sampleBufferVideoView.sampleBufferLayer.preventsDisplaySleepDuringVideoPlayback = true
}
if #available(iOSApplicationExtension 15.0, iOS 15.0, *), AVPictureInPictureController.isPictureInPictureSupported() {
// if #available(iOSApplicationExtension 15.0, iOS 15.0, *), AVPictureInPictureController.isPictureInPictureSupported() {
final class PlaybackDelegateImpl: NSObject, AVPictureInPictureSampleBufferPlaybackDelegate {
func pictureInPictureController(_ pictureInPictureController: AVPictureInPictureController, setPlaying playing: Bool) {
@ -168,15 +177,25 @@ final class MediaStreamVideoComponent: Component {
return false
}
}
let pictureInPictureController = AVPictureInPictureController(contentSource: AVPictureInPictureController.ContentSource(sampleBufferDisplayLayer: sampleBufferVideoView.sampleBufferLayer, playbackDelegate: PlaybackDelegateImpl()))
let pictureInPictureController: AVPictureInPictureController
if #available(iOS 15.0, *) {
pictureInPictureController = AVPictureInPictureController(contentSource: AVPictureInPictureController.ContentSource(sampleBufferDisplayLayer: sampleBufferVideoView.sampleBufferLayer, playbackDelegate: PlaybackDelegateImpl()))
} else {
// TODO: support PiP for iOS < 15.0
// sampleBufferVideoView.sampleBufferLayer
pictureInPictureController = AVPictureInPictureController.init(playerLayer: AVPlayerLayer(player: AVPlayer()))!
}
pictureInPictureController.delegate = self
if #available(iOS 14.2, *) {
pictureInPictureController.canStartPictureInPictureAutomaticallyFromInline = true
}
if #available(iOS 14.0, *) {
pictureInPictureController.requiresLinearPlayback = true
}
self.pictureInPictureController = pictureInPictureController
}
// }
}
videoView.setOnOrientationUpdated { [weak state] _, _ in
@ -207,6 +226,8 @@ final class MediaStreamVideoComponent: Component {
}
}
// sheetView.frame = .init(x: 0, y: sheetTop, width: availableSize.width, height: sheetHeight)
if let videoView = self.videoView {
var isVideoVisible = component.isVisible
if let pictureInPictureController = self.pictureInPictureController {