react-native-firework-sdk 2.19.2 → 2.19.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 (40) hide show
  1. package/android/gradle.properties +1 -1
  2. package/android/src/main/java/com/fireworksdk/bridge/components/storyblock/StoryBlockContainerView.kt +3 -12
  3. package/android/src/main/java/com/fireworksdk/bridge/components/videofeed/FWVideoFeed.kt +0 -50
  4. package/android/src/main/java/com/fireworksdk/bridge/reactnative/FWReactNativeSDK.kt +0 -4
  5. package/android/src/main/java/com/fireworksdk/bridge/reactnative/manager/FWStoryBlockManager.kt +109 -111
  6. package/android/src/main/java/com/fireworksdk/bridge/reactnative/manager/FWVideoFeedManager.kt +6 -4
  7. package/android/src/main/java/com/fireworksdk/bridge/reactnative/models/FireworkSDKInterface.kt +0 -1
  8. package/android/src/main/java/com/fireworksdk/bridge/reactnative/module/FireworkSDKModule.kt +0 -6
  9. package/ios/Modules/FireworkSDKModule/FireworkSDKModule.swift +5 -12
  10. package/lib/commonjs/FireworkSDK.js +0 -17
  11. package/lib/commonjs/FireworkSDK.js.map +1 -1
  12. package/lib/commonjs/components/StoryBlock.js +8 -18
  13. package/lib/commonjs/components/StoryBlock.js.map +1 -1
  14. package/lib/commonjs/components/VideoFeed.js +3 -1
  15. package/lib/commonjs/components/VideoFeed.js.map +1 -1
  16. package/lib/commonjs/modules/FireworkSDKModule.js.map +1 -1
  17. package/lib/module/FireworkSDK.js +0 -17
  18. package/lib/module/FireworkSDK.js.map +1 -1
  19. package/lib/module/components/StoryBlock.js +5 -15
  20. package/lib/module/components/StoryBlock.js.map +1 -1
  21. package/lib/module/components/VideoFeed.js +3 -1
  22. package/lib/module/components/VideoFeed.js.map +1 -1
  23. package/lib/module/modules/FireworkSDKModule.js.map +1 -1
  24. package/lib/typescript/commonjs/src/FireworkSDK.d.ts +0 -9
  25. package/lib/typescript/commonjs/src/FireworkSDK.d.ts.map +1 -1
  26. package/lib/typescript/commonjs/src/components/StoryBlock.d.ts.map +1 -1
  27. package/lib/typescript/commonjs/src/components/VideoFeed.d.ts.map +1 -1
  28. package/lib/typescript/commonjs/src/modules/FireworkSDKModule.d.ts +0 -1
  29. package/lib/typescript/commonjs/src/modules/FireworkSDKModule.d.ts.map +1 -1
  30. package/lib/typescript/module/src/FireworkSDK.d.ts +0 -9
  31. package/lib/typescript/module/src/FireworkSDK.d.ts.map +1 -1
  32. package/lib/typescript/module/src/components/StoryBlock.d.ts.map +1 -1
  33. package/lib/typescript/module/src/components/VideoFeed.d.ts.map +1 -1
  34. package/lib/typescript/module/src/modules/FireworkSDKModule.d.ts +0 -1
  35. package/lib/typescript/module/src/modules/FireworkSDKModule.d.ts.map +1 -1
  36. package/package.json +1 -1
  37. package/src/FireworkSDK.ts +0 -17
  38. package/src/components/StoryBlock.tsx +3 -5
  39. package/src/components/VideoFeed.tsx +3 -1
  40. package/src/modules/FireworkSDKModule.ts +0 -1
@@ -6,4 +6,4 @@ FireworkSDK_targetSdkVersion=33
6
6
  FireworkSDK_compileSdkVersion=33
7
7
  FireworkSDK_kotlinVersion=1.8.22
8
8
  FireworkSDK_fwPlayerLaunchMode=singleTask
