cloudx-react-native 2.0.0-beta.1 → 2.2.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (198) hide show
  1. package/README.md +420 -1046
  2. package/android/build.gradle +1 -2
  3. package/android/src/main/AndroidManifest.xml +0 -4
  4. package/android/src/main/java/com/cloudxreactnative/CloudXAdEvents.kt +39 -0
  5. package/android/src/main/java/com/cloudxreactnative/CloudXAdInfo.kt +32 -0
  6. package/android/src/main/java/com/cloudxreactnative/CloudXModuleImpl.kt +694 -0
  7. package/android/src/{newarch/com/cloudxreactnative/CloudXReactNativePackage.kt → main/java/com/cloudxreactnative/CloudXPackage.kt} +14 -13
  8. package/android/src/newarch/com/cloudxreactnative/{CloudXReactNativeModule.kt → CloudXModule.kt} +31 -34
  9. package/android/src/oldarch/com/cloudxreactnative/{CloudXReactNativeModule.kt → CloudXModule.kt} +27 -32
  10. package/cloudx-react-native.podspec +1 -1
  11. package/ios/CloudX.h +47 -0
  12. package/ios/CloudX.mm +1406 -0
  13. package/lib/commonjs/AppTrackingTransparency.js +13 -13
  14. package/lib/commonjs/AppTrackingTransparency.js.map +1 -1
  15. package/lib/commonjs/CloudX.js +16 -12
  16. package/lib/commonjs/CloudX.js.map +1 -1
  17. package/lib/commonjs/CloudXAdPosition.js +23 -0
  18. package/lib/commonjs/CloudXAdPosition.js.map +1 -0
  19. package/lib/commonjs/{BannerAd.js → CloudXBannerAd.js} +42 -37
  20. package/lib/commonjs/CloudXBannerAd.js.map +1 -0
  21. package/lib/commonjs/CloudXErrorCode.js +116 -0
  22. package/lib/commonjs/CloudXErrorCode.js.map +1 -0
  23. package/lib/commonjs/{InterstitialAd.js → CloudXInterstitialAd.js} +10 -10
  24. package/lib/commonjs/CloudXInterstitialAd.js.map +1 -0
  25. package/lib/commonjs/{MRecAd.js → CloudXMRECAd.js} +42 -37
  26. package/lib/commonjs/CloudXMRECAd.js.map +1 -0
  27. package/lib/commonjs/{RewardedAd.js → CloudXRewardedAd.js} +10 -10
  28. package/lib/commonjs/CloudXRewardedAd.js.map +1 -0
  29. package/lib/commonjs/EventEmitter.js +3 -3
  30. package/lib/commonjs/EventEmitter.js.map +1 -1
  31. package/lib/commonjs/hooks.js +25 -26
  32. package/lib/commonjs/hooks.js.map +1 -1
  33. package/lib/commonjs/index.js +27 -41
  34. package/lib/commonjs/index.js.map +1 -1
  35. package/lib/commonjs/specs/{NativeCloudXModule.js → NativeCloudX.js} +2 -2
  36. package/lib/commonjs/specs/NativeCloudX.js.map +1 -0
  37. package/lib/commonjs/types/AdProps.js +6 -0
  38. package/lib/commonjs/types/AdProps.js.map +1 -0
  39. package/lib/commonjs/types/InterstitialAd.js +6 -0
  40. package/lib/commonjs/types/InterstitialAd.js.map +1 -0
  41. package/lib/commonjs/types/MRECAd.js +6 -0
  42. package/lib/commonjs/types/MRECAd.js.map +1 -0
  43. package/lib/commonjs/types/ViewAd.js +6 -0
  44. package/lib/commonjs/types/ViewAd.js.map +1 -0
  45. package/lib/module/AppTrackingTransparency.js +12 -12
  46. package/lib/module/AppTrackingTransparency.js.map +1 -1
  47. package/lib/module/CloudX.js +16 -12
  48. package/lib/module/CloudX.js.map +1 -1
  49. package/lib/module/CloudXAdPosition.js +17 -0
  50. package/lib/module/CloudXAdPosition.js.map +1 -0
  51. package/lib/module/{BannerAd.js → CloudXBannerAd.js} +41 -36
  52. package/lib/module/CloudXBannerAd.js.map +1 -0
  53. package/lib/module/CloudXErrorCode.js +110 -0
  54. package/lib/module/CloudXErrorCode.js.map +1 -0
  55. package/lib/module/{InterstitialAd.js → CloudXInterstitialAd.js} +9 -9
  56. package/lib/module/CloudXInterstitialAd.js.map +1 -0
  57. package/lib/module/{MRecAd.js → CloudXMRECAd.js} +41 -36
  58. package/lib/module/CloudXMRECAd.js.map +1 -0
  59. package/lib/module/{RewardedAd.js → CloudXRewardedAd.js} +9 -9
  60. package/lib/module/CloudXRewardedAd.js.map +1 -0
  61. package/lib/module/EventEmitter.js +2 -2
  62. package/lib/module/EventEmitter.js.map +1 -1
  63. package/lib/module/hooks.js +14 -15
  64. package/lib/module/hooks.js.map +1 -1
  65. package/lib/module/index.js +9 -10
  66. package/lib/module/index.js.map +1 -1
  67. package/lib/module/specs/{NativeCloudXModule.js → NativeCloudX.js} +2 -2
  68. package/lib/module/specs/NativeCloudX.js.map +1 -0
  69. package/lib/module/types/AdProps.js +2 -0
  70. package/lib/module/types/AdProps.js.map +1 -0
  71. package/lib/module/types/InterstitialAd.js +2 -0
  72. package/lib/module/types/InterstitialAd.js.map +1 -0
  73. package/lib/module/types/MRECAd.js +2 -0
  74. package/lib/module/types/MRECAd.js.map +1 -0
  75. package/lib/module/types/ViewAd.js +2 -0
  76. package/lib/module/types/ViewAd.js.map +1 -0
  77. package/lib/typescript/src/AppTrackingTransparency.d.ts +4 -4
  78. package/lib/typescript/src/AppTrackingTransparency.d.ts.map +1 -1
  79. package/lib/typescript/src/CloudX.d.ts.map +1 -1
  80. package/lib/typescript/src/CloudXAdPosition.d.ts +16 -0
  81. package/lib/typescript/src/CloudXAdPosition.d.ts.map +1 -0
  82. package/lib/typescript/src/CloudXBannerAd.d.ts +4 -0
  83. package/lib/typescript/src/CloudXBannerAd.d.ts.map +1 -0
  84. package/lib/typescript/src/{ErrorCode.d.ts → CloudXErrorCode.d.ts} +2 -2
  85. package/lib/typescript/src/CloudXErrorCode.d.ts.map +1 -0
  86. package/lib/typescript/src/CloudXInterstitialAd.d.ts +4 -0
  87. package/lib/typescript/src/CloudXInterstitialAd.d.ts.map +1 -0
  88. package/lib/typescript/src/CloudXMRECAd.d.ts +4 -0
  89. package/lib/typescript/src/CloudXMRECAd.d.ts.map +1 -0
  90. package/lib/typescript/src/CloudXRewardedAd.d.ts +4 -0
  91. package/lib/typescript/src/CloudXRewardedAd.d.ts.map +1 -0
  92. package/lib/typescript/src/EventEmitter.d.ts +4 -2
  93. package/lib/typescript/src/EventEmitter.d.ts.map +1 -1
  94. package/lib/typescript/src/hooks.d.ts +7 -8
  95. package/lib/typescript/src/hooks.d.ts.map +1 -1
  96. package/lib/typescript/src/index.d.ts +12 -13
  97. package/lib/typescript/src/index.d.ts.map +1 -1
  98. package/lib/typescript/src/specs/{NativeCloudXModule.d.ts → NativeCloudX.d.ts} +47 -64
  99. package/lib/typescript/src/specs/NativeCloudX.d.ts.map +1 -0
  100. package/lib/typescript/src/types/AdEvent.d.ts +3 -3
  101. package/lib/typescript/src/types/AdEvent.d.ts.map +1 -1
  102. package/lib/typescript/src/types/AdInfo.d.ts +7 -7
  103. package/lib/typescript/src/types/AdInfo.d.ts.map +1 -1
  104. package/lib/typescript/src/types/AdProps.d.ts +21 -0
  105. package/lib/typescript/src/types/AdProps.d.ts.map +1 -0
  106. package/lib/typescript/src/types/BannerAd.d.ts +8 -34
  107. package/lib/typescript/src/types/BannerAd.d.ts.map +1 -1
  108. package/lib/typescript/src/types/CloudX.d.ts +7 -4
  109. package/lib/typescript/src/types/CloudX.d.ts.map +1 -1
  110. package/lib/typescript/src/types/Configuration.d.ts +7 -3
  111. package/lib/typescript/src/types/Configuration.d.ts.map +1 -1
  112. package/lib/typescript/src/types/FullscreenAd.d.ts +10 -9
  113. package/lib/typescript/src/types/FullscreenAd.d.ts.map +1 -1
  114. package/lib/typescript/src/types/InterstitialAd.d.ts +8 -0
  115. package/lib/typescript/src/types/InterstitialAd.d.ts.map +1 -0
  116. package/lib/typescript/src/types/MRECAd.d.ts +13 -0
  117. package/lib/typescript/src/types/MRECAd.d.ts.map +1 -0
  118. package/lib/typescript/src/types/RewardedAd.d.ts +5 -4
  119. package/lib/typescript/src/types/RewardedAd.d.ts.map +1 -1
  120. package/lib/typescript/src/types/ViewAd.d.ts +29 -0
  121. package/lib/typescript/src/types/ViewAd.d.ts.map +1 -0
  122. package/lib/typescript/src/types/index.d.ts +11 -7
  123. package/lib/typescript/src/types/index.d.ts.map +1 -1
  124. package/package.json +8 -10
  125. package/src/AppTrackingTransparency.ts +10 -10
  126. package/src/CloudX.ts +21 -16
  127. package/src/CloudXAdPosition.ts +16 -0
  128. package/src/{BannerAd.ts → CloudXBannerAd.ts} +69 -47
  129. package/src/{ErrorCode.ts → CloudXErrorCode.ts} +1 -1
  130. package/src/{InterstitialAd.ts → CloudXInterstitialAd.ts} +17 -17
  131. package/src/{MRecAd.ts → CloudXMRECAd.ts} +69 -47
  132. package/src/{RewardedAd.ts → CloudXRewardedAd.ts} +18 -18
  133. package/src/EventEmitter.ts +4 -4
  134. package/src/hooks.ts +20 -22
  135. package/src/index.ts +27 -24
  136. package/src/specs/{NativeCloudXModule.ts → NativeCloudX.ts} +61 -82
  137. package/src/types/AdEvent.ts +3 -3
  138. package/src/types/AdInfo.ts +7 -7
  139. package/src/types/AdProps.ts +27 -0
  140. package/src/types/BannerAd.ts +8 -54
  141. package/src/types/CloudX.ts +10 -5
  142. package/src/types/Configuration.ts +8 -3
  143. package/src/types/FullscreenAd.ts +10 -9
  144. package/src/types/InterstitialAd.ts +8 -0
  145. package/src/types/MRECAd.ts +13 -0
  146. package/src/types/RewardedAd.ts +5 -4
  147. package/src/types/ViewAd.ts +38 -0
  148. package/src/types/index.ts +11 -7
  149. package/android/src/main/java/com/cloudxreactnative/CloudXAdViewEvent.kt +0 -15
  150. package/android/src/main/java/com/cloudxreactnative/CloudXBannerViewManagerImpl.kt +0 -472
  151. package/android/src/main/java/com/cloudxreactnative/CloudXReactNativeModuleImpl.kt +0 -861
  152. package/android/src/newarch/com/cloudxreactnative/CloudXBannerViewManager.kt +0 -90
  153. package/android/src/oldarch/com/cloudxreactnative/CloudXBannerViewManager.kt +0 -76
  154. package/android/src/oldarch/com/cloudxreactnative/CloudXReactNativePackage.kt +0 -16
  155. package/ios/RNCloudXBannerView.h +0 -51
  156. package/ios/RNCloudXBannerView.mm +0 -633
  157. package/ios/RNCloudXBannerViewManager.h +0 -11
  158. package/ios/RNCloudXBannerViewManager.mm +0 -60
  159. package/ios/RNCloudXModule.h +0 -30
  160. package/ios/RNCloudXModule.mm +0 -1088
  161. package/lib/commonjs/AdView.js +0 -151
  162. package/lib/commonjs/AdView.js.map +0 -1
  163. package/lib/commonjs/BannerAd.js.map +0 -1
  164. package/lib/commonjs/ErrorCode.js +0 -116
  165. package/lib/commonjs/ErrorCode.js.map +0 -1
  166. package/lib/commonjs/InterstitialAd.js.map +0 -1
  167. package/lib/commonjs/MRecAd.js.map +0 -1
  168. package/lib/commonjs/RewardedAd.js.map +0 -1
  169. package/lib/commonjs/specs/CloudXAdViewNativeComponent.js +0 -26
  170. package/lib/commonjs/specs/CloudXAdViewNativeComponent.js.map +0 -1
  171. package/lib/commonjs/specs/NativeCloudXModule.js.map +0 -1
  172. package/lib/module/AdView.js +0 -144
  173. package/lib/module/AdView.js.map +0 -1
  174. package/lib/module/BannerAd.js.map +0 -1
  175. package/lib/module/ErrorCode.js +0 -110
  176. package/lib/module/ErrorCode.js.map +0 -1
  177. package/lib/module/InterstitialAd.js.map +0 -1
  178. package/lib/module/MRecAd.js.map +0 -1
  179. package/lib/module/RewardedAd.js.map +0 -1
  180. package/lib/module/specs/CloudXAdViewNativeComponent.js +0 -20
  181. package/lib/module/specs/CloudXAdViewNativeComponent.js.map +0 -1
  182. package/lib/module/specs/NativeCloudXModule.js.map +0 -1
  183. package/lib/typescript/src/AdView.d.ts +0 -69
  184. package/lib/typescript/src/AdView.d.ts.map +0 -1
  185. package/lib/typescript/src/BannerAd.d.ts +0 -4
  186. package/lib/typescript/src/BannerAd.d.ts.map +0 -1
  187. package/lib/typescript/src/ErrorCode.d.ts.map +0 -1
  188. package/lib/typescript/src/InterstitialAd.d.ts +0 -4
  189. package/lib/typescript/src/InterstitialAd.d.ts.map +0 -1
  190. package/lib/typescript/src/MRecAd.d.ts +0 -4
  191. package/lib/typescript/src/MRecAd.d.ts.map +0 -1
  192. package/lib/typescript/src/RewardedAd.d.ts +0 -4
  193. package/lib/typescript/src/RewardedAd.d.ts.map +0 -1
  194. package/lib/typescript/src/specs/CloudXAdViewNativeComponent.d.ts +0 -61
  195. package/lib/typescript/src/specs/CloudXAdViewNativeComponent.d.ts.map +0 -1
  196. package/lib/typescript/src/specs/NativeCloudXModule.d.ts.map +0 -1
  197. package/src/AdView.tsx +0 -213
  198. package/src/specs/CloudXAdViewNativeComponent.ts +0 -82
