react-native-firework-sdk 2.8.6 → 2.9.0

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 (88) hide show
  1. package/FireworkVideoUI.xcframework/Info.plist +5 -5
  2. package/FireworkVideoUI.xcframework/ios-arm64/FireworkVideoUI.framework/FireworkVideoUI +0 -0
  3. package/FireworkVideoUI.xcframework/ios-arm64/FireworkVideoUI.framework/Info.plist +0 -0
  4. package/FireworkVideoUI.xcframework/ios-arm64_x86_64-simulator/FireworkVideoUI.framework/FireworkVideoUI +0 -0
  5. package/FireworkVideoUI.xcframework/ios-arm64_x86_64-simulator/FireworkVideoUI.framework/Info.plist +0 -0
  6. package/FireworkVideoUI.xcframework/ios-arm64_x86_64-simulator/FireworkVideoUI.framework/_CodeSignature/CodeResources +1 -1
  7. package/android/build.gradle +2 -1
  8. package/android/gradle.properties +1 -1
  9. package/android/src/main/java/com/fireworksdk/bridge/components/base/FWLoading.kt +22 -0
  10. package/android/src/main/java/com/fireworksdk/bridge/components/storyblock/StoryBlockFragment.kt +240 -18
  11. package/android/src/main/java/com/fireworksdk/bridge/components/videofeed/FWVideoFeed.kt +19 -9
  12. package/android/src/main/java/com/fireworksdk/bridge/models/FWAdConfigurationDeserializer.kt +49 -0
  13. package/android/src/main/java/com/fireworksdk/bridge/models/FWAdConfigurationModel.kt +13 -0
  14. package/android/src/main/java/com/fireworksdk/bridge/models/FWAdConfigurationSerializer.kt +42 -0
  15. package/android/src/main/java/com/fireworksdk/bridge/models/FWButtonInfoDeserializer.kt +21 -0
  16. package/android/src/main/java/com/fireworksdk/bridge/models/FWButtonInfoModel.kt +6 -0
  17. package/android/src/main/java/com/fireworksdk/bridge/models/FWButtonInfoSerializer.kt +17 -0
  18. package/android/src/main/java/com/fireworksdk/bridge/models/FWPlayerButtonConfigurationDeserializer.kt +33 -0
  19. package/android/src/main/java/com/fireworksdk/bridge/models/FWPlayerButtonConfigurationModel.kt +10 -0
  20. package/android/src/main/java/com/fireworksdk/bridge/models/FWPlayerButtonConfigurationSerializer.kt +25 -0
  21. package/android/src/main/java/com/fireworksdk/bridge/models/FWProductInfoViewConfiguration.kt +7 -0
  22. package/android/src/main/java/com/fireworksdk/bridge/models/FWProductInfoViewConfigurationDeserializer.kt +17 -0
  23. package/android/src/main/java/com/fireworksdk/bridge/models/FWProductInfoViewConfigurationSerializer.kt +13 -0
  24. package/android/src/main/java/com/fireworksdk/bridge/models/FWVideoFeedPropsModel.kt +1 -0
  25. package/android/src/main/java/com/fireworksdk/bridge/models/FWVideoFeedPropsModelDeserializer.kt +3 -0
  26. package/android/src/main/java/com/fireworksdk/bridge/models/FWVideoFeedPropsModelSerializer.kt +2 -0
  27. package/android/src/main/java/com/fireworksdk/bridge/models/FWVideoPlayerConfigModel.kt +3 -1
  28. package/android/src/main/java/com/fireworksdk/bridge/models/FWVideoPlayerConfigModelDeserializer.kt +7 -1
  29. package/android/src/main/java/com/fireworksdk/bridge/models/FWVideoPlayerConfigModelSerializer.kt +4 -0
  30. package/android/src/main/java/com/fireworksdk/bridge/models/enums/FWErrorAction.kt +18 -0
  31. package/android/src/main/java/com/fireworksdk/bridge/models/enums/FWEventName.kt +3 -0
  32. package/android/src/main/java/com/fireworksdk/bridge/reactnative/manager/FWStoryBlockManager.kt +50 -26
  33. package/android/src/main/java/com/fireworksdk/bridge/reactnative/manager/FWVideoFeedManager.kt +47 -8
  34. package/android/src/main/java/com/fireworksdk/bridge/reactnative/models/FWVideoShoppingInterface.kt +1 -0
  35. package/android/src/main/java/com/fireworksdk/bridge/reactnative/module/FWNavigatorModule.kt +0 -10
  36. package/android/src/main/java/com/fireworksdk/bridge/reactnative/module/FWVideoShoppingModule.kt +42 -0
  37. package/android/src/main/java/com/fireworksdk/bridge/reactnative/module/FireworkSDKModule.kt +5 -3
  38. package/android/src/main/java/com/fireworksdk/bridge/reactnative/utils/FWEventUtils.kt +24 -6
  39. package/android/src/main/java/com/fireworksdk/bridge/utils/FWConfigUtil.kt +95 -0
  40. package/android/src/main/res/layout/fw_bridge_story_block.xml +6 -0
  41. package/android/src/main/res/layout/fw_loading.xml +14 -0
  42. package/ios/Components/VideoFeed.swift +1 -1
  43. package/ios/FireworkVideoUI/Podfile.lock +1 -1
  44. package/ios/Modules/FWNavigatorModule/RNSScreenStackView+Window.h +20 -0
  45. package/ios/Modules/FWNavigatorModule/RNSScreenStackView+Window.m +84 -0
  46. package/lib/commonjs/VideoShopping.js +1 -4
  47. package/lib/commonjs/VideoShopping.js.map +1 -1
  48. package/lib/commonjs/components/StoryBlock.js +32 -42
  49. package/lib/commonjs/components/StoryBlock.js.map +1 -1
  50. package/lib/commonjs/components/VideoFeed.js +29 -11
  51. package/lib/commonjs/components/VideoFeed.js.map +1 -1
  52. package/lib/commonjs/index.js +8 -0
  53. package/lib/commonjs/index.js.map +1 -1
  54. package/lib/commonjs/utils/VideoFeedUtil.js +73 -0
  55. package/lib/commonjs/utils/VideoFeedUtil.js.map +1 -0
  56. package/lib/module/VideoShopping.js +1 -5
  57. package/lib/module/VideoShopping.js.map +1 -1
  58. package/lib/module/components/StoryBlock.js +32 -40
  59. package/lib/module/components/StoryBlock.js.map +1 -1
  60. package/lib/module/components/VideoFeed.js +28 -11
  61. package/lib/module/components/VideoFeed.js.map +1 -1
  62. package/lib/module/index.js +2 -1
  63. package/lib/module/index.js.map +1 -1
  64. package/lib/module/utils/VideoFeedUtil.js +65 -0
  65. package/lib/module/utils/VideoFeedUtil.js.map +1 -0
  66. package/lib/typescript/VideoShopping.d.ts +0 -1
  67. package/lib/typescript/components/StoryBlock.d.ts +15 -4
  68. package/lib/typescript/components/VideoFeed.d.ts +12 -1
  69. package/lib/typescript/index.d.ts +2 -1
  70. package/lib/typescript/models/ButtonInfo.d.ts +0 -1
  71. package/lib/typescript/models/ProductInfoViewConfiguration.d.ts +3 -3
  72. package/lib/typescript/models/StoryBlockConfiguration.d.ts +0 -2
  73. package/lib/typescript/models/VideoPlayerButtonConfiguration.d.ts +0 -6
  74. package/lib/typescript/models/VideoPlayerConfiguration.d.ts +0 -2
  75. package/lib/typescript/utils/VideoFeedUtil.d.ts +10 -0
  76. package/package.json +1 -1
  77. package/src/VideoShopping.ts +1 -4
  78. package/src/components/StoryBlock.tsx +40 -44
  79. package/src/components/VideoFeed.tsx +32 -11
  80. package/src/index.ts +2 -0
  81. package/src/models/ButtonInfo.ts +0 -1
  82. package/src/models/ProductInfoViewConfiguration.ts +3 -3
  83. package/src/models/StoryBlockConfiguration.ts +0 -2
  84. package/src/models/VideoPlayerButtonConfiguration.ts +0 -6
  85. package/src/models/VideoPlayerConfiguration.ts +0 -2
  86. package/src/utils/VideoFeedUtil.ts +74 -0
  87. package/android/src/main/java/com/fireworksdk/bridge/utils/FWStatusBarUtil.kt +0 -28
  88. package/android/src/main/java/com/fireworksdk/bridge/utils/FWStoryBlockUtil.kt +0 -30