9
- FireworkSDK_fwNativeVersion=6.30.8
9
+ FireworkSDK_fwNativeVersion=6.30.7
@@ -133,18 +133,6 @@ class StoryBlockContainerView(
133
133
 
134
134
  override fun onAttachedToWindow() {
135
135
  super.onAttachedToWindow()
136
-
137
- // Re-register fragment lifecycle callbacks after reattach (e.g., from removeClippedSubviews)
138
- if (!isCallbackRegistered && storyBlockFragment != null) {
139
- (context as? FragmentActivity)?.supportFragmentManager?.let { fm ->
140
- fm.registerFragmentLifecycleCallbacks(fragmentLifecycleCallbacks, false)
141
- isCallbackRegistered = true
142
- }
143
- if (storyBlockFragment?.isAdded == true) {
144
- isFragmentAttached = true
145
- }
146
- }
147
-
148
136
  // Try to attach pending fragment when view is attached to window
149
137
  pendingFragment?.let { fragment ->
150
138
  val savedPendingFragment = fragment
@@ -181,6 +169,9 @@ class StoryBlockContainerView(
181
169
  }
182
170
  }
183
171
 
172
+ // Clear all references to prevent memory leaks
173
+ // pendingFragment = null
174
+ // storyBlockFragment = null
184
175
  isFragmentAttached = false
185
176
  retryCount = 0
186
177
  totalRetryCount = 0
@@ -2,7 +2,6 @@ package com.fireworksdk.bridge.components.videofeed
2
2
 
3
3
  import android.content.Context
4
4
  import android.util.AttributeSet
5
- import android.view.Choreographer
6
5
  import android.widget.FrameLayout
7
6
  import com.firework.error.FwErrorListener
8
7
  import com.firework.videofeed.FeedViewStateListener
@@ -22,13 +21,10 @@ class FWVideoFeed(
22
21
 
23
22
  val videoFeedView = FwVideoFeedView(context)
24
23
  var videoFeedPropsModel: FWVideoFeedPropsModel = FWVideoFeedPropsModel()
25
- var themedReactContext: Any? = null
26
24
  private var isInit = false
27
25
 
28
26
  private var onWindowFocusChanged = false
29
27
  private var feedViewStateListener: FeedViewStateListener? = null
30
- private var layoutFrameCallback: Choreographer.FrameCallback? = null
31
- private var needsForceLayout = false
32
28
 
33
29
  init {
34
30
  FWLanguageUtil.getInstance(context).updateBaseContextLocale(context)
@@ -36,52 +32,6 @@ class FWVideoFeed(
36
32
  addView(videoFeedView, LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT))
37
33
  }
38
34
 
39
- override fun onAttachedToWindow() {
40
- super.onAttachedToWindow()
41
- needsForceLayout = true
42
- startLayoutUpdates()
43
- }
44
-
45
- override fun onDetachedFromWindow() {
46
- super.onDetachedFromWindow()
47
- stopLayoutUpdates()
48
- }
49
-
50
- private fun startLayoutUpdates() {
51
- if (layoutFrameCallback != null) return
52
- layoutFrameCallback = object : Choreographer.FrameCallback {
53
- override fun doFrame(frameTimeNanos: Long) {
54
- manuallyLayoutChildren()
55
- if (viewTreeObserver.isAlive) {
56
- viewTreeObserver.dispatchOnGlobalLayout()
57
- }
58
- layoutFrameCallback?.let {
59
- Choreographer.getInstance().postFrameCallback(it)
60
- }
61
- }
62
- }
63
- Choreographer.getInstance().postFrameCallback(layoutFrameCallback!!)
64
- }
65
-
66
- private fun stopLayoutUpdates() {
67
- layoutFrameCallback?.let {
68
- Choreographer.getInstance().removeFrameCallback(it)
69
- }
70
- layoutFrameCallback = null
71
- }
72
-
73
- private fun manuallyLayoutChildren() {
74
- if (needsForceLayout) {
75
- videoFeedView.forceLayout()
76
- needsForceLayout = false
77
- }
78
- videoFeedView.measure(
79
- MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY),
80
- MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY)
81
- )
82
- videoFeedView.layout(0, 0, width, height)
83
- }
84
-
85
35
  fun setVideoFeedLayoutParams(l: LayoutParams?) {
86
36
  l ?: return
87
37
  videoFeedView.layoutParams = l
@@ -42,10 +42,6 @@ object FWReactNativeSDK {
42
42
  })
43
43
  }
44
44
 
45
- fun setLanguageSwitchingBehavior(behavior: FWSwitchLanguageBehavior) {
46
- FWGlobalDataUtil.switchLanguageBehavior = behavior
47
- }
48
-
49
45
  fun addLivestreamPlayerInitializer(initializer: LivestreamPlayerInitializer?) {
50
46
  FWLiveStreamUtil.addLivestreamPlayerInitializer(initializer)
51
47
  }
