Beam/ElementX/Sources/Other/ScrollViewAdapter.swift
manuroe 3950cac085
Dual licensing: AGPL + Element Commercial (#3657)
* New LICENSE-COMMERCIAL file

* Apply dual licenses: AGPL + Element Commercial to file headers

* Update README with dual licensing
2025-01-06 11:27:37 +01:00

79 lines
2.3 KiB
Swift

//
// Copyright 2022-2024 New Vector Ltd.
//
// SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
// Please see LICENSE files in the repository root for full details.
//
import Combine
import UIKit
class ScrollViewAdapter: NSObject, UIScrollViewDelegate {
var scrollView: UIScrollView? {
didSet {
oldValue?.delegate = nil
scrollView?.delegate = self
}
}
var shouldScrollToTopClosure: ((UIScrollView) -> Bool)?
private let didScrollSubject = PassthroughSubject<Void, Never>()
var didScroll: AnyPublisher<Void, Never> {
didScrollSubject.eraseToAnyPublisher()
}
private let isScrollingSubject = CurrentValueSubject<Bool, Never>(false)
var isScrolling: CurrentValuePublisher<Bool, Never> {
.init(isScrollingSubject)
}
private let isAtTopEdgeSubject: CurrentValueSubject<Bool, Never> = .init(false)
var isAtTopEdge: CurrentValuePublisher<Bool, Never> {
isAtTopEdgeSubject
.asCurrentValuePublisher()
}
// MARK: - UIScrollViewDelegate
func scrollViewDidScroll(_ scrollView: UIScrollView) {
didScrollSubject.send(())
let insetContentOffset = scrollView.contentOffset.y + scrollView.contentInset.top
isAtTopEdgeSubject.send(insetContentOffset >= 3)
}
func scrollViewWillBeginDragging(_ scrollView: UIScrollView) {
updateDidScroll(scrollView)
}
func scrollViewDidEndDragging(_ scrollView: UIScrollView, willDecelerate decelerate: Bool) {
updateDidScroll(scrollView)
}
func scrollViewDidEndScrollingAnimation(_ scrollView: UIScrollView) {
updateDidScroll(scrollView)
}
func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {
updateDidScroll(scrollView)
}
func scrollViewDidScrollToTop(_ scrollView: UIScrollView) {
updateDidScroll(scrollView)
}
func scrollViewShouldScrollToTop(_ scrollView: UIScrollView) -> Bool {
guard let shouldScrollToTopClosure else {
// Default behaviour
return true
}
return shouldScrollToTopClosure(scrollView)
}
// MARK: - Private
private func updateDidScroll(_ scrollView: UIScrollView) {
isScrollingSubject.send(scrollView.isDragging || scrollView.isDecelerating)
}
}