react-native-firework-sdk 2.15.3 → 2.16.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 (24) hide show
  1. package/android/gradle.properties +1 -1
  2. package/android/src/main/java/com/fireworksdk/bridge/components/videofeed/FWVideoFeed.kt +1 -2
  3. package/android/src/main/java/com/fireworksdk/bridge/models/FWShoppingCustomCta.kt +7 -0
  4. package/android/src/main/java/com/fireworksdk/bridge/models/FWVideoFeedConfigModel.kt +1 -0
  5. package/android/src/main/java/com/fireworksdk/bridge/models/FWVideoFeedConfigModelDeserializer.kt +3 -0
  6. package/android/src/main/java/com/fireworksdk/bridge/models/FWVideoFeedConfigModelSerializer.kt +2 -0
  7. package/android/src/main/java/com/fireworksdk/bridge/models/FWVideoPlayerConfigModel.kt +1 -0
  8. package/android/src/main/java/com/fireworksdk/bridge/models/FWVideoPlayerConfigModelDeserializer.kt +5 -1
  9. package/android/src/main/java/com/fireworksdk/bridge/models/FWVideoPlayerConfigModelSerializer.kt +2 -0
  10. package/android/src/main/java/com/fireworksdk/bridge/models/enums/FWEventName.kt +1 -0
  11. package/android/src/main/java/com/fireworksdk/bridge/reactnative/module/FWVideoShoppingModule.kt +10 -2
  12. package/android/src/main/java/com/fireworksdk/bridge/reactnative/utils/FWEventUtils.kt +20 -1
  13. package/android/src/main/java/com/fireworksdk/bridge/utils/FWConfigUtil.kt +7 -0
  14. package/android/src/main/java/com/fireworksdk/bridge/utils/FWModelUtils.kt +18 -1
  15. package/ios/Components/StoryBlock.swift +1 -1
  16. package/ios/Components/VideoFeed.swift +1 -1
  17. package/ios/Modules/FireworkSDKModule/FireworkSDKModule.swift +1 -0
  18. package/ios/Modules/Shopping/ShoppingModule.swift +12 -0
  19. package/lib/typescript/models/FWEvents.d.ts +18 -0
  20. package/lib/typescript/models/VideoPlayerConfiguration.d.ts +0 -1
  21. package/package.json +1 -1
  22. package/react-native-firework-sdk.podspec +2 -2
  23. package/src/models/FWEvents.ts +22 -0
  24. package/src/models/VideoPlayerConfiguration.ts +0 -1
@@ -6,4 +6,4 @@ FireworkSDK_minSdkVersion=21
6
6
  FireworkSDK_compileSdkVersion=33
7
7
  FireworkSDK_targetSdkVersion=33
8
8
  FireworkSDK_fwPlayerLaunchMode=singleTask
9
- FireworkSDK_fwNativeVersion=6.16.5
9
+ FireworkSDK_fwNativeVersion=6.18.11
@@ -2,7 +2,6 @@ package com.fireworksdk.bridge.components.videofeed
2
2
 
3
3
  import android.content.Context
4
4
  import android.util.AttributeSet
5
- import android.view.ViewGroup
6
5
  import android.widget.FrameLayout
7
6
  import com.firework.error.FwErrorListener
8
7
  import com.firework.videofeed.FeedViewStateListener
@@ -29,7 +28,7 @@ class FWVideoFeed(
29
28
  init {
30
29
  FWLanguageUtil.getInstance(context).updateBaseContextLocale(context)
31
30
  videoFeedView.layoutDirection = LAYOUT_DIRECTION_LOCALE
32
- addView(videoFeedView, LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT))
31
+ addView(videoFeedView, LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT))
33
32
  }
34
33
 
