react-native-firework-sdk 2.12.1 → 2.14.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 (117) hide show
  1. package/android/.idea/codeStyles/Project.xml +124 -0
  2. package/android/.idea/codeStyles/codeStyleConfig.xml +5 -0
  3. package/android/build.gradle +3 -2
  4. package/android/gradle.properties +4 -3
  5. package/android/src/main/AndroidManifest.xml +14 -0
  6. package/android/src/main/java/com/fireworksdk/bridge/FWInitializationProvider.kt +4 -0
  7. package/android/src/main/java/com/fireworksdk/bridge/components/storyblock/StoryBlockFragment.kt +1 -2
  8. package/android/src/main/java/com/fireworksdk/bridge/models/FWLiveStreamEventDetailsModel.kt +1 -0
  9. package/android/src/main/java/com/fireworksdk/bridge/models/FWVideoFeedConfigModel.kt +1 -0
  10. package/android/src/main/java/com/fireworksdk/bridge/models/FWVideoFeedConfigModelDeserializer.kt +3 -0
  11. package/android/src/main/java/com/fireworksdk/bridge/models/FWVideoFeedConfigModelSerializer.kt +2 -0
  12. package/android/src/main/java/com/fireworksdk/bridge/models/FWVideoPlayerLogoConfigurationModel.kt +1 -0
  13. package/android/src/main/java/com/fireworksdk/bridge/models/FWVideoPlayerLogoConfigurationModelDeserializer.kt +3 -0
  14. package/android/src/main/java/com/fireworksdk/bridge/models/FWVideoPlayerLogoConfigurationModelSerializer.kt +2 -0
  15. package/android/src/main/java/com/fireworksdk/bridge/models/enums/FWDataTrackingLevel.kt +7 -0
  16. package/android/src/main/java/com/fireworksdk/bridge/models/enums/FWEventName.kt +2 -1
  17. package/android/src/main/java/com/fireworksdk/bridge/models/enums/FWSwitchLanguageBehavior.kt +6 -0
  18. package/android/src/main/java/com/fireworksdk/bridge/reactnative/FWReactNativeSDK.kt +19 -7
  19. package/android/src/main/java/com/fireworksdk/bridge/reactnative/models/FWNavigatorInterface.kt +2 -0
  20. package/android/src/main/java/com/fireworksdk/bridge/reactnative/models/FireworkSDKInterface.kt +1 -0
  21. package/android/src/main/java/com/fireworksdk/bridge/reactnative/module/FWLiveStreamModule.kt +6 -4
  22. package/android/src/main/java/com/fireworksdk/bridge/reactnative/module/FWNavigatorModule.kt +26 -0
  23. package/android/src/main/java/com/fireworksdk/bridge/reactnative/module/FWVideoShoppingModule.kt +29 -19
  24. package/android/src/main/java/com/fireworksdk/bridge/reactnative/module/FireworkSDKModule.kt +43 -19
  25. package/android/src/main/java/com/fireworksdk/bridge/reactnative/utils/FWEventUtils.kt +25 -13
  26. package/android/src/main/java/com/fireworksdk/bridge/utils/FWConfigUtil.kt +25 -2
  27. package/android/src/main/java/com/fireworksdk/bridge/utils/FWGlobalDataUtil.kt +5 -0
  28. package/android/src/main/java/com/fireworksdk/bridge/utils/FWLanguageUtil.kt +57 -15
  29. package/android/src/main/java/com/fireworksdk/bridge/utils/FWModelUtils.kt +16 -8
  30. package/ios/Components/StoryBlock.swift +5 -8
  31. package/ios/Components/VideoFeed.swift +1 -5
  32. package/ios/FireworkSdk.xcodeproj/project.pbxproj +4 -0
  33. package/ios/Models/NativeToRN/FireworkEventName.swift +1 -0
  34. package/ios/Models/NativeToRN/FireworkSDK+Json.swift +6 -2
  35. package/ios/Models/RNToNative/RCTConvert+FireworkSDKModule.swift +13 -0
  36. package/ios/Modules/FireworkSDKModule/FireworkSDKModule+CTA.swift +8 -16
  37. package/ios/Modules/FireworkSDKModule/FireworkSDKModule+EventTracking.swift +9 -1
  38. package/ios/Modules/FireworkSDKModule/FireworkSDKModule.m +1 -0
  39. package/ios/Modules/FireworkSDKModule/FireworkSDKModule.swift +96 -31
  40. package/ios/Modules/Shopping/ShoppingModule.swift +12 -3
  41. package/ios/Utils/Extensions/NumberFormatter+AppLanguage.swift +27 -0
  42. package/lib/commonjs/FireworkSDK.js +66 -12
  43. package/lib/commonjs/FireworkSDK.js.map +1 -1
  44. package/lib/commonjs/VideoShopping.js +15 -0
  45. package/lib/commonjs/VideoShopping.js.map +1 -1
  46. package/lib/commonjs/components/StoryBlock.js +6 -0
  47. package/lib/commonjs/components/StoryBlock.js.map +1 -1
  48. package/lib/commonjs/components/VideoFeed.js +29 -12
  49. package/lib/commonjs/components/VideoFeed.js.map +1 -1
  50. package/lib/commonjs/index.js +14 -6
  51. package/lib/commonjs/index.js.map +1 -1
  52. package/lib/commonjs/models/DataTrackingLevel.js +2 -0
  53. package/lib/commonjs/models/DataTrackingLevel.js.map +1 -0
  54. package/lib/commonjs/models/FWComponentType.js +14 -0
  55. package/lib/commonjs/models/FWComponentType.js.map +1 -0
  56. package/lib/commonjs/models/FWEventName.js +1 -0
  57. package/lib/commonjs/models/FWEventName.js.map +1 -1
  58. package/lib/commonjs/models/VideoPlayerLivestreamCountdownTimerTheme.js +2 -0
  59. package/lib/commonjs/models/VideoPlayerLivestreamCountdownTimerTheme.js.map +1 -0
  60. package/lib/commonjs/modules/FireworkSDKModule.js.map +1 -1
  61. package/lib/commonjs/utils/FWGlobalState.js +2 -0
  62. package/lib/commonjs/utils/FWGlobalState.js.map +1 -1
  63. package/lib/module/FireworkSDK.js +64 -11
  64. package/lib/module/FireworkSDK.js.map +1 -1
  65. package/lib/module/VideoShopping.js +15 -0
  66. package/lib/module/VideoShopping.js.map +1 -1
  67. package/lib/module/components/StoryBlock.js +5 -0
  68. package/lib/module/components/StoryBlock.js.map +1 -1
  69. package/lib/module/components/VideoFeed.js +28 -11
  70. package/lib/module/components/VideoFeed.js.map +1 -1
  71. package/lib/module/index.js +6 -5
  72. package/lib/module/index.js.map +1 -1
  73. package/lib/module/models/DataTrackingLevel.js +2 -0
  74. package/lib/module/models/DataTrackingLevel.js.map +1 -0
  75. package/lib/module/models/FWComponentType.js +7 -0
  76. package/lib/module/models/FWComponentType.js.map +1 -0
  77. package/lib/module/models/FWEventName.js +1 -0
  78. package/lib/module/models/FWEventName.js.map +1 -1
  79. package/lib/module/models/VideoPlayerLivestreamCountdownTimerTheme.js +2 -0
  80. package/lib/module/models/VideoPlayerLivestreamCountdownTimerTheme.js.map +1 -0
  81. package/lib/module/modules/FireworkSDKModule.js.map +1 -1
  82. package/lib/module/utils/FWGlobalState.js +2 -0
  83. package/lib/module/utils/FWGlobalState.js.map +1 -1
  84. package/lib/typescript/FireworkSDK.d.ts +22 -1
  85. package/lib/typescript/VideoShopping.d.ts +8 -1
  86. package/lib/typescript/index.d.ts +16 -13
  87. package/lib/typescript/models/DataTrackingLevel.d.ts +1 -0
  88. package/lib/typescript/models/FWComponentType.d.ts +4 -0
  89. package/lib/typescript/models/FWEventName.d.ts +2 -1
  90. package/lib/typescript/models/FWEvents.d.ts +18 -1
  91. package/lib/typescript/models/FeedItemDetails.d.ts +0 -1
  92. package/lib/typescript/models/LiveStreamEventDetails.d.ts +1 -0
  93. package/lib/typescript/models/ReplayBadgeConfiguration.d.ts +1 -1
  94. package/lib/typescript/models/StoryBlockConfiguration.d.ts +0 -2
  95. package/lib/typescript/models/VideoFeedConfiguration.d.ts +0 -1
  96. package/lib/typescript/models/VideoPlayerLivestreamCountdownTimerTheme.d.ts +1 -0
  97. package/lib/typescript/modules/FireworkSDKModule.d.ts +2 -0
  98. package/lib/typescript/utils/FWGlobalState.d.ts +2 -0
  99. package/package.json +1 -1
  100. package/react-native-firework-sdk.podspec +4 -3
  101. package/src/FireworkSDK.ts +59 -14
  102. package/src/VideoShopping.ts +24 -0
  103. package/src/components/StoryBlock.tsx +8 -0
  104. package/src/components/VideoFeed.tsx +24 -7
  105. package/src/index.ts +40 -30
  106. package/src/models/DataTrackingLevel.ts +1 -0
  107. package/src/models/FWComponentType.ts +4 -0
  108. package/src/models/FWEventName.ts +1 -0
  109. package/src/models/FWEvents.ts +19 -1
  110. package/src/models/FeedItemDetails.ts +0 -1
  111. package/src/models/LiveStreamEventDetails.ts +1 -0
  112. package/src/models/ReplayBadgeConfiguration.ts +1 -1
  113. package/src/models/StoryBlockConfiguration.ts +0 -2
  114. package/src/models/VideoFeedConfiguration.ts +0 -1
  115. package/src/models/VideoPlayerLivestreamCountdownTimerTheme.ts +1 -0
  116. package/src/modules/FireworkSDKModule.ts +2 -0
  117. package/src/utils/FWGlobalState.ts +3 -0
