diff --git a/submodules/ChatListUI/Sources/ChatListController.swift b/submodules/ChatListUI/Sources/ChatListController.swift index 03fd884181..da1a4b3fc3 100644 --- a/submodules/ChatListUI/Sources/ChatListController.swift +++ b/submodules/ChatListUI/Sources/ChatListController.swift @@ -2074,6 +2074,7 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController } } + private weak var storyTooltip: TooltipScreen? fileprivate func maybeDisplayStoryTooltip() { let content = self.updateHeaderContent() if content.secondaryContent != nil { @@ -2128,6 +2129,7 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController } ) self.present(tooltipScreen, in: .current) + self.storyTooltip = tooltipScreen #if !DEBUG let _ = ApplicationSpecificNotice.setDisplayChatListStoriesTooltip(accountManager: self.context.sharedContext.accountManager).startStandalone() @@ -4345,7 +4347,18 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController self.activateSearch(filter: filter, query: query) } + private var previousSearchToggleTimestamp: Double? func activateSearch(filter: ChatListSearchFilter = .chats, query: String? = nil, skipScrolling: Bool = false, searchContentNode: NavigationBarSearchContentNode) { + let currentTimestamp = CACurrentMediaTime() + if let previousSearchActivationTimestamp = self.previousSearchToggleTimestamp, currentTimestamp < previousSearchActivationTimestamp + 0.6 { + return + } + self.previousSearchToggleTimestamp = currentTimestamp + + if let storyTooltip = self.storyTooltip { + storyTooltip.dismiss() + } + var filter = filter if case .forum = self.chatListDisplayNode.effectiveContainerNode.location { filter = .topics @@ -4420,46 +4433,53 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController } public func deactivateSearch(animated: Bool) { - if !self.displayNavigationBar { - var completion: (() -> Void)? - - self.searchTabsNode = nil - - var searchContentNode: NavigationBarSearchContentNode? - if let navigationBarView = self.chatListDisplayNode.navigationBarView.view as? ChatListNavigationBar.View { - searchContentNode = navigationBarView.searchContentNode + guard !self.displayNavigationBar else { + return + } + let currentTimestamp = CACurrentMediaTime() + if let previousSearchActivationTimestamp = self.previousSearchToggleTimestamp, currentTimestamp < previousSearchActivationTimestamp + 0.6 { + return + } + self.previousSearchToggleTimestamp = currentTimestamp + + var completion: (() -> Void)? + + self.searchTabsNode = nil + + var searchContentNode: NavigationBarSearchContentNode? + if let navigationBarView = self.chatListDisplayNode.navigationBarView.view as? ChatListNavigationBar.View { + searchContentNode = navigationBarView.searchContentNode + } + + if let searchContentNode { + let previousFrame = searchContentNode.placeholderNode.frame + if case .chatList(.root) = self.location { + searchContentNode.placeholderNode.frame = previousFrame.offsetBy(dx: 0.0, dy: 79.0) } - - if let searchContentNode { - let previousFrame = searchContentNode.placeholderNode.frame - if case .chatList(.root) = self.location { - searchContentNode.placeholderNode.frame = previousFrame.offsetBy(dx: 0.0, dy: 79.0) - } - completion = self.chatListDisplayNode.deactivateSearch(placeholderNode: searchContentNode.placeholderNode, animated: animated) - searchContentNode.placeholderNode.frame = previousFrame - } - - self.chatListDisplayNode.tempAllowAvatarExpansion = true - self.requestLayout(transition: .animated(duration: 0.5, curve: .spring)) - self.chatListDisplayNode.tempAllowAvatarExpansion = false - - //TODO:swap tabs - - let transition: ContainedViewLayoutTransition = animated ? .animated(duration: 0.4, curve: .spring) : .immediate - //transition.updateAlpha(node: self.tabContainerNode, alpha: tabsIsEmpty ? 0.0 : 1.0) - self.setDisplayNavigationBar(true, transition: transition) - - completion?() - - (self.parent as? TabBarController)?.updateIsTabBarHidden(false, transition: .animated(duration: 0.4, curve: .spring)) - - self.isSearchActive = false - if let navigationController = self.navigationController as? NavigationController { - for controller in navigationController.globalOverlayControllers { - if let controller = controller as? VoiceChatOverlayController { - controller.updateVisibility() - break - } + completion = self.chatListDisplayNode.deactivateSearch(placeholderNode: searchContentNode.placeholderNode, animated: animated) + searchContentNode.placeholderNode.frame = previousFrame + } + + self.chatListDisplayNode.tempAllowAvatarExpansion = true + self.requestLayout(transition: .animated(duration: 0.5, curve: .spring)) + self.chatListDisplayNode.tempAllowAvatarExpansion = false + + //TODO:swap tabs + + let transition: ContainedViewLayoutTransition = animated ? .animated(duration: 0.4, curve: .spring) : .immediate + //transition.updateAlpha(node: self.tabContainerNode, alpha: tabsIsEmpty ? 0.0 : 1.0) + self.setDisplayNavigationBar(true, transition: transition) + + completion?() + + (self.parent as? TabBarController)?.updateIsTabBarHidden(false, transition: .animated(duration: 0.4, curve: .spring)) + + self.isSearchActive = false + if let navigationController = self.navigationController as? NavigationController { + for controller in navigationController.globalOverlayControllers { + if let controller = controller as? VoiceChatOverlayController { + controller.updateVisibility() + break } } } diff --git a/submodules/SearchBarNode/Sources/SearchBarNode.swift b/submodules/SearchBarNode/Sources/SearchBarNode.swift index deb6724b72..131323d318 100644 --- a/submodules/SearchBarNode/Sources/SearchBarNode.swift +++ b/submodules/SearchBarNode/Sources/SearchBarNode.swift @@ -20,6 +20,10 @@ private func generateHashtagIcon(color: UIColor) -> UIImage? { return generateTintedImage(image: UIImage(bundleImageName: "Components/Search Bar/Hashtag"), color: color) } +private func generateCashtagIcon(color: UIColor) -> UIImage? { + return generateTintedImage(image: UIImage(bundleImageName: "Components/Search Bar/Cashtag"), color: color) +} + private func generateClearIcon(color: UIColor) -> UIImage? { return generateTintedImage(image: UIImage(bundleImageName: "Components/Search Bar/Clear"), color: color) } @@ -851,6 +855,7 @@ public class SearchBarNode: ASDisplayNode, UITextFieldDelegate { public enum Icon { case loupe case hashtag + case cashtag } public let icon: Icon @@ -1062,6 +1067,8 @@ public class SearchBarNode: ASDisplayNode, UITextFieldDelegate { icon = generateLoupeIcon(color: theme.inputIcon) case .hashtag: icon = generateHashtagIcon(color: theme.inputIcon) + case .cashtag: + icon = generateCashtagIcon(color: theme.inputIcon) } self.iconNode.image = icon self.textField.keyboardAppearance = theme.keyboard.keyboardAppearance @@ -1150,6 +1157,11 @@ public class SearchBarNode: ASDisplayNode, UITextFieldDelegate { } self.textBackgroundNode.layer.animateFrame(from: initialTextBackgroundFrame, to: self.textBackgroundNode.frame, duration: duration, timingFunction: timingFunction) + if initialTextBackgroundFrame.height.isZero { + self.iconNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.25) + self.textField.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.25) + } + let textFieldFrame = self.textField.frame var tokensWidth = self.textField.tokensWidth if tokensWidth > 0.0 { @@ -1264,24 +1276,24 @@ public class SearchBarNode: ASDisplayNode, UITextFieldDelegate { separatorCompleted = true intermediateCompletion() }) - + self.textBackgroundNode.isHidden = true /*if let accessoryComponentView = node.accessoryComponentView { - let tempContainer = UIView() - - let accessorySize = accessoryComponentView.bounds.size - tempContainer.frame = CGRect(origin: CGPoint(x: self.textBackgroundNode.frame.maxX - accessorySize.width - 4.0, y: floor((self.textBackgroundNode.frame.minY + self.textBackgroundNode.frame.height - accessorySize.height) / 2.0)), size: accessorySize) - - let targetTempContainerFrame = CGRect(origin: CGPoint(x: targetTextBackgroundFrame.maxX - accessorySize.width - 4.0, y: floor((targetTextBackgroundFrame.minY + 8.0 + targetTextBackgroundFrame.height - accessorySize.height) / 2.0)), size: accessorySize) - - tempContainer.layer.animateFrame(from: tempContainer.frame, to: targetTempContainerFrame, duration: duration, timingFunction: timingFunction, removeOnCompletion: false) - - accessoryComponentView.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.2) - tempContainer.addSubview(accessoryComponentView) - self.view.addSubview(tempContainer) - }*/ - + let tempContainer = UIView() + + let accessorySize = accessoryComponentView.bounds.size + tempContainer.frame = CGRect(origin: CGPoint(x: self.textBackgroundNode.frame.maxX - accessorySize.width - 4.0, y: floor((self.textBackgroundNode.frame.minY + self.textBackgroundNode.frame.height - accessorySize.height) / 2.0)), size: accessorySize) + + let targetTempContainerFrame = CGRect(origin: CGPoint(x: targetTextBackgroundFrame.maxX - accessorySize.width - 4.0, y: floor((targetTextBackgroundFrame.minY + 8.0 + targetTextBackgroundFrame.height - accessorySize.height) / 2.0)), size: accessorySize) + + tempContainer.layer.animateFrame(from: tempContainer.frame, to: targetTempContainerFrame, duration: duration, timingFunction: timingFunction, removeOnCompletion: false) + + accessoryComponentView.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.2) + tempContainer.addSubview(accessoryComponentView) + self.view.addSubview(tempContainer) + }*/ + self.textBackgroundNode.layer.animateFrame(from: self.textBackgroundNode.frame, to: targetTextBackgroundFrame, duration: duration, timingFunction: timingFunction, removeOnCompletion: false, completion: { [weak node] _ in textBackgroundCompleted = true intermediateCompletion() @@ -1300,8 +1312,11 @@ public class SearchBarNode: ASDisplayNode, UITextFieldDelegate { self.insertSubnode(transitionBackgroundNode, aboveSubnode: self.textBackgroundNode) transitionBackgroundNode.layer.animateFrame(from: self.textBackgroundNode.frame, to: targetTextBackgroundFrame, duration: duration, timingFunction: timingFunction, removeOnCompletion: false) - - if let snapshot = node.labelNode.layer.snapshotContentTree() { + + if targetTextBackgroundFrame.height.isZero { + self.iconNode.layer.animateAlpha(from: self.iconNode.alpha, to: 0.0, duration: 0.2, removeOnCompletion: false) + self.textField.layer.animateAlpha(from: self.textField.alpha, to: 0.0, duration: 0.2, removeOnCompletion: false) + } else if let snapshot = node.labelNode.layer.snapshotContentTree() { snapshot.frame = CGRect(origin: self.textField.placeholderLabel.frame.origin.offsetBy(dx: 0.0, dy: UIScreenPixel), size: node.labelNode.frame.size) self.textField.layer.addSublayer(snapshot) snapshot.animateAlpha(from: 0.0, to: 1.0, duration: duration * 2.0 / 3.0, timingFunction: CAMediaTimingFunctionName.linear.rawValue) diff --git a/submodules/SearchUI/Sources/SearchDisplayController.swift b/submodules/SearchUI/Sources/SearchDisplayController.swift index 9da8055e06..50420e6b50 100644 --- a/submodules/SearchUI/Sources/SearchDisplayController.swift +++ b/submodules/SearchUI/Sources/SearchDisplayController.swift @@ -268,16 +268,20 @@ public final class SearchDisplayController { searchBar?.removeFromSupernode() }) } else { - searchBar.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.3, removeOnCompletion: false, completion: { [weak searchBar] _ in - searchBar?.removeFromSupernode() + searchBar.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.3, removeOnCompletion: false, completion: { [weak searchBar] finished in + if finished { + searchBar?.removeFromSupernode() + } }) } let backgroundNode = self.backgroundNode let contentNode = self.contentNode if animated { - backgroundNode.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.3, removeOnCompletion: false, completion: { [weak backgroundNode] _ in - backgroundNode?.removeFromSupernode() + backgroundNode.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.3, removeOnCompletion: false, completion: { [weak backgroundNode] finished in + if finished { + backgroundNode?.removeFromSupernode() + } }) } else { backgroundNode.removeFromSupernode() diff --git a/submodules/TelegramUI/Components/Stars/StarsTransactionsScreen/Sources/StarsTransactionScreen.swift b/submodules/TelegramUI/Components/Stars/StarsTransactionsScreen/Sources/StarsTransactionScreen.swift index d29f80c281..a3e2450ba2 100644 --- a/submodules/TelegramUI/Components/Stars/StarsTransactionsScreen/Sources/StarsTransactionScreen.swift +++ b/submodules/TelegramUI/Components/Stars/StarsTransactionsScreen/Sources/StarsTransactionScreen.swift @@ -727,6 +727,8 @@ public class StarsTransactionScreen: ViewControllerComponentContainer { let presentationData = context.sharedContext.currentPresentationData.with { $0 } self.present(UndoOverlayController(presentationData: presentationData, content: .copy(text: presentationData.strings.Stars_Transaction_CopiedId), elevatedLayout: false, position: .bottom, action: { _ in return true }), in: .current) + + HapticFeedback().tap() } } diff --git a/submodules/TelegramUI/Sources/ChatControllerNode.swift b/submodules/TelegramUI/Sources/ChatControllerNode.swift index d7df67602f..928b6c650f 100644 --- a/submodules/TelegramUI/Sources/ChatControllerNode.swift +++ b/submodules/TelegramUI/Sources/ChatControllerNode.swift @@ -2816,8 +2816,8 @@ class ChatControllerNode: ASDisplayNode, ASScrollViewDelegate { } self.skippedShowSearchResultsAsListAnimationOnce = true inlineSearchResultsView.layer.allowsGroupOpacity = true - if let inlineSearchResultsView = self.inlineSearchResults?.view { - self.contentContainerNode.view.insertSubview(inlineSearchResultsView, aboveSubview: inlineSearchResultsView) + if let emptyNode = self.emptyNode { + self.contentContainerNode.view.insertSubview(inlineSearchResultsView, aboveSubview: emptyNode.view) } else { self.contentContainerNode.view.insertSubview(inlineSearchResultsView, aboveSubview: self.historyNodeContainer.view) }