-
Notifications
You must be signed in to change notification settings - Fork 15
Expand file tree
/
Copy pathReactInlineMessageView.swift
More file actions
143 lines (118 loc) · 4.4 KB
/
Copy pathReactInlineMessageView.swift
File metadata and controls
143 lines (118 loc) · 4.4 KB
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
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
import CioMessagingInApp
import Foundation
import UIKit
import WebKit
/// React Native wrapper for inline message display with content view lifecycle management.
///
/// This Swift class provides the actual functionality while allowing Objective-C/C++ files to
/// import only the header for compile-time safety across different linking configurations.
/// Methods are called dynamically from Objective-C using runtime resolution.
@objc(ReactInlineMessageView)
class ReactInlineMessageView: NSObject {
private weak var eventEmitter: AnyObject?
private let contentView: InlineMessageBridgeView = .init()
@objc
init(containerView: UIView) {
super.init()
contentView.attachToParent(parent: containerView, delegate: self)
}
@objc
func setEventEmitter(_ eventEmitter: AnyObject?) {
self.eventEmitter = eventEmitter
}
@objc
func setElementId(_ elementId: String) {
// Set element ID on the prepared content view
contentView.elementId = elementId
}
private var showScrollIndicators: Bool = true
@objc
func setShowScrollIndicators(_ showScrollIndicators: Bool) {
self.showScrollIndicators = showScrollIndicators
applyScrollIndicators(in: contentView)
}
@objc
func setupForReuse() {
contentView.onViewAttached()
}
@objc
func prepareForRecycle() {
// Remove content view for reuse, cleaning up observers and releasing resources
contentView.onViewDetached()
}
@objc
func updateLayout(_ boundsValue: NSValue) {
let bounds = boundsValue.cgRectValue
contentView.frame = bounds
contentView.setNeedsLayout()
contentView.layoutIfNeeded()
}
// MARK: - Event Emission Helper
private func emitEvent(_ selectorName: String, payload: [String: Any?]) {
guard let emitter = eventEmitter else {
assertionFailure("Event emitter is nil when trying to emit \(selectorName)")
return
}
let selector = Selector((selectorName))
guard emitter.responds(to: selector) else {
assertionFailure("Event emitter does not respond to selector: \(selectorName)")
return
}
_ = emitter.perform(selector, with: payload as NSDictionary)
}
private func sendOnSizeChangeEvent(width: Double = 0, height: Double) {
let duration = 200.0
var payload: [String: Any] = [
"height": height,
"duration": duration
]
// Only include positive width values as rendering requires valid width to calculate layout size
if width > 0 {
payload["width"] = width
}
emitEvent("emitOnSizeChangeEvent:", payload: payload)
}
private func sendOnStateChangeEvent(state: InlineInAppMessageStateEvent) {
let payload: [String: Any] = [
"state": state.stringValue
]
emitEvent("emitOnStateChangeEvent:", payload: payload)
}
}
extension ReactInlineMessageView: InlineMessageBridgeViewDelegate {
func onActionClick(message: InAppMessage, actionValue: String, actionName: String) -> Bool {
let payload: [String: Any?] = [
"message": [
"messageId": message.messageId,
"deliveryId": message.deliveryId,
"elementId": message.elementId
],
"actionValue": actionValue,
"actionName": actionName
]
emitEvent("emitOnActionClickEvent:", payload: payload)
return true
}
func onMessageSizeChanged(width: CGFloat, height: CGFloat) {
applyScrollIndicators(in: contentView)
sendOnSizeChangeEvent(width: width, height: height)
}
func onNoMessageToDisplay() {
sendOnStateChangeEvent(state: .noMessageToDisplay)
}
func onStartLoading(onComplete: @escaping () -> Void) {
applyScrollIndicators(in: contentView)
sendOnStateChangeEvent(state: .loadingStarted)
onComplete()
}
func onFinishLoading() {
sendOnStateChangeEvent(state: .loadingFinished)
}
private func applyScrollIndicators(in view: UIView) {
if let webView = view as? WKWebView {
webView.scrollView.showsVerticalScrollIndicator = showScrollIndicators
webView.scrollView.showsHorizontalScrollIndicator = showScrollIndicators
}
view.subviews.forEach { applyScrollIndicators(in: $0) }
}
}