Skip to content

Commit ae46567

Browse files
committed
Update
1 parent 425b665 commit ae46567

4 files changed

Lines changed: 69 additions & 110 deletions

File tree

Sources/FluidCore/SafeAreaFinder.swift

Lines changed: 34 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -16,51 +16,28 @@ public final class SafeAreaFinder: NSObject {
1616
@available(iOS 13.0, *)
1717
public weak var windowScene: UIWindowScene?
1818

19-
public weak var window: UIWindow?
20-
2119
private var currentInsets: UIEdgeInsets? = nil
2220

23-
private var referenceCounter: Int = 0 {
24-
didSet {
25-
if referenceCounter > 0 {
26-
currentDisplayLink.isPaused = false
27-
} else {
28-
currentDisplayLink.isPaused = true
29-
}
30-
}
31-
}
32-
33-
private nonisolated(unsafe) var currentDisplayLink: CADisplayLink!
21+
private var isRunning: Bool = false
3422

35-
public override init() {
36-
37-
super.init()
38-
39-
setUpDisplayLink()
40-
}
23+
private nonisolated(unsafe) var currentDisplayLink: CADisplayLink?
4124

4225
@available(iOS 13.0, *)
43-
public init(windowScene: UIWindowScene) {
26+
public init(windowScene: UIWindowScene?) {
4427
self.windowScene = windowScene
4528

4629
super.init()
47-
48-
setUpDisplayLink()
49-
}
50-
51-
public init(window: UIWindow) {
52-
self.window = window
53-
54-
super.init()
55-
56-
setUpDisplayLink()
5730
}
5831

5932
private func setUpDisplayLink() {
33+
guard currentDisplayLink == nil else {
34+
return
35+
}
36+
6037
currentDisplayLink = .init(target: self, selector: #selector(handle))
61-
currentDisplayLink.preferredFramesPerSecond = 1
62-
currentDisplayLink.add(to: .main, forMode: .default)
63-
currentDisplayLink.isPaused = true
38+
currentDisplayLink?.preferredFramesPerSecond = 1
39+
currentDisplayLink?.add(to: .main, forMode: .default)
40+
currentDisplayLink?.isPaused = false
6441
}
6542

6643
public func request() {
@@ -69,36 +46,47 @@ public final class SafeAreaFinder: NSObject {
6946
}
7047

7148
public func start() {
72-
referenceCounter += 1
49+
guard isRunning == false else {
50+
request()
51+
return
52+
}
53+
54+
isRunning = true
55+
setUpDisplayLink()
7356
request()
7457
}
7558

59+
/// Stops polling and releases the display link so the finder can deallocate when its owner goes away.
60+
public func stop() {
61+
guard isRunning || currentDisplayLink != nil else {
62+
return
63+
}
64+
65+
isRunning = false
66+
currentInsets = nil
67+
currentDisplayLink?.invalidate()
68+
currentDisplayLink = nil
69+
}
70+
71+
/// Stops polling. Kept as a compatibility alias for older callers that used the reference-counted API.
7672
public func pause() {
77-
referenceCounter -= 1
73+
stop()
7874
}
7975

8076
deinit {
81-
currentDisplayLink?.isPaused = true
8277
currentDisplayLink?.invalidate()
8378
}
8479

8580
@objc private dynamic func handle() {
86-
if let window {
87-
_handle(in: window)
88-
return
89-
}
9081

91-
if #available(iOS 13.0, *), let windowScene {
92-
guard let window = windowScene.windows.first(where: \.isKeyWindow) ?? windowScene.windows.first else {
93-
return
94-
}
95-
_handle(in: window)
82+
guard let windowScene else {
9683
return
9784
}
9885

99-
guard let window = UIApplication.shared.delegate?.window ?? nil else {
86+
guard let window = windowScene.windows.first(where: \.isKeyWindow) ?? windowScene.windows.first else {
10087
return
10188
}
89+
10290
_handle(in: window)
10391
}
10492

Sources/FluidPictureInPicture/FluidPictureInPictureController.swift

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,7 @@ extension FluidPictureInPictureController {
104104
let containerView: ContainerView = .init()
105105

106106
let sizeForFloating = CGSize(width: 100, height: 140)
107-
let safeAreaFinder = SafeAreaFinder()
107+
let safeAreaFinder: SafeAreaFinder
108108

109109
private(set) var state: State = .init() {
110110
didSet {
@@ -124,6 +124,9 @@ extension FluidPictureInPictureController {
124124
override init(
125125
frame: CGRect
126126
) {
127+
128+
self.safeAreaFinder = .init(windowScene: nil)
129+
127130
super.init(frame: frame)
128131

129132
let dragGesture = UIPanGestureRecognizer(target: self, action: #selector(handlePanGesture))
@@ -232,7 +235,7 @@ extension FluidPictureInPictureController {
232235
override func didMoveToWindow() {
233236
super.didMoveToWindow()
234237

235-
safeAreaFinder.window = window
238+
safeAreaFinder.windowScene = window?.windowScene
236239

237240
if window != nil {
238241
safeAreaFinder.start()

Sources/FluidSnackbar/FloatingDisplayController.swift

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -33,10 +33,6 @@ open class FloatingDisplayController {
3333

3434
// MARK: - Initializers
3535

36-
public init(edgeTargetSafeArea: FloatingDisplayTarget.EdgeTargetSafeArea) {
37-
self.displayTarget = .init(edgeTargetSafeArea: edgeTargetSafeArea)
38-
}
39-
4036
@available(iOS 13.0, *)
4137
public init(
4238
edgeTargetSafeArea: FloatingDisplayTarget.EdgeTargetSafeArea,

Sources/FluidSnackbar/FloatingDisplayTarget.swift

Lines changed: 30 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -40,9 +40,16 @@ public final class FloatingDisplayTarget {
4040
left: .activeWindow
4141
)
4242
}
43+
44+
fileprivate var containsActiveWindowEdge: Bool {
45+
top == .activeWindow
46+
|| right == .activeWindow
47+
|| bottom == .activeWindow
48+
|| left == .activeWindow
49+
}
4350
}
4451

45-
public enum TargetSafeArea {
52+
public enum TargetSafeArea: Equatable {
4653
case notificationWindow
4754
case activeWindow
4855
}
@@ -70,54 +77,17 @@ public final class FloatingDisplayTarget {
7077
}
7178

7279
public func makeWindowVisible() {
80+
_ = notificationViewController.view
7381
notificationWindow.isHidden = false
74-
}
7582

76-
public func hideWindow() {
77-
notificationWindow.isHidden = true
78-
}
79-
80-
public init(edgeTargetSafeArea: EdgeTargetSafeArea) {
81-
82-
if #available(iOS 13, *) {
83-
let windowScene = UIApplication.shared
84-
.connectedScenes
85-
.lazy
86-
.filter({ $0.activationState == .foregroundActive })
87-
.compactMap({ $0 as? UIWindowScene })
88-
.first
89-
if let windowScene {
90-
self.safeAreaFinder = .init(windowScene: windowScene)
91-
self.notificationViewController = .init(
92-
edgeTargetSafeArea: edgeTargetSafeArea,
93-
safeAreaFinder: safeAreaFinder
94-
)
95-
notificationWindow = .init(windowScene: windowScene)
96-
} else {
97-
self.safeAreaFinder = .init()
98-
self.notificationViewController = .init(
99-
edgeTargetSafeArea: edgeTargetSafeArea,
100-
safeAreaFinder: safeAreaFinder
101-
)
102-
notificationWindow = .init(frame: .zero)
103-
}
104-
105-
} else {
106-
self.safeAreaFinder = .init()
107-
self.notificationViewController = .init(
108-
edgeTargetSafeArea: edgeTargetSafeArea,
109-
safeAreaFinder: safeAreaFinder
110-
)
111-
notificationWindow = .init(frame: .zero)
83+
if notificationViewController.needsActiveWindowSafeArea {
84+
safeAreaFinder.start()
11285
}
86+
}
11387

114-
notificationWindow.windowLevel = UIWindow.Level(rawValue: 5)
88+
public func hideWindow() {
11589
notificationWindow.isHidden = true
116-
notificationWindow.backgroundColor = UIColor.clear
117-
notificationWindow.frame = UIScreen.main.bounds
118-
notificationViewController.beginAppearanceTransition(true, animated: false)
119-
notificationWindow.rootViewController = notificationViewController
120-
notificationViewController.endAppearanceTransition()
90+
safeAreaFinder.stop()
12191
}
12292

12393
@available(iOS 13.0, *)
@@ -142,11 +112,11 @@ public final class FloatingDisplayTarget {
142112
notificationViewController.endAppearanceTransition()
143113
}
144114

145-
deinit {
146-
Task { @MainActor [notificationWindow] in
115+
deinit {
116+
Task { @MainActor [safeAreaFinder, notificationWindow] in
117+
safeAreaFinder.stop()
147118
notificationWindow.isHidden = false
148119
}
149-
150120
}
151121

152122
}
@@ -185,6 +155,10 @@ extension FloatingDisplayTarget {
185155
private let edgeTargetSafeArea: EdgeTargetSafeArea
186156
private let safeAreaFinder: SafeAreaFinder
187157

158+
fileprivate var needsActiveWindowSafeArea: Bool {
159+
edgeTargetSafeArea.containsActiveWindowEdge
160+
}
161+
188162
init(
189163
edgeTargetSafeArea: EdgeTargetSafeArea,
190164
safeAreaFinder: SafeAreaFinder
@@ -236,7 +210,7 @@ extension FloatingDisplayTarget {
236210

237211
addLayoutGuide(_safeAreaLayoutGuide)
238212

239-
var containsActievWindowSafeAreaEdge: Bool = false
213+
var containsActiveWindowSafeAreaEdge: Bool = false
240214

241215
switch edgeTargetSafeArea.top {
242216
case .notificationWindow:
@@ -245,7 +219,7 @@ extension FloatingDisplayTarget {
245219
case .activeWindow:
246220
activeWindowSafeAreaLayoutGuideConstraintTop = topAnchor.constraint(
247221
equalTo: _safeAreaLayoutGuide.topAnchor)
248-
containsActievWindowSafeAreaEdge = true
222+
containsActiveWindowSafeAreaEdge = true
249223
}
250224

251225
switch edgeTargetSafeArea.right {
@@ -256,7 +230,7 @@ extension FloatingDisplayTarget {
256230
case .activeWindow:
257231
activeWindowSafeAreaLayoutGuideConstraintRight = rightAnchor.constraint(
258232
equalTo: _safeAreaLayoutGuide.rightAnchor)
259-
containsActievWindowSafeAreaEdge = true
233+
containsActiveWindowSafeAreaEdge = true
260234
}
261235

262236
switch edgeTargetSafeArea.bottom {
@@ -267,7 +241,7 @@ extension FloatingDisplayTarget {
267241
case .activeWindow:
268242
activeWindowSafeAreaLayoutGuideConstraintBottom = bottomAnchor.constraint(
269243
equalTo: _safeAreaLayoutGuide.bottomAnchor)
270-
containsActievWindowSafeAreaEdge = true
244+
containsActiveWindowSafeAreaEdge = true
271245
}
272246

273247
switch edgeTargetSafeArea.left {
@@ -277,10 +251,10 @@ extension FloatingDisplayTarget {
277251
case .activeWindow:
278252
activeWindowSafeAreaLayoutGuideConstraintLeft = leftAnchor.constraint(
279253
equalTo: _safeAreaLayoutGuide.leftAnchor)
280-
containsActievWindowSafeAreaEdge = true
254+
containsActiveWindowSafeAreaEdge = true
281255
}
282256

283-
if containsActievWindowSafeAreaEdge {
257+
if containsActiveWindowSafeAreaEdge {
284258

285259
NSLayoutConstraint.activate(
286260
[
@@ -295,7 +269,6 @@ extension FloatingDisplayTarget {
295269
NotificationCenter.default.addObserver(
296270
self, selector: #selector(handleInsetsUpdate), name: SafeAreaFinder.notificationName,
297271
object: nil)
298-
safeAreaFinder.start()
299272
}
300273
}
301274

@@ -335,10 +308,9 @@ extension FloatingDisplayTarget {
335308
}
336309

337310
deinit {
338-
Task { @MainActor [hasSafeAreaFinderActivated, safeAreaFinder] in
339-
if hasSafeAreaFinderActivated {
340-
safeAreaFinder.pause()
341-
}
311+
NotificationCenter.default.removeObserver(self)
312+
Task { @MainActor [safeAreaFinder] in
313+
safeAreaFinder.stop()
342314
}
343315
}
344316
}

0 commit comments

Comments
 (0)