1 import React
2 import ExpoModulesCore
3 
4 class SafeAreaProvider: ExpoView {
5   private var _currentSafeAreaInsets: UIEdgeInsets = .zero
6   private var _currentFrame: CGRect = .zero
7   private var _initialInsetsSent: Bool = false
8   let onInsetsChange = EventDispatcher()
9 
10   override func safeAreaInsetsDidChange() {
11     invalidateSafeAreaInsets()
12   }
13 
14   func invalidateSafeAreaInsets() {
15     guard !frame.size.equalTo(.zero) else {
16       return
17     }
18 
19     let safeAreaInsets = safeAreaInsetsOrEmulate()
20     let frame = convert(bounds, to: nil)
21 
22     if _initialInsetsSent &&
23       DevMenuUIEdgeInsetsEqualToEdgeInsetsWithThreshold(safeAreaInsets, _currentSafeAreaInsets, 1.0 / RCTScreenScale()) &&
24       frame.equalTo(_currentFrame) {
25       return
26     }
27 
28     _initialInsetsSent = true
29     _currentSafeAreaInsets = safeAreaInsets
30     _currentFrame = frame
31 
32     onInsetsChange([
33       "insets": [
34         "top": safeAreaInsets.top,
35         "right": safeAreaInsets.right,
36         "bottom": safeAreaInsets.bottom,
37         "left": safeAreaInsets.left
38       ],
39       "frame": [
40         "x": frame.origin.x,
41         "y": frame.origin.y,
42         "width": frame.size.width,
43         "height": frame.size.height
44       ]
45     ])
46   }
47 
48   override func layoutSubviews() {
49     super.layoutSubviews()
50     invalidateSafeAreaInsets()
51   }
52 }
53