@applicaster/quick-brick-native-apple 6.18.0 → 6.19.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/tvos/Helpers/FocusableGroupManager/Coordinator/GroupProxyCoordinator.swift +10 -0
- package/apple/tvos/Helpers/FocusableGroupManager/Coordinator/SetItemFocus.swift +65 -10
- package/apple/tvos/Helpers/FocusableGroupManager/Coordinator/SetPreferredFocus.swift +14 -2
- package/apple/tvos/Helpers/FocusableGroupManager/GroupProxy.swift +24 -8
- package/apple/tvos/Helpers/FocusableGroupManager/GroupProxyManager.swift +55 -3
- package/apple/tvos/Views/FocusableGroupView/FocusableGroupView.swift +8 -46
- package/apple/tvos/Views/FocusableView/FocusableView.swift +9 -3
- package/apple/tvos/Views/ParallaxView/Protocols/FocusableGroupProtocol.swift +1 -1
- package/package.json +1 -1
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "QuickBrickApple",
|
|
3
|
-
"version": "6.
|
|
3
|
+
"version": "6.19.0",
|
|
4
4
|
"platforms": {
|
|
5
5
|
"ios": "16.0",
|
|
6
6
|
"tvos": "16.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/6.
|
|
19
|
+
"tag": "@@applicaster/quick-brick-native-apple/6.19.0"
|
|
20
20
|
},
|
|
21
21
|
"requires_arc": true,
|
|
22
22
|
"source_files": "universal/**/*.{m,swift}",
|
|
@@ -14,11 +14,16 @@ class GroupProxyCoordinator {
|
|
|
14
14
|
|
|
15
15
|
protocol Command {
|
|
16
16
|
var groupId: String { get }
|
|
17
|
+
var shouldDiscard: Bool { get }
|
|
17
18
|
func canBeApplied() -> Bool
|
|
18
19
|
func apply()
|
|
19
20
|
func cancel()
|
|
20
21
|
}
|
|
21
22
|
|
|
23
|
+
protocol QueueTimeoutCommand: Command {
|
|
24
|
+
func startQueueTimeout()
|
|
25
|
+
}
|
|
26
|
+
|
|
22
27
|
func tryApply(_ command: Command) {
|
|
23
28
|
lock.lock()
|
|
24
29
|
defer { lock.unlock() }
|
|
@@ -27,6 +32,7 @@ class GroupProxyCoordinator {
|
|
|
27
32
|
command.apply()
|
|
28
33
|
} else {
|
|
29
34
|
commandsQueue.append(command)
|
|
35
|
+
(command as? QueueTimeoutCommand)?.startQueueTimeout()
|
|
30
36
|
}
|
|
31
37
|
}
|
|
32
38
|
|
|
@@ -37,6 +43,10 @@ class GroupProxyCoordinator {
|
|
|
37
43
|
lock.unlock()
|
|
38
44
|
|
|
39
45
|
for command in commands {
|
|
46
|
+
if command.shouldDiscard {
|
|
47
|
+
continue
|
|
48
|
+
}
|
|
49
|
+
|
|
40
50
|
if command.canBeApplied() {
|
|
41
51
|
command.apply()
|
|
42
52
|
} else {
|
|
@@ -9,7 +9,7 @@ import Foundation
|
|
|
9
9
|
import UIKit
|
|
10
10
|
|
|
11
11
|
extension GroupProxyCoordinator {
|
|
12
|
-
class SetItemFocus: Command {
|
|
12
|
+
class SetItemFocus: Command, QueueTimeoutCommand {
|
|
13
13
|
let groupId: String
|
|
14
14
|
let itemId: String
|
|
15
15
|
let needsForceUpdate: Bool
|
|
@@ -17,6 +17,15 @@ extension GroupProxyCoordinator {
|
|
|
17
17
|
weak var manager: GroupProxyManager?
|
|
18
18
|
private var isCancelled = false
|
|
19
19
|
private let lock = NSLock()
|
|
20
|
+
private var queueTimeoutWorkItem: DispatchWorkItem?
|
|
21
|
+
|
|
22
|
+
private static let queueTimeout: TimeInterval = 5.0
|
|
23
|
+
|
|
24
|
+
var shouldDiscard: Bool {
|
|
25
|
+
lock.lock()
|
|
26
|
+
defer { lock.unlock() }
|
|
27
|
+
return isCancelled
|
|
28
|
+
}
|
|
20
29
|
|
|
21
30
|
init(groupId: String,
|
|
22
31
|
itemId: String,
|
|
@@ -30,6 +39,37 @@ extension GroupProxyCoordinator {
|
|
|
30
39
|
self.manager = manager
|
|
31
40
|
}
|
|
32
41
|
|
|
42
|
+
func startQueueTimeout() {
|
|
43
|
+
lock.lock()
|
|
44
|
+
defer { lock.unlock() }
|
|
45
|
+
|
|
46
|
+
guard !isCancelled else { return }
|
|
47
|
+
|
|
48
|
+
let workItem = DispatchWorkItem { [weak self] in
|
|
49
|
+
self?.handleQueueTimeout()
|
|
50
|
+
}
|
|
51
|
+
queueTimeoutWorkItem = workItem
|
|
52
|
+
DispatchQueue.main.asyncAfter(deadline: .now() + Self.queueTimeout, execute: workItem)
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
private func handleQueueTimeout() {
|
|
56
|
+
lock.lock()
|
|
57
|
+
if isCancelled {
|
|
58
|
+
lock.unlock()
|
|
59
|
+
return
|
|
60
|
+
}
|
|
61
|
+
isCancelled = true
|
|
62
|
+
queueTimeoutWorkItem = nil
|
|
63
|
+
lock.unlock()
|
|
64
|
+
|
|
65
|
+
completion?(false)
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
private func cancelQueueTimeout() {
|
|
69
|
+
queueTimeoutWorkItem?.cancel()
|
|
70
|
+
queueTimeoutWorkItem = nil
|
|
71
|
+
}
|
|
72
|
+
|
|
33
73
|
func canBeApplied() -> Bool {
|
|
34
74
|
lock.lock()
|
|
35
75
|
defer { lock.unlock() }
|
|
@@ -65,9 +105,9 @@ extension GroupProxyCoordinator {
|
|
|
65
105
|
|
|
66
106
|
func apply() {
|
|
67
107
|
lock.lock()
|
|
108
|
+
cancelQueueTimeout()
|
|
68
109
|
if isCancelled {
|
|
69
110
|
lock.unlock()
|
|
70
|
-
completion?(false)
|
|
71
111
|
return
|
|
72
112
|
}
|
|
73
113
|
lock.unlock()
|
|
@@ -80,26 +120,41 @@ extension GroupProxyCoordinator {
|
|
|
80
120
|
return
|
|
81
121
|
}
|
|
82
122
|
|
|
83
|
-
|
|
123
|
+
guard needsForceUpdate else {
|
|
124
|
+
let completionHandler = completion
|
|
125
|
+
DispatchQueue.main.async {
|
|
126
|
+
groupView.forceFocus(
|
|
127
|
+
view: focusableView,
|
|
128
|
+
needsForceUpdate: false
|
|
129
|
+
)
|
|
130
|
+
completionHandler?(true)
|
|
131
|
+
}
|
|
132
|
+
return
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
let completionHandler = completion
|
|
136
|
+
manager.setForceFocusUpdateData(itemId: itemId, groupId: groupId, callback: { success in
|
|
137
|
+
completionHandler?(success)
|
|
138
|
+
})
|
|
84
139
|
|
|
85
|
-
DispatchQueue.main.async {
|
|
140
|
+
DispatchQueue.main.async {
|
|
86
141
|
groupView.forceFocus(
|
|
87
142
|
view: focusableView,
|
|
88
|
-
needsForceUpdate:
|
|
89
|
-
callback: { success in
|
|
90
|
-
manager?.clearForceFocusUpdate()
|
|
91
|
-
self.completion?(success)
|
|
92
|
-
}
|
|
143
|
+
needsForceUpdate: true
|
|
93
144
|
)
|
|
94
145
|
}
|
|
95
146
|
}
|
|
96
147
|
|
|
97
148
|
func cancel() {
|
|
98
149
|
lock.lock()
|
|
150
|
+
cancelQueueTimeout()
|
|
151
|
+
let wasAlreadyCancelled = isCancelled
|
|
99
152
|
isCancelled = true
|
|
100
153
|
lock.unlock()
|
|
101
154
|
|
|
102
|
-
|
|
155
|
+
if !wasAlreadyCancelled {
|
|
156
|
+
completion?(false)
|
|
157
|
+
}
|
|
103
158
|
}
|
|
104
159
|
}
|
|
105
160
|
}
|
|
@@ -17,6 +17,12 @@ extension GroupProxyCoordinator {
|
|
|
17
17
|
private var isCancelled = false
|
|
18
18
|
private let lock = NSLock()
|
|
19
19
|
|
|
20
|
+
var shouldDiscard: Bool {
|
|
21
|
+
lock.lock()
|
|
22
|
+
defer { lock.unlock() }
|
|
23
|
+
return isCancelled
|
|
24
|
+
}
|
|
25
|
+
|
|
20
26
|
init(groupId: String,
|
|
21
27
|
itemId: String,
|
|
22
28
|
isPreferred: Bool,
|
|
@@ -41,6 +47,10 @@ extension GroupProxyCoordinator {
|
|
|
41
47
|
return false
|
|
42
48
|
}
|
|
43
49
|
|
|
50
|
+
if group.isFocusDisabled {
|
|
51
|
+
return false
|
|
52
|
+
}
|
|
53
|
+
|
|
44
54
|
if !proxy.isExistingChild(itemId) {
|
|
45
55
|
return false
|
|
46
56
|
}
|
|
@@ -71,8 +81,10 @@ extension GroupProxyCoordinator {
|
|
|
71
81
|
return
|
|
72
82
|
}
|
|
73
83
|
|
|
74
|
-
|
|
75
|
-
|
|
84
|
+
let isPreferred = isPreferred
|
|
85
|
+
DispatchQueue.main.async { [weak self] in
|
|
86
|
+
guard self != nil else { return }
|
|
87
|
+
if isPreferred {
|
|
76
88
|
group.setUserPreferredFocusEnvironments([focusableView])
|
|
77
89
|
} else if let currentPreferred = group.getUserPreferredFocusEnvironments()?.first as? FocusableView,
|
|
78
90
|
currentPreferred === focusableView {
|
|
@@ -26,7 +26,16 @@ class GroupProxy {
|
|
|
26
26
|
lock.lock()
|
|
27
27
|
defer { lock.unlock() }
|
|
28
28
|
|
|
29
|
-
|
|
29
|
+
guard let box = children[itemId] else {
|
|
30
|
+
return nil
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
guard let view = box.value else {
|
|
34
|
+
children.removeValue(forKey: itemId)
|
|
35
|
+
return nil
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
return view
|
|
30
39
|
}
|
|
31
40
|
|
|
32
41
|
// MARK: - Child Management
|
|
@@ -66,7 +75,17 @@ class GroupProxy {
|
|
|
66
75
|
func isExistingChild(_ itemId: String) -> Bool {
|
|
67
76
|
lock.lock()
|
|
68
77
|
defer { lock.unlock() }
|
|
69
|
-
|
|
78
|
+
|
|
79
|
+
guard let box = children[itemId] else {
|
|
80
|
+
return false
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
guard box.value != nil else {
|
|
84
|
+
children.removeValue(forKey: itemId)
|
|
85
|
+
return false
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
return true
|
|
70
89
|
}
|
|
71
90
|
|
|
72
91
|
// MARK: - Group Binding
|
|
@@ -101,7 +120,7 @@ class GroupProxy {
|
|
|
101
120
|
coordinator?.onGroupBound(groupId: groupId)
|
|
102
121
|
}
|
|
103
122
|
|
|
104
|
-
func unbindGroup(expectedGroup: FocusableGroupView) {
|
|
123
|
+
@MainActor func unbindGroup(expectedGroup: FocusableGroupView) {
|
|
105
124
|
if let group,
|
|
106
125
|
group !== expectedGroup {
|
|
107
126
|
logger?.warningLog(message: """
|
|
@@ -109,7 +128,7 @@ class GroupProxy {
|
|
|
109
128
|
Expected group: \(expectedGroup.debugDescription)
|
|
110
129
|
Current bound group: \(String(describing: group.debugDescription))
|
|
111
130
|
identifier1: \(ObjectIdentifier(expectedGroup))
|
|
112
|
-
identifier2: \(ObjectIdentifier(group))
|
|
131
|
+
identifier2: \(ObjectIdentifier(group))
|
|
113
132
|
Skipping unbind.
|
|
114
133
|
""")
|
|
115
134
|
|
|
@@ -117,6 +136,7 @@ class GroupProxy {
|
|
|
117
136
|
}
|
|
118
137
|
|
|
119
138
|
lock.lock()
|
|
139
|
+
group = nil
|
|
120
140
|
let shouldRemoveProxy = children.isEmpty
|
|
121
141
|
lock.unlock()
|
|
122
142
|
|
|
@@ -124,10 +144,6 @@ class GroupProxy {
|
|
|
124
144
|
coordinator?.cancelCommandsForGroup(groupId: groupId)
|
|
125
145
|
GroupProxyManager.shared.removeProxy(forGroupId: groupId)
|
|
126
146
|
}
|
|
127
|
-
|
|
128
|
-
lock.lock()
|
|
129
|
-
group = nil
|
|
130
|
-
lock.unlock()
|
|
131
147
|
}
|
|
132
148
|
|
|
133
149
|
// MARK: - Preferred Focus
|
|
@@ -56,20 +56,72 @@ class GroupProxyManager {
|
|
|
56
56
|
proxies.removeValue(forKey: groupId)
|
|
57
57
|
}
|
|
58
58
|
|
|
59
|
-
// MARK: - Focus Update
|
|
59
|
+
// MARK: - Force Focus Update
|
|
60
60
|
|
|
61
61
|
private var forceFocusUpdateData: (itemId: String, groupId: String)?
|
|
62
|
+
private var forceFocusCallback: ((Bool) -> Void)?
|
|
62
63
|
|
|
63
|
-
|
|
64
|
+
private var forceFocusTimer: Timer?
|
|
65
|
+
|
|
66
|
+
func setForceFocusUpdateData(itemId: String, groupId: String, callback: ((Bool) -> Void)?) {
|
|
64
67
|
lock.lock()
|
|
68
|
+
|
|
69
|
+
let previousCallback = forceFocusCallback
|
|
65
70
|
forceFocusUpdateData = (itemId: itemId, groupId: groupId)
|
|
71
|
+
forceFocusCallback = callback
|
|
66
72
|
lock.unlock()
|
|
73
|
+
|
|
74
|
+
DispatchQueue.main.async { [weak self] in
|
|
75
|
+
previousCallback?(false)
|
|
76
|
+
|
|
77
|
+
self?.forceFocusTimer?.invalidate()
|
|
78
|
+
self?.startForceFocusTimer()
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
private func startForceFocusTimer() {
|
|
83
|
+
let timeout: TimeInterval = 1
|
|
84
|
+
forceFocusTimer = Timer.scheduledTimer(withTimeInterval: timeout, repeats: false) { [weak self] _ in
|
|
85
|
+
self?.handleForceFocusTimeout()
|
|
86
|
+
}
|
|
67
87
|
}
|
|
68
88
|
|
|
69
|
-
func
|
|
89
|
+
private func handleForceFocusTimeout() {
|
|
90
|
+
forceFocusTimer = nil
|
|
91
|
+
|
|
70
92
|
lock.lock()
|
|
93
|
+
let callback = forceFocusCallback
|
|
94
|
+
forceFocusCallback = nil
|
|
71
95
|
forceFocusUpdateData = nil
|
|
72
96
|
lock.unlock()
|
|
97
|
+
|
|
98
|
+
callback?(false)
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
@MainActor
|
|
102
|
+
func notifyFocusDidUpdate(focusedView: FocusableView?) {
|
|
103
|
+
lock.lock()
|
|
104
|
+
|
|
105
|
+
guard let focusData = forceFocusUpdateData,
|
|
106
|
+
let callback = forceFocusCallback else {
|
|
107
|
+
lock.unlock()
|
|
108
|
+
return
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
guard let focusedView,
|
|
112
|
+
focusedView.itemId == focusData.itemId,
|
|
113
|
+
focusedView.groupId == focusData.groupId else {
|
|
114
|
+
lock.unlock()
|
|
115
|
+
return
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
forceFocusCallback = nil
|
|
119
|
+
forceFocusUpdateData = nil
|
|
120
|
+
lock.unlock()
|
|
121
|
+
|
|
122
|
+
forceFocusTimer?.invalidate()
|
|
123
|
+
forceFocusTimer = nil
|
|
124
|
+
callback(true)
|
|
73
125
|
}
|
|
74
126
|
|
|
75
127
|
func focusableViewCanBecomeFocusableForceFocusUpdate(groupId: String?, itemId: String?) -> Bool? {
|
|
@@ -35,7 +35,6 @@ public class FocusableGroupView: RCTTVView {
|
|
|
35
35
|
}
|
|
36
36
|
|
|
37
37
|
public private(set) var isPresented: Bool = false
|
|
38
|
-
private var focusTimer: Timer?
|
|
39
38
|
|
|
40
39
|
override public func didMoveToWindow() {
|
|
41
40
|
super.didMoveToWindow()
|
|
@@ -74,8 +73,6 @@ public class FocusableGroupView: RCTTVView {
|
|
|
74
73
|
isGroupRegistered = true
|
|
75
74
|
}
|
|
76
75
|
|
|
77
|
-
public var didForceFocusCallBack: ((Bool) -> Void)?
|
|
78
|
-
|
|
79
76
|
private let activeStateNotifier = FocusableGroupStateNotifierDefault()
|
|
80
77
|
|
|
81
78
|
@objc public var onGroupFocus: RCTDirectEventBlock?
|
|
@@ -107,6 +104,9 @@ public class FocusableGroupView: RCTTVView {
|
|
|
107
104
|
}
|
|
108
105
|
}
|
|
109
106
|
|
|
107
|
+
/// Parent group ID for nested group hierarchy.
|
|
108
|
+
/// Currently used for informational purposes only (passed to React Native events).
|
|
109
|
+
/// If nested group registration is needed, implement didSet with proxy registration similar to FocusableView.
|
|
110
110
|
@objc public var groupId: String?
|
|
111
111
|
|
|
112
112
|
func sendGroupRegisteredEvent() {
|
|
@@ -138,69 +138,31 @@ public class FocusableGroupView: RCTTVView {
|
|
|
138
138
|
}
|
|
139
139
|
|
|
140
140
|
deinit {
|
|
141
|
-
focusTimer?.invalidate()
|
|
142
|
-
focusTimer = nil
|
|
143
141
|
cleanup()
|
|
144
142
|
}
|
|
145
143
|
|
|
146
144
|
@MainActor public func forceFocus(view: FocusableView,
|
|
147
|
-
needsForceUpdate: Bool
|
|
148
|
-
callback completion: ((Bool) -> Void)?) {
|
|
145
|
+
needsForceUpdate: Bool) {
|
|
149
146
|
updatePreferredFocusEnv(with: view)
|
|
150
147
|
|
|
151
|
-
|
|
152
|
-
completion?(true)
|
|
148
|
+
guard needsForceUpdate else {
|
|
153
149
|
return
|
|
154
150
|
}
|
|
155
151
|
|
|
156
152
|
guard let rootView = UIApplication.shared.rootViewController()?.view as? RCTRootView else {
|
|
157
|
-
completion?(false)
|
|
158
153
|
return
|
|
159
154
|
}
|
|
160
155
|
|
|
161
156
|
guard itemId != nil else {
|
|
162
|
-
completion?(false)
|
|
163
157
|
return
|
|
164
158
|
}
|
|
165
159
|
|
|
166
|
-
focusTimer?.invalidate()
|
|
167
|
-
focusTimer = nil
|
|
168
|
-
|
|
169
|
-
didForceFocusCallBack = { [weak self] success in
|
|
170
|
-
guard let self else {
|
|
171
|
-
completion?(false)
|
|
172
|
-
return
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
focusTimer?.invalidate()
|
|
176
|
-
focusTimer = nil
|
|
177
|
-
|
|
178
|
-
completion?(success)
|
|
179
|
-
didForceFocusCallBack = nil
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
let cancelationTimeout: TimeInterval = 1
|
|
183
|
-
focusTimer?.invalidate()
|
|
184
|
-
focusTimer = Timer.scheduledTimer(withTimeInterval: cancelationTimeout, repeats: false) { [weak self] _ in
|
|
185
|
-
guard let self else {
|
|
186
|
-
completion?(false)
|
|
187
|
-
return
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
if let callback = didForceFocusCallBack {
|
|
191
|
-
callback(false)
|
|
192
|
-
didForceFocusCallBack = nil
|
|
193
|
-
}
|
|
194
|
-
|
|
195
|
-
focusTimer = nil
|
|
196
|
-
}
|
|
197
|
-
|
|
198
160
|
rootView.setNeedsFocusUpdate()
|
|
199
161
|
rootView.updateFocusIfNeeded()
|
|
200
162
|
}
|
|
201
163
|
|
|
202
164
|
private func cleanup() {
|
|
203
|
-
guard
|
|
165
|
+
guard isGroupRegistered else {
|
|
204
166
|
return
|
|
205
167
|
}
|
|
206
168
|
|
|
@@ -365,7 +327,7 @@ public class FocusableGroupView: RCTTVView {
|
|
|
365
327
|
updatePreferredFocusView(nextFocusItem: context.nextFocusedItem)
|
|
366
328
|
}
|
|
367
329
|
|
|
368
|
-
|
|
330
|
+
GroupProxyManager.shared.notifyFocusDidUpdate(focusedView: context.nextFocusedView as? FocusableView)
|
|
369
331
|
|
|
370
332
|
let isActive = focusItemIsDescendant(nextFocusItem: context.nextFocusedItem)
|
|
371
333
|
activeStateNotifier.updateFocus(currentlyActive: isActive, context: context)
|
|
@@ -373,7 +335,7 @@ public class FocusableGroupView: RCTTVView {
|
|
|
373
335
|
}
|
|
374
336
|
|
|
375
337
|
extension FocusableGroupView: FocusableGroupProtocol {
|
|
376
|
-
var
|
|
338
|
+
var canChildrenBecomeFocused: Bool {
|
|
377
339
|
if let forceFocusEnabled = GroupProxyManager.shared.focusableGroupCanBecomeFocusableForceFocusUpdate(groupId: itemId) {
|
|
378
340
|
return forceFocusEnabled
|
|
379
341
|
}
|
|
@@ -112,11 +112,12 @@ public class FocusableView: ParallaxView {
|
|
|
112
112
|
delegate = self
|
|
113
113
|
}
|
|
114
114
|
|
|
115
|
-
@objc
|
|
115
|
+
@objc public var itemId: String? {
|
|
116
116
|
didSet {
|
|
117
117
|
if itemId != oldValue {
|
|
118
118
|
if oldValue != nil {
|
|
119
119
|
proxy?.removeChild(self)
|
|
120
|
+
proxy = nil
|
|
120
121
|
isViewRegistered = false
|
|
121
122
|
}
|
|
122
123
|
|
|
@@ -125,7 +126,7 @@ public class FocusableView: ParallaxView {
|
|
|
125
126
|
}
|
|
126
127
|
}
|
|
127
128
|
|
|
128
|
-
@objc
|
|
129
|
+
@objc public var groupId: String? {
|
|
129
130
|
didSet {
|
|
130
131
|
if groupId != oldValue {
|
|
131
132
|
if oldValue != nil {
|
|
@@ -172,8 +173,13 @@ public class FocusableView: ParallaxView {
|
|
|
172
173
|
}
|
|
173
174
|
|
|
174
175
|
private func cleanup() {
|
|
176
|
+
guard isViewRegistered else {
|
|
177
|
+
return
|
|
178
|
+
}
|
|
179
|
+
|
|
175
180
|
proxy?.removeChild(self)
|
|
176
181
|
proxy = nil
|
|
182
|
+
isViewRegistered = false
|
|
177
183
|
}
|
|
178
184
|
|
|
179
185
|
private func addFocusGuideIfNeeded(tag: NSNumber?,
|
|
@@ -258,6 +264,6 @@ public class FocusableView: ParallaxView {
|
|
|
258
264
|
return forceFocusEnabled
|
|
259
265
|
}
|
|
260
266
|
|
|
261
|
-
return focusableGroup.
|
|
267
|
+
return focusableGroup.canChildrenBecomeFocused && focusable
|
|
262
268
|
}
|
|
263
269
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@applicaster/quick-brick-native-apple",
|
|
3
|
-
"version": "6.
|
|
3
|
+
"version": "6.19.0",
|
|
4
4
|
"description": "iOS and tvOS native code for QuickBrick applications. This package is used to provide native logic for QuickBrick",
|
|
5
5
|
"scripts": {
|
|
6
6
|
"test": "echo \"Error: no test specified\" && exit 1"
|