mirror of
https://github.com/ichmagmaus111/ghostgram.git
synced 2026-06-08 11:03:55 +02:00
chore: migrate to new version + fixed several critical bugs
- Migrated project to latest Telegram iOS base (v12.3.2+) - Fixed circular dependency between GhostModeManager and MiscSettingsManager - Fixed multiple Bazel build configuration errors (select() default conditions) - Fixed duplicate type definitions in PeerInfoScreen - Fixed swiftmodule directory resolution in build scripts - Added Ghostgram Settings tab in main Settings menu with all 5 features - Cleared sensitive credentials from config.json (template-only now) - Excluded bazel-cache from version control
This commit is contained in:
@@ -13,7 +13,7 @@ public struct ImmediateTextNodeLayoutInfo {
|
||||
}
|
||||
}
|
||||
|
||||
public class ImmediateTextNode: TextNode {
|
||||
open class ImmediateTextNode: TextNode {
|
||||
public var attributedText: NSAttributedString?
|
||||
public var textAlignment: NSTextAlignment = .natural
|
||||
public var verticalAlignment: TextVerticalAlignment = .top
|
||||
@@ -60,7 +60,7 @@ public class ImmediateTextNode: TextNode {
|
||||
|
||||
public var trailingLineWidth: CGFloat?
|
||||
|
||||
var constrainedSize: CGSize?
|
||||
public var constrainedSize: CGSize?
|
||||
|
||||
public var highlightAttributeAction: (([NSAttributedString.Key: Any]) -> NSAttributedString.Key?)? {
|
||||
didSet {
|
||||
@@ -94,7 +94,7 @@ public class ImmediateTextNode: TextNode {
|
||||
return node
|
||||
}
|
||||
|
||||
public func updateLayout(_ constrainedSize: CGSize) -> CGSize {
|
||||
open func updateLayout(_ constrainedSize: CGSize) -> CGSize {
|
||||
self.constrainedSize = constrainedSize
|
||||
|
||||
let makeLayout = TextNode.asyncLayout(self)
|
||||
|
||||
@@ -9,11 +9,7 @@ public class KeyShortcutsController: UIResponder {
|
||||
private var viewControllerEnumerator: (@escaping (ContainableController) -> Bool) -> Void
|
||||
|
||||
public static var isAvailable: Bool {
|
||||
if #available(iOSApplicationExtension 8.0, iOS 8.0, *), UIDevice.current.userInterfaceIdiom == .pad {
|
||||
return true
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
public init(enumerator: @escaping (@escaping (ContainableController) -> Bool) -> Void) {
|
||||
|
||||
@@ -30,6 +30,232 @@ private func drawFullCorner(context: CGContext, color: UIColor, at point: CGPoin
|
||||
}
|
||||
}
|
||||
|
||||
private func drawRectsImageContent(size: CGSize, context: CGContext, color: UIColor, rects: [CGRect], inset: CGFloat, outerRadius: CGFloat, innerRadius: CGFloat, stroke: Bool, strokeWidth: CGFloat, useModernPathCalculation: Bool, topLeft: CGPoint) {
|
||||
context.clear(CGRect(origin: CGPoint(), size: size))
|
||||
context.setFillColor(color.cgColor)
|
||||
|
||||
context.setBlendMode(.copy)
|
||||
|
||||
if useModernPathCalculation {
|
||||
if rects.count == 1 {
|
||||
let path = UIBezierPath(roundedRect: rects[0].offsetBy(dx: -topLeft.x, dy: -topLeft.y), cornerRadius: outerRadius).cgPath
|
||||
context.addPath(path)
|
||||
|
||||
if stroke {
|
||||
context.setStrokeColor(color.cgColor)
|
||||
context.setLineWidth(strokeWidth)
|
||||
context.strokePath()
|
||||
} else {
|
||||
context.fillPath()
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
var combinedRects: [[CGRect]] = []
|
||||
var currentRects: [CGRect] = []
|
||||
for rect in rects {
|
||||
if rect.width.isZero {
|
||||
if !currentRects.isEmpty {
|
||||
combinedRects.append(currentRects)
|
||||
}
|
||||
currentRects.removeAll()
|
||||
} else {
|
||||
currentRects.append(rect)
|
||||
}
|
||||
}
|
||||
if !currentRects.isEmpty {
|
||||
combinedRects.append(currentRects)
|
||||
}
|
||||
|
||||
for rects in combinedRects {
|
||||
var rects = rects.map { $0.insetBy(dx: -inset, dy: -inset).offsetBy(dx: -topLeft.x, dy: -topLeft.y) }
|
||||
|
||||
let minRadius: CGFloat = 2.0
|
||||
|
||||
for _ in 0 ..< rects.count * rects.count {
|
||||
var hadChanges = false
|
||||
for i in 0 ..< rects.count - 1 {
|
||||
if rects[i].maxY > rects[i + 1].minY {
|
||||
let midY = floor((rects[i].maxY + rects[i + 1].minY) * 0.5)
|
||||
rects[i].size.height = midY - rects[i].minY
|
||||
rects[i + 1].origin.y = midY
|
||||
rects[i + 1].size.height = rects[i + 1].maxY - midY
|
||||
hadChanges = true
|
||||
}
|
||||
if rects[i].maxY >= rects[i + 1].minY && rects[i].insetBy(dx: 0.0, dy: 1.0).intersects(rects[i + 1]) {
|
||||
if abs(rects[i].minX - rects[i + 1].minX) < minRadius {
|
||||
let commonMinX = min(rects[i].origin.x, rects[i + 1].origin.x)
|
||||
if rects[i].origin.x != commonMinX {
|
||||
rects[i].origin.x = commonMinX
|
||||
hadChanges = true
|
||||
}
|
||||
if rects[i + 1].origin.x != commonMinX {
|
||||
rects[i + 1].origin.x = commonMinX
|
||||
hadChanges = true
|
||||
}
|
||||
}
|
||||
if abs(rects[i].maxX - rects[i + 1].maxX) < minRadius {
|
||||
let commonMaxX = max(rects[i].maxX, rects[i + 1].maxX)
|
||||
if rects[i].maxX != commonMaxX {
|
||||
rects[i].size.width = commonMaxX - rects[i].minX
|
||||
hadChanges = true
|
||||
}
|
||||
if rects[i + 1].maxX != commonMaxX {
|
||||
rects[i + 1].size.width = commonMaxX - rects[i + 1].minX
|
||||
hadChanges = true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if !hadChanges {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
context.move(to: CGPoint(x: rects[0].midX, y: rects[0].minY))
|
||||
context.addLine(to: CGPoint(x: rects[0].maxX - outerRadius, y: rects[0].minY))
|
||||
context.addArc(tangent1End: rects[0].topRight, tangent2End: CGPoint(x: rects[0].maxX, y: rects[0].minY + outerRadius), radius: outerRadius)
|
||||
context.addLine(to: CGPoint(x: rects[0].maxX, y: rects[0].midY))
|
||||
|
||||
for i in 0 ..< rects.count - 1 {
|
||||
let rect = rects[i]
|
||||
let next = rects[i + 1]
|
||||
|
||||
if rect.maxX == next.maxX {
|
||||
context.addLine(to: CGPoint(x: next.maxX, y: next.midY))
|
||||
} else {
|
||||
let nextRadius = min(outerRadius, floor(abs(rect.maxX - next.maxX) * 0.5))
|
||||
context.addLine(to: CGPoint(x: rect.maxX, y: rect.maxY - nextRadius))
|
||||
if next.maxX > rect.maxX {
|
||||
context.addArc(tangent1End: CGPoint(x: rect.maxX, y: rect.maxY), tangent2End: CGPoint(x: rect.maxX + nextRadius, y: rect.maxY), radius: nextRadius)
|
||||
context.addLine(to: CGPoint(x: next.maxX - nextRadius, y: next.minY))
|
||||
} else {
|
||||
context.addArc(tangent1End: CGPoint(x: rect.maxX, y: rect.maxY), tangent2End: CGPoint(x: rect.maxX - nextRadius, y: rect.maxY), radius: nextRadius)
|
||||
context.addLine(to: CGPoint(x: next.maxX + nextRadius, y: next.minY))
|
||||
}
|
||||
context.addArc(tangent1End: next.topRight, tangent2End: CGPoint(x: next.maxX, y: next.minY + nextRadius), radius: nextRadius)
|
||||
context.addLine(to: CGPoint(x: next.maxX, y: next.midY))
|
||||
}
|
||||
}
|
||||
|
||||
let last = rects[rects.count - 1]
|
||||
context.addLine(to: CGPoint(x: last.maxX, y: last.maxY - outerRadius))
|
||||
context.addArc(tangent1End: last.bottomRight, tangent2End: CGPoint(x: last.maxX - outerRadius, y: last.maxY), radius: outerRadius)
|
||||
context.addLine(to: CGPoint(x: last.minX + outerRadius, y: last.maxY))
|
||||
context.addArc(tangent1End: last.bottomLeft, tangent2End: CGPoint(x: last.minX, y: last.maxY - outerRadius), radius: outerRadius)
|
||||
|
||||
for i in (1 ..< rects.count).reversed() {
|
||||
let rect = rects[i]
|
||||
let prev = rects[i - 1]
|
||||
|
||||
if rect.minX == prev.minX {
|
||||
context.addLine(to: CGPoint(x: prev.minX, y: prev.midY))
|
||||
} else {
|
||||
let prevRadius = min(outerRadius, floor(abs(rect.minX - prev.minX) * 0.5))
|
||||
context.addLine(to: CGPoint(x: rect.minX, y: rect.minY + prevRadius))
|
||||
if rect.minX < prev.minX {
|
||||
context.addArc(tangent1End: CGPoint(x: rect.minX, y: rect.minY), tangent2End: CGPoint(x: rect.minX + prevRadius, y: rect.minY), radius: prevRadius)
|
||||
context.addLine(to: CGPoint(x: prev.minX - prevRadius, y: prev.maxY))
|
||||
} else {
|
||||
context.addArc(tangent1End: CGPoint(x: rect.minX, y: rect.minY), tangent2End: CGPoint(x: rect.minX - prevRadius, y: rect.minY), radius: prevRadius)
|
||||
context.addLine(to: CGPoint(x: prev.minX + prevRadius, y: prev.maxY))
|
||||
}
|
||||
context.addArc(tangent1End: prev.bottomLeft, tangent2End: CGPoint(x: prev.minX, y: prev.maxY - prevRadius), radius: prevRadius)
|
||||
context.addLine(to: CGPoint(x: prev.minX, y: prev.midY))
|
||||
}
|
||||
}
|
||||
|
||||
context.addLine(to: CGPoint(x: rects[0].minX, y: rects[0].minY + outerRadius))
|
||||
context.addArc(tangent1End: rects[0].topLeft, tangent2End: CGPoint(x: rects[0].minX + outerRadius, y: rects[0].minY), radius: outerRadius)
|
||||
context.addLine(to: CGPoint(x: rects[0].midX, y: rects[0].minY))
|
||||
|
||||
if stroke {
|
||||
context.setStrokeColor(color.cgColor)
|
||||
context.setLineWidth(strokeWidth)
|
||||
context.strokePath()
|
||||
} else {
|
||||
context.fillPath()
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
for i in 0 ..< rects.count {
|
||||
let rect = rects[i].insetBy(dx: -inset, dy: -inset)
|
||||
context.fill(rect.offsetBy(dx: -topLeft.x, dy: -topLeft.y))
|
||||
}
|
||||
|
||||
for i in 0 ..< rects.count {
|
||||
let rect = rects[i].insetBy(dx: -inset, dy: -inset).offsetBy(dx: -topLeft.x, dy: -topLeft.y)
|
||||
|
||||
var previous: CGRect?
|
||||
if i != 0 {
|
||||
previous = rects[i - 1].insetBy(dx: -inset, dy: -inset).offsetBy(dx: -topLeft.x, dy: -topLeft.y)
|
||||
}
|
||||
|
||||
var next: CGRect?
|
||||
if i != rects.count - 1 {
|
||||
next = rects[i + 1].insetBy(dx: -inset, dy: -inset).offsetBy(dx: -topLeft.x, dy: -topLeft.y)
|
||||
}
|
||||
|
||||
if let previous = previous {
|
||||
if previous.contains(rect.topLeft) {
|
||||
if abs(rect.topLeft.x - previous.minX) >= innerRadius {
|
||||
var radius = innerRadius
|
||||
if let next = next {
|
||||
radius = min(radius, floor((next.minY - previous.maxY) / 2.0))
|
||||
}
|
||||
drawConnectingCorner(context: context, color: color, at: CGPoint(x: rect.topLeft.x, y: previous.maxY), type: .topLeft, radius: radius)
|
||||
}
|
||||
} else {
|
||||
drawFullCorner(context: context, color: color, at: rect.topLeft, type: .topLeft, radius: outerRadius)
|
||||
}
|
||||
if previous.contains(rect.topRight.offsetBy(dx: -1.0, dy: 0.0)) {
|
||||
if abs(rect.topRight.x - previous.maxX) >= innerRadius {
|
||||
var radius = innerRadius
|
||||
if let next = next {
|
||||
radius = min(radius, floor((next.minY - previous.maxY) / 2.0))
|
||||
}
|
||||
drawConnectingCorner(context: context, color: color, at: CGPoint(x: rect.topRight.x, y: previous.maxY), type: .topRight, radius: radius)
|
||||
}
|
||||
} else {
|
||||
drawFullCorner(context: context, color: color, at: rect.topRight, type: .topRight, radius: outerRadius)
|
||||
}
|
||||
} else {
|
||||
drawFullCorner(context: context, color: color, at: rect.topLeft, type: .topLeft, radius: outerRadius)
|
||||
drawFullCorner(context: context, color: color, at: rect.topRight, type: .topRight, radius: outerRadius)
|
||||
}
|
||||
|
||||
if let next = next {
|
||||
if next.contains(rect.bottomLeft) {
|
||||
if abs(rect.bottomRight.x - next.maxX) >= innerRadius {
|
||||
var radius = innerRadius
|
||||
if let previous = previous {
|
||||
radius = min(radius, floor((next.minY - previous.maxY) / 2.0))
|
||||
}
|
||||
drawConnectingCorner(context: context, color: color, at: CGPoint(x: rect.bottomLeft.x, y: next.minY), type: .bottomLeft, radius: radius)
|
||||
}
|
||||
} else {
|
||||
drawFullCorner(context: context, color: color, at: rect.bottomLeft, type: .bottomLeft, radius: outerRadius)
|
||||
}
|
||||
if next.contains(rect.bottomRight.offsetBy(dx: -1.0, dy: 0.0)) {
|
||||
if abs(rect.bottomRight.x - next.maxX) >= innerRadius {
|
||||
var radius = innerRadius
|
||||
if let previous = previous {
|
||||
radius = min(radius, floor((next.minY - previous.maxY) / 2.0))
|
||||
}
|
||||
drawConnectingCorner(context: context, color: color, at: CGPoint(x: rect.bottomRight.x, y: next.minY), type: .bottomRight, radius: radius)
|
||||
}
|
||||
} else {
|
||||
drawFullCorner(context: context, color: color, at: rect.bottomRight, type: .bottomRight, radius: outerRadius)
|
||||
}
|
||||
} else {
|
||||
drawFullCorner(context: context, color: color, at: rect.bottomLeft, type: .bottomLeft, radius: outerRadius)
|
||||
drawFullCorner(context: context, color: color, at: rect.bottomRight, type: .bottomRight, radius: outerRadius)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private func drawConnectingCorner(context: CGContext, color: UIColor, at point: CGPoint, type: CornerType, radius: CGFloat) {
|
||||
context.setFillColor(color.cgColor)
|
||||
switch type {
|
||||
@@ -76,230 +302,9 @@ public func generateRectsImage(color: UIColor, rects: [CGRect], inset: CGFloat,
|
||||
bottomRight.x += drawingInset * 2.0
|
||||
bottomRight.y += drawingInset * 2.0
|
||||
|
||||
let capturedTopLeft = topLeft
|
||||
return (topLeft, generateImage(CGSize(width: bottomRight.x - topLeft.x, height: bottomRight.y - topLeft.y), rotatedContext: { size, context in
|
||||
context.clear(CGRect(origin: CGPoint(), size: size))
|
||||
context.setFillColor(color.cgColor)
|
||||
|
||||
context.setBlendMode(.copy)
|
||||
|
||||
if useModernPathCalculation {
|
||||
if rects.count == 1 {
|
||||
let path = UIBezierPath(roundedRect: rects[0].offsetBy(dx: -topLeft.x, dy: -topLeft.y), cornerRadius: outerRadius).cgPath
|
||||
context.addPath(path)
|
||||
|
||||
if stroke {
|
||||
context.setStrokeColor(color.cgColor)
|
||||
context.setLineWidth(strokeWidth)
|
||||
context.strokePath()
|
||||
} else {
|
||||
context.fillPath()
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
var combinedRects: [[CGRect]] = []
|
||||
var currentRects: [CGRect] = []
|
||||
for rect in rects {
|
||||
if rect.width.isZero {
|
||||
if !currentRects.isEmpty {
|
||||
combinedRects.append(currentRects)
|
||||
}
|
||||
currentRects.removeAll()
|
||||
} else {
|
||||
currentRects.append(rect)
|
||||
}
|
||||
}
|
||||
if !currentRects.isEmpty {
|
||||
combinedRects.append(currentRects)
|
||||
}
|
||||
|
||||
for rects in combinedRects {
|
||||
var rects = rects.map { $0.insetBy(dx: -inset, dy: -inset).offsetBy(dx: -topLeft.x, dy: -topLeft.y) }
|
||||
|
||||
let minRadius: CGFloat = 2.0
|
||||
|
||||
for _ in 0 ..< rects.count * rects.count {
|
||||
var hadChanges = false
|
||||
for i in 0 ..< rects.count - 1 {
|
||||
if rects[i].maxY > rects[i + 1].minY {
|
||||
let midY = floor((rects[i].maxY + rects[i + 1].minY) * 0.5)
|
||||
rects[i].size.height = midY - rects[i].minY
|
||||
rects[i + 1].origin.y = midY
|
||||
rects[i + 1].size.height = rects[i + 1].maxY - midY
|
||||
hadChanges = true
|
||||
}
|
||||
if rects[i].maxY >= rects[i + 1].minY && rects[i].insetBy(dx: 0.0, dy: 1.0).intersects(rects[i + 1]) {
|
||||
if abs(rects[i].minX - rects[i + 1].minX) < minRadius {
|
||||
let commonMinX = min(rects[i].origin.x, rects[i + 1].origin.x)
|
||||
if rects[i].origin.x != commonMinX {
|
||||
rects[i].origin.x = commonMinX
|
||||
hadChanges = true
|
||||
}
|
||||
if rects[i + 1].origin.x != commonMinX {
|
||||
rects[i + 1].origin.x = commonMinX
|
||||
hadChanges = true
|
||||
}
|
||||
}
|
||||
if abs(rects[i].maxX - rects[i + 1].maxX) < minRadius {
|
||||
let commonMaxX = max(rects[i].maxX, rects[i + 1].maxX)
|
||||
if rects[i].maxX != commonMaxX {
|
||||
rects[i].size.width = commonMaxX - rects[i].minX
|
||||
hadChanges = true
|
||||
}
|
||||
if rects[i + 1].maxX != commonMaxX {
|
||||
rects[i + 1].size.width = commonMaxX - rects[i + 1].minX
|
||||
hadChanges = true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if !hadChanges {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
context.move(to: CGPoint(x: rects[0].midX, y: rects[0].minY))
|
||||
context.addLine(to: CGPoint(x: rects[0].maxX - outerRadius, y: rects[0].minY))
|
||||
context.addArc(tangent1End: rects[0].topRight, tangent2End: CGPoint(x: rects[0].maxX, y: rects[0].minY + outerRadius), radius: outerRadius)
|
||||
context.addLine(to: CGPoint(x: rects[0].maxX, y: rects[0].midY))
|
||||
|
||||
for i in 0 ..< rects.count - 1 {
|
||||
let rect = rects[i]
|
||||
let next = rects[i + 1]
|
||||
|
||||
if rect.maxX == next.maxX {
|
||||
context.addLine(to: CGPoint(x: next.maxX, y: next.midY))
|
||||
} else {
|
||||
let nextRadius = min(outerRadius, floor(abs(rect.maxX - next.maxX) * 0.5))
|
||||
context.addLine(to: CGPoint(x: rect.maxX, y: rect.maxY - nextRadius))
|
||||
if next.maxX > rect.maxX {
|
||||
context.addArc(tangent1End: CGPoint(x: rect.maxX, y: rect.maxY), tangent2End: CGPoint(x: rect.maxX + nextRadius, y: rect.maxY), radius: nextRadius)
|
||||
context.addLine(to: CGPoint(x: next.maxX - nextRadius, y: next.minY))
|
||||
} else {
|
||||
context.addArc(tangent1End: CGPoint(x: rect.maxX, y: rect.maxY), tangent2End: CGPoint(x: rect.maxX - nextRadius, y: rect.maxY), radius: nextRadius)
|
||||
context.addLine(to: CGPoint(x: next.maxX + nextRadius, y: next.minY))
|
||||
}
|
||||
context.addArc(tangent1End: next.topRight, tangent2End: CGPoint(x: next.maxX, y: next.minY + nextRadius), radius: nextRadius)
|
||||
context.addLine(to: CGPoint(x: next.maxX, y: next.midY))
|
||||
}
|
||||
}
|
||||
|
||||
let last = rects[rects.count - 1]
|
||||
context.addLine(to: CGPoint(x: last.maxX, y: last.maxY - outerRadius))
|
||||
context.addArc(tangent1End: last.bottomRight, tangent2End: CGPoint(x: last.maxX - outerRadius, y: last.maxY), radius: outerRadius)
|
||||
context.addLine(to: CGPoint(x: last.minX + outerRadius, y: last.maxY))
|
||||
context.addArc(tangent1End: last.bottomLeft, tangent2End: CGPoint(x: last.minX, y: last.maxY - outerRadius), radius: outerRadius)
|
||||
|
||||
for i in (1 ..< rects.count).reversed() {
|
||||
let rect = rects[i]
|
||||
let prev = rects[i - 1]
|
||||
|
||||
if rect.minX == prev.minX {
|
||||
context.addLine(to: CGPoint(x: prev.minX, y: prev.midY))
|
||||
} else {
|
||||
let prevRadius = min(outerRadius, floor(abs(rect.minX - prev.minX) * 0.5))
|
||||
context.addLine(to: CGPoint(x: rect.minX, y: rect.minY + prevRadius))
|
||||
if rect.minX < prev.minX {
|
||||
context.addArc(tangent1End: CGPoint(x: rect.minX, y: rect.minY), tangent2End: CGPoint(x: rect.minX + prevRadius, y: rect.minY), radius: prevRadius)
|
||||
context.addLine(to: CGPoint(x: prev.minX - prevRadius, y: prev.maxY))
|
||||
} else {
|
||||
context.addArc(tangent1End: CGPoint(x: rect.minX, y: rect.minY), tangent2End: CGPoint(x: rect.minX - prevRadius, y: rect.minY), radius: prevRadius)
|
||||
context.addLine(to: CGPoint(x: prev.minX + prevRadius, y: prev.maxY))
|
||||
}
|
||||
context.addArc(tangent1End: prev.bottomLeft, tangent2End: CGPoint(x: prev.minX, y: prev.maxY - prevRadius), radius: prevRadius)
|
||||
context.addLine(to: CGPoint(x: prev.minX, y: prev.midY))
|
||||
}
|
||||
}
|
||||
|
||||
context.addLine(to: CGPoint(x: rects[0].minX, y: rects[0].minY + outerRadius))
|
||||
context.addArc(tangent1End: rects[0].topLeft, tangent2End: CGPoint(x: rects[0].minX + outerRadius, y: rects[0].minY), radius: outerRadius)
|
||||
context.addLine(to: CGPoint(x: rects[0].midX, y: rects[0].minY))
|
||||
|
||||
if stroke {
|
||||
context.setStrokeColor(color.cgColor)
|
||||
context.setLineWidth(strokeWidth)
|
||||
context.strokePath()
|
||||
} else {
|
||||
context.fillPath()
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
for i in 0 ..< rects.count {
|
||||
let rect = rects[i].insetBy(dx: -inset, dy: -inset)
|
||||
context.fill(rect.offsetBy(dx: -topLeft.x, dy: -topLeft.y))
|
||||
}
|
||||
|
||||
for i in 0 ..< rects.count {
|
||||
let rect = rects[i].insetBy(dx: -inset, dy: -inset).offsetBy(dx: -topLeft.x, dy: -topLeft.y)
|
||||
|
||||
var previous: CGRect?
|
||||
if i != 0 {
|
||||
previous = rects[i - 1].insetBy(dx: -inset, dy: -inset).offsetBy(dx: -topLeft.x, dy: -topLeft.y)
|
||||
}
|
||||
|
||||
var next: CGRect?
|
||||
if i != rects.count - 1 {
|
||||
next = rects[i + 1].insetBy(dx: -inset, dy: -inset).offsetBy(dx: -topLeft.x, dy: -topLeft.y)
|
||||
}
|
||||
|
||||
if let previous = previous {
|
||||
if previous.contains(rect.topLeft) {
|
||||
if abs(rect.topLeft.x - previous.minX) >= innerRadius {
|
||||
var radius = innerRadius
|
||||
if let next = next {
|
||||
radius = min(radius, floor((next.minY - previous.maxY) / 2.0))
|
||||
}
|
||||
drawConnectingCorner(context: context, color: color, at: CGPoint(x: rect.topLeft.x, y: previous.maxY), type: .topLeft, radius: radius)
|
||||
}
|
||||
} else {
|
||||
drawFullCorner(context: context, color: color, at: rect.topLeft, type: .topLeft, radius: outerRadius)
|
||||
}
|
||||
if previous.contains(rect.topRight.offsetBy(dx: -1.0, dy: 0.0)) {
|
||||
if abs(rect.topRight.x - previous.maxX) >= innerRadius {
|
||||
var radius = innerRadius
|
||||
if let next = next {
|
||||
radius = min(radius, floor((next.minY - previous.maxY) / 2.0))
|
||||
}
|
||||
drawConnectingCorner(context: context, color: color, at: CGPoint(x: rect.topRight.x, y: previous.maxY), type: .topRight, radius: radius)
|
||||
}
|
||||
} else {
|
||||
drawFullCorner(context: context, color: color, at: rect.topRight, type: .topRight, radius: outerRadius)
|
||||
}
|
||||
} else {
|
||||
drawFullCorner(context: context, color: color, at: rect.topLeft, type: .topLeft, radius: outerRadius)
|
||||
drawFullCorner(context: context, color: color, at: rect.topRight, type: .topRight, radius: outerRadius)
|
||||
}
|
||||
|
||||
if let next = next {
|
||||
if next.contains(rect.bottomLeft) {
|
||||
if abs(rect.bottomRight.x - next.maxX) >= innerRadius {
|
||||
var radius = innerRadius
|
||||
if let previous = previous {
|
||||
radius = min(radius, floor((next.minY - previous.maxY) / 2.0))
|
||||
}
|
||||
drawConnectingCorner(context: context, color: color, at: CGPoint(x: rect.bottomLeft.x, y: next.minY), type: .bottomLeft, radius: radius)
|
||||
}
|
||||
} else {
|
||||
drawFullCorner(context: context, color: color, at: rect.bottomLeft, type: .bottomLeft, radius: outerRadius)
|
||||
}
|
||||
if next.contains(rect.bottomRight.offsetBy(dx: -1.0, dy: 0.0)) {
|
||||
if abs(rect.bottomRight.x - next.maxX) >= innerRadius {
|
||||
var radius = innerRadius
|
||||
if let previous = previous {
|
||||
radius = min(radius, floor((next.minY - previous.maxY) / 2.0))
|
||||
}
|
||||
drawConnectingCorner(context: context, color: color, at: CGPoint(x: rect.bottomRight.x, y: next.minY), type: .bottomRight, radius: radius)
|
||||
}
|
||||
} else {
|
||||
drawFullCorner(context: context, color: color, at: rect.bottomRight, type: .bottomRight, radius: outerRadius)
|
||||
}
|
||||
} else {
|
||||
drawFullCorner(context: context, color: color, at: rect.bottomLeft, type: .bottomLeft, radius: outerRadius)
|
||||
drawFullCorner(context: context, color: color, at: rect.bottomRight, type: .bottomRight, radius: outerRadius)
|
||||
}
|
||||
}
|
||||
drawRectsImageContent(size: size, context: context, color: color, rects: rects, inset: inset, outerRadius: outerRadius, innerRadius: innerRadius, stroke: stroke, strokeWidth: strokeWidth, useModernPathCalculation: useModernPathCalculation, topLeft: capturedTopLeft)
|
||||
}))
|
||||
}
|
||||
|
||||
|
||||
@@ -210,7 +210,6 @@ open class ListView: ASDisplayNode, ASScrollViewDelegate, ASGestureRecognizerDel
|
||||
private final var displayLink: CADisplayLink!
|
||||
private final var needsAnimations = false
|
||||
|
||||
public final var dynamicBounceEnabled = true
|
||||
public final var rotated = false
|
||||
public final var experimentalSnapScrollToItem = false
|
||||
public final var useMainQueueTransactions = false
|
||||
@@ -265,6 +264,9 @@ open class ListView: ASDisplayNode, ASScrollViewDelegate, ASGestureRecognizerDel
|
||||
public final var addContentOffset: ((CGFloat, ListViewItemNode?) -> Void)?
|
||||
public final var shouldStopScrolling: ((CGFloat) -> Bool)?
|
||||
public final var onContentsUpdated: ((ContainedViewLayoutTransition) -> Void)?
|
||||
|
||||
public private(set) final var edgeEffectExtension: CGFloat = 0.0
|
||||
public final var onEdgeEffectExtensionUpdated: ((ContainedViewLayoutTransition) -> Void)?
|
||||
|
||||
public final var updateScrollingIndicator: ((ScrollingIndicatorState?, ContainedViewLayoutTransition) -> Void)?
|
||||
|
||||
@@ -1044,41 +1046,10 @@ open class ListView: ASDisplayNode, ASScrollViewDelegate, ASGestureRecognizerDel
|
||||
self.enqueueUpdateVisibleItems(synchronous: false)
|
||||
}
|
||||
|
||||
var useScrollDynamics = false
|
||||
|
||||
let anchor: CGFloat
|
||||
if self.isTracking {
|
||||
anchor = self.touchesPosition.y
|
||||
} else if deltaY < 0.0 {
|
||||
anchor = self.visibleSize.height
|
||||
} else {
|
||||
anchor = 0.0
|
||||
}
|
||||
|
||||
self.didScrollWithOffset?(deltaY, .immediate, nil, self.isTrackingOrDecelerating)
|
||||
|
||||
for itemNode in self.itemNodes {
|
||||
itemNode.updateFrame(itemNode.frame.offsetBy(dx: 0.0, dy: -deltaY), within: self.visibleSize)
|
||||
|
||||
if self.dynamicBounceEnabled && itemNode.wantsScrollDynamics {
|
||||
useScrollDynamics = true
|
||||
|
||||
var distance: CGFloat
|
||||
let itemFrame = itemNode.apparentFrame
|
||||
if anchor < itemFrame.origin.y {
|
||||
distance = abs(itemFrame.origin.y - anchor)
|
||||
} else if anchor > itemFrame.origin.y + itemFrame.size.height {
|
||||
distance = abs(anchor - (itemFrame.origin.y + itemFrame.size.height))
|
||||
} else {
|
||||
distance = 0.0
|
||||
}
|
||||
|
||||
let factor: CGFloat = max(0.08, abs(distance) / self.visibleSize.height)
|
||||
|
||||
let resistance: CGFloat = testSpringFreeResistance
|
||||
|
||||
itemNode.addScrollingOffset(deltaY * factor * resistance)
|
||||
}
|
||||
}
|
||||
|
||||
if !self.snapToBounds(snapTopItem: false, stackFromBottom: self.stackFromBottom, insetDeltaOffsetFix: 0.0).offset.isZero {
|
||||
@@ -1088,38 +1059,10 @@ open class ListView: ASDisplayNode, ASScrollViewDelegate, ASGestureRecognizerDel
|
||||
|
||||
self.updateItemHeaders(leftInset: self.insets.left, rightInset: self.insets.right, synchronousLoad: false)
|
||||
|
||||
for (_, headerNode) in self.itemHeaderNodes {
|
||||
if self.dynamicBounceEnabled && headerNode.wantsScrollDynamics {
|
||||
useScrollDynamics = true
|
||||
|
||||
var distance: CGFloat
|
||||
let itemFrame = headerNode.frame
|
||||
if anchor < itemFrame.origin.y {
|
||||
distance = abs(itemFrame.origin.y - anchor)
|
||||
} else if anchor > itemFrame.origin.y + itemFrame.size.height {
|
||||
distance = abs(anchor - (itemFrame.origin.y + itemFrame.size.height))
|
||||
} else {
|
||||
distance = 0.0
|
||||
}
|
||||
|
||||
let factor: CGFloat = max(0.08, abs(distance) / self.visibleSize.height)
|
||||
|
||||
let resistance: CGFloat = testSpringFreeResistance
|
||||
|
||||
headerNode.addScrollingOffset(deltaY * factor * resistance)
|
||||
}
|
||||
}
|
||||
|
||||
if useScrollDynamics {
|
||||
self.setNeedsAnimations()
|
||||
}
|
||||
|
||||
self.updateVisibleContentOffset()
|
||||
self.updateVisibleItemRange()
|
||||
self.updateItemNodesVisibilities(onlyPositive: false)
|
||||
self.onContentsUpdated?(.immediate)
|
||||
|
||||
//CATransaction.commit()
|
||||
}
|
||||
|
||||
private func calculateAdditionalTopInverseInset() -> CGFloat {
|
||||
@@ -3914,6 +3857,8 @@ open class ListView: ASDisplayNode, ASScrollViewDelegate, ASGestureRecognizerDel
|
||||
|
||||
let flashing = self.headerItemsAreFlashing()
|
||||
|
||||
var maxEdgeEffectExtension: CGFloat = 0.0
|
||||
|
||||
func addHeader(id: VisibleHeaderNodeId, upperBound: CGFloat, upperIndex: Int, upperBoundEdge: CGFloat, lowerBound: CGFloat, lowerIndex: Int, item: ListViewItemHeader, hasValidNodes: Bool) {
|
||||
let itemHeaderHeight: CGFloat = item.height
|
||||
|
||||
@@ -3928,7 +3873,11 @@ open class ListView: ASDisplayNode, ASScrollViewDelegate, ASGestureRecognizerDel
|
||||
switch item.stickDirection {
|
||||
case .top:
|
||||
naturalY = lowerBound
|
||||
headerFrame = CGRect(origin: CGPoint(x: 0.0, y: min(max(upperDisplayBound, upperBound), lowerBound - itemHeaderHeight)), size: CGSize(width: self.visibleSize.width, height: itemHeaderHeight))
|
||||
if item.isSticky {
|
||||
headerFrame = CGRect(origin: CGPoint(x: 0.0, y: min(max(upperDisplayBound, upperBound), lowerBound - itemHeaderHeight)), size: CGSize(width: self.visibleSize.width, height: itemHeaderHeight))
|
||||
} else {
|
||||
headerFrame = CGRect(origin: CGPoint(x: 0.0, y: min(upperBound, lowerBound - itemHeaderHeight)), size: CGSize(width: self.visibleSize.width, height: itemHeaderHeight))
|
||||
}
|
||||
stickLocationDistance = headerFrame.minY - upperBound
|
||||
stickLocationDistanceFactor = max(0.0, min(1.0, stickLocationDistance / itemHeaderHeight))
|
||||
case .topEdge:
|
||||
@@ -4096,6 +4045,11 @@ open class ListView: ASDisplayNode, ASScrollViewDelegate, ASGestureRecognizerDel
|
||||
}
|
||||
headerNode.updateStickDistanceFactor(stickLocationDistanceFactor, distance: stickLocationDistance, transition: .immediate)
|
||||
}
|
||||
|
||||
if headerNode.contributesToEdgeEffect && stickLocationDistance > 0.0 {
|
||||
maxEdgeEffectExtension = max(maxEdgeEffectExtension, upperDisplayBound + headerFrame.height + 8.0)
|
||||
}
|
||||
|
||||
headerNode.offsetByHeaderNodeId = offsetByHeaderNodeId
|
||||
headerNode.naturalOriginY = naturalY
|
||||
var maxIntersectionHeight: (CGFloat, Int)?
|
||||
@@ -4228,6 +4182,11 @@ open class ListView: ASDisplayNode, ASScrollViewDelegate, ASGestureRecognizerDel
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if self.edgeEffectExtension != maxEdgeEffectExtension {
|
||||
self.edgeEffectExtension = maxEdgeEffectExtension
|
||||
self.onEdgeEffectExtensionUpdated?(transition.0)
|
||||
}
|
||||
}
|
||||
|
||||
private func updateItemNodesVisibilities(onlyPositive: Bool) {
|
||||
|
||||
@@ -12,6 +12,7 @@ public protocol ListViewItemHeader: AnyObject {
|
||||
var id: ListViewItemNode.HeaderId { get }
|
||||
var stackingId: ListViewItemNode.HeaderId? { get }
|
||||
var stickDirection: ListViewItemHeaderStickDirection { get }
|
||||
var isSticky: Bool { get }
|
||||
var height: CGFloat { get }
|
||||
var stickOverInsets: Bool { get }
|
||||
|
||||
@@ -21,14 +22,19 @@ public protocol ListViewItemHeader: AnyObject {
|
||||
func updateNode(_ node: ListViewItemHeaderNode, previous: ListViewItemHeader?, next: ListViewItemHeader?)
|
||||
}
|
||||
|
||||
public extension ListViewItemHeader {
|
||||
var isSticky: Bool {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
open class ListViewItemHeaderNode: ASDisplayNode {
|
||||
private final var spring: ListViewItemSpring?
|
||||
let wantsScrollDynamics: Bool
|
||||
let isRotated: Bool
|
||||
final private(set) var internalStickLocationDistanceFactor: CGFloat = 0.0
|
||||
final var internalStickLocationDistance: CGFloat = 0.0
|
||||
private var isFlashingOnScrolling = false
|
||||
weak var attachedToItemNode: ListViewItemNode?
|
||||
public var contributesToEdgeEffect: Bool = false
|
||||
|
||||
var offsetByHeaderNodeId: ListViewItemNode.HeaderId?
|
||||
var naturalOriginY: CGFloat?
|
||||
@@ -53,12 +59,8 @@ open class ListViewItemHeaderNode: ASDisplayNode {
|
||||
return self.alpha
|
||||
}
|
||||
|
||||
public init(layerBacked: Bool = false, dynamicBounce: Bool = false, isRotated: Bool = false, seeThrough: Bool = false) {
|
||||
self.wantsScrollDynamics = dynamicBounce
|
||||
public init(layerBacked: Bool = false, isRotated: Bool = false, seeThrough: Bool = false) {
|
||||
self.isRotated = isRotated
|
||||
if dynamicBounce {
|
||||
self.spring = ListViewItemSpring(stiffness: -280.0, damping: -24.0, mass: 0.85)
|
||||
}
|
||||
|
||||
super.init()
|
||||
|
||||
@@ -69,54 +71,10 @@ open class ListViewItemHeaderNode: ASDisplayNode {
|
||||
}
|
||||
|
||||
final func addScrollingOffset(_ scrollingOffset: CGFloat) {
|
||||
if self.spring != nil && internalStickLocationDistanceFactor.isZero {
|
||||
let bounds = self.bounds
|
||||
self.bounds = CGRect(origin: CGPoint(x: 0.0, y: bounds.origin.y + scrollingOffset), size: bounds.size)
|
||||
}
|
||||
}
|
||||
|
||||
public func animate(_ timestamp: Double) -> Bool {
|
||||
var continueAnimations = false
|
||||
|
||||
if let _ = self.spring {
|
||||
let bounds = self.bounds
|
||||
var offset = bounds.origin.y
|
||||
let currentOffset = offset
|
||||
|
||||
let frictionConstant: CGFloat = testSpringFriction
|
||||
let springConstant: CGFloat = testSpringConstant
|
||||
let time: CGFloat = 1.0 / 60.0
|
||||
|
||||
// friction force = velocity * friction constant
|
||||
let frictionForce = self.spring!.velocity * frictionConstant
|
||||
// spring force = (target point - current position) * spring constant
|
||||
let springForce = -currentOffset * springConstant
|
||||
// force = spring force - friction force
|
||||
let force = springForce - frictionForce
|
||||
|
||||
// velocity = current velocity + force * time / mass
|
||||
self.spring!.velocity = self.spring!.velocity + force * time
|
||||
// position = current position + velocity * time
|
||||
offset = currentOffset + self.spring!.velocity * time
|
||||
|
||||
offset = offset.isNaN ? 0.0 : offset
|
||||
|
||||
let epsilon: CGFloat = 0.1
|
||||
if abs(offset) < epsilon && abs(self.spring!.velocity) < epsilon {
|
||||
offset = 0.0
|
||||
self.spring!.velocity = 0.0
|
||||
} else {
|
||||
continueAnimations = true
|
||||
}
|
||||
|
||||
if abs(offset) > 250.0 {
|
||||
offset = offset < 0.0 ? -250.0 : 250.0
|
||||
}
|
||||
|
||||
self.bounds = CGRect(origin: CGPoint(x: 0.0, y: offset), size: bounds.size)
|
||||
}
|
||||
|
||||
return continueAnimations
|
||||
return false
|
||||
}
|
||||
|
||||
open func animateRemoved(duration: Double) {
|
||||
|
||||
@@ -129,7 +129,6 @@ open class ListViewItemNode: ASDisplayNode, AccessibilityFocusableNode {
|
||||
return nil
|
||||
}
|
||||
|
||||
private final var spring: ListViewItemSpring?
|
||||
private final var animations: [(String, ListViewAnimation)] = []
|
||||
private final var pendingControlledTransitions: [ControlledTransition] = []
|
||||
private final var controlledTransitions: [ControlledTransitionContext] = []
|
||||
@@ -142,8 +141,6 @@ open class ListViewItemNode: ASDisplayNode, AccessibilityFocusableNode {
|
||||
open func attachedHeaderNodesUpdated() {
|
||||
}
|
||||
|
||||
final let wantsScrollDynamics: Bool
|
||||
|
||||
open var preferredAnimationCurve: (CGFloat) -> CGFloat {
|
||||
return listViewAnimationCurveSystem
|
||||
}
|
||||
@@ -236,12 +233,7 @@ open class ListViewItemNode: ASDisplayNode, AccessibilityFocusableNode {
|
||||
return .complete()
|
||||
}
|
||||
|
||||
public init(layerBacked: Bool, dynamicBounce: Bool = true, rotated: Bool = false, seeThrough: Bool = false) {
|
||||
if dynamicBounce {
|
||||
self.spring = ListViewItemSpring(stiffness: -280.0, damping: -24.0, mass: 0.85)
|
||||
}
|
||||
self.wantsScrollDynamics = dynamicBounce
|
||||
|
||||
public init(layerBacked: Bool, rotated: Bool = false, seeThrough: Bool = false) {
|
||||
self.rotated = rotated
|
||||
|
||||
super.init()
|
||||
@@ -338,56 +330,14 @@ open class ListViewItemNode: ASDisplayNode, AccessibilityFocusableNode {
|
||||
}
|
||||
|
||||
final func addScrollingOffset(_ scrollingOffset: CGFloat) {
|
||||
if self.spring != nil {
|
||||
self.contentOffset += scrollingOffset
|
||||
}
|
||||
}
|
||||
|
||||
func initializeDynamicsFromSibling(_ itemView: ListViewItemNode, additionalOffset: CGFloat) {
|
||||
if let itemViewSpring = itemView.spring {
|
||||
self.contentOffset = itemView.contentOffset + additionalOffset
|
||||
self.spring?.velocity = itemViewSpring.velocity
|
||||
}
|
||||
}
|
||||
|
||||
public func animate(timestamp: Double, invertOffsetDirection: inout Bool) -> Bool {
|
||||
var continueAnimations = false
|
||||
|
||||
if let _ = self.spring {
|
||||
var offset = self.contentOffset
|
||||
|
||||
let frictionConstant: CGFloat = testSpringFriction
|
||||
let springConstant: CGFloat = testSpringConstant
|
||||
let time: CGFloat = 1.0 / 60.0
|
||||
|
||||
// friction force = velocity * friction constant
|
||||
let frictionForce = self.spring!.velocity * frictionConstant
|
||||
// spring force = (target point - current position) * spring constant
|
||||
let springForce = -self.contentOffset * springConstant
|
||||
// force = spring force - friction force
|
||||
let force = springForce - frictionForce
|
||||
|
||||
// velocity = current velocity + force * time / mass
|
||||
self.spring!.velocity = self.spring!.velocity + force * time
|
||||
// position = current position + velocity * time
|
||||
offset = self.contentOffset + self.spring!.velocity * time
|
||||
|
||||
offset = offset.isNaN ? 0.0 : offset
|
||||
|
||||
let epsilon: CGFloat = 0.1
|
||||
if abs(offset) < epsilon && abs(self.spring!.velocity) < epsilon {
|
||||
offset = 0.0
|
||||
self.spring!.velocity = 0.0
|
||||
} else {
|
||||
continueAnimations = true
|
||||
}
|
||||
|
||||
if abs(offset) > 250.0 {
|
||||
offset = offset < 0.0 ? -250.0 : 250.0
|
||||
}
|
||||
self.contentOffset = offset
|
||||
}
|
||||
|
||||
var i = 0
|
||||
var animationCount = self.animations.count
|
||||
while i < animationCount {
|
||||
|
||||
@@ -109,7 +109,7 @@ public final class NavigationModalFrame: ASDisplayNode {
|
||||
let contentScale = (layout.size.width - sideInset * 2.0) / layout.size.width
|
||||
let bottomInset: CGFloat = layout.size.height - contentScale * layout.size.height - topInset
|
||||
|
||||
let cornerRadius: CGFloat = 28.0
|
||||
let cornerRadius: CGFloat = 38.0
|
||||
let initialCornerRadius: CGFloat
|
||||
if !layout.safeInsets.top.isZero {
|
||||
initialCornerRadius = layout.deviceMetrics.screenCornerRadius
|
||||
|
||||
@@ -0,0 +1,332 @@
|
||||
import Foundation
|
||||
import UIKit
|
||||
import AsyncDisplayKit
|
||||
|
||||
private var sharedIsReduceTransparencyEnabled = UIAccessibility.isReduceTransparencyEnabled
|
||||
|
||||
public final class NavigationBackgroundNode: ASDisplayNode {
|
||||
private var _color: UIColor
|
||||
|
||||
public var color: UIColor {
|
||||
return self._color
|
||||
}
|
||||
|
||||
private var enableBlur: Bool
|
||||
private var enableSaturation: Bool
|
||||
private var customBlurRadius: CGFloat?
|
||||
|
||||
public var effectView: UIVisualEffectView?
|
||||
private let backgroundNode: ASDisplayNode
|
||||
|
||||
public var backgroundView: UIView {
|
||||
return self.backgroundNode.view
|
||||
}
|
||||
|
||||
private var validLayout: (CGSize, CGFloat)?
|
||||
|
||||
public var backgroundCornerRadius: CGFloat {
|
||||
if let (_, cornerRadius) = self.validLayout {
|
||||
return cornerRadius
|
||||
} else {
|
||||
return 0.0
|
||||
}
|
||||
}
|
||||
|
||||
public init(color: UIColor, enableBlur: Bool = true, enableSaturation: Bool = true, customBlurRadius: CGFloat? = nil) {
|
||||
self._color = .clear
|
||||
self.enableBlur = enableBlur
|
||||
self.enableSaturation = enableSaturation
|
||||
self.customBlurRadius = customBlurRadius
|
||||
|
||||
self.backgroundNode = ASDisplayNode()
|
||||
|
||||
super.init()
|
||||
|
||||
self.addSubnode(self.backgroundNode)
|
||||
|
||||
self.updateColor(color: color, transition: .immediate)
|
||||
}
|
||||
|
||||
|
||||
public override func didLoad() {
|
||||
super.didLoad()
|
||||
|
||||
if self.scheduledUpdate {
|
||||
self.scheduledUpdate = false
|
||||
self.updateBackgroundBlur(forceKeepBlur: false)
|
||||
}
|
||||
}
|
||||
|
||||
private var scheduledUpdate = false
|
||||
|
||||
private func updateBackgroundBlur(forceKeepBlur: Bool) {
|
||||
guard self.isNodeLoaded else {
|
||||
self.scheduledUpdate = true
|
||||
return
|
||||
}
|
||||
if self.enableBlur && !sharedIsReduceTransparencyEnabled && ((self._color.alpha > .ulpOfOne && self._color.alpha < 0.95) || forceKeepBlur) {
|
||||
if self.effectView == nil {
|
||||
let effectView = UIVisualEffectView(effect: UIBlurEffect(style: .light))
|
||||
|
||||
for subview in effectView.subviews {
|
||||
if subview.description.contains("VisualEffectSubview") {
|
||||
subview.isHidden = true
|
||||
}
|
||||
}
|
||||
|
||||
if let sublayer = effectView.layer.sublayers?[0], let filters = sublayer.filters {
|
||||
sublayer.backgroundColor = nil
|
||||
sublayer.isOpaque = false
|
||||
var allowedKeys: [String] = [
|
||||
"gaussianBlur"
|
||||
]
|
||||
if self.enableSaturation {
|
||||
allowedKeys.append("colorSaturate")
|
||||
}
|
||||
sublayer.filters = filters.filter { filter in
|
||||
guard let filter = filter as? NSObject else {
|
||||
return true
|
||||
}
|
||||
let filterName = String(describing: filter)
|
||||
if !allowedKeys.contains(filterName) {
|
||||
return false
|
||||
}
|
||||
if let customBlurRadius = self.customBlurRadius, filterName == "gaussianBlur" {
|
||||
filter.setValue(customBlurRadius as NSNumber, forKey: "inputRadius")
|
||||
}
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
if let (size, cornerRadius) = self.validLayout {
|
||||
effectView.frame = CGRect(origin: CGPoint(), size: size)
|
||||
ContainedViewLayoutTransition.immediate.updateCornerRadius(layer: effectView.layer, cornerRadius: cornerRadius)
|
||||
effectView.clipsToBounds = !cornerRadius.isZero
|
||||
}
|
||||
self.effectView = effectView
|
||||
self.view.insertSubview(effectView, at: 0)
|
||||
}
|
||||
} else if let effectView = self.effectView {
|
||||
self.effectView = nil
|
||||
effectView.removeFromSuperview()
|
||||
}
|
||||
}
|
||||
|
||||
public func updateColor(color: UIColor, enableBlur: Bool? = nil, enableSaturation: Bool? = nil, forceKeepBlur: Bool = false, transition: ContainedViewLayoutTransition) {
|
||||
let effectiveEnableBlur = enableBlur ?? self.enableBlur
|
||||
let effectiveEnableSaturation = enableSaturation ?? self.enableSaturation
|
||||
|
||||
if self._color.isEqual(color) && self.enableBlur == effectiveEnableBlur && self.enableSaturation == effectiveEnableSaturation {
|
||||
return
|
||||
}
|
||||
self._color = color
|
||||
self.enableBlur = effectiveEnableBlur
|
||||
self.enableSaturation = effectiveEnableSaturation
|
||||
|
||||
if sharedIsReduceTransparencyEnabled {
|
||||
transition.updateBackgroundColor(node: self.backgroundNode, color: self._color.withAlphaComponent(1.0))
|
||||
} else {
|
||||
transition.updateBackgroundColor(node: self.backgroundNode, color: self._color)
|
||||
}
|
||||
|
||||
self.updateBackgroundBlur(forceKeepBlur: forceKeepBlur)
|
||||
}
|
||||
|
||||
public func update(size: CGSize, cornerRadius: CGFloat = 0.0, transition: ContainedViewLayoutTransition, beginWithCurrentState: Bool = true) {
|
||||
self.validLayout = (size, cornerRadius)
|
||||
|
||||
let contentFrame = CGRect(origin: CGPoint(), size: size)
|
||||
transition.updateFrame(node: self.backgroundNode, frame: contentFrame, beginWithCurrentState: true)
|
||||
if let effectView = self.effectView, effectView.frame != contentFrame {
|
||||
transition.updateFrame(layer: effectView.layer, frame: contentFrame, beginWithCurrentState: true)
|
||||
if let sublayers = effectView.layer.sublayers {
|
||||
for sublayer in sublayers {
|
||||
transition.updateFrame(layer: sublayer, frame: contentFrame, beginWithCurrentState: true)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
transition.updateCornerRadius(node: self.backgroundNode, cornerRadius: cornerRadius)
|
||||
if let effectView = self.effectView {
|
||||
transition.updateCornerRadius(layer: effectView.layer, cornerRadius: cornerRadius)
|
||||
effectView.clipsToBounds = !cornerRadius.isZero
|
||||
}
|
||||
}
|
||||
|
||||
public func update(size: CGSize, cornerRadius: CGFloat = 0.0, animator: ControlledTransitionAnimator) {
|
||||
self.validLayout = (size, cornerRadius)
|
||||
|
||||
let contentFrame = CGRect(origin: CGPoint(), size: size)
|
||||
animator.updateFrame(layer: self.backgroundNode.layer, frame: contentFrame, completion: nil)
|
||||
if let effectView = self.effectView, effectView.frame != contentFrame {
|
||||
animator.updateFrame(layer: effectView.layer, frame: contentFrame, completion: nil)
|
||||
if let sublayers = effectView.layer.sublayers {
|
||||
for sublayer in sublayers {
|
||||
animator.updateFrame(layer: sublayer, frame: contentFrame, completion: nil)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
animator.updateCornerRadius(layer: self.backgroundNode.layer, cornerRadius: cornerRadius, completion: nil)
|
||||
if let effectView = self.effectView {
|
||||
animator.updateCornerRadius(layer: effectView.layer, cornerRadius: cornerRadius, completion: nil)
|
||||
effectView.clipsToBounds = !cornerRadius.isZero
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
open class BlurredBackgroundView: UIView {
|
||||
private var _color: UIColor?
|
||||
|
||||
private var enableBlur: Bool
|
||||
private var customBlurRadius: CGFloat?
|
||||
|
||||
public private(set) var effectView: UIVisualEffectView?
|
||||
private let backgroundView: UIView
|
||||
|
||||
private var validLayout: (CGSize, CGFloat)?
|
||||
|
||||
public var backgroundCornerRadius: CGFloat {
|
||||
if let (_, cornerRadius) = self.validLayout {
|
||||
return cornerRadius
|
||||
} else {
|
||||
return 0.0
|
||||
}
|
||||
}
|
||||
|
||||
public init(color: UIColor?, enableBlur: Bool = true, customBlurRadius: CGFloat? = nil) {
|
||||
self._color = nil
|
||||
self.enableBlur = enableBlur
|
||||
self.customBlurRadius = customBlurRadius
|
||||
|
||||
self.backgroundView = UIView()
|
||||
|
||||
super.init(frame: CGRect())
|
||||
|
||||
self.addSubview(self.backgroundView)
|
||||
|
||||
if let color = color {
|
||||
self.updateColor(color: color, transition: .immediate)
|
||||
}
|
||||
}
|
||||
|
||||
required public init?(coder: NSCoder) {
|
||||
fatalError("init(coder:) has not been implemented")
|
||||
}
|
||||
|
||||
private func updateBackgroundBlur(forceKeepBlur: Bool) {
|
||||
if let color = self._color, self.enableBlur && !sharedIsReduceTransparencyEnabled && ((color.alpha > .ulpOfOne && color.alpha < 0.95) || forceKeepBlur) {
|
||||
if self.effectView == nil {
|
||||
let effectView = UIVisualEffectView(effect: UIBlurEffect(style: .light))
|
||||
|
||||
for subview in effectView.subviews {
|
||||
if subview.description.contains("VisualEffectSubview") {
|
||||
subview.isHidden = true
|
||||
}
|
||||
}
|
||||
|
||||
if let sublayer = effectView.layer.sublayers?[0], let filters = sublayer.filters {
|
||||
sublayer.backgroundColor = nil
|
||||
sublayer.isOpaque = false
|
||||
//sublayer.setValue(true as NSNumber, forKey: "allowsInPlaceFiltering")
|
||||
let allowedKeys: [String] = [
|
||||
"colorSaturate",
|
||||
"gaussianBlur"
|
||||
]
|
||||
sublayer.filters = filters.filter { filter in
|
||||
guard let filter = filter as? NSObject else {
|
||||
return true
|
||||
}
|
||||
let filterName = String(describing: filter)
|
||||
if !allowedKeys.contains(filterName) {
|
||||
return false
|
||||
}
|
||||
if let customBlurRadius = self.customBlurRadius, filterName == "gaussianBlur" {
|
||||
filter.setValue(customBlurRadius as NSNumber, forKey: "inputRadius")
|
||||
}
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
if let (size, cornerRadius) = self.validLayout {
|
||||
effectView.frame = CGRect(origin: CGPoint(), size: size)
|
||||
ContainedViewLayoutTransition.immediate.updateCornerRadius(layer: effectView.layer, cornerRadius: cornerRadius)
|
||||
effectView.clipsToBounds = !cornerRadius.isZero
|
||||
}
|
||||
self.effectView = effectView
|
||||
self.insertSubview(effectView, at: 0)
|
||||
}
|
||||
} else if let effectView = self.effectView {
|
||||
self.effectView = nil
|
||||
effectView.removeFromSuperview()
|
||||
}
|
||||
}
|
||||
|
||||
public func updateColor(color: UIColor, enableBlur: Bool? = nil, forceKeepBlur: Bool = false, transition: ContainedViewLayoutTransition) {
|
||||
let effectiveEnableBlur = enableBlur ?? self.enableBlur
|
||||
|
||||
if self._color == color && self.enableBlur == effectiveEnableBlur {
|
||||
return
|
||||
}
|
||||
self._color = color
|
||||
self.enableBlur = effectiveEnableBlur
|
||||
|
||||
if sharedIsReduceTransparencyEnabled {
|
||||
transition.updateBackgroundColor(layer: self.backgroundView.layer, color: color.withAlphaComponent(1.0))
|
||||
} else {
|
||||
transition.updateBackgroundColor(layer: self.backgroundView.layer, color: color)
|
||||
}
|
||||
|
||||
self.updateBackgroundBlur(forceKeepBlur: forceKeepBlur)
|
||||
}
|
||||
|
||||
public func update(size: CGSize, cornerRadius: CGFloat = 0.0, maskedCorners: CACornerMask = [.layerMaxXMaxYCorner, .layerMaxXMinYCorner, .layerMinXMaxYCorner, .layerMinXMinYCorner], transition: ContainedViewLayoutTransition) {
|
||||
self.validLayout = (size, cornerRadius)
|
||||
|
||||
let contentFrame = CGRect(origin: CGPoint(), size: size)
|
||||
transition.updateFrame(view: self.backgroundView, frame: contentFrame, beginWithCurrentState: true)
|
||||
if let effectView = self.effectView, effectView.frame != contentFrame {
|
||||
transition.updateFrame(layer: effectView.layer, frame: contentFrame, beginWithCurrentState: true)
|
||||
if let sublayers = effectView.layer.sublayers {
|
||||
for sublayer in sublayers {
|
||||
transition.updateFrame(layer: sublayer, frame: contentFrame, beginWithCurrentState: true)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if #available(iOS 11.0, *) {
|
||||
self.backgroundView.layer.maskedCorners = maskedCorners
|
||||
}
|
||||
|
||||
transition.updateCornerRadius(layer: self.backgroundView.layer, cornerRadius: cornerRadius)
|
||||
if let effectView = self.effectView {
|
||||
transition.updateCornerRadius(layer: effectView.layer, cornerRadius: cornerRadius)
|
||||
effectView.clipsToBounds = !cornerRadius.isZero
|
||||
|
||||
if #available(iOS 11.0, *) {
|
||||
effectView.layer.maskedCorners = maskedCorners
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public func update(size: CGSize, cornerRadius: CGFloat = 0.0, animator: ControlledTransitionAnimator) {
|
||||
self.validLayout = (size, cornerRadius)
|
||||
|
||||
let contentFrame = CGRect(origin: CGPoint(), size: size)
|
||||
animator.updateFrame(layer: self.backgroundView.layer, frame: contentFrame, completion: nil)
|
||||
if let effectView = self.effectView, effectView.frame != contentFrame {
|
||||
animator.updateFrame(layer: effectView.layer, frame: contentFrame, completion: nil)
|
||||
if let sublayers = effectView.layer.sublayers {
|
||||
for sublayer in sublayers {
|
||||
animator.updateFrame(layer: sublayer, frame: contentFrame, completion: nil)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
animator.updateCornerRadius(layer: self.backgroundView.layer, cornerRadius: cornerRadius, completion: nil)
|
||||
if let effectView = self.effectView {
|
||||
animator.updateCornerRadius(layer: effectView.layer, cornerRadius: cornerRadius, completion: nil)
|
||||
effectView.clipsToBounds = !cornerRadius.isZero
|
||||
}
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -12,7 +12,7 @@ public final class NavigationBarBadgeNode: ASDisplayNode {
|
||||
|
||||
private let font: UIFont = Font.regular(13.0)
|
||||
|
||||
var text: String = "" {
|
||||
public var text: String = "" {
|
||||
didSet {
|
||||
self.textNode.attributedText = NSAttributedString(string: self.text, font: self.font, textColor: self.textColor)
|
||||
self.invalidateCalculatedLayout()
|
||||
@@ -39,7 +39,7 @@ public final class NavigationBarBadgeNode: ASDisplayNode {
|
||||
self.addSubnode(self.textNode)
|
||||
}
|
||||
|
||||
func updateTheme(fillColor: UIColor, strokeColor: UIColor, textColor: UIColor) {
|
||||
public func updateTheme(fillColor: UIColor, strokeColor: UIColor, textColor: UIColor) {
|
||||
self.fillColor = fillColor
|
||||
self.strokeColor = strokeColor
|
||||
self.textColor = textColor
|
||||
|
||||
@@ -26,6 +26,7 @@ open class NavigationBarContentNode: ASDisplayNode {
|
||||
return .replacement
|
||||
}
|
||||
|
||||
open func updateLayout(size: CGSize, leftInset: CGFloat, rightInset: CGFloat, transition: ContainedViewLayoutTransition) {
|
||||
open func updateLayout(size: CGSize, leftInset: CGFloat, rightInset: CGFloat, transition: ContainedViewLayoutTransition) -> CGSize {
|
||||
return size
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
import Foundation
|
||||
import UIKit
|
||||
|
||||
public protocol NavigationBarTitleView {
|
||||
public protocol NavigationBarTitleView: UIView {
|
||||
var requestUpdate: ((ContainedViewLayoutTransition) -> Void)? { get set }
|
||||
|
||||
func animateLayoutTransition()
|
||||
|
||||
func updateLayout(size: CGSize, clearBounds: CGRect, transition: ContainedViewLayoutTransition) -> CGRect
|
||||
func updateLayout(availableSize: CGSize, transition: ContainedViewLayoutTransition) -> CGSize
|
||||
}
|
||||
|
||||
@@ -201,10 +201,9 @@ final class NavigationTransitionCoordinator {
|
||||
position = progress
|
||||
}
|
||||
|
||||
transition.animateView {
|
||||
topNavigationBar.transitionState = NavigationBarTransitionState(navigationBar: bottomNavigationBar, transition: self.transition, role: .top, progress: position)
|
||||
bottomNavigationBar.transitionState = NavigationBarTransitionState(navigationBar: topNavigationBar, transition: self.transition, role: .bottom, progress: position)
|
||||
}
|
||||
let _ = position
|
||||
let _ = topNavigationBar
|
||||
let _ = bottomNavigationBar
|
||||
}
|
||||
}
|
||||
|
||||
@@ -218,15 +217,16 @@ final class NavigationTransitionCoordinator {
|
||||
position = progress
|
||||
}
|
||||
|
||||
topNavigationBar.transitionState = NavigationBarTransitionState(navigationBar: bottomNavigationBar, transition: self.transition, role: .top, progress: position)
|
||||
bottomNavigationBar.transitionState = NavigationBarTransitionState(navigationBar: topNavigationBar, transition: self.transition, role: .bottom, progress: position)
|
||||
let _ = position
|
||||
let _ = topNavigationBar
|
||||
let _ = bottomNavigationBar
|
||||
}
|
||||
}
|
||||
|
||||
func endNavigationBarTransition() {
|
||||
if let topNavigationBar = self.topNavigationBar, let bottomNavigationBar = self.bottomNavigationBar, self.inlineNavigationBarTransition {
|
||||
topNavigationBar.transitionState = nil
|
||||
bottomNavigationBar.transitionState = nil
|
||||
let _ = topNavigationBar
|
||||
let _ = bottomNavigationBar
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
import Foundation
|
||||
import UIKit
|
||||
import AsyncDisplayKit
|
||||
|
||||
open class SparseNode: ASDisplayNode {
|
||||
override open func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
|
||||
if self.alpha.isZero {
|
||||
return nil
|
||||
}
|
||||
for view in self.view.subviews.reversed() {
|
||||
if let result = view.hitTest(self.view.convert(point, to: view), with: event), result.isUserInteractionEnabled {
|
||||
return result
|
||||
}
|
||||
}
|
||||
|
||||
if !self.bounds.inset(by: self.hitTestSlop).contains(point) {
|
||||
return nil
|
||||
}
|
||||
|
||||
let result = super.hitTest(point, with: event)
|
||||
if result != self.view {
|
||||
return result
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
open class SparseContainerView: UIView {
|
||||
override public func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
|
||||
if self.alpha.isZero {
|
||||
return nil
|
||||
}
|
||||
for view in self.subviews.reversed() {
|
||||
if let result = view.hitTest(self.convert(point, to: view), with: event), result.isUserInteractionEnabled {
|
||||
return result
|
||||
}
|
||||
}
|
||||
|
||||
let result = super.hitTest(point, with: event)
|
||||
if result != self {
|
||||
return result
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -108,9 +108,13 @@ public extension UIColor {
|
||||
var green: CGFloat = 0.0
|
||||
var blue: CGFloat = 0.0
|
||||
if self.getRed(&red, green: &green, blue: &blue, alpha: nil) {
|
||||
return (UInt32(max(0.0, red) * 255.0) << 16) | (UInt32(max(0.0, green) * 255.0) << 8) | (UInt32(max(0.0, blue) * 255.0))
|
||||
let r: UInt32 = UInt32(max(0.0, red) * 255.0)
|
||||
let g: UInt32 = UInt32(max(0.0, green) * 255.0)
|
||||
let b: UInt32 = UInt32(max(0.0, blue) * 255.0)
|
||||
return (r << 16) | (g << 8) | b
|
||||
} else if self.getWhite(&red, alpha: nil) {
|
||||
return (UInt32(max(0.0, red) * 255.0) << 16) | (UInt32(max(0.0, red) * 255.0) << 8) | (UInt32(max(0.0, red) * 255.0))
|
||||
let w: UInt32 = UInt32(max(0.0, red) * 255.0)
|
||||
return (w << 16) | (w << 8) | w
|
||||
} else {
|
||||
return 0
|
||||
}
|
||||
@@ -122,9 +126,15 @@ public extension UIColor {
|
||||
var blue: CGFloat = 0.0
|
||||
var alpha: CGFloat = 0.0
|
||||
if self.getRed(&red, green: &green, blue: &blue, alpha: &alpha) {
|
||||
return (UInt32(alpha * 255.0) << 24) | (UInt32(max(0.0, red) * 255.0) << 16) | (UInt32(max(0.0, green) * 255.0) << 8) | (UInt32(max(0.0, blue) * 255.0))
|
||||
let a: UInt32 = UInt32(alpha * 255.0)
|
||||
let r: UInt32 = UInt32(max(0.0, red) * 255.0)
|
||||
let g: UInt32 = UInt32(max(0.0, green) * 255.0)
|
||||
let b: UInt32 = UInt32(max(0.0, blue) * 255.0)
|
||||
return (a << 24) | (r << 16) | (g << 8) | b
|
||||
} else if self.getWhite(&red, alpha: &alpha) {
|
||||
return (UInt32(max(0.0, alpha) * 255.0) << 24) | (UInt32(max(0.0, red) * 255.0) << 16) | (UInt32(max(0.0, red) * 255.0) << 8) | (UInt32(max(0.0, red) * 255.0))
|
||||
let a: UInt32 = UInt32(max(0.0, alpha) * 255.0)
|
||||
let w: UInt32 = UInt32(max(0.0, red) * 255.0)
|
||||
return (a << 24) | (w << 16) | (w << 8) | w
|
||||
} else {
|
||||
return 0
|
||||
}
|
||||
|
||||
@@ -217,6 +217,18 @@ public protocol CustomViewControllerNavigationDataSummary: AnyObject {
|
||||
open var navigationBarRequiresEntireLayoutUpdate: Bool {
|
||||
return true
|
||||
}
|
||||
|
||||
public struct TabBarSearchState: Equatable {
|
||||
public var isActive: Bool
|
||||
|
||||
public init(isActive: Bool) {
|
||||
self.isActive = isActive
|
||||
}
|
||||
}
|
||||
|
||||
public private(set) var tabBarSearchState: TabBarSearchState?
|
||||
public var tabBarSearchStateUpdated: ((ContainedViewLayoutTransition) -> Void)?
|
||||
public var currentTabBarSearchNode: (() -> ASDisplayNode?)?
|
||||
|
||||
private weak var activeInputViewCandidate: UIResponder?
|
||||
private weak var activeInputView: UIResponder?
|
||||
@@ -237,16 +249,24 @@ public protocol CustomViewControllerNavigationDataSummary: AnyObject {
|
||||
open var interactiveNavivationGestureEdgeWidth: InteractiveTransitionGestureRecognizerEdgeWidth? {
|
||||
return nil
|
||||
}
|
||||
|
||||
open var navigationEdgeEffectExtension: CGFloat {
|
||||
return 0.0
|
||||
}
|
||||
|
||||
public func updateNavigationEdgeEffectExtension(transition: ContainedViewLayoutTransition) {
|
||||
if let navigationBar = self.navigationBar {
|
||||
navigationBar.updateEdgeEffectExtension(value: max(0.0, self.navigationEdgeEffectExtension - navigationBar.frame.maxY), transition: transition)
|
||||
}
|
||||
}
|
||||
|
||||
open func navigationLayout(layout: ContainerViewLayout) -> NavigationLayout {
|
||||
let statusBarHeight: CGFloat = layout.statusBarHeight ?? 0.0
|
||||
var defaultNavigationBarHeight: CGFloat
|
||||
if self._presentedInModal && self._hasGlassStyle {
|
||||
defaultNavigationBarHeight = 66.0
|
||||
} else if self._presentedInModal && layout.orientation == .portrait {
|
||||
defaultNavigationBarHeight = 56.0
|
||||
defaultNavigationBarHeight = 68.0
|
||||
} else {
|
||||
defaultNavigationBarHeight = 44.0
|
||||
defaultNavigationBarHeight = 60.0
|
||||
}
|
||||
let navigationBarHeight: CGFloat = statusBarHeight + (self.navigationBar?.contentHeight(defaultHeight: defaultNavigationBarHeight) ?? defaultNavigationBarHeight)
|
||||
|
||||
@@ -375,7 +395,7 @@ public protocol CustomViewControllerNavigationDataSummary: AnyObject {
|
||||
public init(navigationBarPresentationData: NavigationBarPresentationData?) {
|
||||
self.statusBar = StatusBar()
|
||||
if let navigationBarPresentationData = navigationBarPresentationData {
|
||||
self.navigationBar = NavigationBar(presentationData: navigationBarPresentationData)
|
||||
self.navigationBar = defaultNavigationBarImpl!(navigationBarPresentationData)
|
||||
} else {
|
||||
self.navigationBar = nil
|
||||
}
|
||||
@@ -447,14 +467,29 @@ public protocol CustomViewControllerNavigationDataSummary: AnyObject {
|
||||
}
|
||||
if let navigationBar = self.navigationBar {
|
||||
if let contentNode = navigationBar.contentNode, case .expansion = contentNode.mode, !self.displayNavigationBar {
|
||||
navigationBarFrame.origin.y -= navigationLayout.defaultContentHeight
|
||||
navigationBarFrame.size.height += contentNode.height + navigationLayout.defaultContentHeight + statusBarHeight
|
||||
navigationBarFrame.origin.y -= navigationLayout.defaultContentHeight + statusBarHeight
|
||||
navigationBarFrame.size.height += contentNode.height + navigationLayout.defaultContentHeight + statusBarHeight * 2.0
|
||||
if self._presentedInModal && self._hasGlassStyle {
|
||||
navigationBarFrame.size.height += 8.0
|
||||
}
|
||||
}
|
||||
//navigationBar.backgroundColor = .blue
|
||||
if let _ = navigationBar.contentNode, let _ = navigationBar.secondaryContentNode, !self.displayNavigationBar {
|
||||
navigationBarFrame.size.height += navigationBar.secondaryContentHeight
|
||||
}
|
||||
|
||||
navigationBar.updateLayout(size: navigationBarFrame.size, defaultHeight: navigationLayout.defaultContentHeight, additionalTopHeight: statusBarHeight, additionalContentHeight: self.additionalNavigationBarHeight, additionalBackgroundHeight: additionalBackgroundHeight, additionalCutout: additionalCutout, leftInset: layout.safeInsets.left, rightInset: layout.safeInsets.right, appearsHidden: !self.displayNavigationBar, isLandscape: isLandscape, transition: transition)
|
||||
var additionalTopHeight = statusBarHeight
|
||||
if !self.displayNavigationBar {
|
||||
additionalTopHeight -= statusBarHeight
|
||||
if statusBarHeight != 0.0 {
|
||||
additionalTopHeight += 6.0
|
||||
}
|
||||
}
|
||||
if self._presentedInModal && self._hasGlassStyle {
|
||||
additionalTopHeight += 8.0
|
||||
}
|
||||
|
||||
navigationBar.updateLayout(size: navigationBarFrame.size, defaultHeight: navigationLayout.defaultContentHeight, additionalTopHeight: additionalTopHeight, additionalContentHeight: self.additionalNavigationBarHeight, additionalBackgroundHeight: additionalBackgroundHeight, additionalCutout: additionalCutout, leftInset: layout.safeInsets.left, rightInset: layout.safeInsets.right, appearsHidden: !self.displayNavigationBar, isLandscape: isLandscape, transition: transition)
|
||||
if !transition.isAnimated {
|
||||
navigationBar.layer.removeAnimation(forKey: "bounds")
|
||||
navigationBar.layer.removeAnimation(forKey: "position")
|
||||
@@ -542,14 +577,14 @@ public protocol CustomViewControllerNavigationDataSummary: AnyObject {
|
||||
UIView.transition(with: navigationBar.view, duration: 0.3, options: [.transitionCrossDissolve], animations: {
|
||||
}, completion: nil)
|
||||
}
|
||||
self.navigationBar?.updatePresentationData(presentationData)
|
||||
self.navigationBar?.updatePresentationData(presentationData, transition: .immediate)
|
||||
if let parent = self.parent as? TabBarController {
|
||||
if parent.currentController === self {
|
||||
if animated, let navigationBar = parent.navigationBar {
|
||||
UIView.transition(with: navigationBar.view, duration: 0.3, options: [.transitionCrossDissolve], animations: {
|
||||
}, completion: nil)
|
||||
}
|
||||
parent.navigationBar?.updatePresentationData(presentationData)
|
||||
parent.navigationBar?.updatePresentationData(presentationData, transition: .immediate)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -705,9 +740,22 @@ public protocol CustomViewControllerNavigationDataSummary: AnyObject {
|
||||
|
||||
open func tabBarDisabledAction() {
|
||||
}
|
||||
|
||||
open func tabBarActivateSearch() {
|
||||
}
|
||||
|
||||
open func tabBarDeactivateSearch() {
|
||||
}
|
||||
|
||||
open func tabBarItemSwipeAction(direction: TabBarItemSwipeDirection) {
|
||||
}
|
||||
|
||||
public func updateTabBarSearchState(_ tabBarSearchState: TabBarSearchState?, transition: ContainedViewLayoutTransition) {
|
||||
if self.tabBarSearchState != tabBarSearchState {
|
||||
self.tabBarSearchState = tabBarSearchState
|
||||
self.tabBarSearchStateUpdated?(transition)
|
||||
}
|
||||
}
|
||||
|
||||
open func updatePossibleControllerDropContent(content: NavigationControllerDropContent?) {
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user