react-native-firework-sdk 2.0.0 → 2.1.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 (138) hide show
  1. package/android/build.gradle +5 -3
  2. package/android/src/main/java/com/fireworksdk/bridge/components/videofeed/StoryBlockFragment.kt +129 -0
  3. package/android/src/main/java/com/fireworksdk/bridge/components/videofeed/StoryBlockFrameLayout.kt +84 -0
  4. package/android/src/main/java/com/fireworksdk/bridge/models/FWEventName.kt +2 -1
  5. package/android/src/main/java/com/fireworksdk/bridge/models/FWProductInfoViewConfiguration.kt +18 -5
  6. package/android/src/main/java/com/fireworksdk/bridge/models/FWProductInfoViewConfigurationDeserializer.kt +33 -9
  7. package/android/src/main/java/com/fireworksdk/bridge/models/FWShoppingCtaResult.kt +17 -0
  8. package/android/src/main/java/com/fireworksdk/bridge/models/FWShoppingCtaResultDeserializer.kt +33 -0
  9. package/android/src/main/java/com/fireworksdk/bridge/reactnative/manager/FWStoryBlockManager.kt +126 -45
  10. package/android/src/main/java/com/fireworksdk/bridge/reactnative/manager/FWVideoFeedManager.kt +6 -3
  11. package/android/src/main/java/com/fireworksdk/bridge/reactnative/models/FWVideoShoppingInterface.kt +2 -2
  12. package/android/src/main/java/com/fireworksdk/bridge/reactnative/module/FWNavigatorModule.kt +9 -1
  13. package/android/src/main/java/com/fireworksdk/bridge/reactnative/module/FWVideoShoppingModule.kt +81 -50
  14. package/android/src/main/java/com/fireworksdk/bridge/reactnative/utils/FWEventUtils.kt +9 -2
  15. package/android/src/main/java/com/fireworksdk/bridge/utils/FWConfigUtil.kt +1 -1
  16. package/android/src/main/java/com/fireworksdk/bridge/utils/FWGlobalDataUtil.kt +4 -0
  17. package/android/src/main/java/com/fireworksdk/bridge/utils/FWLanguageUtil.kt +48 -16
  18. package/android/src/main/res/layout/fw_bridge_story_block.xml +24 -0
  19. package/ios/Components/StoryBlock.swift +33 -2
  20. package/ios/Components/StoryBlockManager.m +32 -0
  21. package/ios/Components/VideoFeed.swift +9 -29
  22. package/ios/Components/VideoFeedManager.m +11 -6
  23. package/ios/FireworkSdk.xcodeproj/project.pbxproj +378 -104
  24. package/ios/Models/NativeToRN/FireworkEventName.swift +3 -1
  25. package/ios/Models/RNToNative/RCTConvert+Shopping.swift +21 -0
  26. package/ios/Models/RNToNative/RCTConvert+VideoFeed.swift +27 -0
  27. package/ios/Modules/FWNavigatorModule/FWNavigatorModule.swift +5 -1
  28. package/ios/Modules/FireworkSDKModule/FireworkSDKModule.m +1 -0
  29. package/ios/Modules/FireworkSDKModule/FireworkSDKModule.swift +30 -0
  30. package/ios/Modules/Shopping/ProductInfoViewConfiguration.swift +13 -0
  31. package/ios/Modules/Shopping/ShoppingCTAResult.swift +16 -0
  32. package/ios/Modules/Shopping/ShoppingModule.m +2 -1
  33. package/ios/Modules/Shopping/ShoppingModule.swift +106 -30
  34. package/ios/Support/MultiHostStreaming/FWMultiHostStreaming.podspec +24 -0
  35. package/ios/Support/MultiHostStreaming/src/MultiHostStreamingSDK.swift +17 -0
  36. package/ios/Utils/AppLanguage/Bundle+FWSwizzle.swift +58 -0
  37. package/ios/Utils/AppLanguage/FWAppLanguageManager.swift +139 -0
  38. package/ios/Utils/AppLanguage/FWLanguageUtil.swift +43 -0
  39. package/ios/Utils/AppLanguage/NumberFormatter+FWSwizzle.swift +25 -0
  40. package/ios/Utils/AppLanguage/UIImageView+FWSwizzle.swift +91 -0
  41. package/ios/Utils/AppLanguage/UILabel+FWSwizzle.swift +98 -0
  42. package/ios/Utils/AppLanguage/UITextField+FWSwizzle.swift +97 -0
  43. package/ios/Utils/AppLanguage/UITextView+FWSwizzle.swift +97 -0
  44. package/ios/Utils/AppLanguage/UIView+FWSwizzle.swift +38 -0
  45. package/ios/Utils/AppLanguage/UIViewController+FWSwizzle.swift +32 -0
  46. package/ios/Utils/AppLanguage/UIWindow+FWSwizzle.swift +26 -0
  47. package/ios/Utils/AppLanguage/URLSession+FWSwizzle.swift +69 -0
  48. package/ios/Utils/{DispatchQueue+FWOnce.swift → Extensions/DispatchQueue+FWOnce.swift} +3 -3
  49. package/ios/Utils/{UINavigationController+FWSwizzle.swift → Extensions/Swizzle/UINavigationController+FWSwizzle.swift} +6 -8
  50. package/ios/Utils/Extensions/UIView+FWUIHierarchy.swift +47 -0
  51. package/ios/Utils/FWRTL/Classes/Manager/FWRTLManager.h +25 -0
  52. package/ios/Utils/FWRTL/Classes/Manager/FWRTLManager.m +75 -0
  53. package/ios/Utils/FWRTL/Classes/UICategories/CALayer+FWRTL.h +21 -0
  54. package/ios/Utils/FWRTL/Classes/UICategories/CALayer+FWRTL.m +124 -0
  55. package/ios/Utils/FWRTL/Classes/UICategories/FWRTLRemoteViewControllerAdaptor.h +11 -0
  56. package/ios/Utils/FWRTL/Classes/UICategories/FWRTLRemoteViewControllerAdaptor.m +86 -0
  57. package/ios/Utils/FWRTL/Classes/UICategories/FWRTLWhiteListManager.h +16 -0
  58. package/ios/Utils/FWRTL/Classes/UICategories/FWRTLWhiteListManager.m +55 -0
  59. package/ios/Utils/FWRTL/Classes/UICategories/UILabel+FWRTL.h +18 -0
  60. package/ios/Utils/FWRTL/Classes/UICategories/UILabel+FWRTL.m +39 -0
  61. package/ios/Utils/FWRTL/Classes/UICategories/UIView+FWRTL.h +54 -0
  62. package/ios/Utils/FWRTL/Classes/UICategories/UIView+FWRTL.m +141 -0
  63. package/ios/Utils/FWRTL/Classes/UICategories/UIWindow+FWRTL.h +16 -0
  64. package/ios/Utils/FWRTL/Classes/UICategories/UIWindow+FWRTL.m +20 -0
  65. package/ios/Utils/FWRTL/Classes/Utils/FWRTLDefinitions.h +52 -0
  66. package/ios/Utils/FWRTL/Classes/Utils/NSObject+FWRTLReloadBlock.h +19 -0
  67. package/ios/Utils/FWRTL/Classes/Utils/NSObject+FWRTLReloadBlock.m +49 -0
  68. package/ios/Utils/FWRTL/Classes/Utils/NSString+FWRTL.h +21 -0
  69. package/ios/Utils/FWRTL/Classes/Utils/NSString+FWRTL.m +38 -0
  70. package/ios/Utils/FWRTL/Classes/Utils/UIImage+FWRTL.h +18 -0
  71. package/ios/Utils/FWRTL/Classes/Utils/UIImage+FWRTL.m +43 -0
  72. package/ios/Utils/FWSwizzleLoader.m +6 -1
  73. package/ios/Utils/FWSwizzleLoader.swift +13 -0
  74. package/ios/Utils/FWSwizzleUtil.swift +17 -9
  75. package/ios/react_native_firework_sdk.h +1 -0
  76. package/ios/scripts/react_native_firework_sdk_pods.rb +31 -0
  77. package/lib/commonjs/FireworkSDK.js +21 -4
  78. package/lib/commonjs/FireworkSDK.js.map +1 -1
  79. package/lib/commonjs/VideoShopping.js +20 -37
  80. package/lib/commonjs/VideoShopping.js.map +1 -1
  81. package/lib/commonjs/components/StoryBlock.js +190 -125
  82. package/lib/commonjs/components/StoryBlock.js.map +1 -1
  83. package/lib/commonjs/components/VideoFeed.js +11 -1
  84. package/lib/commonjs/components/VideoFeed.js.map +1 -1
  85. package/lib/commonjs/index.js.map +1 -1
  86. package/lib/commonjs/models/FWEventName.js +2 -0
  87. package/lib/commonjs/models/FWEventName.js.map +1 -1
  88. package/lib/commonjs/models/ShoppingCTAResult.js +2 -0
  89. package/lib/commonjs/modules/FireworkSDKModule.js.map +1 -1
  90. package/lib/commonjs/modules/ShoppingModule.js.map +1 -1
  91. package/lib/module/FireworkSDK.js +21 -4
  92. package/lib/module/FireworkSDK.js.map +1 -1
  93. package/lib/module/VideoShopping.js +20 -39
  94. package/lib/module/VideoShopping.js.map +1 -1
  95. package/lib/module/components/StoryBlock.js +179 -131
  96. package/lib/module/components/StoryBlock.js.map +1 -1
  97. package/lib/module/components/VideoFeed.js +10 -1
  98. package/lib/module/components/VideoFeed.js.map +1 -1
  99. package/lib/module/index.js.map +1 -1
  100. package/lib/module/models/FWEventName.js +2 -0
  101. package/lib/module/models/FWEventName.js.map +1 -1
  102. package/lib/module/models/ShoppingCTAResult.js +2 -0
  103. package/lib/module/modules/FireworkSDKModule.js.map +1 -1
  104. package/lib/module/modules/ShoppingModule.js.map +1 -1
  105. package/lib/typescript/FireworkSDK.d.ts +7 -4
  106. package/lib/typescript/VideoShopping.d.ts +9 -11
  107. package/lib/typescript/components/StoryBlock.d.ts +19 -25
  108. package/lib/typescript/index.d.ts +6 -6
  109. package/lib/typescript/models/FWEventName.d.ts +2 -0
  110. package/lib/typescript/models/FWEvents.d.ts +14 -1
  111. package/lib/typescript/models/ProductInfoViewConfiguration.d.ts +36 -1
  112. package/lib/typescript/models/ShoppingCTAResult.d.ts +11 -0
  113. package/lib/typescript/modules/FireworkSDKModule.d.ts +1 -2
  114. package/lib/typescript/modules/ShoppingModule.d.ts +2 -1
  115. package/package.json +2 -2
  116. package/react-native-firework-sdk.podspec +26 -24
  117. package/src/FireworkSDK.ts +18 -5
  118. package/src/VideoShopping.ts +40 -53
  119. package/src/components/StoryBlock.tsx +199 -96
  120. package/src/components/VideoFeed.tsx +11 -0
  121. package/src/index.ts +15 -7
  122. package/src/models/FWEventName.ts +2 -0
  123. package/src/models/FWEvents.ts +14 -1
  124. package/src/models/ProductInfoViewConfiguration.ts +38 -1
  125. package/src/models/ShoppingCTAResult.ts +11 -0
  126. package/src/modules/FireworkSDKModule.ts +1 -2
  127. package/src/modules/ShoppingModule.ts +5 -5
  128. package/android/src/main/java/com/fireworksdk/bridge/constants/FWCommandConstant.kt +0 -6
  129. package/ios/Utils/UIView+ParentViewController.swift +0 -21
  130. package/lib/commonjs/models/AddToCartResult.js +0 -2
  131. package/lib/module/models/AddToCartResult.js +0 -2
  132. package/lib/typescript/models/AddToCartResult.d.ts +0 -10
  133. package/src/models/AddToCartResult.ts +0 -10
  134. /package/ios/Utils/{String+Color.swift → Extensions/String+Color.swift} +0 -0
  135. /package/ios/Utils/{UIView+Constraints.swift → Extensions/UIView+Constraints.swift} +0 -0
  136. /package/ios/Utils/{UIViewController+AttachChild.swift → Extensions/UIViewController+AttachChild.swift} +0 -0
  137. /package/lib/commonjs/models/{AddToCartResult.js.map → ShoppingCTAResult.js.map} +0 -0
  138. /package/lib/module/models/{AddToCartResult.js.map → ShoppingCTAResult.js.map} +0 -0
