react-native-firework-sdk 1.7.1 → 1.9.0-beta.3

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 (139) hide show
  1. package/android/src/main/java/com/fireworksdk/bridge/components/videofeed/FWVideoFeed.kt +0 -1
  2. package/android/src/main/java/com/fireworksdk/bridge/models/FWEventName.kt +1 -0
  3. package/android/src/main/java/com/fireworksdk/bridge/reactnative/models/FWVideoShoppingInterface.kt +1 -0
  4. package/android/src/main/java/com/fireworksdk/bridge/reactnative/module/FWVideoShoppingModule.kt +11 -1
  5. package/android/src/main/java/com/fireworksdk/bridge/reactnative/utils/FWEventUtils.kt +9 -0
  6. package/android/src/main/java/com/fireworksdk/bridge/utils/FWLanguageUtil.kt +0 -2
  7. package/android/src/main/java/com/fireworksdk/bridge/utils/FWVideoPlayerUtils.kt +1 -0
  8. package/ios/Components/StoryBlock.swift +6 -9
  9. package/ios/Components/StoryBlockManager.swift +4 -0
  10. package/ios/Components/VideoFeed.swift +14 -15
  11. package/ios/Components/VideoFeedConfiguration.swift +2 -0
  12. package/ios/Components/VideoFeedManager.m +2 -0
  13. package/ios/Components/VideoFeedManager.swift +4 -0
  14. package/ios/Components/VideoPlayerConfiguration.swift +1 -0
  15. package/ios/FireworkSdk-Bridging-Header.h +6 -0
  16. package/ios/FireworkSdk.xcodeproj/project.pbxproj +374 -200
  17. package/ios/Models/Common/FontInfo.swift +57 -0
  18. package/ios/Models/NativeToRN/FireworkEventName.swift +1 -0
  19. package/ios/Modules/FWNavigatorModule/FWNavigatorModule.m +2 -0
  20. package/ios/Modules/FWNavigatorModule/FWNavigatorModule.swift +271 -107
  21. package/ios/Modules/FireworkSDKModule/FireworkSDKModule+EventTracking.swift +0 -2
  22. package/ios/Modules/FireworkSDKModule/FireworkSDKModule.m +1 -0
  23. package/ios/Modules/FireworkSDKModule/FireworkSDKModule.swift +43 -12
  24. package/ios/Modules/LiveStream/LiveStreamModule.swift +5 -3
  25. package/ios/Modules/Shopping/ProductInfoViewConfiguration.swift +7 -2
  26. package/ios/Modules/Shopping/ShoppingModule.m +1 -1
  27. package/ios/Modules/Shopping/ShoppingModule.swift +72 -63
  28. package/ios/Utils/AppLanguage/Bundle+FWSwizzle.swift +58 -0
  29. package/ios/Utils/AppLanguage/FWAppLanguageManager.swift +118 -0
  30. package/ios/Utils/AppLanguage/FWLanguageUtil.swift +39 -0
  31. package/ios/Utils/AppLanguage/NumberFormatter+FWSwizzle.swift +25 -0
  32. package/ios/Utils/AppLanguage/UIImageView+FWSwizzle.swift +91 -0
  33. package/ios/Utils/AppLanguage/UILabel+FWSwizzle.swift +98 -0
  34. package/ios/Utils/AppLanguage/UITextField+FWSwizzle.swift +97 -0
  35. package/ios/Utils/AppLanguage/UITextView+FWSwizzle.swift +97 -0
  36. package/ios/Utils/AppLanguage/UIView+FWSwizzle.swift +38 -0
  37. package/ios/Utils/AppLanguage/UIViewController+FWSwizzle.swift +32 -0
  38. package/ios/Utils/AppLanguage/UIWindow+FWSwizzle.swift +26 -0
  39. package/ios/Utils/AppLanguage/URLSession+FWSwizzle.swift +69 -0
  40. package/ios/Utils/{DispatchQueue+FWOnce.swift → Extensions/DispatchQueue+FWOnce.swift} +3 -3
  41. package/ios/Utils/{UINavigationController+FWSwizzle.swift → Extensions/Swizzle/UINavigationController+FWSwizzle.swift} +6 -8
  42. package/ios/Utils/Extensions/UIView+FWUIHierarchy.swift +47 -0
  43. package/ios/Utils/FWRTL/Classes/Manager/FWRTLManager.h +25 -0
  44. package/ios/Utils/FWRTL/Classes/Manager/FWRTLManager.m +75 -0
  45. package/ios/Utils/FWRTL/Classes/UICategories/CALayer+FWRTL.h +21 -0
  46. package/ios/Utils/FWRTL/Classes/UICategories/CALayer+FWRTL.m +124 -0
  47. package/ios/Utils/FWRTL/Classes/UICategories/FWRTLRemoteViewControllerAdaptor.h +11 -0
  48. package/ios/Utils/FWRTL/Classes/UICategories/FWRTLRemoteViewControllerAdaptor.m +86 -0
  49. package/ios/Utils/FWRTL/Classes/UICategories/FWRTLWhiteListManager.h +16 -0
  50. package/ios/Utils/FWRTL/Classes/UICategories/FWRTLWhiteListManager.m +55 -0
  51. package/ios/Utils/FWRTL/Classes/UICategories/UILabel+FWRTL.h +18 -0
  52. package/ios/Utils/FWRTL/Classes/UICategories/UILabel+FWRTL.m +39 -0
  53. package/ios/Utils/FWRTL/Classes/UICategories/UIView+FWRTL.h +54 -0
  54. package/ios/Utils/FWRTL/Classes/UICategories/UIView+FWRTL.m +141 -0
  55. package/ios/Utils/FWRTL/Classes/UICategories/UIWindow+FWRTL.h +16 -0
  56. package/ios/Utils/FWRTL/Classes/UICategories/UIWindow+FWRTL.m +20 -0
  57. package/ios/Utils/FWRTL/Classes/Utils/FWRTLDefinitions.h +52 -0
  58. package/ios/Utils/FWRTL/Classes/Utils/NSObject+FWRTLReloadBlock.h +19 -0
  59. package/ios/Utils/FWRTL/Classes/Utils/NSObject+FWRTLReloadBlock.m +49 -0
  60. package/ios/Utils/FWRTL/Classes/Utils/NSString+FWRTL.h +21 -0
  61. package/ios/Utils/FWRTL/Classes/Utils/NSString+FWRTL.m +38 -0
  62. package/ios/Utils/FWRTL/Classes/Utils/UIImage+FWRTL.h +18 -0
  63. package/ios/Utils/FWRTL/Classes/Utils/UIImage+FWRTL.m +43 -0
  64. package/ios/Utils/FWSwizzleLoader.m +1 -2
  65. package/ios/Utils/FWSwizzleLoader.swift +13 -0
  66. package/ios/Utils/FWSwizzleUtil.swift +17 -9
  67. package/ios/react_native_firework_sdk.h +1 -0
  68. package/ios/scripts/firework_sdk_pods.rb +3 -0
  69. package/lib/commonjs/FWNavigator.js +32 -1
  70. package/lib/commonjs/FWNavigator.js.map +1 -1
  71. package/lib/commonjs/FireworkSDK.js +26 -12
  72. package/lib/commonjs/FireworkSDK.js.map +1 -1
  73. package/lib/commonjs/VideoShopping.js +64 -9
  74. package/lib/commonjs/VideoShopping.js.map +1 -1
  75. package/lib/commonjs/components/VideoFeed.js +26 -5
  76. package/lib/commonjs/components/VideoFeed.js.map +1 -1
  77. package/lib/commonjs/index.js +6 -0
  78. package/lib/commonjs/index.js.map +1 -1
  79. package/lib/commonjs/models/FWEventName.js +2 -0
  80. package/lib/commonjs/models/FWEventName.js.map +1 -1
  81. package/lib/commonjs/models/IOSFontInfo.js +2 -0
  82. package/lib/commonjs/models/IOSFontInfo.js.map +1 -0
  83. package/lib/commonjs/modules/FWNavigatorModule.js.map +1 -1
  84. package/lib/commonjs/modules/ShoppingModule.js.map +1 -1
  85. package/lib/module/FWNavigator.js +31 -1
  86. package/lib/module/FWNavigator.js.map +1 -1
  87. package/lib/module/FireworkSDK.js +27 -11
  88. package/lib/module/FireworkSDK.js.map +1 -1
  89. package/lib/module/VideoShopping.js +63 -9
  90. package/lib/module/VideoShopping.js.map +1 -1
  91. package/lib/module/components/VideoFeed.js +21 -5
  92. package/lib/module/components/VideoFeed.js.map +1 -1
  93. package/lib/module/index.js +1 -1
  94. package/lib/module/index.js.map +1 -1
  95. package/lib/module/models/FWEventName.js +2 -0
  96. package/lib/module/models/FWEventName.js.map +1 -1
  97. package/lib/module/models/IOSFontInfo.js +2 -0
  98. package/lib/module/models/IOSFontInfo.js.map +1 -0
  99. package/lib/module/modules/FWNavigatorModule.js.map +1 -1
  100. package/lib/module/modules/ShoppingModule.js.map +1 -1
  101. package/lib/typescript/FWNavigator.d.ts +17 -2
  102. package/lib/typescript/FireworkSDK.d.ts +9 -5
  103. package/lib/typescript/LiveStream.d.ts +2 -2
  104. package/lib/typescript/VideoShopping.d.ts +33 -11
  105. package/lib/typescript/components/VideoFeed.d.ts +5 -1
  106. package/lib/typescript/index.d.ts +8 -4
  107. package/lib/typescript/models/AdBadgeConfiguration.d.ts +1 -1
  108. package/lib/typescript/models/FWEventName.d.ts +3 -1
  109. package/lib/typescript/models/FWEvents.d.ts +5 -0
  110. package/lib/typescript/models/IOSFontInfo.d.ts +19 -0
  111. package/lib/typescript/models/NewNativeContainerProps.d.ts +1 -1
  112. package/lib/typescript/models/ProductInfoViewConfiguration.d.ts +23 -0
  113. package/lib/typescript/models/StoryBlockSource.d.ts +1 -1
  114. package/lib/typescript/models/VideoFeedConfiguration.d.ts +20 -2
  115. package/lib/typescript/models/VideoFeedSource.d.ts +1 -1
  116. package/lib/typescript/models/VideoPlayerConfiguration.d.ts +20 -4
  117. package/lib/typescript/modules/FWNavigatorModule.d.ts +2 -0
  118. package/lib/typescript/modules/ShoppingModule.d.ts +2 -1
  119. package/package.json +7 -4
  120. package/react-native-firework-sdk.podspec +15 -18
  121. package/src/{FWNavigator.tsx → FWNavigator.ts} +30 -2
  122. package/src/FireworkSDK.ts +24 -13
  123. package/src/VideoShopping.ts +86 -20
  124. package/src/components/VideoFeed.tsx +24 -2
  125. package/src/{index.tsx → index.ts} +24 -1
  126. package/src/models/FWEventName.ts +2 -0
  127. package/src/models/FWEvents.ts +6 -0
  128. package/src/models/IOSFontInfo.ts +29 -0
  129. package/src/models/ProductInfoViewConfiguration.ts +25 -0
  130. package/src/models/VideoFeedConfiguration.ts +20 -1
  131. package/src/models/VideoPlayerConfiguration.ts +17 -0
  132. package/src/modules/FWNavigatorModule.ts +2 -0
  133. package/src/modules/ShoppingModule.ts +2 -4
  134. package/ios/Utils/FWPiPManager.swift +0 -24
  135. package/ios/Utils/UIButton+FWSwizzle.swift +0 -33
  136. package/ios/Utils/UIView+ParentViewController.swift +0 -21
  137. /package/ios/Utils/{String+Color.swift → Extensions/String+Color.swift} +0 -0
  138. /package/ios/Utils/{UIView+Constraints.swift → Extensions/UIView+Constraints.swift} +0 -0
  139. /package/ios/Utils/{UIViewController+AttachChild.swift → Extensions/UIViewController+AttachChild.swift} +0 -0
