react-native-firework-sdk 1.8.0 → 1.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 (138) hide show
  1. package/android/build.gradle +1 -1
  2. package/android/src/main/java/com/fireworksdk/bridge/utils/FWLanguageUtil.kt +47 -14
  3. package/ios/Components/StoryBlock.swift +33 -2
  4. package/ios/Components/StoryBlockManager.m +32 -0
  5. package/ios/Components/VideoFeed.swift +10 -29
  6. package/ios/Components/VideoFeedManager.m +11 -6
  7. package/ios/FireworkSdk.xcodeproj/project.pbxproj +378 -204
  8. package/ios/Models/NativeToRN/FireworkEventName.swift +3 -1
  9. package/ios/Models/RNToNative/RCTConvert+Shopping.swift +21 -0
  10. package/ios/Models/RNToNative/RCTConvert+VideoFeed.swift +27 -0
  11. package/ios/Modules/FWNavigatorModule/FWNavigatorModule.swift +23 -5
  12. package/ios/Modules/FireworkSDKModule/FireworkSDKModule.m +1 -0
  13. package/ios/Modules/FireworkSDKModule/FireworkSDKModule.swift +31 -0
  14. package/ios/Modules/Shopping/ProductInfoViewConfiguration.swift +13 -0
  15. package/ios/Modules/Shopping/ShoppingCTAResult.swift +16 -0
  16. package/ios/Modules/Shopping/ShoppingModule.m +2 -1
  17. package/ios/Modules/Shopping/ShoppingModule.swift +103 -30
  18. package/ios/Support/MultiHostStreaming/FWMultiHostStreaming.podspec +24 -0
  19. package/ios/Support/MultiHostStreaming/src/MultiHostStreamingSDK.swift +17 -0
  20. package/ios/Utils/AppLanguage/Bundle+FWSwizzle.swift +58 -0
  21. package/ios/Utils/AppLanguage/FWAppLanguageManager.swift +139 -0
  22. package/ios/Utils/AppLanguage/FWLanguageUtil.swift +43 -0
  23. package/ios/Utils/AppLanguage/NumberFormatter+FWSwizzle.swift +25 -0
  24. package/ios/Utils/AppLanguage/UIImageView+FWSwizzle.swift +91 -0
  25. package/ios/Utils/AppLanguage/UILabel+FWSwizzle.swift +98 -0
  26. package/ios/Utils/AppLanguage/UITextField+FWSwizzle.swift +97 -0
  27. package/ios/Utils/AppLanguage/UITextView+FWSwizzle.swift +97 -0
  28. package/ios/Utils/AppLanguage/UIView+FWSwizzle.swift +38 -0
  29. package/ios/Utils/AppLanguage/UIViewController+FWSwizzle.swift +32 -0
  30. package/ios/Utils/AppLanguage/UIWindow+FWSwizzle.swift +26 -0
  31. package/ios/Utils/AppLanguage/URLSession+FWSwizzle.swift +69 -0
  32. package/ios/Utils/{DispatchQueue+FWOnce.swift → Extensions/DispatchQueue+FWOnce.swift} +3 -3
  33. package/ios/Utils/{UINavigationController+FWSwizzle.swift → Extensions/Swizzle/UINavigationController+FWSwizzle.swift} +6 -8
  34. package/ios/Utils/Extensions/UIView+FWUIHierarchy.swift +47 -0
  35. package/ios/Utils/FWRTL/Classes/Manager/FWRTLManager.h +25 -0
  36. package/ios/Utils/FWRTL/Classes/Manager/FWRTLManager.m +75 -0
  37. package/ios/Utils/FWRTL/Classes/UICategories/CALayer+FWRTL.h +21 -0
  38. package/ios/Utils/FWRTL/Classes/UICategories/CALayer+FWRTL.m +124 -0
  39. package/ios/Utils/FWRTL/Classes/UICategories/FWRTLRemoteViewControllerAdaptor.h +11 -0
  40. package/ios/Utils/FWRTL/Classes/UICategories/FWRTLRemoteViewControllerAdaptor.m +86 -0
  41. package/ios/Utils/FWRTL/Classes/UICategories/FWRTLWhiteListManager.h +16 -0
  42. package/ios/Utils/FWRTL/Classes/UICategories/FWRTLWhiteListManager.m +55 -0
  43. package/ios/Utils/FWRTL/Classes/UICategories/UILabel+FWRTL.h +18 -0
  44. package/ios/Utils/FWRTL/Classes/UICategories/UILabel+FWRTL.m +39 -0
  45. package/ios/Utils/FWRTL/Classes/UICategories/UIView+FWRTL.h +54 -0
  46. package/ios/Utils/FWRTL/Classes/UICategories/UIView+FWRTL.m +141 -0
  47. package/ios/Utils/FWRTL/Classes/UICategories/UIWindow+FWRTL.h +16 -0
  48. package/ios/Utils/FWRTL/Classes/UICategories/UIWindow+FWRTL.m +20 -0
  49. package/ios/Utils/FWRTL/Classes/Utils/FWRTLDefinitions.h +52 -0
  50. package/ios/Utils/FWRTL/Classes/Utils/NSObject+FWRTLReloadBlock.h +19 -0
  51. package/ios/Utils/FWRTL/Classes/Utils/NSObject+FWRTLReloadBlock.m +49 -0
  52. package/ios/Utils/FWRTL/Classes/Utils/NSString+FWRTL.h +21 -0
  53. package/ios/Utils/FWRTL/Classes/Utils/NSString+FWRTL.m +38 -0
  54. package/ios/Utils/FWRTL/Classes/Utils/UIImage+FWRTL.h +18 -0
  55. package/ios/Utils/FWRTL/Classes/Utils/UIImage+FWRTL.m +43 -0
  56. package/ios/Utils/FWSwizzleLoader.m +6 -1
  57. package/ios/Utils/FWSwizzleLoader.swift +13 -0
  58. package/ios/Utils/FWSwizzleUtil.swift +17 -9
  59. package/ios/react_native_firework_sdk.h +1 -0
  60. package/ios/scripts/react_native_firework_sdk_pods.rb +31 -0
  61. package/lib/commonjs/FWNavigator.js +2 -2
  62. package/lib/commonjs/FWNavigator.js.map +1 -1
  63. package/lib/commonjs/FireworkSDK.js +31 -6
  64. package/lib/commonjs/FireworkSDK.js.map +1 -1
  65. package/lib/commonjs/VideoShopping.js +71 -22
  66. package/lib/commonjs/VideoShopping.js.map +1 -1
  67. package/lib/commonjs/components/StoryBlock.js +156 -106
  68. package/lib/commonjs/components/StoryBlock.js.map +1 -1
  69. package/lib/commonjs/components/VideoFeed.js +37 -11
  70. package/lib/commonjs/components/VideoFeed.js.map +1 -1
  71. package/lib/commonjs/index.js +6 -0
  72. package/lib/commonjs/index.js.map +1 -1
  73. package/lib/commonjs/models/FWEventName.js +2 -0
  74. package/lib/commonjs/models/FWEventName.js.map +1 -1
  75. package/lib/commonjs/models/ShoppingCTAResult.js +2 -0
  76. package/lib/commonjs/models/ShoppingCTAResult.js.map +1 -0
  77. package/lib/commonjs/modules/FireworkSDKModule.js.map +1 -1
  78. package/lib/commonjs/modules/ShoppingModule.js.map +1 -1
  79. package/lib/module/FWNavigator.js +5 -2
  80. package/lib/module/FWNavigator.js.map +1 -1
  81. package/lib/module/FireworkSDK.js +31 -6
  82. package/lib/module/FireworkSDK.js.map +1 -1
  83. package/lib/module/VideoShopping.js +70 -23
  84. package/lib/module/VideoShopping.js.map +1 -1
  85. package/lib/module/components/StoryBlock.js +146 -103
  86. package/lib/module/components/StoryBlock.js.map +1 -1
  87. package/lib/module/components/VideoFeed.js +41 -10
  88. package/lib/module/components/VideoFeed.js.map +1 -1
  89. package/lib/module/index.js +1 -1
  90. package/lib/module/index.js.map +1 -1
  91. package/lib/module/models/FWEventName.js +2 -0
  92. package/lib/module/models/FWEventName.js.map +1 -1
  93. package/lib/module/models/ShoppingCTAResult.js +2 -0
  94. package/lib/module/models/ShoppingCTAResult.js.map +1 -0
  95. package/lib/module/modules/FireworkSDKModule.js.map +1 -1
  96. package/lib/module/modules/ShoppingModule.js.map +1 -1
  97. package/lib/typescript/FWNavigator.d.ts +6 -3
  98. package/lib/typescript/FireworkSDK.d.ts +20 -7
  99. package/lib/typescript/LiveStream.d.ts +2 -2
  100. package/lib/typescript/VideoShopping.d.ts +32 -11
  101. package/lib/typescript/components/StoryBlock.d.ts +21 -11
  102. package/lib/typescript/components/VideoFeed.d.ts +21 -5
  103. package/lib/typescript/index.d.ts +7 -4
  104. package/lib/typescript/models/AdBadgeConfiguration.d.ts +1 -1
  105. package/lib/typescript/models/AddToCartResult.d.ts +4 -0
  106. package/lib/typescript/models/FWEventName.d.ts +2 -0
  107. package/lib/typescript/models/FWEvents.d.ts +27 -0
  108. package/lib/typescript/models/IOSFontInfo.d.ts +2 -2
  109. package/lib/typescript/models/NewNativeContainerProps.d.ts +1 -1
  110. package/lib/typescript/models/ProductInfoViewConfiguration.d.ts +35 -0
  111. package/lib/typescript/models/ShoppingCTAResult.d.ts +11 -0
  112. package/lib/typescript/models/StoryBlockSource.d.ts +1 -1
  113. package/lib/typescript/models/VideoFeedConfiguration.d.ts +4 -3
  114. package/lib/typescript/models/VideoFeedSource.d.ts +1 -1
  115. package/lib/typescript/models/VideoPlayerConfiguration.d.ts +7 -5
  116. package/lib/typescript/modules/FireworkSDKModule.d.ts +1 -2
  117. package/lib/typescript/modules/ShoppingModule.d.ts +2 -0
  118. package/package.json +10 -6
  119. package/react-native-firework-sdk.podspec +26 -24
  120. package/src/FWNavigator.ts +6 -3
  121. package/src/FireworkSDK.ts +27 -8
  122. package/src/VideoShopping.ts +110 -41
  123. package/src/components/StoryBlock.tsx +158 -84
  124. package/src/components/VideoFeed.tsx +38 -9
  125. package/src/index.ts +21 -0
  126. package/src/models/AddToCartResult.ts +4 -0
  127. package/src/models/FWEventName.ts +2 -0
  128. package/src/models/FWEvents.ts +28 -0
  129. package/src/models/ProductInfoViewConfiguration.ts +37 -0
  130. package/src/models/ShoppingCTAResult.ts +11 -0
  131. package/src/models/VideoFeedConfiguration.ts +3 -2
  132. package/src/models/VideoPlayerConfiguration.ts +3 -1
  133. package/src/modules/FireworkSDKModule.ts +1 -2
  134. package/src/modules/ShoppingModule.ts +6 -1
  135. package/ios/Utils/UIView+ParentViewController.swift +0 -21
  136. /package/ios/Utils/{String+Color.swift → Extensions/String+Color.swift} +0 -0
  137. /package/ios/Utils/{UIView+Constraints.swift → Extensions/UIView+Constraints.swift} +0 -0
  138. /package/ios/Utils/{UIViewController+AttachChild.swift → Extensions/UIViewController+AttachChild.swift} +0 -0