@@ -13,8 +13,10 @@ import com.firework.analyticsevents.player.PlayerLifecycleAnalyticsEvent
13
13
  import com.firework.analyticsevents.share.ShareButtonAnalyticsEvent
14
14
  import com.firework.bus.FwAnalyticCallable
15
15
  import com.firework.sdk.FireworkSdk
16
+ import com.firework.sdk.FwTrackingLevel
16
17
  import com.fireworksdk.bridge.FWInitializationProvider
17
18
  import com.fireworksdk.bridge.models.*
19
+ import com.fireworksdk.bridge.models.enums.FWDataTrackingLevel
18
20
  import com.fireworksdk.bridge.models.enums.FWVideoPlaybackSubEventName
19
21
  import com.fireworksdk.bridge.reactnative.FWReactNativeSDK
20
22
  import com.fireworksdk.bridge.reactnative.models.FireworkSDKInterface
@@ -29,6 +31,30 @@ class FireworkSDKModule(
29
31
  reactContext: ReactApplicationContext
30
32
  ) : ReactContextBaseJavaModule(reactContext), FireworkSDKInterface {
31
33
 
34
+ init {
35
+ FWGlobalDataUtil.initCompletedListener = {
36
+ initCallback()
37
+ }
38
+ }
39
+
40
+ private fun initCallback(): Boolean {
41
+ val sdkInitResultModel = FWGlobalDataUtil.sdkInitResultModel
42
+ return if (sdkInitResultModel != null) { // init in application
43
+ if (sdkInitResultModel.success == true) {
44
+ FWEventUtils.sendInitSuccessEvent(reactApplicationContext)
45
+ } else if (sdkInitResultModel.success == false) {
46
+ FWEventUtils.sendInitFailedEvent(reactApplicationContext, sdkInitResultModel.reason)
47
+ }
48
+
49
+ FireworkSdk.analytics.register(this)
50
+ true
51
+ } else {
52
+ false
53
+ }
54
+ }
55
+
56
+
57
+
32
58
  /**
33
59
  * Initializes FW SDK
34
60
  *
@@ -63,22 +89,7 @@ class FireworkSDKModule(
63
89
  override fun markInitCalled(promise: Promise) {
64
90
  FWColorUtil.useRgba = true
65
91
  FWGlobalDataUtil.pauseWhenNotVisible = true
66
-
67
- val sdkInitResultModel = FWGlobalDataUtil.sdkInitResultModel
68
- if (sdkInitResultModel != null) { // init in application
69
- if (sdkInitResultModel.success == true) {
70
- FWEventUtils.sendInitSuccessEvent(reactApplicationContext)
71
- } else if (sdkInitResultModel.success == false) {
72
- FWEventUtils.sendInitFailedEvent(reactApplicationContext, sdkInitResultModel.reason)
73
- }
74
-
75
- FireworkSdk.analytics.register(this)
76
- promise.resolve(true)
77
-
78
- return
79
- }
80
-
81
- promise.resolve(false)
92
+ promise.resolve(initCallback())
82
93
  }
83
94
 
84
95
  /**
@@ -186,7 +197,7 @@ class FireworkSDKModule(
186
197
  val videoPlaybackDetails = FWModelUtils.convertPlayerEvent2PlaybackDetails(event)
187
198
  when (event) {
188
199
  is PlayerLifecycleAnalyticsEvent.OnStarted -> {
189
- if (event.videoInfo.isAd) {
200
+ if (event.videoInfo?.isAd == true) {
190
201
  FWEventUtils.sendVideoPlaybackEvent(reactApplicationContext, FWVideoPlaybackSubEventName.AdStart.rawValue, videoPlaybackDetails)
191
202
  } else {
192
203
  FWEventUtils.sendVideoPlaybackEvent(reactApplicationContext, FWVideoPlaybackSubEventName.Start.rawValue, videoPlaybackDetails)
@@ -199,7 +210,7 @@ class FireworkSDKModule(
199
210
  is PlayerLifecycleAnalyticsEvent.OnIdle -> {}
200
211
  is PlayerLifecycleAnalyticsEvent.OnRepeat -> {}
201
212
  is PlayerLifecycleAnalyticsEvent.OnEnded -> {
202
- if (event.videoInfo.isAd) {
213
+ if (event.videoInfo?.isAd == true) {
203
214
  FWEventUtils.sendVideoPlaybackEvent(reactApplicationContext, FWVideoPlaybackSubEventName.AdEnd.rawValue, videoPlaybackDetails)
204
215
  } else {
205
216
  FWEventUtils.sendVideoPlaybackEvent(reactApplicationContext, FWVideoPlaybackSubEventName.Complete.rawValue, videoPlaybackDetails)
@@ -236,7 +247,7 @@ class FireworkSDKModule(
236
247
  return
237
248
  }
238
249
  UiThreadUtil.runOnUiThread {
239
- val result = FWLanguageUtil.getInstance(activity).changeLanguage(language, activity)
250
+ val result = FWReactNativeSDK.changeLanguage(language, activity)
240
251
  promise.resolve(result)
241
252
  }
242
253
  }
@@ -299,6 +310,19 @@ class FireworkSDKModule(
299
310
  }
300
311
  }
301
312
 
313
+ @ReactMethod
314
+ override fun setDataTrackingLevel(level: String?, promise: Promise) {
315
+ val trackingLevel =
316
+ when (level) {
317
+ FWDataTrackingLevel.ALL.rawValue -> FwTrackingLevel.ALL
318
+ FWDataTrackingLevel.NONE.rawValue -> FwTrackingLevel.NONE
319
+ FWDataTrackingLevel.ESSENTIAL_ONLY.rawValue -> FwTrackingLevel.ESSENTIAL_ONLY
320
+ else -> FwTrackingLevel.ALL
321
+ }
322
+ FireworkSdk.setTrackingLevel(trackingLevel)
323
+ promise.resolve(true)
324
+ }
325
+
302
326
  @ReactMethod
303
327
  fun addListener(eventName: String?, promise: Promise) {
304
328
  // Set up any upstream listeners or background tasks as necessary
@@ -18,7 +18,7 @@ import java.util.*
18
18
  object FWEventUtils {
19
19
 
20
20
  fun sendInitSuccessEvent(reactContext: ReactContext) {
21
- sendEvent(reactContext, FWEventName.SDKIni.rawValue, Arguments.createMap())
21
+ sendEvent(reactContext, FWEventName.SDKInit.rawValue, Arguments.createMap())
22
22
  }
23
23
 
24
24
  fun sendInitFailedEvent(reactContext: ReactContext, reason: String?) {
@@ -26,7 +26,7 @@ object FWEventUtils {
26
26
  val contentMap = Arguments.createMap()
27
27
  contentMap.putString(FWSDKInitSubEventName.InitFailed.rawValue, reason?:"unknown")
28
28
  eventMap.putMap("error", contentMap)
29
- sendEvent(reactContext, FWEventName.SDKIni.rawValue, eventMap)
29
+ sendEvent(reactContext, FWEventName.SDKInit.rawValue, eventMap)
30
30
  }
31
31
 
32
32
  fun sendVideoFeedClickEvent(reactContext: ReactContext, info: FWVideoFeedItemDetailsModel) {
@@ -79,6 +79,17 @@ object FWEventUtils {
79
79
  sendEvent(reactContext, FWEventName.VideoPlayback.rawValue, eventMap)
80
80
  }
81
81
 
82
+ private fun convertLiveStreamDetails2Map(info: FWLiveStreamEventDetailsModel?): WritableMap {
83
+ val contentMap = Arguments.createMap()
84
+ if (!info?.id.isNullOrBlank()) {
85
+ contentMap.putString("id", info?.id)
86
+ }
87
+ if (!info?.feedId.isNullOrBlank()) {
88
+ contentMap.putString("feedId", info?.feedId)
89
+ }
90
+ return contentMap
91
+ }
92
+
82
93
  private fun convertVideoPlaybackDetails2Map(info: FWVideoPlaybackDetails?): WritableMap {
83
94
  val contentMap = Arguments.createMap()
84
95
  if (!info?.id.isNullOrBlank()) {
@@ -244,11 +255,7 @@ object FWEventUtils {
244
255
  val eventMap = Arguments.createMap()
245
256
  eventMap.putString("eventName", eventName)
246
257
 
247
- val contentMap = Arguments.createMap()
248
- if (!info?.id.isNullOrBlank()) {
249
- contentMap.putString("id", info?.id)
250
- }
251
- eventMap.putMap("info", contentMap)
258
+ eventMap.putMap("info", convertLiveStreamDetails2Map(info))
252
259
  sendEvent(reactContext, FWEventName.LiveStream.rawValue, eventMap)
253
260
  }
254
261
 
@@ -267,14 +274,10 @@ object FWEventUtils {
267
274
  if (!message?.text.isNullOrBlank()) {
268
275
  chatMap.putString("text", message?.text)
269
276
  }
270
- eventMap.putMap("chat", chatMap)
277
+ eventMap.putMap("message", chatMap)
271
278
 
272
279
  // live stream map
273
- val liveStreamMap = Arguments.createMap()
274
- if (!liveStream?.id.isNullOrBlank()) {
275
- liveStreamMap.putString("id", liveStream?.id)
276
- }
277
- eventMap.putMap("liveStream", liveStreamMap)
280
+ eventMap.putMap("liveStream", convertLiveStreamDetails2Map(liveStream))
278
281
 
279
282
  sendEvent(reactContext, FWEventName.LiveStreamChat.rawValue, eventMap)
280
283
  }
@@ -289,6 +292,15 @@ object FWEventUtils {
289
292
  sendEvent(reactContext, FWVideoShoppingEventName.CustomProductCardTap.rawValue, eventMap)
290
293
  }
291
294
 
295
+ fun sendProductClickEvent(reactContext: ReactContext, url: String?, productId: String?, unitId: String?, info: FWVideoPlaybackDetails?) {
296
+ val eventMap = Arguments.createMap()
297
+ eventMap.putString("url", url?:"")
298
+ eventMap.putString("productId", productId)
299
+ eventMap.putString("unitId", unitId)
300
+ eventMap.putMap("video", convertVideoPlaybackDetails2Map(info))
301
+ sendEvent(reactContext, FWVideoShoppingEventName.ProductClick.rawValue, eventMap)
302
+ }
303
+
292
304
  fun sendCustomLinkButtonClickEvent(reactContext: ReactContext, url: String?, productId: String?, unitId: String?, info: FWVideoPlaybackDetails?, callbackId: Int?) {
293
305
  val eventMap = Arguments.createMap()
294
306
  eventMap.putString("url", url ?: "")
@@ -5,6 +5,7 @@ import android.content.Context
5
5
  import android.graphics.Typeface
6
6
  import android.graphics.drawable.GradientDrawable
7
7
  import com.firework.common.PlayerMode
8
+ import com.firework.common.Theme
8
9
  import com.firework.common.ad.AdBadgeOption
9
10
  import com.firework.common.ad.AdBadgeTextType
10
11
  import com.firework.common.ad.AdOption
@@ -14,6 +15,7 @@ import com.firework.common.feed.FeedLayout
14
15
  import com.firework.common.feed.FeedResource
15
16
  import com.firework.common.feed.FeedTitlePosition
16
17
  import com.firework.common.player.CloseButtonOption
18
+ import com.firework.common.player.LivestreamCountDownOption
17
19
  import com.firework.common.player.MuteButtonOption
18
20
  import com.firework.common.player.PlaybackButtonOption
19
21
  import com.firework.common.player.PlayerUiOption
@@ -22,6 +24,7 @@ import com.firework.common.widget.WidgetImage
22
24
  import com.firework.viewoptions.*
23
25
  import com.fireworksdk.bridge.FWInitializationProvider
24
26
  import com.fireworksdk.bridge.models.*
27
+ import com.fireworksdk.bridge.models.enums.FWAppearanceMode
25
28
  import com.fireworksdk.bridge.models.enums.FWBadgeTextType
26
29
  import com.fireworksdk.bridge.models.enums.FWCtaDelayType
27
30
  import com.fireworksdk.bridge.models.enums.FWGradientDrawableOrientation
@@ -52,6 +55,7 @@ object FWConfigUtil {
52
55
  val adBadgeOptionBuilder = getDefaultAdBadgeOptionBuilder()
53
56
  val ctaOptionBuilder = getDefaultCtaOptionBuilder()
54
57
  val adOptionBuilder = getDefaultAdOptionBuilder()
58
+ val countDownOptionBuilder = getDefaultPlayerCountdownTimerOptionBuilder()
55
59
 
56
60
  when (videoFeedPropsModel.source) {
57
61
  FWVideoFeedSource.Discover -> {
@@ -133,6 +137,7 @@ object FWConfigUtil {
133
137
  val titleHidden = title.hidden
134
138
  val titleTextColor = title.textColor
135
139
  val titleFontSize = title.fontSize
140
+ val titleNumberOfLines = title.numberOfLines
136
141
  val titleBackgroundColor = title.backgroundColor
137
142
  val titleGradientDrawable = title.gradientDrawable
138
143
  val typeface = getTypeface(context, title.fontInfo)
@@ -145,6 +150,9 @@ object FWConfigUtil {
145
150
  if (titleFontSize != null && titleFontSize > 0) {
146
151
  titleOptionBuilder.feedTitleTextSize(FWCommonUtil.spToPx(titleFontSize.toFloat(), context))
147
152
  }
153
+ if (titleNumberOfLines != null && titleNumberOfLines > 0 && titleNumberOfLines < 6) {
154
+ titleOptionBuilder.feedTitleTextNumberOfLines(titleNumberOfLines.toInt())
155
+ }
148
156
  typeface?.let {
149
157
  titleOptionBuilder.feedTitleTextTypeface(it)
150
158
  }
@@ -397,16 +405,27 @@ object FWConfigUtil {
397
405
 
398
406
  val logoConfigOption = videoFeedPropsModel.videoPlayerConfiguration?.videoPlayerLogoConfiguration?.option
399
407
  val logoConfigChannelId = videoFeedPropsModel.videoPlayerConfiguration?.videoPlayerLogoConfiguration?.encodedId
408
+ val isLogoClickable = videoFeedPropsModel.videoPlayerConfiguration?.videoPlayerLogoConfiguration?.isClickable ?: true
400
409
  when {
401
410
  logoConfigOption == FWVideoPlayerLogoOption.Creator && !logoConfigChannelId.isNullOrBlank() -> {
402
- playerOptionBuilder.logoConfig(LogoConfig.Logo.CreatorLogo(logoConfigChannelId))
411
+ playerOptionBuilder.logoConfig(LogoConfig.Logo.CreatorLogo(logoConfigChannelId, isLogoClickable))
403
412
  }
404
413
  logoConfigOption == FWVideoPlayerLogoOption.ChannelAggregator && !logoConfigChannelId.isNullOrBlank() -> {
405
- playerOptionBuilder.logoConfig(LogoConfig.Logo.AggregatorLogo(logoConfigChannelId))
414
+ playerOptionBuilder.logoConfig(LogoConfig.Logo.AggregatorLogo(logoConfigChannelId, isLogoClickable))
406
415
  }
407
416
  else -> {}
408
417
  }
409
418
 
419
+ val countdownTimerAppearance = videoFeedPropsModel.videoPlayerConfiguration?.countdownTimerConfiguration?.appearance
420
+ val isCountdownTimerHidden = videoFeedPropsModel.videoPlayerConfiguration?.countdownTimerConfiguration?.isHidden ?: true
421
+ countDownOptionBuilder.isHidden(isCountdownTimerHidden)
422
+ when (countdownTimerAppearance) {
423
+ FWAppearanceMode.Light -> countDownOptionBuilder.theme(Theme.LIGHT)
424
+ FWAppearanceMode.Dark -> countDownOptionBuilder.theme(Theme.DARK)
425
+ else -> {}
426
+ }
427
+ playerOptionBuilder.livestreamCountDownOption(countDownOptionBuilder.build())
428
+
410
429
  return ViewOptions.Builder()
411
430
  .layoutOption(layoutOptionBuilder.build())
412
431
  .titleOption(titleOptionBuilder.build())
@@ -437,6 +456,10 @@ object FWConfigUtil {
437
456
  return PlayerUiOption.Builder()
438
457
  }
439
458
 
459
+ private fun getDefaultPlayerCountdownTimerOptionBuilder(): LivestreamCountDownOption.Builder {
460
+ return LivestreamCountDownOption.Builder()
461
+ }
462
+
440
463
  private fun getDefaultVideoDetailsOptionBuilder(): VideoDetailsOption.Builder {
441
464
  return VideoDetailsOption.Builder()
442
465
  }
@@ -2,6 +2,7 @@ package com.fireworksdk.bridge.utils
2
2
 
3
3
  import com.fireworksdk.bridge.models.FWAdBadgeConfigModel
4
4
  import com.fireworksdk.bridge.models.FWSdkInitResultModel
5
+ import com.fireworksdk.bridge.models.enums.FWSwitchLanguageBehavior
5
6
 
6
7
  object FWGlobalDataUtil {
7
8
 
@@ -18,4 +19,8 @@ object FWGlobalDataUtil {
18
19
  var shareBaseUrl: String? = null
19
20
 
20
21
  var pauseWhenNotVisible: Boolean = false
22
+
23
+ var switchLanguageBehavior = FWSwitchLanguageBehavior.RestartingActivity
24
+
25
+ var initCompletedListener: (() -> Unit)? = null
21
26
  }
@@ -4,6 +4,7 @@ import android.app.Activity
4
4
  import android.content.Context
5
5
  import androidx.fragment.app.FragmentActivity
6
6
  import com.fireworksdk.bridge.components.base.FWBaseFragment
7
+
7
8
  import java.util.Locale
8
9
 
9
10
  class FWLanguageUtil private constructor(context: Context) {
@@ -14,12 +15,38 @@ class FWLanguageUtil private constructor(context: Context) {
14
15
 
15
16
  private val initAppLocale: Locale = Locale.getDefault()
16
17
 
18
+ /**
19
+ * local string, e.g. ar, ar-AE, pt-BR
20
+ */
17
21
  private var localeString: String? = null
18
22
 
19
23
  init {
20
24
  localeString = sharedPreferences.getString(LOCALE_KEY, null)
21
25
  }
22
26
 
27
+ fun getCurrentSettingLocale(): Locale {
28
+ val localeLanguage = localeString
29
+ if (localeLanguage.isNullOrBlank()) {
30
+ return Locale(initAppLocale.language, initAppLocale.country)
31
+ } else {
32
+ if (localeLanguage.contains("-")) {
33
+ val locales = localeLanguage.split("-")
34
+ if (locales.size > 1) {
35
+ return Locale(locales[0], locales[1])
36
+ }
37
+ }
38
+ return Locale(localeLanguage)
39
+ }
40
+ }
41
+
42
+ fun shouldOverrideLanguage(language: String): Boolean {
43
+ if (localeString.isNullOrBlank()) {
44
+ // not update language in local string
45
+ return false
46
+ }
47
+ return !localeString.equals(language, true)
48
+ }
49
+
23
50
  fun updateBaseContextLocale(baseContext: Context): Context {
24
51
  val currentLocaleString = localeString
25
52
 
@@ -28,29 +55,45 @@ class FWLanguageUtil private constructor(context: Context) {
28
55
  return updateResourcesLocale(baseContext, initAppLocale)
29
56
  }
30
57
 
31
- val localeStrings = currentLocaleString.split("-")
32
- val locale = if (localeStrings.size > 1) {
33
- Locale(localeStrings[0], localeStrings[1])
34
- } else {
35
- Locale(currentLocaleString)
36
- }
58
+ val locale = getLocaleByLanguage(currentLocaleString)
59
+
37
60
  Locale.setDefault(locale)
38
61
  return updateResourcesLocale(baseContext, locale)
39
62
  }
40
63
 
64
+ private fun getLocaleByLanguage(language: String): Locale {
65
+ if (language.contains("-")) {
66
+ val locales = language.split("-")
67
+ if (locales.size > 1) {
68
+ return Locale(locales[0], locales[1])
69
+ }
70
+ }
71
+ return Locale(language)
72
+ }
73
+
41
74
  private fun updateResourcesLocale(context: Context, locale: Locale): Context {
42
75
  val resources = context.resources
43
76
  val configuration = resources.configuration
44
77
  configuration.setLocale(locale)
45
78
  configuration.setLayoutDirection(locale)
46
- return context.createConfigurationContext(configuration)
79
+ val newContext = context.createConfigurationContext(configuration)
80
+ context.resources.updateConfiguration(configuration, context.resources.displayMetrics)
81
+ return newContext
47
82
  }
48
83
 
49
- fun changeLanguage(inputLocaleString: String?, activity: Activity?): Boolean {
50
- // no change
51
- if ((inputLocaleString.isNullOrBlank() && localeString.isNullOrBlank())
84
+ /**
85
+ * return
86
+ * true: need to execute change language.
87
+ * false: don't need to execute change language.
88
+ */
89
+ fun isSameLanguageWithCache(inputLocaleString: String?): Boolean {
90
+ return (inputLocaleString.isNullOrBlank() && localeString.isNullOrBlank())
52
91
  || localeString == inputLocaleString
53
- ) {
92
+ }
93
+
94
+ fun changeLanguage(inputLocaleString: String?): Boolean {
95
+ // no change
96
+ if (isSameLanguageWithCache(inputLocaleString)) {
54
97
  return true
55
98
  }
56
99
 
@@ -58,7 +101,6 @@ class FWLanguageUtil private constructor(context: Context) {
58
101
  if (inputLocaleString.isNullOrBlank()) {
59
102
  localeString = null
60
103
  updateSpLanguage(inputLocaleString)
61
- restartActivity(activity)
62
104
  return true
63
105
  }
64
106
 
@@ -70,7 +112,6 @@ class FWLanguageUtil private constructor(context: Context) {
70
112
  // update locale
71
113
  localeString = inputLocaleString
72
114
  updateSpLanguage(inputLocaleString)
73
- restartActivity(activity)
74
115
  return true
75
116
  }
76
117
 
@@ -86,7 +127,7 @@ class FWLanguageUtil private constructor(context: Context) {
86
127
  }
87
128
  }
88
129
 
89
- private fun restartActivity(activity: Activity?) {
130
+ fun restartActivity(activity: Activity?) {
90
131
  if (activity is FragmentActivity) {
91
132
  val fragments = activity.supportFragmentManager.fragments
92
133
  for (f in fragments) {
@@ -98,7 +139,7 @@ class FWLanguageUtil private constructor(context: Context) {
98
139
  activity?.recreate()
99
140
  }
100
141
 
101
- private fun isValidLocale(locale: String?) : Boolean {
142
+ private fun isValidLocale(locale: String?): Boolean {
102
143
  locale ?: return false
103
144
  val list = Locale.getAvailableLocales()
104
145
  if (locale.contains("-")) {
@@ -114,4 +155,5 @@ class FWLanguageUtil private constructor(context: Context) {
114
155
  private const val LOCALE_SP = "fw_locale_sp"
115
156
  private const val LOCALE_KEY = "fw_locale_key"
116
157
  }
158
+
117
159
  }
@@ -4,6 +4,7 @@ import com.firework.analyticsevents.VideoInfo
4
4
  import com.firework.analyticsevents.cta.CtaButtonClickAnalyticsEvent
5
5
  import com.firework.analyticsevents.player.PlayerLifecycleAnalyticsEvent
6
6
  import com.firework.analyticsevents.share.ShareButtonAnalyticsEvent
7
+ import com.fireworksdk.bridge.models.FWLiveStreamEventDetailsModel
7
8
  import com.fireworksdk.bridge.models.FWVideoPlaybackDetails
8
9
 
9
10
  object FWModelUtils {
@@ -20,6 +21,13 @@ object FWModelUtils {
20
21
  )
21
22
  }
22
23
 
24
+ fun convertVideoInfo2LivestreamDetails(videoInfo: VideoInfo): FWLiveStreamEventDetailsModel {
25
+ return FWLiveStreamEventDetailsModel(
26
+ id = videoInfo.id,
27
+ feedId = videoInfo.feedId,
28
+ )
29
+ }
30
+
23
31
  fun convertCtaEvent2PlaybackDetails(event: CtaButtonClickAnalyticsEvent): FWVideoPlaybackDetails {
24
32
  return FWVideoPlaybackDetails(
25
33
  badge = event.videoInfo.badge,
@@ -36,15 +44,15 @@ object FWModelUtils {
36
44
 
37
45
  fun convertPlayerEvent2PlaybackDetails(event: PlayerLifecycleAnalyticsEvent): FWVideoPlaybackDetails {
38
46
  return FWVideoPlaybackDetails(
39
- badge = event.videoInfo.badge,
40
- caption = event.videoInfo.caption,
41
- duration = event.videoInfo.duration,
42
- hasCta = event.videoInfo.hasCta,
43
- playerHeight = event.videoInfo.playerHeight,
44
- playerWidth = event.videoInfo.playerWidth,
45
- id = event.videoInfo.id,
47
+ badge = event.videoInfo?.badge,
48
+ caption = event.videoInfo?.caption,
49
+ duration = event.videoInfo?.duration,
50
+ hasCta = event.videoInfo?.hasCta,
51
+ playerHeight = event.videoInfo?.playerHeight,
52
+ playerWidth = event.videoInfo?.playerWidth,
53
+ id = event.videoInfo?.id,
46
54
  progress = event.progress,
47
- feedId = event.videoInfo.feedId,
55
+ feedId = event.videoInfo?.feedId,
48
56
  )
49
57
  }
50
58
 
@@ -123,7 +123,7 @@ public class StoryBlock: UIView, StoryBlockViewControllerDelegate, PictureInPict
123
123
  self.storyBlockVC = storyBlockVC
124
124
  updateStoryBlockVCConfiguration()
125
125
 
126
- storyBlockVC.isPictureInPictureEnabled = storyBlockConfiguration?.enablePictureInPicture ?? true
126
+ storyBlockVC.isPictureInPictureEnabled = storyBlockConfiguration?.enablePictureInPicture ?? false
127
127
  storyBlockVC.pictureInPictureDelegate = self
128
128
  storyBlockVC.delegate = self
129
129
 
@@ -243,10 +243,10 @@ public class StoryBlock: UIView, StoryBlockViewControllerDelegate, PictureInPict
243
243
  }
244
244
  }
245
245
 
246
- // if let showPlaybackButton = config.showPlaybackButton {
247
- // resultConfig.fullScreenPlayerView.playbackButton.isHidden = !showPlaybackButton
248
- // }
249
- //
246
+ if let showPlaybackButton = config.showPlaybackButton {
247
+ resultConfig.fullScreenPlayerView.playbackButton.isHidden = !showPlaybackButton
248
+ }
249
+
250
250
  // if let showMuteButton = config.showMuteButton {
251
251
  // resultConfig.fullScreenPlayerView.muteButton.isHidden = !showMuteButton
252
252
  // }
@@ -356,9 +356,6 @@ public class StoryBlock: UIView, StoryBlockViewControllerDelegate, PictureInPict
356
356
  if let replayBadgeConfiguration = config.replayBadgeConfiguration {
357
357
  resultConfig.replayBadge.isHidden = replayBadgeConfiguration.isHidden
358
358
  resultConfig.fullScreenPlayerView.replayBadge.isHidden = replayBadgeConfiguration.isHidden
359
- } else {
360
- resultConfig.replayBadge.isHidden = false
361
- resultConfig.fullScreenPlayerView.replayBadge.isHidden = false
362
359
  }
363
360
 
364
361
  if let countdownTimerConfiguration = config.countdownTimerConfiguration {
@@ -208,7 +208,7 @@ public class VideoFeed: UIView, VideoFeedViewControllerDelegate, PictureInPictur
208
208
  feedVC.viewConfiguration = viewConfiguration
209
209
  }
210
210
 
211
- feedVC.isPictureInPictureEnabled = playerViewConfig?.enablePictureInPicture ?? true
211
+ feedVC.isPictureInPictureEnabled = playerViewConfig?.enablePictureInPicture ?? false
212
212
 
213
213
  feedVC.delegate = self
214
214
  feedVC.pictureInPictureDelegate = self
@@ -537,8 +537,6 @@ extension VideoFeed {
537
537
 
538
538
  if let replayBadgeConfiguration = config.replayBadgeConfiguration {
539
539
  vpcConfig.replayBadge.isHidden = replayBadgeConfiguration.isHidden
540
- } else {
541
- vpcConfig.replayBadge.isHidden = false
542
540
  }
543
541
 
544
542
  if let countdownTimerConfiguration = config.countdownTimerConfiguration {
@@ -570,8 +568,6 @@ extension VideoFeed {
570
568
 
571
569
  if let replayBadge = feedViewConfig?.replayBadge {
572
570
  videoConfig.replayBadge.isHidden = replayBadge.isHidden
573
- } else {
574
- videoConfig.replayBadge.isHidden = false
575
571
  }
576
572
 
577
573
  return videoConfig
@@ -7,6 +7,7 @@
7
7
  objects = {
8
8
 
9
9
  /* Begin PBXBuildFile section */
10
+ 890B6B402BF5F9B4007E5762 /* NumberFormatter+AppLanguage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 890B6B3F2BF5F9B4007E5762 /* NumberFormatter+AppLanguage.swift */; };
10
11
  891F4AF62A67E12800A9E8DA /* FWRNContainerViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 891F4AF52A67E12800A9E8DA /* FWRNContainerViewController.swift */; };
11
12
  891F4AF82A68DEDF00A9E8DA /* PushRNContainerParams.swift in Sources */ = {isa = PBXBuildFile; fileRef = 891F4AF72A68DEDF00A9E8DA /* PushRNContainerParams.swift */; };
12
13
  891F4AFA2A68DF2B00A9E8DA /* RCTConvert+FWNavigatorModule.swift in Sources */ = {isa = PBXBuildFile; fileRef = 891F4AF92A68DF2B00A9E8DA /* RCTConvert+FWNavigatorModule.swift */; };
@@ -98,6 +99,7 @@
98
99
 
99
100
  /* Begin PBXFileReference section */
100
101
  1F6F718A2771B48100224AF3 /* FireworkSdk-Bridging-Header.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "FireworkSdk-Bridging-Header.h"; sourceTree = "<group>"; };
102
+ 890B6B3F2BF5F9B4007E5762 /* NumberFormatter+AppLanguage.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "NumberFormatter+AppLanguage.swift"; sourceTree = "<group>"; };
101
103
  891F4AF52A67E12800A9E8DA /* FWRNContainerViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FWRNContainerViewController.swift; sourceTree = "<group>"; };
102
104
  891F4AF72A68DEDF00A9E8DA /* PushRNContainerParams.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PushRNContainerParams.swift; sourceTree = "<group>"; };
103
105
  891F4AF92A68DF2B00A9E8DA /* RCTConvert+FWNavigatorModule.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "RCTConvert+FWNavigatorModule.swift"; sourceTree = "<group>"; };
@@ -183,6 +185,7 @@
183
185
  898873122A0A8E7E0089CD1C /* Extensions */ = {
184
186
  isa = PBXGroup;
185
187
  children = (
188
+ 890B6B3F2BF5F9B4007E5762 /* NumberFormatter+AppLanguage.swift */,
186
189
  89C105642BAD2C1D00E47CDD /* UIWindowScene+Swizzle.swift */,
187
190
  898873132A0A8E7E0089CD1C /* UIViewController+AttachChild.swift */,
188
191
  898873142A0A8E7E0089CD1C /* UIView+Constraints.swift */,
@@ -424,6 +427,7 @@
424
427
  8988735B2A0A8E7E0089CD1C /* FireworkSDKModule.m in Sources */,
425
428
  8988736A2A0A8E7E0089CD1C /* VideoFeedConfiguration.swift in Sources */,
426
429
  8975238D2817DEF80070EBB6 /* (null) in Sources */,
430
+ 890B6B402BF5F9B4007E5762 /* NumberFormatter+AppLanguage.swift in Sources */,
427
431
  8975238C2817DEF80070EBB6 /* (null) in Sources */,
428
432
  8988736B2A0A8E7E0089CD1C /* VideoFeed.swift in Sources */,
429
433
  891F4AF62A67E12800A9E8DA /* FWRNContainerViewController.swift in Sources */,
@@ -45,6 +45,7 @@ enum ShoppingEventName: String, CaseIterable {
45
45
  case logMessage = "fw:log-message"
46
46
  case customLinkButtonClick = "fw:shopping:custom-link-button-click"
47
47
  case customProductCardTap = "fw:shopping:custom-product-card-tap"
48
+ case productClick = "fw:shopping:product-click"
48
49
  }
49
50
 
50
51
  /// Live stream event
@@ -72,7 +72,8 @@ extension FeedEventDetails {
72
72
  var result: [String: Any] = [
73
73
  "index": index,
74
74
  "id": id,
75
- "duration": duration
75
+ "duration": duration,
76
+ "feedId": feedId
76
77
  ]
77
78
  if let title = caption {
78
79
  result["title"] = title
@@ -112,7 +113,10 @@ extension FeedEventDetails {
112
113
 
113
114
  extension LiveStreamEventDetails {
114
115
  var jsObject: [String: Any] {
115
- return ["id": id]
116
+ return [
117
+ "id": videoID,
118
+ "feedId": feedID
119
+ ]
116
120
  }
117
121
  }
118
122
 
@@ -113,4 +113,17 @@ extension RCTConvert {
113
113
 
114
114
  return result
115
115
  }
116
+
117
+ static func dataTrackingLevel(_ level: String) -> FireworkVideo.DataTrackingLevel? {
118
+ switch level {
119
+ case "all":
120
+ return FireworkVideo.DataTrackingLevel.all
121
+ case "essentialOnly":
122
+ return FireworkVideo.DataTrackingLevel.essentialOnly
123
+ case "none":
124
+ return FireworkVideo.DataTrackingLevel.none
125
+ default:
126
+ return nil
127
+ }
128
+ }
116
129
  }
@@ -8,27 +8,19 @@
8
8
  import FireworkVideo
9
9
  import Foundation
10
10
 
11
- var gVideoDetailsForTappingCTAButton: VideoDetails?
12
-
13
11
  extension FireworkSDKModule: FireworkVideoCTADelegate {
14
- func handleCustomCTAClick(_ viewController: PlayerViewController, url: URL) -> Bool {
12
+ func handleCustomCTAClick(_ viewController: PlayerViewController, url: URL, for video: VideoDetails) -> Bool {
15
13
  let callbackId = UUID().uuidString
16
14
  playerMap.setObject(viewController, forKey: callbackId as NSString)
17
15
 
18
- DispatchQueue.main.async { [weak self] in
19
- var body: [String: Any?] = [
20
- "url": url.absoluteString,
21
- "callbackId": callbackId
22
- ]
23
-
24
- if let video = gVideoDetailsForTappingCTAButton {
25
- body["video"] = video.jsObject
26
- gVideoDetailsForTappingCTAButton = nil
27
- }
16
+ let body: [String: Any?] = [
17
+ "url": url.absoluteString,
18
+ "callbackId": callbackId,
19
+ "video": video.jsObject
20
+ ]
28
21
 
29
- self?.sendEvent(withName: FWEventName.customCTAClick.rawValue,
30
- body: body)
31
- }
22
+ self.sendEvent(withName: FWEventName.customCTAClick.rawValue,
23
+ body: body)
32
24
 
33
25
  return customCTAClickEnabled
34
26
  }