35
34
  fun setVideoFeedLayoutParams(l: LayoutParams?) {
@@ -0,0 +1,7 @@
1
+ package com.fireworksdk.bridge.models
2
+
3
+ data class FWShoppingCustomCta(
4
+ val url: String,
5
+ val titleKey: String,
6
+ val title: String,
7
+ )
@@ -12,6 +12,7 @@ data class FWVideoFeedConfigModel(
12
12
  val enableAutoplay: Boolean? = null,
13
13
  val gridColumns: Int? = null,
14
14
  val itemSpacing: Int? = null,
15
+ val aspectRatio: Double? = null,
15
16
  ) {
16
17
 
17
18
  data class FWTitleModel(
@@ -7,6 +7,7 @@ object FWVideoFeedConfigModelDeserializer {
7
7
 
8
8
  private const val BACKGROUND_COLOR_KEY = "backgroundColor"
9
9
  private const val CORNER_RADIUS_KEY = "cornerRadius"
10
+ private const val ASPECT_RATIO_KEY = "aspectRatio"
10
11
  private const val TITLE_KEY = "title"
11
12
  private const val TITLE_POSITION_KEY = "titlePosition"
12
13
  private const val PLAY_ICON_KEY = "playIcon"
@@ -29,6 +30,7 @@ object FWVideoFeedConfigModelDeserializer {
29
30
 
30
31
  val backgroundColor = if (responseJson.has(BACKGROUND_COLOR_KEY)) responseJson.optString(BACKGROUND_COLOR_KEY) else null
31
32
  val cornerRadius = if (!responseJson.isNull(CORNER_RADIUS_KEY)) responseJson.optInt(CORNER_RADIUS_KEY) else null
33
+ val aspectRatio = if (!responseJson.isNull(ASPECT_RATIO_KEY)) responseJson.optDouble(ASPECT_RATIO_KEY) else null
32
34
  val title = if (responseJson.has(TITLE_KEY)) deserializeTitle(responseJson.optJSONObject(TITLE_KEY)) else null
33
35
  val titlePosition = if (responseJson.has(TITLE_POSITION_KEY)) responseJson.optString(TITLE_POSITION_KEY) else null
34
36
  val playIcon = if (responseJson.has(PLAY_ICON_KEY)) deserializePlayIcon(responseJson.optJSONObject(PLAY_ICON_KEY)) else null
@@ -47,6 +49,7 @@ object FWVideoFeedConfigModelDeserializer {
47
49
  enableAutoplay = enableAutoplay,
48
50
  gridColumns = gridColumns,
49
51
  itemSpacing = itemSpacing,
52
+ aspectRatio = aspectRatio,
50
53
  )
51
54
  }
52
55
 
@@ -7,6 +7,7 @@ object FWVideoFeedConfigModelSerializer {
7
7
 
8
8
  private const val BACKGROUND_COLOR_KEY = "backgroundColor"
9
9
  private const val CORNER_RADIUS_KEY = "cornerRadius"
10
+ private const val ASPECT_RATIO_KEY = "aspectRatio"
10
11
  private const val TITLE_KEY = "title"
11
12
  private const val TITLE_POSITION_KEY = "titlePosition"
12
13
  private const val PLAY_ICON_KEY = "playIcon"
@@ -29,6 +30,7 @@ object FWVideoFeedConfigModelSerializer {
29
30
  val jsonObject = JSONObject()
30
31
  jsonObject.put(BACKGROUND_COLOR_KEY, model.backgroundColor)
31
32
  jsonObject.put(CORNER_RADIUS_KEY, model.cornerRadius)
33
+ jsonObject.put(ASPECT_RATIO_KEY, model.aspectRatio)
32
34
  jsonObject.put(TITLE_KEY, serializeTitle(model.title))
33
35
  jsonObject.put(TITLE_POSITION_KEY, FWVideoFeedTitlePosition.serialize(model.titlePosition))
34
36
  jsonObject.put(PLAY_ICON_KEY, serializePlayIcon(model.playIcon))
@@ -27,6 +27,7 @@ data class FWVideoPlayerConfigModel(
27
27
  val showFullScreenIcon: Boolean? = null,
28
28
  val enableAutoPlay: Boolean? = null,
29
29
  val enableAutoPause: Boolean? = null,
30
+ val enableSmallSizeInCompact: Boolean? = null
30
31
  ) {
31
32
 
32
33
  data class FWCtaButtonStyleModel(
@@ -38,6 +38,7 @@ object FWVideoPlayerConfigModelDeserializer {
38
38
  private const val SHOW_FULL_SCREEN_ICON = "enableFullScreen"
39
39
  private const val ENABLE_AUTOPLAY = "enableAutoplay"
40
40
  private const val ENABLE_AUTOPAUSE = "enableAutopause"
41
+ private const val ENABLE_SMALL_SIZE_IN_COMPACT = "enableSmallSizeInCompact"
41
42
 
42
43
  fun deserialize(responseJson: JSONObject?): FWVideoPlayerConfigModel? {
43
44
  responseJson ?: return null
@@ -66,6 +67,8 @@ object FWVideoPlayerConfigModelDeserializer {
66
67
  if (responseJson.has(ENABLE_AUTOPLAY)) responseJson.optBoolean(ENABLE_AUTOPLAY) else null
67
68
  val enableAutoPause =
68
69
  if (responseJson.has(ENABLE_AUTOPAUSE)) responseJson.optBoolean(ENABLE_AUTOPAUSE) else null
70
+ val enableSmallSizeInCompact =
71
+ if (responseJson.has(ENABLE_SMALL_SIZE_IN_COMPACT)) responseJson.optBoolean(ENABLE_SMALL_SIZE_IN_COMPACT) else null
69
72
 
70
73
  return FWVideoPlayerConfigModel(
71
74
  playerStyle = if (!playerStyle.isNullOrBlank()) FWPlayerStyle.deserialize(playerStyle) else null,
@@ -88,7 +91,8 @@ object FWVideoPlayerConfigModelDeserializer {
88
91
  cancelButtonStyle = FWActionButtonDeserializer.deserialize(cancelButtonStyleJsonObject),
89
92
  showFullScreenIcon = showFullScreenIcon,
90
93
  enableAutoPlay = enableAutoPlay,
91
- enableAutoPause = enableAutoPause
94
+ enableAutoPause = enableAutoPause,
95
+ enableSmallSizeInCompact = enableSmallSizeInCompact
92
96
  )
93
97
  }
94
98
 
@@ -38,6 +38,7 @@ object FWVideoPlayerConfigModelSerializer {
38
38
  private const val SHOW_FULL_SCREEN_ICON = "enableFullScreen"
39
39
  private const val ENABLE_AUTOPLAY = "enableAutoplay"
40
40
  private const val ENABLE_AUTOPAUSE = "enableAutopause"
41
+ private const val ENABLE_SMALL_SIZE_IN_COMPACT = "enableSmallSizeInCompact"
41
42
 
42
43
 
43
44
  fun serialize(model: FWVideoPlayerConfigModel?): JSONObject? {
@@ -64,6 +65,7 @@ object FWVideoPlayerConfigModelSerializer {
64
65
  jsonObject.put(SHOW_FULL_SCREEN_ICON, model.showFullScreenIcon)
65
66
  jsonObject.put(ENABLE_AUTOPLAY, model.enableAutoPlay)
66
67
  jsonObject.put(ENABLE_AUTOPAUSE, model.enableAutoPause)
68
+ jsonObject.put(ENABLE_SMALL_SIZE_IN_COMPACT, model.enableSmallSizeInCompact)
67
69
  return jsonObject
68
70
  }
69
71
 
@@ -7,6 +7,7 @@ enum class FWEventName(val rawValue: String) {
7
7
  VideoFeedClick("fw:video-feed-click"),
8
8
  LiveStream("fw:livestream"),
9
9
  LiveStreamChat("fw:livestream-chat"),
10
+ LiveStreamLinkInteractionClick("fw:livestream:custom-link-interaction-click"),
10
11
  LogMessage("fw:log-message"),
11
12
  CustomShareURL("fw:custom-share-url")
12
13
  }
@@ -289,8 +289,16 @@ class FWVideoShoppingModule(
289
289
  ctaHandler = Triple(callbackId, productId, unitId)
290
290
 
291
291
  val videoPlaybackDetails = FWModelUtils.convertVideoInfo2PlaybackDetails(videoInfo)
292
-
293
- FWEventUtils.sendShoppingCtaButtonClickEvent(reactApplicationContext, productId, unitId, productWebUrl, videoPlaybackDetails, callbackId)
292
+ val customCtaDetails = FWModelUtils.convertVideoInfo2CustomCta(product)
293
+
294
+ FWEventUtils.sendShoppingCtaButtonClickEvent(
295
+ reactContext = reactApplicationContext,
296
+ productId = productId,
297
+ unitId = unitId,
298
+ url = productWebUrl,
299
+ info = videoPlaybackDetails,
300
+ customCta = customCtaDetails,
301
+ callbackId = callbackId)
294
302
  }
295
303
 
296
304
  FireworkSdk.shopping.setOnShoppingErrorListener(
@@ -90,6 +90,14 @@ object FWEventUtils {
90
90
  return contentMap
91
91
  }
92
92
 
93
+ private fun convertCustomCta2Map(info: FWShoppingCustomCta): WritableMap {
94
+ val contentMap = Arguments.createMap()
95
+ contentMap.putString("url", info.url)
96
+ contentMap.putString("titleKey", info.titleKey)
97
+ contentMap.putString("title", info.title)
98
+ return contentMap
99
+ }
100
+
93
101
  private fun convertVideoPlaybackDetails2Map(info: FWVideoPlaybackDetails?): WritableMap {
94
102
  val contentMap = Arguments.createMap()
95
103
  if (!info?.id.isNullOrBlank()) {
@@ -129,13 +137,24 @@ object FWEventUtils {
129
137
  return contentMap;
130
138
  }
131
139
 
132
- fun sendShoppingCtaButtonClickEvent(reactContext: ReactContext, productId: String?, unitId: String?, url: String?, info: FWVideoPlaybackDetails?, callbackId: Int?) {
140
+ fun sendShoppingCtaButtonClickEvent(
141
+ reactContext: ReactContext,
142
+ productId: String?,
143
+ unitId: String?,
144
+ url: String?,
145
+ info: FWVideoPlaybackDetails?,
146
+ customCta: FWShoppingCustomCta?,
147
+ callbackId: Int?
148
+ ) {
133
149
  val eventMap = Arguments.createMap()
134
150
  eventMap.putString("productId", productId)
135
151
  eventMap.putString("unitId", unitId)
136
152
  eventMap.putString("url", url)
137
153
  eventMap.putInt("callbackId", callbackId?:0)
138
154
  eventMap.putMap("video", convertVideoPlaybackDetails2Map(info))
155
+ customCta?.let {
156
+ eventMap.putMap("customCTA", convertCustomCta2Map(it))
157
+ }
139
158
  sendEvent(reactContext, FWVideoShoppingEventName.CtaButtonClick.rawValue, eventMap)
140
159
  }
141
160
 
@@ -151,6 +151,11 @@ object FWConfigUtil {
151
151
  .roundedCornerRadius(FWCommonUtil.dpToPx(cornerRadius.toFloat(), context))
152
152
  }
153
153
 
154
+ val aspectRatio = videoFeedPropsModel.videoFeedConfiguration?.aspectRatio
155
+ if (aspectRatio != null && aspectRatio > 0) {
156
+ layoutOptionBuilder.aspectRatio(aspectRatio)
157
+ }
158
+
154
159
  val title = videoFeedPropsModel.videoFeedConfiguration?.title
155
160
  if (title != null) {
156
161
  val titleHidden = title.hidden
@@ -563,6 +568,8 @@ object FWConfigUtil {
563
568
  storyblockOptionBuilder.showFullScreenIcon(showFullScreenIcon)}
564
569
  videoFeedPropsModel.videoPlayerConfiguration?.enableAutoPause?.let { enableAutoPause ->
565
570
  storyblockOptionBuilder.enableAutoPause(enableAutoPause)}
571
+ videoFeedPropsModel.videoPlayerConfiguration?.enableSmallSizeInCompact?.let { enableSmallSizeInCompact ->
572
+ storyblockOptionBuilder.enableSmallSizeInCompact(enableSmallSizeInCompact)}
566
573
 
567
574
  playerOptionBuilder.shareUrlCustomCallBack(FWGlobalDataUtil.customShareUrlCallback)
568
575
 
@@ -5,7 +5,9 @@ import com.firework.analyticsevents.VideoType
5
5
  import com.firework.analyticsevents.cta.CtaButtonClickAnalyticsEvent
6
6
  import com.firework.analyticsevents.player.PlayerLifecycleAnalyticsEvent
7
7
  import com.firework.analyticsevents.share.ShareButtonAnalyticsEvent
8
+ import com.firework.common.product.Product
8
9
  import com.fireworksdk.bridge.models.FWLiveStreamEventDetailsModel
10
+ import com.fireworksdk.bridge.models.FWShoppingCustomCta
9
11
  import com.fireworksdk.bridge.models.FWVideoPlaybackDetails
10
12
 
11
13
  object FWModelUtils {
@@ -45,6 +47,21 @@ object FWModelUtils {
45
47
  )
46
48
  }
47
49
 
50
+ fun convertVideoInfo2CustomCta(product: Product?): FWShoppingCustomCta? {
51
+ val url = product?.customCTAUrl
52
+ val title = product?.customCTATitleTranslation
53
+ val titleKey = product?.customCTATitle
54
+ return if (!url.isNullOrBlank() && !titleKey.isNullOrBlank() && !title.isNullOrBlank() && product.isCustomCtaPrimary) {
55
+ FWShoppingCustomCta(
56
+ url = url,
57
+ titleKey = titleKey,
58
+ title = title,
59
+ )
60
+ } else {
61
+ null
62
+ }
63
+ }
64
+
48
65
  fun convertVideoInfo2LivestreamDetails(videoInfo: VideoInfo): FWLiveStreamEventDetailsModel {
49
66
  return FWLiveStreamEventDetailsModel(
50
67
  id = videoInfo.id,
@@ -101,4 +118,4 @@ object FWModelUtils {
101
118
  )
102
119
  }
103
120
 
104
- }
121
+ }
@@ -79,7 +79,7 @@ public class StoryBlock: UIView, StoryBlockViewControllerDelegate, PictureInPict
79
79
  case .sku:
80
80
  return .skuPlaylist(channelID: channel, productIDs: (productIds as? [String]) ?? [])
81
81
  case .singleContent:
82
- return .singleContent(videoOrLiveStreamID: contentId)
82
+ return .singleContent(contentID: contentId)
83
83
  }
84
84
  }
85
85
  private var isInPip: Bool = false
@@ -105,7 +105,7 @@ public class VideoFeed: UIView, VideoFeedViewControllerDelegate, PictureInPictur
105
105
  case .sku:
106
106
  return .skuPlaylist(channelID: channel, productIDs: (productIds as? [String]) ?? [])
107
107
  case .singleContent:
108
- return .singleContent(videoOrLiveStreamID: contentId)
108
+ return .singleContent(contentID: contentId)
109
109
  }
110
110
  }
111
111
 
@@ -8,6 +8,7 @@
8
8
 
9
9
  import FireworkVideo
10
10
  import FireworkVideoUI
11
+ import Network
11
12
 
12
13
  var gShareBaseURL: String?
13
14
  var gAdBadgeConfiguration: AdBadgeConfiguration?
@@ -230,6 +230,18 @@ class ShoppingModule: RCTEventEmitter, FireworkVideoShoppingDelegate {
230
230
  var body = item.jsObject
231
231
  body["callbackId"] = callbackId
232
232
  body["video"] = video.jsObject
233
+ if let product = item.product,
234
+ product.hasCustomPrimaryCTA,
235
+ let customCTA = product.customCTA,
236
+ let url = customCTA.url,
237
+ let title = customCTA.title,
238
+ let titleTranslation = customCTA.titleTranslation {
239
+ body["customCTA"] = [
240
+ "url": url,
241
+ "titleKey": title,
242
+ "title": titleTranslation
243
+ ]
244
+ }
233
245
  sendEvent(
234
246
  withName: ShoppingEventName.ctaButtonClick.rawValue,
235
247
  body: body)
@@ -46,6 +46,20 @@ export interface VideoPlaybackEvent {
46
46
  export interface VideoFeedClickEvent {
47
47
  info: FeedItemDetails;
48
48
  }
49
+ export interface CustomCTA {
50
+ /**
51
+ * Action URL that is associated with this CTA
52
+ */
53
+ url: string;
54
+ /**
55
+ * The title key of the CTA, such as buy_now.
56
+ */
57
+ titleKey: string;
58
+ /**
59
+ * The title of the CTA, such as "Buy Now".
60
+ */
61
+ title: string;
62
+ }
49
63
  export interface ShoppingCTAEvent {
50
64
  /**
51
65
  * The url for the product unit
@@ -63,6 +77,10 @@ export interface ShoppingCTAEvent {
63
77
  * The video playback details for the event.
64
78
  */
65
79
  video: VideoPlaybackDetails;
80
+ /**
81
+ * This property only has value when configuring a custom product primary CTA in the business portal.
82
+ */
83
+ customCTA?: CustomCTA;
66
84
  }
67
85
  export interface UpdateProductDetailsEvent {
68
86
  /**
@@ -81,7 +81,6 @@ export default interface VideoPlayerConfiguration {
81
81
  replayBadgeConfiguration?: ReplayBadgeConfiguration;
82
82
  /**
83
83
  * Specifies countdown timer configuration.
84
- * Only supported on iOS.
85
84
  */
86
85
  countdownTimerConfiguration?: CountdownTimerConfiguration;
87
86
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-native-firework-sdk",
3
- "version": "2.15.3",
3
+ "version": "2.16.0",
4
4
  "description": "Firework React Native SDK",
5
5
  "main": "lib/commonjs/index",
6
6
  "module": "lib/module/index",
@@ -33,6 +33,6 @@ fi
33
33
  s.static_framework = true
34
34
 
35
35
  s.dependency 'React-Core'
36
- s.dependency 'FireworkVideoUI', '0.2.14'
37
- s.dependency 'FireworkVideo', '1.28.3'
36
+ s.dependency 'FireworkVideoUI', '0.2.15'
37
+ s.dependency 'FireworkVideo', '1.30.0'
38
38
  end
@@ -55,6 +55,23 @@ export interface VideoFeedClickEvent {
55
55
  info: FeedItemDetails;
56
56
  }
57
57
 
58
+ export interface CustomCTA {
59
+ /**
60
+ * Action URL that is associated with this CTA
61
+ */
62
+ url: string;
63
+
64
+ /**
65
+ * The title key of the CTA, such as buy_now.
66
+ */
67
+ titleKey: string;
68
+
69
+ /**
70
+ * The title of the CTA, such as "Buy Now".
71
+ */
72
+ title: string;
73
+ }
74
+
58
75
  export interface ShoppingCTAEvent {
59
76
  /**
60
77
  * The url for the product unit
@@ -72,6 +89,11 @@ export interface ShoppingCTAEvent {
72
89
  * The video playback details for the event.
73
90
  */
74
91
  video: VideoPlaybackDetails;
92
+
93
+ /**
94
+ * This property only has value when configuring a custom product primary CTA in the business portal.
95
+ */
96
+ customCTA?: CustomCTA;
75
97
  }
76
98
 
77
99
  export interface UpdateProductDetailsEvent {
@@ -82,7 +82,6 @@ export default interface VideoPlayerConfiguration {
82
82
  replayBadgeConfiguration?: ReplayBadgeConfiguration;
83
83
  /**
84
84
  * Specifies countdown timer configuration.
85
- * Only supported on iOS.
86
85
  */
87
86
  countdownTimerConfiguration?: CountdownTimerConfiguration;
88
87
  }