Implement tooltips

This commit is contained in:
Ali 2021-12-24 01:05:58 +04:00
parent a154aae943
commit 81810c94a9
3 changed files with 73 additions and 5 deletions

View File

@ -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

View File

@ -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()
}
}
}
}

View File

@ -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)