@@ -15,6 +15,7 @@ enum FWEventName: String, CaseIterable {
15
15
  case videoFeedClick = "fw:video-feed-click"
16
16
  case shareBaseURLUpdated = "fw:share-base-url-updated" // emitted in JS side
17
17
  case adBadgeConfigurationUpdated = "fw:ad-badge-configuration-updated" // emitted in JS side
18
+ case appLanguageUpdated = "fw:app-language-updated" // emitted in JS side
18
19
  case logMessage = "fw:log-message"
19
20
  }
20
21
 
@@ -34,9 +35,10 @@ enum VideoPlaybackSubEventName: String {
34
35
  enum ShoppingEventName: String, CaseIterable {
35
36
  case updateProductDetails = "fw:shopping:update-product-details"
36
37
  case willDisplayProduct = "fw:shopping:will-display-product"
37
- case addToCart = "fw:shopping:add-to-cart"
38
+ case ctaButtonClick = "fw:shopping:cta-button-click"
38
39
  case clickCartIcon = "fw:shopping:click-cart-icon"
39
40
  case logMessage = "fw:log-message"
41
+ case customLinkButtonClick = "fw:shopping:custom-link-button-click"
40
42
  }
41
43
 
42
44
  /// Live stream event
@@ -63,4 +63,25 @@ extension RCTConvert {
63
63
 
64
64
  return result
65
65
  }
66
+
67
+ static func buildShoppingCTAResult(_ result: [String: Any]?)
68
+ -> ShoppingCTAResult? {
69
+ guard let rResult = result else {
70
+ return nil
71
+ }
72
+
73
+ let jsonData = try? JSONSerialization.data(withJSONObject: rResult, options: .prettyPrinted)
74
+ guard let rJsonData = jsonData else {
75
+ return nil
76
+ }
77
+
78
+ var ctaResult: ShoppingCTAResult?
79
+ do {
80
+ ctaResult = try JSONDecoder().decode(ShoppingCTAResult.self, from: rJsonData)
81
+ } catch let error {
82
+ print(error.localizedDescription)
83
+ }
84
+
85
+ return ctaResult
86
+ }
66
87
  }
