This PR contains all the work related to setting up this project as required to implement the [Assignment](https://repo.rock-n-code.com/rock-n-code/deep-linking-assignment/wiki/Assignment) on top, as intended. To summarise this work: - [x] created a new **Xcode** project; - [x] cloned the `Wikipedia` app and inserted it into the **Xcode** project; - [x] created the `Locations` app and also, its `Libraries` package; - [x] created the `Shared` package to share dependencies between the apps; - [x] added a `Makefile` file and implemented some **environment** and **help** commands. Co-authored-by: Javier Cicchelli <javier@rock-n-code.com> Reviewed-on: rock-n-code/deep-linking-assignment#1
75 lines
2.8 KiB
Swift
75 lines
2.8 KiB
Swift
import UIKit
|
|
|
|
extension UIScrollView {
|
|
private var topOffsetY: CGFloat {
|
|
return 0 - adjustedContentInset.top
|
|
}
|
|
|
|
public var bottomOffsetY: CGFloat {
|
|
return contentSize.height - bounds.size.height + adjustedContentInset.bottom
|
|
}
|
|
|
|
private var topOffset: CGPoint {
|
|
return CGPoint(x: contentOffset.x, y: topOffsetY)
|
|
}
|
|
|
|
private var bottomOffset: CGPoint {
|
|
return CGPoint(x: contentOffset.x, y: bottomOffsetY)
|
|
}
|
|
|
|
public var isAtTop: Bool {
|
|
// Rounded: Sometimes when we expect them to be equal, these are less than .2 different (due to rounding in earleir calculation) - and with multiple layout passes, it caused a large scrolling bug on a VC's launch.
|
|
return contentOffset.y.rounded(.up) <= topOffsetY.rounded(.up)
|
|
}
|
|
|
|
private var isAtBottom: Bool {
|
|
// Rounded: Sometimes when we expect them to be equal, these are less than .2 different (due to rounding in earleir calculation) - and with multiple layout passes, it caused a large scrolling bug on a VC's launch.
|
|
return contentOffset.y.rounded(.up) >= bottomOffsetY.rounded(.up)
|
|
}
|
|
|
|
public var verticalOffsetPercentage: CGFloat {
|
|
get {
|
|
let height = contentSize.height
|
|
guard height > 0 else {
|
|
return 0
|
|
}
|
|
return contentOffset.y / height
|
|
}
|
|
set {
|
|
let newOffsetY = contentSize.height * newValue
|
|
setContentOffset(CGPoint(x: contentOffset.x, y: newOffsetY), animated: false)
|
|
}
|
|
}
|
|
|
|
@objc(wmf_setContentInset:verticalScrollIndicatorInsets:preserveContentOffset:preserveAnimation:)
|
|
public func setContentInset(_ updatedContentInset: UIEdgeInsets, verticalScrollIndicatorInsets updatedVerticalScrollIndicatorInsets: UIEdgeInsets, preserveContentOffset: Bool = true, preserveAnimation: Bool = false) -> Bool {
|
|
guard updatedContentInset != contentInset || updatedVerticalScrollIndicatorInsets != verticalScrollIndicatorInsets else {
|
|
return false
|
|
}
|
|
let wasAtTop = isAtTop
|
|
let wasAtBottom = isAtBottom
|
|
verticalScrollIndicatorInsets = updatedVerticalScrollIndicatorInsets
|
|
|
|
if preserveAnimation {
|
|
contentInset = updatedContentInset
|
|
} else {
|
|
let wereAnimationsEnabled = UIView.areAnimationsEnabled
|
|
UIView.setAnimationsEnabled(false)
|
|
contentInset = updatedContentInset
|
|
UIView.setAnimationsEnabled(wereAnimationsEnabled)
|
|
}
|
|
|
|
guard preserveContentOffset else {
|
|
return true
|
|
}
|
|
|
|
if wasAtTop {
|
|
contentOffset = topOffset
|
|
} else if contentSize.height > bounds.inset(by: adjustedContentInset).height && wasAtBottom {
|
|
contentOffset = bottomOffset
|
|
}
|
|
|
|
return true
|
|
}
|
|
}
|