Merge branch 'master' of gitlab.com:peter-iakovlev/telegram-ios

This commit is contained in:
overtake 2021-05-07 20:20:15 +03:00
commit 0c0af6c8f7
33 changed files with 733 additions and 293 deletions

View File

@ -2,7 +2,7 @@ import Foundation
import UIKit
import AsyncDisplayKit
public enum ContainedViewLayoutTransitionCurve {
public enum ContainedViewLayoutTransitionCurve: Equatable, Hashable {
case linear
case easeInOut
case spring
@ -13,6 +13,21 @@ public enum ContainedViewLayoutTransitionCurve {
}
}
public extension ContainedViewLayoutTransitionCurve {
func solve(at offset: CGFloat) -> CGFloat {
switch self {
case .linear:
return offset
case .easeInOut:
return listViewAnimationCurveEaseInOut(offset)
case .spring:
return listViewAnimationCurveSystem(offset)
case let .custom(c1x, c1y, c2x, c2y):
return bezierPoint(CGFloat(c1x), CGFloat(c1y), CGFloat(c2x), CGFloat(c2y), offset)
}
}
}
public extension ContainedViewLayoutTransitionCurve {
var timingFunction: String {
switch self {

View File

@ -479,7 +479,7 @@ public class DrawingContext {
}
}
public init(size: CGSize, scale: CGFloat = 0.0, premultiplied: Bool = true, clear: Bool = false) {
public init(size: CGSize, scale: CGFloat = 0.0, premultiplied: Bool = true, opaque: Bool = false, clear: Bool = false) {
let actualScale: CGFloat
if scale.isZero {
actualScale = deviceScale
@ -492,8 +492,10 @@ public class DrawingContext {
self.bytesPerRow = (4 * Int(scaledSize.width) + 15) & (~15)
self.length = bytesPerRow * Int(scaledSize.height)
if premultiplied {
if opaque {
self.bitmapInfo = CGBitmapInfo(rawValue: CGBitmapInfo.byteOrder32Little.rawValue | CGImageAlphaInfo.noneSkipFirst.rawValue)
} else if premultiplied {
self.bitmapInfo = CGBitmapInfo(rawValue: CGBitmapInfo.byteOrder32Little.rawValue | CGImageAlphaInfo.premultipliedFirst.rawValue)
} else {
self.bitmapInfo = CGBitmapInfo(rawValue: CGBitmapInfo.byteOrder32Little.rawValue | CGImageAlphaInfo.first.rawValue)

View File

@ -3012,7 +3012,9 @@ open class ListView: ASDisplayNode, UIScrollViewAccessibilityDelegate, UIGesture
switch scrollToItem.directionHint {
case .Up:
offset = updatedLowerBound - (previousUpperBound ?? 0.0)
if let previousUpperBound = previousUpperBound {
offset = updatedLowerBound - previousUpperBound
}
case .Down:
offset = updatedUpperBound - (previousLowerBound ?? self.visibleSize.height)
}

View File

@ -115,6 +115,69 @@ enum NavigationPreviousAction: Equatable {
}
}
public final class NavigationBackgroundNode: ASDisplayNode {
public var color: UIColor {
didSet {
if !self.color.isEqual(oldValue) {
self.backgroundNode.backgroundColor = self.color
self.updateBackgroundBlur()
}
}
}
private var effectView: UIVisualEffectView?
private let backgroundNode: ASDisplayNode
public init(color: UIColor) {
self.color = color
self.backgroundNode = ASDisplayNode()
self.backgroundNode.backgroundColor = self.color
super.init()
self.addSubnode(self.backgroundNode)
self.updateBackgroundBlur()
}
private func updateBackgroundBlur() {
if self.color.alpha > 0.1 && self.color.alpha < 0.95 {
self.effectView?.removeFromSuperview()
self.effectView = nil
if self.color.lightness > 0.6 {
if #available(iOS 13.0, *) {
self.effectView = UIVisualEffectView(effect: UIBlurEffect(style: .systemMaterialLight))
} else {
self.effectView = UIVisualEffectView(effect: UIBlurEffect(style: .light))
}
} else {
if #available(iOS 13.0, *) {
self.effectView = UIVisualEffectView(effect: UIBlurEffect(style: .systemMaterialDark))
} else {
self.effectView = UIVisualEffectView(effect: UIBlurEffect(style: .dark))
}
}
if let effectView = self.effectView {
effectView.frame = self.bounds
self.view.insertSubview(effectView, at: 0)
}
} else if let effectView = self.effectView {
self.effectView = nil
effectView.removeFromSuperview()
}
}
public func update(size: CGSize, transition: ContainedViewLayoutTransition) {
transition.updateFrame(node: self.backgroundNode, frame: CGRect(origin: CGPoint(), size: size))
if let effectView = self.effectView {
transition.updateFrame(view: effectView, frame: CGRect(origin: CGPoint(), size: size))
}
}
}
open class NavigationBar: ASDisplayNode {
public static var defaultSecondaryContentHeight: CGFloat {
return 38.0
@ -635,7 +698,8 @@ open class NavigationBar: ASDisplayNode {
}
self.updateAccessibilityElements()
}
private let backgroundNode: NavigationBackgroundNode
public let backButtonNode: NavigationButtonNode
public let badgeNode: NavigationBarBadgeNode
public let backButtonArrow: ASImageNode
@ -750,13 +814,17 @@ open class NavigationBar: ASDisplayNode {
self.titleNode.accessibilityLabel = title
}
self.stripeNode.backgroundColor = self.presentationData.theme.separatorColor
self.backgroundNode = NavigationBackgroundNode(color: self.presentationData.theme.backgroundColor)
super.init()
self.addSubnode(self.backgroundNode)
self.addSubnode(self.buttonsContainerNode)
self.addSubnode(self.clippingNode)
self.backgroundColor = self.presentationData.theme.backgroundColor
self.backgroundColor = nil
self.isOpaque = false
self.stripeNode.isLayerBacked = true
self.stripeNode.displaysAsynchronously = false
@ -811,7 +879,7 @@ open class NavigationBar: ASDisplayNode {
if presentationData.theme !== self.presentationData.theme || presentationData.strings !== self.presentationData.strings {
self.presentationData = presentationData
self.backgroundColor = self.presentationData.theme.backgroundColor
self.backgroundNode.color = self.presentationData.theme.backgroundColor
self.backButtonNode.color = self.presentationData.theme.buttonColor
self.backButtonNode.disabledColor = self.presentationData.theme.disabledButtonColor
@ -853,6 +921,9 @@ open class NavigationBar: ASDisplayNode {
}
self.validLayout = (size, defaultHeight, additionalHeight, leftInset, rightInset, appearsHidden)
transition.updateFrame(node: self.backgroundNode, frame: CGRect(origin: CGPoint(), size: size))
self.backgroundNode.update(size: size, transition: transition)
let apparentAdditionalHeight: CGFloat = self.secondaryContentNode != nil ? NavigationBar.defaultSecondaryContentHeight : 0.0

View File

@ -331,7 +331,8 @@ class TabBarNode: ASDisplayNode {
private var centered: Bool = false
private var badgeImage: UIImage
let backgroundNode: NavigationBackgroundNode
let separatorNode: ASDisplayNode
private var tabBarNodeContainers: [TabBarNodeContainer] = []
@ -342,6 +343,8 @@ class TabBarNode: ASDisplayNode {
self.contextAction = contextAction
self.swipeAction = swipeAction
self.theme = theme
self.backgroundNode = NavigationBackgroundNode(color: theme.tabBarBackgroundColor)
self.separatorNode = ASDisplayNode()
self.separatorNode.backgroundColor = theme.tabBarSeparatorColor
@ -354,9 +357,10 @@ class TabBarNode: ASDisplayNode {
self.isAccessibilityContainer = false
self.isOpaque = true
self.backgroundColor = theme.tabBarBackgroundColor
self.isOpaque = false
self.backgroundColor = nil
self.addSubnode(self.backgroundNode)
self.addSubnode(self.separatorNode)
}
@ -389,7 +393,7 @@ class TabBarNode: ASDisplayNode {
self.theme = theme
self.separatorNode.backgroundColor = theme.tabBarSeparatorColor
self.backgroundColor = theme.tabBarBackgroundColor
self.backgroundNode.color = theme.tabBarBackgroundColor
self.badgeImage = generateStretchableFilledCircleImage(diameter: 18.0, color: theme.tabBarBadgeBackgroundColor, strokeColor: theme.tabBarBadgeStrokeColor, strokeWidth: 1.0, backgroundColor: nil)!
for container in self.tabBarNodeContainers {
@ -539,6 +543,9 @@ class TabBarNode: ASDisplayNode {
func updateLayout(size: CGSize, leftInset: CGFloat, rightInset: CGFloat, additionalSideInsets: UIEdgeInsets, bottomInset: CGFloat, transition: ContainedViewLayoutTransition) {
self.validLayout = (size, leftInset, rightInset, additionalSideInsets, bottomInset)
transition.updateFrame(node: self.backgroundNode, frame: CGRect(origin: CGPoint(), size: size))
self.backgroundNode.update(size: size, transition: transition)
transition.updateFrame(node: self.separatorNode, frame: CGRect(origin: CGPoint(x: 0.0, y: -separatorHeight), size: CGSize(width: size.width, height: separatorHeight)))

View File

@ -8,7 +8,8 @@ public final class ToolbarNode: ASDisplayNode {
public var left: () -> Void
public var right: () -> Void
public var middle: () -> Void
private let backgroundNode: NavigationBackgroundNode
private let separatorNode: ASDisplayNode
private let leftTitle: ImmediateTextNode
private let leftButton: HighlightTrackingButtonNode
@ -23,6 +24,8 @@ public final class ToolbarNode: ASDisplayNode {
self.left = left
self.right = right
self.middle = middle
self.backgroundNode = NavigationBackgroundNode(color: theme.tabBarBackgroundColor)
self.separatorNode = ASDisplayNode()
self.separatorNode.isLayerBacked = true
@ -40,6 +43,8 @@ public final class ToolbarNode: ASDisplayNode {
super.init()
self.isAccessibilityContainer = false
self.addSubnode(self.backgroundNode)
self.addSubnode(self.leftTitle)
self.addSubnode(self.leftButton)
@ -47,6 +52,7 @@ public final class ToolbarNode: ASDisplayNode {
self.addSubnode(self.rightButton)
self.addSubnode(self.middleTitle)
self.addSubnode(self.middleButton)
if self.displaySeparator {
self.addSubnode(self.separatorNode)
}
@ -96,10 +102,12 @@ public final class ToolbarNode: ASDisplayNode {
public func updateTheme(_ theme: TabBarControllerTheme) {
self.separatorNode.backgroundColor = theme.tabBarSeparatorColor
self.backgroundColor = theme.tabBarBackgroundColor
self.backgroundNode.color = theme.tabBarBackgroundColor
}
public func updateLayout(size: CGSize, leftInset: CGFloat, rightInset: CGFloat, additionalSideInsets: UIEdgeInsets, bottomInset: CGFloat, toolbar: Toolbar, transition: ContainedViewLayoutTransition) {
transition.updateFrame(node: self.backgroundNode, frame: CGRect(origin: CGPoint(), size: size))
self.backgroundNode.update(size: size, transition: transition)
transition.updateFrame(node: self.separatorNode, frame: CGRect(origin: CGPoint(x: 0.0, y: 0.0), size: CGSize(width: size.width, height: UIScreenPixel)))
var sideInset: CGFloat = 16.0

View File

@ -4,8 +4,11 @@ swift_library(
name = "GradientBackground",
module_name = "GradientBackground",
srcs = glob([
"Sources/**/*.swift",
"Sources/**/*.swift",
]),
copts = [
"-O",
],
deps = [
"//submodules/AsyncDisplayKit:AsyncDisplayKit",
"//submodules/Display:Display",

View File

@ -3,193 +3,11 @@ import UIKit
import Display
import AsyncDisplayKit
private func shiftArray(array: [CGPoint], offset: Int) -> [CGPoint] {
var newArray = array
var offset = offset
while offset > 0 {
let element = newArray.removeFirst()
newArray.append(element)
offset -= 1
}
return newArray
public protocol GradientBackgroundNode: ASDisplayNode {
func updateLayout(size: CGSize, transition: ContainedViewLayoutTransition)
func animateEvent(transition: ContainedViewLayoutTransition)
}
private func generateGradientComponent(size: CGSize, color: UIColor) -> UIImage? {
UIGraphicsBeginImageContextWithOptions(size, false, 1.0)
let c = UIGraphicsGetCurrentContext()
c?.clear(CGRect(origin: CGPoint.zero, size: size))
c?.setBlendMode(.normal)
var gradLocs: [CGFloat] = [0.0, 0.05, 1.0]
let colorSpace = CGColorSpaceCreateDeviceRGB()
let radius = min(size.width / 2.0, size.height / 2.0)
let colors = [
color.cgColor,
color.cgColor,
color.withAlphaComponent(0).cgColor
]
let grad = CGGradient(colorsSpace: colorSpace, colors: colors as CFArray, locations: &gradLocs)
if let grad = grad {
let newPoint = CGPoint(x: size.width / 2.0, y: size.height / 2.0)
c?.drawRadialGradient(grad, startCenter: newPoint, startRadius: 0, endCenter: newPoint, endRadius: radius, options: [])
}
let image = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return image
}
public final class GradientBackgroundNode: ASDisplayNode {
private final class PointImage {
let stack: [UIImageView]
init(image: UIImage, count: Int) {
self.stack = (0 ..< count).map { _ in
let imageView = UIImageView(image: image)
imageView.alpha = min(1.0, (1.0 / CGFloat(count)) * 1.2)
return imageView
}
}
func updateFrame(frame: CGRect, transition: ContainedViewLayoutTransition) {
let nextFrame = frame
for i in 0 ..< self.stack.count {
transition.updateFrame(view: self.stack[i], frame: nextFrame)
//nextFrame = nextFrame.insetBy(dx: nextFrame.width / 4.0, dy: nextFrame.height / 4.0)
}
}
}
private var pointImages: [PointImage] = []
private let dimView: UIView
private var phase: Int = 0
private var validLayout: CGSize?
private var testTimer: Timer?
override public init() {
self.dimView = UIView()
self.dimView.backgroundColor = UIColor(white: 1.0, alpha: 0.0)
super.init()
self.phase = 0
self.backgroundColor = .white
self.clipsToBounds = true
let colors: [UIColor] = [
UIColor(rgb: 0x7FA381),
UIColor(rgb: 0xFFF5C5),
UIColor(rgb: 0x336F55),
UIColor(rgb: 0xFBE37D)
]
let layerCount = 1
for i in 0 ..< colors.count {
let image = generateGradientComponent(size: CGSize(width: 300.0, height: 300.0), color: colors[i].withMultiplied(hue: 1.0, saturation: 1.0, brightness: 1.0))!
let pointImage = PointImage(image: image, count: layerCount)
self.pointImages.append(pointImage)
}
for i in 0 ..< layerCount {
for pointImage in self.pointImages {
self.view.addSubview(pointImage.stack[i])
}
}
self.view.addSubview(self.dimView)
let defaultAlpha = self.pointImages[0].stack[0].alpha
var alphaPhase = 0
if #available(iOSApplicationExtension 10.0, iOS 10.0, *) {
let testTimer = Timer(timeInterval: 1.5, repeats: true, block: { [weak self] _ in
guard let strongSelf = self else {
return
}
return;
alphaPhase += 1
for image in strongSelf.pointImages {
for i in 0 ..< image.stack.count {
if alphaPhase % 2 == 0 {
//image.stack[i].alpha = defaultAlpha
image.stack[i].layer.compositingFilter = "screenBlendMode"
} else {
//image.stack[i].alpha = i == 0 ? 1.0 : 0.0
image.stack[i].layer.compositingFilter = nil
}
}
}
})
self.testTimer = testTimer
RunLoop.main.add(testTimer, forMode: .common)
}
}
deinit {
self.testTimer?.invalidate()
}
public func updateLayout(size: CGSize, transition: ContainedViewLayoutTransition) {
self.validLayout = size
self.dimView.frame = CGRect(origin: CGPoint(), size: size)
let positions: [CGPoint]
let basePositions: [CGPoint] = [
CGPoint(x: 0.80, y: 0.10),
CGPoint(x: 0.60, y: 0.20),
CGPoint(x: 0.35, y: 0.25),
CGPoint(x: 0.25, y: 0.60),
CGPoint(x: 0.20, y: 0.90),
CGPoint(x: 0.40, y: 0.80),
CGPoint(x: 0.65, y: 0.75),
CGPoint(x: 0.75, y: 0.40)
]/*.map { point -> CGPoint in
var point = point
if point.x < 0.5 {
point.x *= 0.5
} else {
point.x = 1.0 - (1.0 - point.x) * 0.5
}
if point.y < 0.5 {
point.y *= 0.5
} else {
point.y = 1.0 - (1.0 - point.x) * 0.5
}
return point
}*/
positions = shiftArray(array: basePositions, offset: self.phase % 8)
for i in 0 ..< positions.count / 2 {
if self.pointImages.count <= i {
break
}
let position = positions[i * 2]
let pointCenter = CGPoint(x: size.width * position.x, y: size.height * position.y)
let pointSize = CGSize(width: size.width * 1.9, height: size.height * 1.9)
self.pointImages[i].updateFrame(frame: CGRect(origin: CGPoint(x: pointCenter.x - pointSize.width / 2.0, y: pointCenter.y - pointSize.height / 2.0), size: pointSize), transition: transition)
}
}
public func animateEvent(transition: ContainedViewLayoutTransition) {
self.phase = self.phase + 1
if let size = self.validLayout {
self.updateLayout(size: size, transition: transition)
}
}
public func createGradientBackgroundNode() -> GradientBackgroundNode {
return SoftwareGradientBackgroundNode()
}

View File

@ -0,0 +1,153 @@
import Foundation
import UIKit
import Display
import AsyncDisplayKit
func shiftArray(array: [CGPoint], offset: Int) -> [CGPoint] {
var newArray = array
var offset = offset
while offset > 0 {
let element = newArray.removeFirst()
newArray.append(element)
offset -= 1
}
return newArray
}
private func generateGradientComponent(size: CGSize, color: UIColor) -> UIImage? {
UIGraphicsBeginImageContextWithOptions(size, false, 1.0)
let c = UIGraphicsGetCurrentContext()
c?.clear(CGRect(origin: CGPoint.zero, size: size))
c?.setBlendMode(.normal)
var gradLocs: [CGFloat] = [0.0, 0.05, 1.0]
let colorSpace = CGColorSpaceCreateDeviceRGB()
let radius = min(size.width / 2.0, size.height / 2.0)
let colors = [
color.cgColor,
color.cgColor,
color.withAlphaComponent(0).cgColor
]
let grad = CGGradient(colorsSpace: colorSpace, colors: colors as CFArray, locations: &gradLocs)
if let grad = grad {
let newPoint = CGPoint(x: size.width / 2.0, y: size.height / 2.0)
c?.drawRadialGradient(grad, startCenter: newPoint, startRadius: 0, endCenter: newPoint, endRadius: radius, options: [])
}
let image = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return image
}
final class PlainGradientBackgroundNode: ASDisplayNode, GradientBackgroundNode {
private final class PointImage {
let stack: [UIImageView]
init(image: UIImage, count: Int) {
self.stack = (0 ..< count).map { _ in
let imageView = UIImageView(image: image)
imageView.alpha = min(1.0, (1.0 / CGFloat(count)) * 1.2)
return imageView
}
}
func updateFrame(frame: CGRect, transition: ContainedViewLayoutTransition) {
let nextFrame = frame
for i in 0 ..< self.stack.count {
transition.updateFrame(view: self.stack[i], frame: nextFrame)
//nextFrame = nextFrame.insetBy(dx: nextFrame.width / 4.0, dy: nextFrame.height / 4.0)
}
}
}
private var pointImages: [PointImage] = []
private let dimView: UIView
private var phase: Int = 0
private var validLayout: CGSize?
override public init() {
self.dimView = UIView()
self.dimView.backgroundColor = UIColor(white: 1.0, alpha: 0.0)
super.init()
self.phase = 0
self.backgroundColor = .white
self.clipsToBounds = true
let colors: [UIColor] = [
UIColor(rgb: 0x7FA381),
UIColor(rgb: 0xFFF5C5),
UIColor(rgb: 0x336F55),
UIColor(rgb: 0xFBE37D)
]
let layerCount = 1
for i in 0 ..< colors.count {
let image = generateGradientComponent(size: CGSize(width: 300.0, height: 300.0), color: colors[i].withMultiplied(hue: 1.0, saturation: 1.0, brightness: 1.0))!
let pointImage = PointImage(image: image, count: layerCount)
self.pointImages.append(pointImage)
}
for i in 0 ..< layerCount {
for pointImage in self.pointImages {
self.view.addSubview(pointImage.stack[i])
}
}
self.view.addSubview(self.dimView)
}
deinit {
}
public func updateLayout(size: CGSize, transition: ContainedViewLayoutTransition) {
self.validLayout = size
self.dimView.frame = CGRect(origin: CGPoint(), size: size)
let positions: [CGPoint]
let basePositions: [CGPoint] = [
CGPoint(x: 0.80, y: 0.10),
CGPoint(x: 0.60, y: 0.20),
CGPoint(x: 0.35, y: 0.25),
CGPoint(x: 0.25, y: 0.60),
CGPoint(x: 0.20, y: 0.90),
CGPoint(x: 0.40, y: 0.80),
CGPoint(x: 0.65, y: 0.75),
CGPoint(x: 0.75, y: 0.40)
]
positions = shiftArray(array: basePositions, offset: self.phase % 8)
for i in 0 ..< positions.count / 2 {
if self.pointImages.count <= i {
break
}
let position = positions[i * 2]
let pointCenter = CGPoint(x: size.width * position.x, y: size.height * position.y)
let pointSize = CGSize(width: size.width * 1.9, height: size.height * 1.9)
self.pointImages[i].updateFrame(frame: CGRect(origin: CGPoint(x: pointCenter.x - pointSize.width / 2.0, y: pointCenter.y - pointSize.height / 2.0), size: pointSize), transition: transition)
}
}
public func animateEvent(transition: ContainedViewLayoutTransition) {
self.phase = self.phase + 1
if let size = self.validLayout {
self.updateLayout(size: size, transition: transition)
}
}
}

View File

@ -0,0 +1,282 @@
import Foundation
import UIKit
import Display
import AsyncDisplayKit
private func gatherPositions(_ list: [CGPoint]) -> [CGPoint] {
var result: [CGPoint] = []
for i in 0 ..< list.count / 2 {
result.append(list[i * 2])
}
return result
}
private func interpolateFloat(_ value1: CGFloat, _ value2: CGFloat, at factor: CGFloat) -> CGFloat {
return value1 * (1.0 - factor) + value2 * factor
}
private func interpolatePoints(_ point1: CGPoint, _ point2: CGPoint, at factor: CGFloat) -> CGPoint {
return CGPoint(x: interpolateFloat(point1.x, point2.x, at: factor), y: interpolateFloat(point1.y, point2.y, at: factor))
}
private func generateGradient(size: CGSize, colors: [UIColor], positions: [CGPoint]) -> UIImage {
let width = Int(size.width)
let height = Int(size.height)
let rgbData = malloc(MemoryLayout<Float>.size * colors.count * 3)!
defer {
free(rgbData)
}
let rgb = rgbData.assumingMemoryBound(to: Float.self)
for i in 0 ..< colors.count {
var r: CGFloat = 0.0
var g: CGFloat = 0.0
var b: CGFloat = 0.0
colors[i].getRed(&r, green: &g, blue: &b, alpha: nil)
rgb.advanced(by: i * 3 + 0).pointee = Float(r)
rgb.advanced(by: i * 3 + 1).pointee = Float(g)
rgb.advanced(by: i * 3 + 2).pointee = Float(b)
}
let positionData = malloc(MemoryLayout<Float>.size * positions.count * 2)!
defer {
free(positionData)
}
let positionFloats = positionData.assumingMemoryBound(to: Float.self)
for i in 0 ..< positions.count {
positionFloats.advanced(by: i * 2 + 0).pointee = Float(positions[i].x)
positionFloats.advanced(by: i * 2 + 1).pointee = Float(1.0 - positions[i].y)
}
let context = DrawingContext(size: CGSize(width: CGFloat(width), height: CGFloat(height)), scale: 1.0, opaque: true, clear: false)
let imageBytes = context.bytes.assumingMemoryBound(to: UInt8.self)
for y in 0 ..< height {
let directPixelY = Float(y) / Float(height)
let centerDistanceY = directPixelY - 0.5
let centerDistanceY2 = centerDistanceY * centerDistanceY
let lineBytes = imageBytes.advanced(by: context.bytesPerRow * y)
for x in 0 ..< width {
let directPixelX = Float(x) / Float(width)
let centerDistanceX = directPixelX - 0.5
let centerDistance = sqrt(centerDistanceX * centerDistanceX + centerDistanceY2)
let swirlFactor = 0.35 * centerDistance
let theta = swirlFactor * swirlFactor * 0.8 * 8.0
let sinTheta = sin(theta)
let cosTheta = cos(theta)
let pixelX = max(0.0, min(1.0, 0.5 + centerDistanceX * cosTheta - centerDistanceY * sinTheta))
let pixelY = max(0.0, min(1.0, 0.5 + centerDistanceX * sinTheta + centerDistanceY * cosTheta))
var distanceSum: Float = 0.0
var r: Float = 0.0
var g: Float = 0.0
var b: Float = 0.0
for i in 0 ..< colors.count {
let colorX = positionFloats[i * 2 + 0]
let colorY = positionFloats[i * 2 + 1]
let distanceX = pixelX - colorX
let distanceY = pixelY - colorY
var distance = max(0.0, 0.92 - sqrt(distanceX * distanceX + distanceY * distanceY))
distance = distance * distance * distance
distanceSum += distance
r = r + distance * rgb[i * 3 + 0]
g = g + distance * rgb[i * 3 + 1]
b = b + distance * rgb[i * 3 + 2]
}
let pixelBytes = lineBytes.advanced(by: x * 4)
pixelBytes.advanced(by: 0).pointee = UInt8(b / distanceSum * 255.0)
pixelBytes.advanced(by: 1).pointee = UInt8(g / distanceSum * 255.0)
pixelBytes.advanced(by: 2).pointee = UInt8(r / distanceSum * 255.0)
pixelBytes.advanced(by: 3).pointee = 0xff
}
}
return context.generateImage()!
}
final class SoftwareGradientBackgroundNode: ASDisplayNode, GradientBackgroundNode {
private var phase: Int = 0
private let contentView: UIImageView
private var validPhase: Int?
private var validLayout: CGSize?
private var timer: Timer?
private struct PhaseTransitionKey: Hashable {
var width: Int
var height: Int
var fromPhase: Int
var toPhase: Int
var numberOfFrames: Int
var curve: ContainedViewLayoutTransitionCurve
}
private var cachedPhaseTransition: [PhaseTransitionKey: [UIImage]] = [:]
override public init() {
self.contentView = UIImageView()
super.init()
self.view.addSubview(self.contentView)
self.phase = 0
self.backgroundColor = .white
/*if #available(iOS 10.0, *) {
let timer = Timer(timeInterval: 1.0, repeats: true, block: { [weak self] _ in
guard let strongSelf = self else {
return
}
strongSelf.phase += 1
if let size = strongSelf.validLayout {
strongSelf.updateLayout(size: size, transition: .animated(duration: 0.5, curve: .spring))
}
})
self.timer = timer
RunLoop.main.add(timer, forMode: .common)
}*/
}
deinit {
self.timer?.invalidate()
}
private func generateAndCachePhaseTransition(key: PhaseTransitionKey) {
DispatchQueue.global().async { [weak self] in
let basePositions: [CGPoint] = [
CGPoint(x: 0.80, y: 0.10),
CGPoint(x: 0.60, y: 0.20),
CGPoint(x: 0.35, y: 0.25),
CGPoint(x: 0.25, y: 0.60),
CGPoint(x: 0.20, y: 0.90),
CGPoint(x: 0.40, y: 0.80),
CGPoint(x: 0.65, y: 0.75),
CGPoint(x: 0.75, y: 0.40)
]
let colors: [UIColor] = [
UIColor(rgb: 0x7FA381),
UIColor(rgb: 0xFFF5C5),
UIColor(rgb: 0x336F55),
UIColor(rgb: 0xFBE37D)
]
var images: [UIImage] = []
let previousPositions = gatherPositions(shiftArray(array: basePositions, offset: key.fromPhase % 8))
let positions = gatherPositions(shiftArray(array: basePositions, offset: key.toPhase % 8))
let startTime = CFAbsoluteTimeGetCurrent()
for i in 0 ..< key.numberOfFrames {
let t = key.curve.solve(at: CGFloat(i) / CGFloat(key.numberOfFrames - 1))
let morphedPositions = Array(zip(previousPositions, positions).map { previous, current -> CGPoint in
return interpolatePoints(previous, current, at: t)
})
images.append(generateGradient(size: CGSize(width: key.width, height: key.height), colors: colors, positions: morphedPositions))
}
print("Animation cached in \((CFAbsoluteTimeGetCurrent() - startTime) * 1000.0) ms")
DispatchQueue.main.async {
guard let strongSelf = self else {
return
}
strongSelf.cachedPhaseTransition.removeAll()
strongSelf.cachedPhaseTransition[key] = images
}
}
}
public func updateLayout(size: CGSize, transition: ContainedViewLayoutTransition) {
let sizeUpdated = self.validLayout != size
self.validLayout = size
let imageSize = size.fitted(CGSize(width: 80.0, height: 80.0)).integralFloor
let basePositions: [CGPoint] = [
CGPoint(x: 0.80, y: 0.10),
CGPoint(x: 0.60, y: 0.20),
CGPoint(x: 0.35, y: 0.25),
CGPoint(x: 0.25, y: 0.60),
CGPoint(x: 0.20, y: 0.90),
CGPoint(x: 0.40, y: 0.80),
CGPoint(x: 0.65, y: 0.75),
CGPoint(x: 0.75, y: 0.40)
]
let colors: [UIColor] = [
UIColor(rgb: 0x7FA381),
UIColor(rgb: 0xFFF5C5),
UIColor(rgb: 0x336F55),
UIColor(rgb: 0xFBE37D)
]
let positions = gatherPositions(shiftArray(array: basePositions, offset: self.phase % 8))
if let validPhase = self.validPhase {
if validPhase != self.phase {
self.validPhase = self.phase
let previousPositions = gatherPositions(shiftArray(array: basePositions, offset: validPhase % 8))
if case let .animated(duration, curve) = transition {
var images: [UIImage] = []
let cacheKey = PhaseTransitionKey(width: Int(imageSize.width), height: Int(imageSize.height), fromPhase: validPhase, toPhase: self.phase, numberOfFrames: Int(duration * 60), curve: curve)
if let current = self.cachedPhaseTransition[cacheKey] {
images = current
} else {
let startTime = CFAbsoluteTimeGetCurrent()
let maxFrame = Int(duration * 30)
for i in 0 ..< maxFrame {
let t = curve.solve(at: CGFloat(i) / CGFloat(maxFrame - 1))
let morphedPositions = Array(zip(previousPositions, positions).map { previous, current -> CGPoint in
return interpolatePoints(previous, current, at: t)
})
images.append(generateGradient(size: imageSize, colors: colors, positions: morphedPositions))
}
print("Animation generated in \((CFAbsoluteTimeGetCurrent() - startTime) * 1000.0) ms")
}
self.contentView.image = images.last
let animation = CAKeyframeAnimation(keyPath: "contents")
animation.values = images.map { $0.cgImage! }
animation.duration = duration * UIView.animationDurationFactor()
animation.calculationMode = .linear
self.contentView.layer.add(animation, forKey: "image")
} else {
self.contentView.image = generateGradient(size: imageSize, colors: colors, positions: positions)
}
}
} else if sizeUpdated {
self.contentView.image = generateGradient(size: imageSize, colors: colors, positions: positions)
self.validPhase = self.phase
}
transition.updateFrame(view: self.contentView, frame: CGRect(origin: CGPoint(), size: size))
}
public func animateEvent(transition: ContainedViewLayoutTransition) {
self.phase = self.phase + 1
if let size = self.validLayout {
self.updateLayout(size: size, transition: transition)
}
}
}

View File

@ -43,7 +43,7 @@
@property (nonatomic, assign) bool openEditor;
@property (nonatomic, copy) void (^cameraPressed)(TGAttachmentCameraView *cameraView);
@property (nonatomic, copy) void (^sendPressed)(TGMediaAsset *currentItem, bool asFiles, bool silentPosting, int32_t scheduleTime);
@property (nonatomic, copy) void (^sendPressed)(TGMediaAsset *currentItem, bool asFiles, bool silentPosting, int32_t scheduleTime, bool isFromPicker);
@property (nonatomic, copy) void (^avatarCompletionBlock)(UIImage *image);
@property (nonatomic, copy) void (^avatarVideoCompletionBlock)(UIImage *image, AVAsset *asset, TGVideoEditAdjustments *adjustments);

View File

@ -270,7 +270,7 @@ const NSUInteger TGAttachmentDisplayedAssetLimit = 500;
{
if (strongSelf->_selectionContext.allowGrouping)
[[NSUserDefaults standardUserDefaults] setObject:@(!strongSelf->_selectionContext.grouping) forKey:@"TG_mediaGroupingDisabled_v0"];
strongSelf.sendPressed(nil, false, false, 0);
strongSelf.sendPressed(nil, false, false, 0, false);
}
}];
[_sendMediaItemView setHidden:true animated:false];
@ -282,7 +282,7 @@ const NSUInteger TGAttachmentDisplayedAssetLimit = 500;
{
__strong TGAttachmentCarouselItemView *strongSelf = weakSelf;
if (strongSelf != nil && strongSelf.sendPressed != nil)
strongSelf.sendPressed(nil, true, false, 0);
strongSelf.sendPressed(nil, true, false, 0, false);
}];
_sendFileItemView.requiresDivider = false;
[_sendFileItemView setHidden:true animated:false];
@ -807,7 +807,7 @@ const NSUInteger TGAttachmentDisplayedAssetLimit = 500;
{
if (strongSelf->_selectionContext.allowGrouping)
[[NSUserDefaults standardUserDefaults] setObject:@(!strongSelf->_selectionContext.grouping) forKey:@"TG_mediaGroupingDisabled_v0"];
strongSelf.sendPressed(item.asset, strongSelf.asFile, silentPosting, scheduleTime);
strongSelf.sendPressed(item.asset, strongSelf.asFile, silentPosting, scheduleTime, true);
}
};

View File

@ -66,7 +66,7 @@
[TGPassportAttachMenu _displayCameraWithView:cameraView menuController:strongController parentController:strongParentController context:context intent:intent uploadAction:uploadAction];
};
carouselItem.sendPressed = ^(TGMediaAsset *currentItem, __unused bool asFiles, __unused bool silentPosting, __unused int32_t scheduleTime)
carouselItem.sendPressed = ^(TGMediaAsset *currentItem, __unused bool asFiles, __unused bool silentPosting, __unused int32_t scheduleTime, __unused bool fromPicker)
{
__strong TGMenuSheetController *strongController = weakController;
if (strongController == nil)

View File

@ -117,7 +117,7 @@ public func legacyMediaEditor(context: AccountContext, peer: Peer, media: AnyMed
})
}
public func legacyAttachmentMenu(context: AccountContext, peer: Peer, chatLocation: ChatLocation, editMediaOptions: LegacyAttachmentMenuMediaEditing?, saveEditedPhotos: Bool, allowGrouping: Bool, hasSchedule: Bool, canSendPolls: Bool, presentationData: PresentationData, parentController: LegacyController, recentlyUsedInlineBots: [Peer], initialCaption: String, openGallery: @escaping () -> Void, openCamera: @escaping (TGAttachmentCameraView?, TGMenuSheetController?) -> Void, openFileGallery: @escaping () -> Void, openWebSearch: @escaping () -> Void, openMap: @escaping () -> Void, openContacts: @escaping () -> Void, openPoll: @escaping () -> Void, presentSelectionLimitExceeded: @escaping () -> Void, presentCantSendMultipleFiles: @escaping () -> Void, presentSchedulePicker: @escaping (@escaping (Int32) -> Void) -> Void, presentTimerPicker: @escaping (@escaping (Int32) -> Void) -> Void, sendMessagesWithSignals: @escaping ([Any]?, Bool, Int32, @escaping (String) -> UIView?, @escaping () -> Void) -> Void, selectRecentlyUsedInlineBot: @escaping (Peer) -> Void, presentStickers: @escaping (@escaping (TelegramMediaFile, Bool, UIView, CGRect) -> Void) -> TGPhotoPaintStickersScreen?, present: @escaping (ViewController, Any?) -> Void) -> TGMenuSheetController {
public func legacyAttachmentMenu(context: AccountContext, peer: Peer, chatLocation: ChatLocation, editMediaOptions: LegacyAttachmentMenuMediaEditing?, saveEditedPhotos: Bool, allowGrouping: Bool, hasSchedule: Bool, canSendPolls: Bool, presentationData: PresentationData, parentController: LegacyController, recentlyUsedInlineBots: [Peer], initialCaption: String, openGallery: @escaping () -> Void, openCamera: @escaping (TGAttachmentCameraView?, TGMenuSheetController?) -> Void, openFileGallery: @escaping () -> Void, openWebSearch: @escaping () -> Void, openMap: @escaping () -> Void, openContacts: @escaping () -> Void, openPoll: @escaping () -> Void, presentSelectionLimitExceeded: @escaping () -> Void, presentCantSendMultipleFiles: @escaping () -> Void, presentSchedulePicker: @escaping (@escaping (Int32) -> Void) -> Void, presentTimerPicker: @escaping (@escaping (Int32) -> Void) -> Void, sendMessagesWithSignals: @escaping ([Any]?, Bool, Int32, ((String) -> UIView?)?, @escaping () -> Void) -> Void, selectRecentlyUsedInlineBot: @escaping (Peer) -> Void, presentStickers: @escaping (@escaping (TelegramMediaFile, Bool, UIView, CGRect) -> Void) -> TGPhotoPaintStickersScreen?, present: @escaping (ViewController, Any?) -> Void) -> TGMenuSheetController {
let defaultVideoPreset = defaultVideoPresetForContext(context)
UserDefaults.standard.set(defaultVideoPreset.rawValue as NSNumber, forKey: "TG_preferredVideoPreset_v0")
@ -213,14 +213,14 @@ public func legacyAttachmentMenu(context: AccountContext, peer: Peer, chatLocati
done?(time)
}
}
carouselItem.sendPressed = { [weak controller, weak carouselItem] currentItem, asFiles, silentPosting, scheduleTime in
carouselItem.sendPressed = { [weak controller, weak carouselItem] currentItem, asFiles, silentPosting, scheduleTime, isFromPicker in
if let controller = controller, let carouselItem = carouselItem {
let intent: TGMediaAssetsControllerIntent = asFiles ? TGMediaAssetsControllerSendFileIntent : TGMediaAssetsControllerSendMediaIntent
let signals = TGMediaAssetsController.resultSignals(for: carouselItem.selectionContext, editingContext: carouselItem.editingContext, intent: intent, currentItem: currentItem, storeAssets: true, useMediaCache: false, descriptionGenerator: legacyAssetPickerItemGenerator(), saveEditedPhotos: saveEditedPhotos)
if slowModeEnabled, let signals = signals, signals.count > 1 {
presentCantSendMultipleFiles()
} else {
sendMessagesWithSignals(signals, silentPosting, scheduleTime, { [weak carouselItem] uniqueId in
sendMessagesWithSignals(signals, silentPosting, scheduleTime, isFromPicker ? nil : { [weak carouselItem] uniqueId in
if let carouselItem = carouselItem {
return carouselItem.getItemSnapshot(uniqueId)
}

View File

@ -59,9 +59,6 @@ public func chatMessagePhotoDatas(postbox: Postbox, photoReference: ImageMediaRe
}
var sources: [SizeSource] = []
if let miniThumbnail = photoReference.media.immediateThumbnailData.flatMap(decodeTinyThumbnail) {
sources.append(.miniThumbnail(data: miniThumbnail))
}
let thumbnailByteSize = Int(progressiveRepresentation.progressiveSizes[0])
var largestByteSize = Int(progressiveRepresentation.progressiveSizes[0])
for (maxDimension, byteSizes) in progressiveRangeMap {
@ -79,6 +76,12 @@ public func chatMessagePhotoDatas(postbox: Postbox, photoReference: ImageMediaRe
break
}
}
if sources.isEmpty {
sources.append(.image(size: largestByteSize))
}
if let miniThumbnail = photoReference.media.immediateThumbnailData.flatMap(decodeTinyThumbnail) {
sources.insert(.miniThumbnail(data: miniThumbnail), at: 0)
}
return Signal { subscriber in
let signals: [Signal<(SizeSource, Data?), NoError>] = sources.map { source -> Signal<(SizeSource, Data?), NoError> in

View File

@ -234,11 +234,11 @@ private final class SemanticStatusNodeProgressTransition {
self.initialValue = initialValue
}
func valueAt(timestamp: Double, actualValue: CGFloat) -> CGFloat {
func valueAt(timestamp: Double, actualValue: CGFloat) -> (CGFloat, Bool) {
let duration = 0.2
var t = CGFloat((timestamp - self.beginTime) / duration)
t = min(1.0, max(0.0, t))
return t * actualValue + (1.0 - t) * self.initialValue
return (t * actualValue + (1.0 - t) * self.initialValue, t >= 1.0 - 0.001)
}
}
@ -388,7 +388,11 @@ private final class SemanticStatusNodeProgressContext: SemanticStatusNodeStateCo
let resolvedValue: CGFloat?
if let value = self.value {
if let transition = self.transition {
resolvedValue = transition.valueAt(timestamp: timestamp, actualValue: value)
let (v, isCompleted) = transition.valueAt(timestamp: timestamp, actualValue: value)
resolvedValue = v
if isCompleted {
self.transition = nil
}
} else {
resolvedValue = value
}
@ -400,12 +404,12 @@ private final class SemanticStatusNodeProgressContext: SemanticStatusNodeStateCo
func updateValue(value: CGFloat?) {
if value != self.value {
let previousValue = value
let previousValue = self.value
self.value = value
let timestamp = CACurrentMediaTime()
if let _ = value, let previousValue = previousValue {
if let transition = self.transition {
self.transition = SemanticStatusNodeProgressTransition(beginTime: timestamp, initialValue: transition.valueAt(timestamp: timestamp, actualValue: previousValue))
self.transition = SemanticStatusNodeProgressTransition(beginTime: timestamp, initialValue: transition.valueAt(timestamp: timestamp, actualValue: previousValue).0)
} else {
self.transition = SemanticStatusNodeProgressTransition(beginTime: timestamp, initialValue: previousValue)
}
@ -509,7 +513,11 @@ private final class SemanticStatusNodeCheckContext: SemanticStatusNodeStateConte
let resolvedValue: CGFloat
if let transition = self.transition {
resolvedValue = transition.valueAt(timestamp: timestamp, actualValue: value)
let (v, isCompleted) = transition.valueAt(timestamp: timestamp, actualValue: value)
resolvedValue = v
if isCompleted {
self.transition = nil
}
} else {
resolvedValue = value
}

View File

@ -130,7 +130,8 @@ public final class GroupCallNavigationAccessoryPanel: ASDisplayNode {
private let avatarsNode: AnimatedAvatarSetNode
private var audioLevelGenerators: [PeerId: FakeAudioLevelGenerator] = [:]
private var audioLevelGeneratorTimer: SwiftSignalKit.Timer?
private let backgroundNode: NavigationBackgroundNode
private let separatorNode: ASDisplayNode
private let membersDisposable = MetaDisposable()
@ -174,13 +175,17 @@ public final class GroupCallNavigationAccessoryPanel: ASDisplayNode {
self.avatarsContext = AnimatedAvatarSetContext()
self.avatarsNode = AnimatedAvatarSetNode()
self.backgroundNode = NavigationBackgroundNode(color: .clear)
self.separatorNode = ASDisplayNode()
self.separatorNode.isLayerBacked = true
super.init()
self.addSubnode(self.contentNode)
self.contentNode.addSubnode(self.backgroundNode)
self.tapButton.highligthedChanged = { [weak self] highlighted in
if let strongSelf = self {
@ -280,7 +285,7 @@ public final class GroupCallNavigationAccessoryPanel: ASDisplayNode {
self.strings = presentationData.strings
self.dateTimeFormat = presentationData.dateTimeFormat
self.contentNode.backgroundColor = self.theme.rootController.navigationBar.backgroundColor
self.backgroundNode.color = self.theme.rootController.navigationBar.backgroundColor
self.separatorNode.backgroundColor = presentationData.theme.chat.historyNavigation.strokeColor
self.joinButtonTitleNode.attributedText = NSAttributedString(string: self.joinButtonTitleNode.attributedText?.string ?? "", font: Font.with(size: 15.0, design: .round, weight: .semibold, traits: [.monospacedNumbers]), textColor: self.isScheduled ? .white : presentationData.theme.chat.inputPanel.actionControlForegroundColor)
@ -630,6 +635,8 @@ public final class GroupCallNavigationAccessoryPanel: ASDisplayNode {
self.micButton.isHidden = self.currentData?.groupCall == nil
transition.updateFrame(node: self.separatorNode, frame: CGRect(origin: CGPoint(x: 0.0, y: panelHeight - UIScreenPixel), size: CGSize(width: size.width, height: UIScreenPixel)))
transition.updateFrame(node: self.backgroundNode, frame: CGRect(origin: CGPoint(), size: CGSize(width: size.width, height: panelHeight)))
self.backgroundNode.update(size: self.backgroundNode.bounds.size, transition: transition)
}
public func animateIn(_ transition: ContainedViewLayoutTransition) {

View File

@ -232,7 +232,7 @@ public func customizeDefaultDarkPresentationTheme(theme: PresentationTheme, edit
public func makeDefaultDarkPresentationTheme(extendingThemeReference: PresentationThemeReference? = nil, preview: Bool) -> PresentationTheme {
let rootTabBar = PresentationThemeRootTabBar(
backgroundColor: UIColor(rgb: 0x1c1c1d),
backgroundColor: UIColor(rgb: 0x1c1c1d, alpha: 0.5),
separatorColor: UIColor(rgb: 0x3d3d40),
iconColor: UIColor(rgb: 0x828282),
selectedIconColor: UIColor(rgb: 0xffffff),
@ -250,7 +250,7 @@ public func makeDefaultDarkPresentationTheme(extendingThemeReference: Presentati
secondaryTextColor: UIColor(rgb: 0xffffff, alpha: 0.5),
controlColor: UIColor(rgb: 0x767676),
accentTextColor: UIColor(rgb: 0xffffff),
backgroundColor: UIColor(rgb: 0x1c1c1d),
backgroundColor: UIColor(rgb: 0x1a1a1a, alpha: 0.5),
separatorColor: UIColor(rgb: 0x3d3d40),
badgeBackgroundColor: UIColor(rgb: 0xffffff),
badgeStrokeColor: UIColor(rgb: 0x1c1c1d),
@ -439,8 +439,8 @@ public func makeDefaultDarkPresentationTheme(extendingThemeReference: Presentati
)
let inputPanel = PresentationThemeChatInputPanel(
panelBackgroundColor: UIColor(rgb: 0x1c1c1d),
panelBackgroundColorNoWallpaper: UIColor(rgb: 0x000000),
panelBackgroundColor: UIColor(rgb: 0x1c1c1d, alpha: 0.5),
panelBackgroundColorNoWallpaper: UIColor(rgb: 0x000000, alpha: 0.5),
panelSeparatorColor: UIColor(rgb: 0x3d3d40),
panelControlAccentColor: UIColor(rgb: 0xffffff),
panelControlColor: UIColor(rgb: 0x808080),

View File

@ -339,7 +339,7 @@ public func makeDefaultDayPresentationTheme(extendingThemeReference: Presentatio
)
let rootTabBar = PresentationThemeRootTabBar(
backgroundColor: UIColor(rgb: 0xf7f7f7),
backgroundColor: UIColor(rgb: 0xffffff, alpha: 0.5),
separatorColor: UIColor(rgb: 0xa3a3a3),
iconColor: UIColor(rgb: 0x959595),
selectedIconColor: UIColor(rgb: 0x007ee5),
@ -357,7 +357,7 @@ public func makeDefaultDayPresentationTheme(extendingThemeReference: Presentatio
secondaryTextColor: UIColor(rgb: 0x787878),
controlColor: UIColor(rgb: 0x7e8791),
accentTextColor: UIColor(rgb: 0x007ee5),
backgroundColor: UIColor(rgb: 0xf7f7f7),
backgroundColor: UIColor(rgb: 0xffffff, alpha: 0.5),
separatorColor: UIColor(rgb: 0xc8c7cc),
badgeBackgroundColor: UIColor(rgb: 0xff3b30),
badgeStrokeColor: UIColor(rgb: 0xff3b30),
@ -655,8 +655,8 @@ public func makeDefaultDayPresentationTheme(extendingThemeReference: Presentatio
)
let inputPanel = PresentationThemeChatInputPanel(
panelBackgroundColor: UIColor(rgb: 0xf7f7f7),
panelBackgroundColorNoWallpaper: UIColor(rgb: 0xffffff),
panelBackgroundColor: UIColor(rgb: 0xffffff, alpha: 0.5),
panelBackgroundColorNoWallpaper: UIColor(rgb: 0xffffff, alpha: 0.5),
panelSeparatorColor: UIColor(rgb: 0xb2b2b2),
panelControlAccentColor: UIColor(rgb: 0x007ee5),
panelControlColor: UIColor(rgb: 0x858e99),

View File

@ -8599,9 +8599,15 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
strongSelf.editMessageMediaWithLegacySignals(signals!)
completion()
} else {
let immediateCompletion = getAnimatedTransitionSource == nil
strongSelf.enqueueMediaMessages(signals: signals, silentPosting: silentPosting, scheduleTime: scheduleTime > 0 ? scheduleTime : nil, getAnimatedTransitionSource: getAnimatedTransitionSource, completion: {
completion()
if !immediateCompletion {
completion()
}
})
if immediateCompletion {
completion()
}
}
}, selectRecentlyUsedInlineBot: { [weak self] peer in
if let strongSelf = self, let addressName = peer.addressName {
@ -9542,7 +9548,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
}
}
private func enqueueMediaMessages(signals: [Any]?, silentPosting: Bool, scheduleTime: Int32? = nil, getAnimatedTransitionSource: @escaping (String) -> UIView? = { _ in nil }, completion: @escaping () -> Void = {}) {
private func enqueueMediaMessages(signals: [Any]?, silentPosting: Bool, scheduleTime: Int32? = nil, getAnimatedTransitionSource: ((String) -> UIView?)? = nil, completion: @escaping () -> Void = {}) {
self.enqueueMediaMessageDisposable.set((legacyAssetPickerEnqueueMessages(account: self.context.account, signals: signals!)
|> deliverOnMainQueue).start(next: { [weak self] items in
if let strongSelf = self {
@ -9555,7 +9561,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
let correlationId = Int64.random(in: 0 ..< Int64.max)
message = message.withUpdatedCorrelationId(correlationId)
if items.count == 1 {
if items.count == 1, let getAnimatedTransitionSource = getAnimatedTransitionSource {
completionImpl = nil
strongSelf.chatDisplayNode.messageTransitionNode.add(correlationId: correlationId, source: .mediaInput(ChatMessageTransitionNode.Source.MediaInput(extractSnapshot: {
return getAnimatedTransitionSource(uniqueId)

View File

@ -301,7 +301,7 @@ class ChatControllerNode: ASDisplayNode, UIScrollViewDelegate {
}
let backgroundNode: WallpaperBackgroundNode
let gradientBackgroundNode: GradientBackgroundNode?
var gradientBackgroundNode: GradientBackgroundNode?
let backgroundImageDisposable = MetaDisposable()
let historyNode: ChatHistoryListNode
var blurredHistoryNode: ASImageNode?
@ -319,7 +319,7 @@ class ChatControllerNode: ASDisplayNode, UIScrollViewDelegate {
private var searchNavigationNode: ChatSearchNavigationContentNode?
private let inputPanelBackgroundNode: ASDisplayNode
private let inputPanelBackgroundNode: NavigationBackgroundNode
private let inputPanelBackgroundSeparatorNode: ASDisplayNode
private var plainInputSeparatorAlpha: CGFloat?
private var usePlainInputSeparator: Bool
@ -471,7 +471,7 @@ class ChatControllerNode: ASDisplayNode, UIScrollViewDelegate {
self.backgroundNode.displaysAsynchronously = false
if chatPresentationInterfaceState.chatWallpaper.isBuiltin {
self.gradientBackgroundNode = GradientBackgroundNode()
self.gradientBackgroundNode = createGradientBackgroundNode()
} else {
self.gradientBackgroundNode = nil
}
@ -489,17 +489,16 @@ class ChatControllerNode: ASDisplayNode, UIScrollViewDelegate {
self.reactionContainerNode = ReactionSelectionParentNode(account: context.account, theme: chatPresentationInterfaceState.theme)
self.loadingNode = ChatLoadingNode(theme: self.chatPresentationInterfaceState.theme, chatWallpaper: self.chatPresentationInterfaceState.chatWallpaper, bubbleCorners: self.chatPresentationInterfaceState.bubbleCorners)
self.inputPanelBackgroundNode = ASDisplayNode()
if case let .color(color) = self.chatPresentationInterfaceState.chatWallpaper, UIColor(rgb: color).isEqual(self.chatPresentationInterfaceState.theme.chat.inputPanel.panelBackgroundColorNoWallpaper) {
self.inputPanelBackgroundNode.backgroundColor = self.chatPresentationInterfaceState.theme.chat.inputPanel.panelBackgroundColorNoWallpaper
self.inputPanelBackgroundNode = NavigationBackgroundNode(color: self.chatPresentationInterfaceState.theme.chat.inputPanel.panelBackgroundColorNoWallpaper)
self.usePlainInputSeparator = true
} else {
self.inputPanelBackgroundNode.backgroundColor = self.chatPresentationInterfaceState.theme.chat.inputPanel.panelBackgroundColor
self.inputPanelBackgroundNode = NavigationBackgroundNode(color: self.chatPresentationInterfaceState.theme.chat.inputPanel.panelBackgroundColor)
self.usePlainInputSeparator = false
self.plainInputSeparatorAlpha = nil
}
self.inputPanelBackgroundNode.isLayerBacked = true
self.inputPanelBackgroundNode.isUserInteractionEnabled = false
self.inputPanelBackgroundSeparatorNode = ASDisplayNode()
self.inputPanelBackgroundSeparatorNode.backgroundColor = self.chatPresentationInterfaceState.theme.chat.inputPanel.panelSeparatorColor
@ -1247,7 +1246,7 @@ class ChatControllerNode: ASDisplayNode, UIScrollViewDelegate {
self.insertSubnode(inputPanelNode, aboveSubnode: self.inputPanelBackgroundNode)
}
} else {
let inputPanelHeight = inputPanelNode.updateLayout(width: layout.size.width, leftInset: layout.safeInsets.left, rightInset: layout.safeInsets.right, additionalSideInsets: layout.additionalInsets, maxHeight: layout.size.height - insets.top - insets.bottom, isSecondary: false, transition: transition, interfaceState: self.chatPresentationInterfaceState, metrics: layout.metrics)
let inputPanelHeight = inputPanelNode.updateLayout(width: layout.size.width, leftInset: layout.safeInsets.left, rightInset: layout.safeInsets.right, additionalSideInsets: layout.additionalInsets, maxHeight: layout.size.height - insets.top - insets.bottom - 120.0, isSecondary: false, transition: transition, interfaceState: self.chatPresentationInterfaceState, metrics: layout.metrics)
inputPanelSize = CGSize(width: layout.size.width, height: inputPanelHeight)
}
} else {
@ -1586,7 +1585,7 @@ class ChatControllerNode: ASDisplayNode, UIScrollViewDelegate {
}
var apparentInputPanelFrame = inputPanelFrame
var apparentSecondaryInputPanelFrame = secondaryInputPanelFrame
let apparentSecondaryInputPanelFrame = secondaryInputPanelFrame
var apparentInputBackgroundFrame = inputBackgroundFrame
var apparentNavigateButtonsFrame = navigateButtonsFrame
if case let .media(_, maybeExpanded) = self.chatPresentationInterfaceState.inputMode, let expanded = maybeExpanded, case .search = expanded, let inputPanelFrame = inputPanelFrame {
@ -1603,6 +1602,7 @@ class ChatControllerNode: ASDisplayNode, UIScrollViewDelegate {
let previousInputPanelBackgroundFrame = self.inputPanelBackgroundNode.frame
transition.updateFrame(node: self.inputPanelBackgroundNode, frame: apparentInputBackgroundFrame)
self.inputPanelBackgroundNode.update(size: apparentInputBackgroundFrame.size, transition: transition)
transition.updateFrame(node: self.inputPanelBackgroundSeparatorNode, frame: CGRect(origin: CGPoint(x: 0.0, y: apparentInputBackgroundFrame.origin.y), size: CGSize(width: apparentInputBackgroundFrame.size.width, height: UIScreenPixel)))
transition.updateFrame(node: self.navigateButtons, frame: apparentNavigateButtonsFrame)
@ -1980,6 +1980,17 @@ class ChatControllerNode: ASDisplayNode, UIScrollViewDelegate {
self.backgroundNode.imageContentMode = .scaleAspectFill
}
self.backgroundNode.motionEnabled = chatPresentationInterfaceState.chatWallpaper.settings?.motion ?? false
if chatPresentationInterfaceState.chatWallpaper.isBuiltin {
if self.gradientBackgroundNode == nil {
let gradientBackgroundNode = createGradientBackgroundNode()
self.gradientBackgroundNode = gradientBackgroundNode
self.backgroundNode.supernode?.insertSubnode(gradientBackgroundNode, aboveSubnode: self.backgroundNode)
}
} else if let gradientBackgroundNode = self.gradientBackgroundNode {
self.gradientBackgroundNode = nil
gradientBackgroundNode.removeFromSupernode()
}
}
self.historyNode.verticalScrollIndicatorColor = UIColor(white: 0.5, alpha: 0.8)
@ -1992,10 +2003,10 @@ class ChatControllerNode: ASDisplayNode, UIScrollViewDelegate {
if themeUpdated {
if case let .color(color) = self.chatPresentationInterfaceState.chatWallpaper, UIColor(rgb: color).isEqual(self.chatPresentationInterfaceState.theme.chat.inputPanel.panelBackgroundColorNoWallpaper) {
self.inputPanelBackgroundNode.backgroundColor = self.chatPresentationInterfaceState.theme.chat.inputPanel.panelBackgroundColorNoWallpaper
self.inputPanelBackgroundNode.color = self.chatPresentationInterfaceState.theme.chat.inputPanel.panelBackgroundColorNoWallpaper
self.usePlainInputSeparator = true
} else {
self.inputPanelBackgroundNode.backgroundColor = self.chatPresentationInterfaceState.theme.chat.inputPanel.panelBackgroundColor
self.inputPanelBackgroundNode.color = self.chatPresentationInterfaceState.theme.chat.inputPanel.panelBackgroundColor
self.usePlainInputSeparator = false
self.plainInputSeparatorAlpha = nil
}
@ -2690,6 +2701,9 @@ class ChatControllerNode: ASDisplayNode, UIScrollViewDelegate {
} else {
webpage = self.chatPresentationInterfaceState.urlPreview?.1
}
#if DEBUG
webpage = nil
#endif
messages.append(.message(text: text.string, attributes: attributes, mediaReference: webpage.flatMap(AnyMediaReference.standalone), replyToMessageId: self.chatPresentationInterfaceState.interfaceState.replyMessageId, localGroupingKey: nil, correlationId: nil))
}
}
@ -2947,6 +2961,8 @@ class ChatControllerNode: ASDisplayNode, UIScrollViewDelegate {
switch self.historyNode.visibleContentOffset() {
case let .known(value) where value < 20.0:
return true
case .none:
return true
default:
return false
}

View File

@ -151,8 +151,8 @@ final class ChatInfoTitlePanelNode: ChatTitleAccessoryPanelNode {
let panelHeight: CGFloat = 55.0
if themeUpdated {
self.backgroundNode.backgroundColor = interfaceState.theme.chat.historyNavigation.fillColor
self.separatorNode.backgroundColor = interfaceState.theme.chat.historyNavigation.strokeColor
self.backgroundNode.backgroundColor = interfaceState.theme.rootController.navigationBar.backgroundColor
self.separatorNode.backgroundColor = interfaceState.theme.rootController.navigationBar.separatorColor
}
let updatedButtons: [ChatInfoTitleButton]

View File

@ -422,8 +422,8 @@ final class ChatMediaInputNode: ChatInputNode {
private var inputNodeInteraction: ChatMediaInputNodeInteraction!
private var trendingInteraction: TrendingPaneInteraction?
private let collectionListPanel: ASDisplayNode
private let collectionListPanel: NavigationBackgroundNode
private let collectionListSeparator: ASDisplayNode
private let collectionListContainer: CollectionListContainerNode
@ -476,14 +476,12 @@ final class ChatMediaInputNode: ChatInputNode {
self.themeAndStringsPromise = Promise((theme, strings))
self.collectionListPanel = ASDisplayNode()
self.collectionListPanel.clipsToBounds = true
if case let .color(color) = chatWallpaper, UIColor(rgb: color).isEqual(theme.chat.inputPanel.panelBackgroundColorNoWallpaper) {
self.collectionListPanel.backgroundColor = theme.chat.inputPanel.panelBackgroundColorNoWallpaper
self.collectionListPanel = NavigationBackgroundNode(color: theme.chat.inputPanel.panelBackgroundColorNoWallpaper)
} else {
self.collectionListPanel.backgroundColor = theme.chat.inputPanel.panelBackgroundColor
self.collectionListPanel = NavigationBackgroundNode(color: theme.chat.inputPanel.panelBackgroundColor)
}
self.collectionListPanel.clipsToBounds = true
self.collectionListSeparator = ASDisplayNode()
self.collectionListSeparator.isLayerBacked = true
@ -1062,9 +1060,9 @@ final class ChatMediaInputNode: ChatInputNode {
self.strings = strings
if case let .color(color) = chatWallpaper, UIColor(rgb: color).isEqual(theme.chat.inputPanel.panelBackgroundColorNoWallpaper) {
self.collectionListPanel.backgroundColor = theme.chat.inputPanel.panelBackgroundColorNoWallpaper
self.collectionListPanel.color = theme.chat.inputPanel.panelBackgroundColorNoWallpaper
} else {
self.collectionListPanel.backgroundColor = theme.chat.inputPanel.panelBackgroundColor
self.collectionListPanel.color = theme.chat.inputPanel.panelBackgroundColor
}
self.collectionListSeparator.backgroundColor = theme.chat.inputMediaPanel.panelSeparatorColor
@ -1565,6 +1563,7 @@ final class ChatMediaInputNode: ChatInputNode {
transition.updateFrame(node: self.collectionListContainer, frame: CGRect(origin: CGPoint(x: 0.0, y: contentVerticalOffset), size: CGSize(width: width, height: max(0.0, 41.0 + UIScreenPixel))))
transition.updateFrame(node: self.collectionListPanel, frame: CGRect(origin: CGPoint(x: 0.0, y: collectionListPanelOffset), size: CGSize(width: width, height: 41.0)))
collectionListPanel.update(size: self.collectionListPanel.bounds.size, transition: transition)
transition.updateFrame(node: self.collectionListSeparator, frame: CGRect(origin: CGPoint(x: 0.0, y: 41.0 + collectionListPanelOffset), size: CGSize(width: width, height: separatorHeight)))
self.listView.bounds = CGRect(x: 0.0, y: 0.0, width: 41.0, height: width)
@ -1899,6 +1898,7 @@ final class ChatMediaInputNode: ChatInputNode {
self.updateAppearanceTransition(transition: transition)
transition.updateFrame(node: self.collectionListPanel, frame: CGRect(origin: CGPoint(x: 0.0, y: collectionListPanelOffset), size: self.collectionListPanel.bounds.size))
collectionListPanel.update(size: self.collectionListPanel.bounds.size, transition: transition)
transition.updateFrame(node: self.collectionListSeparator, frame: CGRect(origin: CGPoint(x: 0.0, y: 41.0 + collectionListPanelOffset), size: self.collectionListSeparator.bounds.size))
transition.updatePosition(node: self.listView, position: CGPoint(x: self.listView.position.x, y: (41.0 - collectionListPanelOffset) / 2.0))
transition.updatePosition(node: self.gifListView, position: CGPoint(x: self.gifListView.position.x, y: (41.0 - collectionListPanelOffset) / 2.0))
@ -1920,6 +1920,7 @@ final class ChatMediaInputNode: ChatInputNode {
let transition = ContainedViewLayoutTransition.animated(duration: 0.25, curve: .spring)
self.updateAppearanceTransition(transition: transition)
transition.updateFrame(node: self.collectionListPanel, frame: CGRect(origin: CGPoint(x: 0.0, y: collectionListPanelOffset), size: self.collectionListPanel.bounds.size))
collectionListPanel.update(size: self.collectionListPanel.bounds.size, transition: transition)
transition.updateFrame(node: self.collectionListSeparator, frame: CGRect(origin: CGPoint(x: 0.0, y: 41.0 + collectionListPanelOffset), size: self.collectionListSeparator.bounds.size))
transition.updatePosition(node: self.listView, position: CGPoint(x: self.listView.position.x, y: (41.0 - collectionListPanelOffset) / 2.0))
transition.updatePosition(node: self.gifListView, position: CGPoint(x: self.gifListView.position.x, y: (41.0 - collectionListPanelOffset) / 2.0))

View File

@ -511,7 +511,7 @@ class ChatMessageAnimatedStickerItemNode: ChatMessageItemView {
}
}
animationNode.visibility = isPlaying && !alreadySeen
animationNode.visibility = isPlaying
if self.didSetUpAnimationNode && alreadySeen {
if let emojiFile = self.emojiFile, emojiFile.resource is LocalFileReferenceMediaResource {
@ -546,7 +546,7 @@ class ChatMessageAnimatedStickerItemNode: ChatMessageItemView {
fitzModifier = EmojiFitzModifier(emoji: fitz)
}
}
if let file = file {
let dimensions = file.dimensions ?? PixelDimensions(width: 512, height: 512)
let fittedSize = isEmoji ? dimensions.cgSize.aspectFilled(CGSize(width: 384.0, height: 384.0)) : dimensions.cgSize.aspectFitted(CGSize(width: 384.0, height: 384.0))

View File

@ -496,8 +496,8 @@ class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePreviewItemNode
self.mainContextSourceNode.contentNode.addSubnode(self.backgroundWallpaperNode)
self.mainContextSourceNode.contentNode.addSubnode(self.backgroundNode)
self.mainContextSourceNode.contentNode.addSubnode(self.contentContainersWrapperNode)
self.mainContextSourceNode.contentNode.addSubnode(self.clippingNode)
self.clippingNode.addSubnode(self.contentContainersWrapperNode)
self.addSubnode(self.messageAccessibilityArea)
self.messageAccessibilityArea.activate = { [weak self] in
@ -2307,6 +2307,11 @@ class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePreviewItemNode
strongSelf.backgroundNode.setType(type: backgroundType, highlighted: strongSelf.highlightedState, graphics: graphics, maskMode: strongSelf.backgroundMaskMode, hasWallpaper: hasWallpaper, transition: transition)
strongSelf.backgroundWallpaperNode.setType(type: backgroundType, theme: item.presentationData.theme, mediaBox: item.context.account.postbox.mediaBox, essentialGraphics: graphics, maskMode: strongSelf.backgroundMaskMode)
strongSelf.shadowNode.setType(type: backgroundType, hasWallpaper: hasWallpaper, graphics: graphics)
if case .none = backgroundType {
strongSelf.clippingNode.clipsToBounds = false
} else {
strongSelf.clippingNode.clipsToBounds = true
}
strongSelf.backgroundType = backgroundType
@ -2631,7 +2636,7 @@ class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePreviewItemNode
containerSupernode = strongSelf.clippingNode
} else {
contextSourceNode = strongSelf.contentContainers.first(where: { $0.contentMessageStableId == contentNodeMessage.stableId })?.sourceNode ?? strongSelf.mainContextSourceNode
containerSupernode = strongSelf.contentContainers.first(where: { $0.contentMessageStableId == contentNodeMessage.stableId })?.sourceNode ?? strongSelf.clippingNode
containerSupernode = strongSelf.contentContainers.first(where: { $0.contentMessageStableId == contentNodeMessage.stableId })?.sourceNode.contentNode ?? strongSelf.clippingNode
}
containerSupernode.addSubnode(contentNode)

View File

@ -213,20 +213,29 @@ final class ChatMessageTransitionNode: ASDisplayNode {
updatedContentAreaInScreenSpace.origin.x = 0.0
updatedContentAreaInScreenSpace.size.width = self.clippingNode.bounds.width
//let timingFunction = CAMediaTimingFunction(controlPoints: 0.33, 0.0, 0.0, 1.0)
let clippingOffset = updatedContentAreaInScreenSpace.minY - self.clippingNode.frame.minY
self.clippingNode.frame = CGRect(origin: CGPoint(x: 0.0, y: updatedContentAreaInScreenSpace.minY), size: self.clippingNode.bounds.size)
self.clippingNode.bounds = CGRect(origin: CGPoint(x: 0.0, y: clippingOffset), size: self.clippingNode.bounds.size)
//self.clippingNode.layer.animateFrame(from: self.clippingNode.frame, to: updatedContentAreaInScreenSpace, duration: verticalDuration, mediaTimingFunction: timingFunction, removeOnCompletion: false)
//self.clippingNode.layer.animateBoundsOriginYAdditive(from: 0.0, to: updatedContentAreaInScreenSpace.minY, duration: verticalDuration, mediaTimingFunction: timingFunction, removeOnCompletion: false)
switch self.source {
case let .textInput(initialTextInput, replyPanel):
self.contextSourceNode.isExtractedToContextPreview = true
self.contextSourceNode.isExtractedToContextPreviewUpdated?(true)
var currentContentRect = self.contextSourceNode.contentRect
let contextSourceNode = self.contextSourceNode
self.contextSourceNode.layoutUpdated = { [weak self, weak contextSourceNode] size in
guard let strongSelf = self, let contextSourceNode = contextSourceNode, strongSelf.contextSourceNode === contextSourceNode else {
return
}
let updatedContentRect = contextSourceNode.contentRect
let deltaY = updatedContentRect.height - currentContentRect.height
if !deltaY.isZero {
currentContentRect = updatedContentRect
strongSelf.addContentOffset(offset: deltaY, itemNode: nil)
}
}
self.containerNode.addSubnode(self.contextSourceNode.contentNode)
let targetAbsoluteRect = self.contextSourceNode.view.convert(self.contextSourceNode.contentRect, to: nil)

View File

@ -54,7 +54,8 @@ final class ChatPinnedMessageTitlePanelNode: ChatTitleAccessoryPanelNode {
private let imageNode: TransformImageNode
private let imageNodeContainer: ASDisplayNode
private let backgroundNode: NavigationBackgroundNode
private let separatorNode: ASDisplayNode
private var currentLayout: (CGFloat, CGFloat, CGFloat)?
@ -91,6 +92,8 @@ final class ChatPinnedMessageTitlePanelNode: ChatTitleAccessoryPanelNode {
self.activityIndicatorContainer.addSubnode(self.activityIndicator)
self.activityIndicator.alpha = 0.0
ContainedViewLayoutTransition.immediate.updateSublayerTransformScale(node: self.activityIndicatorContainer, scale: 0.1)
self.backgroundNode = NavigationBackgroundNode(color: .clear)
self.separatorNode = ASDisplayNode()
self.separatorNode.isLayerBacked = true
@ -119,6 +122,8 @@ final class ChatPinnedMessageTitlePanelNode: ChatTitleAccessoryPanelNode {
self.imageNodeContainer = ASDisplayNode()
super.init()
self.addSubnode(self.backgroundNode)
self.tapButton.highligthedChanged = { [weak self] highlighted in
if let strongSelf = self {
@ -185,6 +190,9 @@ final class ChatPinnedMessageTitlePanelNode: ChatTitleAccessoryPanelNode {
override func updateLayout(width: CGFloat, leftInset: CGFloat, rightInset: CGFloat, transition: ContainedViewLayoutTransition, interfaceState: ChatPresentationInterfaceState) -> CGFloat {
let panelHeight: CGFloat = 50.0
var themeUpdated = false
transition.updateFrame(node: self.backgroundNode, frame: CGRect(origin: CGPoint(), size: CGSize(width: width, height: panelHeight)))
self.backgroundNode.update(size: self.backgroundNode.bounds.size, transition: transition)
self.contextContainer.frame = CGRect(origin: CGPoint(), size: CGSize(width: width, height: panelHeight))
@ -193,8 +201,8 @@ final class ChatPinnedMessageTitlePanelNode: ChatTitleAccessoryPanelNode {
self.theme = interfaceState.theme
self.closeButton.setImage(PresentationResourcesChat.chatInputPanelCloseIconImage(interfaceState.theme), for: [])
self.listButton.setImage(PresentationResourcesChat.chatInputPanelPinnedListIconImage(interfaceState.theme), for: [])
self.backgroundColor = interfaceState.theme.chat.historyNavigation.fillColor
self.separatorNode.backgroundColor = interfaceState.theme.chat.historyNavigation.strokeColor
self.backgroundNode.color = interfaceState.theme.rootController.navigationBar.backgroundColor
self.separatorNode.backgroundColor = interfaceState.theme.rootController.navigationBar.separatorColor
}
if self.statusDisposable == nil, let interfaceInteraction = self.interfaceInteraction, let statuses = interfaceInteraction.statuses {

View File

@ -305,7 +305,7 @@ private final class ChatInfoTitlePanelPeerNearbyInfoNode: ASDisplayNode {
}
final class ChatReportPeerTitlePanelNode: ChatTitleAccessoryPanelNode {
private let backgroundNode: ASDisplayNode
private let backgroundNode: NavigationBackgroundNode
private let separatorNode: ASDisplayNode
private let closeButton: HighlightableButtonNode
@ -317,8 +317,7 @@ final class ChatReportPeerTitlePanelNode: ChatTitleAccessoryPanelNode {
private var peerNearbyInfoNode: ChatInfoTitlePanelPeerNearbyInfoNode?
override init() {
self.backgroundNode = ASDisplayNode()
self.backgroundNode.isLayerBacked = true
self.backgroundNode = NavigationBackgroundNode(color: .clear)
self.separatorNode = ASDisplayNode()
self.separatorNode.isLayerBacked = true
@ -340,8 +339,8 @@ final class ChatReportPeerTitlePanelNode: ChatTitleAccessoryPanelNode {
self.theme = interfaceState.theme
self.closeButton.setImage(PresentationResourcesChat.chatInputPanelEncircledCloseIconImage(interfaceState.theme), for: [])
self.backgroundNode.backgroundColor = interfaceState.theme.chat.historyNavigation.fillColor
self.separatorNode.backgroundColor = interfaceState.theme.chat.historyNavigation.strokeColor
self.backgroundNode.color = interfaceState.theme.rootController.navigationBar.backgroundColor
self.separatorNode.backgroundColor = interfaceState.theme.rootController.navigationBar.separatorColor
}
var panelHeight: CGFloat = 40.0
@ -439,6 +438,7 @@ final class ChatReportPeerTitlePanelNode: ChatTitleAccessoryPanelNode {
}
transition.updateFrame(node: self.backgroundNode, frame: CGRect(origin: CGPoint(x: 0.0, y: 0.0), size: CGSize(width: width, height: panelHeight)))
self.backgroundNode.update(size: self.backgroundNode.bounds.size, transition: transition)
transition.updateFrame(node: self.separatorNode, frame: CGRect(origin: CGPoint(x: 0.0, y: panelHeight - UIScreenPixel), size: CGSize(width: width, height: UIScreenPixel)))

View File

@ -5,6 +5,7 @@ import AsyncDisplayKit
import TelegramPresentationData
final class ChatRequestInProgressTitlePanelNode: ChatTitleAccessoryPanelNode {
private let backgroundNode: NavigationBackgroundNode
private let separatorNode: ASDisplayNode
private let titleNode: ImmediateTextNode
@ -12,6 +13,8 @@ final class ChatRequestInProgressTitlePanelNode: ChatTitleAccessoryPanelNode {
private var strings: PresentationStrings?
override init() {
self.backgroundNode = NavigationBackgroundNode(color: .clear)
self.separatorNode = ASDisplayNode()
self.separatorNode.isLayerBacked = true
@ -19,7 +22,8 @@ final class ChatRequestInProgressTitlePanelNode: ChatTitleAccessoryPanelNode {
self.titleNode.maximumNumberOfLines = 1
super.init()
self.addSubnode(self.backgroundNode)
self.addSubnode(self.titleNode)
self.addSubnode(self.separatorNode)
}
@ -34,11 +38,14 @@ final class ChatRequestInProgressTitlePanelNode: ChatTitleAccessoryPanelNode {
if interfaceState.theme !== self.theme {
self.theme = interfaceState.theme
self.backgroundColor = interfaceState.theme.chat.historyNavigation.fillColor
self.separatorNode.backgroundColor = interfaceState.theme.chat.historyNavigation.strokeColor
self.backgroundNode.color = interfaceState.theme.rootController.navigationBar.backgroundColor
self.separatorNode.backgroundColor = interfaceState.theme.rootController.navigationBar.separatorColor
}
let panelHeight: CGFloat = 40.0
transition.updateFrame(node: self.backgroundNode, frame: CGRect(origin: CGPoint(), size: CGSize(width: width, height: panelHeight)))
self.backgroundNode.update(size: self.backgroundNode.bounds.size, transition: transition)
let titleSize = self.titleNode.updateLayout(CGSize(width: width - leftInset - rightInset, height: 100.0))
transition.updateFrame(node: self.titleNode, frame: CGRect(origin: CGPoint(x: floor((width - titleSize.width) / 2.0), y: floor((panelHeight - titleSize.height) / 2.0)), size: titleSize))

View File

@ -192,12 +192,7 @@ private func textInputBackgroundImage(backgroundColor: UIColor?, inputBackground
}
let image = generateImage(CGSize(width: diameter, height: diameter), rotatedContext: { size, context in
if let backgroundColor = backgroundColor {
context.setFillColor(backgroundColor.cgColor)
context.fill(CGRect(x: 0.0, y: 0.0, width: diameter, height: diameter))
} else {
context.clear(CGRect(x: 0.0, y: 0.0, width: diameter, height: diameter))
}
context.clear(CGRect(x: 0.0, y: 0.0, width: diameter, height: diameter))
if let inputBackgroundColor = inputBackgroundColor {
context.setBlendMode(.normal)
@ -235,6 +230,7 @@ class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDelegate {
var textPlaceholderNode: ImmediateTextNode
var contextPlaceholderNode: TextNode?
var slowmodePlaceholderNode: ChatTextInputSlowmodePlaceholderNode?
let textInputContainerBackgroundNode: ASImageNode
let textInputContainer: ASDisplayNode
var textInputNode: EditableTextNode?
@ -426,10 +422,14 @@ class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDelegate {
init(presentationInterfaceState: ChatPresentationInterfaceState, presentController: @escaping (ViewController) -> Void) {
self.presentationInterfaceState = presentationInterfaceState
self.textInputContainerBackgroundNode = ASImageNode()
self.textInputContainerBackgroundNode.isUserInteractionEnabled = false
self.textInputContainerBackgroundNode.displaysAsynchronously = false
self.textInputContainer = ASDisplayNode()
self.textInputContainer.addSubnode(self.textInputContainerBackgroundNode)
self.textInputContainer.clipsToBounds = true
self.textInputContainer.backgroundColor = presentationInterfaceState.theme.chat.inputPanel.inputBackgroundColor
self.textInputBackgroundNode = ASImageNode()
self.textInputBackgroundNode.displaysAsynchronously = false
@ -794,11 +794,8 @@ class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDelegate {
textInputNode.keyboardAppearance = keyboardAppearance
}
self.textInputContainer.backgroundColor = interfaceState.theme.chat.inputPanel.inputBackgroundColor
self.theme = interfaceState.theme
if isEditingMedia {
self.attachmentButton.setImage(PresentationResourcesChat.chatInputPanelEditAttachmentButtonImage(interfaceState.theme), for: [])
} else {
@ -819,6 +816,7 @@ class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDelegate {
self.textInputBackgroundNode.image = textInputBackgroundImage(backgroundColor: backgroundColor, inputBackgroundColor: nil, strokeColor: interfaceState.theme.chat.inputPanel.inputStrokeColor, diameter: minimalInputHeight)
self.transparentTextInputBackgroundImage = textInputBackgroundImage(backgroundColor: nil, inputBackgroundColor: interfaceState.theme.chat.inputPanel.inputBackgroundColor, strokeColor: interfaceState.theme.chat.inputPanel.inputStrokeColor, diameter: minimalInputHeight)
self.textInputContainerBackgroundNode.image = generateStretchableFilledCircleImage(diameter: minimalInputHeight, color: interfaceState.theme.chat.inputPanel.inputBackgroundColor)
self.searchLayoutClearImageNode.image = PresentationResourcesChat.chatInputTextFieldClearImage(interfaceState.theme)
@ -1307,6 +1305,7 @@ class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDelegate {
let textInputFrame = CGRect(x: leftInset + textFieldInsets.left, y: textFieldInsets.top, width: baseWidth - textFieldInsets.left - textFieldInsets.right + textInputBackgroundWidthOffset, height: panelHeight - textFieldInsets.top - textFieldInsets.bottom)
transition.updateFrame(node: self.textInputContainer, frame: textInputFrame)
transition.updateFrame(node: self.textInputContainerBackgroundNode, frame: CGRect(origin: CGPoint(), size: textInputFrame.size))
transition.updateAlpha(node: self.textInputContainer, alpha: audioRecordingItemsAlpha)
if let textInputNode = self.textInputNode {

View File

@ -4,6 +4,7 @@ import Display
import AsyncDisplayKit
final class ChatToastAlertPanelNode: ChatTitleAccessoryPanelNode {
private let backgroundNode: NavigationBackgroundNode
private let separatorNode: ASDisplayNode
private let titleNode: ImmediateTextNode
@ -25,6 +26,8 @@ final class ChatToastAlertPanelNode: ChatTitleAccessoryPanelNode {
}
override init() {
self.backgroundNode = NavigationBackgroundNode(color: .clear)
self.separatorNode = ASDisplayNode()
self.separatorNode.isLayerBacked = true
@ -34,7 +37,8 @@ final class ChatToastAlertPanelNode: ChatTitleAccessoryPanelNode {
self.titleNode.insets = UIEdgeInsets(top: 2.0, left: 2.0, bottom: 2.0, right: 2.0)
super.init()
self.addSubnode(self.backgroundNode)
self.addSubnode(self.titleNode)
self.addSubnode(self.separatorNode)
}
@ -42,8 +46,11 @@ final class ChatToastAlertPanelNode: ChatTitleAccessoryPanelNode {
override func updateLayout(width: CGFloat, leftInset: CGFloat, rightInset: CGFloat, transition: ContainedViewLayoutTransition, interfaceState: ChatPresentationInterfaceState) -> CGFloat {
let panelHeight: CGFloat = 40.0
transition.updateFrame(node: self.backgroundNode, frame: CGRect(origin: CGPoint(), size: CGSize(width: width, height: panelHeight)))
self.backgroundNode.update(size: self.backgroundNode.bounds.size, transition: transition)
self.textColor = interfaceState.theme.rootController.navigationBar.primaryTextColor
self.backgroundColor = interfaceState.theme.chat.historyNavigation.fillColor
self.backgroundNode.color = interfaceState.theme.chat.historyNavigation.fillColor
self.separatorNode.backgroundColor = interfaceState.theme.chat.historyNavigation.strokeColor
transition.updateFrame(node: self.separatorNode, frame: CGRect(origin: CGPoint(x: 0.0, y: panelHeight - UIScreenPixel), size: CGSize(width: width, height: UIScreenPixel)))

View File

@ -243,7 +243,10 @@ tgcalls::VideoCaptureInterfaceObject *GetVideoCaptureAssumingSameThread(tgcalls:
}
-(void)setOnFatalError:(dispatch_block_t _Nullable)onError {
#if TARGET_OS_IOS
#else
_interface->setOnFatalError(onError);
#endif
}
- (void)makeOutgoingVideoView:(void (^_Nonnull)(UIView<OngoingCallThreadLocalContextWebrtcVideoView> * _Nullable))completion {
@ -968,7 +971,7 @@ private:
std::vector<tgcalls::VideoCodecName> videoCodecPreferences;
videoCodecPreferences.push_back(tgcalls::VideoCodecName::VP8);
videoCodecPreferences.push_back(tgcalls::VideoCodecName::VP9);
//videoCodecPreferences.push_back(tgcalls::VideoCodecName::VP9);
int minOutgoingVideoBitrateKbit = 100;
#if DEBUG

@ -1 +1 @@
Subproject commit 94a9c7b4e49c943d1ca108e35779739ad99d695a
Subproject commit bffd2b41310e773ef4d7560fbf6703e5fefb6020