mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-11-28 19:05:49 +00:00
Integrating streaming video into basic sheet
This commit is contained in:
parent
21e432bc0c
commit
a9ed9202a6
@ -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
|
||||
|
||||
@ -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 {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user