@@ -6,6 +6,7 @@
6
6
  //
7
7
 
8
8
  import Foundation
9
+ import FireworkVideo
9
10
 
10
11
  extension VideFeedSourceType {
11
12
  static var sourceTypeMapper: [String: VideFeedSourceType] {
@@ -87,4 +88,30 @@ extension RCTConvert {
87
88
 
88
89
  return try? JSONDecoder().decode(AdConfiguration.self, from: rJsonData)
89
90
  }
91
+
92
+ @nonobjc
93
+ public static func getFireworkVideoAdConfiguration(
94
+ _ adConfiguration: AdConfiguration?
95
+ ) -> FireworkVideo.AdConfiguration? {
96
+ guard let feedAdConfiguration = adConfiguration else {
97
+ return nil
98
+ }
99
+
100
+ var resultAdConfiguration = FireworkVideo.AdConfiguration()
101
+ if let requiresAds = feedAdConfiguration.requiresAds {
102
+ resultAdConfiguration.requiresAds = requiresAds
103
+ }
104
+
105
+ if let adsFetchTimeout = feedAdConfiguration.adsFetchTimeout {
106
+ resultAdConfiguration.adsFetchTimeout = adsFetchTimeout
107
+ }
108
+
109
+ if let vastAttributes = feedAdConfiguration.vastAttributes {
110
+ resultAdConfiguration.vastAttributes = vastAttributes.map({ attribute in
111
+ return URLQueryItem(name: attribute.name ?? "", value: attribute.value ?? "")
112
+ })
113
+ }
114
+
115
+ return resultAdConfiguration
116
+ }
90
117
  }
@@ -7,6 +7,11 @@
7
7
 
8
8
  import FireworkVideo
9
9
 
10
+ private let FWExitButtonImageNames: [String] = [
11
+ "closeX",
12
+ "down-arrow-light"
13
+ ]
14
+
10
15
  private struct PlayerInfo {
11
16
  enum PlayerMode: Int {
12
17
  case fullscreen, floating
@@ -210,11 +215,25 @@ class FWNavigatorModule: RCTEventEmitter, FWNavigator {
210
215
 
211
216
  extension FWNavigatorModule {
212
217
  private static func getExitButton(view: UIView) -> UIButton? {
213
- if let button = view as? UIButton, let targetImage = button.image(for: .normal) {
218
+ if let button = view as? UIButton, let image = button.image(for: .normal) {
214
219
  let iOSSDKBundle = Bundle(for: FireworkVideoSDK.self)
215
- if targetImage.isEqual(UIImage(named: "closeX", in: iOSSDKBundle, compatibleWith: nil))
216
- || targetImage.isEqual(UIImage(named: "down-arrow-light", in: iOSSDKBundle, compatibleWith: nil)) {
217
- return button
220
+ for imageName in FWExitButtonImageNames {
221
+ let targetImage = UIImage(named: imageName, in: iOSSDKBundle, compatibleWith: nil)
222
+ if image.isEqual(targetImage) {
223
+ return button
224
+ }
225
+
226
+ if let cgImage = image.cgImage,
227
+ let targetCgImage = targetImage?.cgImage,
228
+ cgImage == targetCgImage {
229
+ return button
230
+ }
231
+
232
+ if let ciImage = image.ciImage,
233
+ let targetCiImage = targetImage?.ciImage,
234
+ ciImage == targetCiImage {
235
+ return button
236
+ }
218
237
  }
219
238
  }
220
239
 
@@ -287,7 +306,6 @@ extension FWNavigatorModule {
287
306
  if let rootVC = keyWindow.rootViewController,
288
307
  let presentedVC = rootVC.presentedViewController {
289
308
  let furthestAncestorController = getFurthestAncestorController(presentedVC)
290
-
291
309
  if let playerVC = getPlayerViewController(furthestAncestorController) {
292
310
  return PlayerInfo(playerVC: playerVC, mode: .fullscreen)
293
311
  }
@@ -19,5 +19,6 @@ RCT_EXTERN_METHOD(setVideoPlaybackEventEnabled:(BOOL)enabled)
19
19
  RCT_EXTERN_METHOD(setAdBadgeConfiguration:(NSDictionary *)config resolver: (RCTPromiseResolveBlock)resolver rejecter:(RCTPromiseRejectBlock)rejecter)
20
20
  RCT_EXTERN_METHOD(setAppComponentName:(NSString *)name resolver: (RCTPromiseResolveBlock)resolver rejecter:(RCTPromiseRejectBlock)rejecter)
21
21
  RCT_EXTERN_METHOD(trackPurchase:(NSDictionary *)parameters)
22
+ RCT_EXTERN_METHOD(changeAppLanguage:(NSString * __nullable)language resolver: (RCTPromiseResolveBlock)resolver rejecter:(RCTPromiseRejectBlock)rejecter)
22
23
 
23
24
  @end
@@ -39,6 +39,18 @@ class FireworkSDKModule: RCTEventEmitter, FireworkVideoSDKDelegate {
39
39
  #if DEBUG
40
40
  let formatter = DateFormatter()
41
41
  formatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSSZ"
42
+ let iOSSDKBundle = Bundle(for: FireworkVideoSDK.self)
43
+
44
+ let messageForLocalizations = """
45
+ [iOS] localizations information \(formatter.string(from: Date()))
46
+ AppleLanguages: \((UserDefaults.standard.object(forKey: "AppleLanguages") as? [String]) ?? [])
47
+ Bundle.main.localizations \(Bundle.main.localizations)
48
+ Bundle.main.preferredLocalizations \(Bundle.main.preferredLocalizations)
49
+ iOSSDKBundle.localizations \(iOSSDKBundle.localizations)
50
+ iOSSDKBundle.preferredLocalizations \(iOSSDKBundle.preferredLocalizations)
51
+ """
52
+ print("[react-native-firework-sdk] [swift] \(messageForLocalizations)")
53
+ sendEvent(withName: FWEventName.logMessage.rawValue, body: ["message": messageForLocalizations])
42
54
 
43
55
  let message = "[iOS] Call initializeSDK \(formatter.string(from: Date()))"
44
56
  print("[react-native-firework-sdk] [swift] \(message)")
@@ -50,6 +62,8 @@ class FireworkSDKModule: RCTEventEmitter, FireworkVideoSDKDelegate {
50
62
  FireworkVideoSDK.ctaDelegate = self
51
63
  FireworkVideoSDK.eventTracking.videoPlaybackDelegate = self
52
64
  FireworkVideoSDK.eventTracking.feedDelegate = self
65
+
66
+ FWAppLanguageManager.shared.initializeManager()
53
67
  }
54
68
 
55
69
  @objc(openVideoPlayer:config:)
@@ -147,6 +161,23 @@ class FireworkSDKModule: RCTEventEmitter, FireworkVideoSDKDelegate {
147
161
  )
148
162
  }
149
163
 
164
+ @objc(changeAppLanguage:resolver:rejecter:)
165
+ func changeAppLanguage(
166
+ _ language: String?, resolver: @escaping RCTPromiseResolveBlock, rejecter: @escaping RCTPromiseRejectBlock
167
+ ) {
168
+ #if DEBUG
169
+ let formatter = DateFormatter()
170
+ formatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSSZ"
171
+ let message = "[iOS] Call changeAppLanguage: \(language ?? "") \(formatter.string(from: Date()))"
172
+ sendEvent(withName: FWEventName.logMessage.rawValue, body: ["message": message])
173
+ #endif
174
+
175
+ DispatchQueue.main.async {
176
+ let result = FWAppLanguageManager.shared.changeAppLanguage(language)
177
+ resolver(result)
178
+ }
179
+ }
180
+
150
181
  // MARK: - FireworkVideoSDKDelegate
151
182
  func fireworkVideoDidLoadSuccessfully() {
152
183
  #if DEBUG
@@ -9,6 +9,7 @@ import Foundation
9
9
 
10
10
  struct ProductInfoViewConfiguration: Codable {
11
11
  var addToCartButton: AddToCartButtonConfiguration?
12
+ var ctaButton: CTAButtonConfiguration?
12
13
  var linkButton: LinkButtonConfiguration?
13
14
 
14
15
  struct AddToCartButtonConfiguration: Codable {
@@ -18,6 +19,18 @@ struct ProductInfoViewConfiguration: Codable {
18
19
  var iOSFontInfo: FontInfo?
19
20
  }
20
21
 
22
+ struct CTAButtonConfiguration: Codable {
23
+ var text: CTAButtonText?
24
+ var backgroundColor: String?
25
+ var textColor: String?
26
+ var fontSize: Double?
27
+ var iOSFontInfo: FontInfo?
28
+ }
29
+
30
+ enum CTAButtonText: String, Codable {
31
+ case addToCart, shopNow
32
+ }
33
+
21
34
  struct LinkButtonConfiguration: Codable {
22
35
  var isHidden: Bool?
23
36
  }
@@ -0,0 +1,16 @@
1
+ //
2
+ // ShoppingCTAResult.swift
3
+ //
4
+ // Created by linjie jiang on 2023/3/20.
5
+ //
6
+
7
+ import Foundation
8
+
9
+ struct ShoppingCTAResult: Codable {
10
+ var res: ShoppingCTAResultRes?
11
+ var tips: String?
12
+
13
+ enum ShoppingCTAResultRes: String, Codable {
14
+ case success, fail
15
+ }
16
+ }
@@ -13,10 +13,11 @@ _RCT_EXTERN_REMAP_METHOD(init, initialize, NO)
13
13
  RCT_EXTERN_METHOD(setCartIconVisible:(BOOL)visible)
14
14
  RCT_EXTERN_METHOD(setCartItemCount:(int)itemCounts)
15
15
  RCT_EXTERN_METHOD(updateVideoProducts:(NSArray *)products cbId:(nonnull NSNumber *)cbId)
16
- RCT_EXTERN_METHOD(updateAddToCartStatus:(NSString *)res tips:(nullable NSString *)tips cbId:(nonnull NSNumber *)cbId)
17
16
  RCT_EXTERN_METHOD(jumpToCartPage:(nonnull NSNumber *)cbId props:(NSDictionary *)props)
18
17
  RCT_EXTERN_METHOD(setCustomClickCartIconEnabled:(BOOL)enabled resolver: (RCTPromiseResolveBlock)resolver rejecter:(RCTPromiseRejectBlock)rejecter)
19
18
  RCT_EXTERN_METHOD(setProductInfoViewConfiguration:(NSDictionary *)config)
20
19
  RCT_EXTERN_METHOD(clearCallbackId:(nonnull NSNumber *)cbId eventName:(nonnull NSString *)name)
20
+ RCT_EXTERN_METHOD(setCustomClickLinkButtonEnabled:(BOOL)enabled resolver: (RCTPromiseResolveBlock)resolver rejecter:(RCTPromiseRejectBlock)rejecter)
21
+ RCT_EXTERN_METHOD(updateShoppingCTAResult:(NSDictionary *)result cbId:(nonnull NSNumber *)cbId)
21
22
 
22
23
  @end
@@ -10,11 +10,14 @@ import Foundation
10
10
 
11
11
  weak var gCartViewController: FWCartViewController?
12
12
 
13
+ // swiftlint:disable type_body_length
14
+ // swiftlint:disable file_length
15
+
13
16
  @objc(ShoppingModule)
14
17
  class ShoppingModule: RCTEventEmitter, FireworkVideoShoppingDelegate, CartViewControllerProviding {
15
18
 
16
19
  private var productInfoViewConfigurator: (Int, ProductInfoViewConfigurable)?
17
- private var addToCartHandlerMap: [Int: AddToCartHandler] = [:]
20
+ private var shoppingCTAHandlerMap: [Int: ShoppingCTAHandler] = [:]
18
21
  private var productHydratingMap: [Int: ProductHydrating] = [:]
19
22
 
20
23
  private var cartViewController: FWCartViewController?
@@ -22,6 +25,7 @@ class ShoppingModule: RCTEventEmitter, FireworkVideoShoppingDelegate, CartViewCo
22
25
  private var itemCounts = 0
23
26
  private var customClickCartIconEnabled = false
24
27
  private var productInfoViewConfiguration: ProductInfoViewConfiguration?
28
+ private var customClickLinkButtonEnabled = false
25
29
 
26
30
  override func supportedEvents() -> [String]! {
27
31
  ShoppingEventName.allCases.map { $0.rawValue }
@@ -130,21 +134,6 @@ class ShoppingModule: RCTEventEmitter, FireworkVideoShoppingDelegate, CartViewCo
130
134
  }
131
135
  }
132
136
 
133
- @objc
134
- func updateAddToCartStatus(_ res: String, tips: String?, cbId: NSNumber) {
135
- guard let handler = addToCartHandlerMap[Int(truncating: cbId)] else {
136
- return
137
- }
138
-
139
- addToCartHandlerMap.removeValue(forKey: Int(truncating: cbId))
140
-
141
- if res == "success" {
142
- handler(.feedbackOnly(.success(message: tips ?? "success")))
143
- } else {
144
- handler(.feedbackOnly(.failure(message: tips ?? "failure")))
145
- }
146
- }
147
-
148
137
  @objc
149
138
  func jumpToCartPage(_ cbId: NSNumber, props: NSDictionary) {
150
139
  let properties: [String: Any] = (props as? [String: Any]) ?? [:]
@@ -186,11 +175,49 @@ class ShoppingModule: RCTEventEmitter, FireworkVideoShoppingDelegate, CartViewCo
186
175
  func clearCallbackId(_ cbId: NSNumber, eventName: String) {
187
176
  if eventName == ShoppingEventName.updateProductDetails.rawValue {
188
177
  productHydratingMap.removeValue(forKey: Int(truncating: cbId))
189
- } else if eventName == ShoppingEventName.addToCart.rawValue {
190
- addToCartHandlerMap.removeValue(forKey: Int(truncating: cbId))
178
+ } else if eventName == ShoppingEventName.ctaButtonClick.rawValue {
179
+ if let handler = shoppingCTAHandlerMap[Int(truncating: cbId)] {
180
+ handler(.none)
181
+ }
182
+ shoppingCTAHandlerMap.removeValue(forKey: Int(truncating: cbId))
191
183
  }
192
184
  }
193
185
 
186
+ @objc
187
+ func setCustomClickLinkButtonEnabled(
188
+ _ enabled: Bool, resolver: @escaping RCTPromiseResolveBlock,
189
+ rejecter: @escaping RCTPromiseRejectBlock
190
+ ) {
191
+ customClickLinkButtonEnabled = enabled
192
+ resolver([:])
193
+ }
194
+
195
+ @objc
196
+ func updateShoppingCTAResult(_ result: [String: Any]?, cbId: NSNumber) {
197
+ guard let ctaResult = RCTConvert.buildShoppingCTAResult(result) else {
198
+ return
199
+ }
200
+
201
+ guard let handler = shoppingCTAHandlerMap[Int(truncating: cbId)] else {
202
+ return
203
+ }
204
+
205
+ if let res = ctaResult.res,
206
+ let tips = ctaResult.tips,
207
+ tips.count > 0 {
208
+ switch res {
209
+ case .success:
210
+ handler(.feedbackOnly(.success(message: tips)))
211
+ case .fail:
212
+ handler(.feedbackOnly(.failure(message: tips)))
213
+ }
214
+ } else {
215
+ handler(.none)
216
+ }
217
+
218
+ shoppingCTAHandlerMap.removeValue(forKey: Int(truncating: cbId))
219
+ }
220
+
194
221
  // MARK: - FireworkVideoShoppingDelegate
195
222
  func fireworkShopping(
196
223
  _ fireworkShopping: FireworkVideoShopping,
@@ -253,15 +280,37 @@ class ShoppingModule: RCTEventEmitter, FireworkVideoShoppingDelegate, CartViewCo
253
280
 
254
281
  func fireworkShopping(
255
282
  _ fireworkShopping: FireworkVideoShopping,
256
- addProductVariantToCart item: SelectedProductVariant, fromVideo video: VideoDetails,
257
- _ addToCartCompletionHandler: @escaping AddToCartHandler
283
+ productVariantCTASelected item: SelectedProductVariant,
284
+ fromVideo video: VideoDetails,
285
+ ctaCompletionHandler: @escaping ShoppingCTAHandler
258
286
  ) {
259
287
  let callbackId = ShoppingModule.generateCallbackId()
260
- self.addToCartHandlerMap[callbackId] = addToCartCompletionHandler
261
-
288
+ self.shoppingCTAHandlerMap[callbackId] = ctaCompletionHandler
262
289
  sendEvent(
263
- withName: ShoppingEventName.addToCart.rawValue,
264
- body: ["productId": item.productID, "unitId": item.unitID, "callbackId": callbackId])
290
+ withName: ShoppingEventName.ctaButtonClick.rawValue,
291
+ body: [
292
+ "url": item.url?.absoluteString ?? "",
293
+ "productId": item.productID,
294
+ "unitId": item.unitID,
295
+ "callbackId": callbackId
296
+ ])
297
+ }
298
+
299
+ func fireworkShopping(
300
+ _ fireworkShopping: FireworkVideoShopping,
301
+ didTapLinkButtonAt item: SelectedProductVariant,
302
+ withURL itemURL: String
303
+ ) -> Bool {
304
+ if customClickLinkButtonEnabled {
305
+ sendEvent(
306
+ withName: ShoppingEventName.customLinkButtonClick.rawValue,
307
+ body: [
308
+ "url": itemURL,
309
+ "productId": item.productID,
310
+ "unitId": item.unitID
311
+ ])
312
+ }
313
+ return customClickLinkButtonEnabled
265
314
  }
266
315
 
267
316
  // MARK: - CartViewControllerProviding
@@ -283,27 +332,52 @@ class ShoppingModule: RCTEventEmitter, FireworkVideoShoppingDelegate, CartViewCo
283
332
  }
284
333
 
285
334
  extension ShoppingModule {
286
-
335
+ // swiftlint:disable:next cyclomatic_complexity
287
336
  fileprivate static func hydrateProductViewConfig(
288
337
  _ config: ProductInfoViewConfiguration,
289
338
  _ productInfoViewConfigurator: ProductInfoViewConfigurable
290
339
  ) {
291
340
  var productDetailsConfiguration = productInfoViewConfigurator.productDetailsConfiguration
292
341
 
293
- if let addToCartButtonConfiguration = config.addToCartButton {
342
+ if let ctaButtonConfiguration = config.ctaButton {
343
+ if let text = ctaButtonConfiguration.text {
344
+ switch text {
345
+ case .addToCart:
346
+ productDetailsConfiguration.ctaButton.text = .addToCart
347
+ case .shopNow:
348
+ productDetailsConfiguration.ctaButton.text = .shopNow
349
+ }
350
+ }
351
+ if let backgroundColor = ctaButtonConfiguration.backgroundColor,
352
+ backgroundColor.count > 0 {
353
+ productDetailsConfiguration.ctaButton.buttonConfiguration.backgroundColor = backgroundColor.uicolor()
354
+ }
355
+
356
+ if let textColor = ctaButtonConfiguration.textColor,
357
+ textColor.count > 0 {
358
+ productDetailsConfiguration.ctaButton.buttonConfiguration.textColor = textColor.uicolor()
359
+ }
360
+
361
+ if let fontSize = ctaButtonConfiguration.fontSize {
362
+ let iOSFontInfo = ctaButtonConfiguration.iOSFontInfo ?? FontInfo()
363
+ productDetailsConfiguration.ctaButton.buttonConfiguration.font = iOSFontInfo.getFont(fontSize)
364
+ }
365
+ } else if let addToCartButtonConfiguration = config.addToCartButton {
366
+ productDetailsConfiguration.ctaButton.text = .addToCart
367
+
294
368
  if let backgroundColor = addToCartButtonConfiguration.backgroundColor,
295
369
  backgroundColor.count > 0 {
296
- productDetailsConfiguration.addToCartButton.backgroundColor = backgroundColor.uicolor()
370
+ productDetailsConfiguration.ctaButton.buttonConfiguration.backgroundColor = backgroundColor.uicolor()
297
371
  }
298
372
 
299
373
  if let textColor = addToCartButtonConfiguration.textColor,
300
374
  textColor.count > 0 {
301
- productDetailsConfiguration.addToCartButton.textColor = textColor.uicolor()
375
+ productDetailsConfiguration.ctaButton.buttonConfiguration.textColor = textColor.uicolor()
302
376
  }
303
377
 
304
378
  if let fontSize = addToCartButtonConfiguration.fontSize {
305
379
  let iOSFontInfo = addToCartButtonConfiguration.iOSFontInfo ?? FontInfo()
306
- productDetailsConfiguration.addToCartButton.font = iOSFontInfo.getFont(fontSize)
380
+ productDetailsConfiguration.ctaButton.buttonConfiguration.font = iOSFontInfo.getFont(fontSize)
307
381
  }
308
382
  }
309
383
 
@@ -381,5 +455,4 @@ extension ShoppingModule {
381
455
  }
382
456
  return result
383
457
  }
384
-
385
458
  }
@@ -0,0 +1,24 @@
1
+ require 'json'
2
+
3
+ packageJsonPath = File.expand_path("#{__dir__}/../../../package.json")
4
+ package = JSON.parse(File.read(packageJsonPath))
5
+
6
+ Pod::Spec.new do |s|
7
+ s.name = 'FWMultiHostStreaming'
8
+ s.version = package['version']
9
+ s.summary = 'Firework Multi Host Streaming'
10
+ s.homepage = package['homepage']
11
+ s.license = 'Apache License, Version 2.0'
12
+ s.authors = package['author']
13
+
14
+ s.platforms = { ios: '13.0' }
15
+ s.source = { git: 'https://github.com/loopsocial/bogano.git', tag: "#{s.version}" }
16
+
17
+ s.swift_version = '5.0'
18
+ s.source_files = 'src/*.{h,m,mm,swift}', 'src/**/*.{h,m,mm,swift}'
19
+
20
+ s.dependency 'AgoraRtcEngine_iOS', '~> 4.1.1'
21
+ s.dependency 'SwiftProtobuf', '~> 1.21.0'
22
+ s.dependency 'FireworkVideoAgoraSupport', '~> 0.2.0'
23
+ s.dependency 'FireworkVideo'
24
+ end
@@ -0,0 +1,17 @@
1
+ //
2
+ // FireworkMultiHostStreaming.swift
3
+ //
4
+ // Created by linjie jiang on 3/31/23.
5
+ //
6
+
7
+ import Foundation
8
+
9
+ import FireworkVideo
10
+ import FireworkVideoAgoraSupport
11
+
12
+ @objc
13
+ public class MultiHostStreamingSDK: NSObject {
14
+ @objc public static func enableMultiHostStreaming() {
15
+ FireworkVideoSDK.enableMultiHostPlayback()
16
+ }
17
+ }
@@ -0,0 +1,58 @@
1
+ //
2
+ // Bundle+FWSwizzle.swift
3
+ //
4
+ // Created by linjie jiang on 2023/2/7.
5
+ //
6
+
7
+ import Foundation
8
+ import FireworkVideo
9
+
10
+ public extension Bundle {
11
+ static func swizzleMethodsForBundle() {
12
+ FWSwizzleUtil.swizzleSelector(
13
+ cls: self,
14
+ originalSelector: #selector(Bundle.localizedString(forKey:value:table:)),
15
+ customSelector: #selector(Bundle.fw_localizedString(forKey:value:table:)))
16
+ }
17
+
18
+ @objc func fw_localizedString(
19
+ forKey key: String,
20
+ value: String?,
21
+ table tableName: String?
22
+ ) -> String {
23
+ if let language = FWAppLanguageManager.shared.appLanguage,
24
+ let languageCode = FWAppLanguageManager.shared.appLanguageCode,
25
+ Bundle(for: FireworkVideoSDK.self) == self {
26
+ let iOSSDKBundle = Bundle(for: FireworkVideoSDK.self)
27
+
28
+ var languageBundlePath: String?
29
+ let defaultLanguageBundlePath = iOSSDKBundle.path(forResource: "Base", ofType: "lproj")
30
+ if languageCode == "en" {
31
+ languageBundlePath = defaultLanguageBundlePath
32
+ } else if let path = iOSSDKBundle.path(forResource: language, ofType: "lproj") {
33
+ languageBundlePath = path
34
+ } else if let path = iOSSDKBundle.path(forResource: languageCode, ofType: "lproj") {
35
+ languageBundlePath = path
36
+ } else {
37
+ let targeLanguageList = iOSSDKBundle.localizations.filter { item in
38
+ return item != "Base" && item != "en"
39
+ }
40
+ if let targeLanguage = targeLanguageList.first(where: { item in
41
+ let targeLanguageCode = FWLanguageUtil.getLanguageCode(item)
42
+ return languageCode == targeLanguageCode
43
+ }) {
44
+ languageBundlePath = iOSSDKBundle.path(forResource: targeLanguage, ofType: "lproj")
45
+ }
46
+ }
47
+
48
+ if let resultLanguageBundlePath = languageBundlePath ?? defaultLanguageBundlePath,
49
+ let resultLanguageBundle = Bundle(path: resultLanguageBundlePath) {
50
+ return resultLanguageBundle.fw_localizedString(forKey: key, value: value, table: tableName)
51
+ } else {
52
+ return self.fw_localizedString(forKey: key, value: value, table: tableName)
53
+ }
54
+ } else {
55
+ return self.fw_localizedString(forKey: key, value: value, table: tableName)
56
+ }
57
+ }
58
+ }