@@ -21,6 +21,7 @@ class ShoppingModule: RCTEventEmitter, FireworkVideoShoppingDelegate, CartViewCo
21
21
  private var cartIconVisible = true
22
22
  private var itemCounts = 0
23
23
  private var customClickCartIconEnabled = false
24
+ private var productInfoViewConfiguration: ProductInfoViewConfiguration?
24
25
 
25
26
  override func supportedEvents() -> [String]! {
26
27
  ShoppingEventName.allCases.map { $0.rawValue }
@@ -30,6 +31,10 @@ class ShoppingModule: RCTEventEmitter, FireworkVideoShoppingDelegate, CartViewCo
30
31
  return true
31
32
  }
32
33
 
34
+ override var methodQueue: DispatchQueue {
35
+ return DispatchQueue.main
36
+ }
37
+
33
38
  private static func generateCallbackId() -> Int {
34
39
  struct CBIdIncreasingFactor {
35
40
  static var callbackId = 0
@@ -41,15 +46,18 @@ class ShoppingModule: RCTEventEmitter, FireworkVideoShoppingDelegate, CartViewCo
41
46
 
42
47
  @objc
43
48
  func initialize() {
44
- DispatchQueue.main.async {
45
- FireworkVideoSDK.shopping.shoppingDelegate = self
46
- FireworkVideoSDK.shopping.cartViewControllerProvider = self
47
- }
49
+ FireworkVideoSDK.shopping.shoppingDelegate = self
50
+ FireworkVideoSDK.shopping.cartViewControllerProvider = self
48
51
  }
49
52
 
50
53
  @objc
51
54
  func setCartIconVisible(_ visible: Bool) {
52
55
  cartIconVisible = visible
56
+ guard let rProductInfoViewConfigurator = productInfoViewConfigurator else {
57
+ return
58
+ }
59
+
60
+ rProductInfoViewConfigurator.1.shoppingCartIconConfiguration.isHidden = !visible
53
61
  }
54
62
 
55
63
  @objc
@@ -59,13 +67,8 @@ class ShoppingModule: RCTEventEmitter, FireworkVideoShoppingDelegate, CartViewCo
59
67
  guard let rProductInfoViewConfigurator = productInfoViewConfigurator else {
60
68
  return
61
69
  }
62
- DispatchQueue.main.async {
63
- var shoppingCartIconConfiguration = rProductInfoViewConfigurator.1
64
- .shoppingCartIconConfiguration
65
- shoppingCartIconConfiguration.indicator.isHidden = itemCounts == 0
66
- rProductInfoViewConfigurator.1.shoppingCartIconConfiguration =
67
- shoppingCartIconConfiguration
68
- }
70
+
71
+ rProductInfoViewConfigurator.1.shoppingCartIconConfiguration.indicator.isHidden = itemCounts == 0
69
72
  }
70
73
 
71
74
  @objc
@@ -119,33 +122,11 @@ class ShoppingModule: RCTEventEmitter, FireworkVideoShoppingDelegate, CartViewCo
119
122
  ])
