diff --git a/TelegramUI/AuthorizationSequenceController.swift b/TelegramUI/AuthorizationSequenceController.swift index d7b5a0956f..48cd5a89a8 100644 --- a/TelegramUI/AuthorizationSequenceController.swift +++ b/TelegramUI/AuthorizationSequenceController.swift @@ -238,7 +238,7 @@ public final class AuthorizationSequenceController: NavigationController { let _ = (strongSelf.account.postbox.transaction { transaction -> Void in transaction.setState(UnauthorizedAccountState(isTestingEnvironment: account.testingEnvironment, masterDatacenterId: account.masterDatacenterId, contents: .empty)) }).start() - })]), on: .root, blockInteraction: false) + })]), on: .root, blockInteraction: false, completion: {}) }) ], actionLayout: .vertical) contentNode.textAttributeAction = (NSAttributedStringKey(rawValue: TelegramTextAttributes.URL), { value in @@ -251,7 +251,7 @@ public final class AuthorizationSequenceController: NavigationController { controller?.dismissAnimated() } strongSelf.view.endEditing(true) - strongSelf.currentWindow?.present(controller, on: .root, blockInteraction: false) + strongSelf.currentWindow?.present(controller, on: .root, blockInteraction: false, completion: {}) } presentAlertAgainImpl = { presentAlertImpl() diff --git a/TelegramUI/ChatMediaInputNode.swift b/TelegramUI/ChatMediaInputNode.swift index 50b32b48f8..8ef26f2f9c 100644 --- a/TelegramUI/ChatMediaInputNode.swift +++ b/TelegramUI/ChatMediaInputNode.swift @@ -88,7 +88,20 @@ private func preparedChatMediaInputGridEntryTransition(account: Account, view: I } else if !toEntries.isEmpty { if let collectionId = collectionId { 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 if !fromEntries.isEmpty && fromEntries[0].index < toEntries[i].index { directionHint = .down @@ -537,49 +550,49 @@ final class ChatMediaInputNode: ChatInputNode { self.addSubnode(self.collectionListContainer) let itemCollectionsView = self.itemCollectionsViewPosition.get() - |> distinctUntilChanged - |> mapToSignal { position -> Signal<(ItemCollectionsView, StickerPacksCollectionUpdate), NoError> in - switch position { - case .initial: - var firstTime = true - return account.postbox.itemCollectionsView(orderedItemListCollectionIds: [Namespaces.OrderedItemList.CloudSavedStickers, Namespaces.OrderedItemList.CloudRecentStickers], namespaces: [Namespaces.ItemCollection.CloudStickerPacks], aroundIndex: nil, count: 50) - |> map { view -> (ItemCollectionsView, StickerPacksCollectionUpdate) in - let update: StickerPacksCollectionUpdate - if firstTime { - firstTime = false - update = .initial - } else { - 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) + |> distinctUntilChanged + |> mapToSignal { position -> Signal<(ItemCollectionsView, StickerPacksCollectionUpdate), NoError> in + switch position { + case .initial: + var firstTime = true + return account.postbox.itemCollectionsView(orderedItemListCollectionIds: [Namespaces.OrderedItemList.CloudSavedStickers, Namespaces.OrderedItemList.CloudRecentStickers], namespaces: [Namespaces.ItemCollection.CloudStickerPacks], aroundIndex: nil, count: 50) + |> map { view -> (ItemCollectionsView, StickerPacksCollectionUpdate) in + let update: StickerPacksCollectionUpdate + if firstTime { + firstTime = false + update = .initial + } else { + 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) + } + } } let previousEntries = Atomic<([ChatMediaInputPanelEntry], [ChatMediaInputGridEntry])>(value: ([], [])) @@ -666,8 +679,12 @@ final class ChatMediaInputNode: ChatInputNode { if let topVisibleSection = visibleItems.topSectionVisible as? ChatMediaInputStickerGridSection { topVisibleCollectionId = topVisibleSection.collectionId - } else if let topVisible = visibleItems.topVisible, let item = topVisible.1 as? ChatMediaInputStickerGridItem { - topVisibleCollectionId = item.index.collectionId + } else if let topVisible = visibleItems.topVisible { + 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 strongSelf.inputNodeInteraction.highlightedItemCollectionId != collectionId { diff --git a/TelegramUI/InstantImageGalleryItem.swift b/TelegramUI/InstantImageGalleryItem.swift index 1247483967..48f063bc78 100644 --- a/TelegramUI/InstantImageGalleryItem.swift +++ b/TelegramUI/InstantImageGalleryItem.swift @@ -161,27 +161,59 @@ final class InstantImageGalleryItemNode: ZoomableContentGalleryItemNode { 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 surfaceCopyView = 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) 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.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) 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) transformedFrame.origin = CGPoint() 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) { + self.fetchDisposable.set(nil) + 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 transformedSelfFrame = node.0.view.convert(node.0.view.bounds, to: self.view) @@ -192,18 +224,30 @@ final class InstantImageGalleryItemNode: ZoomableContentGalleryItemNode { var copyCompleted = false 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) copyView.frame = transformedSelfFrame - let intermediateCompletion = { [weak copyView] in + let intermediateCompletion = { [weak copyView, weak surfaceCopyView] in if positionCompleted && boundsCompleted && copyCompleted { copyView?.removeFromSuperview() + surfaceCopyView?.removeFromSuperview() 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) 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() }) + 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 positionCompleted = true 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() self.imageNode.layer.animateBounds(from: self.imageNode.layer.bounds, to: transformedFrame, duration: 0.25, timingFunction: kCAMediaTimingFunctionSpring, removeOnCompletion: false, completion: { _ in boundsCompleted = true 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) { diff --git a/TelegramUI/InstantPageControllerNode.swift b/TelegramUI/InstantPageControllerNode.swift index 5998630bda..0c31b4abed 100644 --- a/TelegramUI/InstantPageControllerNode.swift +++ b/TelegramUI/InstantPageControllerNode.swift @@ -1195,7 +1195,10 @@ final class InstantPageControllerNode: ASDisplayNode, UIScrollViewDelegate { if let strongSelf = self { for (_, itemNode) in strongSelf.visibleItemsWithNodes { 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) + } }) } } diff --git a/TelegramUI/LegacyImagePicker.swift b/TelegramUI/LegacyImagePicker.swift index d2bbb12a21..f1a8d25a84 100644 --- a/TelegramUI/LegacyImagePicker.swift +++ b/TelegramUI/LegacyImagePicker.swift @@ -29,9 +29,7 @@ private final class LegacyImagePickerController: LegacyController, TGLegacyCamer } func legacyImagePicker(theme: PresentationTheme, completion: @escaping (UIImage?) -> Void) -> ViewController { - var dismissImpl: (() -> Void)? let legacyController = LegacyImagePickerController(presentation: .modal(animateIn: true), theme: theme, completion: { image in - dismissImpl?() completion(image) }) @@ -41,9 +39,5 @@ func legacyImagePicker(theme: PresentationTheme, completion: @escaping (UIImage? legacyController.bind(controller: imagePickerController) - dismissImpl = { [weak legacyController] in - legacyController?.dismiss() - } - return legacyController } diff --git a/TelegramUI/ManagedAudioSession.swift b/TelegramUI/ManagedAudioSession.swift index c0102ae4e3..ce802a0a31 100644 --- a/TelegramUI/ManagedAudioSession.swift +++ b/TelegramUI/ManagedAudioSession.swift @@ -121,12 +121,14 @@ public struct AudioSessionActivationState { public class ManagedAudioSessionControl { private let setupImpl: (Bool) -> Void private let activateImpl: (ManagedAudioSessionControlActivate) -> Void + private let setupAndActivateImpl: (Bool, ManagedAudioSessionControlActivate) -> 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.activateImpl = activateImpl self.setOutputModeImpl = setOutputModeImpl + self.setupAndActivateImpl = setupAndActivateImpl } public func setup(synchronous: Bool = false) { @@ -137,6 +139,10 @@ public class ManagedAudioSessionControl { self.activateImpl(ManagedAudioSessionControlActivate(completion)) } + public func setupAndActivate(synchronous: Bool = false, _ completion: @escaping (AudioSessionActivationState) -> Void) { + self.setupAndActivateImpl(synchronous, ManagedAudioSessionControlActivate(completion)) + } + public func setOutputMode(_ mode: AudioSessionOutputMode) { 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) -> Disposable { return self.push(audioSessionType: audioSessionType, once: once, manualActivate: { control in - control.setup() - control.activate({ state in + control.setupAndActivate(synchronous: false, { state in activate(state) }) }, deactivate: deactivate) @@ -361,21 +366,21 @@ public final class ManagedAudioSession { let queue = self.queue queue.async { 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 { if holder.id == id && holder.active { - strongSelf.setup(type: audioSessionType, outputMode: holder.outputMode) + strongSelf.setup(type: audioSessionType, outputMode: holder.outputMode, activateNow: false) break } } } - - if synchronous { - strongSelf.queue.sync(f) - } else { - strongSelf.queue.async(f) - } + } + + if synchronous { + queue.sync(f) + } else { + queue.async(f) } }, activateImpl: { [weak self] completion in 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 manualActivate(state) 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 = nil @@ -600,9 +625,13 @@ public final class ManagedAudioSession { case .record, .voiceCall: options.insert(.allowBluetooth) } - try AVAudioSession.sharedInstance().setCategory(nativeCategoryForType(type, headphones: self.isHeadsetPluggedInValue), with: options) 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 { print("ManagedAudioSession setup error \(error)") } @@ -618,6 +647,10 @@ public final class ManagedAudioSession { subscriber(true) } } + + if activateNow { + self.activate() + } } private func setupOutputMode(_ outputMode: AudioSessionOutputMode, type: ManagedAudioSessionType) throws { diff --git a/TelegramUI/OngoingCallThreadLocalContext.h b/TelegramUI/OngoingCallThreadLocalContext.h index 66985d6a33..4d1efb9a8c 100644 --- a/TelegramUI/OngoingCallThreadLocalContext.h +++ b/TelegramUI/OngoingCallThreadLocalContext.h @@ -57,6 +57,7 @@ typedef NS_ENUM(int32_t, OngoingCallDataSaving) { + (void)setupLoggingFunction:(void (* _Nullable)(NSString * _Nullable))loggingFunction; + (void)applyServerConfig:(NSString * _Nullable)data; ++ (int32_t)maxLayer; @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); diff --git a/TelegramUI/OngoingCallThreadLocalContext.mm b/TelegramUI/OngoingCallThreadLocalContext.mm index c91358c418..8a37502037 100644 --- a/TelegramUI/OngoingCallThreadLocalContext.mm +++ b/TelegramUI/OngoingCallThreadLocalContext.mm @@ -224,6 +224,10 @@ static int callControllerDataSavingForType(OngoingCallDataSaving type) { } } ++ (int32_t)maxLayer { + return tgvoip::VoIPController::connectionMaxLayer; +} + - (instancetype _Nonnull)initWithQueue:(id _Nonnull)queue proxy:(VoipProxyServer * _Nullable)proxy networkType:(OngoingCallNetworkType)networkType dataSaving:(OngoingCallDataSaving)dataSaving { self = [super init]; if (self != nil) { diff --git a/TelegramUI/OpenUrl.swift b/TelegramUI/OpenUrl.swift index b1d2d59538..9f1971236f 100644 --- a/TelegramUI/OpenUrl.swift +++ b/TelegramUI/OpenUrl.swift @@ -205,7 +205,7 @@ public func openExternalUrl(account: Account, context: OpenURLContext = .generic 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() }) @@ -436,7 +436,7 @@ public func openExternalUrl(account: Account, context: OpenURLContext = .generic account.telegramApplicationContext.applicationBindings.dismissNativeController() 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 diff --git a/TelegramUI/PresentationCallManager.swift b/TelegramUI/PresentationCallManager.swift index 845c48d608..d00d933d15 100644 --- a/TelegramUI/PresentationCallManager.swift +++ b/TelegramUI/PresentationCallManager.swift @@ -62,6 +62,10 @@ public final class PresentationCallManager { private var callSettings: (VoiceCallSettings, VoipConfiguration)? 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, audioSession: ManagedAudioSession, callSessionManager: CallSessionManager) { self.account = account self.getDeviceAccessData = getDeviceAccessData diff --git a/TelegramUI/ThemeGridController.swift b/TelegramUI/ThemeGridController.swift index 75157779a7..581adb3f80 100644 --- a/TelegramUI/ThemeGridController.swift +++ b/TelegramUI/ThemeGridController.swift @@ -72,15 +72,30 @@ final class ThemeGridController: ViewController { self?.present(controller, in: .window(.root), with: arguments, blockInteraction: true) }, selectCustomWallpaper: { [weak self] in if let strongSelf = self { - strongSelf.present(legacyImagePicker(theme: strongSelf.presentationData.theme, completion: { image in - if let strongSelf = self, let image = image { - strongSelf.present(legacyWallpaperEditor(theme: strongSelf.presentationData.theme, image: image, completion: { image in - if let image = image { - self?.applyCustomWallpaperImage(image) - } - }), in: .window(.root)) + var completionImpl: ((UIImage?) -> Void)? + let legacyPicker = legacyImagePicker(theme: strongSelf.presentationData.theme, completion: { image in + completionImpl?(image) + }) + var lastPresentationTimestamp = 0.0 + completionImpl = { [weak legacyPicker] image in + 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())