@applicaster/quick-brick-native-apple 5.16.0 → 5.18.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/apple/QuickBrickApple.podspec.json +2 -2
- package/apple/ios/LocalNotifications/ReactNativeManager+UNUserNotificationCenterDelegate.swift +7 -5
- package/apple/ios/ReactNative/PushBridge.swift +11 -11
- package/apple/ios/ReactNative/QuickBrickExceptionManager.swift +22 -20
- package/apple/ios/ReactNative/QuickBrickViewController.swift +15 -20
- package/apple/ios/ReactNative/ReactNativeManageriOS+UIApplicationDelegate.swift +15 -18
- package/apple/ios/ReactNativeEventEmitter.swift +19 -21
- package/apple/tvos/Helpers/FocusableGroupManager/FocusableGroupManager.swift +39 -39
- package/apple/tvos/Helpers/FocusableGroupManager/FocusableManagerModule.swift +18 -23
- package/apple/tvos/LocalNotifications/ReactNativeManager+UNUserNotificationCenterDelegate.swift +4 -3
- package/apple/tvos/ReactNative/QuickBrickViewController.swift +3 -3
- package/apple/tvos/Views/FocusableGroupView/FocusableGroupView.swift +118 -114
- package/apple/tvos/Views/FocusableGroupView/FocusableGroupViewConsts.swift +19 -19
- package/apple/tvos/Views/FocusableGroupView/FocusableGroupViewModule.swift +10 -10
- package/apple/tvos/Views/FocusableView/FocusableView+ParallaxViewDelegate.swift +14 -20
- package/apple/tvos/Views/FocusableView/FocusableView.swift +38 -40
- package/apple/tvos/Views/FocusableView/FocusableViewModule.swift +8 -9
- package/apple/tvos/Views/ParallaxView/Extensions/ParallaxableView+Extensions.swift +20 -26
- package/apple/tvos/Views/ParallaxView/Extensions/UIView+ParallaxEffect.swift +26 -28
- package/apple/tvos/Views/ParallaxView/Other/ParallaxEffectOptions.swift +5 -9
- package/apple/tvos/Views/ParallaxView/Other/ParallaxMotionEffect.swift +8 -12
- package/apple/tvos/Views/ParallaxView/Other/ParallaxableView.swift +0 -2
- package/apple/tvos/Views/ParallaxView/ParallaxCollectionViewCell.swift +17 -19
- package/apple/tvos/Views/ParallaxView/ParallaxView.swift +29 -31
- package/apple/tvos/Views/ParallaxView/Protocols/ParallaxViewDelegate.swift +6 -7
- package/apple/universal/ReactNative/AnalyticsBridge.swift +3 -3
- package/apple/universal/ReactNative/LocalNotification/LocalNotificationBridge.swift +8 -6
- package/apple/universal/ReactNative/OfflineAssetsBridge.swift +21 -15
- package/apple/universal/ReactNative/PluginsManagerBridge.swift +20 -15
- package/apple/universal/ReactNative/ReactNativeCommunicationModule.swift +15 -13
- package/apple/universal/ReactNative/ReactNativeManager+UIApplicationDelegate.swift +10 -9
- package/apple/universal/ReactNative/ReactNativeManager.swift +12 -9
- package/apple/universal/Storages/LocalStorage/LocalStorageBridge.swift +35 -20
- package/apple/universal/Storages/SessionStorage/SessionStorageBridge.swift +20 -12
- package/apple/universal/Utils/RTLLocales.swift +5 -5
- package/apple/universal/Utils/XrayLoggerTemplates/QuickBrickViewControllerLogs.swift +0 -2
- package/apple/universal/Utils/XrayLoggerTemplates/ReactNativeManagerLogs.swift +0 -1
- package/package.json +1 -1
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "QuickBrickApple",
|
|
3
|
-
"version": "5.
|
|
3
|
+
"version": "5.18.0",
|
|
4
4
|
"platforms": {
|
|
5
5
|
"ios": "14.0",
|
|
6
6
|
"tvos": "14.0"
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
"authors": "Applicaster LTD.",
|
|
17
17
|
"source": {
|
|
18
18
|
"git": "https://github.com/applicaster/Zapp-Frameworks.git",
|
|
19
|
-
"tag": "@@applicaster/quick-brick-native-apple/5.
|
|
19
|
+
"tag": "@@applicaster/quick-brick-native-apple/5.18.0"
|
|
20
20
|
},
|
|
21
21
|
"requires_arc": true,
|
|
22
22
|
"source_files": "universal/**/*.{m,swift}",
|
package/apple/ios/LocalNotifications/ReactNativeManager+UNUserNotificationCenterDelegate.swift
CHANGED
|
@@ -10,15 +10,17 @@ import React
|
|
|
10
10
|
import ZappCore
|
|
11
11
|
|
|
12
12
|
extension ReactNativeManager: UNUserNotificationCenterDelegate {
|
|
13
|
-
public func userNotificationCenter(_
|
|
14
|
-
willPresent
|
|
15
|
-
withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void)
|
|
13
|
+
public func userNotificationCenter(_: UNUserNotificationCenter,
|
|
14
|
+
willPresent _: UNNotification,
|
|
15
|
+
withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void)
|
|
16
|
+
{
|
|
16
17
|
completionHandler([.alert, .sound])
|
|
17
18
|
}
|
|
18
19
|
|
|
19
|
-
public func userNotificationCenter(_
|
|
20
|
+
public func userNotificationCenter(_: UNUserNotificationCenter,
|
|
20
21
|
didReceive response: UNNotificationResponse,
|
|
21
|
-
withCompletionHandler completionHandler: @escaping () -> Void)
|
|
22
|
+
withCompletionHandler completionHandler: @escaping () -> Void)
|
|
23
|
+
{
|
|
22
24
|
guard let url = LocalNotificationResponseParser.urlFromLocalNotification(response: response) else {
|
|
23
25
|
completionHandler()
|
|
24
26
|
return
|
|
@@ -16,16 +16,16 @@ class PushBridge: NSObject, RCTBridgeModule {
|
|
|
16
16
|
let getTagsErrorCode = "error_get_tags"
|
|
17
17
|
|
|
18
18
|
static func moduleName() -> String! {
|
|
19
|
-
|
|
19
|
+
"PushBridge"
|
|
20
20
|
}
|
|
21
21
|
|
|
22
22
|
public class func requiresMainQueueSetup() -> Bool {
|
|
23
|
-
|
|
23
|
+
true
|
|
24
24
|
}
|
|
25
25
|
|
|
26
26
|
/// prefered thread on which to run this native module
|
|
27
27
|
@objc public var methodQueue: DispatchQueue {
|
|
28
|
-
|
|
28
|
+
DispatchQueue.main
|
|
29
29
|
}
|
|
30
30
|
|
|
31
31
|
/// Subscribe the push provider with the tags passed as parameters
|
|
@@ -36,17 +36,16 @@ class PushBridge: NSObject, RCTBridgeModule {
|
|
|
36
36
|
/// - rejecter: rejecter when something fails
|
|
37
37
|
@objc func registerTags(_ tags: [String]?,
|
|
38
38
|
resolver: @escaping RCTPromiseResolveBlock,
|
|
39
|
-
rejecter: @escaping RCTPromiseRejectBlock)
|
|
40
|
-
|
|
39
|
+
rejecter: @escaping RCTPromiseRejectBlock)
|
|
40
|
+
{
|
|
41
41
|
FacadeConnector.connector?.push?.addTags(tags, completion: { result in
|
|
42
42
|
switch result {
|
|
43
|
-
case .success
|
|
43
|
+
case .success:
|
|
44
44
|
resolver(true)
|
|
45
45
|
case let .failure(error):
|
|
46
46
|
rejecter(self.addTagsErrorCode, error.description, nil)
|
|
47
47
|
}
|
|
48
48
|
})
|
|
49
|
-
|
|
50
49
|
}
|
|
51
50
|
|
|
52
51
|
/// Remove the tags from the push provider
|
|
@@ -57,11 +56,11 @@ class PushBridge: NSObject, RCTBridgeModule {
|
|
|
57
56
|
/// - rejecter: rejecter when something fails
|
|
58
57
|
@objc func unregisterTags(_ tags: [String]?,
|
|
59
58
|
resolver: @escaping RCTPromiseResolveBlock,
|
|
60
|
-
rejecter: @escaping RCTPromiseRejectBlock)
|
|
61
|
-
|
|
59
|
+
rejecter: @escaping RCTPromiseRejectBlock)
|
|
60
|
+
{
|
|
62
61
|
FacadeConnector.connector?.push?.removeTags(tags, completion: { result in
|
|
63
62
|
switch result {
|
|
64
|
-
case .success
|
|
63
|
+
case .success:
|
|
65
64
|
resolver(true)
|
|
66
65
|
case let .failure(error):
|
|
67
66
|
rejecter(self.removeTagsErrorCode, error.localizedDescription, nil)
|
|
@@ -74,7 +73,8 @@ class PushBridge: NSObject, RCTBridgeModule {
|
|
|
74
73
|
/// - Parameters:
|
|
75
74
|
/// - resolver: resolver when everything succeed
|
|
76
75
|
@objc func getRegisteredTags(_ resolver: @escaping RCTPromiseResolveBlock,
|
|
77
|
-
rejecter: @escaping RCTPromiseResolveBlock)
|
|
76
|
+
rejecter _: @escaping RCTPromiseResolveBlock)
|
|
77
|
+
{
|
|
78
78
|
let tags = FacadeConnector.connector?.push?.getDeviceTags()
|
|
79
79
|
resolver(tags)
|
|
80
80
|
}
|
|
@@ -16,43 +16,45 @@ class QuickBrickExceptionManager: RCTExceptionsManager, RCTExceptionsManagerDele
|
|
|
16
16
|
|
|
17
17
|
func handleSoftJSException(withMessage message: String?, stack: [Any]?, exceptionId: NSNumber) {
|
|
18
18
|
guard let message = message,
|
|
19
|
-
|
|
19
|
+
let stack = stack
|
|
20
|
+
else {
|
|
20
21
|
return
|
|
21
22
|
}
|
|
22
23
|
|
|
23
24
|
let logOrigin = OSLog(subsystem: "\(Self.self)", category: "handleSoftJSException")
|
|
24
25
|
os_log("handleSoftJSException message: %{public}@, stack: %{public}@",
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
26
|
+
log: logOrigin,
|
|
27
|
+
type: .error,
|
|
28
|
+
message, stack)
|
|
28
29
|
|
|
29
30
|
logger?.errorLog(message: ReactNativeManagerLogs.handleSoftJSException.message,
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
31
|
+
category: ReactNativeManagerLogs.handleSoftJSException.category,
|
|
32
|
+
data: [
|
|
33
|
+
"message": message,
|
|
34
|
+
"stack": stack,
|
|
35
|
+
"exceptionId": "\(exceptionId)",
|
|
36
|
+
])
|
|
36
37
|
}
|
|
37
38
|
|
|
38
39
|
func handleFatalJSException(withMessage message: String?, stack: [Any]?, exceptionId: NSNumber) {
|
|
39
40
|
guard let message = message,
|
|
40
|
-
|
|
41
|
+
let stack = stack
|
|
42
|
+
else {
|
|
41
43
|
return
|
|
42
44
|
}
|
|
43
45
|
|
|
44
46
|
let logOrigin = OSLog(subsystem: "\(Self.self)", category: "handleFatalJSException")
|
|
45
47
|
os_log("handleFatalJSException message: %{public}@, stack: %{public}@",
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
48
|
+
log: logOrigin,
|
|
49
|
+
type: .error,
|
|
50
|
+
message, stack)
|
|
49
51
|
|
|
50
52
|
logger?.errorLog(message: ReactNativeManagerLogs.handleFatalJSException.message,
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
53
|
+
category: ReactNativeManagerLogs.handleFatalJSException.category,
|
|
54
|
+
data: [
|
|
55
|
+
"message": message,
|
|
56
|
+
"stack": stack,
|
|
57
|
+
"exceptionId": "\(exceptionId)",
|
|
58
|
+
])
|
|
57
59
|
}
|
|
58
60
|
}
|
|
@@ -17,17 +17,17 @@ class QuickBrickViewController: UIViewController, UILayerViewControllerProtocol
|
|
|
17
17
|
}
|
|
18
18
|
|
|
19
19
|
lazy var logger = Logger.getLogger(for: QuickBrickViewControllerLogs.subsystem)
|
|
20
|
-
var currentOrientation = UIDevice.current.orientation
|
|
20
|
+
var currentOrientation = UIDevice.current.orientation
|
|
21
21
|
|
|
22
22
|
var orientationStack = [UIInterfaceOrientationMask.all]
|
|
23
23
|
var orientationMask: UIInterfaceOrientationMask = QuickBrickViewController.initialOrientationMask
|
|
24
24
|
|
|
25
25
|
override public var supportedInterfaceOrientations: UIInterfaceOrientationMask {
|
|
26
|
-
|
|
26
|
+
orientationMask
|
|
27
27
|
}
|
|
28
28
|
|
|
29
29
|
override public var shouldAutorotate: Bool {
|
|
30
|
-
|
|
30
|
+
true
|
|
31
31
|
}
|
|
32
32
|
|
|
33
33
|
static var initialOrientationMask: UIInterfaceOrientationMask {
|
|
@@ -43,7 +43,8 @@ class QuickBrickViewController: UIViewController, UILayerViewControllerProtocol
|
|
|
43
43
|
|
|
44
44
|
static var isTabletPortrait: Bool {
|
|
45
45
|
guard let value = FacadeConnector.connector?.storage?.sessionStorageValue(for: "isTabletPortrait",
|
|
46
|
-
namespace: nil)
|
|
46
|
+
namespace: nil)
|
|
47
|
+
else {
|
|
47
48
|
return false
|
|
48
49
|
}
|
|
49
50
|
return value.boolValue
|
|
@@ -75,21 +76,21 @@ class QuickBrickViewController: UIViewController, UILayerViewControllerProtocol
|
|
|
75
76
|
}
|
|
76
77
|
}
|
|
77
78
|
|
|
78
|
-
override func viewWillTransition(to
|
|
79
|
+
override func viewWillTransition(to _: CGSize, with _: UIViewControllerTransitionCoordinator) {
|
|
79
80
|
ReactNativeEventEmitter.orientationChange(toOrientation: UIDevice.current.orientation, fromOrientation: currentOrientation)
|
|
80
81
|
currentOrientation = UIDevice.current.orientation
|
|
81
82
|
}
|
|
82
83
|
|
|
83
84
|
override func viewWillAppear(_ animated: Bool) {
|
|
84
|
-
|
|
85
|
-
|
|
85
|
+
super.viewWillAppear(animated)
|
|
86
|
+
currentOrientation = UIDevice.current.orientation
|
|
86
87
|
}
|
|
87
88
|
|
|
88
89
|
private func mapOrientation(_ orientation: Int) -> UIInterfaceOrientationMask {
|
|
89
|
-
let JS_PORTAIT =
|
|
90
|
-
let JS_LANDSCAPE =
|
|
91
|
-
let JS_LANDSCAPE_REVERSED =
|
|
92
|
-
let JS_PORTAIT_REVERSED =
|
|
90
|
+
let JS_PORTAIT = 0x0000_0001
|
|
91
|
+
let JS_LANDSCAPE = 0x0000_0002 // landscapeRight: 2,
|
|
92
|
+
let JS_LANDSCAPE_REVERSED = 0x0000_0004
|
|
93
|
+
let JS_PORTAIT_REVERSED = 0x0000_0008
|
|
93
94
|
let JS_LANDSCAPE_SENSOR = JS_LANDSCAPE | JS_LANDSCAPE_REVERSED
|
|
94
95
|
let JS_PORTAIT_SENSOR = JS_PORTAIT | JS_PORTAIT_REVERSED
|
|
95
96
|
let JS_FULL_SENSOR = JS_LANDSCAPE_SENSOR | JS_PORTAIT_SENSOR
|
|
@@ -144,7 +145,6 @@ class QuickBrickViewController: UIViewController, UILayerViewControllerProtocol
|
|
|
144
145
|
if !UIDevice.current.orientation.isPortrait {
|
|
145
146
|
forceOrientation(UIInterfaceOrientation.portrait)
|
|
146
147
|
}
|
|
147
|
-
break
|
|
148
148
|
case UIInterfaceOrientationMask.landscape:
|
|
149
149
|
if !UIDevice.current.orientation.isLandscape {
|
|
150
150
|
let statusBarOrientation = UIApplication.shared.statusBarOrientation
|
|
@@ -154,29 +154,24 @@ class QuickBrickViewController: UIViewController, UILayerViewControllerProtocol
|
|
|
154
154
|
forceOrientation(UIInterfaceOrientation.landscapeRight)
|
|
155
155
|
}
|
|
156
156
|
}
|
|
157
|
-
break
|
|
158
157
|
case UIInterfaceOrientationMask.landscapeRight:
|
|
159
158
|
if UIDevice.current.orientation.rawValue != UIInterfaceOrientation.landscapeRight.rawValue {
|
|
160
159
|
forceOrientation(UIInterfaceOrientation.landscapeRight)
|
|
161
160
|
}
|
|
162
|
-
break
|
|
163
161
|
case UIInterfaceOrientationMask.landscapeLeft:
|
|
164
162
|
if UIDevice.current.orientation.rawValue != UIInterfaceOrientation.landscapeLeft.rawValue {
|
|
165
163
|
forceOrientation(UIInterfaceOrientation.landscapeLeft)
|
|
166
164
|
}
|
|
167
|
-
break
|
|
168
165
|
case UIInterfaceOrientationMask.all:
|
|
169
166
|
break
|
|
170
167
|
case UIInterfaceOrientationMask.allButUpsideDown:
|
|
171
|
-
if !UIDevice.current.orientation.isLandscape
|
|
168
|
+
if !UIDevice.current.orientation.isLandscape, UIDevice.current.orientation.rawValue != UIInterfaceOrientation.portrait.rawValue {
|
|
172
169
|
forceOrientation(UIInterfaceOrientation.portrait)
|
|
173
170
|
}
|
|
174
|
-
break
|
|
175
171
|
case UIInterfaceOrientationMask.portraitUpsideDown:
|
|
176
172
|
if UIDevice.current.orientation.rawValue != UIInterfaceOrientation.portraitUpsideDown.rawValue {
|
|
177
173
|
forceOrientation(UIInterfaceOrientation.portraitUpsideDown)
|
|
178
174
|
}
|
|
179
|
-
break
|
|
180
175
|
default:
|
|
181
176
|
break
|
|
182
177
|
}
|
|
@@ -190,8 +185,8 @@ class QuickBrickViewController: UIViewController, UILayerViewControllerProtocol
|
|
|
190
185
|
UIDevice.current.setValue(orientation.rawValue, forKey: "orientation")
|
|
191
186
|
UIViewController.attemptRotationToDeviceOrientation()
|
|
192
187
|
}
|
|
193
|
-
|
|
188
|
+
|
|
194
189
|
override var prefersHomeIndicatorAutoHidden: Bool {
|
|
195
|
-
|
|
190
|
+
homeIndicatorAutoHidden
|
|
196
191
|
}
|
|
197
192
|
}
|
|
@@ -9,8 +9,8 @@ import Foundation
|
|
|
9
9
|
import React
|
|
10
10
|
import ZappCore
|
|
11
11
|
|
|
12
|
-
extension ReactNativeManager {
|
|
13
|
-
func getLink(userInfo: [AnyHashable: Any]) -> String? {
|
|
12
|
+
public extension ReactNativeManager {
|
|
13
|
+
internal func getLink(userInfo: [AnyHashable: Any]) -> String? {
|
|
14
14
|
if let url = userInfo["url"] as? String {
|
|
15
15
|
return url
|
|
16
16
|
} else if let url = userInfo["^d"] as? String {
|
|
@@ -21,34 +21,31 @@ extension ReactNativeManager {
|
|
|
21
21
|
return nil
|
|
22
22
|
}
|
|
23
23
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
}
|
|
24
|
+
func application(_: UIApplication,
|
|
25
|
+
didReceiveRemoteNotification _: [AnyHashable: Any]) {}
|
|
27
26
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
27
|
+
func application(_: UIApplication,
|
|
28
|
+
didReceiveRemoteNotification userInfo: [AnyHashable: Any],
|
|
29
|
+
fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void)
|
|
30
|
+
{
|
|
31
31
|
let userInfo = userInfo
|
|
32
32
|
if let urlString = getLink(userInfo: userInfo),
|
|
33
|
-
|
|
33
|
+
let url = URL(string: urlString)
|
|
34
|
+
{
|
|
34
35
|
UIApplication.shared.open(url,
|
|
35
36
|
options: [:],
|
|
36
37
|
completionHandler: nil)
|
|
37
|
-
|
|
38
38
|
}
|
|
39
39
|
completionHandler(UIBackgroundFetchResult.newData)
|
|
40
|
-
|
|
41
40
|
}
|
|
42
41
|
|
|
43
|
-
|
|
42
|
+
func applicationWillResignActive(_: UIApplication) {
|
|
44
43
|
UIApplication.shared.applicationIconBadgeNumber = 0
|
|
45
44
|
}
|
|
46
45
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
}
|
|
46
|
+
func application(_: UIApplication,
|
|
47
|
+
didRegisterForRemoteNotificationsWithDeviceToken _: Data) {}
|
|
50
48
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
}
|
|
49
|
+
func application(_: UIApplication,
|
|
50
|
+
didFailToRegisterForRemoteNotificationsWithError _: Error) {}
|
|
54
51
|
}
|
|
@@ -8,28 +8,26 @@
|
|
|
8
8
|
import Foundation
|
|
9
9
|
import React
|
|
10
10
|
|
|
11
|
-
|
|
12
11
|
@objc(ReactNativeEventEmitter)
|
|
13
12
|
open class ReactNativeEventEmitter: RCTEventEmitter {
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
13
|
+
public static var emitter: RCTEventEmitter!
|
|
14
|
+
|
|
15
|
+
public static func orientationChange(toOrientation: UIDeviceOrientation, fromOrientation: UIDeviceOrientation) {
|
|
16
|
+
if toOrientation.rawValue > 0 {
|
|
17
|
+
emitter.sendEvent(withName: "orientationChange", body: ["toOrientation": toOrientation.mapOrientation(), "fromOrientation": fromOrientation.mapOrientation()])
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
override init() {
|
|
22
|
+
super.init()
|
|
23
|
+
ReactNativeEventEmitter.emitter = self
|
|
19
24
|
}
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
override init() {
|
|
23
|
-
super.init()
|
|
24
|
-
ReactNativeEventEmitter.emitter = self
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
override open func supportedEvents() -> [String] {
|
|
28
|
-
return ["orientationChange"]
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
override public class func requiresMainQueueSetup() -> Bool {
|
|
32
|
-
return true
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
25
|
|
|
26
|
+
override open func supportedEvents() -> [String] {
|
|
27
|
+
["orientationChange"]
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
override public class func requiresMainQueueSetup() -> Bool {
|
|
31
|
+
true
|
|
32
|
+
}
|
|
33
|
+
}
|
|
@@ -10,23 +10,23 @@ import Foundation
|
|
|
10
10
|
import React
|
|
11
11
|
|
|
12
12
|
/// Storage for focusable groups view [GroupID:FocusableGroupViewInstance]
|
|
13
|
-
var focusableGroups:[String:FocusableGroupView] = [:]
|
|
13
|
+
var focusableGroups: [String: FocusableGroupView] = [:]
|
|
14
14
|
|
|
15
15
|
/// Storage for focusable views [GroupID:[ViewID:FocusableViewIntance]]
|
|
16
|
-
var itemsGroups:[String:[String:FocusableView]] = [:]
|
|
16
|
+
var itemsGroups: [String: [String: FocusableView]] = [:]
|
|
17
17
|
|
|
18
18
|
/// Class control focusable group view with focusable items
|
|
19
19
|
class FocusableGroupManager {
|
|
20
|
-
|
|
21
20
|
/// Register FocusableView at storage
|
|
22
21
|
///
|
|
23
22
|
/// - Parameter item: FocusableView instance
|
|
24
|
-
class func registerView(item:FocusableView) -> Bool {
|
|
23
|
+
class func registerView(item: FocusableView) -> Bool {
|
|
25
24
|
guard let itemId = item.itemId,
|
|
26
|
-
|
|
25
|
+
let groupId = item.groupId
|
|
26
|
+
else {
|
|
27
27
|
return false
|
|
28
28
|
}
|
|
29
|
-
var newItemsGroup:[String:FocusableView] = [:]
|
|
29
|
+
var newItemsGroup: [String: FocusableView] = [:]
|
|
30
30
|
if let itemsGroup = itemsGroups[groupId] {
|
|
31
31
|
newItemsGroup = itemsGroup
|
|
32
32
|
}
|
|
@@ -39,7 +39,7 @@ class FocusableGroupManager {
|
|
|
39
39
|
/// Register FocusableGroup at storage
|
|
40
40
|
///
|
|
41
41
|
/// - Parameter item: FocusableGroup instance
|
|
42
|
-
class func registerFocusableGroup(group:FocusableGroupView) -> Bool {
|
|
42
|
+
class func registerFocusableGroup(group: FocusableGroupView) -> Bool {
|
|
43
43
|
var retVal = false
|
|
44
44
|
|
|
45
45
|
if let id = group.itemId {
|
|
@@ -47,35 +47,34 @@ class FocusableGroupManager {
|
|
|
47
47
|
retVal = true
|
|
48
48
|
}
|
|
49
49
|
return retVal
|
|
50
|
-
|
|
51
50
|
}
|
|
52
|
-
|
|
51
|
+
|
|
53
52
|
/// Retrieve group by ID
|
|
54
53
|
///
|
|
55
54
|
/// - Parameter groupID: ID of the group
|
|
56
55
|
/// - Returns: FocusableGroupView instance if registered into manager
|
|
57
|
-
class func group(by groupID:String) -> FocusableGroupView? {
|
|
56
|
+
class func group(by groupID: String) -> FocusableGroupView? {
|
|
58
57
|
guard let groupView = focusableGroups[groupID] else {
|
|
59
58
|
return nil
|
|
60
59
|
}
|
|
61
60
|
return groupView
|
|
62
61
|
}
|
|
63
|
-
|
|
62
|
+
|
|
64
63
|
/// Retrieve All items that connected to Group
|
|
65
64
|
///
|
|
66
65
|
/// - Parameter groupID: ID of the group
|
|
67
66
|
/// - Returns: Dictionary in format [ViewID:FocusableViewIntance]
|
|
68
|
-
class func itemsForGroup(by groupID:String) -> [String:FocusableView] {
|
|
67
|
+
class func itemsForGroup(by groupID: String) -> [String: FocusableView] {
|
|
69
68
|
guard let groupViewsDict = itemsGroups[groupID] else {
|
|
70
69
|
return [:]
|
|
71
70
|
}
|
|
72
71
|
return groupViewsDict
|
|
73
72
|
}
|
|
74
|
-
|
|
73
|
+
|
|
75
74
|
/// Notify group view that item relevant to it was updated
|
|
76
75
|
///
|
|
77
76
|
/// - Parameter groupID: ID of the group
|
|
78
|
-
class func notifyGroupView(groupID:String) {
|
|
77
|
+
class func notifyGroupView(groupID: String) {
|
|
79
78
|
DispatchQueue.main.async {
|
|
80
79
|
guard let groupView = focusableGroups[groupID] else {
|
|
81
80
|
return
|
|
@@ -84,19 +83,19 @@ class FocusableGroupManager {
|
|
|
84
83
|
groupView.groupItemsUpdated(groupItems: groupItems)
|
|
85
84
|
}
|
|
86
85
|
}
|
|
87
|
-
|
|
86
|
+
|
|
88
87
|
/// Retrieve FocusableView view instance
|
|
89
88
|
///
|
|
90
89
|
/// - Parameters:
|
|
91
90
|
/// - groupId: Id of the group
|
|
92
91
|
/// - itemId: Id of the FocusableView to search
|
|
93
92
|
/// - Returns: FocusableView instance if exist in searched group, otherwise nil
|
|
94
|
-
class func item(byGroupId groupId:String,
|
|
95
|
-
andItemId itemId:String) -> FocusableView?
|
|
96
|
-
|
|
93
|
+
class func item(byGroupId groupId: String,
|
|
94
|
+
andItemId itemId: String) -> FocusableView?
|
|
95
|
+
{
|
|
96
|
+
itemsForGroup(by: groupId).first(where: { $0.key == itemId })?.value
|
|
97
97
|
}
|
|
98
|
-
|
|
99
|
-
|
|
98
|
+
|
|
100
99
|
/// Make focus item focusable if exists and registered
|
|
101
100
|
///
|
|
102
101
|
/// - Parameters:
|
|
@@ -104,38 +103,40 @@ class FocusableGroupManager {
|
|
|
104
103
|
/// - itemId: Id of the focusable item
|
|
105
104
|
/// - needsForceUpdate: if value is true after make item as preferred item focus, It will also request Focus Engine to focus immidiately
|
|
106
105
|
/// - completion: completion block in case need, that will be called when focusable item did focus
|
|
107
|
-
class func updateFocus(_ groupId: String?, itemId: String?, needsForceUpdate:Bool = false, completion:((_ success:Bool) -> Void)? = nil) {
|
|
106
|
+
class func updateFocus(_ groupId: String?, itemId: String?, needsForceUpdate: Bool = false, completion: ((_ success: Bool) -> Void)? = nil) {
|
|
108
107
|
DispatchQueue.main.async {
|
|
109
|
-
|
|
110
108
|
if let groupId = groupId,
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
109
|
+
let itemId = itemId,
|
|
110
|
+
let groupView = focusableGroups[groupId],
|
|
111
|
+
let viewToFocus = FocusableGroupManager.item(byGroupId: groupId,
|
|
112
|
+
andItemId: itemId)
|
|
113
|
+
{
|
|
115
114
|
groupView.updatePrefferedFocusEnv(with: viewToFocus)
|
|
116
|
-
|
|
117
|
-
var rootView:UIView? = groupView
|
|
118
|
-
while
|
|
115
|
+
|
|
116
|
+
var rootView: UIView? = groupView
|
|
117
|
+
while rootView !== nil, rootView?.isReactRootView() == false {
|
|
119
118
|
if let unwrapedRootView = rootView,
|
|
120
|
-
|
|
119
|
+
let superView = unwrapedRootView.superview
|
|
120
|
+
{
|
|
121
121
|
rootView = superView
|
|
122
122
|
} else {
|
|
123
123
|
rootView = nil
|
|
124
124
|
}
|
|
125
125
|
}
|
|
126
|
-
|
|
126
|
+
|
|
127
127
|
if rootView == nil {
|
|
128
128
|
return
|
|
129
129
|
}
|
|
130
|
-
|
|
130
|
+
|
|
131
131
|
if let rootView = rootView,
|
|
132
|
-
|
|
132
|
+
let superView = rootView.superview as? RCTRootView
|
|
133
|
+
{
|
|
133
134
|
superView.reactPreferredFocusedView = viewToFocus
|
|
134
135
|
if needsForceUpdate == true {
|
|
135
136
|
superView.setNeedsFocusUpdate()
|
|
136
137
|
superView.updateFocusIfNeeded()
|
|
137
138
|
var completionWasCalled = false
|
|
138
|
-
|
|
139
|
+
|
|
139
140
|
// Timeout 2 seconds if did focus was not called by some reason, we are passing completion
|
|
140
141
|
DispatchQueue.main.asyncAfter(deadline: .now() + 2) {
|
|
141
142
|
if completionWasCalled == false {
|
|
@@ -143,16 +144,15 @@ class FocusableGroupManager {
|
|
|
143
144
|
groupView.didFocusCallBack = nil
|
|
144
145
|
}
|
|
145
146
|
}
|
|
146
|
-
|
|
147
|
-
groupView.didFocusCallBack = (completion:{
|
|
147
|
+
|
|
148
|
+
groupView.didFocusCallBack = (completion: {
|
|
148
149
|
completionWasCalled = true
|
|
149
150
|
completion?(true)
|
|
150
|
-
|
|
151
|
-
}, focusableItemId:itemId)
|
|
151
|
+
|
|
152
|
+
}, focusableItemId: itemId)
|
|
152
153
|
}
|
|
153
154
|
}
|
|
154
155
|
}
|
|
155
156
|
}
|
|
156
157
|
}
|
|
157
158
|
}
|
|
158
|
-
|
|
@@ -13,29 +13,26 @@ let kFocusableManagerModule = "FocusableManagerModule"
|
|
|
13
13
|
|
|
14
14
|
@objc(FocusableManagerModule)
|
|
15
15
|
class FocusableManagerModule: NSObject, RCTBridgeModule {
|
|
16
|
-
|
|
17
16
|
/// Delay timer before focus will be invoked, was done to resolve async problems.
|
|
18
17
|
/// Sometimes focusale item did has superview when it render that may cayse glitches.
|
|
19
18
|
var delayTimer = 100
|
|
20
|
-
|
|
19
|
+
|
|
21
20
|
/// main React bridge
|
|
22
21
|
public var bridge: RCTBridge?
|
|
23
|
-
|
|
24
|
-
|
|
22
|
+
|
|
25
23
|
static func moduleName() -> String! {
|
|
26
|
-
|
|
24
|
+
kFocusableManagerModule
|
|
27
25
|
}
|
|
28
|
-
|
|
26
|
+
|
|
29
27
|
public class func requiresMainQueueSetup() -> Bool {
|
|
30
|
-
|
|
28
|
+
true
|
|
31
29
|
}
|
|
32
|
-
|
|
30
|
+
|
|
33
31
|
/// prefered thread on which to run this native module
|
|
34
32
|
@objc public var methodQueue: DispatchQueue {
|
|
35
|
-
|
|
33
|
+
DispatchQueue.main
|
|
36
34
|
}
|
|
37
|
-
|
|
38
|
-
|
|
35
|
+
|
|
39
36
|
/// Updates next preffered focus item for focusable group
|
|
40
37
|
///
|
|
41
38
|
/// - Parameters:
|
|
@@ -45,32 +42,30 @@ class FocusableManagerModule: NSObject, RCTBridgeModule {
|
|
|
45
42
|
@objc func setPreferredFocus(_ groupId: String?, itemId: String?) {
|
|
46
43
|
// We need delay to make sure that on native side group will have superview
|
|
47
44
|
let delay = DispatchTime.now() + DispatchTimeInterval.milliseconds(delayTimer)
|
|
48
|
-
|
|
49
|
-
DispatchQueue.main.asyncAfter(deadline: delay)
|
|
45
|
+
|
|
46
|
+
DispatchQueue.main.asyncAfter(deadline: delay) {
|
|
50
47
|
FocusableGroupManager.updateFocus(groupId,
|
|
51
48
|
itemId: itemId)
|
|
52
49
|
}
|
|
53
|
-
|
|
54
50
|
}
|
|
55
|
-
|
|
51
|
+
|
|
56
52
|
/// Force updates next preffered focus item for focusable group
|
|
57
53
|
///
|
|
58
54
|
/// - Parameters:
|
|
59
55
|
/// - groupId: id of the focusable group
|
|
60
56
|
/// - itemId: id of the focusable item
|
|
61
57
|
/// - Note: This method is forcing focus engine to focus on focusable item in focusable group
|
|
62
|
-
@objc func forceFocus(_ groupId: String?, itemId: String?, callback:RCTResponseSenderBlock?) {
|
|
58
|
+
@objc func forceFocus(_ groupId: String?, itemId: String?, callback: RCTResponseSenderBlock?) {
|
|
63
59
|
// We need delay to make sure that on native side group will have superview
|
|
64
60
|
let delay = DispatchTime.now() + DispatchTimeInterval.milliseconds(delayTimer)
|
|
65
|
-
|
|
66
|
-
DispatchQueue.main.asyncAfter(deadline: delay)
|
|
61
|
+
|
|
62
|
+
DispatchQueue.main.asyncAfter(deadline: delay) {
|
|
67
63
|
FocusableGroupManager.updateFocus(groupId,
|
|
68
64
|
itemId: itemId,
|
|
69
|
-
needsForceUpdate: true, completion: {
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
65
|
+
needsForceUpdate: true, completion: { succeed in
|
|
66
|
+
callback?([succeed])
|
|
67
|
+
|
|
68
|
+
})
|
|
73
69
|
}
|
|
74
70
|
}
|
|
75
71
|
}
|
|
76
|
-
|