This commit is contained in:
Peter
2018-11-23 04:38:14 +03:00
parent 054688879a
commit 89696eb037
11 changed files with 210 additions and 86 deletions

View File

@@ -238,7 +238,7 @@ public final class AuthorizationSequenceController: NavigationController {
let _ = (strongSelf.account.postbox.transaction { transaction -> Void in let _ = (strongSelf.account.postbox.transaction { transaction -> Void in
transaction.setState(UnauthorizedAccountState(isTestingEnvironment: account.testingEnvironment, masterDatacenterId: account.masterDatacenterId, contents: .empty)) transaction.setState(UnauthorizedAccountState(isTestingEnvironment: account.testingEnvironment, masterDatacenterId: account.masterDatacenterId, contents: .empty))
}).start() }).start()
})]), on: .root, blockInteraction: false) })]), on: .root, blockInteraction: false, completion: {})
}) })
], actionLayout: .vertical) ], actionLayout: .vertical)
contentNode.textAttributeAction = (NSAttributedStringKey(rawValue: TelegramTextAttributes.URL), { value in contentNode.textAttributeAction = (NSAttributedStringKey(rawValue: TelegramTextAttributes.URL), { value in
@@ -251,7 +251,7 @@ public final class AuthorizationSequenceController: NavigationController {
controller?.dismissAnimated() controller?.dismissAnimated()
} }
strongSelf.view.endEditing(true) strongSelf.view.endEditing(true)
strongSelf.currentWindow?.present(controller, on: .root, blockInteraction: false) strongSelf.currentWindow?.present(controller, on: .root, blockInteraction: false, completion: {})
} }
presentAlertAgainImpl = { presentAlertAgainImpl = {
presentAlertImpl() presentAlertImpl()

View File

@@ -88,7 +88,20 @@ private func preparedChatMediaInputGridEntryTransition(account: Account, view: I
} else if !toEntries.isEmpty { } else if !toEntries.isEmpty {
if let collectionId = collectionId { if let collectionId = collectionId {
for i in 0 ..< toEntries.count { for i in 0 ..< toEntries.count {
if case let .collectionIndex(collectionIndex) = toEntries[i].index, collectionIndex.collectionId == collectionId { var indexMatches = false
switch toEntries[i].index {
case let .collectionIndex(collectionIndex):
if collectionIndex.collectionId == collectionId {
indexMatches = true
}
case .peerSpecificSetup:
if collectionId.namespace == ChatMediaInputPanelAuxiliaryNamespace.peerSpecific.rawValue {
indexMatches = true
}
default:
break
}
if indexMatches {
var directionHint: GridNodePreviousItemsTransitionDirectionHint = .up var directionHint: GridNodePreviousItemsTransitionDirectionHint = .up
if !fromEntries.isEmpty && fromEntries[0].index < toEntries[i].index { if !fromEntries.isEmpty && fromEntries[0].index < toEntries[i].index {
directionHint = .down directionHint = .down
@@ -537,49 +550,49 @@ final class ChatMediaInputNode: ChatInputNode {
self.addSubnode(self.collectionListContainer) self.addSubnode(self.collectionListContainer)
let itemCollectionsView = self.itemCollectionsViewPosition.get() let itemCollectionsView = self.itemCollectionsViewPosition.get()
|> distinctUntilChanged |> distinctUntilChanged
|> mapToSignal { position -> Signal<(ItemCollectionsView, StickerPacksCollectionUpdate), NoError> in |> mapToSignal { position -> Signal<(ItemCollectionsView, StickerPacksCollectionUpdate), NoError> in
switch position { switch position {
case .initial: case .initial:
var firstTime = true var firstTime = true
return account.postbox.itemCollectionsView(orderedItemListCollectionIds: [Namespaces.OrderedItemList.CloudSavedStickers, Namespaces.OrderedItemList.CloudRecentStickers], namespaces: [Namespaces.ItemCollection.CloudStickerPacks], aroundIndex: nil, count: 50) return account.postbox.itemCollectionsView(orderedItemListCollectionIds: [Namespaces.OrderedItemList.CloudSavedStickers, Namespaces.OrderedItemList.CloudRecentStickers], namespaces: [Namespaces.ItemCollection.CloudStickerPacks], aroundIndex: nil, count: 50)
|> map { view -> (ItemCollectionsView, StickerPacksCollectionUpdate) in |> map { view -> (ItemCollectionsView, StickerPacksCollectionUpdate) in
let update: StickerPacksCollectionUpdate let update: StickerPacksCollectionUpdate
if firstTime { if firstTime {
firstTime = false firstTime = false
update = .initial update = .initial
} else { } else {
update = .generic update = .generic
}
return (view, update)
}
case let .scroll(aroundIndex):
var firstTime = true
return account.postbox.itemCollectionsView(orderedItemListCollectionIds: [Namespaces.OrderedItemList.CloudSavedStickers, Namespaces.OrderedItemList.CloudRecentStickers], namespaces: [Namespaces.ItemCollection.CloudStickerPacks], aroundIndex: aroundIndex, count: 300)
|> map { view -> (ItemCollectionsView, StickerPacksCollectionUpdate) in
let update: StickerPacksCollectionUpdate
if firstTime {
firstTime = false
update = .scroll
} else {
update = .generic
}
return (view, update)
}
case let .navigate(index, collectionId):
var firstTime = true
return account.postbox.itemCollectionsView(orderedItemListCollectionIds: [Namespaces.OrderedItemList.CloudSavedStickers, Namespaces.OrderedItemList.CloudRecentStickers], namespaces: [Namespaces.ItemCollection.CloudStickerPacks], aroundIndex: index, count: 300)
|> map { view -> (ItemCollectionsView, StickerPacksCollectionUpdate) in
let update: StickerPacksCollectionUpdate
if firstTime {
firstTime = false
update = .navigate(index, collectionId)
} else {
update = .generic
}
return (view, update)
} }
} return (view, update)
}
case let .scroll(aroundIndex):
var firstTime = true
return account.postbox.itemCollectionsView(orderedItemListCollectionIds: [Namespaces.OrderedItemList.CloudSavedStickers, Namespaces.OrderedItemList.CloudRecentStickers], namespaces: [Namespaces.ItemCollection.CloudStickerPacks], aroundIndex: aroundIndex, count: 300)
|> map { view -> (ItemCollectionsView, StickerPacksCollectionUpdate) in
let update: StickerPacksCollectionUpdate
if firstTime {
firstTime = false
update = .scroll
} else {
update = .generic
}
return (view, update)
}
case let .navigate(index, collectionId):
var firstTime = true
return account.postbox.itemCollectionsView(orderedItemListCollectionIds: [Namespaces.OrderedItemList.CloudSavedStickers, Namespaces.OrderedItemList.CloudRecentStickers], namespaces: [Namespaces.ItemCollection.CloudStickerPacks], aroundIndex: index, count: 300)
|> map { view -> (ItemCollectionsView, StickerPacksCollectionUpdate) in
let update: StickerPacksCollectionUpdate
if firstTime {
firstTime = false
update = .navigate(index, collectionId)
} else {
update = .generic
}
return (view, update)
}
}
} }
let previousEntries = Atomic<([ChatMediaInputPanelEntry], [ChatMediaInputGridEntry])>(value: ([], [])) let previousEntries = Atomic<([ChatMediaInputPanelEntry], [ChatMediaInputGridEntry])>(value: ([], []))
@@ -666,8 +679,12 @@ final class ChatMediaInputNode: ChatInputNode {
if let topVisibleSection = visibleItems.topSectionVisible as? ChatMediaInputStickerGridSection { if let topVisibleSection = visibleItems.topSectionVisible as? ChatMediaInputStickerGridSection {
topVisibleCollectionId = topVisibleSection.collectionId topVisibleCollectionId = topVisibleSection.collectionId
} else if let topVisible = visibleItems.topVisible, let item = topVisible.1 as? ChatMediaInputStickerGridItem { } else if let topVisible = visibleItems.topVisible {
topVisibleCollectionId = item.index.collectionId if let item = topVisible.1 as? ChatMediaInputStickerGridItem {
topVisibleCollectionId = item.index.collectionId
} else if let _ = topVisible.1 as? StickerPanePeerSpecificSetupGridItem {
topVisibleCollectionId = ItemCollectionId(namespace: ChatMediaInputPanelAuxiliaryNamespace.peerSpecific.rawValue, id: 0)
}
} }
if let collectionId = topVisibleCollectionId { if let collectionId = topVisibleCollectionId {
if strongSelf.inputNodeInteraction.highlightedItemCollectionId != collectionId { if strongSelf.inputNodeInteraction.highlightedItemCollectionId != collectionId {

View File

@@ -161,27 +161,59 @@ final class InstantImageGalleryItemNode: ZoomableContentGalleryItemNode {
let transformedSelfFrame = node.0.view.convert(node.0.view.bounds, to: self.view) let transformedSelfFrame = node.0.view.convert(node.0.view.bounds, to: self.view)
let transformedCopyViewFinalFrame = self.imageNode.view.convert(self.imageNode.view.bounds, to: self.view) let transformedCopyViewFinalFrame = self.imageNode.view.convert(self.imageNode.view.bounds, to: self.view)
let surfaceCopyView = node.1()!
let copyView = node.1()! let copyView = node.1()!
addToTransitionSurface(surfaceCopyView)
var transformedSurfaceFrame: CGRect?
var transformedSurfaceFinalFrame: CGRect?
if let contentSurface = surfaceCopyView.superview {
transformedSurfaceFrame = node.0.view.convert(node.0.view.bounds, to: contentSurface)
transformedSurfaceFinalFrame = self.imageNode.view.convert(self.imageNode.view.bounds, to: contentSurface)
}
if let transformedSurfaceFrame = transformedSurfaceFrame {
surfaceCopyView.frame = transformedSurfaceFrame
}
self.view.insertSubview(copyView, belowSubview: self.scrollNode.view) self.view.insertSubview(copyView, belowSubview: self.scrollNode.view)
copyView.frame = transformedSelfFrame copyView.frame = transformedSelfFrame
copyView.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.25, removeOnCompletion: false, completion: { [weak copyView] _ in copyView.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.2, removeOnCompletion: false)
surfaceCopyView.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.25, removeOnCompletion: false)
let positionDuration: Double = 0.21
copyView.layer.animatePosition(from: CGPoint(x: transformedSelfFrame.midX, y: transformedSelfFrame.midY), to: CGPoint(x: transformedCopyViewFinalFrame.midX, y: transformedCopyViewFinalFrame.midY), duration: positionDuration, timingFunction: kCAMediaTimingFunctionSpring, removeOnCompletion: false, completion: { [weak copyView] _ in
copyView?.removeFromSuperview() copyView?.removeFromSuperview()
}) })
copyView.layer.animatePosition(from: CGPoint(x: transformedSelfFrame.midX, y: transformedSelfFrame.midY), to: CGPoint(x: transformedCopyViewFinalFrame.midX, y: transformedCopyViewFinalFrame.midY), duration: 0.25, timingFunction: kCAMediaTimingFunctionSpring, removeOnCompletion: false)
let scale = CGSize(width: transformedCopyViewFinalFrame.size.width / transformedSelfFrame.size.width, height: transformedCopyViewFinalFrame.size.height / transformedSelfFrame.size.height) let scale = CGSize(width: transformedCopyViewFinalFrame.size.width / transformedSelfFrame.size.width, height: transformedCopyViewFinalFrame.size.height / transformedSelfFrame.size.height)
copyView.layer.animate(from: NSValue(caTransform3D: CATransform3DIdentity), to: NSValue(caTransform3D: CATransform3DMakeScale(scale.width, scale.height, 1.0)), keyPath: "transform", timingFunction: kCAMediaTimingFunctionSpring, duration: 0.25, removeOnCompletion: false) copyView.layer.animate(from: NSValue(caTransform3D: CATransform3DIdentity), to: NSValue(caTransform3D: CATransform3DMakeScale(scale.width, scale.height, 1.0)), keyPath: "transform", timingFunction: kCAMediaTimingFunctionSpring, duration: 0.25, removeOnCompletion: false)
self.imageNode.layer.animatePosition(from: CGPoint(x: transformedSuperFrame.midX, y: transformedSuperFrame.midY), to: self.imageNode.layer.position, duration: 0.25, timingFunction: kCAMediaTimingFunctionSpring) if let transformedSurfaceFrame = transformedSurfaceFrame, let transformedSurfaceFinalFrame = transformedSurfaceFinalFrame {
surfaceCopyView.layer.animatePosition(from: CGPoint(x: transformedSurfaceFrame.midX, y: transformedSurfaceFrame.midY), to: CGPoint(x: transformedCopyViewFinalFrame.midX, y: transformedCopyViewFinalFrame.midY), duration: positionDuration, timingFunction: kCAMediaTimingFunctionSpring, removeOnCompletion: false, completion: { [weak surfaceCopyView] _ in
surfaceCopyView?.removeFromSuperview()
})
let scale = CGSize(width: transformedSurfaceFinalFrame.size.width / transformedSurfaceFrame.size.width, height: transformedSurfaceFinalFrame.size.height / transformedSurfaceFrame.size.height)
surfaceCopyView.layer.animate(from: NSValue(caTransform3D: CATransform3DIdentity), to: NSValue(caTransform3D: CATransform3DMakeScale(scale.width, scale.height, 1.0)), keyPath: "transform", timingFunction: kCAMediaTimingFunctionSpring, duration: 0.25, removeOnCompletion: false)
}
self.imageNode.layer.animatePosition(from: CGPoint(x: transformedSuperFrame.midX, y: transformedSuperFrame.midY), to: self.imageNode.layer.position, duration: positionDuration, timingFunction: kCAMediaTimingFunctionSpring)
self.imageNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.1) self.imageNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.1)
transformedFrame.origin = CGPoint() transformedFrame.origin = CGPoint()
self.imageNode.layer.animateBounds(from: transformedFrame, to: self.imageNode.layer.bounds, duration: 0.25, timingFunction: kCAMediaTimingFunctionSpring) self.imageNode.layer.animateBounds(from: transformedFrame, to: self.imageNode.layer.bounds, duration: 0.25, timingFunction: kCAMediaTimingFunctionSpring)
/*self.statusNodeContainer.layer.animatePosition(from: CGPoint(x: transformedSuperFrame.midX, y: transformedSuperFrame.midY), to: self.statusNodeContainer.position, duration: positionDuration, timingFunction: kCAMediaTimingFunctionSpring)
self.statusNodeContainer.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.25, timingFunction: kCAMediaTimingFunctionSpring)
self.statusNodeContainer.layer.animateScale(from: 0.5, to: 1.0, duration: 0.25, timingFunction: kCAMediaTimingFunctionSpring)*/
} }
override func animateOut(to node: (ASDisplayNode, () -> UIView?), addToTransitionSurface: (UIView) -> Void, completion: @escaping () -> Void) { override func animateOut(to node: (ASDisplayNode, () -> UIView?), addToTransitionSurface: (UIView) -> Void, completion: @escaping () -> Void) {
self.fetchDisposable.set(nil)
var transformedFrame = node.0.view.convert(node.0.view.bounds, to: self.imageNode.view) var transformedFrame = node.0.view.convert(node.0.view.bounds, to: self.imageNode.view)
let transformedSuperFrame = node.0.view.convert(node.0.view.bounds, to: self.imageNode.view.superview) let transformedSuperFrame = node.0.view.convert(node.0.view.bounds, to: self.imageNode.view.superview)
let transformedSelfFrame = node.0.view.convert(node.0.view.bounds, to: self.view) let transformedSelfFrame = node.0.view.convert(node.0.view.bounds, to: self.view)
@@ -192,18 +224,30 @@ final class InstantImageGalleryItemNode: ZoomableContentGalleryItemNode {
var copyCompleted = false var copyCompleted = false
let copyView = node.1()! let copyView = node.1()!
let surfaceCopyView = node.1()!
addToTransitionSurface(surfaceCopyView)
var transformedSurfaceFrame: CGRect?
var transformedSurfaceCopyViewInitialFrame: CGRect?
if let contentSurface = surfaceCopyView.superview {
transformedSurfaceFrame = node.0.view.convert(node.0.view.bounds, to: contentSurface)
transformedSurfaceCopyViewInitialFrame = self.imageNode.view.convert(self.imageNode.view.bounds, to: contentSurface)
}
self.view.insertSubview(copyView, belowSubview: self.scrollNode.view) self.view.insertSubview(copyView, belowSubview: self.scrollNode.view)
copyView.frame = transformedSelfFrame copyView.frame = transformedSelfFrame
let intermediateCompletion = { [weak copyView] in let intermediateCompletion = { [weak copyView, weak surfaceCopyView] in
if positionCompleted && boundsCompleted && copyCompleted { if positionCompleted && boundsCompleted && copyCompleted {
copyView?.removeFromSuperview() copyView?.removeFromSuperview()
surfaceCopyView?.removeFromSuperview()
completion() completion()
} }
} }
copyView.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.1, removeOnCompletion: false) copyView.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.08, removeOnCompletion: false)
surfaceCopyView.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.025, removeOnCompletion: false)
copyView.layer.animatePosition(from: CGPoint(x: transformedCopyViewInitialFrame.midX, y: transformedCopyViewInitialFrame.midY), to: CGPoint(x: transformedSelfFrame.midX, y: transformedSelfFrame.midY), duration: 0.25, timingFunction: kCAMediaTimingFunctionSpring, removeOnCompletion: false) copyView.layer.animatePosition(from: CGPoint(x: transformedCopyViewInitialFrame.midX, y: transformedCopyViewInitialFrame.midY), to: CGPoint(x: transformedSelfFrame.midX, y: transformedSelfFrame.midY), duration: 0.25, timingFunction: kCAMediaTimingFunctionSpring, removeOnCompletion: false)
let scale = CGSize(width: transformedCopyViewInitialFrame.size.width / transformedSelfFrame.size.width, height: transformedCopyViewInitialFrame.size.height / transformedSelfFrame.size.height) let scale = CGSize(width: transformedCopyViewInitialFrame.size.width / transformedSelfFrame.size.width, height: transformedCopyViewInitialFrame.size.height / transformedSelfFrame.size.height)
@@ -212,18 +256,27 @@ final class InstantImageGalleryItemNode: ZoomableContentGalleryItemNode {
intermediateCompletion() intermediateCompletion()
}) })
if let transformedSurfaceFrame = transformedSurfaceFrame, let transformedCopyViewInitialFrame = transformedSurfaceCopyViewInitialFrame {
surfaceCopyView.layer.animatePosition(from: CGPoint(x: transformedCopyViewInitialFrame.midX, y: transformedCopyViewInitialFrame.midY), to: CGPoint(x: transformedSurfaceFrame.midX, y: transformedSurfaceFrame.midY), duration: 0.25, timingFunction: kCAMediaTimingFunctionSpring, removeOnCompletion: false)
let scale = CGSize(width: transformedCopyViewInitialFrame.size.width / transformedSurfaceFrame.size.width, height: transformedCopyViewInitialFrame.size.height / transformedSurfaceFrame.size.height)
surfaceCopyView.layer.animate(from: NSValue(caTransform3D: CATransform3DMakeScale(scale.width, scale.height, 1.0)), to: NSValue(caTransform3D: CATransform3DIdentity), keyPath: "transform", timingFunction: kCAMediaTimingFunctionSpring, duration: 0.25, removeOnCompletion: false)
}
self.imageNode.layer.animatePosition(from: self.imageNode.layer.position, to: CGPoint(x: transformedSuperFrame.midX, y: transformedSuperFrame.midY), duration: 0.25, timingFunction: kCAMediaTimingFunctionSpring, removeOnCompletion: false, completion: { _ in self.imageNode.layer.animatePosition(from: self.imageNode.layer.position, to: CGPoint(x: transformedSuperFrame.midX, y: transformedSuperFrame.midY), duration: 0.25, timingFunction: kCAMediaTimingFunctionSpring, removeOnCompletion: false, completion: { _ in
positionCompleted = true positionCompleted = true
intermediateCompletion() intermediateCompletion()
}) })
self.imageNode.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.25, removeOnCompletion: false) self.imageNode.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.08, removeOnCompletion: false)
transformedFrame.origin = CGPoint() transformedFrame.origin = CGPoint()
self.imageNode.layer.animateBounds(from: self.imageNode.layer.bounds, to: transformedFrame, duration: 0.25, timingFunction: kCAMediaTimingFunctionSpring, removeOnCompletion: false, completion: { _ in self.imageNode.layer.animateBounds(from: self.imageNode.layer.bounds, to: transformedFrame, duration: 0.25, timingFunction: kCAMediaTimingFunctionSpring, removeOnCompletion: false, completion: { _ in
boundsCompleted = true boundsCompleted = true
intermediateCompletion() intermediateCompletion()
}) })
/*self.statusNodeContainer.layer.animatePosition(from: self.statusNodeContainer.position, to: CGPoint(x: transformedSuperFrame.midX, y: transformedSuperFrame.midY), duration: 0.25, timingFunction: kCAMediaTimingFunctionSpring, removeOnCompletion: false)
self.statusNodeContainer.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.15, timingFunction: kCAMediaTimingFunctionEaseIn, removeOnCompletion: false)*/
} }
override func visibilityUpdated(isVisible: Bool) { override func visibilityUpdated(isVisible: Bool) {

View File

@@ -1195,7 +1195,10 @@ final class InstantPageControllerNode: ASDisplayNode, UIScrollViewDelegate {
if let strongSelf = self { if let strongSelf = self {
for (_, itemNode) in strongSelf.visibleItemsWithNodes { for (_, itemNode) in strongSelf.visibleItemsWithNodes {
if let transitionNode = itemNode.transitionNode(media: entry.media) { if let transitionNode = itemNode.transitionNode(media: entry.media) {
return GalleryTransitionArguments(transitionNode: transitionNode, addToTransitionSurface: { _ in return GalleryTransitionArguments(transitionNode: transitionNode, addToTransitionSurface: { view in
if let strongSelf = self {
strongSelf.scrollNode.view.superview?.insertSubview(view, aboveSubview: strongSelf.scrollNode.view)
}
}) })
} }
} }

View File

@@ -29,9 +29,7 @@ private final class LegacyImagePickerController: LegacyController, TGLegacyCamer
} }
func legacyImagePicker(theme: PresentationTheme, completion: @escaping (UIImage?) -> Void) -> ViewController { func legacyImagePicker(theme: PresentationTheme, completion: @escaping (UIImage?) -> Void) -> ViewController {
var dismissImpl: (() -> Void)?
let legacyController = LegacyImagePickerController(presentation: .modal(animateIn: true), theme: theme, completion: { image in let legacyController = LegacyImagePickerController(presentation: .modal(animateIn: true), theme: theme, completion: { image in
dismissImpl?()
completion(image) completion(image)
}) })
@@ -41,9 +39,5 @@ func legacyImagePicker(theme: PresentationTheme, completion: @escaping (UIImage?
legacyController.bind(controller: imagePickerController) legacyController.bind(controller: imagePickerController)
dismissImpl = { [weak legacyController] in
legacyController?.dismiss()
}
return legacyController return legacyController
} }

View File

@@ -121,12 +121,14 @@ public struct AudioSessionActivationState {
public class ManagedAudioSessionControl { public class ManagedAudioSessionControl {
private let setupImpl: (Bool) -> Void private let setupImpl: (Bool) -> Void
private let activateImpl: (ManagedAudioSessionControlActivate) -> Void private let activateImpl: (ManagedAudioSessionControlActivate) -> Void
private let setupAndActivateImpl: (Bool, ManagedAudioSessionControlActivate) -> Void
private let setOutputModeImpl: (AudioSessionOutputMode) -> Void private let setOutputModeImpl: (AudioSessionOutputMode) -> Void
fileprivate init(setupImpl: @escaping (Bool) -> Void, activateImpl: @escaping (ManagedAudioSessionControlActivate) -> Void, setOutputModeImpl: @escaping (AudioSessionOutputMode) -> Void) { fileprivate init(setupImpl: @escaping (Bool) -> Void, activateImpl: @escaping (ManagedAudioSessionControlActivate) -> Void, setOutputModeImpl: @escaping (AudioSessionOutputMode) -> Void, setupAndActivateImpl: @escaping (Bool, ManagedAudioSessionControlActivate) -> Void) {
self.setupImpl = setupImpl self.setupImpl = setupImpl
self.activateImpl = activateImpl self.activateImpl = activateImpl
self.setOutputModeImpl = setOutputModeImpl self.setOutputModeImpl = setOutputModeImpl
self.setupAndActivateImpl = setupAndActivateImpl
} }
public func setup(synchronous: Bool = false) { public func setup(synchronous: Bool = false) {
@@ -137,6 +139,10 @@ public class ManagedAudioSessionControl {
self.activateImpl(ManagedAudioSessionControlActivate(completion)) self.activateImpl(ManagedAudioSessionControlActivate(completion))
} }
public func setupAndActivate(synchronous: Bool = false, _ completion: @escaping (AudioSessionActivationState) -> Void) {
self.setupAndActivateImpl(synchronous, ManagedAudioSessionControlActivate(completion))
}
public func setOutputMode(_ mode: AudioSessionOutputMode) { public func setOutputMode(_ mode: AudioSessionOutputMode) {
self.setOutputModeImpl(mode) self.setOutputModeImpl(mode)
} }
@@ -349,8 +355,7 @@ public final class ManagedAudioSession {
func push(audioSessionType: ManagedAudioSessionType, outputMode: AudioSessionOutputMode = .system, once: Bool = false, activate: @escaping (AudioSessionActivationState) -> Void, deactivate: @escaping () -> Signal<Void, NoError>) -> Disposable { func push(audioSessionType: ManagedAudioSessionType, outputMode: AudioSessionOutputMode = .system, once: Bool = false, activate: @escaping (AudioSessionActivationState) -> Void, deactivate: @escaping () -> Signal<Void, NoError>) -> Disposable {
return self.push(audioSessionType: audioSessionType, once: once, manualActivate: { control in return self.push(audioSessionType: audioSessionType, once: once, manualActivate: { control in
control.setup() control.setupAndActivate(synchronous: false, { state in
control.activate({ state in
activate(state) activate(state)
}) })
}, deactivate: deactivate) }, deactivate: deactivate)
@@ -361,21 +366,21 @@ public final class ManagedAudioSession {
let queue = self.queue let queue = self.queue
queue.async { queue.async {
self.holders.append(HolderRecord(id: id, audioSessionType: audioSessionType, control: ManagedAudioSessionControl(setupImpl: { [weak self] synchronous in self.holders.append(HolderRecord(id: id, audioSessionType: audioSessionType, control: ManagedAudioSessionControl(setupImpl: { [weak self] synchronous in
if let strongSelf = self { let f: () -> Void = {
let f: () -> Void = { if let strongSelf = self {
for holder in strongSelf.holders { for holder in strongSelf.holders {
if holder.id == id && holder.active { if holder.id == id && holder.active {
strongSelf.setup(type: audioSessionType, outputMode: holder.outputMode) strongSelf.setup(type: audioSessionType, outputMode: holder.outputMode, activateNow: false)
break break
} }
} }
} }
}
if synchronous {
strongSelf.queue.sync(f) if synchronous {
} else { queue.sync(f)
strongSelf.queue.async(f) } else {
} queue.async(f)
} }
}, activateImpl: { [weak self] completion in }, activateImpl: { [weak self] completion in
if let strongSelf = self { if let strongSelf = self {
@@ -405,6 +410,26 @@ public final class ManagedAudioSession {
} }
} }
} }
}, setupAndActivateImpl: { [weak self] synchronous, completion in
queue.async {
let f: () -> Void = {
if let strongSelf = self {
for holder in strongSelf.holders {
if holder.id == id && holder.active {
strongSelf.setup(type: audioSessionType, outputMode: holder.outputMode, activateNow: true)
completion.f(AudioSessionActivationState(isHeadsetConnected: strongSelf.isHeadsetPluggedInValue))
break
}
}
}
}
if synchronous {
queue.sync(f)
} else {
queue.async(f)
}
}
}), activate: { [weak self] state in }), activate: { [weak self] state in
manualActivate(state) manualActivate(state)
queue.async { queue.async {
@@ -575,7 +600,7 @@ public final class ManagedAudioSession {
} }
} }
private func setup(type: ManagedAudioSessionType, outputMode: AudioSessionOutputMode) { private func setup(type: ManagedAudioSessionType, outputMode: AudioSessionOutputMode, activateNow: Bool) {
self.deactivateTimer?.invalidate() self.deactivateTimer?.invalidate()
self.deactivateTimer = nil self.deactivateTimer = nil
@@ -600,9 +625,13 @@ public final class ManagedAudioSession {
case .record, .voiceCall: case .record, .voiceCall:
options.insert(.allowBluetooth) options.insert(.allowBluetooth)
} }
try AVAudioSession.sharedInstance().setCategory(nativeCategoryForType(type, headphones: self.isHeadsetPluggedInValue), with: options)
print("ManagedAudioSession setting active \(type != .none)") print("ManagedAudioSession setting active \(type != .none)")
try AVAudioSession.sharedInstance().setMode(type == .voiceCall ? AVAudioSessionModeVoiceChat : AVAudioSessionModeDefault) if #available(iOSApplicationExtension 11.0, *) {
try AVAudioSession.sharedInstance().setCategory(nativeCategoryForType(type, headphones: self.isHeadsetPluggedInValue), mode: type == .voiceCall ? AVAudioSessionModeVoiceChat : AVAudioSessionModeDefault, routeSharingPolicy: .default, options: options)
} else {
try AVAudioSession.sharedInstance().setCategory(nativeCategoryForType(type, headphones: self.isHeadsetPluggedInValue), with: options)
try AVAudioSession.sharedInstance().setMode(type == .voiceCall ? AVAudioSessionModeVoiceChat : AVAudioSessionModeDefault)
}
} catch let error { } catch let error {
print("ManagedAudioSession setup error \(error)") print("ManagedAudioSession setup error \(error)")
} }
@@ -618,6 +647,10 @@ public final class ManagedAudioSession {
subscriber(true) subscriber(true)
} }
} }
if activateNow {
self.activate()
}
} }
private func setupOutputMode(_ outputMode: AudioSessionOutputMode, type: ManagedAudioSessionType) throws { private func setupOutputMode(_ outputMode: AudioSessionOutputMode, type: ManagedAudioSessionType) throws {

View File

@@ -57,6 +57,7 @@ typedef NS_ENUM(int32_t, OngoingCallDataSaving) {
+ (void)setupLoggingFunction:(void (* _Nullable)(NSString * _Nullable))loggingFunction; + (void)setupLoggingFunction:(void (* _Nullable)(NSString * _Nullable))loggingFunction;
+ (void)applyServerConfig:(NSString * _Nullable)data; + (void)applyServerConfig:(NSString * _Nullable)data;
+ (int32_t)maxLayer;
@property (nonatomic, copy) void (^ _Nullable stateChanged)(OngoingCallState); @property (nonatomic, copy) void (^ _Nullable stateChanged)(OngoingCallState);
@property (nonatomic, copy) void (^ _Nullable callEnded)(NSString * _Nullable debugLog, int64_t bytesSentWifi, int64_t bytesReceivedWifi, int64_t bytesSentMobile, int64_t bytesReceivedMobile); @property (nonatomic, copy) void (^ _Nullable callEnded)(NSString * _Nullable debugLog, int64_t bytesSentWifi, int64_t bytesReceivedWifi, int64_t bytesSentMobile, int64_t bytesReceivedMobile);

View File

@@ -224,6 +224,10 @@ static int callControllerDataSavingForType(OngoingCallDataSaving type) {
} }
} }
+ (int32_t)maxLayer {
return tgvoip::VoIPController::connectionMaxLayer;
}
- (instancetype _Nonnull)initWithQueue:(id<OngoingCallThreadLocalContextQueue> _Nonnull)queue proxy:(VoipProxyServer * _Nullable)proxy networkType:(OngoingCallNetworkType)networkType dataSaving:(OngoingCallDataSaving)dataSaving { - (instancetype _Nonnull)initWithQueue:(id<OngoingCallThreadLocalContextQueue> _Nonnull)queue proxy:(VoipProxyServer * _Nullable)proxy networkType:(OngoingCallNetworkType)networkType dataSaving:(OngoingCallDataSaving)dataSaving {
self = [super init]; self = [super init];
if (self != nil) { if (self != nil) {

View File

@@ -205,7 +205,7 @@ public func openExternalUrl(account: Account, context: OpenURLContext = .generic
c.presentationArguments = a c.presentationArguments = a
account.telegramApplicationContext.applicationBindings.getWindowHost()?.present(c, on: .root, blockInteraction: false) account.telegramApplicationContext.applicationBindings.getWindowHost()?.present(c, on: .root, blockInteraction: false, completion: {})
}, dismissInput: { }, dismissInput: {
dismissInput() dismissInput()
}) })
@@ -436,7 +436,7 @@ public func openExternalUrl(account: Account, context: OpenURLContext = .generic
account.telegramApplicationContext.applicationBindings.dismissNativeController() account.telegramApplicationContext.applicationBindings.dismissNativeController()
navigationController.view.window?.endEditing(true) navigationController.view.window?.endEditing(true)
account.telegramApplicationContext.applicationBindings.getWindowHost()?.present(controller, on: .root, blockInteraction: false) account.telegramApplicationContext.applicationBindings.getWindowHost()?.present(controller, on: .root, blockInteraction: false, completion: {})
} }
} }
return return

View File

@@ -62,6 +62,10 @@ public final class PresentationCallManager {
private var callSettings: (VoiceCallSettings, VoipConfiguration)? private var callSettings: (VoiceCallSettings, VoipConfiguration)?
private var callSettingsDisposable: Disposable? private var callSettingsDisposable: Disposable?
public static var voipMaxLayer: Int32 {
return OngoingCallContext.
}
public init(account: Account, getDeviceAccessData: @escaping () -> (presentationData: PresentationData, present: (ViewController, Any?) -> Void, openSettings: () -> Void), networkType: Signal<NetworkType, NoError>, audioSession: ManagedAudioSession, callSessionManager: CallSessionManager) { public init(account: Account, getDeviceAccessData: @escaping () -> (presentationData: PresentationData, present: (ViewController, Any?) -> Void, openSettings: () -> Void), networkType: Signal<NetworkType, NoError>, audioSession: ManagedAudioSession, callSessionManager: CallSessionManager) {
self.account = account self.account = account
self.getDeviceAccessData = getDeviceAccessData self.getDeviceAccessData = getDeviceAccessData

View File

@@ -72,15 +72,30 @@ final class ThemeGridController: ViewController {
self?.present(controller, in: .window(.root), with: arguments, blockInteraction: true) self?.present(controller, in: .window(.root), with: arguments, blockInteraction: true)
}, selectCustomWallpaper: { [weak self] in }, selectCustomWallpaper: { [weak self] in
if let strongSelf = self { if let strongSelf = self {
strongSelf.present(legacyImagePicker(theme: strongSelf.presentationData.theme, completion: { image in var completionImpl: ((UIImage?) -> Void)?
if let strongSelf = self, let image = image { let legacyPicker = legacyImagePicker(theme: strongSelf.presentationData.theme, completion: { image in
strongSelf.present(legacyWallpaperEditor(theme: strongSelf.presentationData.theme, image: image, completion: { image in completionImpl?(image)
if let image = image { })
self?.applyCustomWallpaperImage(image) var lastPresentationTimestamp = 0.0
} completionImpl = { [weak legacyPicker] image in
}), in: .window(.root)) guard let strongSelf = self, let image = image else {
legacyPicker?.dismiss()
return
} }
}), in: .window(.root)) let timestamp = CACurrentMediaTime()
if timestamp < lastPresentationTimestamp + 1.0 {
return
}
lastPresentationTimestamp = timestamp
strongSelf.present(legacyWallpaperEditor(theme: strongSelf.presentationData.theme, image: image, completion: { image in
if let image = image {
self?.applyCustomWallpaperImage(image)
legacyPicker?.dismiss()
}
}), in: .window(.root))
}
strongSelf.present(legacyPicker, in: .window(.root), blockInteraction: true)
} }
}) })
self._ready.set(self.controllerNode.ready.get()) self._ready.set(self.controllerNode.ready.get())