@@ -7,7 +7,6 @@ import com.facebook.react.uimanager.SimpleViewManager
7
7
  import com.facebook.react.uimanager.ThemedReactContext
8
8
 
9
9
  import com.facebook.react.uimanager.annotations.ReactProp
10
- import com.fireworksdk.bridge.constants.FWCommandConstant
11
10
  import com.facebook.react.common.MapBuilder
12
11
  import com.firework.videofeed.FeedItemClickListener
13
12
  import com.firework.videofeed.FeedViewState
@@ -148,7 +147,7 @@ class FWVideoFeedManager : SimpleViewManager<FWVideoFeed>() {
148
147
 
149
148
  override fun getCommandsMap(): MutableMap<String, Int> {
150
149
  val map: MutableMap<String, Int> = HashMap()
151
- map["refresh"] = FWCommandConstant.FW_COMMAND_VIDEO_FEED_REFRESH
150
+ map["refresh"] = COMMAND_REFRESH
152
151
  return map
153
152
  }
154
153
 
@@ -156,7 +155,7 @@ class FWVideoFeedManager : SimpleViewManager<FWVideoFeed>() {
156
155
  super.receiveCommand(root, commandId, args)
157
156
  FWLogUtils.d { "FWVideoFeedManager receiveCommand commandId: $commandId" }
158
157
  when (commandId?.toInt()) {
159
- FWCommandConstant.FW_COMMAND_VIDEO_FEED_REFRESH -> {
158
+ COMMAND_REFRESH -> {
160
159
  FWLogUtils.d { "FWVideoFeedManager call refresh" }
161
160
  root.refresh()
162
161
  }
@@ -175,4 +174,8 @@ class FWVideoFeedManager : SimpleViewManager<FWVideoFeed>() {
175
174
  .build()
176
175
  }
177
176
 
177
+ companion object {
178
+ private const val COMMAND_REFRESH = 1000001
179
+ }
180
+
178
181
  }
@@ -8,8 +8,8 @@ interface FWVideoShoppingInterface {
8
8
 
9
9
  fun init()
10
10
  fun updateVideoProducts(productArray: ReadableArray?, callbackId: String?)
11
- fun updateProductViewConfig(config: ReadableMap?, callbackId: Int?)
12
- fun updateAddToCartStatus(res: String?, tip: String?, callbackId: Int?)
11
+ fun setProductInfoViewConfiguration(config: ReadableMap?)
12
+ fun updateShoppingCTAResult(result: ReadableMap?, callbackId: Int?)
13
13
  fun jumpToCartPage(callbackId: Int?, props: ReadableMap?)
14
14
  fun setCartIconVisible(visible: Boolean?)
15
15
  fun setCartItemCount(count: Int?)
@@ -3,10 +3,10 @@ package com.fireworksdk.bridge.reactnative.module
3
3
  import android.app.Activity
4
4
  import com.facebook.react.bridge.*
5
5
  import com.firework.sdk.FireworkSdk
6
- import com.firework.videofeed.PlayerActivity
7
6
  import com.fireworksdk.bridge.FWInitializationProvider
8
7
  import com.fireworksdk.bridge.reactnative.models.FWNavigatorInterface
9
8
  import com.fireworksdk.bridge.reactnative.utils.FWEventUtils
9
+ import com.fireworksdk.bridge.utils.FWGlobalDataUtil
10
10
  import com.fireworksdk.bridge.utils.FWLogUtils
11
11
 
12
12
 
@@ -30,6 +30,14 @@ class FWNavigatorModule(
30
30
  }
31
31
 
32
32
  if (isTaskRoot(activity)) {
33
+ if (FWGlobalDataUtil.storyBlockFragment?.isFullScreen() == true) {
34
+ UiThreadUtil.runOnUiThread {
35
+ FWGlobalDataUtil.storyBlockFragment?.toggleFullScreen()
36
+ }
37
+ promise.resolve(true)
38
+ return
39
+ }
40
+
33
41
  promise.resolve(false)
34
42
  return
35
43
  }
@@ -7,12 +7,9 @@ import com.firework.common.product.CurrencyCode
7
7
  import com.firework.common.product.Product
8
8
  import com.firework.error.shopping.ShoppingError
9
9
  import com.firework.sdk.FireworkSdk
10
- import com.firework.shopping.ProductHydrator
11
- import com.firework.shopping.Shopping
10
+ import com.firework.shopping.*
12
11
  import com.fireworksdk.bridge.FWInitializationProvider
13
- import com.fireworksdk.bridge.models.FWProductInfoViewConfigurationDeserializer
14
- import com.fireworksdk.bridge.models.FWVideoShoppingProduct
15
- import com.fireworksdk.bridge.models.FWVideoShoppingProductDeserializer
12
+ import com.fireworksdk.bridge.models.*
16
13
  import com.fireworksdk.bridge.reactnative.models.FWVideoShoppingInterface
17
14
  import com.fireworksdk.bridge.reactnative.utils.FWEventUtils
18
15
  import com.fireworksdk.bridge.utils.FWDateUtils
@@ -28,7 +25,7 @@ class FWVideoShoppingModule(
28
25
  reactContext: ReactApplicationContext
29
26
  ) : ReactContextBaseJavaModule(reactContext), FWVideoShoppingInterface {
30
27
 
31
- private var addToCartHandler: Triple<Int, String, String>? = null
28
+ private var ctaHandler: Triple<Int, String, String>? = null
32
29
  private var cartClickHandler: Pair<Int, Activity>? = null
33
30
  private val updateProductHandler: HashMap<String, List<Product>> = HashMap()
34
31
  private val updateProductHydratorHandler: HashMap<String, ProductHydrator> = HashMap()
@@ -129,47 +126,80 @@ class FWVideoShoppingModule(
129
126
  }
130
127
 
131
128
  @ReactMethod
132
- override fun updateProductViewConfig(config: ReadableMap?, callbackId: Int?) {
133
- FWLogUtils.d { "FWVideoShoppingModule updateProductViewConfig: $callbackId, config: $config" }
129
+ override fun setProductInfoViewConfiguration(config: ReadableMap?) {
130
+ FWLogUtils.d { "FWVideoShoppingModule setProductInfoViewConfiguration: $callbackId, config: $config" }
134
131
  val configMap = config?.toHashMap() ?: hashMapOf()
135
132
  val jsonObject = JSONObject(configMap)
136
133
  val configModel = FWProductInfoViewConfigurationDeserializer.deserialize(jsonObject)
137
- FWLogUtils.d { "FWVideoShoppingModule updateProductViewConfig: $callbackId, configModel: $configModel" }
134
+ FWLogUtils.d { "FWVideoShoppingModule setProductInfoViewConfiguration: $callbackId, configModel: $configModel" }
135
+
136
+ if (configModel == null) {
137
+ return
138
+ }
139
+
140
+ val isLinkButtonHidden = configModel.linkButton?.isHidden == true
141
+ var text = ShoppingCtaButtonOptions.Text.ADD_TO_CART
142
+ when (configModel.ctaButton?.text) {
143
+ FWProductInfoViewConfiguration.CtaButtonConfiguration.TextValue.ShopNow -> {
144
+ text = ShoppingCtaButtonOptions.Text.SHOP_NOW
145
+ }
146
+ else -> {}
147
+ }
148
+
149
+ FireworkSdk.shopping.setShoppingViewOptions(
150
+ ShoppingViewOptions(
151
+ ProductDetailsOptions(
152
+ linkButtonOptions = LinkButtonOptions(isVisible = !isLinkButtonHidden),
153
+ shoppingCtaButtonOptions = ShoppingCtaButtonOptions(text = text),
154
+ ),
155
+ ),
156
+ )
138
157
  }
139
158
 
140
159
  @ReactMethod
141
- override fun updateAddToCartStatus(res: String?, tip: String?, callbackId: Int?) {
142
- FWLogUtils.d { "FWVideoShoppingModule updateAddToCartStatus: $callbackId, res: $res, tip: $tip, addToCartHandler: ${addToCartHandler?.first}" }
143
- if (callbackId == null || addToCartHandler?.first != callbackId) {
160
+ override fun updateShoppingCTAResult(result: ReadableMap?, callbackId: Int?) {
161
+ FWLogUtils.d { "FWVideoShoppingModule updateShoppingCTAResult: $callbackId, result: $result, ctaHandler: ${ctaHandler?.first}" }
162
+ val resultMap = result?.toHashMap() ?: hashMapOf()
163
+ val jsonObject = JSONObject(resultMap)
164
+ val resultModel = FWShoppingCtaResultDeserializer.deserialize(jsonObject)
165
+ FWLogUtils.d { "FWVideoShoppingModule updateShoppingCTAResult: $callbackId, resultModel: $resultModel" }
166
+
167
+ if (resultModel == null) {
168
+ return
169
+ }
170
+
171
+ if (callbackId == null || ctaHandler?.first != callbackId) {
144
172
  return
145
173
  }
146
174
 
147
- val productId = addToCartHandler?.second
175
+ val productId = ctaHandler?.second
148
176
  productId ?: return
149
177
 
150
- val unitId = addToCartHandler?.third
178
+ val unitId = ctaHandler?.third
151
179
  if (unitId.isNullOrBlank()) {
152
180
  return
153
181
  }
154
182
 
155
- when {
156
- res.equals("success") -> {
157
- val status = Shopping.AddToCartStatus.Success(
158
- productId = productId,
159
- unitId = unitId
160
- )
161
- FireworkSdk.shopping.setAddToCartStatus(status)
162
- Toast.makeText(currentActivity, tip, Toast.LENGTH_LONG).show()
183
+ when (resultModel.res) {
184
+ FWShoppingCtaResult.Res.Success -> {
185
+ val numberOfItemsInCart = FireworkSdk.shopping.numberOfItemsInCart
186
+ FireworkSdk.shopping.setCtaButtonStatus(Shopping.CtaButtonStatus.Success)
187
+ FireworkSdk.shopping.numberOfItemsInCart = numberOfItemsInCart
188
+ }
189
+ FWShoppingCtaResult.Res.Fail -> {
190
+ FireworkSdk.shopping.setCtaButtonStatus(Shopping.CtaButtonStatus.Error)
163
191
  }
164
- res.equals("fail") -> {
165
- val status = Shopping.AddToCartStatus.Error(productId = productId, unitId = unitId)
166
- FireworkSdk.shopping.setAddToCartStatus(status)
167
- Toast.makeText(currentActivity, tip, Toast.LENGTH_LONG).show()
192
+ FWShoppingCtaResult.Res.Loading -> {
193
+ FireworkSdk.shopping.setCtaButtonStatus(Shopping.CtaButtonStatus.Loading)
168
194
  }
169
- res.equals("loading") -> {
170
- FireworkSdk.shopping.setAddToCartStatus(Shopping.AddToCartStatus.Loading)
195
+ else -> {
196
+ // throw IllegalStateException("Not allowed: ${resultModel.res}")
171
197
  }
172
198
  }
199
+
200
+ if (!resultModel.tips.isNullOrBlank()) {
201
+ Toast.makeText(currentActivity, resultModel.tips, Toast.LENGTH_LONG).show()
202
+ }
173
203
  }
174
204
 
175
205
  @ReactMethod
@@ -196,33 +226,32 @@ class FWVideoShoppingModule(
196
226
  }
197
227
 
198
228
  private fun cartListener() {
199
- FireworkSdk.shopping.setOnCartActionListener(
200
- object : Shopping.OnCartActionListener {
201
- override fun onProductAddedToCart(productId: String, unitId: String) {
202
- FWLogUtils.d { "FWVideoShoppingModule updateCart, productId: $productId, unitId: $unitId" }
229
+ FireworkSdk.shopping.setOnCartClickListener(object : Shopping.OnCartClickListener {
230
+ override fun onCartClick() {
231
+ FWLogUtils.d { "FWVideoShoppingModule cartClicked" }
232
+ val activity = FWInitializationProvider.INSTANCE.resumedActivity
233
+ activity ?: return
234
+ val callbackId = generateCallbackId()
235
+ cartClickHandler = Pair(callbackId, activity)
236
+ FWEventUtils.sendCartIconClickEvent(reactApplicationContext, callbackId)
237
+ }
238
+ })
203
239
 
204
- FireworkSdk.shopping.setAddToCartStatus(Shopping.AddToCartStatus.Loading)
240
+ FireworkSdk.shopping.setOnCtaButtonClicked { productId, unitId, productWebUrl ->
241
+ FWLogUtils.d { "FWVideoShoppingModule updateCart, productId: $productId, unitId: $unitId" }
205
242
 
206
- val callbackId = generateCallbackId()
207
- addToCartHandler = Triple(callbackId, productId, unitId)
208
- FWEventUtils.sendAddToCartClickEvent(reactApplicationContext, productId, unitId, callbackId)
209
- }
243
+ FireworkSdk.shopping.setCtaButtonStatus(Shopping.CtaButtonStatus.Loading)
244
+
245
+ val callbackId = generateCallbackId()
246
+ ctaHandler = Triple(callbackId, productId, unitId)
247
+ FWEventUtils.sendShoppingCtaButtonClickEvent(reactApplicationContext, productId, unitId, productWebUrl, callbackId)
248
+ }
210
249
 
211
- override fun onCartClicked() {
212
- FWLogUtils.d { "FWVideoShoppingModule cartClicked" }
213
- val activity = FWInitializationProvider.INSTANCE.resumedActivity
214
- activity ?: return
215
- val callbackId = generateCallbackId()
216
- cartClickHandler = Pair(callbackId, activity)
217
- FWEventUtils.sendCartIconClickEvent(reactApplicationContext, callbackId)
218
- }
219
- },
220
- )
221
250
  FireworkSdk.shopping.setOnShoppingErrorListener(
222
251
  object : Shopping.OnShoppingErrorListener {
223
252
  override fun onShoppingError(error: ShoppingError) {
224
253
  when (error) {
225
- is ShoppingError.AddToCartError.Timeout -> {
254
+ is ShoppingError.CtaButtonClickError.Timeout -> {
226
255
  }
227
256
  else -> {}
228
257
  }
@@ -232,7 +261,7 @@ class FWVideoShoppingModule(
232
261
  }
233
262
 
234
263
  private fun productListener() {
235
- FireworkSdk.shopping.setOnProductActionListener(object : Shopping.OnProductActionListener {
264
+ FireworkSdk.shopping.setOnProductHydrationListener(object : Shopping.OnProductHydrationListener {
236
265
  override fun onProductHydration(products: List<Product>, hydrator: ProductHydrator) {
237
266
  FWLogUtils.d { "FWVideoShoppingModule hydrateProducts, hydrator: ${hydrator.hashCode()}" }
238
267
  if (products.isEmpty()) {
@@ -243,8 +272,10 @@ class FWVideoShoppingModule(
243
272
  updateProductHydratorHandler[callbackId] = hydrator
244
273
  FWEventUtils.sendUpdateProductsDetailsEvent(reactApplicationContext, products, callbackId)
245
274
  }
275
+ })
246
276
 
247
- override fun onDisplayProductInfo(
277
+ FireworkSdk.shopping.setOnProductLinkClickListener(object : Shopping.OnProductLinkClickListener {
278
+ override fun onProductLinkClick(
248
279
  productId: String,
249
280
  unitId: String,
250
281
  productWebUrl: String?
@@ -135,12 +135,13 @@ object FWEventUtils {
135
135
  sendEvent(reactContext, FWEventName.VideoPlayback.rawValue, eventMap)
136
136
  }
137
137
 
138
- fun sendAddToCartClickEvent(reactContext: ReactContext, productId: String?, unitId: String?, callbackId: Int?) {
138
+ fun sendShoppingCtaButtonClickEvent(reactContext: ReactContext, productId: String?, unitId: String?, url: String?, callbackId: Int?) {
139
139
  val eventMap = Arguments.createMap()
140
140
  eventMap.putString("productId", productId)
141
141
  eventMap.putString("unitId", unitId)
142
+ eventMap.putString("url", url)
142
143
  eventMap.putInt("callbackId", callbackId?:0)
143
- sendEvent(reactContext, FWVideoShoppingEventName.AddToCart.rawValue, eventMap)
144
+ sendEvent(reactContext, FWVideoShoppingEventName.CtaButtonClick.rawValue, eventMap)
144
145
  }
145
146
 
146
147
  fun sendCartIconClickEvent(reactContext: ReactContext, callbackId: Int?) {
@@ -205,6 +206,12 @@ object FWEventUtils {
205
206
  receiveEvent(reactContext, targetTag, FWStoryBlockEventName.StoryBlockLoadFinished.rawValue, eventMap)
206
207
  }
207
208
 
209
+ fun receiveStoryBlockFullScreenStateChangedEvent(reactContext: ReactContext, targetTag: Int, isFullScreen: Boolean) {
210
+ val eventMap = Arguments.createMap()
211
+ eventMap.putBoolean("isFullScreen", isFullScreen)
212
+ receiveEvent(reactContext, targetTag, FWStoryBlockEventName.StoryBlockFullScreenStateChanged.rawValue, eventMap)
213
+ }
214
+
208
215
  private fun receiveEvent(reactContext: ReactContext, targetTag: Int, eventName: String, event: WritableMap?) {
209
216
  reactContext.getJSModule(RCTEventEmitter::class.java).receiveEvent(
210
217
  targetTag,
@@ -324,7 +324,7 @@ object FWConfigUtil {
324
324
 
325
325
  return AdBadgeOption.Builder()
326
326
  // .adBadgeBackColor(Color.parseColor("#FF6200EE"))
327
- .adBadgeTextColor(Color.parseColor("#FFFFFFFF"))
327
+ // .adBadgeTextColor(Color.parseColor("#FFFFFFFF"))
328
328
  .adBadgeLabel(AdBadgeTextType.SPONSORED)
329
329
  .adBadgeIsHidden(false)
330
330
  .adBadgeShowOnThumbnails(false)
@@ -1,6 +1,8 @@
1
1
  package com.fireworksdk.bridge.utils
2
2
 
3
+ import com.fireworksdk.bridge.components.videofeed.StoryBlockFragment
3
4
  import com.fireworksdk.bridge.models.FWAdBadgeConfigModel
5
+ import com.fireworksdk.bridge.models.weakProperty
4
6
 
5
7
  object FWGlobalDataUtil {
6
8
 
@@ -11,4 +13,6 @@ object FWGlobalDataUtil {
11
13
  var videoPlaybackEventEnabled: Boolean = false
12
14
 
13
15
  var customClickLinkButtonEnabled: Boolean = false
16
+
17
+ var storyBlockFragment by weakProperty<StoryBlockFragment?>()
14
18
  }
@@ -10,40 +10,66 @@ object FWLanguageUtil {
10
10
  private const val LOCALE_SP = "fw_locale_sp"
11
11
  private const val LOCALE_KEY = "fw_locale_key"
12
12
 
13
- private fun init(context: Context) {
13
+ private var systemLocale: Locale? = null
14
+
15
+ private fun readLocaleFromSp(context: Context) {
14
16
  locale = context.getSharedPreferences(LOCALE_SP, Context.MODE_PRIVATE)
15
17
  .getString(LOCALE_KEY, null)
16
18
  }
17
19
 
18
20
  fun changeLanguage(context: Context, l: String?): Boolean {
19
- if (l.isNullOrBlank() || !isValidLocale(l)) {
21
+ readLocaleFromSp(context)
22
+ val sharedPreferences =
23
+ context.getSharedPreferences(LOCALE_SP, Context.MODE_PRIVATE)
24
+ if (l.isNullOrBlank()) {
25
+ if (locale.isNullOrBlank()) {
26
+ return true
27
+ }
28
+
29
+ locale = null
30
+ sharedPreferences.edit().apply {
31
+ remove(LOCALE_KEY)
32
+ }.commit()
33
+
34
+ // change sdk locale to system locale
35
+ // val sysLocale = getSystemLocale()
36
+ // if (sysLocale.country.isNullOrBlank()) {
37
+ // FwSDK.changeAppLocale(context, sysLocale.language)
38
+ // } else {
39
+ // FwSDK.changeAppLocale(context, "${sysLocale.language}-${sysLocale.country}")
40
+ // }
41
+
42
+ restartActivity(context)
43
+ return true
44
+ }
45
+
46
+ if (!isValidLocale(l)) {
20
47
  return false
21
48
  }
22
49
 
23
- if (isSame(context, l)) {
50
+ if (locale == l) {
24
51
  return true
25
52
  }
26
53
 
27
54
  locale = l
28
55
 
29
56
  // save to sp
30
- val sharedPreferences =
31
- context.getSharedPreferences(LOCALE_SP, Context.MODE_PRIVATE)
32
57
  sharedPreferences.edit().apply {
33
58
  putString(LOCALE_KEY, l)
34
59
  }.apply()
35
60
 
36
- if (context is Activity) {
37
- context.recreate()
38
- }
61
+ restartActivity(context)
39
62
 
40
63
  return true
41
64
  }
42
65
 
43
- fun updateBaseContextLocale(context: Context?): Context? {
44
- context ?: return null
66
+ fun updateBaseContextLocale(context: Context): Context {
67
+ if (systemLocale == null) {
68
+ systemLocale = Locale.getDefault()
69
+ }
70
+
45
71
  if (locale.isNullOrBlank()) {
46
- init(context)
72
+ readLocaleFromSp(context)
47
73
  }
48
74
  locale?.let {
49
75
  val locale = getLocale(it)
@@ -51,7 +77,10 @@ object FWLanguageUtil {
51
77
 
52
78
  return updateResourcesLocale(context, locale)
53
79
  }
54
- return context
80
+
81
+ val l = getSystemLocale()
82
+ Locale.setDefault(l)
83
+ return updateResourcesLocale(context, l)
55
84
  }
56
85
 
57
86
  private fun updateResourcesLocale(context: Context, locale: Locale): Context {
@@ -78,11 +107,14 @@ object FWLanguageUtil {
78
107
  return Locale(locale)
79
108
  }
80
109
 
81
- private fun isSame(context: Context, l: String?) : Boolean {
82
- if (locale.isNullOrBlank()) {
83
- init(context)
110
+ private fun restartActivity(context: Context) {
111
+ if (context is Activity) {
112
+ context.recreate()
84
113
  }
85
- return locale.equals(l)
114
+ }
115
+
116
+ private fun getSystemLocale(): Locale {
117
+ return systemLocale ?: Locale.getDefault()
86
118
  }
87
119
 
88
120
  }
@@ -0,0 +1,24 @@
1
+ <?xml version="1.0" encoding="utf-8"?>
2
+ <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
3
+ xmlns:app="http://schemas.android.com/apk/res-auto"
4
+ android:layout_width="match_parent"
5
+ android:layout_height="match_parent"
6
+ android:layout_gravity="center"
7
+ android:layout_marginVertical="16dp">
8
+
9
+ <FrameLayout
10
+ android:id="@+id/story_block_container"
11
+ android:layout_width="0dp"
12
+ android:layout_height="0dp"
13
+ app:layout_constraintBottom_toBottomOf="parent"
14
+ app:layout_constraintEnd_toEndOf="parent"
15
+ app:layout_constraintStart_toStartOf="parent"
16
+ app:layout_constraintTop_toTopOf="parent">
17
+
18
+ <com.firework.storyblock.FwStoryBlockView
19
+ android:id="@+id/story_block"
20
+ android:layout_width="match_parent"
21
+ android:layout_height="match_parent" />
22
+
23
+ </FrameLayout>
24
+ </androidx.constraintlayout.widget.ConstraintLayout>
@@ -25,6 +25,7 @@ public class StoryBlock: UIView, StoryBlockViewControllerDelegate {
25
25
  @objc public var playlist: String = ""
26
26
  @objc public var dynamicContentParameters: [String: [String]] = [:]
27
27
  @objc public var enablePictureInPicture: Bool = false
28
+ @objc public var adConfiguration: AdConfiguration?
28
29
 
29
30
  public weak var delegate: StoryBlockViewDelegate?
30
31
 
@@ -61,18 +62,32 @@ public class StoryBlock: UIView, StoryBlockViewControllerDelegate {
61
62
  }
62
63
 
63
64
  private func embed() {
64
- guard let parentVC = parentViewController else {
65
+ guard let parentVC = fwParentViewController else {
65
66
  return
66
67
  }
67
68
  guard self.storyBlockVC == nil else {
68
69
  return
69
70
  }
70
71
 
71
- let storyBlockVC = StoryBlockViewController(source: source)
72
+ var resultStoryBlockVC: StoryBlockViewController?
73
+ if let fireworkVideoAdConfiguration = RCTConvert.getFireworkVideoAdConfiguration(adConfiguration) {
74
+ resultStoryBlockVC = StoryBlockViewController(source: source, adConfiguration: fireworkVideoAdConfiguration)
75
+ } else {
76
+ resultStoryBlockVC = StoryBlockViewController(source: source)
77
+ }
78
+
79
+ guard let storyBlockVC = resultStoryBlockVC else {
80
+ return
81
+ }
82
+
72
83
  if self.enablePictureInPicture {
73
84
  storyBlockVC.isPictureInPictureEnabled = true
74
85
  }
75
86
 
87
+ if FWAppLanguageManager.shared.shouldHorizontalFlip {
88
+ storyBlockVC.view.fwrtl_viewType = FWRTLViewTypeFlip
89
+ }
90
+
76
91
  storyBlockVC.delegate = self
77
92
  self.storyBlockVC = storyBlockVC
78
93
  parentVC.attachChild(storyBlockVC, to: self)
@@ -89,6 +104,22 @@ public class StoryBlock: UIView, StoryBlockViewControllerDelegate {
89
104
  self.storyBlockVC = nil
90
105
  }
91
106
 
107
+ @objc
108
+ public func play() {
109
+ guard let storyBlockVC = self.storyBlockVC else {
110
+ return
111
+ }
112
+ storyBlockVC.play()
113
+ }
114
+
115
+ @objc
116
+ public func pause() {
117
+ guard let storyBlockVC = self.storyBlockVC else {
118
+ return
119
+ }
120
+ storyBlockVC.pause()
121
+ }
122
+
92
123
  public func storyBlockDidLoadFeed(_ viewController: StoryBlockViewController) {
93
124
  guard let delegate = self.delegate else {
94
125
  return
@@ -8,7 +8,13 @@
8
8
  #import <React/RCTBridgeModule.h>
9
9
  #import <React/RCTViewManager.h>
10
10
  #import <React/RCTUIManager.h>
11
+
12
+ #if __has_include(<react_native_firework_sdk/react_native_firework_sdk-Swift.h>)
13
+ #import <react_native_firework_sdk/react_native_firework_sdk-Swift.h>
14
+ #else
11
15
  #import "react_native_firework_sdk-Swift.h"
16
+ #endif
17
+
12
18
 
13
19
  @interface RCT_EXTERN_REMAP_MODULE(FWStoryBlock, StoryBlockManager, NSObject)
14
20
 
@@ -23,8 +29,34 @@ RCT_EXPORT_VIEW_PROPERTY(playlist, NSString)
23
29
  RCT_EXPORT_VIEW_PROPERTY(dynamicContentParameters, NSDictionary)
24
30
  RCT_EXPORT_VIEW_PROPERTY(enablePictureInPicture, BOOL)
25
31
 
32
+ RCT_CUSTOM_VIEW_PROPERTY(adConfiguration, AdConfiguration, StoryBlock) {
33
+ AdConfiguration *config = [RCTConvert adConfiguration:json];
34
+ view.adConfiguration = config;
35
+ }
26
36
 
27
37
  RCT_EXPORT_VIEW_PROPERTY(onStoryBlockLoadFinished, RCTBubblingEventBlock)
28
38
 
39
+ RCT_EXPORT_METHOD(play:(nonnull NSNumber *)reactTag) {
40
+ [self.bridge.uiManager addUIBlock:^(RCTUIManager *uiManager, NSDictionary<NSNumber *,UIView *> *viewRegistry) {
41
+ StoryBlock *view = (StoryBlock *)(viewRegistry[reactTag]);
42
+ if (!view || ![view isKindOfClass:[StoryBlock class]]) {
43
+ RCTLogError(@"Cannot find NativeView with tag #%@", reactTag);
44
+ return;
45
+ }
46
+ [view play];
47
+ }];
48
+ }
49
+
50
+ RCT_EXPORT_METHOD(pause:(nonnull NSNumber *)reactTag) {
51
+ [self.bridge.uiManager addUIBlock:^(RCTUIManager *uiManager, NSDictionary<NSNumber *,UIView *> *viewRegistry) {
52
+ StoryBlock *view = (StoryBlock *)(viewRegistry[reactTag]);
53
+ if (!view || ![view isKindOfClass:[StoryBlock class]]) {
54
+ RCTLogError(@"Cannot find NativeView with tag #%@", reactTag);
55
+ return;
56
+ }
57
+ [view pause];
58
+ }];
59
+ }
60
+
29
61
  @end
30
62
 
@@ -130,29 +130,6 @@ public class VideoFeed: UIView, VideoFeedViewControllerDelegate {
130
130
  return resultLayout ?? VideoFeedHorizontalLayout()
131
131
  }
132
132
 
133
- private var fireworkVideoAdConfiguration: FireworkVideo.AdConfiguration? {
134
- guard let feedAdConfiguration = adConfiguration else {
135
- return nil
136
- }
137
-
138
- var resultAdConfiguration = FireworkVideo.AdConfiguration()
139
- if let requiresAds = feedAdConfiguration.requiresAds {
140
- resultAdConfiguration.requiresAds = requiresAds
141
- }
142
-
143
- if let adsFetchTimeout = feedAdConfiguration.adsFetchTimeout {
144
- resultAdConfiguration.adsFetchTimeout = adsFetchTimeout
145
- }
146
-
147
- if let vastAttributes = feedAdConfiguration.vastAttributes {
148
- resultAdConfiguration.vastAttributes = vastAttributes.map({ attribute in
149
- return URLQueryItem(name: attribute.name ?? "", value: attribute.value ?? "")
150
- })
151
- }
152
-
153
- return resultAdConfiguration
154
- }
155
-
156
133
  public override func layoutSubviews() {
157
134
  super.layoutSubviews()
158
135
 
@@ -160,12 +137,15 @@ public class VideoFeed: UIView, VideoFeedViewControllerDelegate {
160
137
  }
161
138
 
162
139
  private func embed() {
163
- guard let parentVC = parentViewController, self.feedVC == nil else {
140
+ guard let parentVC = fwParentViewController else {
141
+ return
142
+ }
143
+ guard self.feedVC == nil else {
164
144
  return
165
145
  }
166
146
 
167
147
  var resultFeedVC: VideoFeedViewController?
168
- if let fireworkVideoAdConfiguration = fireworkVideoAdConfiguration {
148
+ if let fireworkVideoAdConfiguration = RCTConvert.getFireworkVideoAdConfiguration(adConfiguration) {
169
149
  resultFeedVC = VideoFeedViewController(
170
150
  layout: videoFeedLayout,
171
151
  source: source,
@@ -204,12 +184,14 @@ public class VideoFeed: UIView, VideoFeedViewControllerDelegate {
204
184
  feedVC.viewConfiguration = viewConfiguration
205
185
  }
206
186
 
207
- // swiftlint:disable:next notification_center_detachment
208
- NotificationCenter.default.removeObserver(self)
209
187
  if self.enablePictureInPicture || feedViewConfig?.enablePictureInPicture == true {
210
188
  feedVC.isPictureInPictureEnabled = true
211
189
  }
212
190
 
191
+ if FWAppLanguageManager.shared.shouldHorizontalFlip {
192
+ feedVC.view.fwrtl_viewType = FWRTLViewTypeFlip
193
+ }
194
+
213
195
  feedVC.delegate = self
214
196
  self.feedVC = feedVC
215
197
  parentVC.attachChild(feedVC, to: self)
@@ -217,8 +199,6 @@ public class VideoFeed: UIView, VideoFeedViewControllerDelegate {
217
199
 
218
200
  public override func removeFromSuperview() {
219
201
  super.removeFromSuperview()
220
- // swiftlint:disable:next notification_center_detachment
221
- NotificationCenter.default.removeObserver(self)
222
202
 
223
203
  guard let feedVC = self.feedVC else {
224
204
  return