about summary refs log tree commit diff
path: root/modules/expo-bluesky-swiss-army/ios/Visibility/VisibilityViewManager.swift
blob: ae8e1686816f1b1df273e9ee0877f47cb6012290 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
import Foundation

class VisibilityViewManager {
  static let shared = VisibilityViewManager()

  private let views = NSHashTable<VisibilityView>(options: .weakMemory)
  private var currentlyActiveView: VisibilityView?
  private var screenHeight: CGFloat = UIScreen.main.bounds.height
  private var prevCount = 0

  func addView(_ view: VisibilityView) {
    self.views.add(view)

    if self.prevCount == 0 {
      self.updateActiveView()
    }
    self.prevCount = self.views.count
  }

  func removeView(_ view: VisibilityView) {
    self.views.remove(view)
    self.prevCount = self.views.count
  }

  func updateActiveView() {
    DispatchQueue.main.async {
      var activeView: VisibilityView?

      if self.views.count == 1 {
        let view = self.views.allObjects[0]
        if view.isViewableEnough() {
          activeView = view
        }
      } else if self.views.count > 1 {
        let views = self.views.allObjects
        var mostVisibleView: VisibilityView?
        var mostVisiblePosition: CGRect?

        views.forEach { view in
          if !view.isViewableEnough() {
            return
          }

          guard let position = view.getPositionOnScreen() else {
            return
          }

          if position.minY >= 150 {
            if mostVisiblePosition == nil {
              mostVisiblePosition = position
            }

            if let unwrapped = mostVisiblePosition,
               position.minY <= unwrapped.minY {
              mostVisibleView = view
              mostVisiblePosition = position
            }
          }
        }

        activeView = mostVisibleView
      }

      if activeView == self.currentlyActiveView {
        return
      }

      self.clearActiveView()
      if let view = activeView {
        self.setActiveView(view)
      }
    }
  }

  private func clearActiveView() {
    if let currentlyActiveView = self.currentlyActiveView {
      currentlyActiveView.setIsCurrentlyActive(isActive: false)
      self.currentlyActiveView = nil
    }
  }

  private func setActiveView(_ view: VisibilityView) {
    view.setIsCurrentlyActive(isActive: true)
    self.currentlyActiveView = view
  }
}