react-native-firework-sdk 2.0.0 → 2.1.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 +5 -3
- package/android/src/main/java/com/fireworksdk/bridge/components/videofeed/StoryBlockFragment.kt +129 -0
- package/android/src/main/java/com/fireworksdk/bridge/components/videofeed/StoryBlockFrameLayout.kt +84 -0
- package/android/src/main/java/com/fireworksdk/bridge/models/FWEventName.kt +2 -1
- package/android/src/main/java/com/fireworksdk/bridge/models/FWProductInfoViewConfiguration.kt +18 -5
- package/android/src/main/java/com/fireworksdk/bridge/models/FWProductInfoViewConfigurationDeserializer.kt +33 -9
- package/android/src/main/java/com/fireworksdk/bridge/models/FWShoppingCtaResult.kt +17 -0
- package/android/src/main/java/com/fireworksdk/bridge/models/FWShoppingCtaResultDeserializer.kt +33 -0
- package/android/src/main/java/com/fireworksdk/bridge/reactnative/manager/FWStoryBlockManager.kt +126 -45
- package/android/src/main/java/com/fireworksdk/bridge/reactnative/manager/FWVideoFeedManager.kt +6 -3
- package/android/src/main/java/com/fireworksdk/bridge/reactnative/models/FWVideoShoppingInterface.kt +2 -2
- package/android/src/main/java/com/fireworksdk/bridge/reactnative/module/FWNavigatorModule.kt +9 -1
- package/android/src/main/java/com/fireworksdk/bridge/reactnative/module/FWVideoShoppingModule.kt +81 -50
- package/android/src/main/java/com/fireworksdk/bridge/reactnative/utils/FWEventUtils.kt +9 -2
- package/android/src/main/java/com/fireworksdk/bridge/utils/FWConfigUtil.kt +1 -1
- package/android/src/main/java/com/fireworksdk/bridge/utils/FWGlobalDataUtil.kt +4 -0
- package/android/src/main/java/com/fireworksdk/bridge/utils/FWLanguageUtil.kt +48 -16
- package/android/src/main/res/layout/fw_bridge_story_block.xml +24 -0
- package/ios/Components/StoryBlock.swift +33 -2
- package/ios/Components/StoryBlockManager.m +32 -0
- package/ios/Components/VideoFeed.swift +9 -29
- package/ios/Components/VideoFeedManager.m +11 -6
- package/ios/FireworkSdk.xcodeproj/project.pbxproj +378 -104
- 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 +5 -1
- package/ios/Modules/FireworkSDKModule/FireworkSDKModule.m +1 -0
- package/ios/Modules/FireworkSDKModule/FireworkSDKModule.swift +30 -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 +106 -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/FireworkSDK.js +21 -4
- package/lib/commonjs/FireworkSDK.js.map +1 -1
- package/lib/commonjs/VideoShopping.js +20 -37
- package/lib/commonjs/VideoShopping.js.map +1 -1
- package/lib/commonjs/components/StoryBlock.js +190 -125
- package/lib/commonjs/components/StoryBlock.js.map +1 -1
- package/lib/commonjs/components/VideoFeed.js +11 -1
- package/lib/commonjs/components/VideoFeed.js.map +1 -1
- 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/modules/FireworkSDKModule.js.map +1 -1
- package/lib/commonjs/modules/ShoppingModule.js.map +1 -1
- package/lib/module/FireworkSDK.js +21 -4
- package/lib/module/FireworkSDK.js.map +1 -1
- package/lib/module/VideoShopping.js +20 -39
- package/lib/module/VideoShopping.js.map +1 -1
- package/lib/module/components/StoryBlock.js +179 -131
- package/lib/module/components/StoryBlock.js.map +1 -1
- package/lib/module/components/VideoFeed.js +10 -1
- package/lib/module/components/VideoFeed.js.map +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/modules/FireworkSDKModule.js.map +1 -1
- package/lib/module/modules/ShoppingModule.js.map +1 -1
- package/lib/typescript/FireworkSDK.d.ts +7 -4
- package/lib/typescript/VideoShopping.d.ts +9 -11
- package/lib/typescript/components/StoryBlock.d.ts +19 -25
- package/lib/typescript/index.d.ts +6 -6
- package/lib/typescript/models/FWEventName.d.ts +2 -0
- package/lib/typescript/models/FWEvents.d.ts +14 -1
- package/lib/typescript/models/ProductInfoViewConfiguration.d.ts +36 -1
- package/lib/typescript/models/ShoppingCTAResult.d.ts +11 -0
- package/lib/typescript/modules/FireworkSDKModule.d.ts +1 -2
- package/lib/typescript/modules/ShoppingModule.d.ts +2 -1
- package/package.json +2 -2
- package/react-native-firework-sdk.podspec +26 -24
- package/src/FireworkSDK.ts +18 -5
- package/src/VideoShopping.ts +40 -53
- package/src/components/StoryBlock.tsx +199 -96
- package/src/components/VideoFeed.tsx +11 -0
- package/src/index.ts +15 -7
- package/src/models/FWEventName.ts +2 -0
- package/src/models/FWEvents.ts +14 -1
- package/src/models/ProductInfoViewConfiguration.ts +38 -1
- package/src/models/ShoppingCTAResult.ts +11 -0
- package/src/modules/FireworkSDKModule.ts +1 -2
- package/src/modules/ShoppingModule.ts +5 -5
- package/android/src/main/java/com/fireworksdk/bridge/constants/FWCommandConstant.kt +0 -6
- package/ios/Utils/UIView+ParentViewController.swift +0 -21
- package/lib/commonjs/models/AddToCartResult.js +0 -2
- package/lib/module/models/AddToCartResult.js +0 -2
- package/lib/typescript/models/AddToCartResult.d.ts +0 -10
- package/src/models/AddToCartResult.ts +0 -10
- /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
- /package/lib/commonjs/models/{AddToCartResult.js.map → ShoppingCTAResult.js.map} +0 -0
- /package/lib/module/models/{AddToCartResult.js.map → ShoppingCTAResult.js.map} +0 -0
package/src/FireworkSDK.ts
CHANGED
|
@@ -100,6 +100,11 @@ class FireworkSDK {
|
|
|
100
100
|
}
|
|
101
101
|
private _adBadgeConfiguration: AdBadgeConfiguration | undefined;
|
|
102
102
|
|
|
103
|
+
public get appLanguage(): string | undefined | null {
|
|
104
|
+
return this._appLanguage;
|
|
105
|
+
}
|
|
106
|
+
private _appLanguage: string | undefined | null;
|
|
107
|
+
|
|
103
108
|
/**
|
|
104
109
|
* Defaults to false.
|
|
105
110
|
* You can enable debug logs by setting this property to true.
|
|
@@ -245,13 +250,21 @@ class FireworkSDK {
|
|
|
245
250
|
}
|
|
246
251
|
|
|
247
252
|
/**
|
|
248
|
-
* Change App level language. Only supported on
|
|
249
|
-
* @param {string} language Such as en, ar and en-US
|
|
250
|
-
*
|
|
253
|
+
* Change App level language. Only supported on iOS.
|
|
254
|
+
* @param {string | undefined | null} language Such as en, ar and en-US
|
|
255
|
+
* If language is null or undefined or empty string, SDK will use system language.
|
|
256
|
+
* @returns {Promise<boolean>} The result of changing app language.
|
|
251
257
|
*/
|
|
252
|
-
public async changeAppLanguage(language
|
|
253
|
-
if (Platform.OS === '
|
|
258
|
+
public async changeAppLanguage(language?: string | null): Promise<boolean> {
|
|
259
|
+
if (Platform.OS === 'ios') {
|
|
254
260
|
const result = await FireworkSDKModule.changeAppLanguage(language);
|
|
261
|
+
if (result) {
|
|
262
|
+
const valueHasChanged = this._appLanguage !== language;
|
|
263
|
+
this._appLanguage = language;
|
|
264
|
+
if (valueHasChanged) {
|
|
265
|
+
this.eventEmitter.emit(FWEventName.AppLanguageUpdated);
|
|
266
|
+
}
|
|
267
|
+
}
|
|
255
268
|
return result;
|
|
256
269
|
}
|
|
257
270
|
|
package/src/VideoShopping.ts
CHANGED
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
import { NativeEventEmitter, Platform } from 'react-native';
|
|
2
2
|
|
|
3
|
-
import type AddToCartResult from './models/AddToCartResult';
|
|
4
3
|
import { FWEventName } from './models/FWEventName';
|
|
5
4
|
import type {
|
|
6
|
-
AddToCartEvent,
|
|
7
5
|
CustomClickLinkButtonEvent,
|
|
6
|
+
ShoppingCTAEvent,
|
|
8
7
|
UpdateProductDetailsEvent,
|
|
9
8
|
} from './models/FWEvents';
|
|
10
9
|
import type Product from './models/Product';
|
|
@@ -13,10 +12,11 @@ import ShoppingModule, {
|
|
|
13
12
|
ShoppingModuleEventEmitter,
|
|
14
13
|
} from './modules/ShoppingModule';
|
|
15
14
|
import FWLoggerUtil from './utils/FWLoggerUtil';
|
|
15
|
+
import type ShoppingCTAResult from './models/ShoppingCTAResult';
|
|
16
16
|
|
|
17
|
-
export type
|
|
18
|
-
event:
|
|
19
|
-
) => Promise<
|
|
17
|
+
export type ShoppingCTACallback = (
|
|
18
|
+
event: ShoppingCTAEvent
|
|
19
|
+
) => Promise<ShoppingCTAResult>;
|
|
20
20
|
|
|
21
21
|
export type CustomClickCartIconCallback = () => Promise<void>;
|
|
22
22
|
|
|
@@ -35,12 +35,10 @@ class VideoShopping {
|
|
|
35
35
|
private static _instance?: VideoShopping;
|
|
36
36
|
|
|
37
37
|
/**
|
|
38
|
-
* This callback is triggered when the user clicks the "Add to cart" button.
|
|
39
|
-
*
|
|
40
|
-
* The host apps can return an AddToCartResult object to tell FireworkSDK the result of adding to cart.
|
|
41
|
-
* If the host apps want to customize the processing logic of clicking "Add to cart" button, they could return null or undefined in the callback.
|
|
38
|
+
* This callback is triggered when the user clicks the "Add to cart" or "Shop now" button.
|
|
39
|
+
* The host app can return a ShoppingCTAResult object to tell SDK how to handle the result.
|
|
42
40
|
*/
|
|
43
|
-
public
|
|
41
|
+
public onShoppingCTA?: ShoppingCTACallback;
|
|
44
42
|
|
|
45
43
|
/**
|
|
46
44
|
* This callback is triggered when the user clicks the shopping cart icon.
|
|
@@ -82,8 +80,8 @@ class VideoShopping {
|
|
|
82
80
|
private _cartIconVisible: boolean = true;
|
|
83
81
|
|
|
84
82
|
/**
|
|
85
|
-
* The
|
|
86
|
-
*
|
|
83
|
+
* The configuration of product info view.
|
|
84
|
+
* Please refer to {@link ProductInfoViewConfiguration} for more details.
|
|
87
85
|
*/
|
|
88
86
|
public get productInfoViewConfiguration():
|
|
89
87
|
| ProductInfoViewConfiguration
|
|
@@ -95,9 +93,7 @@ class VideoShopping {
|
|
|
95
93
|
value: ProductInfoViewConfiguration | undefined
|
|
96
94
|
) {
|
|
97
95
|
this._productInfoViewConfiguration = value;
|
|
98
|
-
|
|
99
|
-
ShoppingModule.setProductInfoViewConfiguration(value ?? {});
|
|
100
|
-
}
|
|
96
|
+
ShoppingModule.setProductInfoViewConfiguration(value ?? {});
|
|
101
97
|
}
|
|
102
98
|
|
|
103
99
|
private _productInfoViewConfiguration?:
|
|
@@ -120,9 +116,7 @@ class VideoShopping {
|
|
|
120
116
|
value: CustomClickLinkButtonCallback | undefined
|
|
121
117
|
) {
|
|
122
118
|
this._onCustomClickLinkButton = value;
|
|
123
|
-
|
|
124
|
-
ShoppingModule.setCustomClickLinkButtonEnabled(!!value);
|
|
125
|
-
}
|
|
119
|
+
ShoppingModule.setCustomClickLinkButtonEnabled(!!value);
|
|
126
120
|
}
|
|
127
121
|
private _onCustomClickLinkButton?: CustomClickLinkButtonCallback | undefined;
|
|
128
122
|
|
|
@@ -140,12 +134,15 @@ class VideoShopping {
|
|
|
140
134
|
}
|
|
141
135
|
|
|
142
136
|
private constructor() {
|
|
143
|
-
this.eventEmitter.addListener(
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
137
|
+
this.eventEmitter.addListener(
|
|
138
|
+
FWEventName.ShoppingCTAButtonClick,
|
|
139
|
+
(event) => {
|
|
140
|
+
FWLoggerUtil.log(
|
|
141
|
+
`Receive ShoppingCTA event productId: ${event?.productId} unitId: ${event?.unitId} url: ${event?.url}`
|
|
142
|
+
);
|
|
143
|
+
this.handleShoppingCTAEvent(event);
|
|
144
|
+
}
|
|
145
|
+
);
|
|
149
146
|
|
|
150
147
|
this.eventEmitter.addListener(FWEventName.ClickCartIcon, () => {
|
|
151
148
|
FWLoggerUtil.log('Receive ClickCartIcon event');
|
|
@@ -161,17 +158,15 @@ class VideoShopping {
|
|
|
161
158
|
|
|
162
159
|
this.eventEmitter.addListener(FWEventName.LogMessage, () => {});
|
|
163
160
|
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
(
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
);
|
|
174
|
-
}
|
|
161
|
+
this.eventEmitter.addListener(
|
|
162
|
+
FWEventName.CustomLinkButtonClick,
|
|
163
|
+
(event) => {
|
|
164
|
+
FWLoggerUtil.log(
|
|
165
|
+
`Receive CustomLinkButtonClick event url: ${event?.url}`
|
|
166
|
+
);
|
|
167
|
+
this.handleCustomLinkButtonClickEvent(event);
|
|
168
|
+
}
|
|
169
|
+
);
|
|
175
170
|
}
|
|
176
171
|
|
|
177
172
|
/**
|
|
@@ -186,30 +181,22 @@ class VideoShopping {
|
|
|
186
181
|
ShoppingModule.setCartItemCount(count);
|
|
187
182
|
}
|
|
188
183
|
|
|
189
|
-
private async
|
|
184
|
+
private async handleShoppingCTAEvent(event: any) {
|
|
190
185
|
const callbackId = event.callbackId;
|
|
191
186
|
delete event.callbackId;
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
result.res,
|
|
198
|
-
result.tips,
|
|
199
|
-
callbackId
|
|
200
|
-
);
|
|
201
|
-
}
|
|
202
|
-
} else {
|
|
203
|
-
if (callbackId) {
|
|
204
|
-
if (Platform.OS === 'ios') {
|
|
205
|
-
ShoppingModule.clearCallbackId(callbackId, FWEventName.AddToCart);
|
|
206
|
-
}
|
|
207
|
-
}
|
|
187
|
+
|
|
188
|
+
if (this.onShoppingCTA) {
|
|
189
|
+
const result = await this.onShoppingCTA(event as ShoppingCTAEvent);
|
|
190
|
+
if (callbackId) {
|
|
191
|
+
ShoppingModule.updateShoppingCTAResult(result, callbackId);
|
|
208
192
|
}
|
|
209
193
|
} else {
|
|
210
194
|
if (callbackId) {
|
|
211
195
|
if (Platform.OS === 'ios') {
|
|
212
|
-
ShoppingModule.clearCallbackId(
|
|
196
|
+
ShoppingModule.clearCallbackId(
|
|
197
|
+
callbackId,
|
|
198
|
+
FWEventName.ShoppingCTAButtonClick
|
|
199
|
+
);
|
|
213
200
|
}
|
|
214
201
|
}
|
|
215
202
|
}
|
|
@@ -1,14 +1,25 @@
|
|
|
1
|
-
import
|
|
1
|
+
import type { ForwardRefRenderFunction } from 'react';
|
|
2
|
+
import React, {
|
|
3
|
+
forwardRef,
|
|
4
|
+
useEffect,
|
|
5
|
+
useImperativeHandle,
|
|
6
|
+
useReducer,
|
|
7
|
+
useRef,
|
|
8
|
+
useState,
|
|
9
|
+
} from 'react';
|
|
2
10
|
|
|
3
|
-
import
|
|
4
|
-
|
|
11
|
+
import {
|
|
12
|
+
BackHandler,
|
|
13
|
+
findNodeHandle,
|
|
5
14
|
NativeSyntheticEvent,
|
|
15
|
+
Platform,
|
|
6
16
|
StyleProp,
|
|
17
|
+
UIManager,
|
|
7
18
|
ViewStyle,
|
|
8
19
|
} from 'react-native';
|
|
9
|
-
import { findNodeHandle, Platform, UIManager } from 'react-native';
|
|
10
20
|
|
|
11
21
|
import FireworkSDK from '../FireworkSDK';
|
|
22
|
+
import type AdConfiguration from '../models/AdConfiguration';
|
|
12
23
|
import type FWError from '../models/FWError';
|
|
13
24
|
import { FWEventName } from '../models/FWEventName';
|
|
14
25
|
import type { StoryBlockSource } from '../models/StoryBlockSource';
|
|
@@ -18,17 +29,16 @@ import FWStoryBlock from './FWStoryBlock';
|
|
|
18
29
|
|
|
19
30
|
const NativeComponentName = 'FWStoryBlock';
|
|
20
31
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
};
|
|
32
|
+
export interface IStoryBlockMethods {
|
|
33
|
+
/**
|
|
34
|
+
* Play the story block.
|
|
35
|
+
*/
|
|
36
|
+
play: () => void;
|
|
37
|
+
/**
|
|
38
|
+
* Pause the story block.
|
|
39
|
+
*/
|
|
40
|
+
pause: () => void;
|
|
41
|
+
}
|
|
32
42
|
|
|
33
43
|
/**
|
|
34
44
|
* The props type of StoryBlock component.
|
|
@@ -55,98 +65,119 @@ export interface IStoryBlockProps {
|
|
|
55
65
|
*/
|
|
56
66
|
dynamicContentParameters?: { [key: string]: string[] };
|
|
57
67
|
/**
|
|
58
|
-
* Specifies if Picture in Picture is enabled.
|
|
68
|
+
* Specifies if Picture in Picture is enabled. Only supported on iOS.
|
|
59
69
|
*/
|
|
60
70
|
enablePictureInPicture?: boolean;
|
|
71
|
+
/**
|
|
72
|
+
* Ad configuration of the feed. Only supported on iOS.
|
|
73
|
+
*/
|
|
74
|
+
adConfiguration?: AdConfiguration;
|
|
61
75
|
/**
|
|
62
76
|
* The feed loading result callback. It means loading successfully when error equals to undefined.
|
|
63
77
|
*/
|
|
64
78
|
onStoryBlockLoadFinished?: (error?: FWError) => void;
|
|
65
79
|
}
|
|
66
80
|
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
81
|
+
const StoryBlock: ForwardRefRenderFunction<
|
|
82
|
+
IStoryBlockMethods,
|
|
83
|
+
IStoryBlockProps
|
|
84
|
+
> = (props: IStoryBlockProps, forwardedRef) => {
|
|
85
|
+
const nativeComponentRef = useRef(null);
|
|
86
|
+
const [isFullscreenState, setIsFullscreenState] = useState<boolean>(false);
|
|
87
|
+
const [, forceUpdate] = useReducer((x) => x + 1, 0);
|
|
88
|
+
useImperativeHandle(
|
|
89
|
+
forwardedRef,
|
|
90
|
+
() => {
|
|
91
|
+
const sendCommand = (command: string) => {
|
|
92
|
+
const nativeNodeHandle = findNodeHandle(nativeComponentRef.current);
|
|
72
93
|
|
|
73
|
-
|
|
94
|
+
let commandId: string | number =
|
|
95
|
+
UIManager.getViewManagerConfig(NativeComponentName).Commands[command];
|
|
96
|
+
if (Platform.OS === 'android') {
|
|
97
|
+
commandId = commandId.toString();
|
|
98
|
+
}
|
|
74
99
|
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
100
|
+
UIManager.dispatchViewManagerCommand(
|
|
101
|
+
findNodeHandle(nativeNodeHandle),
|
|
102
|
+
commandId,
|
|
103
|
+
[]
|
|
104
|
+
);
|
|
105
|
+
};
|
|
106
|
+
return {
|
|
107
|
+
play: () => {
|
|
108
|
+
sendCommand('play');
|
|
109
|
+
},
|
|
110
|
+
pause: () => {
|
|
111
|
+
sendCommand('pause');
|
|
112
|
+
},
|
|
113
|
+
};
|
|
114
|
+
},
|
|
115
|
+
[]
|
|
116
|
+
);
|
|
117
|
+
useEffect(() => {
|
|
79
118
|
const subscriptionOfShareBaseURLUpdated =
|
|
80
119
|
FireworkSDKModuleEventEmitter.addListener(
|
|
81
120
|
FWEventName.ShareBaseURLUpdated,
|
|
82
121
|
() => {
|
|
83
|
-
|
|
122
|
+
FWLoggerUtil.log('Receive FWEventName.ShareBaseURLUpdated');
|
|
123
|
+
forceUpdate();
|
|
84
124
|
}
|
|
85
125
|
);
|
|
86
|
-
this._subscriptions.push(subscriptionOfShareBaseURLUpdated);
|
|
87
|
-
|
|
88
126
|
const subscriptionOfAdBadgeConfigurationUpdated =
|
|
89
127
|
FireworkSDKModuleEventEmitter.addListener(
|
|
90
128
|
FWEventName.AdBadgeConfigurationUpdated,
|
|
91
129
|
() => {
|
|
92
|
-
|
|
130
|
+
FWLoggerUtil.log('Receive FWEventName.AdBadgeConfigurationUpdated');
|
|
131
|
+
forceUpdate();
|
|
93
132
|
}
|
|
94
133
|
);
|
|
95
|
-
this._subscriptions.push(subscriptionOfAdBadgeConfigurationUpdated);
|
|
96
134
|
|
|
97
135
|
const subscriptionOfVideoLaunchBehaviorUpdated =
|
|
98
136
|
FireworkSDKModuleEventEmitter.addListener(
|
|
99
137
|
FWEventName.VideoLaunchBehaviorUpdated,
|
|
100
138
|
() => {
|
|
101
139
|
FWLoggerUtil.log('Receive FWEventName.VideoLaunchBehaviorUpdated');
|
|
102
|
-
|
|
140
|
+
forceUpdate();
|
|
103
141
|
}
|
|
104
142
|
);
|
|
105
|
-
this._subscriptions.push(subscriptionOfVideoLaunchBehaviorUpdated);
|
|
106
143
|
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
144
|
+
const subscriptionOfAppLanguageUpdated =
|
|
145
|
+
FireworkSDKModuleEventEmitter.addListener(
|
|
146
|
+
FWEventName.AppLanguageUpdated,
|
|
147
|
+
() => {
|
|
148
|
+
FWLoggerUtil.log('Receive FWEventName.AppLanguageUpdated');
|
|
149
|
+
forceUpdate();
|
|
150
|
+
}
|
|
111
151
|
);
|
|
112
|
-
createFragment(viewId);
|
|
113
|
-
}
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
/**
|
|
117
|
-
* @ignore
|
|
118
|
-
*/
|
|
119
|
-
componentWillUnmount() {
|
|
120
|
-
this._subscriptions.forEach((value) => {
|
|
121
|
-
value.remove();
|
|
122
|
-
});
|
|
123
152
|
|
|
124
|
-
|
|
125
|
-
|
|
153
|
+
if (Platform.OS === 'android') {
|
|
154
|
+
setTimeout(() => {
|
|
155
|
+
const viewId = findNodeHandle(nativeComponentRef.current);
|
|
156
|
+
FWLoggerUtil.log(`StoryBlock createFragment viewId: ${viewId}`);
|
|
157
|
+
UIManager.dispatchViewManagerCommand(
|
|
158
|
+
viewId,
|
|
159
|
+
UIManager.getViewManagerConfig(
|
|
160
|
+
NativeComponentName
|
|
161
|
+
).Commands.create.toString(),
|
|
162
|
+
[viewId]
|
|
163
|
+
);
|
|
164
|
+
}, 500);
|
|
165
|
+
}
|
|
126
166
|
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
<FWStoryBlock
|
|
135
|
-
ref={this._nativeComponentRef}
|
|
136
|
-
key={this._generateKey()}
|
|
137
|
-
{...this.props}
|
|
138
|
-
onStoryBlockLoadFinished={this._onStoryBlockLoadFinished}
|
|
139
|
-
style={Object.assign({}, style, { zIndex: -1 })}
|
|
140
|
-
/>
|
|
141
|
-
);
|
|
142
|
-
}
|
|
167
|
+
return () => {
|
|
168
|
+
subscriptionOfShareBaseURLUpdated.remove();
|
|
169
|
+
subscriptionOfAdBadgeConfigurationUpdated.remove();
|
|
170
|
+
subscriptionOfVideoLaunchBehaviorUpdated.remove();
|
|
171
|
+
subscriptionOfAppLanguageUpdated.remove();
|
|
172
|
+
};
|
|
173
|
+
}, []);
|
|
143
174
|
|
|
144
|
-
|
|
175
|
+
const handleStoryBlockLoadFinished = (event: NativeSyntheticEvent<any>) => {
|
|
145
176
|
FWLoggerUtil.log(
|
|
146
|
-
`StoryBlock
|
|
177
|
+
`StoryBlock handleStoryBlockLoadFinished ${event.nativeEvent.name}`
|
|
147
178
|
);
|
|
148
179
|
|
|
149
|
-
const { onStoryBlockLoadFinished } =
|
|
180
|
+
const { onStoryBlockLoadFinished } = props;
|
|
150
181
|
const { name, reason } = event.nativeEvent;
|
|
151
182
|
|
|
152
183
|
if (onStoryBlockLoadFinished) {
|
|
@@ -162,60 +193,132 @@ class StoryBlock extends React.Component<IStoryBlockProps> {
|
|
|
162
193
|
}
|
|
163
194
|
};
|
|
164
195
|
|
|
165
|
-
|
|
196
|
+
const handleStoryBlockFullscreenStateChanged = (
|
|
197
|
+
event: NativeSyntheticEvent<any>
|
|
198
|
+
) => {
|
|
199
|
+
FWLoggerUtil.log(
|
|
200
|
+
`StoryBlock handleStoryBlockFullscreenStateChanged ${event.nativeEvent.isFullScreen}`
|
|
201
|
+
);
|
|
202
|
+
const { isFullScreen } = event.nativeEvent;
|
|
203
|
+
setIsFullscreenState(isFullScreen);
|
|
204
|
+
};
|
|
205
|
+
|
|
206
|
+
const generateDynamicContentParametersString = (): string => {
|
|
207
|
+
const { dynamicContentParameters } = props;
|
|
208
|
+
|
|
209
|
+
if (!dynamicContentParameters) {
|
|
210
|
+
return '';
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
let resultString = '';
|
|
214
|
+
const sortedKeyList = Object.keys(dynamicContentParameters).sort();
|
|
215
|
+
for (const key of sortedKeyList) {
|
|
216
|
+
const value = dynamicContentParameters[key];
|
|
217
|
+
const valueString = value.join(',');
|
|
218
|
+
if (resultString.length > 0) {
|
|
219
|
+
resultString += '_';
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
resultString += `${key}:${valueString}`;
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
return resultString;
|
|
226
|
+
};
|
|
227
|
+
|
|
228
|
+
const generateVastAttributesString = () => {
|
|
229
|
+
const { adConfiguration } = props;
|
|
230
|
+
const vastAttributes = adConfiguration?.vastAttributes ?? '';
|
|
231
|
+
if (!vastAttributes) {
|
|
232
|
+
return '';
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
let resultString = '';
|
|
236
|
+
for (const attribute of vastAttributes) {
|
|
237
|
+
if (resultString.length > 0) {
|
|
238
|
+
resultString += '_';
|
|
239
|
+
}
|
|
240
|
+
resultString += `${attribute.name ?? ''}:${attribute.value}`;
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
return resultString;
|
|
244
|
+
};
|
|
245
|
+
|
|
246
|
+
const generateKey = (): string => {
|
|
166
247
|
const {
|
|
167
248
|
source,
|
|
168
249
|
channel = '',
|
|
169
250
|
playlist = '',
|
|
170
251
|
enablePictureInPicture = false,
|
|
171
|
-
|
|
252
|
+
adConfiguration,
|
|
253
|
+
} = props;
|
|
172
254
|
|
|
173
255
|
const shareBaseURL = FireworkSDK.getInstance().getShareBaseURL() ?? '';
|
|
256
|
+
const videoLaunchBehavior =
|
|
257
|
+
FireworkSDK.getInstance().getVideoLaunchBehavior();
|
|
174
258
|
const adBadgeConfiguration =
|
|
175
259
|
FireworkSDK.getInstance().getAdBadgeConfiguration() ?? {};
|
|
176
260
|
const adBadgeTextType = adBadgeConfiguration.badgeTextType ?? '';
|
|
177
261
|
const backgroundColorOfAdBadge = adBadgeConfiguration.backgroundColor ?? '';
|
|
178
262
|
const textColorOfAdBadge = adBadgeConfiguration.textColor ?? '';
|
|
179
263
|
const dynamicContentParametersString =
|
|
180
|
-
|
|
181
|
-
const
|
|
182
|
-
|
|
264
|
+
generateDynamicContentParametersString();
|
|
265
|
+
const appLanguage = FireworkSDK.getInstance().appLanguage ?? '';
|
|
266
|
+
const requiresAds = adConfiguration?.requiresAds ?? false;
|
|
267
|
+
const adsFetchTimeout = adConfiguration?.adsFetchTimeout ?? 10;
|
|
268
|
+
const vastAttributesString = generateVastAttributesString();
|
|
183
269
|
|
|
184
270
|
let key = `source:${source}`;
|
|
185
271
|
key += `_channel:${channel}`;
|
|
186
272
|
key += `_playlist:${playlist}`;
|
|
187
273
|
key += `_shareBaseURL:${shareBaseURL}`;
|
|
274
|
+
key += `_videoLaunchBehavior:${videoLaunchBehavior}`;
|
|
188
275
|
key += `_adBadgeTextType:${adBadgeTextType}`;
|
|
189
276
|
key += `_backgroundColorOfAdBadge:${backgroundColorOfAdBadge}`;
|
|
190
277
|
key += `_textColorOfAdBadge:${textColorOfAdBadge}`;
|
|
191
278
|
key += `_dynamicContentParameters:${dynamicContentParametersString}`;
|
|
192
279
|
key += `_enablePictureInPicture:${enablePictureInPicture}`;
|
|
193
|
-
key += `
|
|
280
|
+
key += `_appLanguage:${appLanguage}`;
|
|
281
|
+
key += `_requiresAds:${requiresAds}`;
|
|
282
|
+
key += `_adsFetchTimeout:${adsFetchTimeout}`;
|
|
283
|
+
key += `_vastAttributes:${vastAttributesString}`;
|
|
194
284
|
|
|
195
285
|
return key;
|
|
196
|
-
}
|
|
197
|
-
|
|
198
|
-
private _generateDynamicContentParametersString(): string {
|
|
199
|
-
const { dynamicContentParameters } = this.props;
|
|
286
|
+
};
|
|
200
287
|
|
|
201
|
-
|
|
202
|
-
|
|
288
|
+
useEffect(() => {
|
|
289
|
+
if (Platform.OS === 'android') {
|
|
290
|
+
const onBackPress = () => {
|
|
291
|
+
if (isFullscreenState) {
|
|
292
|
+
FireworkSDK.getInstance().navigator.popNativeContainer();
|
|
293
|
+
return true;
|
|
294
|
+
}
|
|
295
|
+
return false;
|
|
296
|
+
};
|
|
297
|
+
const subscription = BackHandler.addEventListener(
|
|
298
|
+
'hardwareBackPress',
|
|
299
|
+
onBackPress
|
|
300
|
+
);
|
|
301
|
+
return () => {
|
|
302
|
+
subscription.remove();
|
|
303
|
+
};
|
|
203
304
|
}
|
|
204
305
|
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
for (const key of sortedKeyList) {
|
|
208
|
-
const value = dynamicContentParameters[key];
|
|
209
|
-
const valueString = value.join(',');
|
|
210
|
-
if (resultString.length > 0) {
|
|
211
|
-
resultString += '_';
|
|
212
|
-
}
|
|
213
|
-
|
|
214
|
-
resultString += `${key}:${valueString}`;
|
|
215
|
-
}
|
|
306
|
+
return;
|
|
307
|
+
}, [isFullscreenState]);
|
|
216
308
|
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
309
|
+
const { style } = props;
|
|
310
|
+
return (
|
|
311
|
+
<FWStoryBlock
|
|
312
|
+
ref={nativeComponentRef}
|
|
313
|
+
key={generateKey()}
|
|
314
|
+
{...props}
|
|
315
|
+
onStoryBlockLoadFinished={handleStoryBlockLoadFinished}
|
|
316
|
+
onStoryBlockFullScreenStateChanged={
|
|
317
|
+
handleStoryBlockFullscreenStateChanged
|
|
318
|
+
}
|
|
319
|
+
style={Object.assign({}, style, { zIndex: -1 })}
|
|
320
|
+
/>
|
|
321
|
+
);
|
|
322
|
+
};
|
|
220
323
|
|
|
221
|
-
export default StoryBlock;
|
|
324
|
+
export default forwardRef(StoryBlock);
|
|
@@ -170,6 +170,15 @@ class VideoFeed extends React.Component<IVideoFeedProps> {
|
|
|
170
170
|
}
|
|
171
171
|
);
|
|
172
172
|
this._subscriptions.push(subscriptionOfVideoLaunchBehaviorUpdated);
|
|
173
|
+
const subscriptionOfAppLanguageUpdated =
|
|
174
|
+
FireworkSDKModuleEventEmitter.addListener(
|
|
175
|
+
FWEventName.AppLanguageUpdated,
|
|
176
|
+
() => {
|
|
177
|
+
FWLoggerUtil.log('Receive FWEventName.AppLanguageUpdated');
|
|
178
|
+
this.setState({});
|
|
179
|
+
}
|
|
180
|
+
);
|
|
181
|
+
this._subscriptions.push(subscriptionOfAppLanguageUpdated);
|
|
173
182
|
}
|
|
174
183
|
|
|
175
184
|
/**
|
|
@@ -222,6 +231,7 @@ class VideoFeed extends React.Component<IVideoFeedProps> {
|
|
|
222
231
|
const showAdBadge = videoFeedConfiguration?.showAdBadge ?? false;
|
|
223
232
|
const videoLaunchBehavior =
|
|
224
233
|
FireworkSDK.getInstance().getVideoLaunchBehavior() ?? 'default';
|
|
234
|
+
const appLanguage = FireworkSDK.getInstance().appLanguage ?? '';
|
|
225
235
|
|
|
226
236
|
let key = `source:${source}`;
|
|
227
237
|
key += `_channel:${channel}`;
|
|
@@ -243,6 +253,7 @@ class VideoFeed extends React.Component<IVideoFeedProps> {
|
|
|
243
253
|
key += `_vastAttributes:${vastAttributesString}`;
|
|
244
254
|
key += `_showAdBadge:${showAdBadge}`;
|
|
245
255
|
key += `_videoLaunchBehavior:${videoLaunchBehavior}`;
|
|
256
|
+
key += `_appLanguage:${appLanguage}`;
|
|
246
257
|
|
|
247
258
|
return (
|
|
248
259
|
<FWVideoFeed
|