react-native-firework-sdk 1.0.0-beta

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 (190) hide show
  1. package/README.md +39 -0
  2. package/android/build.gradle +193 -0
  3. package/android/gradle/wrapper/gradle-wrapper.jar +0 -0
  4. package/android/gradle/wrapper/gradle-wrapper.properties +5 -0
  5. package/android/gradle.properties +5 -0
  6. package/android/gradlew +185 -0
  7. package/android/gradlew.bat +89 -0
  8. package/android/publish.gradle +65 -0
  9. package/android/src/main/AndroidManifest.xml +16 -0
  10. package/android/src/main/java/com/reactnativefireworksdk/FireworkSDKPackage.kt +20 -0
  11. package/android/src/main/java/com/reactnativefireworksdk/components/videofeed/FWVideoFeed.kt +123 -0
  12. package/android/src/main/java/com/reactnativefireworksdk/constants/FWCommandConstant.kt +6 -0
  13. package/android/src/main/java/com/reactnativefireworksdk/constants/FWVideoPlayerConstant.kt +20 -0
  14. package/android/src/main/java/com/reactnativefireworksdk/manager/FWVideoFeedManager.kt +88 -0
  15. package/android/src/main/java/com/reactnativefireworksdk/models/FWEventName.kt +35 -0
  16. package/android/src/main/java/com/reactnativefireworksdk/models/FWVideoFeedConfigModel.kt +27 -0
  17. package/android/src/main/java/com/reactnativefireworksdk/models/FWVideoFeedItemDetailsModel.kt +11 -0
  18. package/android/src/main/java/com/reactnativefireworksdk/models/FWVideoFeedMode.kt +7 -0
  19. package/android/src/main/java/com/reactnativefireworksdk/models/FWVideoFeedSource.kt +7 -0
  20. package/android/src/main/java/com/reactnativefireworksdk/models/FWVideoFeedTitlePosition.kt +7 -0
  21. package/android/src/main/java/com/reactnativefireworksdk/models/FWVideoPlaybackDetails.kt +19 -0
  22. package/android/src/main/java/com/reactnativefireworksdk/models/FWVideoPlayerConfigModel.kt +20 -0
  23. package/android/src/main/java/com/reactnativefireworksdk/models/FWVideoShoppingInterface.kt +13 -0
  24. package/android/src/main/java/com/reactnativefireworksdk/models/FWVideoShoppingProduct.kt +34 -0
  25. package/android/src/main/java/com/reactnativefireworksdk/models/FireworkSDKInterface.kt +12 -0
  26. package/android/src/main/java/com/reactnativefireworksdk/module/FWVideoShoppingModule.kt +190 -0
  27. package/android/src/main/java/com/reactnativefireworksdk/module/FireworkSDKModule.kt +248 -0
  28. package/android/src/main/java/com/reactnativefireworksdk/pages/FWVideoShoppingCartActivity.kt +43 -0
  29. package/android/src/main/java/com/reactnativefireworksdk/utils/FWEventUtils.kt +127 -0
  30. package/android/src/main/java/com/reactnativefireworksdk/utils/FWJsonUtils.kt +57 -0
  31. package/android/src/main/java/com/reactnativefireworksdk/utils/FWLogUtils.kt +147 -0
  32. package/android/src/main/java/com/reactnativefireworksdk/utils/FWUrlUtils.kt +68 -0
  33. package/android/src/main/java/com/reactnativefireworksdk/utils/FWVideoPlayerUtils.kt +18 -0
  34. package/android/src/main/res/layout/fwrn_fragment_shoppingcart.xml +8 -0
  35. package/android/src/main/res/layout/fwrn_fragment_videofeed.xml +20 -0
  36. package/android/src/main/res/values/styles.xml +43 -0
  37. package/ios/Component/VideoFeed.swift +262 -0
  38. package/ios/Component/VideoFeedConfiguration.swift +32 -0
  39. package/ios/Component/VideoFeedManager.m +51 -0
  40. package/ios/Component/VideoFeedManager.swift +40 -0
  41. package/ios/Component/VideoPlayerConfiguration.swift +30 -0
  42. package/ios/FireworkSdk-Bridging-Header.h +6 -0
  43. package/ios/FireworkSdk.xcodeproj/project.pbxproj +291 -0
  44. package/ios/Models/FireworkJsEvent.swift +34 -0
  45. package/ios/Models/FireworkSDK+JsModel.swift +62 -0
  46. package/ios/Models/RCTConvert+FireworkSDKModule.swift +91 -0
  47. package/ios/Models/RCTConvert+Shopping.swift +49 -0
  48. package/ios/Models/RCTConvert+VideoFeed.swift +69 -0
  49. package/ios/Modules/FireworkSDKModule/FireworkSDKModule+CTA.swift +17 -0
  50. package/ios/Modules/FireworkSDKModule/FireworkSDKModule+EventTracking.swift +74 -0
  51. package/ios/Modules/FireworkSDKModule/FireworkSDKModule.m +19 -0
  52. package/ios/Modules/FireworkSDKModule/FireworkSDKModule.swift +106 -0
  53. package/ios/Modules/FireworkSDKModule/MobileADConfiguration.swift +17 -0
  54. package/ios/Modules/Shopping/CartViewController.swift +98 -0
  55. package/ios/Modules/Shopping/Product.swift +33 -0
  56. package/ios/Modules/Shopping/ProductInfoViewConfiguration.swift +24 -0
  57. package/ios/Modules/Shopping/ShoppingModule.m +19 -0
  58. package/ios/Modules/Shopping/ShoppingModule.swift +214 -0
  59. package/ios/Utils/String+Color.swift +38 -0
  60. package/ios/Utils/UIView+Constraints.swift +91 -0
  61. package/ios/Utils/UIView+ParentViewController.swift +21 -0
  62. package/ios/Utils/UIViewController+AttachChild.swift +69 -0
  63. package/lib/commonjs/FireworkSDK.js +171 -0
  64. package/lib/commonjs/FireworkSDK.js.map +1 -0
  65. package/lib/commonjs/VideoShopping.js +146 -0
  66. package/lib/commonjs/VideoShopping.js.map +1 -0
  67. package/lib/commonjs/components/CartContainer.js +35 -0
  68. package/lib/commonjs/components/CartContainer.js.map +1 -0
  69. package/lib/commonjs/components/FWVideoFeed.js +18 -0
  70. package/lib/commonjs/components/FWVideoFeed.js.map +1 -0
  71. package/lib/commonjs/components/VideoFeed.js +82 -0
  72. package/lib/commonjs/components/VideoFeed.js.map +1 -0
  73. package/lib/commonjs/constants/FWErrorMessage.js +15 -0
  74. package/lib/commonjs/constants/FWErrorMessage.js.map +1 -0
  75. package/lib/commonjs/index.js +44 -0
  76. package/lib/commonjs/index.js.map +1 -0
  77. package/lib/commonjs/models/ADConfig.js +2 -0
  78. package/lib/commonjs/models/ADConfig.js.map +1 -0
  79. package/lib/commonjs/models/AddToCartResult.js +2 -0
  80. package/lib/commonjs/models/AddToCartResult.js.map +1 -0
  81. package/lib/commonjs/models/FWError.js +2 -0
  82. package/lib/commonjs/models/FWError.js.map +1 -0
  83. package/lib/commonjs/models/FWEvents.js +20 -0
  84. package/lib/commonjs/models/FWEvents.js.map +1 -0
  85. package/lib/commonjs/models/FeedItemDetails.js +2 -0
  86. package/lib/commonjs/models/FeedItemDetails.js.map +1 -0
  87. package/lib/commonjs/models/Product.js +2 -0
  88. package/lib/commonjs/models/Product.js.map +1 -0
  89. package/lib/commonjs/models/ProductInfoViewConfiguration.js +2 -0
  90. package/lib/commonjs/models/ProductInfoViewConfiguration.js.map +1 -0
  91. package/lib/commonjs/models/ProductUnit.js +2 -0
  92. package/lib/commonjs/models/ProductUnit.js.map +1 -0
  93. package/lib/commonjs/models/VideoFeedConfiguration.js +2 -0
  94. package/lib/commonjs/models/VideoFeedConfiguration.js.map +1 -0
  95. package/lib/commonjs/models/VideoPlaybackDetails.js +2 -0
  96. package/lib/commonjs/models/VideoPlaybackDetails.js.map +1 -0
  97. package/lib/commonjs/models/VideoPlaybackEventName.js +23 -0
  98. package/lib/commonjs/models/VideoPlaybackEventName.js.map +1 -0
  99. package/lib/commonjs/models/VideoPlayerConfiguration.js +2 -0
  100. package/lib/commonjs/models/VideoPlayerConfiguration.js.map +1 -0
  101. package/lib/commonjs/modules/FireworkSDKModule.js +20 -0
  102. package/lib/commonjs/modules/FireworkSDKModule.js.map +1 -0
  103. package/lib/commonjs/modules/ShoppingModule.js +20 -0
  104. package/lib/commonjs/modules/ShoppingModule.js.map +1 -0
  105. package/lib/module/FireworkSDK.js +153 -0
  106. package/lib/module/FireworkSDK.js.map +1 -0
  107. package/lib/module/VideoShopping.js +134 -0
  108. package/lib/module/VideoShopping.js.map +1 -0
  109. package/lib/module/components/CartContainer.js +18 -0
  110. package/lib/module/components/CartContainer.js.map +1 -0
  111. package/lib/module/components/FWVideoFeed.js +8 -0
  112. package/lib/module/components/FWVideoFeed.js.map +1 -0
  113. package/lib/module/components/VideoFeed.js +66 -0
  114. package/lib/module/components/VideoFeed.js.map +1 -0
  115. package/lib/module/constants/FWErrorMessage.js +7 -0
  116. package/lib/module/constants/FWErrorMessage.js.map +1 -0
  117. package/lib/module/index.js +10 -0
  118. package/lib/module/index.js.map +1 -0
  119. package/lib/module/models/ADConfig.js +2 -0
  120. package/lib/module/models/ADConfig.js.map +1 -0
  121. package/lib/module/models/AddToCartResult.js +2 -0
  122. package/lib/module/models/AddToCartResult.js.map +1 -0
  123. package/lib/module/models/FWError.js +2 -0
  124. package/lib/module/models/FWError.js.map +1 -0
  125. package/lib/module/models/FWEvents.js +13 -0
  126. package/lib/module/models/FWEvents.js.map +1 -0
  127. package/lib/module/models/FeedItemDetails.js +2 -0
  128. package/lib/module/models/FeedItemDetails.js.map +1 -0
  129. package/lib/module/models/Product.js +2 -0
  130. package/lib/module/models/Product.js.map +1 -0
  131. package/lib/module/models/ProductInfoViewConfiguration.js +2 -0
  132. package/lib/module/models/ProductInfoViewConfiguration.js.map +1 -0
  133. package/lib/module/models/ProductUnit.js +2 -0
  134. package/lib/module/models/ProductUnit.js.map +1 -0
  135. package/lib/module/models/VideoFeedConfiguration.js +2 -0
  136. package/lib/module/models/VideoFeedConfiguration.js.map +1 -0
  137. package/lib/module/models/VideoPlaybackDetails.js +2 -0
  138. package/lib/module/models/VideoPlaybackDetails.js.map +1 -0
  139. package/lib/module/models/VideoPlaybackEventName.js +16 -0
  140. package/lib/module/models/VideoPlaybackEventName.js.map +1 -0
  141. package/lib/module/models/VideoPlayerConfiguration.js +2 -0
  142. package/lib/module/models/VideoPlayerConfiguration.js.map +1 -0
  143. package/lib/module/modules/FireworkSDKModule.js +10 -0
  144. package/lib/module/modules/FireworkSDKModule.js.map +1 -0
  145. package/lib/module/modules/ShoppingModule.js +10 -0
  146. package/lib/module/modules/ShoppingModule.js.map +1 -0
  147. package/lib/typescript/FireworkSDK.d.ts +74 -0
  148. package/lib/typescript/VideoShopping.d.ts +54 -0
  149. package/lib/typescript/components/CartContainer.d.ts +3 -0
  150. package/lib/typescript/components/FWVideoFeed.d.ts +2 -0
  151. package/lib/typescript/components/VideoFeed.d.ts +53 -0
  152. package/lib/typescript/constants/FWErrorMessage.d.ts +2 -0
  153. package/lib/typescript/index.d.ts +25 -0
  154. package/lib/typescript/models/ADConfig.d.ts +10 -0
  155. package/lib/typescript/models/AddToCartResult.d.ts +10 -0
  156. package/lib/typescript/models/FWError.d.ts +10 -0
  157. package/lib/typescript/models/FWEvents.d.ts +55 -0
  158. package/lib/typescript/models/FeedItemDetails.d.ts +14 -0
  159. package/lib/typescript/models/Product.d.ts +19 -0
  160. package/lib/typescript/models/ProductInfoViewConfiguration.d.ts +18 -0
  161. package/lib/typescript/models/ProductUnit.d.ts +22 -0
  162. package/lib/typescript/models/VideoFeedConfiguration.d.ts +32 -0
  163. package/lib/typescript/models/VideoPlaybackDetails.d.ts +31 -0
  164. package/lib/typescript/models/VideoPlaybackEventName.d.ts +39 -0
  165. package/lib/typescript/models/VideoPlayerConfiguration.d.ts +25 -0
  166. package/lib/typescript/modules/FireworkSDKModule.d.ts +12 -0
  167. package/lib/typescript/modules/ShoppingModule.d.ts +13 -0
  168. package/package.json +147 -0
  169. package/react-native-firework-sdk.podspec +22 -0
  170. package/src/FireworkSDK.ts +153 -0
  171. package/src/VideoShopping.ts +165 -0
  172. package/src/components/CartContainer.tsx +20 -0
  173. package/src/components/FWVideoFeed.tsx +10 -0
  174. package/src/components/VideoFeed.tsx +109 -0
  175. package/src/constants/FWErrorMessage.ts +11 -0
  176. package/src/index.tsx +109 -0
  177. package/src/models/ADConfig.ts +10 -0
  178. package/src/models/AddToCartResult.ts +10 -0
  179. package/src/models/FWError.ts +10 -0
  180. package/src/models/FWEvents.ts +63 -0
  181. package/src/models/FeedItemDetails.ts +14 -0
  182. package/src/models/Product.ts +20 -0
  183. package/src/models/ProductInfoViewConfiguration.ts +20 -0
  184. package/src/models/ProductUnit.ts +23 -0
  185. package/src/models/VideoFeedConfiguration.ts +35 -0
  186. package/src/models/VideoPlaybackDetails.ts +33 -0
  187. package/src/models/VideoPlaybackEventName.ts +40 -0
  188. package/src/models/VideoPlayerConfiguration.ts +26 -0
  189. package/src/modules/FireworkSDKModule.ts +27 -0
  190. package/src/modules/ShoppingModule.ts +29 -0
