react-native-firework-sdk 2.17.0 → 2.17.2

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 (124) hide show
  1. package/android/build.gradle +1 -1
  2. package/android/gradle.properties +1 -1
  3. package/android/src/main/java/com/fireworksdk/bridge/components/storyblock/StoryBlockContainer.kt +13 -0
  4. package/android/src/main/java/com/fireworksdk/bridge/components/storyblock/StoryBlockContainerView.kt +103 -0
  5. package/android/src/main/java/com/fireworksdk/bridge/components/storyblock/StoryBlockFragment.kt +9 -0
  6. package/android/src/main/java/com/fireworksdk/bridge/components/storyblock/StoryBlockFrameLayout.kt +5 -4
  7. package/android/src/main/java/com/fireworksdk/bridge/models/FWChatConfigModelDeserializer.kt +21 -0
  8. package/android/src/main/java/com/fireworksdk/bridge/models/FWControlsInsetModel.kt +3 -0
  9. package/android/src/main/java/com/fireworksdk/bridge/models/FWControlsInsetModelDeserializer.kt +15 -0
  10. package/android/src/main/java/com/fireworksdk/bridge/models/FWControlsInsetModelSerializer.kt +17 -0
  11. package/android/src/main/java/com/fireworksdk/bridge/models/FWLiveStreamEventDetailsModel.kt +2 -1
  12. package/android/src/main/java/com/fireworksdk/bridge/models/FWProductInfoViewConfiguration.kt +28 -1
  13. package/android/src/main/java/com/fireworksdk/bridge/models/FWProductInfoViewConfigurationDeserializer.kt +72 -1
  14. package/android/src/main/java/com/fireworksdk/bridge/models/FWShoppingCustomCta.kt +3 -3
  15. package/android/src/main/java/com/fireworksdk/bridge/models/FWTextShadowModelDeserializer.kt +30 -0
  16. package/android/src/main/java/com/fireworksdk/bridge/models/FWTrackPurchaseModel.kt +3 -0
  17. package/android/src/main/java/com/fireworksdk/bridge/models/FWTrackPurchaseModelDeserializer.kt +14 -0
  18. package/android/src/main/java/com/fireworksdk/bridge/models/FWTrackPurchaseModelSerializer.kt +7 -1
  19. package/android/src/main/java/com/fireworksdk/bridge/models/FWTrackPurchaseProduct.kt +7 -0
  20. package/android/src/main/java/com/fireworksdk/bridge/models/FWTrackPurchaseProductDeserializer.kt +36 -0
  21. package/android/src/main/java/com/fireworksdk/bridge/models/FWTrackPurchaseProductSerializer.kt +29 -0
  22. package/android/src/main/java/com/fireworksdk/bridge/models/FWVideoPlayerConfigModel.kt +17 -1
  23. package/android/src/main/java/com/fireworksdk/bridge/models/FWVideoPlayerConfigModelDeserializer.kt +16 -1
  24. package/android/src/main/java/com/fireworksdk/bridge/models/FWVideoPlayerConfigModelSerializer.kt +33 -1
  25. package/android/src/main/java/com/fireworksdk/bridge/models/enums/FWEventName.kt +5 -1
  26. package/android/src/main/java/com/fireworksdk/bridge/reactnative/module/FireworkSDKModule.kt +15 -5
  27. package/android/src/main/java/com/fireworksdk/bridge/utils/FWColorUtil.kt +15 -0
  28. package/android/src/main/java/com/fireworksdk/bridge/utils/FWCommonUtil.kt +2 -2
  29. package/android/src/main/java/com/fireworksdk/bridge/utils/FWConfigUtil.kt +59 -1
  30. package/android/src/main/java/com/fireworksdk/bridge/utils/FWGlobalDataUtil.kt +2 -0
  31. package/android/src/main/java/com/fireworksdk/bridge/utils/FWModelUtils.kt +32 -0
  32. package/ios/Components/StoryBlock.swift +27 -0
  33. package/ios/Components/StoryBlockConfiguration.swift +5 -0
  34. package/ios/Components/VideoFeed.swift +16 -0
  35. package/ios/Components/VideoPlayerConfiguration.swift +17 -0
  36. package/ios/Models/Common/ControlsInset.swift +12 -0
  37. package/ios/Models/Common/PipPlacement.swift +20 -0
  38. package/ios/Modules/FWNavigatorModule/FWNavigatorModule.m +1 -0
  39. package/ios/Modules/FWNavigatorModule/FWNavigatorModule.swift +12 -100
  40. package/ios/Modules/FireworkSDKModule/FireworkSDKModule.swift +5 -0
  41. package/ios/Modules/FireworkSDKModule/TrackPurchaseParameters.swift +18 -0
  42. package/lib/commonjs/FWNavigator.js +18 -2
  43. package/lib/commonjs/FWNavigator.js.map +1 -1
  44. package/lib/commonjs/components/StoryBlock.js +10 -0
  45. package/lib/commonjs/components/StoryBlock.js.map +1 -1
  46. package/lib/commonjs/components/VideoFeed.js +8 -0
  47. package/lib/commonjs/components/VideoFeed.js.map +1 -1
  48. package/lib/commonjs/index.js +7 -0
  49. package/lib/commonjs/index.js.map +1 -1
  50. package/lib/commonjs/models/ControlsInset.js +2 -0
  51. package/lib/commonjs/models/ControlsInset.js.map +1 -0
  52. package/lib/commonjs/models/PipPlacement.js +18 -0
  53. package/lib/commonjs/models/PipPlacement.js.map +1 -0
  54. package/lib/commonjs/models/StatusBarStyle.js +2 -0
  55. package/lib/commonjs/models/StatusBarStyle.js.map +1 -0
  56. package/lib/commonjs/modules/FWNavigatorModule.js.map +1 -1
  57. package/lib/module/FWNavigator.js +18 -2
  58. package/lib/module/FWNavigator.js.map +1 -1
  59. package/lib/module/components/StoryBlock.js +10 -0
  60. package/lib/module/components/StoryBlock.js.map +1 -1
  61. package/lib/module/components/VideoFeed.js +8 -0
  62. package/lib/module/components/VideoFeed.js.map +1 -1
  63. package/lib/module/index.js +2 -1
  64. package/lib/module/index.js.map +1 -1
  65. package/lib/module/models/ControlsInset.js +2 -0
  66. package/lib/module/models/ControlsInset.js.map +1 -0
  67. package/lib/module/models/PipPlacement.js +14 -0
  68. package/lib/module/models/PipPlacement.js.map +1 -0
  69. package/lib/module/models/StatusBarStyle.js +2 -0
  70. package/lib/module/models/StatusBarStyle.js.map +1 -0
  71. package/lib/module/modules/FWNavigatorModule.js.map +1 -1
  72. package/lib/typescript/commonjs/src/FWNavigator.d.ts +7 -2
  73. package/lib/typescript/commonjs/src/FWNavigator.d.ts.map +1 -1
  74. package/lib/typescript/commonjs/src/components/StoryBlock.d.ts.map +1 -1
  75. package/lib/typescript/commonjs/src/components/VideoFeed.d.ts.map +1 -1
  76. package/lib/typescript/commonjs/src/index.d.ts +6 -2
  77. package/lib/typescript/commonjs/src/index.d.ts.map +1 -1
  78. package/lib/typescript/commonjs/src/models/ControlsInset.d.ts +4 -0
  79. package/lib/typescript/commonjs/src/models/ControlsInset.d.ts.map +1 -0
  80. package/lib/typescript/commonjs/src/models/PipPlacement.d.ts +11 -0
  81. package/lib/typescript/commonjs/src/models/PipPlacement.d.ts.map +1 -0
  82. package/lib/typescript/commonjs/src/models/StatusBarStyle.d.ts +2 -0
  83. package/lib/typescript/commonjs/src/models/StatusBarStyle.d.ts.map +1 -0
  84. package/lib/typescript/commonjs/src/models/StoryBlockConfiguration.d.ts +29 -1
  85. package/lib/typescript/commonjs/src/models/StoryBlockConfiguration.d.ts.map +1 -1
  86. package/lib/typescript/commonjs/src/models/TrackPurchaseParameters.d.ts +26 -0
  87. package/lib/typescript/commonjs/src/models/TrackPurchaseParameters.d.ts.map +1 -1
  88. package/lib/typescript/commonjs/src/models/VideoPlayerConfiguration.d.ts +20 -0
  89. package/lib/typescript/commonjs/src/models/VideoPlayerConfiguration.d.ts.map +1 -1
  90. package/lib/typescript/commonjs/src/modules/FWNavigatorModule.d.ts +1 -0
  91. package/lib/typescript/commonjs/src/modules/FWNavigatorModule.d.ts.map +1 -1
  92. package/lib/typescript/module/src/FWNavigator.d.ts +7 -2
  93. package/lib/typescript/module/src/FWNavigator.d.ts.map +1 -1
  94. package/lib/typescript/module/src/components/StoryBlock.d.ts.map +1 -1
  95. package/lib/typescript/module/src/components/VideoFeed.d.ts.map +1 -1
  96. package/lib/typescript/module/src/index.d.ts +6 -2
  97. package/lib/typescript/module/src/index.d.ts.map +1 -1
  98. package/lib/typescript/module/src/models/ControlsInset.d.ts +4 -0
  99. package/lib/typescript/module/src/models/ControlsInset.d.ts.map +1 -0
  100. package/lib/typescript/module/src/models/PipPlacement.d.ts +11 -0
  101. package/lib/typescript/module/src/models/PipPlacement.d.ts.map +1 -0
  102. package/lib/typescript/module/src/models/StatusBarStyle.d.ts +2 -0
  103. package/lib/typescript/module/src/models/StatusBarStyle.d.ts.map +1 -0
  104. package/lib/typescript/module/src/models/StoryBlockConfiguration.d.ts +29 -1
  105. package/lib/typescript/module/src/models/StoryBlockConfiguration.d.ts.map +1 -1
  106. package/lib/typescript/module/src/models/TrackPurchaseParameters.d.ts +26 -0
  107. package/lib/typescript/module/src/models/TrackPurchaseParameters.d.ts.map +1 -1
  108. package/lib/typescript/module/src/models/VideoPlayerConfiguration.d.ts +20 -0
  109. package/lib/typescript/module/src/models/VideoPlayerConfiguration.d.ts.map +1 -1
  110. package/lib/typescript/module/src/modules/FWNavigatorModule.d.ts +1 -0
  111. package/lib/typescript/module/src/modules/FWNavigatorModule.d.ts.map +1 -1
  112. package/package.json +1 -1
  113. package/react_native_firework_sdk.podspec +1 -1
  114. package/src/FWNavigator.ts +18 -2
  115. package/src/components/StoryBlock.tsx +13 -0
  116. package/src/components/VideoFeed.tsx +9 -0
  117. package/src/index.tsx +8 -0
  118. package/src/models/ControlsInset.ts +3 -0
  119. package/src/models/PipPlacement.ts +11 -0
  120. package/src/models/StatusBarStyle.ts +1 -0
  121. package/src/models/StoryBlockConfiguration.ts +34 -1
  122. package/src/models/TrackPurchaseParameters.ts +29 -0
  123. package/src/models/VideoPlayerConfiguration.ts +24 -0
  124. package/src/modules/FWNavigatorModule.ts +1 -0