@@ -2,6 +2,7 @@ package com.fireworksdk.bridge.reactnative.manager
2
2
 
3
3
  import android.view.Choreographer
4
4
  import android.view.View
5
+ import android.view.ViewGroup
5
6
  import androidx.fragment.app.FragmentActivity
6
7
  import com.facebook.react.bridge.ReadableArray
7
8
  import com.facebook.react.bridge.ReadableMap
@@ -11,99 +12,34 @@ import com.facebook.react.uimanager.ViewGroupManager
11
12
  import com.facebook.react.uimanager.annotations.ReactProp
12
13
  import com.firework.error.storyblock.StoryBlockError
13
14
  import com.firework.storyblock.FeedLoadState
14
- import com.fireworksdk.bridge.components.storyblock.StoryBlockContainerView
15
15
  import com.fireworksdk.bridge.components.storyblock.StoryBlockFragment
16
+ import com.fireworksdk.bridge.components.storyblock.StoryBlockFrameLayout
16
17
  import com.fireworksdk.bridge.models.*
17
18
  import com.fireworksdk.bridge.models.enums.FWStoryBlockEventName
18
19
  import com.fireworksdk.bridge.models.enums.FWVideoFeedSource
19
20
  import com.fireworksdk.bridge.reactnative.utils.FWEventUtils
21
+ import com.fireworksdk.bridge.utils.FWFragmentUtil
20
22
  import com.fireworksdk.bridge.utils.FWLogUtils
21
23
  import org.json.JSONObject
22
- import java.util.WeakHashMap
23
24
 
24
25
 