@@ -0,0 +1,33 @@
1
+ package com.fireworksdk.bridge.models
2
+
3
+ import org.json.JSONObject
4
+
5
+ object FWPlayerButtonConfigurationDeserializer {
6
+
7
+ private const val VIDEO_DETAIL_BUTTON_KEY = "videoDetailButton"
8
+ private const val CLOSE_BUTTON_KEY = "closeButton"
9
+ private const val MUTE_BUTTON_KEY = "muteButton"
10
+ private const val UNMUTE_BUTTON_KEY = "unmuteButton"
11
+ private const val PLAY_BUTTON_KEY = "playButton"
12
+ private const val PAUSE_BUTTON_KEY = "pauseButton"
13
+
14
+ fun deserialize(responseJson: JSONObject?): FWPlayerButtonConfigurationModel? {
15
+ responseJson ?: return null
16
+
17
+ val videoDetailButtonJsonObject = responseJson.optJSONObject(VIDEO_DETAIL_BUTTON_KEY)
18
+ val closeButtonJsonObject = responseJson.optJSONObject(CLOSE_BUTTON_KEY)
19
+ val muteButtonJsonObject = responseJson.optJSONObject(MUTE_BUTTON_KEY)
20
+ val unmuteButtonJsonObject = responseJson.optJSONObject(UNMUTE_BUTTON_KEY)
21
+ val playButtonJsonObject = responseJson.optJSONObject(PLAY_BUTTON_KEY)
22
+ val pauseButtonJsonObject = responseJson.optJSONObject(PAUSE_BUTTON_KEY)
23
+
24
+ return FWPlayerButtonConfigurationModel(
25
+ videoDetailButton = FWButtonInfoDeserializer.deserialize(videoDetailButtonJsonObject),
26
+ closeButton = FWButtonInfoDeserializer.deserialize(closeButtonJsonObject),
27
+ muteButton = FWButtonInfoDeserializer.deserialize(muteButtonJsonObject),
28
+ unmuteButton = FWButtonInfoDeserializer.deserialize(unmuteButtonJsonObject),
29
+ playButton = FWButtonInfoDeserializer.deserialize(playButtonJsonObject),
30
+ pauseButton = FWButtonInfoDeserializer.deserialize(pauseButtonJsonObject),
31
+ )
32
+ }
33
+ }
@@ -0,0 +1,10 @@
1
+ package com.fireworksdk.bridge.models
2
+
3
+ data class FWPlayerButtonConfigurationModel(
4
+ val videoDetailButton: FWButtonInfoModel? = null,
5
+ val closeButton: FWButtonInfoModel? = null,
6
+ val muteButton: FWButtonInfoModel? = null,
7
+ val unmuteButton: FWButtonInfoModel? = null,
8
+ val playButton: FWButtonInfoModel? = null,
9
+ val pauseButton: FWButtonInfoModel? = null,
10
+ )
@@ -0,0 +1,25 @@
1
+ package com.fireworksdk.bridge.models
2
+
3
+ import org.json.JSONObject
4
+
5
+ object FWPlayerButtonConfigurationSerializer {
6
+
7
+ private const val VIDEO_DETAIL_BUTTON_KEY = "videoDetailButton"
8
+ private const val CLOSE_BUTTON_KEY = "closeButton"
9
+ private const val MUTE_BUTTON_KEY = "muteButton"
10
+ private const val UNMUTE_BUTTON_KEY = "unmuteButton"
11
+ private const val PLAY_BUTTON_KEY = "playButton"
12
+ private const val PAUSE_BUTTON_KEY = "pauseButton"
13
+
14
+ fun serialize(model: FWPlayerButtonConfigurationModel?): JSONObject? {
15
+ model ?: return null
16
+ val jsonObject = JSONObject()
17
+ jsonObject.put(VIDEO_DETAIL_BUTTON_KEY, FWButtonInfoSerializer.serialize(model.videoDetailButton))
18
+ jsonObject.put(CLOSE_BUTTON_KEY, FWButtonInfoSerializer.serialize(model.closeButton))
19
+ jsonObject.put(MUTE_BUTTON_KEY, FWButtonInfoSerializer.serialize(model.muteButton))
20
+ jsonObject.put(UNMUTE_BUTTON_KEY, FWButtonInfoSerializer.serialize(model.unmuteButton))
21
+ jsonObject.put(PLAY_BUTTON_KEY, FWButtonInfoSerializer.serialize(model.playButton))
22
+ jsonObject.put(PAUSE_BUTTON_KEY, FWButtonInfoSerializer.serialize(model.pauseButton))
23
+ return jsonObject
24
+ }
25
+ }
@@ -24,5 +24,12 @@ data class FWProductInfoViewConfiguration(
24
24
  data class ProductCardConfiguration(
25
25
  val ctaButtonText: FWProductCardCtaButtonTextValue? = null,
26
26
  val theme: FWProductCardTheme? = null,
27
+ val cornerRadius: Int? = null,
28
+ val priceConfiguration: ProductCardPriceConfiguration? = null,
29
+ val isCtaButtonHidden: Boolean? = null,
30
+ )
31
+
32
+ data class ProductCardPriceConfiguration(
33
+ val isHidden: Boolean? = null,
27
34
  )
28
35
  }
