diff --git a/submodules/ContextUI/Sources/ContextActionsContainerNode.swift b/submodules/ContextUI/Sources/ContextActionsContainerNode.swift index 7dcabb6bb4..b4b0647024 100644 --- a/submodules/ContextUI/Sources/ContextActionsContainerNode.swift +++ b/submodules/ContextUI/Sources/ContextActionsContainerNode.swift @@ -337,7 +337,7 @@ private final class InnerActionsContainerNode: ASDisplayNode { } } -private final class InnerTextSelectionTipContainerNode: ASDisplayNode { +final class InnerTextSelectionTipContainerNode: ASDisplayNode { private let presentationData: PresentationData private var effectView: UIVisualEffectView? private let textNode: TextNode diff --git a/submodules/ContextUI/Sources/ContextControllerActionsStackNode.swift b/submodules/ContextUI/Sources/ContextControllerActionsStackNode.swift index ee4cbd847c..41ee37707a 100644 --- a/submodules/ContextUI/Sources/ContextControllerActionsStackNode.swift +++ b/submodules/ContextUI/Sources/ContextControllerActionsStackNode.swift @@ -29,6 +29,7 @@ public protocol ContextControllerActionsStackItem: AnyObject { requestUpdateApparentHeight: @escaping (ContainedViewLayoutTransition) -> Void ) -> ContextControllerActionsStackItemNode + var tip: ContextController.Tip? { get } var reactionItems: (context: AccountContext, reactionItems: [ReactionContextItem])? { get } } @@ -558,13 +559,16 @@ final class ContextControllerActionsListStackItem: ContextControllerActionsStack private let items: [ContextMenuItem] let reactionItems: (context: AccountContext, reactionItems: [ReactionContextItem])? + let tip: ContextController.Tip? init( items: [ContextMenuItem], - reactionItems: (context: AccountContext, reactionItems: [ReactionContextItem])? + reactionItems: (context: AccountContext, reactionItems: [ReactionContextItem])?, + tip: ContextController.Tip? ) { self.items = items self.reactionItems = reactionItems + self.tip = tip } func node( @@ -632,13 +636,16 @@ final class ContextControllerActionsCustomStackItem: ContextControllerActionsSta private let content: ContextControllerItemsContent let reactionItems: (context: AccountContext, reactionItems: [ReactionContextItem])? + let tip: ContextController.Tip? init( content: ContextControllerItemsContent, - reactionItems: (context: AccountContext, reactionItems: [ReactionContextItem])? + reactionItems: (context: AccountContext, reactionItems: [ReactionContextItem])?, + tip: ContextController.Tip? ) { self.content = content self.reactionItems = reactionItems + self.tip = tip } func node( @@ -663,9 +670,9 @@ func makeContextControllerActionsStackItem(items: ContextController.Items) -> Co } switch items.content { case let .list(listItems): - return ContextControllerActionsListStackItem(items: listItems, reactionItems: reactionItems) + return ContextControllerActionsListStackItem(items: listItems, reactionItems: reactionItems, tip: items.tip) case let .custom(customContent): - return ContextControllerActionsCustomStackItem(content: customContent, reactionItems: reactionItems) + return ContextControllerActionsCustomStackItem(content: customContent, reactionItems: reactionItems, tip: items.tip) } } @@ -728,6 +735,8 @@ final class ContextControllerActionsStackNode: ASDisplayNode { let requestUpdate: (ContainedViewLayoutTransition) -> Void let node: ContextControllerActionsStackItemNode let dimNode: ASDisplayNode + let tip: ContextController.Tip? + var tipNode: InnerTextSelectionTipContainerNode? let reactionItems: (context: AccountContext, reactionItems: [ReactionContextItem])? var storedScrollingState: CGFloat? let positionLock: CGFloat? @@ -738,6 +747,7 @@ final class ContextControllerActionsStackNode: ASDisplayNode { requestUpdate: @escaping (ContainedViewLayoutTransition) -> Void, requestUpdateApparentHeight: @escaping (ContainedViewLayoutTransition) -> Void, item: ContextControllerActionsStackItem, + tip: ContextController.Tip?, reactionItems: (context: AccountContext, reactionItems: [ReactionContextItem])?, positionLock: CGFloat? ) { @@ -756,6 +766,8 @@ final class ContextControllerActionsStackNode: ASDisplayNode { self.reactionItems = reactionItems self.positionLock = positionLock + self.tip = tip + super.init() self.clipsToBounds = true @@ -790,6 +802,27 @@ final class ContextControllerActionsStackNode: ASDisplayNode { return (size, apparentHeight) } + func updateTip(presentationData: PresentationData, width: CGFloat, transition: ContainedViewLayoutTransition) -> (node: ASDisplayNode, height: CGFloat)? { + if let tip = self.tip { + var updatedTransition = transition + if self.tipNode == nil { + updatedTransition = .immediate + let tipNode = InnerTextSelectionTipContainerNode(presentationData: presentationData, tip: tip) + tipNode.isUserInteractionEnabled = false + self.tipNode = tipNode + } + + if let tipNode = self.tipNode { + let size = tipNode.updateLayout(widthClass: .compact, width: width, transition: updatedTransition) + return (tipNode, size.height) + } else { + return nil + } + } else { + return nil + } + } + func updateDimNode(presentationData: PresentationData, size: CGSize, transitionFraction: CGFloat, transition: ContainedViewLayoutTransition) { self.dimNode.backgroundColor = presentationData.theme.contextMenu.sectionSeparatorColor @@ -906,6 +939,7 @@ final class ContextControllerActionsStackNode: ASDisplayNode { strongSelf.requestUpdate(transition) }, item: item, + tip: item.tip, reactionItems: item.reactionItems, positionLock: positionLock ) @@ -946,6 +980,8 @@ final class ContextControllerActionsStackNode: ASDisplayNode { constrainedSize: CGSize, transition: ContainedViewLayoutTransition ) -> CGSize { + let tipSpacing: CGFloat = 10.0 + self.navigationContainer.backgroundColor = presentationData.theme.contextMenu.backgroundColor let animateAppearingContainers = transition.isAnimated && !self.dismissingItemContainers.isEmpty @@ -1047,6 +1083,23 @@ final class ContextControllerActionsStackNode: ASDisplayNode { } self.itemContainers[i].updateDimNode(presentationData: presentationData, size: CGSize(width: itemLayouts[i].size.width, height: navigationContainerFrame.size.height), transitionFraction: itemLayouts[i].alphaTransitionFraction, transition: transition) + + if let (tipNode, tipHeight) = self.itemContainers[i].updateTip(presentationData: presentationData, width: itemLayouts[i].size.width, transition: transition) { + var tipTransition = transition + if tipNode.supernode == nil { + tipTransition = .immediate + self.addSubnode(tipNode) + } + + let tipAlpha: CGFloat = itemLayouts[i].alphaTransitionFraction + + tipTransition.updateFrame(node: tipNode, frame: CGRect(origin: CGPoint(x: navigationContainerFrame.minX, y: navigationContainerFrame.maxY + tipSpacing), size: CGSize(width: itemLayouts[i].size.width, height: tipHeight)), beginWithCurrentState: true) + tipTransition.updateAlpha(node: tipNode, alpha: tipAlpha, beginWithCurrentState: true) + + if i == self.itemContainers.count - 1 { + topItemSize.height += tipSpacing + tipHeight + } + } } for (itemContainer, isPopped) in self.dismissingItemContainers { @@ -1059,6 +1112,11 @@ final class ContextControllerActionsStackNode: ASDisplayNode { transition.updatePosition(node: itemContainer, position: position, completion: { [weak itemContainer] _ in itemContainer?.removeFromSupernode() }) + if let tipNode = itemContainer.tipNode { + transition.updateAlpha(node: tipNode, alpha: 0.0, completion: { [weak tipNode] _ in + tipNode?.removeFromSupernode() + }) + } } self.dismissingItemContainers.removeAll() @@ -1082,4 +1140,12 @@ final class ContextControllerActionsStackNode: ASDisplayNode { selectionPanGesture.isEnabled = isEnabled } } + + func animateIn() { + for itemContainer in self.itemContainers { + if let tipNode = itemContainer.tipNode { + tipNode.animateIn() + } + } + } } diff --git a/submodules/ContextUI/Sources/ContextControllerExtractedPresentationNode.swift b/submodules/ContextUI/Sources/ContextControllerExtractedPresentationNode.swift index bac0f86382..0ef886fe5d 100644 --- a/submodules/ContextUI/Sources/ContextControllerExtractedPresentationNode.swift +++ b/submodules/ContextUI/Sources/ContextControllerExtractedPresentationNode.swift @@ -503,6 +503,8 @@ final class ContextControllerExtractedPresentationNode: ASDisplayNode, ContextCo reactionContextNode.animateIn(from: currentContentScreenFrame) } + self.actionsStackNode.animateIn() + contentNode.containingNode.isExtractedToContextPreview = true contentNode.containingNode.isExtractedToContextPreviewUpdated?(true) contentNode.containingNode.willUpdateIsExtractedToContextPreview?(true, transition) diff --git a/submodules/TelegramUI/Sources/AppDelegate.swift b/submodules/TelegramUI/Sources/AppDelegate.swift index a43ff5cb3d..5ec03202f2 100644 --- a/submodules/TelegramUI/Sources/AppDelegate.swift +++ b/submodules/TelegramUI/Sources/AppDelegate.swift @@ -1272,6 +1272,7 @@ private func extractAccountManagerState(records: AccountRecordsView mapToSignal { context -> Signal in if let context = context { @@ -1281,6 +1282,12 @@ private func extractAccountManagerState(records: AccountRecordsView deliverOnMainQueue).start(next: { count in + if resetOnce { + resetOnce = false + if count == 0 { + UIApplication.shared.applicationIconBadgeNumber = 1 + } + } UIApplication.shared.applicationIconBadgeNumber = Int(count) })) } diff --git a/submodules/TelegramUI/Sources/ChatInterfaceStateContextMenus.swift b/submodules/TelegramUI/Sources/ChatInterfaceStateContextMenus.swift index 6e3ca8bac7..a9200c47b7 100644 --- a/submodules/TelegramUI/Sources/ChatInterfaceStateContextMenus.swift +++ b/submodules/TelegramUI/Sources/ChatInterfaceStateContextMenus.swift @@ -1228,6 +1228,11 @@ func contextMenuForChatPresentationInterfaceState(chatPresentationInterfaceState for reaction in mergedMessageReactionsAndPeers(message: message).reactions { reactionCount += Int(reaction.count) } + if let reactionsAttribute = message.reactionsAttribute { + if !reactionsAttribute.canViewList { + reactionCount = 0 + } + } if let peer = message.peers[message.id.peerId], (canViewStats || reactionCount != 0) { var hasReadReports = false diff --git a/submodules/TelegramUI/Sources/ChatMessageAnimatedStickerItemNode.swift b/submodules/TelegramUI/Sources/ChatMessageAnimatedStickerItemNode.swift index 975916a24f..783ea0f50b 100644 --- a/submodules/TelegramUI/Sources/ChatMessageAnimatedStickerItemNode.swift +++ b/submodules/TelegramUI/Sources/ChatMessageAnimatedStickerItemNode.swift @@ -1412,6 +1412,9 @@ class ChatMessageAnimatedStickerItemNode: ChatMessageItemView { if let reactionButtonsSizeAndApply = reactionButtonsSizeAndApply { let reactionButtonsNode = reactionButtonsSizeAndApply.1(animation) var reactionButtonsFrame = CGRect(origin: CGPoint(x: imageFrame.minX, y: imageFrame.maxY), size: reactionButtonsSizeAndApply.0) + if !incoming { + reactionButtonsFrame.origin.x = imageFrame.maxX - reactionButtonsSizeAndApply.0.width + } if let actionButtonsSizeAndApply = actionButtonsSizeAndApply { reactionButtonsFrame.origin.y += 4.0 + actionButtonsSizeAndApply.0.height } diff --git a/submodules/TelegramUI/Sources/ChatMessageInstantVideoItemNode.swift b/submodules/TelegramUI/Sources/ChatMessageInstantVideoItemNode.swift index c7f1201d13..22b1316106 100644 --- a/submodules/TelegramUI/Sources/ChatMessageInstantVideoItemNode.swift +++ b/submodules/TelegramUI/Sources/ChatMessageInstantVideoItemNode.swift @@ -788,6 +788,9 @@ class ChatMessageInstantVideoItemNode: ChatMessageItemView, UIGestureRecognizerD if let reactionButtonsSizeAndApply = reactionButtonsSizeAndApply { let reactionButtonsNode = reactionButtonsSizeAndApply.1(animation) var reactionButtonsFrame = CGRect(origin: CGPoint(x: videoFrame.minX, y: videoFrame.maxY + 6.0), size: reactionButtonsSizeAndApply.0) + if !incoming { + reactionButtonsFrame.origin.x = videoFrame.maxX - reactionButtonsSizeAndApply.0.width + } if let actionButtonsSizeAndApply = actionButtonsSizeAndApply { reactionButtonsFrame.origin.y += 4.0 + actionButtonsSizeAndApply.0.height } diff --git a/submodules/TelegramUI/Sources/ChatMessageInteractiveInstantVideoNode.swift b/submodules/TelegramUI/Sources/ChatMessageInteractiveInstantVideoNode.swift index e0ca23424b..411a175a66 100644 --- a/submodules/TelegramUI/Sources/ChatMessageInteractiveInstantVideoNode.swift +++ b/submodules/TelegramUI/Sources/ChatMessageInteractiveInstantVideoNode.swift @@ -825,7 +825,9 @@ class ChatMessageInteractiveInstantVideoNode: ASDisplayNode { messageMediaFileCancelInteractiveFetch(context: item.context, messageId: item.message.id, file: file) } case .Remote: - self.videoNode?.fetchControl(.fetch) + if let file = self.media { + self.fetchDisposable.set(messageMediaFileInteractiveFetched(context: item.context, message: item.message, file: file, userInitiated: true).start()) + } case .Local: self.activateVideoPlayback() } diff --git a/submodules/TelegramUI/Sources/ChatMessageReactionsFooterContentNode.swift b/submodules/TelegramUI/Sources/ChatMessageReactionsFooterContentNode.swift index 9337d725cc..dca403670c 100644 --- a/submodules/TelegramUI/Sources/ChatMessageReactionsFooterContentNode.swift +++ b/submodules/TelegramUI/Sources/ChatMessageReactionsFooterContentNode.swift @@ -126,30 +126,6 @@ final class MessageReactionButtonsNode: ASDisplayNode { ) } - /*switch type { - case .incoming: - reactionColors = ReactionButtonComponent.Colors( - deselectedBackground: presentationData.theme.theme.chat.message.incoming.accentControlColor.withMultipliedAlpha(0.1).argb, - selectedBackground: presentationData.theme.theme.chat.message.incoming.accentControlColor.withMultipliedAlpha(1.0).argb, - deselectedForeground: presentationData.theme.theme.chat.message.incoming.accentTextColor.argb, - selectedForeground: presentationData.theme.theme.chat.message.incoming.bubble.withWallpaper.fill.last!.argb - ) - case .outgoing: - reactionColors = ReactionButtonComponent.Colors( - deselectedBackground: presentationData.theme.theme.chat.message.outgoing.accentControlColor.withMultipliedAlpha(0.1).argb, - selectedBackground: presentationData.theme.theme.chat.message.outgoing.accentControlColor.withMultipliedAlpha(1.0).argb, - deselectedForeground: presentationData.theme.theme.chat.message.outgoing.accentTextColor.argb, - selectedForeground: presentationData.theme.theme.chat.message.outgoing.bubble.withWallpaper.fill.last!.argb - ) - case .freeform: - reactionColors = ReactionButtonComponent.Colors( - deselectedBackground: selectDateFillStaticColor(theme: presentationData.theme.theme, wallpaper: presentationData.theme.wallpaper).argb, - selectedBackground: UIColor(white: 1.0, alpha: 0.8).argb, - deselectedForeground: UIColor(white: 1.0, alpha: 1.0).argb, - selectedForeground: UIColor(white: 0.0, alpha: 0.1).argb - ) - }*/ - var totalReactionCount: Int = 0 for reaction in reactions.reactions { totalReactionCount += Int(reaction.count) diff --git a/submodules/TelegramUI/Sources/ChatMessageStickerItemNode.swift b/submodules/TelegramUI/Sources/ChatMessageStickerItemNode.swift index 083827b70a..3e926654b0 100644 --- a/submodules/TelegramUI/Sources/ChatMessageStickerItemNode.swift +++ b/submodules/TelegramUI/Sources/ChatMessageStickerItemNode.swift @@ -689,7 +689,7 @@ class ChatMessageStickerItemNode: ChatMessageItemView { layoutSize.height += dateAndStatusSize.height } if let reactionButtonsSizeAndApply = reactionButtonsSizeAndApply { - layoutSize.height += 4.0 + reactionButtonsSizeAndApply.0.height + layoutSize.height += 4.0 + reactionButtonsSizeAndApply.0.height + 4.0 } if let actionButtonsSizeAndApply = actionButtonsSizeAndApply { layoutSize.height += actionButtonsSizeAndApply.0.height @@ -986,7 +986,10 @@ class ChatMessageStickerItemNode: ChatMessageItemView { if let reactionButtonsSizeAndApply = reactionButtonsSizeAndApply { let reactionButtonsNode = reactionButtonsSizeAndApply.1(animation) - var reactionButtonsFrame = CGRect(origin: CGPoint(x: imageFrame.minX, y: imageFrame.maxY - 4.0), size: reactionButtonsSizeAndApply.0) + var reactionButtonsFrame = CGRect(origin: CGPoint(x: imageFrame.minX, y: imageFrame.maxY - innerImageInset + 4.0), size: reactionButtonsSizeAndApply.0) + if !incoming { + reactionButtonsFrame.origin.x = imageFrame.maxX - innerImageInset - reactionButtonsSizeAndApply.0.width + } if let actionButtonsSizeAndApply = actionButtonsSizeAndApply { reactionButtonsFrame.origin.y += 4.0 + actionButtonsSizeAndApply.0.height }