@@ -26,6 +26,7 @@ object FWVideoPlayerConfigModelDeserializer {
26
26
  private const val COUNT_DOWN_TIMER_CONFIGURATION_KEY = "countdownTimerConfiguration"
27
27
  private const val ACTION_BUTTON_STYLE_KEY = "actionButtonStyle"
28
28
  private const val CANCEL_BUTTON_STYLE_KEY = "cancelButtonStyle"
29
+ private const val CHAT_STYLE_KEY = "chatStyle"
29
30
 
30
31
  private const val BACKGROUND_COLOR_KEY = "backgroundColor"
31
32
  private const val FONT_SIZE_KEY = "fontSize"
@@ -35,10 +36,15 @@ object FWVideoPlayerConfigModelDeserializer {
35
36
  private const val TYPE_KEY = "type"
36
37
  private const val VALUE_KEY = "value"
37
38
 
39
+ private const val ANDROID_FONT_INFO_KEY = "androidFontInfo"
40
+ private const val SHADOW_COLOR_KEY = "shadowColor"
41
+
38
42
  private const val SHOW_FULL_SCREEN_ICON = "enableFullScreen"
39
43
  private const val ENABLE_AUTOPLAY = "enableAutoplay"
40
44
  private const val ENABLE_AUTOPAUSE = "enableAutopause"
41
45
  private const val ENABLE_SMALL_SIZE_IN_COMPACT = "enableSmallSizeInCompact"
46
+ private const val SHOULD_EXTEND_MEDIA_OUTSIDE_SAFE_AREA_KEY = "shouldExtendMediaOutsideSafeArea"
47
+ private const val ADDITIONAL_CONTROLS_INSET_KEY = "additionalControlsInset"
42
48
 
43
49
  fun deserialize(responseJson: JSONObject?): FWVideoPlayerConfigModel? {
44
50
  responseJson ?: return null
@@ -61,6 +67,8 @@ object FWVideoPlayerConfigModelDeserializer {
61
67
  val countdownTimerConfigurationJsonObject = responseJson.optJSONObject(COUNT_DOWN_TIMER_CONFIGURATION_KEY)
62
68
  val actionButtonStyleJsonObject = responseJson.optJSONObject(ACTION_BUTTON_STYLE_KEY)
63
69
  val cancelButtonStyleJsonObject = responseJson.optJSONObject(CANCEL_BUTTON_STYLE_KEY)
70
+ val chatStyleJsonObject = responseJson.optJSONObject(CHAT_STYLE_KEY)
71
+
64
72
  val showFullScreenIcon =
65
73
  if (responseJson.has(SHOW_FULL_SCREEN_ICON)) responseJson.optBoolean(SHOW_FULL_SCREEN_ICON) else null
66
74
  val enableAutoPlay =
@@ -69,6 +77,10 @@ object FWVideoPlayerConfigModelDeserializer {
69
77
  if (responseJson.has(ENABLE_AUTOPAUSE)) responseJson.optBoolean(ENABLE_AUTOPAUSE) else null
70
78
  val enableSmallSizeInCompact =
71
79
  if (responseJson.has(ENABLE_SMALL_SIZE_IN_COMPACT)) responseJson.optBoolean(ENABLE_SMALL_SIZE_IN_COMPACT) else null
80
+ val shouldExtendMediaOutsideSafeArea =
81
+ if (responseJson.has(SHOULD_EXTEND_MEDIA_OUTSIDE_SAFE_AREA_KEY)) responseJson.optBoolean(SHOULD_EXTEND_MEDIA_OUTSIDE_SAFE_AREA_KEY) else null
82
+ val additionalControlsInset =
83
+ if (responseJson.has(ADDITIONAL_CONTROLS_INSET_KEY)) FWControlsInsetModelDeserializer.deserialize(responseJson.optJSONObject(ADDITIONAL_CONTROLS_INSET_KEY)) else null
72
84
 
73
85
  return FWVideoPlayerConfigModel(
74
86
  playerStyle = if (!playerStyle.isNullOrBlank()) FWPlayerStyle.deserialize(playerStyle) else null,
@@ -92,7 +104,10 @@ object FWVideoPlayerConfigModelDeserializer {
92
104
  showFullScreenIcon = showFullScreenIcon,
93
105
  enableAutoPlay = enableAutoPlay,
94
106
  enableAutoPause = enableAutoPause,
95
- enableSmallSizeInCompact = enableSmallSizeInCompact
107
+ enableSmallSizeInCompact = enableSmallSizeInCompact,
108
+ chatStyle = FWChatConfigModelDeserializer.deserialize(chatStyleJsonObject),
109
+ shouldExtendMediaOutsideSafeArea = shouldExtendMediaOutsideSafeArea,
110
+ additionalControlsInset = additionalControlsInset,
96
111
  )
97
112
  }
98
113
 
@@ -26,11 +26,19 @@ object FWVideoPlayerConfigModelSerializer {
26
26
  private const val COUNT_DOWN_TIMER_CONFIGURATION_KEY = "countdownTimerConfiguration"
27
27
  private const val ACTION_BUTTON_STYLE_KEY = "actionButtonStyle"
28
28
  private const val CANCEL_BUTTON_STYLE_KEY = "cancelButtonStyle"
29
+ private const val CHAT_STYLE_KEY = "chatStyle"
29
30
 
30
31
  private const val BACKGROUND_COLOR_KEY = "backgroundColor"
31
32
  private const val FONT_SIZE_KEY = "fontSize"
32
33
  private const val TEXT_COLOR_KEY = "textColor"
33
34
  private const val SHAPE_KEY = "shape"
35
+ private const val TEXT_SHADOW_KEY = "textShadow"
36
+
37
+ private const val OPACITY_KEY = "opacity"
38
+ private const val COLOR_KEY = "color"
39
+ private const val OFFSET_X_KEY = "offsetX"
40
+ private const val OFFSET_Y_KEY = "offsetY"
41
+ private const val RADIUS_KEY = "radius"
34
42
 
35
43
  private const val TYPE_KEY = "type"
36
44
  private const val VALUE_KEY = "value"
@@ -39,6 +47,8 @@ object FWVideoPlayerConfigModelSerializer {
39
47
  private const val ENABLE_AUTOPLAY = "enableAutoplay"
40
48
  private const val ENABLE_AUTOPAUSE = "enableAutopause"
41
49
  private const val ENABLE_SMALL_SIZE_IN_COMPACT = "enableSmallSizeInCompact"
50
+ private const val SHOULD_EXTEND_MEDIA_OUTSIDE_SAFE_AREA_KEY = "shouldExtendMediaOutsideSafeArea"
51
+ private const val ADDITIONAL_CONTROLS_INSET_KEY = "additionalControlsInset"
42
52
 
43
53
 
44
54
  fun serialize(model: FWVideoPlayerConfigModel?): JSONObject? {
@@ -48,6 +58,7 @@ object FWVideoPlayerConfigModelSerializer {
48
58
  jsonObject.put(VIDEO_COMPLETE_ACTION_KEY, FWVideoCompleteAction.serialize(model.videoCompleteAction))
49
59
  jsonObject.put(SHOW_SHARE_BUTTON_KEY, model.showShareButton)
50
60
  jsonObject.put(CTA_BUTTON_STYLE_KEY, serializeCtaButtonStyle(model.ctaButtonStyle))
61
+ jsonObject.put(CHAT_STYLE_KEY, serializeChatStyle(model.chatStyle))
51
62
  jsonObject.put(SHOW_MUTE_BUTTON_KEY, model.showMuteButton)
52
63
  jsonObject.put(SHOW_PLAYBACK_BUTTON_KEY, model.showPlaybackButton)
53
64
  jsonObject.put(SHOW_BRANDING_KEY, model.showBranding)
@@ -66,6 +77,8 @@ object FWVideoPlayerConfigModelSerializer {
66
77
  jsonObject.put(ENABLE_AUTOPLAY, model.enableAutoPlay)
67
78
  jsonObject.put(ENABLE_AUTOPAUSE, model.enableAutoPause)
68
79
  jsonObject.put(ENABLE_SMALL_SIZE_IN_COMPACT, model.enableSmallSizeInCompact)
80
+ jsonObject.put(SHOULD_EXTEND_MEDIA_OUTSIDE_SAFE_AREA_KEY, model.shouldExtendMediaOutsideSafeArea)
81
+ jsonObject.put(ADDITIONAL_CONTROLS_INSET_KEY, FWControlsInsetModelSerializer.serialize(model.additionalControlsInset))
69
82
  return jsonObject
70
83
  }
71
84
 
@@ -79,6 +92,25 @@ object FWVideoPlayerConfigModelSerializer {
79
92
  return jsonObject
80
93
  }
81
94
 
95
+ private fun serializeChatStyle(model: FWVideoPlayerConfigModel.FWChatStyleModel?): JSONObject? {
96
+ model ?: return null
97
+ val jsonObject = JSONObject()
98
+ jsonObject.put(TEXT_COLOR_KEY, model.textColor)
99
+ jsonObject.put(TEXT_SHADOW_KEY, serializeTextShadow(model.textShadow))
100
+ return jsonObject
101
+ }
102
+
103
+ private fun serializeTextShadow(model: FWVideoPlayerConfigModel.FWTextShadowModel?): JSONObject? {
104
+ model ?: return null
105
+ val jsonObject = JSONObject()
106
+ jsonObject.put(OPACITY_KEY, model.opacity)
107
+ jsonObject.put(COLOR_KEY, model.color)
108
+ jsonObject.put(OFFSET_X_KEY, model.offsetX)
109
+ jsonObject.put(OFFSET_Y_KEY, model.offsetY)
110
+ jsonObject.put(RADIUS_KEY, model.radius)
111
+ return jsonObject
112
+ }
113
+
82
114
  private fun serializeCtaDelay(model: FWVideoPlayerConfigModel.FWCtaDelayModel?): JSONObject? {
83
115
  model ?: return null
84
116
  val jsonObject = JSONObject()
@@ -86,4 +118,4 @@ object FWVideoPlayerConfigModelSerializer {
86
118
  jsonObject.put(VALUE_KEY, model.value)
87
119
  return jsonObject
88
120
  }
89
- }
121
+ }
@@ -8,8 +8,11 @@ enum class FWEventName(val rawValue: String) {
8
8
  LiveStream("fw:livestream"),
9
9
  LiveStreamChat("fw:livestream-chat"),
10
10
  LiveStreamLinkInteractionClick("fw:livestream:custom-link-interaction-click"),
11
+ LivestreamGiveawayTermsClick("fw:livestream:custom-giveaway-terms-and-conditions-click"),
11
12
  LogMessage("fw:log-message"),
12
- CustomShareURL("fw:custom-share-url")
13
+ CustomShareURL("fw:custom-share-url"),
14
+ InteractableEngagement("fw:interactable-engagement"),
15
+ StoryBlockClickToFullScreen("fw:storyblock:click-to-full-screen"),
13
16
  }
14
17
 
15
18
  enum class FWSDKInitSubEventName(val rawValue: String) {
@@ -39,6 +42,7 @@ enum class FWVideoPlaybackSubEventName(val rawValue: String) {
39
42
 
40
43
  enum class FWVideoShoppingEventName(val rawValue: String) {
41
44
  CtaButtonClick("fw:shopping:cta-button-click"),
45
+ SecondaryCtaButtonClick("fw:shopping:secondary-cta-click"),
42
46
  ClickCartIcon("fw:shopping:click-cart-icon"),
43
47
  UpdateProductDetails("fw:shopping:update-product-details"),
44
48
  WillDisplayProduct("fw:shopping:will-display-product"),
@@ -12,6 +12,7 @@ import com.firework.analyticsevents.cta.CtaButtonClickAnalyticsEvent
12
12
  import com.firework.analyticsevents.player.PlayerLifecycleAnalyticsEvent
13
13
  import com.firework.analyticsevents.share.ShareButtonAnalyticsEvent
14
14
  import com.firework.bus.FwAnalyticCallable
15
+ import com.firework.common.tracking.ProductItem
15
16
  import com.firework.sdk.FireworkSdk
16
17
  import com.firework.sdk.FwLivestreamPlayerVersion
17
18
  import com.firework.sdk.FwTrackingLevel
@@ -302,11 +303,20 @@ class FireworkSDKModule(
302
303
 
303
304
  UiThreadUtil.runOnUiThread {
304
305
  FireworkSdk.shopping.trackPurchase(
305
- trackPurchaseModel.orderId,
306
- trackPurchaseModel.value,
307
- trackPurchaseModel.currencyCode,
308
- trackPurchaseModel.countryCode,
309
- trackPurchaseModel.additionalInfo ?: mutableMapOf()
306
+ orderId = trackPurchaseModel.orderId,
307
+ value = trackPurchaseModel.value,
308
+ currencyCode = trackPurchaseModel.currencyCode,
309
+ countryCode = trackPurchaseModel.countryCode,
310
+ additionalInfo = trackPurchaseModel.additionalInfo ?: mutableMapOf(),
311
+ products = (trackPurchaseModel.products?.map { it ->
312
+ ProductItem(
313
+ productId = it.extProductId ?: "",
314
+ price = it.price ?: 0.0,
315
+ quantity = it.quantity ?: 0
316
+ )
317
+ } ?: mutableListOf<ProductItem>()) as List<ProductItem>?,
318
+ shippingPrice = trackPurchaseModel.shippingPrice,
319
+ subtotal = trackPurchaseModel.subtotal,
310
320
  )
311
321
  promise.resolve(true)
312
322
  }
@@ -26,6 +26,21 @@ object FWColorUtil {
26
26
  }
27
27
  }
28
28
 
29
+ /**
30
+ * Parse a color string with alpha value.
31
+ * @param alpha Float, transparency in range 0-1f
32
+ * @param color String, color string like "#3A86FF"
33
+ * @return Int, color int with alpha channel
34
+ */
35
+ fun parseColorWithAlpha(alpha: Double, color: String): Int {
36
+ // Parse base color
37
+ val baseColor = parseColor(color)
38
+ // Calculate alpha channel (0-255)
39
+ val alphaInt = (alpha * 255).toInt().coerceIn(0, 255)
40
+ // Combine alpha and color int
41
+ return (baseColor and 0x00FFFFFF) or (alphaInt shl 24)
42
+ }
43
+
29
44
  /**
30
45
  * color: #FF3A86FF, #3A86FF
31
46
  */
@@ -13,10 +13,10 @@ object FWCommonUtil {
13
13
  ).toInt()
14
14
  }
15
15
 
16
- fun dpToPx(sp: Float, context: Context): Int {
16
+ fun dpToPx(dp: Float, context: Context): Int {
17
17
  return TypedValue.applyDimension(
18
18
  TypedValue.COMPLEX_UNIT_DIP,
19
- sp,
19
+ dp,
20
20
  context.resources.displayMetrics,
21
21
  ).toInt()
22
22
  }
@@ -9,6 +9,8 @@ import com.firework.common.Theme
9
9
  import com.firework.common.ad.AdBadgeOption
10
10
  import com.firework.common.ad.AdBadgeTextType
11
11
  import com.firework.common.ad.AdOption
12
+ import com.firework.common.chat.ChatStyle
13
+ import com.firework.common.chat.TextShadow
12
14
  import com.firework.common.cta.CtaDelay
13
15
  import com.firework.common.cta.CtaDelayUnit
14
16
  import com.firework.common.cta.CtaStyle
@@ -27,7 +29,9 @@ import com.firework.common.widget.ActionButton
27
29
  import com.firework.common.widget.Shape
28
30
  import com.firework.common.widget.WidgetImage
29
31
  import com.firework.viewoptions.BaseOption
32
+ import com.firework.viewoptions.ChatOption
30
33
  import com.firework.viewoptions.CtaOption
34
+ import com.firework.viewoptions.ImmersiveParam
31
35
  import com.firework.viewoptions.LayoutOption
32
36
  import com.firework.viewoptions.LogoConfig
33
37
  import com.firework.viewoptions.PlayerOption
@@ -71,6 +75,7 @@ object FWConfigUtil {
71
75
  val baseOptionBuilder = getDefaultBaseOptionBuilder()
72
76
  val adBadgeOptionBuilder = getDefaultAdBadgeOptionBuilder()
73
77
  val ctaOptionBuilder = getDefaultCtaOptionBuilder()
78
+ val chatOptionBuilder = getDefaultChatOptionBuilder()
74
79
  val adOptionBuilder = getDefaultAdOptionBuilder()
75
80
  val countDownOptionBuilder = getDefaultPlayerCountdownTimerOptionBuilder()
76
81
  val actionButtonOption = getDefaultActionButtonOptionBuilder()
@@ -458,6 +463,48 @@ object FWConfigUtil {
458
463
  }
459
464
  playerOptionBuilder.actionButtonOption(actionButtonOption.build())
460
465
 
466
+ val chatStyle = videoFeedPropsModel.videoPlayerConfiguration?.chatStyle
467
+ chatStyle?.let { style ->
468
+ var shadowColor: Int? = null
469
+ var shadowOffsetX: Float? = null
470
+ var shadowOffsetY: Float? = null
471
+ var shadowRadius: Float? = null
472
+
473
+
474
+ // Use textColor directly
475
+ val textColor: Int? = if (!style.textColor.isNullOrBlank()) {
476
+ FWColorUtil.parseColor(style.textColor)
477
+ } else {
478
+ null
479
+ }
480
+
481
+ style.textShadow?.let { shadow ->
482
+ shadowColor = if (!shadow.color.isNullOrBlank()) {
483
+ if (shadow.opacity != null) {
484
+ FWColorUtil.parseColorWithAlpha(shadow.opacity, shadow.color)
485
+ } else {
486
+ FWColorUtil.parseColor(shadow.color)
487
+ }
488
+ } else {
489
+ null
490
+ }
491
+
492
+ shadowOffsetX = shadow.offsetX?.toFloat()
493
+ shadowOffsetY = shadow.offsetY?.toFloat()
494
+ shadowRadius = shadow.radius?.toFloat()
495
+ }
496
+
497
+ chatOptionBuilder.chatStyle(ChatStyle(
498
+ textColor = textColor,
499
+ textShadow = TextShadow(
500
+ color = shadowColor,
501
+ offsetX = shadowOffsetX,
502
+ offsetY = shadowOffsetY,
503
+ radius = shadowRadius,
504
+ )
505
+ ))
506
+ }
507
+
461
508
  val ctaDelay = videoFeedPropsModel.videoPlayerConfiguration?.ctaDelay
462
509
  ctaDelay?.let { delay ->
463
510
  delay.value ?: return@let
@@ -570,6 +617,12 @@ object FWConfigUtil {
570
617
  storyblockOptionBuilder.enableAutoPause(enableAutoPause)}
571
618
  videoFeedPropsModel.videoPlayerConfiguration?.enableSmallSizeInCompact?.let { enableSmallSizeInCompact ->
572
619
  storyblockOptionBuilder.enableSmallSizeInCompact(enableSmallSizeInCompact)}
620
+ videoFeedPropsModel.videoPlayerConfiguration?.additionalControlsInset?.let { additionalControlsInset ->
621
+ storyblockOptionBuilder.setImmersiveParam(ImmersiveParam(FWCommonUtil.dpToPx((additionalControlsInset.top ?: 0).toFloat(), context)))
622
+ }
623
+ videoFeedPropsModel.videoPlayerConfiguration?.shouldExtendMediaOutsideSafeArea?.let { shouldExtendMediaOutsideSafeArea ->
624
+ playerOptionBuilder.enableImmersiveMode(shouldExtendMediaOutsideSafeArea)
625
+ }
573
626
 
574
627
  playerOptionBuilder.shareUrlCustomCallBack(FWGlobalDataUtil.customShareUrlCallback)
575
628
 
@@ -581,6 +634,7 @@ object FWConfigUtil {
581
634
  .adBadgeOption(adBadgeOptionBuilder.build())
582
635
  .ctaOption(ctaOptionBuilder.build())
583
636
  .adOption(adOptionBuilder.build())
637
+ .chatOption(chatOptionBuilder.build())
584
638
  .storyBlockOption(storyblockOptionBuilder.build())
585
639
  }
586
640
 
@@ -648,11 +702,15 @@ object FWConfigUtil {
648
702
  return CtaOption.Builder()
649
703
  }
650
704
 
705
+ private fun getDefaultChatOptionBuilder(): ChatOption.Builder {
706
+ return ChatOption.Builder()
707
+ }
708
+
651
709
  private fun getDefaultAdOptionBuilder(): AdOption.Builder {
652
710
  return AdOption.Builder()
653
711
  }
654
712
 
655
- private fun getTypeface(context: Context, font: FWFontInfoModel?): Typeface? {
713
+ fun getTypeface(context: Context, font: FWFontInfoModel?): Typeface? {
656
714
  val typefaceName = font?.typefaceName
657
715
  typefaceName ?: return null
658
716
 
@@ -19,6 +19,8 @@ object FWGlobalDataUtil {
19
19
 
20
20
  var shareBaseUrl: String? = null
21
21
 
22
+ var customShareUrl: String? = null
23
+
22
24
  var pauseWhenNotVisible: Boolean = false
23
25
 
24
26
  var switchLanguageBehavior = FWSwitchLanguageBehavior.RestartingActivity
@@ -4,6 +4,7 @@ import com.firework.analyticsevents.VideoInfo
4
4
  import com.firework.analyticsevents.VideoType
5
5
  import com.firework.analyticsevents.cta.CtaButtonClickAnalyticsEvent
6
6
  import com.firework.analyticsevents.player.PlayerLifecycleAnalyticsEvent
7
+ import com.firework.analyticsevents.player.VideoEngagedEvent
7
8
  import com.firework.analyticsevents.share.ShareButtonAnalyticsEvent
8
9
  import com.firework.common.product.Product
9
10
  import com.fireworksdk.bridge.models.FWLiveStreamEventDetailsModel
@@ -62,12 +63,28 @@ object FWModelUtils {
62
63
  }
63
64
  }
64
65
 
66
+ fun convertVideoInfo2CustomSecondaryCta(product: Product?): FWShoppingCustomCta? {
67
+ val url = product?.customCTAUrl
68
+ val title = product?.customCTATitleTranslation
69
+ val titleKey = product?.customCTATitle
70
+ return if (!url.isNullOrBlank() && !titleKey.isNullOrBlank() && !title.isNullOrBlank() && !product.isCustomCtaPrimary) {
71
+ FWShoppingCustomCta(
72
+ url = url,
73
+ titleKey = titleKey,
74
+ title = title,
75
+ )
76
+ } else {
77
+ null
78
+ }
79
+ }
80
+
65
81
  fun convertVideoInfo2LivestreamDetails(videoInfo: VideoInfo): FWLiveStreamEventDetailsModel {
66
82
  return FWLiveStreamEventDetailsModel(
67
83
  id = videoInfo.id,
68
84
  feedId = videoInfo.feedId,
69
85
  videoType = videoInfo.internalVideoType,
70
86
  liveStreamStatus = videoInfo.internalLiveStreamStatus,
87
+ playbackDetails = convertVideoInfo2PlaybackDetails(videoInfo)
71
88
  )
72
89
  }
73
90
 
@@ -103,6 +120,21 @@ object FWModelUtils {
103
120
  )
104
121
  }
105
122
 
123
+ fun convertVideoEngageEvent2PlaybackDetails(event: VideoEngagedEvent) : FWVideoPlaybackDetails {
124
+ return FWVideoPlaybackDetails(
125
+ badge = event.videoInfo?.badge,
126
+ caption = event.videoInfo?.caption,
127
+ duration = event.videoInfo?.duration,
128
+ hasCta = event.videoInfo?.hasCta,
129
+ playerHeight = event.videoInfo?.playerHeight,
130
+ playerWidth = event.videoInfo?.playerWidth,
131
+ id = event.videoInfo?.id,
132
+ feedId = event.videoInfo?.feedId,
133
+ videoType = event.videoInfo?.internalVideoType,
134
+ liveStreamStatus = event.videoInfo?.internalLiveStreamStatus,
135
+ )
136
+ }
137
+
106
138
  fun convertShareButtonEvent2PlaybackDetails(event: ShareButtonAnalyticsEvent): FWVideoPlaybackDetails {
107
139
  return FWVideoPlaybackDetails(
108
140
  badge = event.videoInfo.badge,
@@ -234,13 +234,16 @@ public class StoryBlock: UIView, StoryBlockViewControllerDelegate, PictureInPict
234
234
 
235
235
  if let ctaButtonStyle = config.ctaButtonStyle {
236
236
  if let backgroundColor = ctaButtonStyle.backgroundColor, let color = backgroundColor.uicolor() {
237
+ resultConfig.ctaButton.contentConfiguration.backgroundColor = color
237
238
  resultConfig.fullScreenPlayerView.ctaButton.contentConfiguration.backgroundColor = color
238
239
  }
239
240
  if let textcolor = ctaButtonStyle.textColor, let color = textcolor.uicolor() {
241
+ resultConfig.ctaButton.contentConfiguration.textColor = color
240
242
  resultConfig.fullScreenPlayerView.ctaButton.contentConfiguration.textColor = color
241
243
  }
242
244
  if let fontSize = ctaButtonStyle.fontSize {
243
245
  let iOSFontInfo = ctaButtonStyle.iOSFontInfo ?? FontInfo()
246
+ resultConfig.ctaButton.contentConfiguration.font = iOSFontInfo.getFont(fontSize)
244
247
  resultConfig.fullScreenPlayerView.ctaButton.contentConfiguration.font = iOSFontInfo.getFont(fontSize)
245
248
  }
246
249
  }
@@ -376,6 +379,30 @@ public class StoryBlock: UIView, StoryBlockViewControllerDelegate, PictureInPict
376
379
  resultConfig.fullScreenPlayerView.countdownTimerConfiguration = countdownTimerConfiguration.fwCountdownTimerConfiguration()
377
380
  }
378
381
 
382
+ if let additionalControlsInset = config.additionalControlsInset {
383
+ resultConfig.additionalControlsInset = .init(
384
+ top: additionalControlsInset.top ?? 0,
385
+ left: 0,
386
+ bottom: 0,
387
+ right: 0)
388
+ }
389
+
390
+ if let shouldExtendMediaOutsideSafeArea = config.shouldExtendMediaOutsideSafeArea {
391
+ resultConfig.fullScreenPlayerView.shouldExtendMediaOutsideSafeArea = shouldExtendMediaOutsideSafeArea
392
+ }
393
+
394
+ if let statusBarHidden = config.statusBarHidden {
395
+ resultConfig.fullScreenPlayerView.statusBarHidden = statusBarHidden
396
+ }
397
+
398
+ if let statusBarStyle = config.statusBarStyle {
399
+ resultConfig.fullScreenPlayerView.statusBarStyle = statusBarStyle.toUIStatusBarStyle()
400
+ }
401
+
402
+ if let pipPlacement = config.pipPlacement {
403
+ resultConfig.fullScreenPlayerView.pipPlacement = pipPlacement.convertToFWPipPlacement()
404
+ }
405
+
379
406
  if let storyBlockBehavior = gVideoLaunchBehavior?.storyBlockBehavior() {
380
407
  resultConfig.onFirstDisplay = storyBlockBehavior
381
408
  } else {
@@ -26,4 +26,9 @@ public class StoryBlockConfiguration: NSObject, Codable {
26
26
  var videoPlayerLogoConfiguration: VideoPlayerLogoConfiguration?
27
27
  var replayBadgeConfiguration: ReplayBadgeConfiguration?
28
28
  var countdownTimerConfiguration: CountdownTimerConfiguration?
29
+ var additionalControlsInset: ControlsInset?
30
+ var shouldExtendMediaOutsideSafeArea: Bool?
31
+ var statusBarHidden: Bool?
32
+ var statusBarStyle: StatusBarStyle?
33
+ var pipPlacement: PipPlacement?
29
34
  }
@@ -530,6 +530,22 @@ extension VideoFeed {
530
530
  vpcConfig.countdownTimerConfiguration = countdownTimerConfiguration.fwCountdownTimerConfiguration()
531
531
  }
532
532
 
533
+ if let shouldExtendMediaOutsideSafeArea = config.shouldExtendMediaOutsideSafeArea {
534
+ vpcConfig.shouldExtendMediaOutsideSafeArea = shouldExtendMediaOutsideSafeArea
535
+ }
536
+
537
+ if let statusBarHidden = config.statusBarHidden {
538
+ vpcConfig.statusBarHidden = statusBarHidden
539
+ }
540
+
541
+ if let statusBarStyle = config.statusBarStyle {
542
+ vpcConfig.statusBarStyle = statusBarStyle.toUIStatusBarStyle()
543
+ }
544
+
545
+ if let pipPlacement = config.pipPlacement {
546
+ vpcConfig.pipPlacement = pipPlacement.convertToFWPipPlacement()
547
+ }
548
+
533
549
  return vpcConfig
534
550
  }
535
551
 
@@ -23,6 +23,19 @@ public enum VideoPlayerCompleteAction: String, Codable {
23
23
  case loop, advanceToNext
24
24
  }
25
25
 
26
+ public enum StatusBarStyle: String, Codable {
27
+ case light, dark
28
+
29
+ func toUIStatusBarStyle() -> UIStatusBarStyle {
30
+ switch self {
31
+ case .light:
32
+ return .lightContent
33
+ case .dark:
34
+ return .darkContent
35
+ }
36
+ }
37
+ }
38
+
26
39
  public enum VideoPlayerCTADelayType: String, Codable {
27
40
  case constant, percentage
28
41
  }
@@ -75,4 +88,8 @@ public class VideoPlayerConfiguration: NSObject, Codable {
75
88
  var videoPlayerLogoConfiguration: VideoPlayerLogoConfiguration?
76
89
  var replayBadgeConfiguration: ReplayBadgeConfiguration?
77
90
  var countdownTimerConfiguration: CountdownTimerConfiguration?
91
+ var shouldExtendMediaOutsideSafeArea: Bool?
92
+ var statusBarHidden: Bool?
93
+ var statusBarStyle: StatusBarStyle?
94
+ var pipPlacement: PipPlacement?
78
95
  }
@@ -0,0 +1,12 @@
1
+ //
2
+ // ControlsInset.swift
3
+ //
4
+ // Created by linjie jiang on 2025/9/15.
5
+ //
6
+
7
+ import Foundation
8
+
9
+ @objc
10
+ public class ControlsInset: NSObject, Codable {
11
+ var top: Double?
12
+ }
@@ -0,0 +1,20 @@
1
+ import Foundation
2
+ import FireworkVideo
3
+
4
+ public enum PipPlacement: String, Codable, CaseIterable {
5
+ case topLeft, topRight, bottomLeft, bottomRight
6
+
7
+ func convertToFWPipPlacement() -> FireworkVideo.VideoPlayerContentConfiguration.PipPlacement {
8
+ // Convert PipPlacement enum to FireworkVideo PipPlacement
9
+ switch self {
10
+ case .topLeft:
11
+ return .topLeft
12
+ case .topRight:
13
+ return .topRight
14
+ case .bottomLeft:
15
+ return .bottomLeft
16
+ case .bottomRight:
17
+ return .bottomRight
18
+ }
19
+ }
20
+ }
@@ -18,5 +18,6 @@ RCT_EXTERN_METHOD(startFloatingPlayer:(RCTPromiseResolveBlock)resolver rejecter:
18
18
  RCT_EXTERN_METHOD(stopFloatingPlayer:(RCTPromiseResolveBlock)resolver rejecter:(RCTPromiseRejectBlock)rejecter)
19
19
  RCT_EXTERN_METHOD(bringRNContainerToTop:(RCTPromiseResolveBlock)resolver rejecter:(RCTPromiseRejectBlock)rejecter)
20
20
  RCT_EXTERN_METHOD(bringRNContainerToBottom:(RCTPromiseResolveBlock)resolver rejecter:(RCTPromiseRejectBlock)rejecter)
21
+ RCT_EXTERN_METHOD(tryStartFloatingOrCloseFullScreen:(RCTPromiseResolveBlock)resolver rejecter:(RCTPromiseRejectBlock)rejecter)
21
22
 
22
23
  @end