mirror of
https://github.com/yattee/yattee.git
synced 2025-08-05 02:04:07 +00:00
Add pull to refresh for Subscriptions, Popular and Trending (fixes #31)
This commit is contained in:
18
Vendor/RefreshControl/ScrollViewMatcher/FramePreferenceKey.swift
vendored
Normal file
18
Vendor/RefreshControl/ScrollViewMatcher/FramePreferenceKey.swift
vendored
Normal file
@@ -0,0 +1,18 @@
|
||||
//
|
||||
// FramePreferenceKey.swift
|
||||
// SwiftUI_Pull_to_Refresh
|
||||
//
|
||||
// Created by Geri Borbás on 21/09/2021.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import SwiftUI
|
||||
|
||||
struct FramePreferenceKey: PreferenceKey {
|
||||
typealias Value = CGRect
|
||||
static var defaultValue = CGRect.zero
|
||||
|
||||
static func reduce(value: inout CGRect, nextValue: () -> CGRect) {
|
||||
value = nextValue()
|
||||
}
|
||||
}
|
106
Vendor/RefreshControl/ScrollViewMatcher/ScrollViewMatcher.swift
vendored
Normal file
106
Vendor/RefreshControl/ScrollViewMatcher/ScrollViewMatcher.swift
vendored
Normal file
@@ -0,0 +1,106 @@
|
||||
//
|
||||
// ScrollViewMatcher.swift
|
||||
// SwiftUI_Pull_to_Refresh
|
||||
//
|
||||
// Created by Geri Borbás on 17/09/2021.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import SwiftUI
|
||||
|
||||
final class ScrollViewMatcher: UIViewControllerRepresentable {
|
||||
let onMatch: (UIScrollView) -> Void
|
||||
@Binding var geometryReaderFrame: CGRect
|
||||
|
||||
init(onResolve: @escaping (UIScrollView) -> Void, geometryReaderFrame: Binding<CGRect>) {
|
||||
onMatch = onResolve
|
||||
_geometryReaderFrame = geometryReaderFrame
|
||||
}
|
||||
|
||||
func makeUIViewController(context _: Context) -> ScrollViewMatcherViewController {
|
||||
ScrollViewMatcherViewController(onResolve: onMatch, geometryReaderFrame: geometryReaderFrame)
|
||||
}
|
||||
|
||||
func updateUIViewController(_ viewController: ScrollViewMatcherViewController, context _: Context) {
|
||||
viewController.geometryReaderFrame = geometryReaderFrame
|
||||
}
|
||||
}
|
||||
|
||||
final class ScrollViewMatcherViewController: UIViewController {
|
||||
let onMatch: (UIScrollView) -> Void
|
||||
private var scrollView: UIScrollView? {
|
||||
didSet {
|
||||
if oldValue != scrollView,
|
||||
let scrollView = scrollView
|
||||
{
|
||||
onMatch(scrollView)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var geometryReaderFrame: CGRect {
|
||||
didSet {
|
||||
match()
|
||||
}
|
||||
}
|
||||
|
||||
init(onResolve: @escaping (UIScrollView) -> Void, geometryReaderFrame: CGRect, debug _: Bool = false) {
|
||||
onMatch = onResolve
|
||||
self.geometryReaderFrame = geometryReaderFrame
|
||||
super.init(nibName: nil, bundle: nil)
|
||||
}
|
||||
|
||||
@available(*, unavailable)
|
||||
required init?(coder _: NSCoder) {
|
||||
fatalError("Use init(onMatch:) to instantiate ScrollViewMatcherViewController.")
|
||||
}
|
||||
|
||||
func match() {
|
||||
// matchUsingHierarchy()
|
||||
matchUsingGeometry()
|
||||
}
|
||||
|
||||
func matchUsingHierarchy() {
|
||||
if parent != nil {
|
||||
// Lookup view ancestry for any `UIScrollView`.
|
||||
view.searchViewAnchestorsFor { (scrollView: UIScrollView) in
|
||||
self.scrollView = scrollView
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func matchUsingGeometry() {
|
||||
if let parent = parent {
|
||||
if let scrollViewsInHierarchy: [UIScrollView] = parent.view.viewsInHierarchy() {
|
||||
// Return first match if only a single scroll view is found in the hierarchy.
|
||||
if scrollViewsInHierarchy.count == 1,
|
||||
let firstScrollViewInHierarchy = scrollViewsInHierarchy.first
|
||||
{
|
||||
scrollView = firstScrollViewInHierarchy
|
||||
|
||||
// Filter by frame origins if multiple matches found.
|
||||
} else {
|
||||
if let firstMatchingFrameOrigin = scrollViewsInHierarchy.filter({
|
||||
$0.globalFrame.origin.close(to: geometryReaderFrame.origin)
|
||||
}).first {
|
||||
scrollView = firstMatchingFrameOrigin
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override func didMove(toParent parent: UIViewController?) {
|
||||
super.didMove(toParent: parent)
|
||||
match()
|
||||
}
|
||||
}
|
||||
|
||||
extension CGPoint {
|
||||
/// Returns `true` if this point is close the other point (considering a ~1 pt tolerance).
|
||||
func close(to point: CGPoint) -> Bool {
|
||||
let inset = Double(1)
|
||||
let rect = CGRect(x: x - inset, y: y - inset, width: inset * 2, height: inset * 2)
|
||||
return rect.contains(point)
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user