mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-06-16 05:55:20 +00:00
Various video call UI improvements
This commit is contained in:
parent
43abc10d7b
commit
b7ef9fdb3f
@ -112,7 +112,7 @@ public final class AuthDataTransferSplashScreen: ViewController {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
DeviceAccess.authorizeAccess(to: .camera, presentationData: strongSelf.presentationData, present: { c, a in
|
DeviceAccess.authorizeAccess(to: .camera(.video), presentationData: strongSelf.presentationData, present: { c, a in
|
||||||
guard let strongSelf = self else {
|
guard let strongSelf = self else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -15,6 +15,12 @@ import TelegramPresentationData
|
|||||||
import LegacyComponents
|
import LegacyComponents
|
||||||
import AccountContext
|
import AccountContext
|
||||||
|
|
||||||
|
public enum DeviceAccessCameraSubject {
|
||||||
|
case video
|
||||||
|
case videoCall
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
public enum DeviceAccessMicrophoneSubject {
|
public enum DeviceAccessMicrophoneSubject {
|
||||||
case audio
|
case audio
|
||||||
case video
|
case video
|
||||||
@ -34,7 +40,7 @@ public enum DeviceAccessLocationSubject {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public enum DeviceAccessSubject {
|
public enum DeviceAccessSubject {
|
||||||
case camera
|
case camera(DeviceAccessCameraSubject)
|
||||||
case microphone(DeviceAccessMicrophoneSubject)
|
case microphone(DeviceAccessMicrophoneSubject)
|
||||||
case mediaLibrary(DeviceAccessMediaLibrarySubject)
|
case mediaLibrary(DeviceAccessMediaLibrarySubject)
|
||||||
case location(DeviceAccessLocationSubject)
|
case location(DeviceAccessLocationSubject)
|
||||||
@ -246,14 +252,20 @@ public final class DeviceAccess {
|
|||||||
|
|
||||||
public static func authorizeAccess(to subject: DeviceAccessSubject, registerForNotifications: ((@escaping (Bool) -> Void) -> Void)? = nil, requestSiriAuthorization: ((@escaping (Bool) -> Void) -> Void)? = nil, locationManager: LocationManager? = nil, presentationData: PresentationData? = nil, present: @escaping (ViewController, Any?) -> Void = { _, _ in }, openSettings: @escaping () -> Void = { }, displayNotificationFromBackground: @escaping (String) -> Void = { _ in }, _ completion: @escaping (Bool) -> Void = { _ in }) {
|
public static func authorizeAccess(to subject: DeviceAccessSubject, registerForNotifications: ((@escaping (Bool) -> Void) -> Void)? = nil, requestSiriAuthorization: ((@escaping (Bool) -> Void) -> Void)? = nil, locationManager: LocationManager? = nil, presentationData: PresentationData? = nil, present: @escaping (ViewController, Any?) -> Void = { _, _ in }, openSettings: @escaping () -> Void = { }, displayNotificationFromBackground: @escaping (String) -> Void = { _ in }, _ completion: @escaping (Bool) -> Void = { _ in }) {
|
||||||
switch subject {
|
switch subject {
|
||||||
case .camera:
|
case let .camera(cameraSubject):
|
||||||
let status = PGCamera.cameraAuthorizationStatus()
|
let status = PGCamera.cameraAuthorizationStatus()
|
||||||
if status == PGCameraAuthorizationStatusNotDetermined {
|
if status == PGCameraAuthorizationStatusNotDetermined {
|
||||||
AVCaptureDevice.requestAccess(for: AVMediaType.video) { response in
|
AVCaptureDevice.requestAccess(for: AVMediaType.video) { response in
|
||||||
Queue.mainQueue().async {
|
Queue.mainQueue().async {
|
||||||
completion(response)
|
completion(response)
|
||||||
if !response, let presentationData = presentationData {
|
if !response, let presentationData = presentationData {
|
||||||
let text = presentationData.strings.AccessDenied_Camera
|
let text: String
|
||||||
|
switch cameraSubject {
|
||||||
|
case .video:
|
||||||
|
text = presentationData.strings.AccessDenied_Camera
|
||||||
|
case .videoCall:
|
||||||
|
text = presentationData.strings.AccessDenied_VideoCallCamera
|
||||||
|
}
|
||||||
present(standardTextAlertController(theme: AlertControllerTheme(presentationData: presentationData), title: presentationData.strings.AccessDenied_Title, text: text, actions: [TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_NotNow, action: {}), TextAlertAction(type: .genericAction, title: presentationData.strings.AccessDenied_Settings, action: {
|
present(standardTextAlertController(theme: AlertControllerTheme(presentationData: presentationData), title: presentationData.strings.AccessDenied_Title, text: text, actions: [TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_NotNow, action: {}), TextAlertAction(type: .genericAction, title: presentationData.strings.AccessDenied_Settings, action: {
|
||||||
openSettings()
|
openSettings()
|
||||||
})]), nil)
|
})]), nil)
|
||||||
|
@ -127,7 +127,7 @@ public func legacyAttachmentMenu(context: AccountContext, peer: Peer, editMediaO
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
DeviceAccess.authorizeAccess(to: .camera, presentationData: context.sharedContext.currentPresentationData.with { $0 }, present: context.sharedContext.presentGlobalController, openSettings: context.sharedContext.applicationBindings.openSettings, { value in
|
DeviceAccess.authorizeAccess(to: .camera(.video), presentationData: context.sharedContext.currentPresentationData.with { $0 }, present: context.sharedContext.presentGlobalController, openSettings: context.sharedContext.applicationBindings.openSettings, { value in
|
||||||
if value {
|
if value {
|
||||||
openCamera(cameraView, controller)
|
openCamera(cameraView, controller)
|
||||||
}
|
}
|
||||||
|
@ -451,12 +451,14 @@ private final class SemanticStatusNodeTransitionDrawingState {
|
|||||||
private final class SemanticStatusNodeDrawingState: NSObject {
|
private final class SemanticStatusNodeDrawingState: NSObject {
|
||||||
let background: UIColor
|
let background: UIColor
|
||||||
let foreground: UIColor
|
let foreground: UIColor
|
||||||
|
let hollow: Bool
|
||||||
let transitionState: SemanticStatusNodeTransitionDrawingState?
|
let transitionState: SemanticStatusNodeTransitionDrawingState?
|
||||||
let drawingState: SemanticStatusNodeStateDrawingState
|
let drawingState: SemanticStatusNodeStateDrawingState
|
||||||
|
|
||||||
init(background: UIColor, foreground: UIColor, transitionState: SemanticStatusNodeTransitionDrawingState?, drawingState: SemanticStatusNodeStateDrawingState) {
|
init(background: UIColor, foreground: UIColor, hollow: Bool, transitionState: SemanticStatusNodeTransitionDrawingState?, drawingState: SemanticStatusNodeStateDrawingState) {
|
||||||
self.background = background
|
self.background = background
|
||||||
self.foreground = foreground
|
self.foreground = foreground
|
||||||
|
self.hollow = hollow
|
||||||
self.transitionState = transitionState
|
self.transitionState = transitionState
|
||||||
self.drawingState = drawingState
|
self.drawingState = drawingState
|
||||||
|
|
||||||
@ -495,6 +497,8 @@ public final class SemanticStatusNode: ASControlNode {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private let hollow: Bool
|
||||||
|
|
||||||
private var animator: ConstantDisplayLinkAnimator?
|
private var animator: ConstantDisplayLinkAnimator?
|
||||||
|
|
||||||
private var hasState: Bool = false
|
private var hasState: Bool = false
|
||||||
@ -502,9 +506,10 @@ public final class SemanticStatusNode: ASControlNode {
|
|||||||
private var transtionContext: SemanticStatusNodeTransitionContext?
|
private var transtionContext: SemanticStatusNodeTransitionContext?
|
||||||
private var stateContext: SemanticStatusNodeStateContext
|
private var stateContext: SemanticStatusNodeStateContext
|
||||||
|
|
||||||
public init(backgroundNodeColor: UIColor, foregroundNodeColor: UIColor) {
|
public init(backgroundNodeColor: UIColor, foregroundNodeColor: UIColor, hollow: Bool = false) {
|
||||||
self.backgroundNodeColor = backgroundNodeColor
|
self.backgroundNodeColor = backgroundNodeColor
|
||||||
self.foregroundNodeColor = foregroundNodeColor
|
self.foregroundNodeColor = foregroundNodeColor
|
||||||
|
self.hollow = hollow
|
||||||
self.state = .none
|
self.state = .none
|
||||||
self.stateContext = self.state.context(current: nil)
|
self.stateContext = self.state.context(current: nil)
|
||||||
|
|
||||||
@ -584,7 +589,7 @@ public final class SemanticStatusNode: ASControlNode {
|
|||||||
transitionState = SemanticStatusNodeTransitionDrawingState(transition: t, drawingState: transitionContext.previousStateContext.drawingState(transitionFraction: 1.0 - t))
|
transitionState = SemanticStatusNodeTransitionDrawingState(transition: t, drawingState: transitionContext.previousStateContext.drawingState(transitionFraction: 1.0 - t))
|
||||||
}
|
}
|
||||||
|
|
||||||
return SemanticStatusNodeDrawingState(background: self.backgroundNodeColor, foreground: self.foregroundNodeColor, transitionState: transitionState, drawingState: self.stateContext.drawingState(transitionFraction: transitionFraction))
|
return SemanticStatusNodeDrawingState(background: self.backgroundNodeColor, foreground: self.foregroundNodeColor, hollow: self.hollow, transitionState: transitionState, drawingState: self.stateContext.drawingState(transitionFraction: transitionFraction))
|
||||||
}
|
}
|
||||||
|
|
||||||
@objc override public class func draw(_ bounds: CGRect, withParameters parameters: Any?, isCancelled: () -> Bool, isRasterizing: Bool) {
|
@objc override public class func draw(_ bounds: CGRect, withParameters parameters: Any?, isCancelled: () -> Bool, isRasterizing: Bool) {
|
||||||
@ -606,5 +611,10 @@ public final class SemanticStatusNode: ASControlNode {
|
|||||||
transitionState.drawingState.draw(context: context, size: bounds.size, foregroundColor: parameters.foreground)
|
transitionState.drawingState.draw(context: context, size: bounds.size, foregroundColor: parameters.foreground)
|
||||||
}
|
}
|
||||||
parameters.drawingState.draw(context: context, size: bounds.size, foregroundColor: parameters.foreground)
|
parameters.drawingState.draw(context: context, size: bounds.size, foregroundColor: parameters.foreground)
|
||||||
|
|
||||||
|
if parameters.hollow {
|
||||||
|
context.setBlendMode(.clear)
|
||||||
|
context.fillEllipse(in: bounds.insetBy(dx: 7.0, dy: 7.0))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -13,6 +13,7 @@ import TelegramAudio
|
|||||||
import AccountContext
|
import AccountContext
|
||||||
import TelegramNotices
|
import TelegramNotices
|
||||||
import AppBundle
|
import AppBundle
|
||||||
|
import TooltipUI
|
||||||
|
|
||||||
protocol CallControllerNodeProtocol: class {
|
protocol CallControllerNodeProtocol: class {
|
||||||
var isMuted: Bool { get set }
|
var isMuted: Bool { get set }
|
||||||
@ -27,6 +28,7 @@ protocol CallControllerNodeProtocol: class {
|
|||||||
var present: ((ViewController) -> Void)? { get set }
|
var present: ((ViewController) -> Void)? { get set }
|
||||||
var callEnded: ((Bool) -> Void)? { get set }
|
var callEnded: ((Bool) -> Void)? { get set }
|
||||||
var dismissedInteractively: (() -> Void)? { get set }
|
var dismissedInteractively: (() -> Void)? { get set }
|
||||||
|
var dismissAllTooltips: (() -> Void)? { get set }
|
||||||
|
|
||||||
func updateAudioOutputs(availableOutputs: [AudioSessionOutput], currentOutput: AudioSessionOutput?)
|
func updateAudioOutputs(availableOutputs: [AudioSessionOutput], currentOutput: AudioSessionOutput?)
|
||||||
func updateCallState(_ callState: PresentationCallState)
|
func updateCallState(_ callState: PresentationCallState)
|
||||||
@ -255,6 +257,17 @@ public final class CallController: ViewController {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
self.controllerNode.dismissAllTooltips = { [weak self] in
|
||||||
|
if let strongSelf = self {
|
||||||
|
strongSelf.forEachController({ controller in
|
||||||
|
if let controller = controller as? TooltipScreen {
|
||||||
|
controller.dismiss()
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
self.controllerNode.callEnded = { [weak self] didPresentRating in
|
self.controllerNode.callEnded = { [weak self] didPresentRating in
|
||||||
if let strongSelf = self, !didPresentRating {
|
if let strongSelf = self, !didPresentRating {
|
||||||
let _ = (combineLatest(strongSelf.sharedContext.accountManager.sharedData(keys: [ApplicationSpecificSharedDataKeys.callListSettings]), ApplicationSpecificNotice.getCallsTabTip(accountManager: strongSelf.sharedContext.accountManager))
|
let _ = (combineLatest(strongSelf.sharedContext.accountManager.sharedData(keys: [ApplicationSpecificSharedDataKeys.callListSettings]), ApplicationSpecificNotice.getCallsTabTip(accountManager: strongSelf.sharedContext.accountManager))
|
||||||
|
@ -134,7 +134,7 @@ final class CallControllerButtonItemNode: HighlightTrackingButtonNode {
|
|||||||
|
|
||||||
if content.hasProgress {
|
if content.hasProgress {
|
||||||
if self.statusNode == nil {
|
if self.statusNode == nil {
|
||||||
let statusNode = SemanticStatusNode(backgroundNodeColor: .white, foregroundNodeColor: .clear)
|
let statusNode = SemanticStatusNode(backgroundNodeColor: .white, foregroundNodeColor: .clear, hollow: true)
|
||||||
self.statusNode = statusNode
|
self.statusNode = statusNode
|
||||||
self.contentContainer.insertSubnode(statusNode, belowSubnode: self.contentNode)
|
self.contentContainer.insertSubnode(statusNode, belowSubnode: self.contentNode)
|
||||||
statusNode.transitionToState(.progress(value: nil, cancelEnabled: false, appearance: SemanticStatusNodeState.ProgressAppearance(inset: 4.0, lineWidth: 3.0)), animated: false, completion: {})
|
statusNode.transitionToState(.progress(value: nil, cancelEnabled: false, appearance: SemanticStatusNodeState.ProgressAppearance(inset: 4.0, lineWidth: 3.0)), animated: false, completion: {})
|
||||||
@ -168,18 +168,19 @@ final class CallControllerButtonItemNode: HighlightTrackingButtonNode {
|
|||||||
let contentImage = generateImage(CGSize(width: self.largeButtonSize, height: self.largeButtonSize), contextGenerator: { size, context in
|
let contentImage = generateImage(CGSize(width: self.largeButtonSize, height: self.largeButtonSize), contextGenerator: { size, context in
|
||||||
context.clear(CGRect(origin: CGPoint(), size: size))
|
context.clear(CGRect(origin: CGPoint(), size: size))
|
||||||
|
|
||||||
|
var ellipseRect = CGRect(origin: CGPoint(), size: size)
|
||||||
var fillColor: UIColor = .clear
|
var fillColor: UIColor = .clear
|
||||||
var imageColor: UIColor = .white
|
let imageColor: UIColor = .white
|
||||||
var drawOverMask = false
|
var drawOverMask = false
|
||||||
context.setBlendMode(.normal)
|
context.setBlendMode(.normal)
|
||||||
var imageScale: CGFloat = 1.0
|
let imageScale: CGFloat = 1.0
|
||||||
switch content.appearance {
|
switch content.appearance {
|
||||||
case let .blurred(isFilled):
|
case let .blurred(isFilled):
|
||||||
if content.hasProgress {
|
if content.hasProgress {
|
||||||
fillColor = .clear
|
fillColor = .white
|
||||||
imageColor = .black
|
drawOverMask = true
|
||||||
drawOverMask = false
|
|
||||||
context.setBlendMode(.copy)
|
context.setBlendMode(.copy)
|
||||||
|
ellipseRect = ellipseRect.insetBy(dx: 7.0, dy: 7.0)
|
||||||
} else {
|
} else {
|
||||||
if isFilled {
|
if isFilled {
|
||||||
fillColor = .white
|
fillColor = .white
|
||||||
@ -187,8 +188,6 @@ final class CallControllerButtonItemNode: HighlightTrackingButtonNode {
|
|||||||
context.setBlendMode(.copy)
|
context.setBlendMode(.copy)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// let smallButtonSize: CGFloat = 60.0
|
|
||||||
// imageScale = self.largeButtonSize / smallButtonSize
|
|
||||||
case let .color(color):
|
case let .color(color):
|
||||||
switch color {
|
switch color {
|
||||||
case .red:
|
case .red:
|
||||||
@ -199,7 +198,7 @@ final class CallControllerButtonItemNode: HighlightTrackingButtonNode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
context.setFillColor(fillColor.cgColor)
|
context.setFillColor(fillColor.cgColor)
|
||||||
context.fillEllipse(in: CGRect(origin: CGPoint(), size: size))
|
context.fillEllipse(in: ellipseRect)
|
||||||
|
|
||||||
var image: UIImage?
|
var image: UIImage?
|
||||||
|
|
||||||
@ -241,11 +240,6 @@ final class CallControllerButtonItemNode: HighlightTrackingButtonNode {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
// if transition.isAnimated, let previousContent = previousContent, content.image == .camera, !previousContent.appearance.isFilled && content.appearance.isFilled {
|
|
||||||
// self.contentBackgroundNode.image = contentBackgroundImage
|
|
||||||
// self.contentBackgroundNode.layer.animateSpring(from: 0.01 as NSNumber, to: 1.0 as NSNumber, keyPath: "transform.scale", duration: 1.25, damping: 105.0)
|
|
||||||
// }
|
|
||||||
|
|
||||||
if transition.isAnimated, let contentBackgroundImage = contentBackgroundImage, let previousContent = self.contentBackgroundNode.image {
|
if transition.isAnimated, let contentBackgroundImage = contentBackgroundImage, let previousContent = self.contentBackgroundNode.image {
|
||||||
self.contentBackgroundNode.image = contentBackgroundImage
|
self.contentBackgroundNode.image = contentBackgroundImage
|
||||||
self.contentBackgroundNode.layer.animate(from: previousContent.cgImage!, to: contentBackgroundImage.cgImage!, keyPath: "contents", timingFunction: CAMediaTimingFunctionName.easeInEaseOut.rawValue, duration: 0.2)
|
self.contentBackgroundNode.layer.animate(from: previousContent.cgImage!, to: contentBackgroundImage.cgImage!, keyPath: "contents", timingFunction: CAMediaTimingFunctionName.easeInEaseOut.rawValue, duration: 0.2)
|
||||||
|
@ -30,6 +30,8 @@ private final class CallVideoNode: ASDisplayNode {
|
|||||||
private let videoView: PresentationCallVideoView
|
private let videoView: PresentationCallVideoView
|
||||||
|
|
||||||
private var effectView: UIVisualEffectView?
|
private var effectView: UIVisualEffectView?
|
||||||
|
private let videoPausedNode: ImmediateTextNode
|
||||||
|
|
||||||
private var isBlurred: Bool = false
|
private var isBlurred: Bool = false
|
||||||
private var currentCornerRadius: CGFloat = 0.0
|
private var currentCornerRadius: CGFloat = 0.0
|
||||||
|
|
||||||
@ -41,7 +43,7 @@ private final class CallVideoNode: ASDisplayNode {
|
|||||||
|
|
||||||
private(set) var currentOrientation: PresentationCallVideoView.Orientation
|
private(set) var currentOrientation: PresentationCallVideoView.Orientation
|
||||||
|
|
||||||
init(videoView: PresentationCallVideoView, assumeReadyAfterTimeout: Bool, isReadyUpdated: @escaping () -> Void, orientationUpdated: @escaping () -> Void, isFlippedUpdated: @escaping (CallVideoNode) -> Void) {
|
init(videoView: PresentationCallVideoView, disabledText: String?, assumeReadyAfterTimeout: Bool, isReadyUpdated: @escaping () -> Void, orientationUpdated: @escaping () -> Void, isFlippedUpdated: @escaping (CallVideoNode) -> Void) {
|
||||||
self.isReadyUpdated = isReadyUpdated
|
self.isReadyUpdated = isReadyUpdated
|
||||||
self.isFlippedUpdated = isFlippedUpdated
|
self.isFlippedUpdated = isFlippedUpdated
|
||||||
|
|
||||||
@ -53,6 +55,10 @@ private final class CallVideoNode: ASDisplayNode {
|
|||||||
|
|
||||||
self.currentOrientation = videoView.getOrientation()
|
self.currentOrientation = videoView.getOrientation()
|
||||||
|
|
||||||
|
self.videoPausedNode = ImmediateTextNode()
|
||||||
|
self.videoPausedNode.alpha = 0.0
|
||||||
|
self.videoPausedNode.maximumNumberOfLines = 2
|
||||||
|
|
||||||
super.init()
|
super.init()
|
||||||
|
|
||||||
if #available(iOS 13.0, *) {
|
if #available(iOS 13.0, *) {
|
||||||
@ -63,6 +69,11 @@ private final class CallVideoNode: ASDisplayNode {
|
|||||||
self.videoTransformContainer.view.addSubview(self.videoView.view)
|
self.videoTransformContainer.view.addSubview(self.videoView.view)
|
||||||
self.addSubnode(self.videoTransformContainer)
|
self.addSubnode(self.videoTransformContainer)
|
||||||
|
|
||||||
|
if let disabledText = disabledText {
|
||||||
|
self.videoPausedNode.attributedText = NSAttributedString(string: disabledText, font: Font.regular(17.0), textColor: .white)
|
||||||
|
self.addSubnode(self.videoPausedNode)
|
||||||
|
}
|
||||||
|
|
||||||
self.videoView.setOnFirstFrameReceived { [weak self] aspectRatio in
|
self.videoView.setOnFirstFrameReceived { [weak self] aspectRatio in
|
||||||
Queue.mainQueue().async {
|
Queue.mainQueue().async {
|
||||||
guard let strongSelf = self else {
|
guard let strongSelf = self else {
|
||||||
@ -200,6 +211,9 @@ private final class CallVideoNode: ASDisplayNode {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let videoPausedSize = self.videoPausedNode.updateLayout(CGSize(width: size.width - 16.0, height: 100.0))
|
||||||
|
transition.updateFrame(node: self.videoPausedNode, frame: CGRect(origin: CGPoint(x: floor((size.width - videoPausedSize.width) / 2.0), y: floor((size.height - videoPausedSize.height) / 2.0)), size: videoPausedSize))
|
||||||
|
|
||||||
let previousVideoFrame = self.videoTransformContainer.frame
|
let previousVideoFrame = self.videoTransformContainer.frame
|
||||||
self.videoTransformContainer.bounds = CGRect(origin: CGPoint(), size: size)
|
self.videoTransformContainer.bounds = CGRect(origin: CGPoint(), size: size)
|
||||||
if transition.isAnimated && !videoFrame.height.isZero && !previousVideoFrame.height.isZero {
|
if transition.isAnimated && !videoFrame.height.isZero && !previousVideoFrame.height.isZero {
|
||||||
@ -244,6 +258,7 @@ private final class CallVideoNode: ASDisplayNode {
|
|||||||
}
|
}
|
||||||
if animated {
|
if animated {
|
||||||
UIView.animate(withDuration: 0.3, animations: {
|
UIView.animate(withDuration: 0.3, animations: {
|
||||||
|
self.videoPausedNode.alpha = 1.0
|
||||||
self.effectView?.effect = UIBlurEffect(style: light ? .light : .dark)
|
self.effectView?.effect = UIBlurEffect(style: light ? .light : .dark)
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
@ -252,6 +267,7 @@ private final class CallVideoNode: ASDisplayNode {
|
|||||||
} else if let effectView = self.effectView {
|
} else if let effectView = self.effectView {
|
||||||
self.effectView = nil
|
self.effectView = nil
|
||||||
UIView.animate(withDuration: 0.3, animations: {
|
UIView.animate(withDuration: 0.3, animations: {
|
||||||
|
self.videoPausedNode.alpha = 0.0
|
||||||
effectView.effect = nil
|
effectView.effect = nil
|
||||||
}, completion: { [weak effectView] _ in
|
}, completion: { [weak effectView] _ in
|
||||||
effectView?.removeFromSuperview()
|
effectView?.removeFromSuperview()
|
||||||
@ -327,7 +343,6 @@ final class CallControllerNode: ViewControllerTracingNode, CallControllerNodePro
|
|||||||
private let backButtonArrowNode: ASImageNode
|
private let backButtonArrowNode: ASImageNode
|
||||||
private let backButtonNode: HighlightableButtonNode
|
private let backButtonNode: HighlightableButtonNode
|
||||||
private let statusNode: CallControllerStatusNode
|
private let statusNode: CallControllerStatusNode
|
||||||
private let videoPausedNode: ImmediateTextNode
|
|
||||||
private let toastNode: CallControllerToastContainerNode
|
private let toastNode: CallControllerToastContainerNode
|
||||||
private let buttonsNode: CallControllerButtonsNode
|
private let buttonsNode: CallControllerButtonsNode
|
||||||
private var keyPreviewNode: CallControllerKeyPreviewNode?
|
private var keyPreviewNode: CallControllerKeyPreviewNode?
|
||||||
@ -343,6 +358,7 @@ final class CallControllerNode: ViewControllerTracingNode, CallControllerNodePro
|
|||||||
var isMuted: Bool = false {
|
var isMuted: Bool = false {
|
||||||
didSet {
|
didSet {
|
||||||
self.buttonsNode.isMuted = self.isMuted
|
self.buttonsNode.isMuted = self.isMuted
|
||||||
|
self.updateToastContent()
|
||||||
if let (layout, navigationBarHeight) = self.validLayout {
|
if let (layout, navigationBarHeight) = self.validLayout {
|
||||||
self.containerLayoutUpdated(layout, navigationBarHeight: navigationBarHeight, transition: .animated(duration: 0.3, curve: .easeInOut))
|
self.containerLayoutUpdated(layout, navigationBarHeight: navigationBarHeight, transition: .animated(duration: 0.3, curve: .easeInOut))
|
||||||
}
|
}
|
||||||
@ -364,6 +380,7 @@ final class CallControllerNode: ViewControllerTracingNode, CallControllerNodePro
|
|||||||
var callEnded: ((Bool) -> Void)?
|
var callEnded: ((Bool) -> Void)?
|
||||||
var dismissedInteractively: (() -> Void)?
|
var dismissedInteractively: (() -> Void)?
|
||||||
var present: ((ViewController) -> Void)?
|
var present: ((ViewController) -> Void)?
|
||||||
|
var dismissAllTooltips: (() -> Void)?
|
||||||
|
|
||||||
private var toastContent: CallControllerToastContent?
|
private var toastContent: CallControllerToastContent?
|
||||||
private var displayToastsAfterTimestamp: Double?
|
private var displayToastsAfterTimestamp: Double?
|
||||||
@ -416,9 +433,6 @@ final class CallControllerNode: ViewControllerTracingNode, CallControllerNodePro
|
|||||||
|
|
||||||
self.statusNode = CallControllerStatusNode()
|
self.statusNode = CallControllerStatusNode()
|
||||||
|
|
||||||
self.videoPausedNode = ImmediateTextNode()
|
|
||||||
self.videoPausedNode.alpha = 0.0
|
|
||||||
|
|
||||||
self.buttonsNode = CallControllerButtonsNode(strings: self.presentationData.strings)
|
self.buttonsNode = CallControllerButtonsNode(strings: self.presentationData.strings)
|
||||||
self.toastNode = CallControllerToastContainerNode(strings: self.presentationData.strings)
|
self.toastNode = CallControllerToastContainerNode(strings: self.presentationData.strings)
|
||||||
self.keyButtonNode = CallControllerKeyButton()
|
self.keyButtonNode = CallControllerKeyButton()
|
||||||
@ -451,7 +465,6 @@ final class CallControllerNode: ViewControllerTracingNode, CallControllerNodePro
|
|||||||
self.containerNode.addSubnode(self.imageNode)
|
self.containerNode.addSubnode(self.imageNode)
|
||||||
self.containerNode.addSubnode(self.dimNode)
|
self.containerNode.addSubnode(self.dimNode)
|
||||||
self.containerNode.addSubnode(self.statusNode)
|
self.containerNode.addSubnode(self.statusNode)
|
||||||
self.containerNode.addSubnode(self.videoPausedNode)
|
|
||||||
self.containerNode.addSubnode(self.buttonsNode)
|
self.containerNode.addSubnode(self.buttonsNode)
|
||||||
self.containerNode.addSubnode(self.toastNode)
|
self.containerNode.addSubnode(self.toastNode)
|
||||||
self.containerNode.addSubnode(self.keyButtonNode)
|
self.containerNode.addSubnode(self.keyButtonNode)
|
||||||
@ -553,7 +566,7 @@ final class CallControllerNode: ViewControllerTracingNode, CallControllerNodePro
|
|||||||
}
|
}
|
||||||
|
|
||||||
func displayCameraTooltip() {
|
func displayCameraTooltip() {
|
||||||
guard let location = self.buttonsNode.videoButtonFrame().flatMap({ frame -> CGRect in
|
guard self.pictureInPictureTransitionFraction.isZero, let location = self.buttonsNode.videoButtonFrame().flatMap({ frame -> CGRect in
|
||||||
return self.buttonsNode.view.convert(frame, to: self.view)
|
return self.buttonsNode.view.convert(frame, to: self.view)
|
||||||
}) else {
|
}) else {
|
||||||
return
|
return
|
||||||
@ -605,8 +618,6 @@ final class CallControllerNode: ViewControllerTracingNode, CallControllerNodePro
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
self.videoPausedNode.attributedText = NSAttributedString(string: self.presentationData.strings.Call_RemoteVideoPaused(peer.compactDisplayTitle).0, font: Font.regular(17.0), textColor: .white)
|
|
||||||
|
|
||||||
if let (layout, navigationBarHeight) = self.validLayout {
|
if let (layout, navigationBarHeight) = self.validLayout {
|
||||||
self.containerLayoutUpdated(layout, navigationBarHeight: navigationBarHeight, transition: .immediate)
|
self.containerLayoutUpdated(layout, navigationBarHeight: navigationBarHeight, transition: .immediate)
|
||||||
}
|
}
|
||||||
@ -671,9 +682,11 @@ final class CallControllerNode: ViewControllerTracingNode, CallControllerNodePro
|
|||||||
}
|
}
|
||||||
strongSelf.expandedVideoNode = incomingVideoNode
|
strongSelf.expandedVideoNode = incomingVideoNode
|
||||||
strongSelf.updateButtonsMode(transition: .animated(duration: 0.4, curve: .spring))
|
strongSelf.updateButtonsMode(transition: .animated(duration: 0.4, curve: .spring))
|
||||||
|
|
||||||
|
strongSelf.updateDimVisibility()
|
||||||
}
|
}
|
||||||
|
|
||||||
let incomingVideoNode = CallVideoNode(videoView: incomingVideoView, assumeReadyAfterTimeout: false, isReadyUpdated: {
|
let incomingVideoNode = CallVideoNode(videoView: incomingVideoView, disabledText: strongSelf.presentationData.strings.Call_RemoteVideoPaused(strongSelf.peer?.compactDisplayTitle ?? "").0, assumeReadyAfterTimeout: false, isReadyUpdated: {
|
||||||
if delayUntilInitialized {
|
if delayUntilInitialized {
|
||||||
Queue.mainQueue().after(0.1, {
|
Queue.mainQueue().after(0.1, {
|
||||||
applyNode()
|
applyNode()
|
||||||
@ -752,9 +765,11 @@ final class CallControllerNode: ViewControllerTracingNode, CallControllerNodePro
|
|||||||
strongSelf.containerNode.insertSubnode(outgoingVideoNode, belowSubnode: strongSelf.dimNode)
|
strongSelf.containerNode.insertSubnode(outgoingVideoNode, belowSubnode: strongSelf.dimNode)
|
||||||
}
|
}
|
||||||
strongSelf.updateButtonsMode(transition: .animated(duration: 0.4, curve: .spring))
|
strongSelf.updateButtonsMode(transition: .animated(duration: 0.4, curve: .spring))
|
||||||
|
|
||||||
|
strongSelf.updateDimVisibility()
|
||||||
}
|
}
|
||||||
|
|
||||||
let outgoingVideoNode = CallVideoNode(videoView: outgoingVideoView, assumeReadyAfterTimeout: true, isReadyUpdated: {
|
let outgoingVideoNode = CallVideoNode(videoView: outgoingVideoView, disabledText: nil, assumeReadyAfterTimeout: true, isReadyUpdated: {
|
||||||
if delayUntilInitialized {
|
if delayUntilInitialized {
|
||||||
Queue.mainQueue().after(0.4, {
|
Queue.mainQueue().after(0.4, {
|
||||||
applyNode()
|
applyNode()
|
||||||
@ -832,15 +847,6 @@ final class CallControllerNode: ViewControllerTracingNode, CallControllerNodePro
|
|||||||
isActive = true
|
isActive = true
|
||||||
}
|
}
|
||||||
incomingVideoNode.updateIsBlurred(isBlurred: !isActive)
|
incomingVideoNode.updateIsBlurred(isBlurred: !isActive)
|
||||||
if isActive != self.videoPausedNode.alpha.isZero {
|
|
||||||
if isActive {
|
|
||||||
self.videoPausedNode.alpha = 0.0
|
|
||||||
self.videoPausedNode.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.3)
|
|
||||||
} else {
|
|
||||||
self.videoPausedNode.alpha = 1.0
|
|
||||||
self.videoPausedNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.3)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -935,6 +941,34 @@ final class CallControllerNode: ViewControllerTracingNode, CallControllerNodePro
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
self.updateToastContent()
|
||||||
|
self.updateButtonsMode()
|
||||||
|
self.updateDimVisibility()
|
||||||
|
|
||||||
|
if self.incomingVideoViewRequested && self.outgoingVideoViewRequested {
|
||||||
|
self.displayedCameraTooltip = true
|
||||||
|
self.displayedCameraConfirmation = true
|
||||||
|
}
|
||||||
|
if self.incomingVideoViewRequested && !self.outgoingVideoViewRequested && !self.displayedCameraTooltip && (self.toastContent?.isEmpty ?? true) {
|
||||||
|
self.displayedCameraTooltip = true
|
||||||
|
Queue.mainQueue().after(2.0) {
|
||||||
|
self.displayCameraTooltip()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if case let .terminated(id, _, reportRating) = callState.state, let callId = id {
|
||||||
|
let presentRating = reportRating || self.forceReportRating
|
||||||
|
if presentRating {
|
||||||
|
self.presentCallRating?(callId)
|
||||||
|
}
|
||||||
|
self.callEnded?(presentRating)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private func updateToastContent() {
|
||||||
|
guard let callState = self.callState else {
|
||||||
|
return
|
||||||
|
}
|
||||||
if case .terminating = callState.state {
|
if case .terminating = callState.state {
|
||||||
} else if case .terminated = callState.state {
|
} else if case .terminated = callState.state {
|
||||||
} else {
|
} else {
|
||||||
@ -961,27 +995,6 @@ final class CallControllerNode: ViewControllerTracingNode, CallControllerNodePro
|
|||||||
}
|
}
|
||||||
self.toastContent = toastContent
|
self.toastContent = toastContent
|
||||||
}
|
}
|
||||||
|
|
||||||
self.updateButtonsMode()
|
|
||||||
self.updateDimVisibility()
|
|
||||||
|
|
||||||
if self.incomingVideoViewRequested && self.outgoingVideoViewRequested {
|
|
||||||
self.displayedCameraTooltip = true
|
|
||||||
}
|
|
||||||
if self.incomingVideoViewRequested && !self.outgoingVideoViewRequested && !self.displayedCameraTooltip && (self.toastContent?.isEmpty ?? true) {
|
|
||||||
self.displayedCameraTooltip = true
|
|
||||||
Queue.mainQueue().after(2.0) {
|
|
||||||
self.displayCameraTooltip()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if case let .terminated(id, _, reportRating) = callState.state, let callId = id {
|
|
||||||
let presentRating = reportRating || self.forceReportRating
|
|
||||||
if presentRating {
|
|
||||||
self.presentCallRating?(callId)
|
|
||||||
}
|
|
||||||
self.callEnded?(presentRating)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private func updateDimVisibility(transition: ContainedViewLayoutTransition = .animated(duration: 0.3, curve: .easeInOut)) {
|
private func updateDimVisibility(transition: ContainedViewLayoutTransition = .animated(duration: 0.3, curve: .easeInOut)) {
|
||||||
@ -998,8 +1011,8 @@ final class CallControllerNode: ViewControllerTracingNode, CallControllerNodePro
|
|||||||
if visible != currentVisible {
|
if visible != currentVisible {
|
||||||
let color = visible ? UIColor(rgb: 0x000000, alpha: 0.3) : UIColor.clear
|
let color = visible ? UIColor(rgb: 0x000000, alpha: 0.3) : UIColor.clear
|
||||||
let image: UIImage? = visible ? nil : generateGradientImage(size: CGSize(width: 1.0, height: 640.0), colors: [UIColor.black.withAlphaComponent(0.3), UIColor.clear, UIColor.clear, UIColor.black.withAlphaComponent(0.3)], locations: [0.0, 0.22, 0.7, 1.0])
|
let image: UIImage? = visible ? nil : generateGradientImage(size: CGSize(width: 1.0, height: 640.0), colors: [UIColor.black.withAlphaComponent(0.3), UIColor.clear, UIColor.clear, UIColor.black.withAlphaComponent(0.3)], locations: [0.0, 0.22, 0.7, 1.0])
|
||||||
if transition.isAnimated {
|
if case let .animated(duration, _) = transition {
|
||||||
UIView.transition(with: self.dimNode.view, duration: 0.3, options: .transitionCrossDissolve, animations: {
|
UIView.transition(with: self.dimNode.view, duration: duration, options: .transitionCrossDissolve, animations: {
|
||||||
self.dimNode.backgroundColor = color
|
self.dimNode.backgroundColor = color
|
||||||
self.dimNode.image = image
|
self.dimNode.image = image
|
||||||
}, completion: nil)
|
}, completion: nil)
|
||||||
@ -1007,8 +1020,8 @@ final class CallControllerNode: ViewControllerTracingNode, CallControllerNodePro
|
|||||||
self.dimNode.backgroundColor = color
|
self.dimNode.backgroundColor = color
|
||||||
self.dimNode.image = image
|
self.dimNode.image = image
|
||||||
}
|
}
|
||||||
self.statusNode.isHidden = !visible
|
|
||||||
}
|
}
|
||||||
|
self.statusNode.setVisible(visible || self.keyPreviewNode != nil, transition: transition)
|
||||||
}
|
}
|
||||||
|
|
||||||
private var buttonsTerminationMode: CallControllerButtonsMode?
|
private var buttonsTerminationMode: CallControllerButtonsMode?
|
||||||
@ -1299,9 +1312,6 @@ final class CallControllerNode: ViewControllerTracingNode, CallControllerNodePro
|
|||||||
transition.updateFrame(node: self.statusNode, frame: CGRect(origin: CGPoint(x: 0.0, y: statusOffset), size: CGSize(width: layout.size.width, height: statusHeight)))
|
transition.updateFrame(node: self.statusNode, frame: CGRect(origin: CGPoint(x: 0.0, y: statusOffset), size: CGSize(width: layout.size.width, height: statusHeight)))
|
||||||
transition.updateAlpha(node: self.statusNode, alpha: overlayAlpha)
|
transition.updateAlpha(node: self.statusNode, alpha: overlayAlpha)
|
||||||
|
|
||||||
let videoPausedSize = self.videoPausedNode.updateLayout(CGSize(width: layout.size.width - 16.0, height: 100.0))
|
|
||||||
transition.updateFrame(node: self.videoPausedNode, frame: CGRect(origin: CGPoint(x: floor((layout.size.width - videoPausedSize.width) / 2.0), y: floor((layout.size.height - videoPausedSize.height) / 2.0)), size: videoPausedSize))
|
|
||||||
|
|
||||||
transition.updateFrame(node: self.toastNode, frame: CGRect(origin: CGPoint(x: 0.0, y: toastOriginY), size: CGSize(width: layout.size.width, height: toastHeight)))
|
transition.updateFrame(node: self.toastNode, frame: CGRect(origin: CGPoint(x: 0.0, y: toastOriginY), size: CGSize(width: layout.size.width, height: toastHeight)))
|
||||||
transition.updateFrame(node: self.buttonsNode, frame: CGRect(origin: CGPoint(x: 0.0, y: buttonsOriginY), size: CGSize(width: layout.size.width, height: buttonsHeight)))
|
transition.updateFrame(node: self.buttonsNode, frame: CGRect(origin: CGPoint(x: 0.0, y: buttonsOriginY), size: CGSize(width: layout.size.width, height: buttonsHeight)))
|
||||||
transition.updateAlpha(node: self.buttonsNode, alpha: overlayAlpha)
|
transition.updateAlpha(node: self.buttonsNode, alpha: overlayAlpha)
|
||||||
@ -1424,6 +1434,8 @@ final class CallControllerNode: ViewControllerTracingNode, CallControllerNodePro
|
|||||||
self.keyButtonNode.isHidden = true
|
self.keyButtonNode.isHidden = true
|
||||||
keyPreviewNode.animateIn(from: self.keyButtonNode.frame, fromNode: self.keyButtonNode)
|
keyPreviewNode.animateIn(from: self.keyButtonNode.frame, fromNode: self.keyButtonNode)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
self.updateDimVisibility()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1434,6 +1446,7 @@ final class CallControllerNode: ViewControllerTracingNode, CallControllerNodePro
|
|||||||
self?.keyButtonNode.isHidden = false
|
self?.keyButtonNode.isHidden = false
|
||||||
keyPreviewNode?.removeFromSupernode()
|
keyPreviewNode?.removeFromSupernode()
|
||||||
})
|
})
|
||||||
|
self.updateDimVisibility()
|
||||||
} else if self.hasVideoNodes {
|
} else if self.hasVideoNodes {
|
||||||
if let (layout, navigationHeight) = self.validLayout {
|
if let (layout, navigationHeight) = self.validLayout {
|
||||||
self.pictureInPictureTransitionFraction = 1.0
|
self.pictureInPictureTransitionFraction = 1.0
|
||||||
@ -1669,7 +1682,7 @@ final class CallControllerNode: ViewControllerTracingNode, CallControllerNodePro
|
|||||||
}
|
}
|
||||||
if self.pictureInPictureTransitionFraction.isZero, let expandedVideoNode = self.expandedVideoNode, let minimizedVideoNode = self.minimizedVideoNode, minimizedVideoNode.frame.contains(location), expandedVideoNode.frame != minimizedVideoNode.frame {
|
if self.pictureInPictureTransitionFraction.isZero, let expandedVideoNode = self.expandedVideoNode, let minimizedVideoNode = self.minimizedVideoNode, minimizedVideoNode.frame.contains(location), expandedVideoNode.frame != minimizedVideoNode.frame {
|
||||||
self.minimizedVideoInitialPosition = minimizedVideoNode.position
|
self.minimizedVideoInitialPosition = minimizedVideoNode.position
|
||||||
} else if let _ = self.minimizedVideoNode {
|
} else if self.hasVideoNodes {
|
||||||
self.minimizedVideoInitialPosition = nil
|
self.minimizedVideoInitialPosition = nil
|
||||||
if !self.pictureInPictureTransitionFraction.isZero {
|
if !self.pictureInPictureTransitionFraction.isZero {
|
||||||
self.pictureInPictureGestureState = .dragging(initialPosition: self.containerTransformationNode.position, draggingPosition: self.containerTransformationNode.position)
|
self.pictureInPictureGestureState = .dragging(initialPosition: self.containerTransformationNode.position, draggingPosition: self.containerTransformationNode.position)
|
||||||
@ -1679,6 +1692,7 @@ final class CallControllerNode: ViewControllerTracingNode, CallControllerNodePro
|
|||||||
} else {
|
} else {
|
||||||
self.pictureInPictureGestureState = .none
|
self.pictureInPictureGestureState = .none
|
||||||
}
|
}
|
||||||
|
self.dismissAllTooltips?()
|
||||||
case .changed:
|
case .changed:
|
||||||
if let minimizedVideoNode = self.minimizedVideoNode, let minimizedVideoInitialPosition = self.minimizedVideoInitialPosition {
|
if let minimizedVideoNode = self.minimizedVideoNode, let minimizedVideoInitialPosition = self.minimizedVideoInitialPosition {
|
||||||
let translation = recognizer.translation(in: self.view)
|
let translation = recognizer.translation(in: self.view)
|
||||||
|
@ -133,6 +133,12 @@ final class CallControllerStatusNode: ASDisplayNode {
|
|||||||
self.statusTimer?.invalidate()
|
self.statusTimer?.invalidate()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func setVisible(_ visible: Bool, transition: ContainedViewLayoutTransition) {
|
||||||
|
let alpha: CGFloat = visible ? 1.0 : 0.0
|
||||||
|
transition.updateAlpha(node: self.titleNode, alpha: alpha)
|
||||||
|
transition.updateAlpha(node: self.statusContainerNode, alpha: alpha)
|
||||||
|
}
|
||||||
|
|
||||||
func updateLayout(constrainedWidth: CGFloat, transition: ContainedViewLayoutTransition) -> CGFloat {
|
func updateLayout(constrainedWidth: CGFloat, transition: ContainedViewLayoutTransition) -> CGFloat {
|
||||||
self.validLayoutWidth = constrainedWidth
|
self.validLayoutWidth = constrainedWidth
|
||||||
|
|
||||||
|
@ -272,25 +272,23 @@ private class CallControllerToastItemNode: ASDisplayNode {
|
|||||||
} else {
|
} else {
|
||||||
self.iconNode.image = image
|
self.iconNode.image = image
|
||||||
}
|
}
|
||||||
|
|
||||||
|
self.textNode.attributedText = NSAttributedString(string: content.text, font: Font.regular(17.0), textColor: .white)
|
||||||
|
|
||||||
if previousContent?.text != content.text {
|
let iconSize = CGSize(width: 44.0, height: 28.0)
|
||||||
self.textNode.attributedText = NSAttributedString(string: content.text, font: Font.regular(17.0), textColor: .white)
|
let iconSpacing: CGFloat = 2.0
|
||||||
|
let textSize = self.textNode.updateLayout(CGSize(width: width - inset * 2.0 - iconSize.width - iconSpacing, height: 100.0))
|
||||||
let iconSize = CGSize(width: 44.0, height: 28.0)
|
|
||||||
let iconSpacing: CGFloat = 2.0
|
let backgroundSize = CGSize(width: iconSize.width + iconSpacing + textSize.width + 6.0 * 2.0, height: max(28.0, textSize.height + 4.0 * 2.0))
|
||||||
let textSize = self.textNode.updateLayout(CGSize(width: width - inset * 2.0 - iconSize.width - iconSpacing, height: 100.0))
|
let backgroundFrame = CGRect(origin: CGPoint(x: floor((width - backgroundSize.width) / 2.0), y: 0.0), size: backgroundSize)
|
||||||
|
|
||||||
let backgroundSize = CGSize(width: iconSize.width + iconSpacing + textSize.width + 6.0 * 2.0, height: max(28.0, textSize.height + 4.0 * 2.0))
|
transition.updateFrame(node: self.clipNode, frame: backgroundFrame)
|
||||||
let backgroundFrame = CGRect(origin: CGPoint(x: floor((width - backgroundSize.width) / 2.0), y: 0.0), size: backgroundSize)
|
transition.updateFrame(view: self.effectView, frame: CGRect(origin: CGPoint(), size: backgroundFrame.size))
|
||||||
|
|
||||||
transition.updateFrame(node: self.clipNode, frame: backgroundFrame)
|
self.iconNode.frame = CGRect(origin: CGPoint(), size: iconSize)
|
||||||
transition.updateFrame(view: self.effectView, frame: CGRect(origin: CGPoint(), size: backgroundFrame.size))
|
self.textNode.frame = CGRect(origin: CGPoint(x: iconSize.width + iconSpacing, y: 4.0), size: textSize)
|
||||||
|
|
||||||
self.iconNode.frame = CGRect(origin: CGPoint(), size: iconSize)
|
self.currentHeight = backgroundSize.height
|
||||||
self.textNode.frame = CGRect(origin: CGPoint(x: iconSize.width + iconSpacing, y: 4.0), size: textSize)
|
|
||||||
|
|
||||||
self.currentHeight = backgroundSize.height
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return self.currentHeight ?? 28.0
|
return self.currentHeight ?? 28.0
|
||||||
}
|
}
|
||||||
|
@ -66,6 +66,7 @@ final class LegacyCallControllerNode: ASDisplayNode, CallControllerNodeProtocol
|
|||||||
var callEnded: ((Bool) -> Void)?
|
var callEnded: ((Bool) -> Void)?
|
||||||
var dismissedInteractively: (() -> Void)?
|
var dismissedInteractively: (() -> Void)?
|
||||||
var present: ((ViewController) -> Void)?
|
var present: ((ViewController) -> Void)?
|
||||||
|
var dismissAllTooltips: (() -> Void)?
|
||||||
|
|
||||||
init(sharedContext: SharedAccountContext, account: Account, presentationData: PresentationData, statusBar: StatusBar, debugInfo: Signal<(String, String), NoError>, shouldStayHiddenUntilConnection: Bool = false, easyDebugAccess: Bool, call: PresentationCall) {
|
init(sharedContext: SharedAccountContext, account: Account, presentationData: PresentationData, statusBar: StatusBar, debugInfo: Signal<(String, String), NoError>, shouldStayHiddenUntilConnection: Bool = false, easyDebugAccess: Bool, call: PresentationCall) {
|
||||||
self.sharedContext = sharedContext
|
self.sharedContext = sharedContext
|
||||||
|
@ -789,7 +789,7 @@ public final class PresentationCallImpl: PresentationCall {
|
|||||||
}
|
}
|
||||||
if value {
|
if value {
|
||||||
if strongSelf.isVideo {
|
if strongSelf.isVideo {
|
||||||
DeviceAccess.authorizeAccess(to: .camera, presentationData: presentationData, present: { c, a in
|
DeviceAccess.authorizeAccess(to: .camera(.videoCall), presentationData: presentationData, present: { c, a in
|
||||||
present(c, a)
|
present(c, a)
|
||||||
}, openSettings: {
|
}, openSettings: {
|
||||||
openSettings()
|
openSettings()
|
||||||
|
@ -374,7 +374,7 @@ public final class PresentationCallManagerImpl: PresentationCallManager {
|
|||||||
openSettings()
|
openSettings()
|
||||||
}, { value in
|
}, { value in
|
||||||
if isVideo && value {
|
if isVideo && value {
|
||||||
DeviceAccess.authorizeAccess(to: .camera, presentationData: presentationData, present: { c, a in
|
DeviceAccess.authorizeAccess(to: .camera(.videoCall), presentationData: presentationData, present: { c, a in
|
||||||
present(c, a)
|
present(c, a)
|
||||||
}, openSettings: {
|
}, openSettings: {
|
||||||
openSettings()
|
openSettings()
|
||||||
@ -450,7 +450,7 @@ public final class PresentationCallManagerImpl: PresentationCallManager {
|
|||||||
openSettings()
|
openSettings()
|
||||||
}, { value in
|
}, { value in
|
||||||
if isVideo && value {
|
if isVideo && value {
|
||||||
DeviceAccess.authorizeAccess(to: .camera, presentationData: presentationData, present: { c, a in
|
DeviceAccess.authorizeAccess(to: .camera(.videoCall), presentationData: presentationData, present: { c, a in
|
||||||
present(c, a)
|
present(c, a)
|
||||||
}, openSettings: {
|
}, openSettings: {
|
||||||
openSettings()
|
openSettings()
|
||||||
|
File diff suppressed because it is too large
Load Diff
Binary file not shown.
@ -4022,7 +4022,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
if isVideo {
|
if isVideo {
|
||||||
DeviceAccess.authorizeAccess(to: .camera, presentationData: strongSelf.presentationData, present: { c, a in
|
DeviceAccess.authorizeAccess(to: .camera(.video), presentationData: strongSelf.presentationData, present: { c, a in
|
||||||
self?.present(c, in: .window(.root), with: a)
|
self?.present(c, in: .window(.root), with: a)
|
||||||
}, openSettings: {
|
}, openSettings: {
|
||||||
self?.context.sharedContext.applicationBindings.openSettings()
|
self?.context.sharedContext.applicationBindings.openSettings()
|
||||||
|
@ -259,7 +259,7 @@ final class WalletContextImpl: WalletContext {
|
|||||||
|
|
||||||
func authorizeAccessToCamera(completion: @escaping () -> Void) {
|
func authorizeAccessToCamera(completion: @escaping () -> Void) {
|
||||||
let presentationData = self.context.sharedContext.currentPresentationData.with { $0 }
|
let presentationData = self.context.sharedContext.currentPresentationData.with { $0 }
|
||||||
DeviceAccess.authorizeAccess(to: .camera, presentationData: presentationData, present: { c, a in
|
DeviceAccess.authorizeAccess(to: .camera(.video), presentationData: presentationData, present: { c, a in
|
||||||
c.presentationArguments = a
|
c.presentationArguments = a
|
||||||
self.context.sharedContext.mainWindow?.present(c, on: .root)
|
self.context.sharedContext.mainWindow?.present(c, on: .root)
|
||||||
}, openSettings: { [weak self] in
|
}, openSettings: { [weak self] in
|
||||||
|
@ -1 +1 @@
|
|||||||
Subproject commit fd1892ffde13fdba03b2d6caca08b4c210ab9dcd
|
Subproject commit da1160dfbf4ac4b0dee65d481bd9c634932cd5a2
|
Loading…
x
Reference in New Issue
Block a user