120
123
  #endif
121
124
 
122
- DispatchQueue.main.async {
123
- for product in rProducts {
124
- productHydrating.hydrateProduct(
125
- product.productId, { build in
126
- return ShoppingModule.hydrateProduct(product, build)
127
- })
128
- }
129
- }
130
- }
131
-
132
- @objc
133
- func updateProductViewConfig(_ config: [String: Any]?, cbId: NSNumber) {
134
- let config = RCTConvert.buildProductInfoViewConfiguration(config)
135
- guard let rConfig = config, let rProductInfoViewConfigurator = productInfoViewConfigurator,
136
- rProductInfoViewConfigurator.0 == Int(truncating: cbId)
137
- else {
138
- return
139
- }
140
-
141
- DispatchQueue.main.async {
142
- // The configuration of CartIcon'visible determined by global cartIconVisible
143
- rProductInfoViewConfigurator.1.shoppingCartIconConfiguration.isHidden = !self
144
- .cartIconVisible
145
- // The configuration of CartIcon'indicator'visible determined by global itemCounts
146
- rProductInfoViewConfigurator.1.shoppingCartIconConfiguration.indicator.isHidden =
147
- self.itemCounts == 0
148
- ShoppingModule.hydrateProductViewConfig(rConfig, rProductInfoViewConfigurator.1)
125
+ for product in rProducts {
126
+ productHydrating.hydrateProduct(
127
+ product.productId, { build in
128
+ return ShoppingModule.hydrateProduct(product, build)
129
+ })
149
130
  }
150
131
  }
151
132
 
@@ -157,27 +138,23 @@ class ShoppingModule: RCTEventEmitter, FireworkVideoShoppingDelegate, CartViewCo
157
138
 
158
139
  addToCartHandlerMap.removeValue(forKey: Int(truncating: cbId))
159
140
 
160
- DispatchQueue.main.async {
161
- if res == "success" {
162
- handler(.feedbackOnly(.success(message: tips ?? "success")))
163
- } else {
164
- handler(.feedbackOnly(.failure(message: tips ?? "failure")))
165
- }
141
+ if res == "success" {
142
+ handler(.feedbackOnly(.success(message: tips ?? "success")))
143
+ } else {
144
+ handler(.feedbackOnly(.failure(message: tips ?? "failure")))
166
145
  }
167
146
  }
168
147
 
169
148
  @objc
170
149
  func jumpToCartPage(_ cbId: NSNumber, props: NSDictionary) {
171
- DispatchQueue.main.async {
172
- let properties: [String: Any] = (props as? [String: Any]) ?? [:]
173
- let noti = Notification(
174
- name: Notification.Name(rawValue: "showCustomCartView"), object: nil,
175
- userInfo: [
176
- "cbId": Int(truncating: cbId),
177
- "properties": properties
178
- ])
179
- NotificationCenter.default.post(noti)
180
- }
150
+ let properties: [String: Any] = (props as? [String: Any]) ?? [:]
151
+ let noti = Notification(
152
+ name: Notification.Name(rawValue: "showCustomCartView"), object: nil,
153
+ userInfo: [
154
+ "cbId": Int(truncating: cbId),
155
+ "properties": properties
156
+ ])
157
+ NotificationCenter.default.post(noti)
181
158
  }
182
159
 
183
160
  @objc
@@ -189,6 +166,22 @@ class ShoppingModule: RCTEventEmitter, FireworkVideoShoppingDelegate, CartViewCo
189
166
  resolver([:])
190
167
  }