@@ -1,472 +0,0 @@
1
- package com.cloudxreactnative
2
-
3
- import android.os.Build
4
- import android.util.Log
5
- import android.view.Gravity
6
- import android.view.View
7
- import android.view.ViewGroup
8
- import android.view.WindowInsets
9
- import android.widget.FrameLayout
10
- import com.facebook.react.bridge.Arguments
11
- import com.facebook.react.bridge.ReactApplicationContext
12
- import com.facebook.react.bridge.WritableMap
13
- import com.facebook.react.common.MapBuilder
14
- import com.facebook.react.uimanager.ThemedReactContext
15
- import com.facebook.react.uimanager.UIManagerHelper
16
- import io.cloudx.sdk.*
17
-
18
- /**
19
- * Ad view position options for programmatic banner placement.
20
- * Used for programmatic banner placement.
21
- */
22
- enum class AdViewPosition {
23
- NONE, // Use React Native layout (default)
24
- TOP_LEFT,
25
- TOP_CENTER,
26
- TOP_RIGHT,
27
- CENTER_LEFT,
28
- CENTERED,
29
- CENTER_RIGHT,
30
- BOTTOM_LEFT,
31
- BOTTOM_CENTER,
32
- BOTTOM_RIGHT;
33
-
34
- companion object {
35
- fun fromString(value: String?): AdViewPosition {
36
- return when (value?.uppercase()) {
37
- "TOP_LEFT" -> TOP_LEFT
38
- "TOP_CENTER" -> TOP_CENTER
39
- "TOP_RIGHT" -> TOP_RIGHT
40
- "CENTER_LEFT" -> CENTER_LEFT
41
- "CENTERED" -> CENTERED
42
- "CENTER_RIGHT" -> CENTER_RIGHT
43
- "BOTTOM_LEFT" -> BOTTOM_LEFT
44
- "BOTTOM_CENTER" -> BOTTOM_CENTER
45
- "BOTTOM_RIGHT" -> BOTTOM_RIGHT
46
- else -> NONE
47
- }
48
- }
49
- }
50
- }
51
-
52
- /**
53
- * Wrapper view that holds a CloudXAdView
54
- * This allows us to create the ad AFTER props are set
55
- */
56
- class CloudXBannerViewWrapper(context: ThemedReactContext) : FrameLayout(context) {
57
- var placement: String? = null
58
- var adId: String? = null
59
- var adType: String? = null
60
- var position: String? = null
61
- var customData: String? = null
62
- var autoRefresh: Boolean = true
63
- var shouldLoad: Boolean = false
64
- var hasCreatedAd: Boolean = false
65
- var isDestroyed: Boolean = false
66
- var cloudXAdView: CloudXAdView? = null
67
- var isUsingWindowPositioning: Boolean = false
68
- val reactContext: ThemedReactContext = context
69
-
70
- init {
71
- clipChildren = false
72
- clipToPadding = false
73
- }
74
-
75
- override fun onDetachedFromWindow() {
76
- super.onDetachedFromWindow()
77
- cloudXAdView?.stopAutoRefresh()
78
- if (isUsingWindowPositioning) {
79
- removeAdFromWindow()
80
- }
81
- }
82
-
83
- override fun onAttachedToWindow() {
84
- super.onAttachedToWindow()
85
- if (autoRefresh) {
86
- cloudXAdView?.startAutoRefresh()
87
- }
88
- }
89
-
90
- fun removeAdFromWindow() {
91
- cloudXAdView?.let { adView ->
92
- (adView.parent as? ViewGroup)?.removeView(adView)
93
- }
94
- }
95
-
96
- override fun requestLayout() {
97
- super.requestLayout()
98
- if (isUsingWindowPositioning) return
99
- // No-op: ad views are always placed in the Activity's content frame
100
- // (see addAdAsSubview). requestLayout is not needed for subview mode
101
- // because we position via window overlay at the wrapper's coordinates.
102
- }
103
- }
104
-
105
- /**
106
- * Shared implementation for CloudXBannerViewManager
107
- * Used by both old and new architecture
108
- */
109
- object CloudXBannerViewManagerImpl {
110
- const val NAME = "CloudXAdView"
111
- private const val TAG = "CloudXBannerViewManager"
112
-
113
- fun createViewInstance(reactContext: ThemedReactContext): CloudXBannerViewWrapper {
114
- return CloudXBannerViewWrapper(reactContext)
115
- }
116
-
117
- fun setPlacement(view: CloudXBannerViewWrapper, placement: String?) {
118
- view.placement = placement
119
- view.cloudXAdView?.setPlacement(placement)
120
- maybeCreateAdView(view)
121
- }
122
-
123
- fun setAdId(view: CloudXBannerViewWrapper, adId: String?) {
124
- view.adId = adId
125
- maybeCreateAdView(view)
126
- }
127
-
128
- fun setAdType(view: CloudXBannerViewWrapper, adType: String?) {
129
- val oldType = view.adType
130
- view.adType = adType
131
- // Destroy and recreate if format changed on an already-mounted ad,
132
- // since banner and MREC use different native SDK creation methods.
133
- if (view.hasCreatedAd && oldType != null && oldType != adType) {
134
- onDropViewInstance(view)
135
- view.hasCreatedAd = false
136
- view.isDestroyed = false
137
- maybeCreateAdView(view)
138
- }
139
- }
140
-
141
- fun setPosition(view: CloudXBannerViewWrapper, position: String?) {
142
- view.position = position
143
- }
144
-
145
- fun setCustomData(view: CloudXBannerViewWrapper, customData: String?) {
146
- view.customData = customData
147
- view.cloudXAdView?.setCustomData(customData)
148
- }
149
-
150
- fun setAutoRefresh(view: CloudXBannerViewWrapper, autoRefresh: Boolean) {
151
- view.autoRefresh = autoRefresh
152
- view.cloudXAdView?.let { adView ->
153
- if (autoRefresh) adView.startAutoRefresh() else adView.stopAutoRefresh()
154
- }
155
- }
156
-
157
- fun setShouldLoad(view: CloudXBannerViewWrapper, shouldLoad: Boolean) {
158
- view.shouldLoad = shouldLoad
159
- maybeCreateAdView(view)
160
- }
161
-
162
- fun onAfterUpdateTransaction(view: CloudXBannerViewWrapper) {
163
- if (view.isDestroyed) {
164
- view.hasCreatedAd = false
165
- view.isDestroyed = false
166
- view.isUsingWindowPositioning = false
167
- }
168
- maybeCreateAdView(view)
169
- }
170
-
171
- private fun maybeCreateAdView(view: CloudXBannerViewWrapper) {
172
- if (view.shouldLoad && !view.hasCreatedAd && view.adId != null) {
173
- // Defer to next run loop so all props are set before creation,
174
- // matching iOS dispatch_async(dispatch_get_main_queue()) pattern
175
- view.post {
176
- if (!view.hasCreatedAd && !view.isDestroyed) {
177
- createAndLoadAd(view)
178
- }
179
- }
180
- }
181
- }
182
-
183
- private fun createAndLoadAd(view: CloudXBannerViewWrapper) {
184
- val adId = view.adId ?: return
185
- val adType = view.adType ?: "BANNER"
186
-
187
- val cloudXAdView = when (adType.uppercase()) {
188
- "MREC" -> CloudX.createMREC(adId)
189
- else -> CloudX.createBanner(adId)
190
- }
191
-
192
- view.cloudXAdView = cloudXAdView
193
- view.hasCreatedAd = true
194
-
195
- view.placement?.let { cloudXAdView.setPlacement(it) }
196
- view.customData?.let { cloudXAdView.setCustomData(it) }
197
-
198
- // Set up listeners BEFORE adding to view hierarchy
199
- setupListeners(view, cloudXAdView, adId)
200
-
201
- // Check if we should use programmatic window positioning
202
- val adPosition = AdViewPosition.fromString(view.position)
203
- val isMREC = adType.uppercase() == "MREC"
204
-
205
- if (adPosition != AdViewPosition.NONE) {
206
- addAdToWindow(view, cloudXAdView, adPosition, isMREC)
207
- } else {
208
- addAdAsSubview(view, cloudXAdView)
209
- }
210
-
211
- if (!view.autoRefresh) {
212
- cloudXAdView.stopAutoRefresh()
213
- }
214
-
215
- view.post {
216
- if (!view.isDestroyed) {
217
- cloudXAdView.load()
218
- }
219
- }
220
- }
221
-
222
- private fun addAdAsSubview(wrapper: CloudXBannerViewWrapper, adView: CloudXAdView) {
223
- // The CloudX SDK's visibility detection (background→foreground layer promotion)
224
- // only works when CXAdView is in the Activity's native view hierarchy, not when
225
- // nested inside React Native's Yoga-managed views. To work around this, we add
226
- // the ad to the Activity's content frame but position it at the wrapper's screen
227
- // coordinates so it visually appears in the expected React Native layout position.
228
- wrapper.isUsingWindowPositioning = true
229
-
230
- val activity = wrapper.reactContext.currentActivity
231
- if (activity == null) {
232
- Log.e(TAG, "No activity for subview-as-overlay; falling back to direct addView")
233
- wrapper.isUsingWindowPositioning = false
234
- wrapper.addView(adView)
235
- return
236
- }
237
-
238
- val contentFrame = activity.window.decorView.findViewById<FrameLayout>(android.R.id.content)
239
- if (contentFrame == null) {
240
- Log.e(TAG, "No content frame for subview-as-overlay; falling back to direct addView")
241
- wrapper.isUsingWindowPositioning = false
242
- wrapper.addView(adView)
243
- return
244
- }
245
-
246
- val isMREC = (wrapper.adType ?: "BANNER").uppercase() == "MREC"
247
- val density = wrapper.context.resources.displayMetrics.density
248
- val isTablet = wrapper.context.resources.configuration.smallestScreenWidthDp >= 600
249
- val adWidthPx = ((if (isMREC) 300 else if (isTablet) 728 else 320) * density).toInt()
250
- val adHeightPx = ((if (isMREC) 250 else if (isTablet) 90 else 50) * density).toInt()
251
-
252
- val layoutParams = FrameLayout.LayoutParams(adWidthPx, adHeightPx).apply {
253
- gravity = Gravity.TOP or Gravity.START
254
- }
255
-
256
- contentFrame.addView(adView, layoutParams)
257
- adView.visibility = View.VISIBLE
258
-
259
- // Position the ad at the wrapper's screen coordinates, updating on layout changes
260
- fun updateAdPosition() {
261
- if (wrapper.isDestroyed) return
262
- val loc = IntArray(2)
263
- wrapper.getLocationInWindow(loc)
264
- val centerX = loc[0] + wrapper.width / 2 - adWidthPx / 2
265
- val centerY = loc[1] + wrapper.height / 2 - adHeightPx / 2
266
- layoutParams.leftMargin = centerX
267
- layoutParams.topMargin = centerY
268
- adView.layoutParams = layoutParams
269
- }
270
-
271
- wrapper.addOnLayoutChangeListener { _, _, _, _, _, _, _, _, _ ->
272
- wrapper.postDelayed(::updateAdPosition, 100)
273
- }
274
-
275
- // Initial position after Yoga computes layout
276
- wrapper.postDelayed(::updateAdPosition, 500)
277
- }
278
-
279
- private fun addAdToWindow(wrapper: CloudXBannerViewWrapper, adView: CloudXAdView, position: AdViewPosition, isMREC: Boolean) {
280
- wrapper.isUsingWindowPositioning = true
281
-
282
- val activity = wrapper.reactContext.currentActivity
283
- if (activity == null) {
284
- Log.e(TAG, "No activity found for window positioning, falling back to React Native layout")
285
- addAdAsSubview(wrapper, adView)
286
- return
287
- }
288
-
289
- val decorView = activity.window.decorView as? ViewGroup
290
- if (decorView == null) {
291
- Log.e(TAG, "No decor view found, falling back to React Native layout")
292
- addAdAsSubview(wrapper, adView)
293
- return
294
- }
295
-
296
- val contentFrame = decorView.findViewById<FrameLayout>(android.R.id.content)
297
- if (contentFrame == null) {
298
- Log.e(TAG, "No content frame found, falling back to React Native layout")
299
- addAdAsSubview(wrapper, adView)
300
- return
301
- }
302
-
303
- val density = wrapper.context.resources.displayMetrics.density
304
- val isTablet = wrapper.context.resources.configuration.smallestScreenWidthDp >= 600
305
- val bannerWidthPx = ((if (isMREC) 300 else if (isTablet) 728 else 320) * density).toInt()
306
- val bannerHeightPx = ((if (isMREC) 250 else if (isTablet) 90 else 50) * density).toInt()
307
-
308
- // Safe area insets (matches iOS safeAreaInsets behavior)
309
- var insetTop = 0
310
- var insetBottom = 0
311
- var insetLeft = 0
312
- var insetRight = 0
313
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
314
- val windowInsets = decorView.rootWindowInsets
315
- if (windowInsets != null) {
316
- val systemBars = windowInsets.getInsets(WindowInsets.Type.systemBars())
317
- insetTop = systemBars.top
318
- insetBottom = systemBars.bottom
319
- insetLeft = systemBars.left
320
- insetRight = systemBars.right
321
- }
322
- } else {
323
- @Suppress("DEPRECATION")
324
- decorView.rootWindowInsets?.let { insets ->
325
- insetTop = insets.systemWindowInsetTop
326
- insetBottom = insets.systemWindowInsetBottom
327
- insetLeft = insets.systemWindowInsetLeft
328
- insetRight = insets.systemWindowInsetRight
329
- }
330
- }
331
-
332
- val gravity = when (position) {
333
- AdViewPosition.TOP_LEFT -> Gravity.TOP or Gravity.START
334
- AdViewPosition.TOP_CENTER -> Gravity.TOP or Gravity.CENTER_HORIZONTAL
335
- AdViewPosition.TOP_RIGHT -> Gravity.TOP or Gravity.END
336
- AdViewPosition.CENTER_LEFT -> Gravity.CENTER_VERTICAL or Gravity.START
337
- AdViewPosition.CENTERED -> Gravity.CENTER
338
- AdViewPosition.CENTER_RIGHT -> Gravity.CENTER_VERTICAL or Gravity.END
339
- AdViewPosition.BOTTOM_LEFT -> Gravity.BOTTOM or Gravity.START
340
- AdViewPosition.BOTTOM_CENTER -> Gravity.BOTTOM or Gravity.CENTER_HORIZONTAL
341
- AdViewPosition.BOTTOM_RIGHT -> Gravity.BOTTOM or Gravity.END
342
- else -> Gravity.BOTTOM or Gravity.CENTER_HORIZONTAL
343
- }
344
-
345
- val marginTop = when (position) {
346
- AdViewPosition.TOP_LEFT, AdViewPosition.TOP_CENTER, AdViewPosition.TOP_RIGHT -> insetTop
347
- else -> 0
348
- }
349
- val marginBottom = when (position) {
350
- AdViewPosition.BOTTOM_LEFT, AdViewPosition.BOTTOM_CENTER, AdViewPosition.BOTTOM_RIGHT -> insetBottom
351
- else -> 0
352
- }
353
- val marginLeft = when (position) {
354
- AdViewPosition.TOP_LEFT, AdViewPosition.CENTER_LEFT, AdViewPosition.BOTTOM_LEFT -> insetLeft
355
- else -> 0
356
- }
357
- val marginRight = when (position) {
358
- AdViewPosition.TOP_RIGHT, AdViewPosition.CENTER_RIGHT, AdViewPosition.BOTTOM_RIGHT -> insetRight
359
- else -> 0
360
- }
361
-
362
- val layoutParams = FrameLayout.LayoutParams(bannerWidthPx, bannerHeightPx).apply {
363
- this.gravity = gravity
364
- setMargins(marginLeft, marginTop, marginRight, marginBottom)
365
- }
366
-
367
- contentFrame.addView(adView, layoutParams)
368
- adView.visibility = View.VISIBLE
369
- adView.bringToFront()
370
- }
371
-
372
- private fun serializeAdInfo(cloudXAd: CloudXAd, wrapper: CloudXBannerViewWrapper): WritableMap {
373
- val map = Arguments.createMap()
374
- map.putString("adUnitId", cloudXAd.adUnitId ?: wrapper.adId ?: "")
375
- val adFormat = if ((wrapper.adType ?: "BANNER").uppercase() == "MREC") "MREC" else "BANNER"
376
- map.putString("adFormat", adFormat)
377
- map.putString("networkName", cloudXAd.networkName ?: "")
378
- map.putString("networkPlacement", cloudXAd.networkPlacement ?: "")
379
- map.putString("placement", cloudXAd.placement ?: wrapper.placement ?: "")
380
- map.putDouble("revenue", cloudXAd.revenue)
381
- return map
382
- }
383
-
384
- private fun serializeError(adUnitId: String, cloudXError: CloudXError): WritableMap {
385
- val map = Arguments.createMap()
386
- map.putString("adUnitId", adUnitId)
387
- map.putInt("code", cloudXError.code.code)
388
- map.putString("message", cloudXError.message ?: "Unknown error")
389
- return map
390
- }
391
-
392
- private fun sendViewEvent(wrapper: CloudXBannerViewWrapper, eventName: String, data: WritableMap) {
393
- val surfaceId = UIManagerHelper.getSurfaceId(wrapper)
394
- val dispatcher = UIManagerHelper.getEventDispatcherForReactTag(wrapper.reactContext, wrapper.id)
395
- if (dispatcher == null) {
396
- Log.e(TAG, "Event dispatcher is null for event '$eventName' (viewId=${wrapper.id}, surfaceId=$surfaceId) — event will be lost")
397
- return
398
- }
399
- dispatcher.dispatchEvent(CloudXAdViewEvent(surfaceId, wrapper.id, eventName, data))
400
- }
401
-
402
- private fun setupListeners(wrapper: CloudXBannerViewWrapper, adView: CloudXAdView, adId: String) {
403
- adView.listener = object : CloudXAdViewListener {
404
- override fun onAdLoaded(cloudXAd: CloudXAd) {
405
- sendViewEvent(wrapper, "onAdLoaded", serializeAdInfo(cloudXAd, wrapper))
406
- }
407
-
408
- override fun onAdLoadFailed(adUnitId: String, cloudXError: CloudXError) {
409
- sendViewEvent(wrapper, "onAdLoadFailed", serializeError(adUnitId, cloudXError))
410
- }
411
-
412
- override fun onAdClicked(cloudXAd: CloudXAd) {
413
- sendViewEvent(wrapper, "onAdClicked", serializeAdInfo(cloudXAd, wrapper))
414
- }
415
-
416
- override fun onAdExpanded(cloudXAd: CloudXAd) {
417
- sendViewEvent(wrapper, "onAdExpanded", serializeAdInfo(cloudXAd, wrapper))
418
- }
419
-
420
- override fun onAdCollapsed(cloudXAd: CloudXAd) {
421
- sendViewEvent(wrapper, "onAdCollapsed", serializeAdInfo(cloudXAd, wrapper))
422
- }
423
- }
424
-
425
- adView.revenueListener = object : CloudXAdRevenueListener {
426
- override fun onAdRevenuePaid(cloudXAd: CloudXAd) {
427
- sendViewEvent(wrapper, "onAdRevenuePaid", serializeAdInfo(cloudXAd, wrapper))
428
- }
429
- }
430
- }
431
-
432
- fun receiveCommand(view: CloudXBannerViewWrapper, commandId: String, args: com.facebook.react.bridge.ReadableArray?) {
433
- when (commandId) {
434
- "loadAd" -> loadAd(view)
435
- "destroy" -> destroy(view)
436
- }
437
- }
438
-
439
- fun loadAd(view: CloudXBannerViewWrapper) {
440
- view.cloudXAdView?.load()
441
- }
442
-
443
- fun destroy(view: CloudXBannerViewWrapper) {
444
- onDropViewInstance(view)
445
- }
446
-
447
- fun getExportedCustomDirectEventTypeConstants(): Map<String, Any> {
448
- return MapBuilder.builder<String, Any>()
449
- .put("onAdLoaded", MapBuilder.of("registrationName", "onAdLoaded"))
450
- .put("onAdLoadFailed", MapBuilder.of("registrationName", "onAdLoadFailed"))
451
- .put("onAdClicked", MapBuilder.of("registrationName", "onAdClicked"))
452
- .put("onAdExpanded", MapBuilder.of("registrationName", "onAdExpanded"))
453
- .put("onAdCollapsed", MapBuilder.of("registrationName", "onAdCollapsed"))
454
- .put("onAdRevenuePaid", MapBuilder.of("registrationName", "onAdRevenuePaid"))
455
- .build()
456
- }
457
-
458
- fun onDropViewInstance(view: CloudXBannerViewWrapper) {
459
- view.isDestroyed = true
460
- view.cloudXAdView?.let { adView ->
461
- adView.listener = null
462
- adView.revenueListener = null
463
- adView.stopAutoRefresh()
464
- if (view.isUsingWindowPositioning) {
465
- (adView.parent as? ViewGroup)?.removeView(adView)
466
- }
467
- adView.destroy()
468
- }
469
- view.cloudXAdView = null
470
- }
471
- }
472
-