25
- class FWStoryBlockManager : ViewGroupManager<StoryBlockContainerView>() {
26
+ class FWStoryBlockManager : ViewGroupManager<StoryBlockFrameLayout>() {
26
27
 
27
- private val viewContextMap = WeakHashMap<StoryBlockContainerView, ThemedReactContext>()
28
- private val viewLayoutCallbackMap = WeakHashMap<StoryBlockContainerView, Choreographer.FrameCallback>()
29
- private val viewNeedsForceLayoutMap = WeakHashMap<StoryBlockContainerView, Boolean>()
28
+ private lateinit var reactContext: ThemedReactContext
30
29
 
31
30
  override fun getName(): String {
32
31
  return REACT_CLASS
33
32
  }
34
33
 
35
- override fun createViewInstance(reactContext: ThemedReactContext): StoryBlockContainerView {
36
- val activity = reactContext.currentActivity as? FragmentActivity
37
- ?: throw IllegalStateException("StoryBlock requires a FragmentActivity")
38
- val containerView = StoryBlockContainerView(activity)
39
- viewContextMap[containerView] = reactContext
40
- containerView.addOnAttachStateChangeListener(object : View.OnAttachStateChangeListener {
41
- override fun onViewAttachedToWindow(v: View) {
42
- viewNeedsForceLayoutMap[containerView] = true
43
- startLayoutUpdates(containerView)
44
- }
45
-
46
- override fun onViewDetachedFromWindow(v: View) {
47
- stopLayoutUpdates(containerView)
48
- }
49
- })
50
- return containerView
34
+ override fun createViewInstance(reactContext: ThemedReactContext): StoryBlockFrameLayout {
35
+ this.reactContext = reactContext
36
+ return StoryBlockFrameLayout(reactContext)
51
37
  }
52
38
 
53
- override fun onAfterUpdateTransaction(view: StoryBlockContainerView) {
39
+ override fun onAfterUpdateTransaction(view: StoryBlockFrameLayout) {
54
40
  super.onAfterUpdateTransaction(view)
55
- initStoryBlock(view)
56
- }
57
-
58
- private fun initStoryBlock(containerView: StoryBlockContainerView) {
59
- if (containerView.storyBlockFragment != null) {
60
- return
61
- }
62
-
63
- val fragment = StoryBlockFragment.newInstance(containerView.videoFeedPropsModel)
64
- val reactContext = viewContextMap[containerView] ?: return
65
- addStoryBlockListener(reactContext, fragment, containerView.id)
66
- containerView.setFragment(fragment)
67
- }
68
-
69
- private fun startLayoutUpdates(containerView: StoryBlockContainerView) {
70
- if (viewLayoutCallbackMap.containsKey(containerView)) return
71
- val callback = object : Choreographer.FrameCallback {
72
- override fun doFrame(frameTimeNanos: Long) {
73
- manuallyLayoutChildren(containerView)
74
- if (containerView.viewTreeObserver.isAlive) {
75
- containerView.viewTreeObserver.dispatchOnGlobalLayout()
76
- }
77
- if (viewLayoutCallbackMap.containsKey(containerView)) {
78
- Choreographer.getInstance().postFrameCallback(this)
79
- }
80
- }
81
- }
82
- viewLayoutCallbackMap[containerView] = callback
83
- Choreographer.getInstance().postFrameCallback(callback)
84
- }
85
-
86
- private fun stopLayoutUpdates(containerView: StoryBlockContainerView) {
87
- viewLayoutCallbackMap.remove(containerView)?.let {
88
- Choreographer.getInstance().removeFrameCallback(it)
89
- }
90
- }
91
-
92
- private fun manuallyLayoutChildren(containerView: StoryBlockContainerView) {
93
- val needsForce = viewNeedsForceLayoutMap.remove(containerView) == true
94
- val width = containerView.width
95
- val height = containerView.height
96
- for (i in 0 until containerView.childCount) {
97
- val child = containerView.getChildAt(i)
98
- if (needsForce) {
99
- child.forceLayout()
100
- }
101
- child.measure(
102
- View.MeasureSpec.makeMeasureSpec(width, View.MeasureSpec.EXACTLY),
103
- View.MeasureSpec.makeMeasureSpec(height, View.MeasureSpec.EXACTLY)
104
- )
105
- child.layout(0, 0, width, height)
106
- }
41
+ // after createFragment
42
+ FWLogUtils.d { "FWStoryBlockManager onAfterUpdateTransaction" }
107
43
  }
108
44
 
109
45
  override fun getCommandsMap(): Map<String, Int> {
@@ -118,30 +54,37 @@ class FWStoryBlockManager : ViewGroupManager<StoryBlockContainerView>() {
118
54
  }
119
55
 
120
56
  override fun receiveCommand(
121
- root: StoryBlockContainerView,
57
+ root: StoryBlockFrameLayout,
122
58
  commandId: Int,
123
59
  args: ReadableArray?
124
60
  ) {
125
61
  super.receiveCommand(root, commandId, args)
126
- FWLogUtils.d { "FWStoryBlockManager receiveCommand (Int), commandId: $commandId" }
127
- handleCommand(root, commandId)
62
+ FWLogUtils.d { "FWStoryBlockManager receiveCommand, args (StoryBlockFrameLayout, Int, ReadableArray?), commandId: $commandId, root.isAttachedToWindow: ${root.isAttachedToWindow}" }
63
+ when (commandId) {
64
+ COMMAND_CREATE -> {
65
+ val reactNativeViewId = requireNotNull(args).getInt(0)
66
+ createFragment(root, reactNativeViewId)
67
+ }
68
+ COMMAND_PLAY -> root.storyBlockFragment?.play()
69
+ COMMAND_PAUSE -> root.storyBlockFragment?.pause()
70
+ COMMAND_OPEN_FULL_SCREEN -> root.storyBlockFragment?.openFullscreen()
71
+ COMMAND_ON_VIEWPORT_ENTERED -> root.storyBlockFragment?.onViewportEntered()
72
+ COMMAND_ON_VIEWPORT_LEFT -> root.storyBlockFragment?.onViewportLeft()
73
+ else -> {}
74
+ }
128
75
  }
129
76
 
130
77
  override fun receiveCommand(
131
- root: StoryBlockContainerView,
78
+ root: StoryBlockFrameLayout,
132
79
  commandId: String?,
133
80
  args: ReadableArray?
134
81
  ) {
135
82
  super.receiveCommand(root, commandId, args)
136
- FWLogUtils.d { "FWStoryBlockManager receiveCommand (String), commandId: $commandId" }
137
- handleCommand(root, commandId?.toIntOrNull() ?: return)
138
- }
139
-
140
- private fun handleCommand(root: StoryBlockContainerView, commandId: Int) {
141
- when (commandId) {
83
+ FWLogUtils.d { "FWStoryBlockManager receiveCommand, args (StoryBlockFrameLayout, String?, ReadableArray?), commandId: $commandId, root.isAttachedToWindow: ${root.isAttachedToWindow}" }
84
+ when (commandId?.toInt()) {
142
85
  COMMAND_CREATE -> {
143
- // No-op: fragment creation is now handled in onAfterUpdateTransaction.
144
- // Kept for backward compatibility with older JS versions.
86
+ val reactNativeViewId = requireNotNull(args).getInt(0)
87
+ createFragment(root, reactNativeViewId)
145
88
  }
146
89
  COMMAND_PLAY -> root.storyBlockFragment?.play()
147
90
  COMMAND_PAUSE -> root.storyBlockFragment?.pause()
@@ -153,28 +96,28 @@ class FWStoryBlockManager : ViewGroupManager<StoryBlockContainerView>() {
153
96
  }
154
97
 
155
98
  @ReactProp(name = "source")
156
- fun setSource(view: StoryBlockContainerView, source: String?) {
99
+ fun setSource(view: StoryBlockFrameLayout, source: String?) {
157
100
  view.videoFeedPropsModel = view.videoFeedPropsModel.copy(
158
101
  source = FWVideoFeedSource.deserialize(source)
159
102
  )
160
103
  }
161
104
 
162
105
  @ReactProp(name = "channel")
163
- fun setChannel(view: StoryBlockContainerView, channel: String?) {
106
+ fun setChannel(view: StoryBlockFrameLayout, channel: String?) {
164
107
  view.videoFeedPropsModel = view.videoFeedPropsModel.copy(
165
108
  channel = channel
166
109
  )
167
110
  }
168
111
 
169
112
  @ReactProp(name = "playlist")
170
- fun setPlaylist(view: StoryBlockContainerView, playlist: String?) {
113
+ fun setPlaylist(view: StoryBlockFrameLayout, playlist: String?) {
171
114
  view.videoFeedPropsModel = view.videoFeedPropsModel.copy(
172
115
  playlist = playlist
173
116
  )
174
117
  }
175
118
 
176
119
  @ReactProp(name = "hashtagFilterExpression")
177
- fun setHashtagFilterExpression(view: StoryBlockContainerView, hashtagFilterExpression: String?) {
120
+ fun setHashtagFilterExpression(view: StoryBlockFrameLayout, hashtagFilterExpression: String?) {
178
121
  view.videoFeedPropsModel = view.videoFeedPropsModel.copy(
179
122
  hashtagFilterExpression = hashtagFilterExpression
180
123
  )
@@ -182,21 +125,21 @@ class FWStoryBlockManager : ViewGroupManager<StoryBlockContainerView>() {
182
125
 
183
126
  @Suppress("UNCHECKED_CAST")
184
127
  @ReactProp(name = "productIds")
185
- fun setProductIds(view: StoryBlockContainerView, productIdArray: ReadableArray?) {
128
+ fun setProductIds(view: StoryBlockFrameLayout, productIdArray: ReadableArray?) {
186
129
  view.videoFeedPropsModel = view.videoFeedPropsModel.copy(
187
130
  productIds = productIdArray?.toArrayList() as ArrayList<String>?
188
131
  )
189
132
  }
190
133
 
191
134
  @ReactProp(name = "contentId")
192
- fun setContentId(view: StoryBlockContainerView, contentId: String?) {
135
+ fun setContentId(view: StoryBlockFrameLayout, contentId: String?) {
193
136
  view.videoFeedPropsModel = view.videoFeedPropsModel.copy(
194
137
  contentId = contentId
195
138
  )
196
139
  }
197
140
 
198
141
  @ReactProp(name = "shareUrl")
199
- fun setShareUrl(view: StoryBlockContainerView, shareUrl: String?) {
142
+ fun setShareUrl(view: StoryBlockFrameLayout, shareUrl: String?) {
200
143
  view.videoFeedPropsModel = view.videoFeedPropsModel.copy(
201
144
  shareUrl = shareUrl
202
145
  )
@@ -204,7 +147,7 @@ class FWStoryBlockManager : ViewGroupManager<StoryBlockContainerView>() {
204
147
 
205
148
  @Suppress("UNCHECKED_CAST")
206
149
  @ReactProp(name = "dynamicContentParameters")
207
- fun setDynamicContentParameters(view: StoryBlockContainerView, parameters: ReadableMap?) {
150
+ fun setDynamicContentParameters(view: StoryBlockFrameLayout, parameters: ReadableMap?) {
208
151
  val parametersMap = parameters?.toHashMap() as? HashMap<String, List<String>>
209
152
  view.videoFeedPropsModel = view.videoFeedPropsModel.copy(
210
153
  dynamicContentParameters = parametersMap
@@ -212,7 +155,7 @@ class FWStoryBlockManager : ViewGroupManager<StoryBlockContainerView>() {
212
155
  }
213
156
 
214
157
  @ReactProp(name = "videoFeedConfiguration")
215
- fun setVideoFeedConfig(view: StoryBlockContainerView, config: ReadableMap?) {
158
+ fun setVideoFeedConfig(view: StoryBlockFrameLayout, config: ReadableMap?) {
216
159
  val configMap = config?.toHashMap() ?: hashMapOf()
217
160
  val jsonObject = JSONObject(configMap)
218
161
  val videoFeedConfigModel = FWVideoFeedConfigModelDeserializer.deserialize(jsonObject)
@@ -222,7 +165,7 @@ class FWStoryBlockManager : ViewGroupManager<StoryBlockContainerView>() {
222
165
  }
223
166
 
224
167
  @ReactProp(name = "storyBlockConfiguration")
225
- fun setStoryBlockConfig(view: StoryBlockContainerView, config: ReadableMap?) {
168
+ fun setStoryBlockConfig(view: StoryBlockFrameLayout, config: ReadableMap?) {
226
169
  val configMap = config?.toHashMap() ?: hashMapOf()
227
170
  val jsonObject = JSONObject(configMap)
228
171
  val videoPlayerConfigModel = FWVideoPlayerConfigModelDeserializer.deserialize(jsonObject)
@@ -232,7 +175,7 @@ class FWStoryBlockManager : ViewGroupManager<StoryBlockContainerView>() {
232
175
  }
233
176
 
234
177
  @ReactProp(name = "adConfiguration")
235
- fun setAdConfiguration(view: StoryBlockContainerView, config: ReadableMap?) {
178
+ fun setAdConfiguration(view: StoryBlockFrameLayout, config: ReadableMap?) {
236
179
  val configMap = config?.toHashMap() ?: hashMapOf()
237
180
  val jsonObject = JSONObject(configMap)
238
181
  val adConfigurationModel = FWAdConfigurationDeserializer.deserialize(jsonObject)
@@ -242,27 +185,42 @@ class FWStoryBlockManager : ViewGroupManager<StoryBlockContainerView>() {
242
185
  }
243
186
 
244
187
  @ReactProp(name = "cornerRadius")
245
- fun setCornerRadius(view: StoryBlockContainerView, cornerRadius: Int?) {
188
+ fun setCornerRadius(view: StoryBlockFrameLayout, cornerRadius: Int?) {
246
189
  view.videoFeedPropsModel = view.videoFeedPropsModel.copy(
247
190
  cornerRadius = cornerRadius
248
191
  )
249
192
  }
250
193
 
251
- private fun addStoryBlockListener(
252
- reactContext: ThemedReactContext,
253
- fragment: StoryBlockFragment,
254
- reactNativeViewId: Int
255
- ) {
194
+ private fun setupLayout(view: View) {
195
+ Choreographer.getInstance().postFrameCallback(object : Choreographer.FrameCallback {
196
+ override fun doFrame(frameTimeNanos: Long) {
197
+ manuallyLayoutChildren(view)
198
+ view.viewTreeObserver.dispatchOnGlobalLayout()
199
+ Choreographer.getInstance().postFrameCallback(this)
200
+ }
201
+ })
202
+ }
203
+
204
+ private fun manuallyLayoutChildren(view: View) {
205
+ view.measure(
206
+ View.MeasureSpec.makeMeasureSpec(view.measuredWidth, View.MeasureSpec.EXACTLY),
207
+ View.MeasureSpec.makeMeasureSpec(view.measuredHeight, View.MeasureSpec.EXACTLY)
208
+ )
209
+ view.layout(view.left, view.top, view.right, view.bottom)
210
+ }
211
+
212
+ private fun addStoryBlockListener(fragment: StoryBlockFragment, reactNativeViewId: Int) {
256
213
  fragment.setCreateViewCallback(object : StoryBlockFragment.OnCreateViewCallback {
257
214
  override fun onCreateView() {
215
+
258
216
  FWEventUtils.receiveStoryBlockGetFeedIdEvent(
259
217
  reactContext,
260
218
  reactNativeViewId,
261
219
  fragment.getFeedId()
262
220
  )
263
221
  }
264
- })
265
222
 
223
+ })
266
224
  fragment.setFeedLoadListener { feedLoadState ->
267
225
  when (feedLoadState) {
268
226
  FeedLoadState.Loading -> {
@@ -304,12 +262,52 @@ class FWStoryBlockManager : ViewGroupManager<StoryBlockContainerView>() {
304
262
  }
305
263
  }
306
264
 
307
- override fun onDropViewInstance(containerView: StoryBlockContainerView) {
308
- stopLayoutUpdates(containerView)
309
- viewContextMap.remove(containerView)
310
- viewNeedsForceLayoutMap.remove(containerView)
311
- containerView.destroy()
312
- super.onDropViewInstance(containerView)
265
+
266
+ private fun createFragment(root: StoryBlockFrameLayout, reactNativeViewId: Int?) {
267
+ FWLogUtils.d { "FWStoryBlockManager createFragment, reactNativeViewId = $reactNativeViewId" }
268
+ reactNativeViewId ?: return
269
+ val activity = reactContext.currentActivity as FragmentActivity?
270
+ activity ?: return
271
+
272
+ val parentView = root.findViewById(reactNativeViewId) as ViewGroup
273
+ // parentView.setBackgroundColor(Color.YELLOW)
274
+ setupLayout(parentView)
275
+
276
+ val fragment = StoryBlockFragment.newInstance(root.videoFeedPropsModel)
277
+ root.storyBlockFragment = fragment
278
+ addStoryBlockListener(fragment, reactNativeViewId)
279
+
280
+ if (parentView.isAttachedToWindow) {
281
+ if (!fragment.isAdded) {
282
+ activity.supportFragmentManager
283
+ .beginTransaction()
284
+ .replace(reactNativeViewId, fragment, reactNativeViewId.toString())
285
+ .commit()
286
+ }
287
+ } else {
288
+ parentView.addOnAttachStateChangeListener(object : View.OnAttachStateChangeListener {
289
+ override fun onViewAttachedToWindow(v: View) {
290
+ FWLogUtils.d { "FWStoryBlockManager createFragment doOnAttach" }
291
+ if (!fragment.isAdded) {
292
+ activity.supportFragmentManager
293
+ .beginTransaction()
294
+ .replace(reactNativeViewId, fragment, reactNativeViewId.toString())
295
+ .commit()
296
+ }
297
+ }
298
+
299
+ override fun onViewDetachedFromWindow(v: View) {
300
+ }
301
+ })
302
+ }
303
+ }
304
+
305
+ override fun onDropViewInstance(storyBlockFrameLayout: StoryBlockFrameLayout) {
306
+ val activity = reactContext.currentActivity as FragmentActivity?
307
+ FWFragmentUtil.removeFragment(activity, storyBlockFrameLayout.storyBlockFragment)
308
+ storyBlockFrameLayout.destroy()
309
+
310
+ super.onDropViewInstance(storyBlockFrameLayout)
313
311
  }
314
312
 
315
313
  override fun getExportedCustomBubblingEventTypeConstants(): Map<String, Any>? {
@@ -29,13 +29,16 @@ import org.json.JSONObject
29
29
 
30
30
  class FWVideoFeedManager : SimpleViewManager<FWVideoFeed>() {
31
31
 
32
+ private lateinit var reactContext: ThemedReactContext
33
+ private lateinit var videoFeed: FWVideoFeed
34
+
32
35
  override fun getName(): String {
33
36
  return "FWVideoFeed"
34
37
  }
35
38
 
36
39
  override fun createViewInstance(reactContext: ThemedReactContext): FWVideoFeed {
37
- val videoFeed = FWVideoFeed(reactContext.currentActivity as Activity)
38
- videoFeed.themedReactContext = reactContext
40
+ this.reactContext = reactContext
41
+ videoFeed = FWVideoFeed(reactContext.currentActivity as Activity)
39
42
  addVideoFeedListener(reactContext, videoFeed)
40
43
  return videoFeed
41
44
  }
@@ -49,10 +52,9 @@ class FWVideoFeedManager : SimpleViewManager<FWVideoFeed>() {
49
52
  super.onAfterUpdateTransaction(view)
50
53
  view.initVideoFeedView()
51
54
 
52
- val reactContext = view.themedReactContext as? ThemedReactContext ?: return
53
55
  FWEventUtils.receiveVideoFeedGetFeedIdEvent(
54
56
  reactContext,
55
- view.id,
57
+ videoFeed.id,
56
58
  view.getFeedId()
57
59
  )
58
60
  }
@@ -18,5 +18,4 @@ interface FireworkSDKInterface {
18
18
  fun setDataTrackingLevel(level: String?, promise: Promise)
19
19
  fun setLivestreamPlayerDesignVersion(version: String?, promise: Promise)
20
20
  fun setShortVideoPlayerDesignVersion(version: String?, promise: Promise)
21
- fun setPreventPipOnLeave(prevent: Boolean?, promise: Promise)
22
21
  }
@@ -360,12 +360,6 @@ class FireworkSDKModule(
360
360
  promise.resolve(true)
361
361
  }
362
362
 
363
- @ReactMethod
364
- override fun setPreventPipOnLeave(prevent: Boolean?, promise: Promise) {
365
- FireworkSdk.setPreventPipOnLeave(prevent ?: false)
366
- promise.resolve(true)
367
- }
368
-
369
363
  @ReactMethod
370
364
  fun addListener(eventName: String?, promise: Promise) {
371
365
  // Set up any upstream listeners or background tasks as necessary
@@ -66,9 +66,10 @@ class FireworkSDKModule: RCTEventEmitter, FireworkVideoSDKDelegate {
66
66
  static func initializeSDK(_ options: SDKInitOptions?) {
67
67
  if let shared = shared {
68
68
  shared.initializeSDK(options, true)
69
+ } else {
70
+ hasCachedSDKInitOptions = true
71
+ cachedSDKInitOptions = options
69
72
  }
70
- hasCachedSDKInitOptions = true
71
- cachedSDKInitOptions = options
72
73
  }
73
74
 
74
75
  @objc(markInitCalled:rejecter:)
@@ -87,16 +88,8 @@ class FireworkSDKModule: RCTEventEmitter, FireworkVideoSDKDelegate {
87
88
 
88
89
  func initializeSDK(_ options: SDKInitOptions?, _ fromNative: Bool) {
89
90
  if hasCalledSDKInit {
90
- if hasListeners, let argumentsForInitEvent = argumentsForInitEvent {
91
- sendEvent(withName: FWEventName.sdkInit.rawValue, body: argumentsForInitEvent)
92
- }
93
- } else if FireworkVideoSDK.isInitialized {
94
- argumentsForInitEvent = [:]
95
- gVideoLaunchBehavior = options?.videoLaunchBehavior
96
- FireworkVideoSDK.ctaDelegate = self
97
- FireworkVideoSDK.eventTracking.videoPlaybackDelegate = self
98
- FireworkVideoSDK.eventTracking.feedDelegate = self
99
- if hasListeners {
91
+ if let argumentsForInitEvent = argumentsForInitEvent {
92
+ // The sdk init event was received before.
100
93
  sendEvent(withName: FWEventName.sdkInit.rawValue, body: argumentsForInitEvent)
101
94
  }
102
95
  } else {
@@ -154,23 +154,6 @@ class FireworkSDK {
154
154
  });
155
155
  }
156
156
  _shortVideoPlayerDesignVersion = _ShortVideoPlayerDesignVersion.default.v1;
157
-
158
- /**
159
- * When enabled, prevents auto-entering PiP when the user leaves the fullscreen player
160
- * (e.g. presses Home or switches to another app). The player activity stays in the
161
- * background stack instead of entering PiP mode.
162
- * Defaults to false. Only supported on Android.
163
- */
164
- set preventPipOnLeave(prevent) {
165
- this._preventPipOnLeave = prevent;
166
- if (_reactNative.Platform.OS === 'android') {
167
- _FireworkSDKModule.default.setPreventPipOnLeave(prevent);
168
- }
169
- }
170
- get preventPipOnLeave() {
171
- return this._preventPipOnLeave;
172
- }
173
- _preventPipOnLeave = false;
174
157
  get eventEmitter() {
175
158
  return _FireworkSDKModule.FireworkSDKModuleEventEmitter;
176
159
  }