@@ -0,0 +1,19 @@
1
+ //
2
+ // VideoFeedManager.m
3
+ // react-native-firework-sdk
4
+ //
5
+ // Created by Jeff Zheng on 2021/12/22.
6
+ //
7
+ // The FireworkSDKModule exposes instances of Objective-C (native) classes to JavaScript (JS) as JS objects
8
+
9
+ #import <React/RCTBridgeModule.h>
10
+
11
+ @interface RCT_EXTERN_REMAP_MODULE(FireworkSDK, FireworkSDKModule, NSObject)
12
+
13
+ _RCT_EXTERN_REMAP_METHOD(init, initializeSDK:(NSString * __nullable)userId config:(NSDictionary *__nullable)config, NO)
14
+ RCT_EXTERN_METHOD(openVideoPlayer:(NSString *)url config:(NSDictionary *)config)
15
+ RCT_EXTERN_METHOD(setCustomCTAClickEnabled:(BOOL)enabled)
16
+ RCT_EXTERN_METHOD(setShareBaseURL:(NSString *)url)
17
+ RCT_EXTERN_METHOD(setVideoPlaybackEventEnabled:(BOOL)enabled)
18
+
19
+ @end
@@ -0,0 +1,106 @@
1
+ //
2
+ // VideoFeedManager.m
3
+ // react-native-firework-sdk
4
+ //
5
+ // Created by Jeff Zheng on 2021/12/22.
6
+ //
7
+ // The FireworkSDKModule Wrap native FireworkVideoSDK class,then expose to JavaScript in Objective-C
8
+
9
+
10
+ import FireworkVideo
11
+
12
+ #if canImport(FireworkVideoGAMSupport)
13
+ import FireworkVideoGAMSupportSDK
14
+ #endif
15
+ #if canImport(FireworkVideoGIMASupport)
16
+ import FireworkVideoGIMASupport
17
+ #endif
18
+
19
+ var gShareBaseURL: String?
20
+
21
+ @objc(FireworkSDKModule)
22
+ class FireworkSDKModule: RCTEventEmitter, FireworkVideoSDKDelegate {
23
+ // var shareBaseURL: String?
24
+ var customCTAClickEnabled: Bool = false
25
+
26
+ /// Decide whether to send video playback event to RN.
27
+ var enableVideoPlayBackEvent: Bool = false
28
+
29
+ override func supportedEvents() -> [String]! {
30
+ FWEventName.allCases.map { $0.rawValue }
31
+ }
32
+
33
+ override class func requiresMainQueueSetup() -> Bool {
34
+ return true
35
+ }
36
+
37
+ @objc(initializeSDK:config:)
38
+ func initializeSDK(_ userId: String? = nil, config: [String: AnyObject]? = nil) {
39
+ DispatchQueue.main.async {
40
+ FireworkVideoSDK.initializeSDK(delegate: self, userID: userId)
41
+ FireworkVideoSDK.ctaDelegate = self
42
+ FireworkVideoSDK.eventTracking.videoPlaybackDelegate = self
43
+ FireworkVideoSDK.eventTracking.feedDelegate = self
44
+
45
+ if let config = RCTConvert.mobileADConfiguration(config) {
46
+ switch config.type {
47
+ case .admob:
48
+ #if canImport(FireworkVideoGAMSupport)
49
+ if let startMobileAds = config.startMobileAds {
50
+ FireworkVideoGAMSupportSDK.initializeSDK()
51
+ } else {
52
+ FireworkVideoGAMSupportSDK.initializeSDK(startGADMobileAds: false)
53
+ }
54
+ #endif
55
+ case .ima:
56
+ #if canImport(FireworkVideoGIMASupport)
57
+ FireworkVideoGIMASupportSDK.enableIMAAds()
58
+ #endif
59
+ default:
60
+ break
61
+ }
62
+ }
63
+ }
64
+ }
65
+
66
+ @objc(openVideoPlayer:config:)
67
+ func openVideoPlayer(_ url: String, config: [String:AnyObject]) {
68
+ var finalConfig = RCTConvert.videoPlayerContentConfiguration(config)
69
+ if let baseUrl = gShareBaseURL {
70
+ finalConfig.shareButton.behavior.baseURL = URL(string: baseUrl)
71
+ }
72
+
73
+ DispatchQueue.main.async {
74
+ guard let presentedVC = RCTPresentedViewController() else {
75
+ return
76
+ }
77
+ VideoFeedViewController.openVideoPlayer(with: url, finalConfig, presentedVC) { _ in
78
+
79
+ }
80
+ }
81
+ }
82
+
83
+ @objc(setCustomCTAClickEnabled:)
84
+ func setCustomCTAClickEnabled(_ enabled: Bool) {
85
+ customCTAClickEnabled = enabled
86
+ }
87
+
88
+ @objc(setShareBaseURL:)
89
+ func setShareBaseURL(_ url: String) {
90
+ gShareBaseURL = url
91
+ }
92
+
93
+ @objc(setVideoPlaybackEventEnabled:)
94
+ func setVideoPlaybackEventEnabled(_ enable: Bool) {
95
+ enableVideoPlayBackEvent = enable
96
+ }
97
+
98
+ // MARK: - FireworkVideoSDKDelegate
99
+ func fireworkVideoDidLoadSuccessfully() {
100
+ sendEvent(withName: FWEventName.SDKInit.rawValue, body: [:])
101
+ }
102
+
103
+ func fireworkVideoDidLoadWith(error: FireworkVideoSDKError) {
104
+ sendEvent(withName: FWEventName.SDKInit.rawValue, body: ["error": [error.jsErrorName: error.recoverySuggestion ?? "default"]])
105
+ }
106
+ }
@@ -0,0 +1,17 @@
1
+ //
2
+ // MobileADConfiguration.swift
3
+ // react-native-firework-sdk
4
+ //
5
+ // Created by Jeff Zheng on 2022/1/5.
6
+ //
7
+
8
+ import Foundation
9
+
10
+ struct MobileADConfiguration: Codable {
11
+ var type: ADType = .none
12
+ var startMobileAds: Bool? = true
13
+
14
+ enum ADType: String, Codable {
15
+ case none, admob, ima
16
+ }
17
+ }
@@ -0,0 +1,98 @@
1
+ //
2
+ // CartViewController.swift
3
+ // react-native-firework-sdk
4
+ //
5
+ // Created by Jeff Zheng on 2021/12/31.
6
+ //
7
+
8
+ import UIKit
9
+ import FireworkVideo
10
+
11
+ class CartViewController: UIViewController, CartViewRepresentable {
12
+ var indicator: UIActivityIndicatorView? = nil
13
+ var callbackId: Int!
14
+ var directShowCartPage = false
15
+
16
+ init(callbackId: Int) {
17
+ self.callbackId = callbackId
18
+
19
+ super.init(nibName: nil, bundle: nil)
20
+
21
+ NotificationCenter.default.addObserver(self, selector: #selector(showCustomCartView), name: Notification.Name(rawValue: "showCustomCartView"), object: nil)
22
+ }
23
+
24
+ required init?(coder: NSCoder) {
25
+ super.init(coder: coder)
26
+ }
27
+
28
+ override func viewWillAppear(_ animated: Bool) {
29
+ super.viewWillAppear(animated)
30
+
31
+ self.navigationController?.setNavigationBarHidden(true, animated: true)
32
+ }
33
+
34
+ override func viewDidLoad() {
35
+ super.viewDidLoad()
36
+
37
+ if directShowCartPage {
38
+ directShowCustomCartView()
39
+ } else {
40
+ setupIndicatorView()
41
+ }
42
+ }
43
+
44
+ override func viewWillDisappear(_ animated: Bool) {
45
+ super.viewWillDisappear(animated)
46
+
47
+
48
+ self.navigationController?.setNavigationBarHidden(false, animated: true)
49
+ }
50
+
51
+ @objc func showCustomCartView(_ noti: NSNotification) {
52
+ guard let cbId = noti.userInfo?["cbid"] as? Int, callbackId == cbId else {
53
+ return
54
+ }
55
+
56
+ if isViewLoaded {
57
+ directShowCustomCartView()
58
+ } else {
59
+ directShowCartPage = true
60
+ }
61
+ }
62
+
63
+ private func setupIndicatorView() {
64
+ let indicator = UIActivityIndicatorView(frame: .zero)
65
+ if #available(iOS 13.0, *) {
66
+ indicator.style = .large
67
+ } else {
68
+ indicator.style = .whiteLarge
69
+ }
70
+ indicator.color = UIColor.white
71
+ view.addSubview(indicator)
72
+ indicator.translatesAutoresizingMaskIntoConstraints = false
73
+
74
+ NSLayoutConstraint.activate([
75
+ indicator.centerXAnchor.constraint(equalTo: view.centerXAnchor),
76
+ indicator.centerYAnchor.constraint(equalTo: view.centerYAnchor)
77
+ ])
78
+
79
+ indicator.startAnimating()
80
+
81
+ self.indicator = indicator
82
+ }
83
+
84
+ private func directShowCustomCartView() {
85
+ indicator?.stopAnimating()
86
+
87
+ let rctRootView = RCTRootView.init(bridge: RCTBridge.current(), moduleName: "FWShoppingCartPage", initialProperties: nil)
88
+ view.addSubview(rctRootView)
89
+ rctRootView.translatesAutoresizingMaskIntoConstraints = false
90
+
91
+ NSLayoutConstraint.activate([
92
+ rctRootView.leftAnchor.constraint(equalTo: view.leftAnchor),
93
+ rctRootView.topAnchor.constraint(equalTo: view.topAnchor),
94
+ rctRootView.rightAnchor.constraint(equalTo: view.rightAnchor),
95
+ rctRootView.bottomAnchor.constraint(equalTo: view.bottomAnchor)
96
+ ])
97
+ }
98
+ }
@@ -0,0 +1,33 @@
1
+ //
2
+ // Product.swift
3
+ // react-native-firework-sdk
4
+ //
5
+ // Created by Jeff Zheng on 2021/12/30.
6
+ //
7
+
8
+ import Foundation
9
+
10
+ struct Product: Codable {
11
+ var productId: String
12
+ var name: String?
13
+ var description: String?
14
+ var units: [ProductUnit]?
15
+
16
+ struct ProductUnit: Codable {
17
+ var unitId: String
18
+ var name: String?
19
+ var price: Price?
20
+ var url: String?
21
+ var options: [VariantOption]?
22
+ }
23
+
24
+ struct Price: Codable {
25
+ var amount: Double?
26
+ var currencyCode: String?
27
+ }
28
+
29
+ struct VariantOption: Codable, Equatable {
30
+ var name: String?
31
+ var value: String?
32
+ }
33
+ }
@@ -0,0 +1,24 @@
1
+ //
2
+ // ProductInfoViewConfiguration.swift
3
+ // react-native-firework-sdk
4
+ //
5
+ // Created by Jeff Zheng on 2021/12/30.
6
+ //
7
+
8
+ import Foundation
9
+
10
+ struct ProductInfoViewConfiguration: Codable {
11
+ var cartIcon: CartIconConfiguration?
12
+ var addToCartButton: ButtonConfiguration?
13
+
14
+
15
+ struct CartIconConfiguration: Codable {
16
+ var isHidden: Bool? = false
17
+ }
18
+ struct ButtonConfiguration: Codable {
19
+ var backgroundColor: String?
20
+ var textColor: String?
21
+ var fontSize: Int?
22
+ }
23
+
24
+ }
@@ -0,0 +1,19 @@
1
+ //
2
+ // ShoppingModule.m
3
+ // react-native-firework-sdk
4
+ //
5
+ // Created by Jeff Zheng on 2021/12/30.
6
+ //
7
+
8
+ #import <React/RCTBridgeModule.h>
9
+
10
+ @interface RCT_EXTERN_REMAP_MODULE(ShoppingModule, ShoppingModule, NSObject)
11
+
12
+ _RCT_EXTERN_REMAP_METHOD(init, initialize, NO)
13
+ RCT_EXTERN_METHOD(updateVideoProduct:(NSDictionary *)product cbId:(nonnull NSNumber *)cbid)
14
+ RCT_EXTERN_METHOD(updateProductViewConfig:(NSDictionary *)config cbId:(nonnull NSNumber *)cbid)
15
+ RCT_EXTERN_METHOD(updateAddToCartStatus:(NSString *)res tips:(nullable NSString *)tips cbId:(nonnull NSNumber *)cbid)
16
+ RCT_EXTERN_METHOD(jumpToCartPage:(nonnull NSNumber *)cbid)
17
+ RCT_EXTERN_METHOD(exitCartPage)
18
+
19
+ @end
@@ -0,0 +1,214 @@
1
+ //
2
+ // File.swift
3
+ // react-native-firework-sdk
4
+ //
5
+ // Created by Jeff Zheng on 2021/12/30.
6
+ //
7
+
8
+ import Foundation
9
+ import FireworkVideo
10
+
11
+ @objc(ShoppingModule)
12
+ class ShoppingModule: RCTEventEmitter, FireworkVideoShoppingDelegate, CartViewControllerProviding {
13
+
14
+ private var productInfoViewConfigurator: (Int, ProductInfoViewConfigurable)?
15
+ private var addToCartHandler: (Int, AddToCartHandler)?
16
+ private var productHydrating: (Int, ProductHydrating)?
17
+ private var cartViewController: CartViewController?
18
+
19
+ override func supportedEvents() -> [String]! {
20
+ ShoppingEventName.allCases.map { $0.rawValue }
21
+ }
22
+
23
+ override class func requiresMainQueueSetup() -> Bool {
24
+ return true
25
+ }
26
+
27
+ private static func generateCallbackId() -> Int {
28
+ struct CBIdIncreasingFactor {
29
+ static var callbackId = 0
30
+ }
31
+
32
+ CBIdIncreasingFactor.callbackId += 1;
33
+ return CBIdIncreasingFactor.callbackId
34
+ }
35
+
36
+ @objc
37
+ func initialize() {
38
+ DispatchQueue.main.async {
39
+ FireworkVideoSDK.shopping.shoppingDelegate = self
40
+ FireworkVideoSDK.shopping.cartViewControllerProvider = self
41
+ }
42
+ }
43
+
44
+ @objc
45
+ func updateVideoProduct(_ product: [String: Any]?, cbId: NSNumber) {
46
+ let product = RCTConvert.buildProduct(product)
47
+ guard let product = product, let productHydrating = productHydrating, productHydrating.0 == Int(truncating: cbId) else {
48
+ return
49
+ }
50
+
51
+ DispatchQueue.main.async {
52
+ productHydrating.1.hydrateProduct(product.productId, { build in
53
+ return ShoppingModule.hydrateProduct(product, build)
54
+ })
55
+ }
56
+ }
57
+
58
+ @objc
59
+ func updateProductViewConfig(_ config: [String: Any]?, cbId: NSNumber) {
60
+ let config = RCTConvert.buildProductInfoViewConfiguration(config)
61
+ guard let config = config, let productInfoViewConfigurator = productInfoViewConfigurator, productInfoViewConfigurator.0 == Int(truncating: cbId) else {
62
+ return
63
+ }
64
+
65
+ DispatchQueue.main.async {
66
+ ShoppingModule.hydrateProductViewConfig(config, productInfoViewConfigurator.1)
67
+ }
68
+ }
69
+
70
+ @objc
71
+ func updateAddToCartStatus(_ res: String, tips: String?, cbId: NSNumber) {
72
+ guard let handler = addToCartHandler, handler.0 == Int(truncating: cbId) else {
73
+ return
74
+ }
75
+
76
+ DispatchQueue.main.async {
77
+ if res == "success" {
78
+ handler.1(.feedbackOnly(.success(message: tips ?? "success")))
79
+ } else {
80
+ handler.1(.feedbackOnly(.failure(message: tips ?? "failure")))
81
+ }
82
+ }
83
+ }
84
+
85
+ @objc
86
+ func jumpToCartPage(_ cbId: NSNumber) {
87
+ DispatchQueue.main.async {
88
+ let noti = Notification(name: Notification.Name(rawValue: "showCustomCartView"), object: nil, userInfo: ["cbid": Int(truncating: cbId)])
89
+ NotificationCenter.default.post(noti)
90
+ }
91
+ }
92
+
93
+ @objc
94
+ func exitCartPage() {
95
+ DispatchQueue.main.async {
96
+ self.cartViewController?.navigationController?.popViewController(animated: true)
97
+ self.cartViewController = nil
98
+ }
99
+ }
100
+
101
+ // MARK: - FireworkVideoShoppingDelegate
102
+ func fireworkShopping(_ fireworkShopping: FireworkVideoShopping, willDisplayProductInfo productInfoViewConfigurator: ProductInfoViewConfigurable, forVideo video: VideoDetails) {
103
+ let callbackId = ShoppingModule.generateCallbackId()
104
+ self.productInfoViewConfigurator = (callbackId, productInfoViewConfigurator)
105
+
106
+ sendEvent(withName: ShoppingEventName.WillDisplayProduct.rawValue, body: ["videoId": video.videoID, "callbackId": callbackId])
107
+ }
108
+
109
+ func fireworkShopping(_ fireworkShopping: FireworkVideoShopping, updateDetailsForProducts products: [ProductID], forVideo video: VideoDetails, _ productHydrator: ProductHydrating) {
110
+ let callbackId = ShoppingModule.generateCallbackId()
111
+ self.productHydrating = (callbackId, productHydrator)
112
+
113
+ for productId in products {
114
+ sendEvent(withName: ShoppingEventName.UpdateProductDetails.rawValue, body: ["productId": productId, "callbackId": callbackId])
115
+ }
116
+ }
117
+
118
+ func fireworkShopping(_ fireworkShopping: FireworkVideoShopping, addProductVariantToCart item: SelectedProductVariant, fromVideo video: VideoDetails, _ addToCartCompletionHandler: @escaping AddToCartHandler) {
119
+ let callbackId = ShoppingModule.generateCallbackId()
120
+ self.addToCartHandler = (callbackId, addToCartCompletionHandler)
121
+
122
+ sendEvent(withName: ShoppingEventName.AddToCart.rawValue, body: ["productId": item.productID, "unitId": item.unitID, "callbackId": callbackId])
123
+ }
124
+
125
+ // MARK: - CartViewControllerProviding
126
+ func cartViewController(for video: VideoDetails) -> FireworkVideo.CartViewController {
127
+ let callbackId = ShoppingModule.generateCallbackId()
128
+ sendEvent(withName: ShoppingEventName.ClickCartIcon.rawValue, body: ["callbackId": callbackId])
129
+
130
+ cartViewController = CartViewController(callbackId: callbackId)
131
+ return cartViewController!
132
+ }
133
+ }
134
+
135
+ private extension ShoppingModule {
136
+
137
+ static func hydrateProductViewConfig(_ config: ProductInfoViewConfiguration, _ productInfoViewConfigurator: ProductInfoViewConfigurable) {
138
+ if let cartIcon = config.cartIcon {
139
+ if let hidden = cartIcon.isHidden {
140
+ var config = productInfoViewConfigurator.shoppingCartIconConfiguration
141
+ config.isHidden = hidden
142
+ productInfoViewConfigurator.shoppingCartIconConfiguration = config
143
+ }
144
+ }
145
+ if let buttonConfiguration = config.addToCartButton {
146
+ var config = productInfoViewConfigurator.productDetailsConfiguration
147
+ if let backgroundColor = buttonConfiguration.backgroundColor {
148
+ config.addToCartButton.backgroundColor = backgroundColor.uicolor()
149
+ }
150
+ if let textColor = buttonConfiguration.textColor {
151
+ config.addToCartButton.textColor = textColor.uicolor()
152
+ }
153
+ if let fontSize = buttonConfiguration.fontSize {
154
+ config.addToCartButton.font = UIFont.systemFont(ofSize: CGFloat(fontSize))
155
+ }
156
+ productInfoViewConfigurator.productDetailsConfiguration = config
157
+ }
158
+ }
159
+
160
+ }
161
+
162
+ private extension ShoppingModule {
163
+
164
+ static func hydrateProduct(_ product: Product, _ pbuild: ProductBuilder) -> ProductBuilder {
165
+ if let name = product.name {
166
+ pbuild.name(name)
167
+ }
168
+ if let description = product.description {
169
+ pbuild.description(description)
170
+ }
171
+ if let variants = product.units {
172
+ for variant in variants {
173
+ pbuild.variant(variant.unitId) { pvBuild in
174
+ return ShoppingModule.buildVariant(variant, pvBuild)
175
+ }
176
+ }
177
+ }
178
+ return pbuild
179
+ }
180
+
181
+ static func buildVariant(_ variant: Product.ProductUnit, _ pvBuild: ProductVariantBuilder) -> ProductVariantBuilder {
182
+ if let name = variant.name {
183
+ pvBuild.name(name)
184
+ }
185
+ if let url = variant.url {
186
+ pvBuild.url(url)
187
+ }
188
+ if let price = variant.price {
189
+ if let amount = price.amount, let currencyCode = price.currencyCode {
190
+ pvBuild.formattedPrice(Decimal(amount), currencyCode: currencyCode)
191
+ }
192
+ }
193
+ let options = ShoppingModule.buildVariantOption(variant.options)
194
+ if let options = options {
195
+ pvBuild.options(options)
196
+ }
197
+ return pvBuild
198
+ }
199
+
200
+ static func buildVariantOption(_ options: [Product.VariantOption]?) -> [String: String]? {
201
+ guard let options = options else {
202
+ return nil
203
+ }
204
+ var result: [String: String] = [:]
205
+ for option in options {
206
+ guard let name = option.name, let value = option.value else {
207
+ continue
208
+ }
209
+ result[name] = value
210
+ }
211
+ return result
212
+ }
213
+
214
+ }
@@ -0,0 +1,38 @@
1
+ //
2
+ // UIColor+Hexadecimal.swift
3
+ // react-native-firework-sdk
4
+ //
5
+ // Created by Jeff Zheng on 2021/12/22.
6
+ //
7
+
8
+ import UIKit
9
+
10
+ extension String {
11
+
12
+ func uicolor(alpha: CGFloat = 1.0) -> UIColor {
13
+ var red: UInt64 = 0, green: UInt64 = 0, blue: UInt64 = 0
14
+ var hex = self
15
+ //
16
+ if hex.hasPrefix("0x") || hex.hasPrefix("0X") {
17
+ hex = String(hex[hex.index(hex.startIndex, offsetBy: 2)...])
18
+ } else if hex.hasPrefix("#") {
19
+ hex = String(hex[hex.index(hex.startIndex, offsetBy: 1)...])
20
+ }
21
+ //
22
+ if hex.count < 6 {
23
+ for _ in 0..<6-hex.count {
24
+ hex += "0"
25
+ }
26
+ }
27
+
28
+ // convert
29
+ // red
30
+ Scanner(string: String(hex[..<hex.index(hex.startIndex, offsetBy: 2)])).scanHexInt64(&red)
31
+ // green
32
+ Scanner(string: String(hex[hex.index(hex.startIndex, offsetBy: 2)..<hex.index(hex.startIndex, offsetBy: 4)])).scanHexInt64(&green)
33
+ // blue
34
+ Scanner(string: String(hex[hex.index(startIndex, offsetBy: 4)...])).scanHexInt64(&blue)
35
+
36
+ return UIColor(red: CGFloat(red)/255.0, green: CGFloat(green)/255.0, blue: CGFloat(blue)/255.0, alpha: alpha)
37
+ }
38
+ }
@@ -0,0 +1,91 @@
1
+ //
2
+ // View+CONTRAIT.swift
3
+ // react-native-firework-sdk
4
+ //
5
+ // Created by Jeff Zheng on 2021/12/30.
6
+ //
7
+
8
+ import Foundation
9
+
10
+ public struct LayoutDirection: OptionSet {
11
+ public let rawValue: Int
12
+
13
+ public init(rawValue: Int) {
14
+ self.rawValue = rawValue
15
+ }
16
+
17
+ public static let top = LayoutDirection(rawValue: 1 << 0)
18
+ public static let bottom = LayoutDirection(rawValue: 1 << 1)
19
+ public static let leading = LayoutDirection(rawValue: 1 << 2)
20
+ public static let trailing = LayoutDirection(rawValue: 1 << 3)
21
+
22
+ public static let horizontal: LayoutDirection = [.leading, .trailing]
23
+ public static let vertical: LayoutDirection = [.top, .bottom]
24
+
25
+ public static let all: LayoutDirection = [.horizontal, .vertical]
26
+ }
27
+
28
+ public extension UILayoutPriority {
29
+ static var almostRequired: UILayoutPriority {
30
+ return .required - 1
31
+ }
32
+ }
33
+
34
+ public extension NSLayoutConstraint {
35
+ func withPriority(_ new: UILayoutPriority) -> NSLayoutConstraint {
36
+ priority = new
37
+ return self
38
+ }
39
+ }
40
+
41
+ public extension UIView {
42
+ func setContentHuggingPriorities(_ new: UILayoutPriority) {
43
+ setContentHuggingPriority(new, for: .horizontal)
44
+ setContentHuggingPriority(new, for: .vertical)
45
+ }
46
+
47
+ func setContentCompressionResistancePriorities(_ new: UILayoutPriority) {
48
+ setContentCompressionResistancePriority(new, for: .horizontal)
49
+ setContentCompressionResistancePriority(new, for: .vertical)
50
+ }
51
+
52
+ func constraints(equalTo other: UIView, directions: LayoutDirection = .all,
53
+ priority: UILayoutPriority = .required) -> [NSLayoutConstraint] {
54
+ var constraints: [NSLayoutConstraint] = []
55
+ if directions.contains(.top) {
56
+ constraints.append(topAnchor.constraint(equalTo: other.topAnchor).withPriority(priority))
57
+ }
58
+ if directions.contains(.leading) {
59
+ constraints.append(leadingAnchor.constraint(equalTo: other.leadingAnchor).withPriority(priority))
60
+ }
61
+ if directions.contains(.bottom) {
62
+ constraints.append(bottomAnchor.constraint(equalTo: other.bottomAnchor).withPriority(priority))
63
+ }
64
+ if directions.contains(.trailing) {
65
+ constraints.append(trailingAnchor.constraint(equalTo: other.trailingAnchor).withPriority(priority))
66
+ }
67
+ return constraints
68
+ }
69
+
70
+ func constraints(equalTo layoutGuide: UILayoutGuide, directions: LayoutDirection = .all,
71
+ priority: UILayoutPriority = .required) -> [NSLayoutConstraint] {
72
+ var constraints: [NSLayoutConstraint] = []
73
+ if directions.contains(.top) {
74
+ constraints.append(topAnchor.constraint(equalTo: layoutGuide.topAnchor).withPriority(priority))
75
+ }
76
+ if directions.contains(.leading) {
77
+ constraints.append(leadingAnchor.constraint(equalTo: layoutGuide.leadingAnchor).withPriority(priority))
78
+ }
79
+ if directions.contains(.bottom) {
80
+ constraints.append(bottomAnchor.constraint(equalTo: layoutGuide.bottomAnchor).withPriority(priority))
81
+ }
82
+ if directions.contains(.trailing) {
83
+ constraints.append(trailingAnchor.constraint(equalTo: layoutGuide.trailingAnchor).withPriority(priority))
84
+ }
85
+ return constraints
86
+ }
87
+
88
+ var isRightToLeft: Bool {
89
+ return UIView.userInterfaceLayoutDirection(for: semanticContentAttribute) == .rightToLeft
90
+ }
91
+ }
@@ -0,0 +1,21 @@
1
+ //
2
+ // View+ParentViewController.swift
3
+ // react-native-firework-sdk
4
+ //
5
+ // Created by Jeff Zheng on 2021/12/22.
6
+ //
7
+
8
+ import UIKit
9
+
10
+ extension UIView {
11
+ var parentViewController: UIViewController? {
12
+ var parentResponder: UIResponder? = self
13
+ while parentResponder != nil {
14
+ parentResponder = parentResponder!.next
15
+ if let viewController = parentResponder as? UIViewController {
16
+ return viewController
17
+ }
18
+ }
19
+ return nil
20
+ }
21
+ }