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.
- package/android/build.gradle +1 -1
- package/android/src/main/java/com/fireworksdk/bridge/utils/FWLanguageUtil.kt +47 -14
- package/ios/Components/StoryBlock.swift +33 -2
- package/ios/Components/StoryBlockManager.m +32 -0
- package/ios/Components/VideoFeed.swift +10 -29
- package/ios/Components/VideoFeedManager.m +11 -6
- package/ios/FireworkSdk.xcodeproj/project.pbxproj +378 -204
- package/ios/Models/NativeToRN/FireworkEventName.swift +3 -1
- package/ios/Models/RNToNative/RCTConvert+Shopping.swift +21 -0
- package/ios/Models/RNToNative/RCTConvert+VideoFeed.swift +27 -0
- package/ios/Modules/FWNavigatorModule/FWNavigatorModule.swift +23 -5
- package/ios/Modules/FireworkSDKModule/FireworkSDKModule.m +1 -0
- package/ios/Modules/FireworkSDKModule/FireworkSDKModule.swift +31 -0
- package/ios/Modules/Shopping/ProductInfoViewConfiguration.swift +13 -0
- package/ios/Modules/Shopping/ShoppingCTAResult.swift +16 -0
- package/ios/Modules/Shopping/ShoppingModule.m +2 -1
- package/ios/Modules/Shopping/ShoppingModule.swift +103 -30
- package/ios/Support/MultiHostStreaming/FWMultiHostStreaming.podspec +24 -0
- package/ios/Support/MultiHostStreaming/src/MultiHostStreamingSDK.swift +17 -0
- package/ios/Utils/AppLanguage/Bundle+FWSwizzle.swift +58 -0
- package/ios/Utils/AppLanguage/FWAppLanguageManager.swift +139 -0
- package/ios/Utils/AppLanguage/FWLanguageUtil.swift +43 -0
- package/ios/Utils/AppLanguage/NumberFormatter+FWSwizzle.swift +25 -0
- package/ios/Utils/AppLanguage/UIImageView+FWSwizzle.swift +91 -0
- package/ios/Utils/AppLanguage/UILabel+FWSwizzle.swift +98 -0
- package/ios/Utils/AppLanguage/UITextField+FWSwizzle.swift +97 -0
- package/ios/Utils/AppLanguage/UITextView+FWSwizzle.swift +97 -0
- package/ios/Utils/AppLanguage/UIView+FWSwizzle.swift +38 -0
- package/ios/Utils/AppLanguage/UIViewController+FWSwizzle.swift +32 -0
- package/ios/Utils/AppLanguage/UIWindow+FWSwizzle.swift +26 -0
- package/ios/Utils/AppLanguage/URLSession+FWSwizzle.swift +69 -0
- package/ios/Utils/{DispatchQueue+FWOnce.swift → Extensions/DispatchQueue+FWOnce.swift} +3 -3
- package/ios/Utils/{UINavigationController+FWSwizzle.swift → Extensions/Swizzle/UINavigationController+FWSwizzle.swift} +6 -8
- package/ios/Utils/Extensions/UIView+FWUIHierarchy.swift +47 -0
- package/ios/Utils/FWRTL/Classes/Manager/FWRTLManager.h +25 -0
- package/ios/Utils/FWRTL/Classes/Manager/FWRTLManager.m +75 -0
- package/ios/Utils/FWRTL/Classes/UICategories/CALayer+FWRTL.h +21 -0
- package/ios/Utils/FWRTL/Classes/UICategories/CALayer+FWRTL.m +124 -0
- package/ios/Utils/FWRTL/Classes/UICategories/FWRTLRemoteViewControllerAdaptor.h +11 -0
- package/ios/Utils/FWRTL/Classes/UICategories/FWRTLRemoteViewControllerAdaptor.m +86 -0
- package/ios/Utils/FWRTL/Classes/UICategories/FWRTLWhiteListManager.h +16 -0
- package/ios/Utils/FWRTL/Classes/UICategories/FWRTLWhiteListManager.m +55 -0
- package/ios/Utils/FWRTL/Classes/UICategories/UILabel+FWRTL.h +18 -0
- package/ios/Utils/FWRTL/Classes/UICategories/UILabel+FWRTL.m +39 -0
- package/ios/Utils/FWRTL/Classes/UICategories/UIView+FWRTL.h +54 -0
- package/ios/Utils/FWRTL/Classes/UICategories/UIView+FWRTL.m +141 -0
- package/ios/Utils/FWRTL/Classes/UICategories/UIWindow+FWRTL.h +16 -0
- package/ios/Utils/FWRTL/Classes/UICategories/UIWindow+FWRTL.m +20 -0
- package/ios/Utils/FWRTL/Classes/Utils/FWRTLDefinitions.h +52 -0
- package/ios/Utils/FWRTL/Classes/Utils/NSObject+FWRTLReloadBlock.h +19 -0
- package/ios/Utils/FWRTL/Classes/Utils/NSObject+FWRTLReloadBlock.m +49 -0
- package/ios/Utils/FWRTL/Classes/Utils/NSString+FWRTL.h +21 -0
- package/ios/Utils/FWRTL/Classes/Utils/NSString+FWRTL.m +38 -0
- package/ios/Utils/FWRTL/Classes/Utils/UIImage+FWRTL.h +18 -0
- package/ios/Utils/FWRTL/Classes/Utils/UIImage+FWRTL.m +43 -0
- package/ios/Utils/FWSwizzleLoader.m +6 -1
- package/ios/Utils/FWSwizzleLoader.swift +13 -0
- package/ios/Utils/FWSwizzleUtil.swift +17 -9
- package/ios/react_native_firework_sdk.h +1 -0
- package/ios/scripts/react_native_firework_sdk_pods.rb +31 -0
- package/lib/commonjs/FWNavigator.js +2 -2
- package/lib/commonjs/FWNavigator.js.map +1 -1
- package/lib/commonjs/FireworkSDK.js +31 -6
- package/lib/commonjs/FireworkSDK.js.map +1 -1
- package/lib/commonjs/VideoShopping.js +71 -22
- package/lib/commonjs/VideoShopping.js.map +1 -1
- package/lib/commonjs/components/StoryBlock.js +156 -106
- package/lib/commonjs/components/StoryBlock.js.map +1 -1
- package/lib/commonjs/components/VideoFeed.js +37 -11
- package/lib/commonjs/components/VideoFeed.js.map +1 -1
- package/lib/commonjs/index.js +6 -0
- package/lib/commonjs/index.js.map +1 -1
- package/lib/commonjs/models/FWEventName.js +2 -0
- package/lib/commonjs/models/FWEventName.js.map +1 -1
- package/lib/commonjs/models/ShoppingCTAResult.js +2 -0
- package/lib/commonjs/models/ShoppingCTAResult.js.map +1 -0
- package/lib/commonjs/modules/FireworkSDKModule.js.map +1 -1
- package/lib/commonjs/modules/ShoppingModule.js.map +1 -1
- package/lib/module/FWNavigator.js +5 -2
- package/lib/module/FWNavigator.js.map +1 -1
- package/lib/module/FireworkSDK.js +31 -6
- package/lib/module/FireworkSDK.js.map +1 -1
- package/lib/module/VideoShopping.js +70 -23
- package/lib/module/VideoShopping.js.map +1 -1
- package/lib/module/components/StoryBlock.js +146 -103
- package/lib/module/components/StoryBlock.js.map +1 -1
- package/lib/module/components/VideoFeed.js +41 -10
- package/lib/module/components/VideoFeed.js.map +1 -1
- package/lib/module/index.js +1 -1
- package/lib/module/index.js.map +1 -1
- package/lib/module/models/FWEventName.js +2 -0
- package/lib/module/models/FWEventName.js.map +1 -1
- package/lib/module/models/ShoppingCTAResult.js +2 -0
- package/lib/module/models/ShoppingCTAResult.js.map +1 -0
- package/lib/module/modules/FireworkSDKModule.js.map +1 -1
- package/lib/module/modules/ShoppingModule.js.map +1 -1
- package/lib/typescript/FWNavigator.d.ts +6 -3
- package/lib/typescript/FireworkSDK.d.ts +20 -7
- package/lib/typescript/LiveStream.d.ts +2 -2
- package/lib/typescript/VideoShopping.d.ts +32 -11
- package/lib/typescript/components/StoryBlock.d.ts +21 -11
- package/lib/typescript/components/VideoFeed.d.ts +21 -5
- package/lib/typescript/index.d.ts +7 -4
- package/lib/typescript/models/AdBadgeConfiguration.d.ts +1 -1
- package/lib/typescript/models/AddToCartResult.d.ts +4 -0
- package/lib/typescript/models/FWEventName.d.ts +2 -0
- package/lib/typescript/models/FWEvents.d.ts +27 -0
- package/lib/typescript/models/IOSFontInfo.d.ts +2 -2
- package/lib/typescript/models/NewNativeContainerProps.d.ts +1 -1
- package/lib/typescript/models/ProductInfoViewConfiguration.d.ts +35 -0
- package/lib/typescript/models/ShoppingCTAResult.d.ts +11 -0
- package/lib/typescript/models/StoryBlockSource.d.ts +1 -1
- package/lib/typescript/models/VideoFeedConfiguration.d.ts +4 -3
- package/lib/typescript/models/VideoFeedSource.d.ts +1 -1
- package/lib/typescript/models/VideoPlayerConfiguration.d.ts +7 -5
- package/lib/typescript/modules/FireworkSDKModule.d.ts +1 -2
- package/lib/typescript/modules/ShoppingModule.d.ts +2 -0
- package/package.json +10 -6
- package/react-native-firework-sdk.podspec +26 -24
- package/src/FWNavigator.ts +6 -3
- package/src/FireworkSDK.ts +27 -8
- package/src/VideoShopping.ts +110 -41
- package/src/components/StoryBlock.tsx +158 -84
- package/src/components/VideoFeed.tsx +38 -9
- package/src/index.ts +21 -0
- package/src/models/AddToCartResult.ts +4 -0
- package/src/models/FWEventName.ts +2 -0
- package/src/models/FWEvents.ts +28 -0
- package/src/models/ProductInfoViewConfiguration.ts +37 -0
- package/src/models/ShoppingCTAResult.ts +11 -0
- package/src/models/VideoFeedConfiguration.ts +3 -2
- package/src/models/VideoPlayerConfiguration.ts +3 -1
- package/src/modules/FireworkSDKModule.ts +1 -2
- package/src/modules/ShoppingModule.ts +6 -1
- package/ios/Utils/UIView+ParentViewController.swift +0 -21
- /package/ios/Utils/{String+Color.swift → Extensions/String+Color.swift} +0 -0
- /package/ios/Utils/{UIView+Constraints.swift → Extensions/UIView+Constraints.swift} +0 -0
- /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
|
|
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
|
|
218
|
+
if let button = view as? UIButton, let image = button.image(for: .normal) {
|
|
214
219
|
let iOSSDKBundle = Bundle(for: FireworkVideoSDK.self)
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
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
|
|
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.
|
|
190
|
-
|
|
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
|
-
|
|
257
|
-
|
|
283
|
+
productVariantCTASelected item: SelectedProductVariant,
|
|
284
|
+
fromVideo video: VideoDetails,
|
|
285
|
+
ctaCompletionHandler: @escaping ShoppingCTAHandler
|
|
258
286
|
) {
|
|
259
287
|
let callbackId = ShoppingModule.generateCallbackId()
|
|
260
|
-
self.
|
|
261
|
-
|
|
288
|
+
self.shoppingCTAHandlerMap[callbackId] = ctaCompletionHandler
|
|
262
289
|
sendEvent(
|
|
263
|
-
withName: ShoppingEventName.
|
|
264
|
-
body: [
|
|
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
|
|
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.
|
|
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.
|
|
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.
|
|
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
|
+
}
|