191
168
 
169
+ @objc
170
+ func setProductInfoViewConfiguration(_ config: [String: Any]?) {
171
+ let config = RCTConvert.buildProductInfoViewConfiguration(config)
172
+ guard let rConfig = config else {
173
+ return
174
+ }
175
+
176
+ productInfoViewConfiguration = rConfig
177
+
178
+ guard let rProductInfoViewConfigurator = productInfoViewConfigurator else {
179
+ return
180
+ }
181
+
182
+ ShoppingModule.hydrateProductViewConfig(rConfig, rProductInfoViewConfigurator.1)
183
+ }
184
+
192
185
  @objc
193
186
  func clearCallbackId(_ cbId: NSNumber, eventName: String) {
194
187
  if eventName == ShoppingEventName.updateProductDetails.rawValue {
@@ -207,6 +200,11 @@ class ShoppingModule: RCTEventEmitter, FireworkVideoShoppingDelegate, CartViewCo
207
200
  let callbackId = ShoppingModule.generateCallbackId()
208
201
  self.productInfoViewConfigurator = (callbackId, productInfoViewConfigurator)
209
202
  productInfoViewConfigurator.shoppingCartIconConfiguration.isHidden = !self.cartIconVisible
203
+ productInfoViewConfigurator.shoppingCartIconConfiguration.indicator.isHidden = itemCounts == 0
204
+
205
+ if let productInfoViewConfiguration = productInfoViewConfiguration {
206
+ ShoppingModule.hydrateProductViewConfig(productInfoViewConfiguration, productInfoViewConfigurator)
207
+ }
210
208
 
211
209
  #if DEBUG
212
210
  let formatter = DateFormatter()
@@ -290,21 +288,32 @@ extension ShoppingModule {
290
288
  _ config: ProductInfoViewConfiguration,
291
289
  _ productInfoViewConfigurator: ProductInfoViewConfigurable
292
290
  ) {
293
- if let buttonConfiguration = config.addToCartButton {
294
- var config = productInfoViewConfigurator.productDetailsConfiguration
295
- if let backgroundColor = buttonConfiguration.backgroundColor,
291
+ var productDetailsConfiguration = productInfoViewConfigurator.productDetailsConfiguration
292
+
293
+ if let addToCartButtonConfiguration = config.addToCartButton {
294
+ if let backgroundColor = addToCartButtonConfiguration.backgroundColor,
296
295
  backgroundColor.count > 0 {
297
- config.addToCartButton.backgroundColor = backgroundColor.uicolor()
296
+ productDetailsConfiguration.addToCartButton.backgroundColor = backgroundColor.uicolor()
298
297
  }
299
- if let textColor = buttonConfiguration.textColor,
298
+
299
+ if let textColor = addToCartButtonConfiguration.textColor,
300
300
  textColor.count > 0 {
301
- config.addToCartButton.textColor = textColor.uicolor()
301
+ productDetailsConfiguration.addToCartButton.textColor = textColor.uicolor()
302
302
  }
303
- if let fontSize = buttonConfiguration.fontSize {
304
- config.addToCartButton.font = UIFont.systemFont(ofSize: fontSize)
303
+
304
+ if let fontSize = addToCartButtonConfiguration.fontSize {
305
+ let iOSFontInfo = addToCartButtonConfiguration.iOSFontInfo ?? FontInfo()
306
+ productDetailsConfiguration.addToCartButton.font = iOSFontInfo.getFont(fontSize)
305
307
  }
306
- productInfoViewConfigurator.productDetailsConfiguration = config
307
308
  }
309
+
310
+ if let linkButtonConfiguration = config.linkButton {
311
+ if let isHidden = linkButtonConfiguration.isHidden {
312
+ productDetailsConfiguration.linkButtonConfiguration.isHidden = isHidden
313
+ }
314
+ }
315
+
316
+ productInfoViewConfigurator.productDetailsConfiguration = productDetailsConfiguration
308
317
  }
309
318
 
310
319
  }
@@ -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
+ }
@@ -0,0 +1,118 @@
1
+ //
2
+ // FWAppLanguageManager.swift
3
+ //
4
+ // Created by linjie jiang on 2023/2/7.
5
+ //
6
+
7
+ import Foundation
8
+
9
+ private let appLanguageStorageKey = "firework_sdk_app_language_storage_key"
10
+
11
+ public enum AppLanguageLayoutDirection: Int {
12
+ case ltr, rtl, unsupported
13
+ }
14
+
15
+ public class FWAppLanguageManager {
16
+ public static let shared = FWAppLanguageManager()
17
+
18
+ private var _systemLanguage: String?
19
+ private var _systemLanguageCode: String? {
20
+ guard let language = _systemLanguage else {
21
+ return nil
22
+ }
23
+
24
+ return FWLanguageUtil.getLanguageCode(language)
25
+ }
26
+
27
+ public var appLanguage: String? {
28
+ didSet {
29
+ if appLanguage != nil {
30
+ FWAppLanguageManager.swizzelMethods()
31
+ }
32
+ }
33
+ }
34
+
35
+ public var appLanguageCode: String? {
36
+ guard let language = appLanguage else {
37
+ return nil
38
+ }
39
+
40
+ return FWLanguageUtil.getLanguageCode(language)
41
+ }
42
+
43
+ public var appLanguageLayoutDirection: AppLanguageLayoutDirection? {
44
+ guard let languageCode = appLanguageCode else {
45
+ return nil
46
+ }
47
+ let direction = Locale.characterDirection(forLanguage: languageCode)
48
+ switch direction {
49
+ case .leftToRight:
50
+ return .ltr
51
+ case .rightToLeft:
52
+ return .rtl
53
+ default:
54
+ return .unsupported
55
+ }
56
+ }
57
+
58
+ public var shouldHorizontalFlip: Bool {
59
+ guard let appLanguageCode = appLanguageCode else {
60
+ return false
61
+ }
62
+
63
+ guard let systemLanguageCode = _systemLanguageCode else {
64
+ return false
65
+ }
66
+
67
+ let appLanguageDirection = Locale.characterDirection(forLanguage: appLanguageCode)
68
+ let systemLanguageDirection = Locale.characterDirection(forLanguage: systemLanguageCode)
69
+
70
+ if appLanguageDirection == .leftToRight, systemLanguageDirection == .rightToLeft {
71
+ return true
72
+ }
73
+
74
+ if appLanguageDirection == .rightToLeft, systemLanguageDirection == .leftToRight {
75
+ return true
76
+ }
77
+
78
+ return false
79
+ }
80
+
81
+ private static func swizzelMethods() {
82
+ DispatchQueue.once {
83
+ UIViewController.swizzleMethodsForViewController()
84
+ Bundle.swizzleMethodsForBundle()
85
+ URLSession.swizzleMethodsForURLSession()
86
+ NumberFormatter.swizzleMethodsForNumberFormatter()
87
+ UIImageView.swizzleMethodsForImageView()
88
+ UILabel.swizzleMethodsForLabel()
89
+ UITextField.swizzleMethodsForTextField()
90
+ UITextView.swizzleMethodsForTextView()
91
+ UIWindow.swizzleMethodsForWindow()
92
+ UIView.swizzleMethodsForView()
93
+ }
94
+ }
95
+
96
+ private init() {
97
+ self._systemLanguage = Locale.preferredLanguages.first
98
+ self.appLanguage = UserDefaults.standard.object(forKey: appLanguageStorageKey) as? String
99
+ #if DEBUG
100
+ print("""
101
+ FWAppLanguageManager init method
102
+ current app language: \(self.appLanguage ?? "")
103
+ system language: \(self._systemLanguage ?? "")
104
+ """)
105
+ #endif
106
+ }
107
+
108
+ public func changeAppLanguage(_ language: String) -> Bool {
109
+ if FWLanguageUtil.isValidLanguage(language) {
110
+ appLanguage = language
111
+ UserDefaults.standard.set(language, forKey: appLanguageStorageKey)
112
+ UserDefaults.standard.synchronize()
113
+ return true
114
+ } else {
115
+ return false
116
+ }
117
+ }
118
+ }
@@ -0,0 +1,39 @@
1
+ //
2
+ // FWLanguageUtil.swift
3
+ //
4
+ // Created by linjie jiang on 2023/2/9.
5
+ //
6
+
7
+ import Foundation
8
+
9
+ public class FWLanguageUtil {
10
+ public static func getLanguageCode(_ language: String) -> String? {
11
+ guard language.count > 0 else {
12
+ return nil
13
+ }
14
+
15
+ var languageCode = ""
16
+ #if compiler(>=5.7)
17
+ if #available(iOS 16, *) {
18
+ languageCode = Locale(identifier: language).language.languageCode?.identifier ?? ""
19
+ } else {
20
+ languageCode = Locale(identifier: language).languageCode ?? ""
21
+ }
22
+ #else
23
+ languageCode = Locale(identifier: language).languageCode ?? ""
24
+ #endif
25
+ return languageCode.lowercased()
26
+ }
27
+
28
+ public static func isValidLanguage(_ language: String) -> Bool {
29
+ guard language.count > 0 else {
30
+ return false
31
+ }
32
+
33
+ let languageWithUnderline = language.replacingOccurrences(of: "-", with: "_")
34
+
35
+ let availableIdentifiers = Locale.availableIdentifiers
36
+
37
+ return availableIdentifiers.contains(language) || availableIdentifiers.contains(languageWithUnderline)
38
+ }
39
+ }
@@ -0,0 +1,25 @@
1
+ //
2
+ // NumberFormatter+FWSwizzle.swift
3
+ //
4
+ // Created by linjie jiang on 2023/2/20.
5
+ //
6
+
7
+ import Foundation
8
+
9
+ public extension NumberFormatter {
10
+ static func swizzleMethodsForNumberFormatter() {
11
+ FWSwizzleUtil.swizzleSelector(
12
+ cls: self,
13
+ originalSelector: #selector(NumberFormatter.string(from:)),
14
+ customSelector: #selector(NumberFormatter.fw_string(from:)))
15
+ }
16
+
17
+ @objc func fw_string(from number: NSNumber) -> String? {
18
+ if let language = FWAppLanguageManager.shared.appLanguage,
19
+ self.numberStyle == .currency {
20
+ self.locale = Locale(identifier: language)
21
+ }
22
+
23
+ return fw_string(from: number)
24
+ }
25
+ }
@@ -0,0 +1,91 @@
1
+ //
2
+ // UIImageView+FWSwizzle.swift
3
+ //
4
+ // Created by linjie jiang on 2023/2/22.
5
+ //
6
+
7
+ import UIKit
8
+ import FireworkVideo
9
+
10
+ private let FWImageNamesWithDirections: [String] = [
11
+ "shopping-cart",
12
+ "left-arrow",
13
+ "right-arrow",
14
+ "speaker-unmute",
15
+ "speaker-mute"
16
+ ]
17
+
18
+ extension UIImageView {
19
+ static func swizzleMethodsForImageView() {
20
+ FWSwizzleUtil.swizzleSelector(
21
+ cls: self,
22
+ originalSelector: #selector(UIImageView.didMoveToWindow),
23
+ customSelector: #selector(UIImageView.fw_imageViewDidMoveToWindow))
24
+ FWSwizzleUtil.swizzleSelector(
25
+ cls: self,
26
+ originalSelector: #selector(setter: UIImageView.image),
27
+ customSelector: #selector(UIImageView.fw_setImage(_:))
28
+ )
29
+ FWSwizzleUtil.swizzleSelector(
30
+ cls: self,
31
+ originalSelector: #selector(UIImageView.awakeFromNib),
32
+ customSelector: #selector(UIImageView.fw_imageViewAwakeFromNib)
33
+ )
34
+ }
35
+
36
+ @objc func fw_imageViewDidMoveToWindow() {
37
+ fw_imageViewDidMoveToWindow()
38
+ updateViewType(self.image)
39
+ }
40
+
41
+ @objc func fw_setImage(_ image: UIImage?) {
42
+ fw_setImage(image)
43
+ updateViewType(image)
44
+ }
45
+
46
+ @objc func fw_imageViewAwakeFromNib() {
47
+ self.fw_imageViewAwakeFromNib()
48
+ updateViewType(self.image)
49
+ }
50
+
51
+ private func updateViewType(_ image: UIImage?) {
52
+ self.fwrtl_viewType = shouldFlipImage(image) ? FWRTLViewTypeFlip : FWRTLViewTypeAuto
53
+ }
54
+
55
+ private func shouldFlipImage(_ image: UIImage?) -> Bool {
56
+ guard let image = image else {
57
+ return false
58
+ }
59
+
60
+ if FWAppLanguageManager.shared.shouldHorizontalFlip, self.isIOSSDKView {
61
+ let iOSSDKBundle = Bundle(for: FireworkVideoSDK.self)
62
+
63
+ for imageName in FWImageNamesWithDirections {
64
+ let targetImage = UIImage(named: imageName, in: iOSSDKBundle, compatibleWith: nil)
65
+ if image.isEqual(targetImage) {
66
+ return true
67
+ }
68
+
69
+ if let cgImage = image.cgImage,
70
+ let targetCgImage = targetImage?.cgImage,
71
+ cgImage == targetCgImage {
72
+ return true
73
+ }
74
+
75
+ if let ciImage = image.ciImage,
76
+ let targetCiImage = targetImage?.ciImage,
77
+ ciImage == targetCiImage {
78
+ return true
79
+ }
80
+ }
81
+ }
82
+
83
+ if FWAppLanguageManager.shared.shouldHorizontalFlip,
84
+ image.flipsForRightToLeftLayoutDirection == true,
85
+ self.isIOSSDKView {
86
+ return true
87
+ }
88
+
89
+ return false
90
+ }
91
+ }
@@ -0,0 +1,98 @@
1
+ //
2
+ // UILabel+FWSwizzle.swift
3
+ //
4
+ // Created by linjie jiang on 2023/2/22.
5
+ //
6
+
7
+ import UIKit
8
+
9
+ extension UILabel {
10
+ private struct AssociatedKeys {
11
+ static var fwHasCalculatedTextAlignment = "fwHasCalculatedTextAlignmentKey"
12
+ }
13
+
14
+ private var fwHasCalculatedTextAlignment: Bool {
15
+ get {
16
+ let result = objc_getAssociatedObject(self, &AssociatedKeys.fwHasCalculatedTextAlignment) as? Bool
17
+ return result ?? false
18
+ }
19
+
20
+ set {
21
+ objc_setAssociatedObject(
22
+ self,
23
+ &AssociatedKeys.fwHasCalculatedTextAlignment,
24
+ newValue,
25
+ .OBJC_ASSOCIATION_RETAIN_NONATOMIC
26
+ )
27
+ }
28
+ }
29
+
30
+ static func swizzleMethodsForLabel() {
31
+ FWSwizzleUtil.swizzleSelector(cls: self,
32
+ originalSelector: #selector(setter: UILabel.textAlignment),
33
+ customSelector: #selector(UILabel.fw_setLabelTextAlignment(_:)))
34
+ FWSwizzleUtil.swizzleSelector(cls: self,
35
+ originalSelector: #selector(UILabel.didMoveToWindow),
36
+ customSelector: #selector(UILabel.fw_labelDidMoveToWindow))
37
+ FWSwizzleUtil.swizzleSelector(cls: self,
38
+ originalSelector: #selector(UILabel.removeFromSuperview),
39
+ customSelector: #selector(UILabel.fw_labelRemoveFromSuperview))
40
+ }
41
+
42
+ @objc func fw_setLabelTextAlignment(_ textAlignment: NSTextAlignment) {
43
+ self.fwrtl_addReloadBlock(forKey: "alignment") { [weak self] in
44
+ guard let self = self else {
45
+ return
46
+ }
47
+
48
+ self.fw_setLabelTextAlignment(self.calculatedTextAlignment(textAlignment))
49
+ }
50
+ }
51
+
52
+ @objc func fw_labelDidMoveToWindow() {
53
+ fw_labelDidMoveToWindow()
54
+ if shouldCalculateTextAlignment(),
55
+ !self.fwHasCalculatedTextAlignment,
56
+ self.isIOSSDKView {
57
+ self.textAlignment = self.textAlignment
58
+ }
59
+ }
60
+
61
+ @objc func fw_labelRemoveFromSuperview() {
62
+ fw_labelRemoveFromSuperview()
63
+ self.fwHasCalculatedTextAlignment = false
64
+ }
65
+
66
+ private func calculatedTextAlignment(_ textAlignment: NSTextAlignment) -> NSTextAlignment {
67
+ if shouldCalculateTextAlignment(),
68
+ let layoutDirection = FWAppLanguageManager.shared.appLanguageLayoutDirection {
69
+ self.fwHasCalculatedTextAlignment = true
70
+ if layoutDirection == .rtl {
71
+ if textAlignment == .center {
72
+ return textAlignment
73
+ } else if textAlignment == .right {
74
+ return .left
75
+ } else {
76
+ return .right
77
+ }
78
+ } else if layoutDirection == .ltr {
79
+ return .left
80
+ }
81
+ } else {
82
+ return textAlignment
83
+ }
84
+ return textAlignment
85
+ }
86
+
87
+ private func shouldCalculateTextAlignment() -> Bool {
88
+ if FWAppLanguageManager.shared.shouldHorizontalFlip,
89
+ self.isIOSSDKView,
90
+ let layoutDirection = FWAppLanguageManager.shared.appLanguageLayoutDirection,
91
+ layoutDirection != .unsupported,
92
+ fwrtl_shouldUseCalculatedTextAlignment() {
93
+ return true
94
+ }
95
+
96
+ return false
97
+ }
98
+ }