@@ -20,6 +20,9 @@ object FWProductInfoViewConfigurationDeserializer {
20
20
 
21
21
  private const val CTA_BUTTON_TEXT_KEY = "ctaButtonText"
22
22
  private const val THEME_KEY = "theme"
23
+ private const val CORNER_RADIUS_KEY = "cornerRadius"
24
+ private const val PRICE_CONFIGURATION_KEY = "priceConfiguration"
25
+ private const val IS_CTA_BUTTON_HIDDEN_KEY = "isCtaButtonHidden"
23
26
 
24
27
  fun deserialize(responseJson: JSONObject?): FWProductInfoViewConfiguration? {
25
28
  responseJson ?: return null
@@ -66,11 +69,25 @@ object FWProductInfoViewConfigurationDeserializer {
66
69
 
67
70
  val ctaButtonTextString = if (productCardConfigJson.has(CTA_BUTTON_TEXT_KEY)) productCardConfigJson.optString(CTA_BUTTON_TEXT_KEY) else null
68
71
  val themeString = if (productCardConfigJson.has(THEME_KEY)) productCardConfigJson.optString(THEME_KEY) else null
72
+ val cornerRadius = if (productCardConfigJson.has(CORNER_RADIUS_KEY)) productCardConfigJson.optInt(CORNER_RADIUS_KEY) else null
73
+ val priceConfiguration = deserializeProductCardPriceConfiguration(productCardConfigJson.optJSONObject(PRICE_CONFIGURATION_KEY))
74
+ val isCtaButtonHidden = if (productCardConfigJson.has(IS_CTA_BUTTON_HIDDEN_KEY)) productCardConfigJson.optBoolean(IS_CTA_BUTTON_HIDDEN_KEY) else null
69
75
 
70
76
  return FWProductInfoViewConfiguration.ProductCardConfiguration(
71
77
  ctaButtonText = FWProductCardCtaButtonTextValue.deserialize(ctaButtonTextString),
72
78
  theme = FWProductCardTheme.deserialize(themeString),
79
+ cornerRadius = cornerRadius,
80
+ priceConfiguration = priceConfiguration,
81
+ isCtaButtonHidden = isCtaButtonHidden,
73
82
  )
74
83
  }
75
84
 
85
+ private fun deserializeProductCardPriceConfiguration(productCardPriceConfigurationJson: JSONObject?): FWProductInfoViewConfiguration.ProductCardPriceConfiguration {
86
+ productCardPriceConfigurationJson ?: return FWProductInfoViewConfiguration.ProductCardPriceConfiguration()
87
+ val isHidden = if (productCardPriceConfigurationJson.has(IS_HIDDEN_KEY)) productCardPriceConfigurationJson.optBoolean(IS_HIDDEN_KEY) else null
88
+
89
+ return FWProductInfoViewConfiguration.ProductCardPriceConfiguration(
90
+ isHidden = isHidden,
91
+ )
92
+ }
76
93
  }
@@ -18,6 +18,9 @@ object FWProductInfoViewConfigurationSerializer {
18
18
 
19
19
  private const val CTA_BUTTON_TEXT_KEY = "ctaButtonText"
20
20
  private const val THEME_KEY = "theme"
21
+ private const val CORNER_RADIUS_KEY = "cornerRadius"
22
+ private const val PRICE_CONFIGURATION_KEY = "priceConfiguration"
23
+ private const val IS_CTA_BUTTON_HIDDEN_KEY = "isCtaButtonHidden"
21
24
 
22
25
  fun serialize(model: FWProductInfoViewConfiguration?): JSONObject? {
23
26
  model ?: return null
@@ -50,6 +53,16 @@ object FWProductInfoViewConfigurationSerializer {
50
53
  val jsonObject = JSONObject()
51
54
  jsonObject.put(CTA_BUTTON_TEXT_KEY, model.ctaButtonText)
52
55
  jsonObject.put(THEME_KEY, model.theme)
56
+ jsonObject.put(CORNER_RADIUS_KEY, model.cornerRadius)
57
+ jsonObject.put(PRICE_CONFIGURATION_KEY, serializeProductCardPriceConfiguration(model.priceConfiguration))
58
+ jsonObject.put(IS_CTA_BUTTON_HIDDEN_KEY, model.isCtaButtonHidden)
59
+ return jsonObject
60
+ }
61
+
62
+ private fun serializeProductCardPriceConfiguration(model: FWProductInfoViewConfiguration.ProductCardPriceConfiguration?): JSONObject? {
63
+ model ?: return null
64
+ val jsonObject = JSONObject()
65
+ jsonObject.put(IS_HIDDEN_KEY, model.isHidden)
53
66
  return jsonObject
54
67
  }
55
68
  }
@@ -18,4 +18,5 @@ data class FWVideoFeedPropsModel(
18
18
  val dynamicContentParameters: Map<String, List<String>>? = null,
19
19
  val marginRight: Double? = null,
20
20
  val cornerRadius: Int? = null,
21
+ val adConfiguration: FWAdConfigurationModel? = null,
21
22
  )
@@ -17,6 +17,7 @@ object FWVideoFeedPropsModelDeserializer {
17
17
  private const val MODE_KEY = "mode"
18
18
  private const val MARGIN_RIGHT_KEY = "marginRight"
19
19
  private const val CORNER_RADIUS_KEY = "cornerRadius"
20
+ private const val AD_CONFIGURATION_KEY = "adConfiguration"
20
21
 
21
22
  private const val VIDEO_FEED_CONFIGURATION_KEY = "videoFeedConfiguration"
22
23
  private const val VIDEO_PLAYER_CONFIGURATION_KEY = "videoPlayerConfiguration"
@@ -81,6 +82,7 @@ object FWVideoFeedPropsModelDeserializer {
81
82
 
82
83
  val marginRight = if (responseJson.has(MARGIN_RIGHT_KEY)) responseJson.optDouble(MARGIN_RIGHT_KEY) else null
83
84
  val cornerRadius = if (!responseJson.isNull(CORNER_RADIUS_KEY)) responseJson.optInt(CORNER_RADIUS_KEY) else null
85
+ val adConfiguration = FWAdConfigurationDeserializer.deserialize(responseJson.optJSONObject(AD_CONFIGURATION_KEY))
84
86
 
85
87
  return FWVideoFeedPropsModel(
86
88
  source = if (!source.isNullOrBlank()) FWVideoFeedSource.deserialize(source) else null,
@@ -97,6 +99,7 @@ object FWVideoFeedPropsModelDeserializer {
97
99
  dynamicContentParameters = dynamicContentParameters,
98
100
  marginRight = marginRight,
99
101
  cornerRadius = cornerRadius,
102
+ adConfiguration = adConfiguration,
100
103
  )
101
104
  }
102
105
  }
@@ -18,6 +18,7 @@ object FWVideoFeedPropsModelSerializer {
18
18
  private const val MODE_KEY = "mode"
19
19
  private const val MARGIN_RIGHT_KEY = "marginRight"
20
20
  private const val CORNER_RADIUS_KEY = "cornerRadius"
21
+ private const val AD_CONFIGURATION_KEY = "adConfiguration"
21
22
 
22
23
  private const val VIDEO_FEED_CONFIGURATION_KEY = "videoFeedConfiguration"
23
24
  private const val VIDEO_PLAYER_CONFIGURATION_KEY = "videoPlayerConfiguration"
@@ -64,6 +65,7 @@ object FWVideoFeedPropsModelSerializer {
64
65
 
65
66
  jsonObject.put(MARGIN_RIGHT_KEY, model.marginRight)
66
67
  jsonObject.put(CORNER_RADIUS_KEY, model.cornerRadius)
68
+ jsonObject.put(AD_CONFIGURATION_KEY, FWAdConfigurationSerializer.serialize(model.adConfiguration))
67
69
 
68
70
  return jsonObject
69
71
  }
@@ -18,7 +18,9 @@ data class FWVideoPlayerConfigModel(
18
18
  val shareBaseUrl: String? = null,
19
19
  val ctaWidth: FWVideoPlayerCTAWidth? = null,
20
20
  val enablePictureInPicture: Boolean? = null,
21
- ) {
21
+ val showVideoDetailTitle: Boolean? = null,
22
+ val buttonConfiguration: FWPlayerButtonConfigurationModel?
23
+ ) {
22
24
 
23
25
  data class FWCtaButtonStyleModel(
24
26
  val backgroundColor: String? = null,
@@ -20,6 +20,8 @@ object FWVideoPlayerConfigModelDeserializer {
20
20
  private const val SHARE_BASE_URL_KEY = "shareBaseURL"
21
21
  private const val CTA_WIDTH_KEY = "ctaWidth"
22
22
  private const val ENABLE_PIP_KEY = "enablePictureInPicture"
23
+ private const val SHOW_VIDEO_DETAIL_TITLE_KEY = "showVideoDetailTitle"
24
+ private const val BUTTON_CONFIGURATION_KEY = "buttonConfiguration"
23
25
 
24
26
  private const val BACKGROUND_COLOR_KEY = "backgroundColor"
25
27
  private const val FONT_SIZE_KEY = "fontSize"
@@ -43,6 +45,8 @@ object FWVideoPlayerConfigModelDeserializer {
43
45
  val shareBaseUrl = if (responseJson.has(SHARE_BASE_URL_KEY)) responseJson.optString(SHARE_BASE_URL_KEY) else null
44
46
  val ctaWidth = if (responseJson.has(CTA_WIDTH_KEY)) responseJson.optString(CTA_WIDTH_KEY) else null
45
47
  val enablePictureInPicture = if (responseJson.has(ENABLE_PIP_KEY)) responseJson.optBoolean(ENABLE_PIP_KEY) else null
48
+ val showVideoDetailTitle = if (responseJson.has(SHOW_VIDEO_DETAIL_TITLE_KEY)) responseJson.optBoolean(SHOW_VIDEO_DETAIL_TITLE_KEY) else null
49
+ val buttonConfigurationJsonObject = responseJson.optJSONObject(BUTTON_CONFIGURATION_KEY)
46
50
 
47
51
  return FWVideoPlayerConfigModel(
48
52
  playerStyle = if (!playerStyle.isNullOrBlank()) FWPlayerStyle.deserialize(playerStyle) else null,
@@ -56,7 +60,9 @@ object FWVideoPlayerConfigModelDeserializer {
56
60
  ctaHighlightDelay = ctaHighlightDelay,
57
61
  shareBaseUrl = shareBaseUrl,
58
62
  ctaWidth = if (!ctaWidth.isNullOrBlank()) FWVideoPlayerCTAWidth.deserialize(ctaWidth) else null,
59
- enablePictureInPicture = enablePictureInPicture
63
+ enablePictureInPicture = enablePictureInPicture,
64
+ showVideoDetailTitle = showVideoDetailTitle,
65
+ buttonConfiguration = FWPlayerButtonConfigurationDeserializer.deserialize(buttonConfigurationJsonObject)
60
66
  )
61
67
  }
62
68
 
@@ -20,6 +20,8 @@ object FWVideoPlayerConfigModelSerializer {
20
20
  private const val SHARE_BASE_URL_KEY = "shareBaseURL"
21
21
  private const val CTA_WIDTH_KEY = "ctaWidth"
22
22
  private const val ENABLE_PIP_KEY = "enablePictureInPicture"
23
+ private const val SHOW_VIDEO_DETAIL_TITLE_KEY = "showVideoDetailTitle"
24
+ private const val BUTTON_CONFIGURATION_KEY = "buttonConfiguration"
23
25
 
24
26
  private const val BACKGROUND_COLOR_KEY = "backgroundColor"
25
27
  private const val FONT_SIZE_KEY = "fontSize"
@@ -43,6 +45,8 @@ object FWVideoPlayerConfigModelSerializer {
43
45
  jsonObject.put(SHARE_BASE_URL_KEY, model.shareBaseUrl)
44
46
  jsonObject.put(CTA_WIDTH_KEY, FWVideoPlayerCTAWidth.serialize(model.ctaWidth))
45
47
  jsonObject.put(ENABLE_PIP_KEY, model.enablePictureInPicture)
48
+ jsonObject.put(SHOW_VIDEO_DETAIL_TITLE_KEY, model.showVideoDetailTitle)
49
+ jsonObject.put(BUTTON_CONFIGURATION_KEY, FWPlayerButtonConfigurationSerializer.serialize(model.buttonConfiguration))
46
50
  return jsonObject
47
51
  }
48
52
 
@@ -0,0 +1,18 @@
1
+ package com.fireworksdk.bridge.models.enums
2
+
3
+ enum class FWErrorAction(val rawValue: String) {
4
+ LoadingFirstPage("loadingFirstPage"),
5
+ LoadingNextPage("loadingNextPage");
6
+
7
+ companion object {
8
+ fun deserialize(rawValue: String?): FWErrorAction? {
9
+ rawValue ?: return null
10
+ return FWErrorAction.values().first { it.rawValue == rawValue }
11
+ }
12
+
13
+ fun serialize(model: FWErrorAction?): String? {
14
+ model ?: return null
15
+ return model.rawValue
16
+ }
17
+ }
18
+ }
@@ -16,6 +16,7 @@ enum class FWSDKInitSubEventName(val rawValue: String) {
16
16
 
17
17
  enum class FWFeedViewEventName(val rawValue: String) {
18
18
  VideoFeedLoadFinished("onVideoFeedLoadFinished"),
19
+ VideoFeedEmpty("onVideoFeedEmpty"),
19
20
  }
20
21
 
21
22
  enum class FWVideoPlaybackSubEventName(val rawValue: String) {
@@ -39,6 +40,7 @@ enum class FWVideoShoppingEventName(val rawValue: String) {
39
40
  UpdateProductDetails("fw:shopping:update-product-details"),
40
41
  WillDisplayProduct("fw:shopping:will-display-product"),
41
42
  CustomLinkButtonClick("fw:shopping:custom-link-button-click"),
43
+ CustomProductCardTap("fw:shopping:custom-product-card-tap"),
42
44
  }
43
45
 
44
46
  enum class FWLiveStreamEventName(val rawValue: String) {
@@ -50,5 +52,6 @@ enum class FWLiveStreamEventName(val rawValue: String) {
50
52
 
51
53
  enum class FWStoryBlockEventName(val rawValue: String) {
52
54
  StoryBlockLoadFinished("onStoryBlockLoadFinished"),
55
+ StoryBlockEmpty("onStoryBlockEmpty"),
53
56
  StoryBlockFullScreenStateChanged("onStoryBlockFullScreenStateChanged"),
54
57
  }
@@ -10,6 +10,7 @@ import com.facebook.react.common.MapBuilder
10
10
  import com.facebook.react.uimanager.ThemedReactContext
11
11
  import com.facebook.react.uimanager.ViewGroupManager
12
12
  import com.facebook.react.uimanager.annotations.ReactProp
13
+ import com.firework.error.storyblock.StoryBlockError
13
14
  import com.firework.storyblock.FeedLoadState
14
15
  import com.fireworksdk.bridge.components.storyblock.StoryBlockFragment
15
16
  import com.fireworksdk.bridge.components.storyblock.StoryBlockFrameLayout
@@ -18,9 +19,7 @@ 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
20
21
  import com.fireworksdk.bridge.utils.FWFragmentUtil
21
- import com.fireworksdk.bridge.utils.FWGlobalDataUtil
22
22
  import com.fireworksdk.bridge.utils.FWLogUtils
23
- import com.fireworksdk.bridge.utils.FWStoryBlockUtil
24
23
  import org.json.JSONObject
25
24
 
26
25
 
@@ -48,7 +47,9 @@ class FWStoryBlockManager : ViewGroupManager<StoryBlockFrameLayout>() {
48
47
  map["create"] = COMMAND_CREATE
49
48
  map["play"] = COMMAND_PLAY
50
49
  map["pause"] = COMMAND_PAUSE
51
- map["toggleFullScreen"] = COMMAND_TOGGLE_FULL_SCREEN
50
+ map["openFullscreen"] = COMMAND_OPEN_FULL_SCREEN
51
+ map["onViewportEntered"] = COMMAND_ON_VIEWPORT_ENTERED
52
+ map["onViewportLeft"] = COMMAND_ON_VIEWPORT_LEFT
52
53
  return map
53
54
  }
54
55
 
@@ -66,7 +67,9 @@ class FWStoryBlockManager : ViewGroupManager<StoryBlockFrameLayout>() {
66
67
  }
67
68
  COMMAND_PLAY -> root.storyBlockFragment?.play()
68
69
  COMMAND_PAUSE -> root.storyBlockFragment?.pause()
69
- COMMAND_TOGGLE_FULL_SCREEN -> root.storyBlockFragment?.toggleFullScreen()
70
+ COMMAND_OPEN_FULL_SCREEN -> root.storyBlockFragment?.openFullscreen()
71
+ COMMAND_ON_VIEWPORT_ENTERED -> root.storyBlockFragment?.onViewportEntered()
72
+ COMMAND_ON_VIEWPORT_LEFT -> root.storyBlockFragment?.onViewportLeft()
70
73
  else -> {}
71
74
  }
72
75
  }
@@ -150,6 +153,16 @@ class FWStoryBlockManager : ViewGroupManager<StoryBlockFrameLayout>() {
150
153
  )
151
154
  }
152
155
 
156
+ @ReactProp(name = "adConfiguration")
157
+ fun setAdConfiguration(view: StoryBlockFrameLayout, config: ReadableMap?) {
158
+ val configMap = config?.toHashMap() ?: hashMapOf()
159
+ val jsonObject = JSONObject(configMap)
160
+ val adConfigurationModel = FWAdConfigurationDeserializer.deserialize(jsonObject)
161
+ view.videoFeedPropsModel = view.videoFeedPropsModel.copy(
162
+ adConfiguration = adConfigurationModel
163
+ )
164
+ }
165
+
153
166
  @ReactProp(name = "cornerRadius")
154
167
  fun setCornerRadius(view: StoryBlockFrameLayout, cornerRadius: Int?) {
155
168
  view.videoFeedPropsModel = view.videoFeedPropsModel.copy(
@@ -160,11 +173,9 @@ class FWStoryBlockManager : ViewGroupManager<StoryBlockFrameLayout>() {
160
173
  private fun setupLayout(view: View) {
161
174
  Choreographer.getInstance().postFrameCallback(object : Choreographer.FrameCallback {
162
175
  override fun doFrame(frameTimeNanos: Long) {
163
- if (view.isAttachedToWindow) {
164
- manuallyLayoutChildren(view)
165
- view.viewTreeObserver.dispatchOnGlobalLayout()
166
- Choreographer.getInstance().postFrameCallback(this)
167
- }
176
+ manuallyLayoutChildren(view)
177
+ view.viewTreeObserver.dispatchOnGlobalLayout()
178
+ Choreographer.getInstance().postFrameCallback(this)
168
179
  }
169
180
  })
170
181
  }
@@ -180,32 +191,42 @@ class FWStoryBlockManager : ViewGroupManager<StoryBlockFrameLayout>() {
180
191
  private fun addStoryBlockListener(fragment: StoryBlockFragment, reactNativeViewId: Int) {
181
192
  fragment.setFeedLoadListener { feedLoadState ->
182
193
  when (feedLoadState) {
194
+ FeedLoadState.Loading -> {
195
+ FWLogUtils.d { "StoryBlock FeedViewState.Loading" }
196
+ }
183
197
  FeedLoadState.FeedLoaded -> {
184
198
  FWEventUtils.receiveStoryBlockLoadFinishedSuccessEvent(reactContext, reactNativeViewId)
185
199
  }
186
- FeedLoadState.FeedLoadFailed -> {
200
+ FeedLoadState.EmptyFeed -> {
201
+ FWEventUtils.receiveStoryBlockEmptyEvent(reactContext, reactNativeViewId)
202
+ }
203
+ FeedLoadState.EndOfFeed -> {
204
+ FWEventUtils.receiveStoryBlockLoadFinishedSuccessEvent(reactContext, reactNativeViewId)
205
+ }
206
+ else -> {}
207
+ }
208
+ }
209
+
210
+ fragment.setOnErrorListener { error ->
211
+ when (error) {
212
+ is StoryBlockError.LoadingFailed -> {
187
213
  FWEventUtils.receiveStoryBlockLoadFinishedFailedEvent(
188
214
  reactContext,
189
215
  reactNativeViewId,
190
- "FeedLoadFailed",
191
- "FeedLoadFailed"
216
+ error.message,
217
+ error.message
192
218
  )
193
219
  }
194
- else -> {}
195
- }
196
- }
197
220
 
198
- fragment.setOnFullScreenStateChangedListener { isFullScreen ->
199
- if (isFullScreen) {
200
- FWStoryBlockUtil.addFullScreenStoryBlockFragment(fragment)
201
- } else {
202
- FWStoryBlockUtil.removeFullScreenStoryBlockFragment(fragment)
221
+ else -> {
222
+ FWEventUtils.receiveStoryBlockLoadFinishedFailedEvent(
223
+ reactContext,
224
+ reactNativeViewId,
225
+ null,
226
+ null
227
+ )
228
+ }
203
229
  }
204
- FWEventUtils.receiveStoryBlockFullScreenStateChangedEvent(
205
- reactContext,
206
- reactNativeViewId,
207
- isFullScreen
208
- )
209
230
  }
210
231
  }
211
232
 
@@ -261,6 +282,7 @@ class FWStoryBlockManager : ViewGroupManager<StoryBlockFrameLayout>() {
261
282
  return MapBuilder.builder<String, Any>()
262
283
  .put(FWStoryBlockEventName.StoryBlockLoadFinished.rawValue, MapBuilder.of("phasedRegistrationNames", MapBuilder.of("bubbled", FWStoryBlockEventName.StoryBlockLoadFinished.rawValue)))
263
284
  .put(FWStoryBlockEventName.StoryBlockFullScreenStateChanged.rawValue, MapBuilder.of("phasedRegistrationNames", MapBuilder.of("bubbled", FWStoryBlockEventName.StoryBlockFullScreenStateChanged.rawValue)))
285
+ .put(FWStoryBlockEventName.StoryBlockEmpty.rawValue, MapBuilder.of("phasedRegistrationNames", MapBuilder.of("bubbled", FWStoryBlockEventName.StoryBlockEmpty.rawValue)))
264
286
  .build()
265
287
  }
266
288
 
@@ -269,7 +291,9 @@ class FWStoryBlockManager : ViewGroupManager<StoryBlockFrameLayout>() {
269
291
  private const val COMMAND_CREATE = 1000000
270
292
  private const val COMMAND_PLAY = 1000001
271
293
  private const val COMMAND_PAUSE = 1000002
272
- private const val COMMAND_TOGGLE_FULL_SCREEN = 1000003
294
+ private const val COMMAND_OPEN_FULL_SCREEN = 1000003
295
+ private const val COMMAND_ON_VIEWPORT_ENTERED = 1000004
296
+ private const val COMMAND_ON_VIEWPORT_LEFT = 1000005
273
297
  }
274
298
 
275
299
  }
@@ -8,12 +8,15 @@ import com.facebook.react.uimanager.ThemedReactContext
8
8
 
9
9
  import com.facebook.react.uimanager.annotations.ReactProp
10
10
  import com.facebook.react.common.MapBuilder
11
+ import com.firework.error.videofeed.VideoFeedError
11
12
  import com.firework.videofeed.FeedItemClickListener
12
13
  import com.firework.videofeed.FeedViewState
13
14
  import com.fireworksdk.bridge.components.videofeed.FWVideoFeed
15
+ import com.fireworksdk.bridge.models.FWAdConfigurationDeserializer
14
16
  import com.fireworksdk.bridge.models.FWVideoFeedConfigModelDeserializer
15
17
  import com.fireworksdk.bridge.models.FWVideoFeedItemDetailsModel
16
18
  import com.fireworksdk.bridge.models.FWVideoPlayerConfigModelDeserializer
19
+ import com.fireworksdk.bridge.models.enums.FWErrorAction
17
20
  import com.fireworksdk.bridge.models.enums.FWFeedViewEventName
18
21
  import com.fireworksdk.bridge.models.enums.FWVideoFeedMode
19
22
  import com.fireworksdk.bridge.models.enums.FWVideoFeedSource
@@ -140,6 +143,16 @@ class FWVideoFeedManager : SimpleViewManager<FWVideoFeed>() {
140
143
  )
141
144
  }
142
145
 
146
+ @ReactProp(name = "adConfiguration")
147
+ fun setAdConfiguration(view: FWVideoFeed, config: ReadableMap?) {
148
+ val configMap = config?.toHashMap() ?: hashMapOf()
149
+ val jsonObject = JSONObject(configMap)
150
+ val adConfigurationModel = FWAdConfigurationDeserializer.deserialize(jsonObject)
151
+ view.videoFeedPropsModel = view.videoFeedPropsModel.copy(
152
+ adConfiguration = adConfigurationModel
153
+ )
154
+ }
155
+
143
156
  private fun addVideoFeedListener(reactContext: ThemedReactContext, videoFeed: FWVideoFeed?) {
144
157
  val videoFeedView = videoFeed?.videoFeedView
145
158
  videoFeedView ?: return
@@ -172,18 +185,43 @@ class FWVideoFeedManager : SimpleViewManager<FWVideoFeed>() {
172
185
  FWLogUtils.d { "FeedViewState.LoadData" }
173
186
  FWEventUtils.receiveVideoFeedLoadFinishedSuccessEvent(reactContext, videoFeed.id)
174
187
  }
175
- is FeedViewState.ScrollToPosition -> {
176
- FWLogUtils.d { "FeedViewState.ScrollToPosition" }
188
+ is FeedViewState.EmptyFeed -> {
189
+ FWLogUtils.d { "FeedViewState.EmptyFeed" }
190
+ FWEventUtils.receiveVideoFeedEmptyEvent(reactContext, videoFeed.id)
177
191
  }
178
- is FeedViewState.OpenFeedElementAtIndex -> {
179
- FWLogUtils.d { "FeedViewState.OpenFeedElementAtIndex" }
180
- }
181
- is FeedViewState.Error -> {
182
- FWLogUtils.d { "FeedViewState.Error" }
183
- FWEventUtils.receiveVideoFeedLoadFinishedFailedEvent(reactContext, videoFeed.id, feedViewState.message, feedViewState.message)
192
+ is FeedViewState.EndOfFeed -> {
193
+ FWLogUtils.d { "FeedViewState.EndOfFeed" }
194
+ FWEventUtils.receiveVideoFeedLoadFinishedSuccessEvent(reactContext, videoFeed.id)
184
195
  }
185
196
  else -> {}
186
197
  }}
198
+
199
+ videoFeed.setOnErrorListener { error ->
200
+ when (error) {
201
+ is VideoFeedError.LoadingFirstPageFailed -> {
202
+ FWEventUtils.receiveVideoFeedLoadFinishedFailedEvent(
203
+ reactContext,
204
+ videoFeed.id,
205
+ error.message,
206
+ error.message,
207
+ FWErrorAction.LoadingFirstPage.rawValue
208
+ )
209
+ }
210
+
211
+ is VideoFeedError.LoadingNextPageFailed -> {
212
+ FWEventUtils.receiveVideoFeedLoadFinishedFailedEvent(
213
+ reactContext,
214
+ videoFeed.id,
215
+ error.message,
216
+ error.message,
217
+ FWErrorAction.LoadingNextPage.rawValue
218
+ )
219
+ }
220
+
221
+ else -> {
222
+ }
223
+ }
224
+ }
187
225
  }
188
226
 
189
227
 
@@ -213,6 +251,7 @@ class FWVideoFeedManager : SimpleViewManager<FWVideoFeed>() {
213
251
  override fun getExportedCustomBubblingEventTypeConstants(): MutableMap<String, Any>? {
214
252
  return MapBuilder.builder<String, Any>()
215
253
  .put(FWFeedViewEventName.VideoFeedLoadFinished.rawValue, MapBuilder.of("phasedRegistrationNames", MapBuilder.of("bubbled", FWFeedViewEventName.VideoFeedLoadFinished.rawValue)))
254
+ .put(FWFeedViewEventName.VideoFeedEmpty.rawValue, MapBuilder.of("phasedRegistrationNames", MapBuilder.of("bubbled", FWFeedViewEventName.VideoFeedEmpty.rawValue)))
216
255
  .build()
217
256
  }
218
257
 
@@ -13,4 +13,5 @@ interface FWVideoShoppingInterface {
13
13
  fun setCartIconVisible(visible: Boolean?)
14
14
  fun setCartItemCount(count: Int?)
15
15
  fun setCustomClickLinkButtonEnabled(value: Boolean?, promise: Promise)
16
+ fun setCustomTapProductCardEnabled(value: Boolean?, promise: Promise)
16
17
  }
@@ -7,7 +7,6 @@ import com.fireworksdk.bridge.FWInitializationProvider
7
7
  import com.fireworksdk.bridge.reactnative.models.FWNavigatorInterface
8
8
  import com.fireworksdk.bridge.reactnative.pages.FWContainerActivity
9
9
  import com.fireworksdk.bridge.utils.FWLogUtils
10
- import com.fireworksdk.bridge.utils.FWStoryBlockUtil
11
10
 
12
11
 
13
12
  class FWNavigatorModule(
@@ -49,15 +48,6 @@ class FWNavigatorModule(
49
48
  return
50
49
  }
51
50
 
52
- val currentStoryBlockFragment = FWStoryBlockUtil.getCurrentFullScreenStoryBlockFragment()
53
- if (currentStoryBlockFragment?.activity == activity) {
54
- UiThreadUtil.runOnUiThread {
55
- currentStoryBlockFragment.toggleFullScreen()
56
- }
57
- promise.resolve(true)
58
- return
59
- }
60
-
61
51
  if (activity.javaClass.name.equals("com.firework.player.pager.PlayerActivity")) {
62
52
  UiThreadUtil.runOnUiThread {
63
53
  activity.finish()
@@ -15,6 +15,7 @@ import com.fireworksdk.bridge.models.enums.FWProductCardTheme
15
15
  import com.fireworksdk.bridge.models.enums.FWShoppingCtaResultRes
16
16
  import com.fireworksdk.bridge.reactnative.models.FWVideoShoppingInterface
17
17
  import com.fireworksdk.bridge.reactnative.utils.FWEventUtils
18
+ import com.fireworksdk.bridge.utils.FWCommonUtil
18
19
  import com.fireworksdk.bridge.utils.FWDateUtils
19
20
  import com.fireworksdk.bridge.utils.FWGlobalDataUtil
20
21
  import com.fireworksdk.bridge.utils.FWLogUtils
@@ -168,10 +169,28 @@ class FWVideoShoppingModule(
168
169
  else -> {}
169
170
  }
170
171
 
172
+ var productCardCornerRadius = FWCommonUtil.dpToPx(4.toFloat(), reactApplicationContext)
173
+ if (configModel.productCard?.cornerRadius != null) {
174
+ productCardCornerRadius = FWCommonUtil.dpToPx(configModel.productCard.cornerRadius.toFloat(), reactApplicationContext)
175
+ }
176
+
177
+ var isPriceVisible = true
178
+ if (configModel.productCard?.priceConfiguration?.isHidden != null) {
179
+ isPriceVisible = !configModel.productCard.priceConfiguration.isHidden
180
+ }
181
+
182
+ var isCtaVisible = true
183
+ if (configModel.productCard?.isCtaButtonHidden != null) {
184
+ isCtaVisible = !configModel.productCard.isCtaButtonHidden
185
+ }
186
+
171
187
  FireworkSdk.shopping.setShoppingViewOptions(
172
188
  ShoppingViewOptions(
173
189
  productCardsOptions = ProductCardsOptions(
174
190
  ctaButtonText = productCtaButtonText,
191
+ cornerRadius = productCardCornerRadius.toFloat(),
192
+ isPriceVisible = isPriceVisible,
193
+ isCtaVisible = isCtaVisible,
175
194
  ),
176
195
  productDetailsOptions = ProductDetailsOptions(
177
196
  linkButtonOptions = LinkButtonOptions(isVisible = !isLinkButtonHidden),
@@ -313,6 +332,29 @@ class FWVideoShoppingModule(
313
332
  promise.resolve(true)
314
333
  }
315
334
 
335
+ @ReactMethod
336
+ override fun setCustomTapProductCardEnabled(value: Boolean?, promise: Promise) {
337
+
338
+ if (value == true) {
339
+ FireworkSdk.shopping.setOnProductCardClickListener { productId, unitId, productWebUrl ->
340
+ FWLogUtils.d { "FWVideoShoppingModule productCardClick $productId $unitId $productWebUrl" }
341
+
342
+ FWEventUtils.sendProductCardClickEvent(
343
+ reactApplicationContext,
344
+ productWebUrl,
345
+ productId,
346
+ unitId,
347
+ callbackId
348
+ )
349
+ }
350
+ } else {
351
+ FireworkSdk.shopping.setOnProductCardClickListener(null)
352
+ }
353
+
354
+
355
+ promise.resolve(true)
356
+ }
357
+
316
358
  @ReactMethod
317
359
  fun addListener(eventName: String?) {
318
360
  // Set up any upstream listeners or background tasks as necessary
@@ -57,9 +57,11 @@ class FireworkSDKModule(
57
57
  val jsonObject = JSONObject(configMap)
58
58
  val sdkInitOptionsModel = FWSDKInitOptionsModelDeserializer.deserialize(jsonObject)
59
59
 
60
- initSdk(sdkInitOptionsModel)
61
- promise.resolve(Arguments.createMap())
62
- FireworkSdk.analytics.register(this)
60
+ UiThreadUtil.runOnUiThread {
61
+ initSdk(sdkInitOptionsModel)
62
+ promise.resolve(Arguments.createMap())
63
+ FireworkSdk.analytics.register(this)
64
+ }
63
65
  }
64
66
 
65
67
  /**