ChatMessageBubbleItemNode
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
private let contextSourceNode: ContextContentContainingNode
private let backgroundWallpaperNode: ChatMessageBubbleBackdrop
private let backgroundNode: ChatMessageBackground
private var selectionNode: ChatMessageSelectionNode?
private var deliveryFailedNode: ChatMessageDeliveryFailedNode?
private var swipeToReplyNode: ChatMessageSwipeToReplyNode?
private var swipeToReplyFeedback: HapticFeedback?
private var nameNode: TextNode?
private var adminBadgeNode: TextNode?
private var credibilityIconNode: ASImageNode?
private var forwardInfoNode: ChatMessageForwardInfoNode?
private var contentNodes: [ChatMessageBubbleContentNode] = []
private var mosaicStatusNode: ChatMessageDateAndStatusNode?
private var actionButtonsNode: ChatMessageActionButtonsNode?
private var shareButtonNode: HighlightableButtonNode?
private let messageAccessibilityArea: AccessibilityAreaNode
private var backgroundType: ChatMessageBackgroundType?
private var highlightedState: Bool = false
private var appliedItem: ChatMessageItem?
private var appliedForwardInfo: (Peer?, String?)?
private var tapRecognizer: TapLongTapOrDoubleTapGestureRecognizer?
private var reactionRecognizer: ReactionSwipeGestureRecognizer?
self.addSubnode(self.contextSourceNode)
self.contextSourceNode.contentNode.addSubnode(self.backgroundWallpaperNode)
self.contextSourceNode.contentNode.addSubnode(self.backgroundNode)
self.addSubnode(self.messageAccessibilityArea)
private func addContentNode(node: ChatMessageBubbleContentNode) {
if let transitionClippingNode = self.transitionClippingNode {
transitionClippingNode.addSubnode(node)
} else {
self.contextSourceNode.contentNode.addSubnode(node)
}
}
ContextContentContainingNode
1
let contentNode: ContextContentNode
ContextContentNode
ChatMessageBackground
1
2
3
4
5
private(set) var type: ChatMessageBackgroundType?
private var currentHighlighted: Bool?
private var graphics: PrincipalThemeEssentialGraphics?
private var maskMode: Bool?
private var themeData:ChatPresentationThemeData?
ChatMessageBubbleBackdrop
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
private let backgroundContent: ASDisplayNode
private var currentType: ChatMessageBackgroundType?
private var currentMaskMode: Bool?
private var theme: ChatPresentationThemeData?
private var essentialGraphics: PrincipalThemeEssentialGraphics?
private var maskView: UIImageView?
self.addSubnode(self.backgroundContent)
private func maskForType(_ type: ChatMessageBackgroundType, graphics: PrincipalThemeEssentialGraphics) -> UIImage? {
let image: UIImage?
switch type {
case .none:
image = nil
case let .incoming(mergeType):
switch mergeType {
case .None, .RedEnvelopes, .Transfer,.File:
image = graphics.chatMessageBackgroundIncomingMaskImage
case let .Top(side):
if side {
image = graphics.chatMessageBackgroundIncomingMergedTopSideMaskImage
} else {
image = graphics.chatMessageBackgroundIncomingMergedTopMaskImage
}
case .Bottom:
image = graphics.chatMessageBackgroundIncomingMergedBottomMaskImage
case .Both:
image = graphics.chatMessageBackgroundIncomingMergedBothMaskImage
case .Side:
image = graphics.chatMessageBackgroundIncomingMergedSideMaskImage
case .translation:
image = graphics.chatMessageBackgroundIncomingTranslationImage
case .Interaction:
image = graphics.chatMessageInteractionBackgroundImage
}
case let .outgoing(mergeType):
switch mergeType {
case .None, .RedEnvelopes, .Transfer:
image = graphics.chatMessageBackgroundOutgoingMaskImage
case let .Top(side):
if side {
image = graphics.chatMessageBackgroundOutgoingMergedTopSideMaskImage
} else {
image = graphics.chatMessageBackgroundOutgoingMergedTopMaskImage
}
case .Bottom:
image = graphics.chatMessageBackgroundOutgoingMergedBottomMaskImage
case .Both:
image = graphics.chatMessageBackgroundOutgoingMergedBothMaskImage
case .Side:
image = graphics.chatMessageBackgroundOutgoingMergedSideMaskImage
case .File:
image = graphics.chatMessageBackgroundOutgoingFileImage
case .translation:
image = graphics.chatMessageBackgroundOutgoingTranslationImage
case .Interaction:
image = graphics.chatMessageInteractionBackgroundImage
}
case let .interaction(mergeType):
switch mergeType {
case let .Interaction(type: interactionType):
switch interactionType {
case .None:
image = graphics.chatMessageInteractionBackgroundImage
case .Top:
image = graphics.chatMessageInteractionBackgroundTopImage
case .Bottom:
image = graphics.chatMessageInteractionBackgroundBottomImage
case .Both:
image = graphics.chatMessageInteractionBackgroundBothImage
}
default:
image = graphics.chatMessageInteractionBackgroundImage
}
}
return image
}
func setType(type: ChatMessageBackgroundType, theme: ChatPresentationThemeData, mediaBox: MediaBox, essentialGraphics: PrincipalThemeEssentialGraphics, maskMode: Bool) {
if self.currentType != type || self.theme != theme || self.currentMaskMode != maskMode {
self.currentType = type
self.theme = theme
self.essentialGraphics = essentialGraphics
if maskMode != self.currentMaskMode {
self.currentMaskMode = maskMode
if maskMode {
let maskView: UIImageView
if let current = self.maskView {
maskView = current
} else {
maskView = UIImageView()
maskView.frame = self.bounds
self.maskView = maskView
self.view.mask = maskView
}
} else {
if let _ = self.maskView {
self.view.mask = nil
self.maskView = nil
}
}
}
switch type {
case .none:
self.backgroundContent.contents = nil
case .incoming:
self.backgroundContent.contents = essentialGraphics.incomingBubbleGradientImage?.cgImage
case .outgoing:
self.backgroundContent.contents = essentialGraphics.outgoingBubbleGradientImage?.cgImage
case .interaction:
self.backgroundContent.contents = nil
}
if let maskView = self.maskView {
maskView.image = self.maskForType(type, graphics: essentialGraphics)
}
}
}
ChatMessageMediaBubbleContentNode