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
163 lines
8.6 KiB
Swift
163 lines
8.6 KiB
Swift
@objc public enum HorizontalAlignment : Int {
|
|
case center
|
|
case left
|
|
case right
|
|
}
|
|
|
|
@objc public enum VerticalAlignment: Int {
|
|
case center
|
|
case top
|
|
case bottom
|
|
}
|
|
|
|
public let NoIntrinsicSize = CGSize(width: UIView.noIntrinsicMetric, height: UIView.noIntrinsicMetric)
|
|
|
|
extension UIView {
|
|
@objc public func wmf_sizeThatFits(_ size: CGSize) -> CGSize {
|
|
return sizeThatFits(size)
|
|
}
|
|
|
|
@objc @discardableResult public func wmf_preferredFrame(at point: CGPoint, maximumSize: CGSize = NoIntrinsicSize, minimumSize: CGSize = NoIntrinsicSize, horizontalAlignment: HorizontalAlignment = .center, verticalAlignment: VerticalAlignment = .center, apply: Bool = false) -> CGRect {
|
|
let viewSize: CGSize = wmf_sizeThatFits(maximumSize)
|
|
|
|
var x: CGFloat = point.x
|
|
var y: CGFloat = point.y
|
|
|
|
let viewWidth: CGFloat
|
|
let widthToFit: CGFloat
|
|
|
|
if minimumSize.width != UIView.noIntrinsicMetric && maximumSize.width != UIView.noIntrinsicMetric { // max and min defined
|
|
viewWidth = max(min(maximumSize.width, viewSize.width), minimumSize.width)
|
|
widthToFit = maximumSize.width
|
|
} else if minimumSize.width != UIView.noIntrinsicMetric && maximumSize.width == UIView.noIntrinsicMetric { // only min defined
|
|
viewWidth = max(minimumSize.width, viewSize.width)
|
|
widthToFit = viewWidth
|
|
} else if minimumSize.width == UIView.noIntrinsicMetric && maximumSize.width != UIView.noIntrinsicMetric { // only max defined
|
|
viewWidth = min(maximumSize.width, viewSize.width)
|
|
widthToFit = maximumSize.width
|
|
} else { // neither defined
|
|
viewWidth = viewSize.width
|
|
widthToFit = viewWidth
|
|
}
|
|
|
|
let viewHeight: CGFloat
|
|
let heightToFit: CGFloat
|
|
|
|
if minimumSize.height != UIView.noIntrinsicMetric && maximumSize.height != UIView.noIntrinsicMetric { // max and min defined
|
|
viewHeight = max(min(maximumSize.height, viewSize.height), minimumSize.height)
|
|
heightToFit = maximumSize.height
|
|
} else if minimumSize.height != UIView.noIntrinsicMetric && maximumSize.height == UIView.noIntrinsicMetric { // only min defined
|
|
viewHeight = max(minimumSize.height, viewSize.height)
|
|
heightToFit = viewHeight
|
|
} else if minimumSize.height == UIView.noIntrinsicMetric && maximumSize.height != UIView.noIntrinsicMetric { // only max defined
|
|
viewHeight = min(maximumSize.height, viewSize.height)
|
|
heightToFit = maximumSize.height
|
|
} else { // neither defined
|
|
viewHeight = viewSize.height
|
|
heightToFit = viewHeight
|
|
}
|
|
|
|
switch verticalAlignment {
|
|
case .center:
|
|
y += floor(0.5*heightToFit - 0.5*viewHeight)
|
|
case .bottom:
|
|
y += (heightToFit - viewHeight)
|
|
case .top:
|
|
break
|
|
}
|
|
|
|
switch horizontalAlignment {
|
|
case .center:
|
|
x += floor(0.5*widthToFit - 0.5*viewWidth)
|
|
case .right:
|
|
x += (widthToFit - viewWidth)
|
|
case .left:
|
|
break
|
|
}
|
|
|
|
let fitFrame = CGRect(x: round(x), y: round(y), width: ceil(viewWidth), height: ceil(viewHeight))
|
|
if apply {
|
|
frame = fitFrame
|
|
}
|
|
return fitFrame
|
|
}
|
|
|
|
@discardableResult public func wmf_preferredFrame(at point: CGPoint, maximumSize: CGSize = NoIntrinsicSize, minimumSize: CGSize = NoIntrinsicSize, horizontalAlignment: HorizontalAlignment, apply: Bool) -> CGRect {
|
|
return wmf_preferredFrame(at: point, maximumSize: maximumSize, minimumSize: minimumSize, horizontalAlignment: horizontalAlignment, verticalAlignment: .top, apply: apply)
|
|
}
|
|
|
|
@discardableResult public func wmf_preferredFrame(at point: CGPoint, maximumSize: CGSize, minimumSize: CGSize = NoIntrinsicSize, alignedBy semanticContentAttribute: UISemanticContentAttribute, apply: Bool) -> CGRect {
|
|
let horizontalAlignment: HorizontalAlignment = semanticContentAttribute == .forceRightToLeft ? .right : .left
|
|
return wmf_preferredFrame(at: point, maximumSize: maximumSize, minimumSize: minimumSize, horizontalAlignment: horizontalAlignment, apply: apply)
|
|
}
|
|
|
|
@discardableResult public func wmf_preferredFrame(at point: CGPoint, maximumWidth: CGFloat, minimumWidth: CGFloat = UIView.noIntrinsicMetric, horizontalAlignment: HorizontalAlignment, apply: Bool) -> CGRect {
|
|
let minimumSize = CGSize(width: minimumWidth, height: UIView.noIntrinsicMetric)
|
|
let maximumSize = CGSize(width: maximumWidth, height: UIView.noIntrinsicMetric)
|
|
return wmf_preferredFrame(at: point, maximumSize: maximumSize, minimumSize: minimumSize, horizontalAlignment: horizontalAlignment, apply: apply)
|
|
}
|
|
|
|
@discardableResult public func wmf_preferredFrame(at point: CGPoint, maximumWidth: CGFloat, minimumWidth: CGFloat = UIView.noIntrinsicMetric, alignedBy semanticContentAttribute: UISemanticContentAttribute, apply: Bool) -> CGRect {
|
|
let horizontalAlignment: HorizontalAlignment = semanticContentAttribute == .forceRightToLeft ? .right : .left
|
|
return wmf_preferredFrame(at: point, maximumWidth: maximumWidth, minimumWidth: minimumWidth, horizontalAlignment: horizontalAlignment, apply: apply)
|
|
}
|
|
|
|
@discardableResult public func wmf_preferredHeight(at point: CGPoint, maximumWidth: CGFloat, minimumWidth: CGFloat = UIView.noIntrinsicMetric, alignedBy semanticContentAttribute: UISemanticContentAttribute, spacing: CGFloat, apply: Bool) -> CGFloat {
|
|
return wmf_preferredFrame(at: point, maximumWidth: maximumWidth, minimumWidth: minimumWidth, alignedBy: semanticContentAttribute, apply: apply).layoutHeight(with: spacing)
|
|
}
|
|
|
|
@discardableResult public func wmf_preferredHeight(at point: CGPoint, maximumWidth: CGFloat, minimumWidth: CGFloat = UIView.noIntrinsicMetric, horizontalAlignment: HorizontalAlignment, spacing: CGFloat, apply: Bool) -> CGFloat {
|
|
return wmf_preferredFrame(at: point, maximumWidth: maximumWidth, minimumWidth: minimumWidth, horizontalAlignment: horizontalAlignment, apply: apply).layoutHeight(with: spacing)
|
|
}
|
|
}
|
|
|
|
extension UIButton {
|
|
public override func wmf_sizeThatFits(_ maximumSize: CGSize) -> CGSize {
|
|
var buttonAdjustedSize = maximumSize
|
|
var heightAdjustment = contentEdgeInsets.top + contentEdgeInsets.bottom
|
|
var widthAdjustment = contentEdgeInsets.left + contentEdgeInsets.right
|
|
|
|
var imageHeight: CGFloat = 0
|
|
if let image = image(for: .normal) {
|
|
widthAdjustment += imageEdgeInsets.left + imageEdgeInsets.right + image.size.width
|
|
imageHeight = image.size.height + imageEdgeInsets.top + imageEdgeInsets.bottom + contentEdgeInsets.top + contentEdgeInsets.bottom
|
|
}
|
|
|
|
heightAdjustment += titleEdgeInsets.top + titleEdgeInsets.bottom
|
|
widthAdjustment += titleEdgeInsets.left + titleEdgeInsets.right
|
|
|
|
if buttonAdjustedSize.width != UIView.noIntrinsicMetric {
|
|
buttonAdjustedSize.width = buttonAdjustedSize.width - widthAdjustment
|
|
}
|
|
|
|
if buttonAdjustedSize.height != UIView.noIntrinsicMetric {
|
|
buttonAdjustedSize.height = buttonAdjustedSize.height - heightAdjustment
|
|
}
|
|
|
|
let buttonLabelSize: CGSize
|
|
if let titleLabel = titleLabel {
|
|
buttonLabelSize = titleLabel.sizeThatFits(buttonAdjustedSize)
|
|
} else {
|
|
buttonLabelSize = .zero
|
|
}
|
|
|
|
let maxHeight = max(imageHeight, buttonLabelSize.height + heightAdjustment)
|
|
return CGSize(width: buttonLabelSize.width + widthAdjustment, height: maxHeight)
|
|
}
|
|
}
|
|
|
|
extension AlignedImageButton {
|
|
@discardableResult override public func wmf_preferredFrame(at point: CGPoint, maximumSize: CGSize = NoIntrinsicSize, minimumSize: CGSize = NoIntrinsicSize, horizontalAlignment: HorizontalAlignment = .center, verticalAlignment: VerticalAlignment = .center, apply: Bool = false) -> CGRect {
|
|
let adjustedPoint = CGPoint(x: point.x - leftPadding, y: point.y - verticalPadding)
|
|
var adjustedSize = maximumSize
|
|
if adjustedSize.width != UIView.noIntrinsicMetric {
|
|
adjustedSize.width = adjustedSize.width + leftPadding + rightPadding
|
|
}
|
|
if adjustedSize.height != UIView.noIntrinsicMetric {
|
|
adjustedSize.height = adjustedSize.height + 2 * verticalPadding
|
|
}
|
|
return super.wmf_preferredFrame(at: adjustedPoint, maximumSize: adjustedSize, minimumSize: minimumSize, horizontalAlignment: horizontalAlignment, verticalAlignment: verticalAlignment, apply: apply)
|
|
}
|
|
}
|
|
|