diff --git a/submodules/ChatListUI/Sources/ChatListController.swift b/submodules/ChatListUI/Sources/ChatListController.swift index e8de89cdf3..8332b4dc0d 100644 --- a/submodules/ChatListUI/Sources/ChatListController.swift +++ b/submodules/ChatListUI/Sources/ChatListController.swift @@ -302,7 +302,7 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController let previousEditingAndNetworkState = previousEditingAndNetworkStateValue.swap((stateAndFilterId.state.editing, networkState)) if stateAndFilterId.state.editing { if strongSelf.groupId == .root { - strongSelf.navigationItem.rightBarButtonItem = nil + strongSelf.navigationItem.setRightBarButton(nil, animated: true) } let title = !stateAndFilterId.state.selectedPeerIds.isEmpty ? strongSelf.presentationData.strings.ChatList_SelectedChats(Int32(stateAndFilterId.state.selectedPeerIds.count)) : defaultTitle @@ -315,10 +315,10 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController strongSelf.titleView.setTitle(NetworkStatusTitle(text: title, activity: false, hasProxy: false, connectsViaProxy: false, isPasscodeSet: false, isManuallyLocked: false), animated: animated) } else if isReorderingTabs { if strongSelf.groupId == .root { - strongSelf.navigationItem.rightBarButtonItem = nil + strongSelf.navigationItem.setRightBarButton(nil, animated: true) } let leftBarButtonItem = UIBarButtonItem(title: strongSelf.presentationData.strings.Common_Done, style: .done, target: strongSelf, action: #selector(strongSelf.reorderingDonePressed)) - strongSelf.navigationItem.leftBarButtonItem = leftBarButtonItem + strongSelf.navigationItem.setLeftBarButton(leftBarButtonItem, animated: true) let (_, connectsViaProxy) = proxy switch networkState { @@ -341,16 +341,21 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController isRoot = true if isReorderingTabs { - strongSelf.navigationItem.rightBarButtonItem = nil + strongSelf.navigationItem.setRightBarButton(nil, animated: true) } else { let rightBarButtonItem = UIBarButtonItem(image: PresentationResourcesRootController.navigationComposeIcon(strongSelf.presentationData.theme), style: .plain, target: strongSelf, action: #selector(strongSelf.composePressed)) rightBarButtonItem.accessibilityLabel = strongSelf.presentationData.strings.VoiceOver_Navigation_Compose - strongSelf.navigationItem.rightBarButtonItem = rightBarButtonItem + if strongSelf.navigationItem.rightBarButtonItem?.accessibilityLabel != rightBarButtonItem.accessibilityLabel { + strongSelf.navigationItem.setRightBarButton(rightBarButtonItem, animated: true) + } } if isReorderingTabs { let leftBarButtonItem = UIBarButtonItem(title: strongSelf.presentationData.strings.Common_Done, style: .done, target: strongSelf, action: #selector(strongSelf.reorderingDonePressed)) - strongSelf.navigationItem.leftBarButtonItem = leftBarButtonItem + leftBarButtonItem.accessibilityLabel = strongSelf.presentationData.strings.Common_Done + if strongSelf.navigationItem.leftBarButtonItem?.accessibilityLabel != leftBarButtonItem.accessibilityLabel { + strongSelf.navigationItem.setLeftBarButton(leftBarButtonItem, animated: true) + } } else { let editItem: UIBarButtonItem if stateAndFilterId.state.editing { @@ -360,7 +365,9 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController editItem = UIBarButtonItem(title: strongSelf.presentationData.strings.Common_Edit, style: .plain, target: self, action: #selector(strongSelf.editPressed)) editItem.accessibilityLabel = strongSelf.presentationData.strings.Common_Edit } - strongSelf.navigationItem.leftBarButtonItem = editItem + if strongSelf.navigationItem.leftBarButtonItem?.accessibilityLabel != editItem.accessibilityLabel { + strongSelf.navigationItem.setLeftBarButton(editItem, animated: true) + } } } @@ -904,6 +911,7 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController } } + let previousToolbarValue = Atomic(value: nil) self.stateDisposable.set(combineLatest(queue: .mainQueue(), self.presentationDataValue.get(), peerIdsAndOptions @@ -954,7 +962,12 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController toolbar = Toolbar(leftAction: leftAction, rightAction: ToolbarAction(title: presentationData.strings.Common_Delete, isEnabled: options.delete), middleAction: middleAction) } } - strongSelf.setToolbar(toolbar, transition: .animated(duration: 0.3, curve: .easeInOut)) + var transition: ContainedViewLayoutTransition = .immediate + let previousToolbar = previousToolbarValue.swap(toolbar) + if (previousToolbar == nil) != (toolbar == nil) { + transition = .animated(duration: 0.3, curve: .easeInOut) + } + strongSelf.setToolbar(toolbar, transition: transition) })) self.tabContainerNode.tabSelected = { [weak self] id in @@ -1445,13 +1458,6 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController @objc private func donePressed() { self.reorderingDonePressed() - let editItem = UIBarButtonItem(title: self.presentationData.strings.Common_Edit, style: .plain, target: self, action: #selector(self.editPressed)) - editItem.accessibilityLabel = self.presentationData.strings.Common_Edit - if case .root = self.groupId, self.filter == nil { - self.navigationItem.setLeftBarButton(editItem, animated: true) - } else { - self.navigationItem.setRightBarButton(editItem, animated: true) - } (self.navigationController as? NavigationController)?.updateMasterDetailsBlackout(nil, transition: .animated(duration: 0.4, curve: .spring)) self.searchContentNode?.setIsEnabled(true, animated: true) self.chatListDisplayNode.didBeginSelectingChatsWhileEditing = false diff --git a/submodules/Display/Source/NavigationBar.swift b/submodules/Display/Source/NavigationBar.swift index 8becd387a4..90571ae6e4 100644 --- a/submodules/Display/Source/NavigationBar.swift +++ b/submodules/Display/Source/NavigationBar.swift @@ -1,6 +1,8 @@ import UIKit import AsyncDisplayKit +private let titleFont = Font.with(size: 17.0, design: .regular, weight: .semibold, traits: [.monospacedNumbers]) + private var backArrowImageCache: [Int32: UIImage] = [:] class SparseNode: ASDisplayNode { @@ -269,7 +271,7 @@ open class NavigationBar: ASDisplayNode { private var title: String? { didSet { if let title = self.title { - self.titleNode.attributedText = NSAttributedString(string: title, font: Font.semibold(17.0), textColor: self.presentationData.theme.primaryTextColor) + self.titleNode.attributedText = NSAttributedString(string: title, font: titleFont, textColor: self.presentationData.theme.primaryTextColor) self.titleNode.accessibilityLabel = title if self.titleNode.supernode == nil { self.buttonsContainerNode.addSubnode(self.titleNode) @@ -744,7 +746,7 @@ open class NavigationBar: ASDisplayNode { self.rightButtonNode.rippleColor = self.presentationData.theme.primaryTextColor.withAlphaComponent(0.05) self.backButtonArrow.image = backArrowImage(color: self.presentationData.theme.buttonColor) if let title = self.title { - self.titleNode.attributedText = NSAttributedString(string: title, font: Font.semibold(17.0), textColor: self.presentationData.theme.primaryTextColor) + self.titleNode.attributedText = NSAttributedString(string: title, font: titleFont, textColor: self.presentationData.theme.primaryTextColor) self.titleNode.accessibilityLabel = title } self.stripeNode.backgroundColor = self.presentationData.theme.separatorColor @@ -820,7 +822,7 @@ open class NavigationBar: ASDisplayNode { self.rightButtonNode.rippleColor = self.presentationData.theme.primaryTextColor.withAlphaComponent(0.05) self.backButtonArrow.image = backArrowImage(color: self.presentationData.theme.buttonColor) if let title = self.title { - self.titleNode.attributedText = NSAttributedString(string: title, font: Font.semibold(17.0), textColor: self.presentationData.theme.primaryTextColor) + self.titleNode.attributedText = NSAttributedString(string: title, font: titleFont, textColor: self.presentationData.theme.primaryTextColor) self.titleNode.accessibilityLabel = title } self.stripeNode.backgroundColor = self.presentationData.theme.separatorColor @@ -1079,7 +1081,7 @@ open class NavigationBar: ASDisplayNode { } } else if let title = self.title { let node = ImmediateTextNode() - node.attributedText = NSAttributedString(string: title, font: Font.semibold(17.0), textColor: foregroundColor) + node.attributedText = NSAttributedString(string: title, font: titleFont, textColor: foregroundColor) return node } else { return nil diff --git a/submodules/GalleryUI/Sources/ChatItemGalleryFooterContentNode.swift b/submodules/GalleryUI/Sources/ChatItemGalleryFooterContentNode.swift index e7852ee034..e90f3321b2 100644 --- a/submodules/GalleryUI/Sources/ChatItemGalleryFooterContentNode.swift +++ b/submodules/GalleryUI/Sources/ChatItemGalleryFooterContentNode.swift @@ -154,6 +154,8 @@ final class ChatItemGalleryFooterContentNode: GalleryFooterContentNode, UIScroll var setPlayRate: ((Double) -> Void)? var fetchControl: (() -> Void)? + var interacting: ((Bool) -> Void)? + private var seekTimer: SwiftSignalKit.Timer? private var currentIsPaused: Bool = true private var seekRate: Double = 1.0 @@ -892,6 +894,8 @@ final class ChatItemGalleryFooterContentNode: GalleryFooterContentNode, UIScroll if messages.count == 1 { strongSelf.commitDeleteMessages(messages, ask: true) } else { + strongSelf.interacting?(true) + var presentationData = strongSelf.context.sharedContext.currentPresentationData.with { $0 } if !presentationData.theme.overallDarkAppearance { presentationData = presentationData.withUpdated(theme: defaultDarkColorPresentationTheme) @@ -930,8 +934,10 @@ final class ChatItemGalleryFooterContentNode: GalleryFooterContentNode, UIScroll } } - let actionSheet = ActionSheetController(presentationData: presentationData) + actionSheet.dismissed = { [weak self] _ in + self?.interacting?(false) + } let items: [ActionSheetItem] = [ ActionSheetButtonItem(title: singleText, color: .destructive, action: { [weak actionSheet] in actionSheet?.dismissAnimated() @@ -1012,6 +1018,10 @@ final class ChatItemGalleryFooterContentNode: GalleryFooterContentNode, UIScroll let _ = deleteMessagesInteractively(account: strongSelf.context.account, messageIds: messages.map { $0.id }, type: .forEveryone).start() strongSelf.controllerInteraction?.dismissController() } else if !items.isEmpty { + strongSelf.interacting?(true) + actionSheet.dismissed = { [weak self] _ in + self?.interacting?(false) + } actionSheet.setItemGroups([ActionSheetItemGroup(items: items), ActionSheetItemGroup(items: [ ActionSheetButtonItem(title: strongSelf.strings.Common_Cancel, color: .accent, font: .bold, action: { [weak actionSheet] in actionSheet?.dismissAnimated() @@ -1024,13 +1034,17 @@ final class ChatItemGalleryFooterContentNode: GalleryFooterContentNode, UIScroll } @objc func actionButtonPressed() { + self.interacting?(true) + if let currentMessage = self.currentMessage { let _ = (self.context.account.postbox.transaction { transaction -> [Message] in return transaction.getMessageGroup(currentMessage.id) ?? [] } |> deliverOnMainQueue).start(next: { [weak self] messages in if let strongSelf = self, !messages.isEmpty { var presentationData = strongSelf.context.sharedContext.currentPresentationData.with { $0 } + var forceTheme: PresentationTheme? if !presentationData.theme.overallDarkAppearance { + forceTheme = defaultDarkColorPresentationTheme presentationData = presentationData.withUpdated(theme: defaultDarkColorPresentationTheme) } var generalMessageContentKind: MessageContentKind? @@ -1109,7 +1123,10 @@ final class ChatItemGalleryFooterContentNode: GalleryFooterContentNode, UIScroll } } } - let shareController = ShareController(context: strongSelf.context, subject: subject, preferredAction: preferredAction, forcedTheme: presentationData.theme.overallDarkAppearance ? nil : defaultDarkColorPresentationTheme) + let shareController = ShareController(context: strongSelf.context, subject: subject, preferredAction: preferredAction, forceTheme: forceTheme) + shareController.dismissed = { [weak self] _ in + self?.interacting?(false) + } shareController.completed = { [weak self] peerIds in if let strongSelf = self { let _ = (strongSelf.context.account.postbox.transaction { transaction -> [Peer] in @@ -1170,7 +1187,10 @@ final class ChatItemGalleryFooterContentNode: GalleryFooterContentNode, UIScroll let shareAction: ([Message]) -> Void = { messages in if let strongSelf = self { - let shareController = ShareController(context: strongSelf.context, subject: .messages(messages), preferredAction: preferredAction, forcedTheme: presentationData.theme.overallDarkAppearance ? nil : defaultDarkColorPresentationTheme) + let shareController = ShareController(context: strongSelf.context, subject: .messages(messages), preferredAction: preferredAction, forceTheme: forceTheme) + shareController.dismissed = { [weak self] _ in + self?.interacting?(false) + } shareController.completed = { [weak self] peerIds in if let strongSelf = self { let _ = (strongSelf.context.account.postbox.transaction { transaction -> [Peer] in @@ -1240,7 +1260,9 @@ final class ChatItemGalleryFooterContentNode: GalleryFooterContentNode, UIScroll }) } else if let (webPage, media) = self.currentWebPageAndMedia { var presentationData = self.context.sharedContext.currentPresentationData.with { $0 } + var forceTheme: PresentationTheme? if !presentationData.theme.overallDarkAppearance { + forceTheme = defaultDarkColorPresentationTheme presentationData = presentationData.withUpdated(theme: defaultDarkColorPresentationTheme) } @@ -1265,7 +1287,7 @@ final class ChatItemGalleryFooterContentNode: GalleryFooterContentNode, UIScroll if availableOpenInOptions(context: self.context, item: item).count > 1 { preferredAction = .custom(action: ShareControllerAction(title: presentationData.strings.Conversation_FileOpenIn, action: { [weak self] in if let strongSelf = self { - let openInController = OpenInActionSheetController(context: strongSelf.context, forceTheme: presentationData.theme.overallDarkAppearance ? nil : defaultDarkColorPresentationTheme, item: item, additionalAction: nil, openUrl: { [weak self] url in + let openInController = OpenInActionSheetController(context: strongSelf.context, forceTheme: forceTheme, item: item, additionalAction: nil, openUrl: { [weak self] url in if let strongSelf = self { strongSelf.context.sharedContext.openExternalUrl(context: strongSelf.context, urlContext: .generic, url: url, forceExternal: true, presentationData: presentationData, navigationController: nil, dismissInput: {}) } @@ -1290,7 +1312,10 @@ final class ChatItemGalleryFooterContentNode: GalleryFooterContentNode, UIScroll } } } - let shareController = ShareController(context: self.context, subject: subject, preferredAction: preferredAction, forcedTheme: presentationData.theme.overallDarkAppearance ? nil : defaultDarkColorPresentationTheme) + let shareController = ShareController(context: self.context, subject: subject, preferredAction: preferredAction, forceTheme: forceTheme) + shareController.dismissed = { [weak self] _ in + self?.interacting?(false) + } shareController.completed = { [weak self] peerIds in if let strongSelf = self { let _ = (strongSelf.context.account.postbox.transaction { transaction -> [Peer] in diff --git a/submodules/GalleryUI/Sources/ChatVideoGalleryItemScrubberView.swift b/submodules/GalleryUI/Sources/ChatVideoGalleryItemScrubberView.swift index 6cceda05ee..6d4911f440 100644 --- a/submodules/GalleryUI/Sources/ChatVideoGalleryItemScrubberView.swift +++ b/submodules/GalleryUI/Sources/ChatVideoGalleryItemScrubberView.swift @@ -120,7 +120,7 @@ final class ChatVideoGalleryItemScrubberView: UIView { self.fetchStatusDisposable.dispose() } - var collapsed: Bool = false + var collapsed: Bool? func setCollapsed(_ collapsed: Bool, animated: Bool) { guard self.collapsed != collapsed else { return @@ -128,15 +128,14 @@ final class ChatVideoGalleryItemScrubberView: UIView { self.collapsed = collapsed - guard let (size, _, _) = self.containerLayout else { - return - } - let alpha: CGFloat = collapsed ? 0.0 : 1.0 self.leftTimestampNode.alpha = alpha self.rightTimestampNode.alpha = alpha - self.infoNode.alpha = size.width < size.height && !self.collapsed ? 1.0 : 0.0 self.updateScrubberVisibility(animated: animated) + + if let (size, _, _) = self.containerLayout { + self.infoNode.alpha = size.width < size.height && !collapsed ? 1.0 : 0.0 + } } private func updateScrubberVisibility(animated: Bool) { @@ -144,10 +143,10 @@ final class ChatVideoGalleryItemScrubberView: UIView { var alpha: CGFloat = 1.0 if let playbackStatus = self.playbackStatus, playbackStatus.duration <= 30.0 { } else { - alpha = self.collapsed ? 0.0 : 1.0 + alpha = self.collapsed == true ? 0.0 : 1.0 collapsed = false } - self.scrubberNode.setCollapsed(collapsed, animated: animated) + self.scrubberNode.setCollapsed(collapsed == true, animated: animated) let transition: ContainedViewLayoutTransition = animated ? .animated(duration: 0.3, curve: .linear) : .immediate transition.updateAlpha(node: self.scrubberNode, alpha: alpha) } @@ -285,7 +284,7 @@ final class ChatVideoGalleryItemScrubberView: UIView { let infoSize = self.infoNode.measure(infoConstrainedSize) self.infoNode.bounds = CGRect(origin: CGPoint(), size: infoSize) transition.updatePosition(node: self.infoNode, position: CGPoint(x: size.width / 2.0, y: infoOffset + infoSize.height / 2.0)) - self.infoNode.alpha = size.width < size.height && !self.collapsed ? 1.0 : 0.0 + self.infoNode.alpha = size.width < size.height && self.collapsed == false ? 1.0 : 0.0 self.scrubberNode.frame = CGRect(origin: CGPoint(x: scrubberInset, y: 6.0), size: CGSize(width: size.width - leftInset - rightInset - scrubberInset * 2.0, height: scrubberHeight)) } diff --git a/submodules/GalleryUI/Sources/GalleryFooterNode.swift b/submodules/GalleryUI/Sources/GalleryFooterNode.swift index c72b8b83f2..95acee8794 100644 --- a/submodules/GalleryUI/Sources/GalleryFooterNode.swift +++ b/submodules/GalleryUI/Sources/GalleryFooterNode.swift @@ -6,6 +6,7 @@ import Display public final class GalleryFooterNode: ASDisplayNode { private let backgroundNode: ASDisplayNode + private var currentThumbnailPanelHeight: CGFloat? private var currentFooterContentNode: GalleryFooterContentNode? private var currentOverlayContentNode: GalleryOverlayContentNode? private var currentLayout: (ContainerViewLayout, CGFloat, Bool)? @@ -36,11 +37,16 @@ public final class GalleryFooterNode: ASDisplayNode { let cleanInsets = layout.insets(options: []) var dismissedCurrentFooterContentNode: GalleryFooterContentNode? + var dismissedThumbnailPanelHeight: CGFloat? if self.currentFooterContentNode !== footerContentNode { if let currentFooterContentNode = self.currentFooterContentNode { currentFooterContentNode.requestLayout = nil dismissedCurrentFooterContentNode = currentFooterContentNode } + if let currentThumbnailPanelHeight = self.currentThumbnailPanelHeight { + dismissedThumbnailPanelHeight = currentThumbnailPanelHeight + } + self.currentThumbnailPanelHeight = thumbnailPanelHeight self.currentFooterContentNode = footerContentNode if let footerContentNode = footerContentNode { footerContentNode.setVisibilityAlpha(self.visibilityAlpha, animated: transition.isAnimated) @@ -68,10 +74,11 @@ public final class GalleryFooterNode: ASDisplayNode { } } + let effectiveThumbnailPanelHeight = self.currentThumbnailPanelHeight ?? thumbnailPanelHeight var backgroundHeight: CGFloat = 0.0 - let verticalOffset: CGFloat = isHidden ? (layout.size.width > layout.size.height ? 44.0 : (thumbnailPanelHeight > 0.0 ? 106.0 : 54.0)) : 0.0 + let verticalOffset: CGFloat = isHidden ? (layout.size.width > layout.size.height ? 44.0 : (effectiveThumbnailPanelHeight > 0.0 ? 106.0 : 54.0)) : 0.0 if let footerContentNode = self.currentFooterContentNode { - backgroundHeight = footerContentNode.updateLayout(size: layout.size, metrics: layout.metrics, leftInset: layout.safeInsets.left, rightInset: layout.safeInsets.right, bottomInset: cleanInsets.bottom, contentInset: thumbnailPanelHeight, transition: transition) + backgroundHeight = footerContentNode.updateLayout(size: layout.size, metrics: layout.metrics, leftInset: layout.safeInsets.left, rightInset: layout.safeInsets.right, bottomInset: cleanInsets.bottom, contentInset: effectiveThumbnailPanelHeight, transition: transition) transition.updateFrame(node: footerContentNode, frame: CGRect(origin: CGPoint(x: 0.0, y: layout.size.height - backgroundHeight + verticalOffset), size: CGSize(width: layout.size.width, height: backgroundHeight))) if let dismissedCurrentFooterContentNode = dismissedCurrentFooterContentNode { let contentTransition = ContainedViewLayoutTransition.animated(duration: 0.4, curve: .spring) diff --git a/submodules/GalleryUI/Sources/Items/UniversalVideoGalleryItem.swift b/submodules/GalleryUI/Sources/Items/UniversalVideoGalleryItem.swift index 2b296b8ebc..59ef265a6a 100644 --- a/submodules/GalleryUI/Sources/Items/UniversalVideoGalleryItem.swift +++ b/submodules/GalleryUI/Sources/Items/UniversalVideoGalleryItem.swift @@ -205,7 +205,9 @@ private final class UniversalVideoGalleryItemOverlayNode: GalleryOverlayContentN } override func animateIn(previousContentNode: GalleryOverlayContentNode?, transition: ContainedViewLayoutTransition) { - transition.updateAlpha(node: self.wrapperNode, alpha: 1.0) + if !self.visibilityAlpha.isZero { + transition.updateAlpha(node: self.wrapperNode, alpha: 1.0) + } } override func animateOut(nextContentNode: GalleryOverlayContentNode?, transition: ContainedViewLayoutTransition, completion: @escaping () -> Void) { @@ -271,12 +273,13 @@ final class UniversalVideoGalleryItemNode: ZoomableContentGalleryItemNode { private let statusNode: RadialStatusNode private var statusNodeShouldBeHidden = true - private var isCentral = false + private var isCentral: Bool? private var _isVisible: Bool? private var initiallyActivated = false private var hideStatusNodeUntilCentrality = false private var playOnContentOwnership = false private var skipInitialPause = false + private var ignorePauseStatus = false private var validLayout: (ContainerViewLayout, CGFloat)? private var didPause = false private var isPaused = true @@ -299,6 +302,11 @@ final class UniversalVideoGalleryItemNode: ZoomableContentGalleryItemNode { private var scrubbingFrames = false private var scrubbingFrameDisposable: Disposable? + private let isPlayingPromise = ValuePromise(false, ignoreRepeated: true) + private let isInteractingPromise = ValuePromise(false, ignoreRepeated: true) + private let controlsVisiblePromise = ValuePromise(true, ignoreRepeated: true) + private var hideControlsDisposable: Disposable? + var playbackCompleted: (() -> Void)? private var customUnembedWhenPortrait: ((OverlayMediaItemNode) -> Bool)? @@ -323,6 +331,10 @@ final class UniversalVideoGalleryItemNode: ZoomableContentGalleryItemNode { super.init() + self.footerContentNode.interacting = { [weak self] value in + self?.isInteractingPromise.set(value) + } + self.overlayContentNode.action = { [weak self] toLandscape in self?.updateControlsVisibility(!toLandscape) context.sharedContext.applicationBindings.forceOrientation(toLandscape ? .landscapeRight : .portrait) @@ -436,12 +448,30 @@ final class UniversalVideoGalleryItemNode: ZoomableContentGalleryItemNode { self.titleContentView = GalleryTitleView(frame: CGRect()) self._titleView.set(.single(self.titleContentView)) + + let shouldHideControlsSignal: Signal = combineLatest(self.isPlayingPromise.get(), self.isInteractingPromise.get(), self.controlsVisiblePromise.get()) + |> mapToSignal { isPlaying, isIntracting, controlsVisible -> Signal in + if isPlaying && !isIntracting && controlsVisible { + return .single(Void()) + |> delay(4.0, queue: Queue.mainQueue()) + } else { + return .complete() + } + } + + self.hideControlsDisposable = (shouldHideControlsSignal + |> deliverOnMainQueue).start(next: { [weak self] _ in + if let strongSelf = self { + strongSelf.updateControlsVisibility(false) + } + }) } deinit { self.statusDisposable.dispose() self.mediaPlaybackStateDisposable.dispose() self.scrubbingFrameDisposable?.dispose() + self.hideControlsDisposable?.dispose() } override func ready() -> Signal { @@ -484,21 +514,9 @@ final class UniversalVideoGalleryItemNode: ZoomableContentGalleryItemNode { } } - private var controlsTimer: SwiftSignalKit.Timer? - private var previousPlaying: Bool? - - private func setupControlsTimer() { - let timer = SwiftSignalKit.Timer(timeout: 3.0, repeat: false, completion: { [weak self] in - self?.updateControlsVisibility(false) - self?.controlsTimer = nil - }, queue: Queue.mainQueue()) - timer.start() - self.controlsTimer = timer - } - func setupItem(_ item: UniversalVideoGalleryItem) { if self.item?.content.id != item.content.id { - self.previousPlaying = nil + self.isPlayingPromise.set(false) if item.hideControls { self.statusButtonNode.isHidden = true @@ -665,7 +683,7 @@ final class UniversalVideoGalleryItemNode: ZoomableContentGalleryItemNode { |> deliverOnMainQueue).start(next: { [weak self] value, fetchStatus in if let strongSelf = self { var initialBuffering = false - var playing = false + var isPlaying = false var isPaused = true var seekable = hintSeekable var hasStarted = false @@ -683,7 +701,8 @@ final class UniversalVideoGalleryItemNode: ZoomableContentGalleryItemNode { switch value.status { case .playing: isPaused = false - playing = true + isPlaying = true + strongSelf.ignorePauseStatus = false case let .buffering(_, whilePlaying, _, display): displayProgress = display initialBuffering = !whilePlaying @@ -716,9 +735,10 @@ final class UniversalVideoGalleryItemNode: ZoomableContentGalleryItemNode { isPaused = false } } else if strongSelf.actionAtEnd == .stop { - strongSelf.updateControlsVisibility(true) - strongSelf.controlsTimer?.invalidate() - strongSelf.controlsTimer = nil + strongSelf.isPlayingPromise.set(false) + if strongSelf.isCentral == true { + strongSelf.updateControlsVisibility(true) + } } } if !value.duration.isZero { @@ -726,14 +746,11 @@ final class UniversalVideoGalleryItemNode: ZoomableContentGalleryItemNode { } } - if strongSelf.isCentral && playing && strongSelf.previousPlaying != true && !disablePlayerControls { - strongSelf.controlsTimer?.invalidate() - strongSelf.setupControlsTimer() - } else if !playing { - strongSelf.controlsTimer?.invalidate() - strongSelf.controlsTimer = nil + if !disablePlayerControls && strongSelf.isCentral == true && isPlaying { + strongSelf.isPlayingPromise.set(true) + } else if !isPlaying { + strongSelf.isPlayingPromise.set(false) } - strongSelf.previousPlaying = playing var fetching = false if initialBuffering { @@ -751,7 +768,7 @@ final class UniversalVideoGalleryItemNode: ZoomableContentGalleryItemNode { case .Remote: state = .download(.white) case let .Fetching(_, progress): - if !playing { + if !isPlaying { fetching = true isPaused = true } @@ -768,13 +785,13 @@ final class UniversalVideoGalleryItemNode: ZoomableContentGalleryItemNode { strongSelf.fetchStatus = fetchStatus if !item.hideControls { - strongSelf.statusNodeShouldBeHidden = (!initialBuffering && (strongSelf.didPause || !isPaused) && !fetching) + strongSelf.statusNodeShouldBeHidden = strongSelf.ignorePauseStatus || (!initialBuffering && (strongSelf.didPause || !isPaused) && !fetching) strongSelf.statusButtonNode.isHidden = strongSelf.hideStatusNodeUntilCentrality || strongSelf.statusNodeShouldBeHidden } if isAnimated || disablePlayerControls { strongSelf.footerContentNode.content = .info - } else if isPaused { + } else if isPaused && !strongSelf.ignorePauseStatus { if hasStarted || strongSelf.didPause { strongSelf.footerContentNode.content = .playback(paused: true, seekable: seekable) } else if let fetchStatus = fetchStatus, !strongSelf.requiresDownload { @@ -808,10 +825,9 @@ final class UniversalVideoGalleryItemNode: ZoomableContentGalleryItemNode { if let strongSelf = self, !isAnimated { videoNode?.seek(0.0) - if strongSelf.actionAtEnd == .stop && strongSelf.isCentral { + if strongSelf.actionAtEnd == .stop && strongSelf.isCentral == true { + strongSelf.isPlayingPromise.set(false) strongSelf.updateControlsVisibility(true) - strongSelf.controlsTimer?.invalidate() - strongSelf.controlsTimer = nil } } } @@ -834,8 +850,7 @@ final class UniversalVideoGalleryItemNode: ZoomableContentGalleryItemNode { } override func controlsVisibilityUpdated(isVisible: Bool) { - self.controlsTimer?.invalidate() - self.controlsTimer = nil + self.controlsVisiblePromise.set(isVisible) self.videoNode?.isUserInteractionEnabled = isVisible ? self.videoNodeUserInteractionEnabled : false self.videoNode?.notifyPlaybackControlsHidden(!isVisible) @@ -915,8 +930,7 @@ final class UniversalVideoGalleryItemNode: ZoomableContentGalleryItemNode { } } } else { - self.controlsTimer?.invalidate() - self.controlsTimer = nil + self.isPlayingPromise.set(false) self.dismissOnOrientationChange = false if videoNode.ownsContentNode { @@ -941,6 +955,7 @@ final class UniversalVideoGalleryItemNode: ZoomableContentGalleryItemNode { if self.skipInitialPause { self.skipInitialPause = false } else { + self.ignorePauseStatus = true videoNode.pause() videoNode.seek(0.0) } @@ -973,7 +988,7 @@ final class UniversalVideoGalleryItemNode: ZoomableContentGalleryItemNode { } override func activateAsInitial() { - if let videoNode = self.videoNode, self.isCentral { + if let videoNode = self.videoNode, self.isCentral == true { self.initiallyActivated = true var isAnimated = false @@ -1614,6 +1629,8 @@ final class UniversalVideoGalleryItemNode: ZoomableContentGalleryItemNode { |> delay(0.15, queue: Queue.mainQueue()) let progressDisposable = progressSignal.start() + self.isInteractingPromise.set(true) + let signal = stickerPacksAttachedToMedia(account: self.context.account, media: media) |> afterDisposed { Queue.mainQueue().async { @@ -1627,7 +1644,9 @@ final class UniversalVideoGalleryItemNode: ZoomableContentGalleryItemNode { } let baseNavigationController = strongSelf.baseNavigationController() baseNavigationController?.view.endEditing(true) - let controller = StickerPackScreen(context: strongSelf.context, mainStickerPack: packs[0], stickerPacks: packs, sendSticker: nil) + let controller = StickerPackScreen(context: strongSelf.context, mainStickerPack: packs[0], stickerPacks: packs, sendSticker: nil, dismissed: { [weak self] in + self?.isInteractingPromise.set(false) + }) (baseNavigationController?.topViewController as? ViewController)?.present(controller, in: .window(.root), with: nil) }) } diff --git a/submodules/ListMessageItem/Sources/ListMessageFileItemNode.swift b/submodules/ListMessageItem/Sources/ListMessageFileItemNode.swift index e614dcbb30..b72e18046c 100644 --- a/submodules/ListMessageItem/Sources/ListMessageFileItemNode.swift +++ b/submodules/ListMessageItem/Sources/ListMessageFileItemNode.swift @@ -575,6 +575,13 @@ public final class ListMessageFileItemNode: ListMessageNode { if statusUpdated { updatedStatusSignal = messageFileMediaResourceStatus(context: item.context, file: selectedMedia, message: message, isRecentActions: false, isSharedMedia: true, isGlobalSearch: item.isGlobalSearchResult) + |> mapToSignal { value -> Signal in + if case .Fetching = value.fetchStatus { + return .single(value) |> delay(0.25, queue: Queue.concurrentDefaultQueue()) + } else { + return .single(value) + } + } if isAudio || isInstantVideo { if let currentUpdatedStatusSignal = updatedStatusSignal { diff --git a/submodules/SearchUI/Sources/SearchDisplayController.swift b/submodules/SearchUI/Sources/SearchDisplayController.swift index e176758e03..5fb7675977 100644 --- a/submodules/SearchUI/Sources/SearchDisplayController.swift +++ b/submodules/SearchUI/Sources/SearchDisplayController.swift @@ -231,6 +231,9 @@ public final class SearchDisplayController { self.searchBar.activate() if let placeholder = placeholder { self.searchBar.animateIn(from: placeholder, duration: 0.5, timingFunction: kCAMediaTimingFunctionSpring) + if self.contentNode.hasDim { + self.contentNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.3, timingFunction: CAMediaTimingFunctionName.easeOut.rawValue) + } } else { self.searchBar.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.3, timingFunction: CAMediaTimingFunctionName.easeOut.rawValue) self.contentNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.3, timingFunction: CAMediaTimingFunctionName.easeOut.rawValue) @@ -255,17 +258,6 @@ public final class SearchDisplayController { let backgroundNode = self.backgroundNode let contentNode = self.contentNode if animated { - if let placeholder = placeholder, let (layout, navigationBarHeight) = self.containerLayout { - let contentNodePosition = self.backgroundNode.layer.position - let targetTextBackgroundFrame = placeholder.convert(placeholder.backgroundNode.frame, to: nil) - - var contentNavigationBarHeight = navigationBarHeight - if layout.statusBarHeight == nil { - contentNavigationBarHeight += 28.0 - } - - self.backgroundNode.layer.animatePosition(from: contentNodePosition, to: CGPoint(x: contentNodePosition.x, y: contentNodePosition.y + (targetTextBackgroundFrame.maxY + 8.0 - contentNavigationBarHeight)), duration: 0.5, timingFunction: kCAMediaTimingFunctionSpring, removeOnCompletion: false) - } backgroundNode.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.3, removeOnCompletion: false, completion: { [weak backgroundNode] _ in backgroundNode?.removeFromSupernode() }) diff --git a/submodules/SettingsUI/Sources/Themes/ThemeGridSearchColorsItem.swift b/submodules/SettingsUI/Sources/Themes/ThemeGridSearchColorsItem.swift index c0dcf33d56..3b6a3d1a41 100644 --- a/submodules/SettingsUI/Sources/Themes/ThemeGridSearchColorsItem.swift +++ b/submodules/SettingsUI/Sources/Themes/ThemeGridSearchColorsItem.swift @@ -93,7 +93,11 @@ final class ThemeGridSearchColorsNode: ASDisplayNode { return CGSize(width: constrainedSize.width, height: 100.0) } + private var validLayout: (CGSize, CGFloat, CGFloat)? func updateLayout(size: CGSize, leftInset: CGFloat, rightInset: CGFloat) { + let hadLayout = self.validLayout != nil + self.validLayout = (size, leftInset, rightInset) + self.sectionHeaderNode.frame = CGRect(origin: CGPoint(), size: CGSize(width: size.width, height: 29.0)) self.sectionHeaderNode.updateLayout(size: CGSize(width: size.width, height: 29.0), leftInset: leftInset, rightInset: rightInset) @@ -103,6 +107,9 @@ final class ThemeGridSearchColorsNode: ASDisplayNode { self.scrollNode.frame = CGRect(x: 0.0, y: 29.0, width: size.width, height: size.height - 29.0) self.scrollNode.view.contentInset = insets + if !hadLayout { + self.scrollNode.view.contentOffset = CGPoint(x: -leftInset, y: 0.0) + } var offset: CGFloat = inset if let subnodes = self.scrollNode.subnodes { diff --git a/submodules/ShareController/Sources/ShareController.swift b/submodules/ShareController/Sources/ShareController.swift index 76e8adbeac..430accf2d7 100644 --- a/submodules/ShareController/Sources/ShareController.swift +++ b/submodules/ShareController/Sources/ShareController.swift @@ -299,7 +299,7 @@ public final class ShareController: ViewController { private var currentAccount: Account private var presentationData: PresentationData private var presentationDataDisposable: Disposable? - private let forcedTheme: PresentationTheme? + private let forceTheme: PresentationTheme? private let externalShare: Bool private let immediateExternalShare: Bool @@ -327,11 +327,11 @@ public final class ShareController: ViewController { } } - public convenience init(context: AccountContext, subject: ShareControllerSubject, presetText: String? = nil, preferredAction: ShareControllerPreferredAction = .default, showInChat: ((Message) -> Void)? = nil, fromForeignApp: Bool = false, segmentedValues: [ShareControllerSegmentedValue]? = nil, externalShare: Bool = true, immediateExternalShare: Bool = false, switchableAccounts: [AccountWithInfo] = [], immediatePeerId: PeerId? = nil, forcedTheme: PresentationTheme? = nil, forcedActionTitle: String? = nil) { - self.init(sharedContext: context.sharedContext, currentContext: context, subject: subject, presetText: presetText, preferredAction: preferredAction, showInChat: showInChat, fromForeignApp: fromForeignApp, segmentedValues: segmentedValues, externalShare: externalShare, immediateExternalShare: immediateExternalShare, switchableAccounts: switchableAccounts, immediatePeerId: immediatePeerId, forcedTheme: forcedTheme, forcedActionTitle: forcedActionTitle) + public convenience init(context: AccountContext, subject: ShareControllerSubject, presetText: String? = nil, preferredAction: ShareControllerPreferredAction = .default, showInChat: ((Message) -> Void)? = nil, fromForeignApp: Bool = false, segmentedValues: [ShareControllerSegmentedValue]? = nil, externalShare: Bool = true, immediateExternalShare: Bool = false, switchableAccounts: [AccountWithInfo] = [], immediatePeerId: PeerId? = nil, forceTheme: PresentationTheme? = nil, forcedActionTitle: String? = nil) { + self.init(sharedContext: context.sharedContext, currentContext: context, subject: subject, presetText: presetText, preferredAction: preferredAction, showInChat: showInChat, fromForeignApp: fromForeignApp, segmentedValues: segmentedValues, externalShare: externalShare, immediateExternalShare: immediateExternalShare, switchableAccounts: switchableAccounts, immediatePeerId: immediatePeerId, forceTheme: forceTheme, forcedActionTitle: forcedActionTitle) } - public init(sharedContext: SharedAccountContext, currentContext: AccountContext, subject: ShareControllerSubject, presetText: String? = nil, preferredAction: ShareControllerPreferredAction = .default, showInChat: ((Message) -> Void)? = nil, fromForeignApp: Bool = false, segmentedValues: [ShareControllerSegmentedValue]? = nil, externalShare: Bool = true, immediateExternalShare: Bool = false, switchableAccounts: [AccountWithInfo] = [], immediatePeerId: PeerId? = nil, forcedTheme: PresentationTheme? = nil, forcedActionTitle: String? = nil) { + public init(sharedContext: SharedAccountContext, currentContext: AccountContext, subject: ShareControllerSubject, presetText: String? = nil, preferredAction: ShareControllerPreferredAction = .default, showInChat: ((Message) -> Void)? = nil, fromForeignApp: Bool = false, segmentedValues: [ShareControllerSegmentedValue]? = nil, externalShare: Bool = true, immediateExternalShare: Bool = false, switchableAccounts: [AccountWithInfo] = [], immediatePeerId: PeerId? = nil, forceTheme: PresentationTheme? = nil, forcedActionTitle: String? = nil) { self.sharedContext = sharedContext self.currentContext = currentContext self.currentAccount = currentContext.account @@ -343,11 +343,11 @@ public final class ShareController: ViewController { self.immediatePeerId = immediatePeerId self.fromForeignApp = fromForeignApp self.segmentedValues = segmentedValues - self.forcedTheme = forcedTheme + self.forceTheme = forceTheme self.presentationData = self.sharedContext.currentPresentationData.with { $0 } - if let forcedTheme = self.forcedTheme { - self.presentationData = self.presentationData.withUpdated(theme: forcedTheme) + if let forceTheme = self.forceTheme { + self.presentationData = self.presentationData.withUpdated(theme: forceTheme) } super.init(navigationBarPresentationData: nil) @@ -487,17 +487,17 @@ public final class ShareController: ViewController { return } strongSelf.present(standardTextAlertController(theme: AlertControllerTheme(presentationData: strongSelf.presentationData), title: title, text: text, actions: [TextAlertAction(type: .defaultAction, title: strongSelf.presentationData.strings.Common_OK, action: {})]), in: .window(.root)) - }, externalShare: self.externalShare, immediateExternalShare: self.immediateExternalShare, immediatePeerId: self.immediatePeerId, fromForeignApp: self.fromForeignApp, forcedTheme: self.forcedTheme, segmentedValues: self.segmentedValues) + }, externalShare: self.externalShare, immediateExternalShare: self.immediateExternalShare, immediatePeerId: self.immediatePeerId, fromForeignApp: self.fromForeignApp, forceTheme: self.forceTheme, segmentedValues: self.segmentedValues) self.controllerNode.completed = self.completed self.controllerNode.dismiss = { [weak self] shared in - self?.presentingViewController?.dismiss(animated: false, completion: nil) self?.dismissed?(shared) + self?.presentingViewController?.dismiss(animated: false, completion: nil) } self.controllerNode.cancel = { [weak self] in self?.controllerNode.view.endEditing(true) self?.controllerNode.animateOut(shared: false, completion: { - self?.presentingViewController?.dismiss(animated: false, completion: nil) self?.dismissed?(false) + self?.presentingViewController?.dismiss(animated: false, completion: nil) }) } self.controllerNode.share = { [weak self] text, peerIds in diff --git a/submodules/ShareController/Sources/ShareControllerNode.swift b/submodules/ShareController/Sources/ShareControllerNode.swift index 4d33c1a50f..8047a4421f 100644 --- a/submodules/ShareController/Sources/ShareControllerNode.swift +++ b/submodules/ShareController/Sources/ShareControllerNode.swift @@ -25,7 +25,7 @@ final class ShareControllerNode: ViewControllerTracingNode, UIScrollViewDelegate private let sharedContext: SharedAccountContext private var context: AccountContext? private var presentationData: PresentationData - private let forcedTheme: PresentationTheme? + private let forceTheme: PresentationTheme? private let externalShare: Bool private let immediateExternalShare: Bool private var immediatePeerId: PeerId? @@ -80,10 +80,10 @@ final class ShareControllerNode: ViewControllerTracingNode, UIScrollViewDelegate private let presetText: String? - init(sharedContext: SharedAccountContext, presetText: String?, defaultAction: ShareControllerAction?, requestLayout: @escaping (ContainedViewLayoutTransition) -> Void, presentError: @escaping (String?, String) -> Void, externalShare: Bool, immediateExternalShare: Bool, immediatePeerId: PeerId?, fromForeignApp: Bool, forcedTheme: PresentationTheme?, segmentedValues: [ShareControllerSegmentedValue]?) { + init(sharedContext: SharedAccountContext, presetText: String?, defaultAction: ShareControllerAction?, requestLayout: @escaping (ContainedViewLayoutTransition) -> Void, presentError: @escaping (String?, String) -> Void, externalShare: Bool, immediateExternalShare: Bool, immediatePeerId: PeerId?, fromForeignApp: Bool, forceTheme: PresentationTheme?, segmentedValues: [ShareControllerSegmentedValue]?) { self.sharedContext = sharedContext self.presentationData = sharedContext.currentPresentationData.with { $0 } - self.forcedTheme = forcedTheme + self.forceTheme = forceTheme self.externalShare = externalShare self.immediateExternalShare = immediateExternalShare self.immediatePeerId = immediatePeerId @@ -96,8 +96,8 @@ final class ShareControllerNode: ViewControllerTracingNode, UIScrollViewDelegate self.defaultAction = defaultAction self.requestLayout = requestLayout - if let forcedTheme = self.forcedTheme { - self.presentationData = self.presentationData.withUpdated(theme: forcedTheme) + if let forceTheme = self.forceTheme { + self.presentationData = self.presentationData.withUpdated(theme: forceTheme) } let roundedBackground = generateStretchableFilledCircleImage(radius: 16.0, color: self.presentationData.theme.actionSheet.opaqueItemBackgroundColor) @@ -272,8 +272,8 @@ final class ShareControllerNode: ViewControllerTracingNode, UIScrollViewDelegate return } self.presentationData = presentationData - if let forcedTheme = self.forcedTheme { - self.presentationData = self.presentationData.withUpdated(theme: forcedTheme) + if let forceTheme = self.forceTheme { + self.presentationData = self.presentationData.withUpdated(theme: forceTheme) } let roundedBackground = generateStretchableFilledCircleImage(radius: 16.0, color: self.presentationData.theme.actionSheet.opaqueItemBackgroundColor) diff --git a/submodules/StickerPackPreviewUI/Sources/StickerPackPreviewController.swift b/submodules/StickerPackPreviewUI/Sources/StickerPackPreviewController.swift index 15923c2ae7..ba352f796c 100644 --- a/submodules/StickerPackPreviewUI/Sources/StickerPackPreviewController.swift +++ b/submodules/StickerPackPreviewUI/Sources/StickerPackPreviewController.swift @@ -25,7 +25,9 @@ public final class StickerPackPreviewController: ViewController, StandalonePrese } private var animatedIn = false - private var dismissed = false + private var isDismissed = false + + public var dismissed: (() -> Void)? private let context: AccountContext private let mode: StickerPackPreviewControllerMode @@ -150,6 +152,7 @@ public final class StickerPackPreviewController: ViewController, StandalonePrese })) }, actionPerformed: self.actionPerformed) self.controllerNode.dismiss = { [weak self] in + self?.dismissed?() self?.presentingViewController?.dismiss(animated: false, completion: nil) } self.controllerNode.cancel = { [weak self] in @@ -264,8 +267,8 @@ public final class StickerPackPreviewController: ViewController, StandalonePrese } override public func dismiss(completion: (() -> Void)? = nil) { - if !self.dismissed { - self.dismissed = true + if !self.isDismissed { + self.isDismissed = true } else { return } diff --git a/submodules/StickerPackPreviewUI/Sources/StickerPackScreen.swift b/submodules/StickerPackPreviewUI/Sources/StickerPackScreen.swift index 512a1b7bcf..56fdd49e00 100644 --- a/submodules/StickerPackPreviewUI/Sources/StickerPackScreen.swift +++ b/submodules/StickerPackPreviewUI/Sources/StickerPackScreen.swift @@ -988,6 +988,8 @@ public final class StickerPackScreenImpl: ViewController { return self.displayNode as! StickerPackScreenNode } + public var dismissed: (() -> Void)? + private let _ready = Promise() override public var ready: Promise { return self._ready @@ -1020,6 +1022,7 @@ public final class StickerPackScreenImpl: ViewController { strongSelf.updateModalStyleOverlayTransitionFactor(value, transition: transition) } }, dismissed: { [weak self] in + self?.dismissed?() self?.dismiss() }, presentInGlobalOverlay: { [weak self] c, a in self?.presentInGlobalOverlay(c, with: a) @@ -1060,10 +1063,11 @@ public enum StickerPackScreenPerformedAction { case remove(positionInList: Int) } -public func StickerPackScreen(context: AccountContext, mode: StickerPackPreviewControllerMode = .default, mainStickerPack: StickerPackReference, stickerPacks: [StickerPackReference], parentNavigationController: NavigationController? = nil, sendSticker: ((FileMediaReference, ASDisplayNode, CGRect) -> Bool)? = nil, actionPerformed: ((StickerPackCollectionInfo, [ItemCollectionItem], StickerPackScreenPerformedAction) -> Void)? = nil) -> ViewController { +public func StickerPackScreen(context: AccountContext, mode: StickerPackPreviewControllerMode = .default, mainStickerPack: StickerPackReference, stickerPacks: [StickerPackReference], parentNavigationController: NavigationController? = nil, sendSticker: ((FileMediaReference, ASDisplayNode, CGRect) -> Bool)? = nil, actionPerformed: ((StickerPackCollectionInfo, [ItemCollectionItem], StickerPackScreenPerformedAction) -> Void)? = nil, dismissed: (() -> Void)? = nil) -> ViewController { //return StickerPackScreenImpl(context: context, stickerPacks: stickerPacks, selectedStickerPackIndex: stickerPacks.firstIndex(of: mainStickerPack) ?? 0, parentNavigationController: parentNavigationController, sendSticker: sendSticker) let controller = StickerPackPreviewController(context: context, stickerPack: mainStickerPack, mode: mode, parentNavigationController: parentNavigationController, actionPerformed: actionPerformed) + controller.dismissed = dismissed controller.sendSticker = sendSticker return controller } diff --git a/submodules/TelegramCallsUI/Sources/VoiceChatController.swift b/submodules/TelegramCallsUI/Sources/VoiceChatController.swift index 59c98a9489..3fe6df4308 100644 --- a/submodules/TelegramCallsUI/Sources/VoiceChatController.swift +++ b/submodules/TelegramCallsUI/Sources/VoiceChatController.swift @@ -563,7 +563,12 @@ public final class VoiceChatController: ViewController { var text: VoiceChatParticipantItem.ParticipantText var expandedText: VoiceChatParticipantItem.ParticipantText? let icon: VoiceChatParticipantItem.Icon - switch peerEntry.state { + + var state = peerEntry.state + if let muteState = peerEntry.muteState, case .speaking = state, muteState.mutedByYou || !muteState.canUnmute { + state = .listening + } + switch state { case .listening: if let muteState = peerEntry.muteState, muteState.mutedByYou { text = .text(presentationData.strings.VoiceChat_StatusMutedForYou, .destructive) @@ -1268,7 +1273,7 @@ public final class VoiceChatController: ViewController { openIcon = UIImage(bundleImageName: "Chat/Context Menu/Channels") } else { openTitle = strongSelf.presentationData.strings.Conversation_ContextMenuOpenProfile - openIcon = UIImage(bundleImageName: "Chat/Context Menu/Info") + openIcon = UIImage(bundleImageName: "Chat/Context Menu/User") } items.append(.action(ContextMenuActionItem(text: openTitle, icon: { theme in return generateTintedImage(image: openIcon, color: theme.actionSheet.primaryTextColor) @@ -2236,7 +2241,7 @@ public final class VoiceChatController: ViewController { return formatSendTitle(presentationData.strings.VoiceChat_InviteLink_InviteListeners(Int32(count))) })] } - let shareController = ShareController(context: strongSelf.context, subject: .url(inviteLinks.listenerLink), segmentedValues: segmentedValues, forcedTheme: strongSelf.darkTheme, forcedActionTitle: presentationData.strings.VoiceChat_CopyInviteLink) + let shareController = ShareController(context: strongSelf.context, subject: .url(inviteLinks.listenerLink), segmentedValues: segmentedValues, forceTheme: strongSelf.darkTheme, forcedActionTitle: presentationData.strings.VoiceChat_CopyInviteLink) shareController.completed = { [weak self] peerIds in if let strongSelf = self { let _ = (strongSelf.context.account.postbox.transaction { transaction -> [Peer] in diff --git a/submodules/TelegramCallsUI/Sources/VoiceChatParticipantItem.swift b/submodules/TelegramCallsUI/Sources/VoiceChatParticipantItem.swift index 4759d4027a..28cd1941a6 100644 --- a/submodules/TelegramCallsUI/Sources/VoiceChatParticipantItem.swift +++ b/submodules/TelegramCallsUI/Sources/VoiceChatParticipantItem.swift @@ -179,6 +179,7 @@ class VoiceChatParticipantItemNode: ItemListRevealOptionsItemNode { private var peerPresenceManager: PeerPresenceStatusManager? private var layoutParams: (VoiceChatParticipantItem, ListViewItemLayoutParams, Bool, Bool)? + private var isExtracted = false private var wavesColor: UIColor? private var videoNode: GroupVideoNode? @@ -279,6 +280,8 @@ class VoiceChatParticipantItemNode: ItemListRevealOptionsItemNode { return } + strongSelf.isExtracted = isExtracted + if isExtracted { strongSelf.extractedBackgroundImageNode.image = generateStretchableFilledCircleImage(diameter: 28.0, color: item.presentationData.theme.list.itemBlocksBackgroundColor) } @@ -521,7 +524,7 @@ class VoiceChatParticipantItemNode: ItemListRevealOptionsItemNode { strongSelf.extractedRect = extractedRect strongSelf.nonExtractedRect = nonExtractedRect - if strongSelf.contextSourceNode.isExtractedToContextPreview { + if strongSelf.isExtracted { strongSelf.extractedBackgroundImageNode.frame = extractedRect } else { strongSelf.extractedBackgroundImageNode.frame = nonExtractedRect diff --git a/submodules/TelegramCore/Sources/ManagedAppConfigurationUpdates.swift b/submodules/TelegramCore/Sources/ManagedAppConfigurationUpdates.swift index b7a757eee1..eb4fab79b5 100644 --- a/submodules/TelegramCore/Sources/ManagedAppConfigurationUpdates.swift +++ b/submodules/TelegramCore/Sources/ManagedAppConfigurationUpdates.swift @@ -30,7 +30,9 @@ func updateAppConfigurationOnce(postbox: Postbox, network: Network) -> Signal Signal { let poll = Signal { subscriber in - return updateAppConfigurationOnce(postbox: postbox, network: network).start() + return updateAppConfigurationOnce(postbox: postbox, network: network).start(completed: { + subscriber.putCompletion() + }) } return (poll |> then(.complete() |> suspendAwareDelay(1.0 * 60.0 * 60.0, queue: Queue.concurrentDefaultQueue()))) |> restart } diff --git a/submodules/TelegramCore/Sources/ManagedAutodownloadSettingsUpdates.swift b/submodules/TelegramCore/Sources/ManagedAutodownloadSettingsUpdates.swift index 620fe11e9c..e68464b5db 100644 --- a/submodules/TelegramCore/Sources/ManagedAutodownloadSettingsUpdates.swift +++ b/submodules/TelegramCore/Sources/ManagedAutodownloadSettingsUpdates.swift @@ -14,7 +14,9 @@ func managedAutodownloadSettingsUpdates(accountManager: AccountManager, network: return updateAutodownloadSettingsInteractively(accountManager: accountManager, { _ -> AutodownloadSettings in return AutodownloadSettings(apiAutodownloadSettings: result) }) - }).start() + }).start(completed: { + subscriber.putCompletion() + }) } return (poll |> then(.complete() |> suspendAwareDelay(1.0 * 60.0 * 60.0, queue: Queue.concurrentDefaultQueue()))) |> restart } diff --git a/submodules/TelegramCore/Sources/ManagedConfigurationUpdates.swift b/submodules/TelegramCore/Sources/ManagedConfigurationUpdates.swift index 39de484df8..4818ad8f99 100644 --- a/submodules/TelegramCore/Sources/ManagedConfigurationUpdates.swift +++ b/submodules/TelegramCore/Sources/ManagedConfigurationUpdates.swift @@ -90,7 +90,9 @@ func managedConfigurationUpdates(accountManager: AccountManager, postbox: Postbo } } |> switchToLatest - }).start() + }).start(completed: { + subscriber.putCompletion() + }) } return (poll |> then(.complete() |> suspendAwareDelay(1.0 * 60.0 * 60.0, queue: Queue.concurrentDefaultQueue()))) |> restart diff --git a/submodules/TelegramCore/Sources/ManagedVoipConfigurationUpdates.swift b/submodules/TelegramCore/Sources/ManagedVoipConfigurationUpdates.swift index b3da17c751..2465ca6d99 100644 --- a/submodules/TelegramCore/Sources/ManagedVoipConfigurationUpdates.swift +++ b/submodules/TelegramCore/Sources/ManagedVoipConfigurationUpdates.swift @@ -19,7 +19,9 @@ func managedVoipConfigurationUpdates(postbox: Postbox, network: Network) -> Sign }) } } - }).start() + }).start(completed: { + subscriber.putCompletion() + }) } return (poll |> then(.complete() |> suspendAwareDelay(12.0 * 60.0 * 60.0, queue: Queue.concurrentDefaultQueue()))) |> restart } diff --git a/submodules/TelegramUI/Sources/ApplicationContext.swift b/submodules/TelegramUI/Sources/ApplicationContext.swift index e401742013..a1f8433069 100644 --- a/submodules/TelegramUI/Sources/ApplicationContext.swift +++ b/submodules/TelegramUI/Sources/ApplicationContext.swift @@ -763,6 +763,7 @@ final class AuthorizedApplicationContext { self.rootController.setForceInCallStatusBar((self.context.sharedContext as! SharedAccountContextImpl).currentCallStatusBarNode) if let groupCallController = self.context.sharedContext.currentGroupCallController as? VoiceChatController { if let overlayController = groupCallController.currentOverlayController { + groupCallController.parentNavigationController = self.rootController self.rootController.presentOverlay(controller: overlayController, inGlobal: true, blockInteraction: false) } } diff --git a/submodules/TelegramUI/Sources/ChatController.swift b/submodules/TelegramUI/Sources/ChatController.swift index 8bfa8cd056..48ed8b191d 100644 --- a/submodules/TelegramUI/Sources/ChatController.swift +++ b/submodules/TelegramUI/Sources/ChatController.swift @@ -1364,6 +1364,13 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G case .replyThread: postAsReply = true } + + if let messageId = messageId, let message = strongSelf.chatDisplayNode.historyNode.messageInCurrentHistoryView(messageId) { + if let author = message.author as? TelegramUser, author.botInfo != nil { + } else { + postAsReply = false + } + } } strongSelf.chatDisplayNode.setupSendActionOnViewUpdate({ @@ -2423,7 +2430,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G } var items: [ContextMenuItem] = [ .action(ContextMenuActionItem(text: isChannel ? strongSelf.presentationData.strings.Conversation_ContextMenuOpenChannelProfile : strongSelf.presentationData.strings.Conversation_ContextMenuOpenProfile, icon: { theme in - return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Info"), color: theme.actionSheet.primaryTextColor) + return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/User"), color: theme.actionSheet.primaryTextColor) }, action: { _, f in f(.dismissWithoutContent) self?.openPeer(peerId: peer.id, navigation: .info, fromMessage: nil) @@ -7266,19 +7273,16 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G self.chatDisplayNode.containerLayoutUpdated(layout, navigationBarHeight: self.navigationHeight, transition: transition, listViewTransaction: { updateSizeAndInsets, additionalScrollDistance, scrollToTop, completion in self.chatDisplayNode.historyNode.updateLayout(transition: transition, updateSizeAndInsets: updateSizeAndInsets, additionalScrollDistance: additionalScrollDistance, scrollToTop: scrollToTop, completion: completion) }) - } - - override public func updateToInterfaceOrientation(_ orientation: UIInterfaceOrientation) { - guard let layout = self.validLayout, case .compact = layout.metrics.widthClass else { - return - } - let hasOverlayNodes = self.context.sharedContext.mediaManager.overlayMediaManager.controller?.hasNodes ?? false - if self.validLayout != nil && orientation.isLandscape && !hasOverlayNodes && self.traceVisibility() && isTopmostChatController(self) { - var completed = false - self.chatDisplayNode.historyNode.forEachVisibleItemNode { itemNode in - if !completed, let itemNode = itemNode as? ChatMessageItemView, let message = itemNode.item?.message, let (_, soundEnabled, _, _, _) = itemNode.playMediaWithSound(), soundEnabled { - let _ = self.controllerInteraction?.openMessage(message, .landscape) - completed = true + + if case .compact = layout.metrics.widthClass { + let hasOverlayNodes = self.context.sharedContext.mediaManager.overlayMediaManager.controller?.hasNodes ?? false + if self.validLayout != nil && layout.size.width > layout.size.height && !hasOverlayNodes && self.traceVisibility() && isTopmostChatController(self) { + var completed = false + self.chatDisplayNode.historyNode.forEachVisibleItemNode { itemNode in + if !completed, let itemNode = itemNode as? ChatMessageItemView, let message = itemNode.item?.message, let (_, soundEnabled, _, _, _) = itemNode.playMediaWithSound(), soundEnabled { + let _ = self.controllerInteraction?.openMessage(message, .landscape) + completed = true + } } } }