Wallpaper updates

This commit is contained in:
Ali 2021-05-11 23:31:03 +04:00
parent f4df115850
commit 6854173dae
34 changed files with 356 additions and 898 deletions

View File

@ -61,26 +61,35 @@ public final class AnimatedNavigationStripeNode: ASDisplayNode {
private let foregroundLineNode: ASImageNode
private var backgroundLineNodes: [Int: BackgroundLineNode] = [:]
private var removingBackgroundLineNodes: [BackgroundLineNode] = []
private let maskContainerNode: ASDisplayNode
private let topShadowNode: ASImageNode
private let bottomShadowNode: ASImageNode
private let middleShadowNode: ASDisplayNode
private var currentForegroundImage: UIImage?
private var currentBackgroundImage: UIImage?
private var currentClearBackgroundImage: UIImage?
override public init() {
self.maskContainerNode = ASDisplayNode()
self.foregroundLineNode = ASImageNode()
self.topShadowNode = ASImageNode()
self.bottomShadowNode = ASImageNode()
self.middleShadowNode = ASDisplayNode()
self.middleShadowNode.backgroundColor = .white
super.init()
self.clipsToBounds = true
self.addSubnode(self.maskContainerNode)
self.addSubnode(self.foregroundLineNode)
self.addSubnode(self.topShadowNode)
self.addSubnode(self.bottomShadowNode)
self.maskContainerNode.addSubnode(self.topShadowNode)
self.maskContainerNode.addSubnode(self.bottomShadowNode)
self.maskContainerNode.addSubnode(self.middleShadowNode)
self.layer.mask = self.maskContainerNode.layer
}
public func update(colors: Colors, configuration: Configuration, transition: ContainedViewLayoutTransition) {
@ -123,7 +132,7 @@ public final class AnimatedNavigationStripeNode: ASDisplayNode {
context.clear(CGRect(origin: CGPoint(), size: size))
var locations: [CGFloat] = [1.0, 0.0]
let colors: [CGColor] = [colors.clearBackground.cgColor, colors.clearBackground.withAlphaComponent(0.0).cgColor]
let colors: [CGColor] = [UIColor.white.withAlphaComponent(0.0).cgColor, UIColor.white.cgColor]
let colorSpace = CGColorSpaceCreateDeviceRGB()
let gradient = CGGradient(colorsSpace: colorSpace, colors: colors as CFArray, locations: &locations)!
@ -135,7 +144,7 @@ public final class AnimatedNavigationStripeNode: ASDisplayNode {
context.clear(CGRect(origin: CGPoint(), size: size))
var locations: [CGFloat] = [1.0, 0.0]
let colors: [CGColor] = [colors.clearBackground.cgColor, colors.clearBackground.withAlphaComponent(0.0).cgColor]
let colors: [CGColor] = [UIColor.white.withAlphaComponent(0.0).cgColor, UIColor.white.cgColor]
let colorSpace = CGColorSpaceCreateDeviceRGB()
let gradient = CGGradient(colorsSpace: colorSpace, colors: colors as CFArray, locations: &locations)!
@ -161,6 +170,8 @@ public final class AnimatedNavigationStripeNode: ASDisplayNode {
transition.updateFrame(node: self.topShadowNode, frame: CGRect(origin: CGPoint(), size: CGSize(width: 2.0, height: defaultVerticalInset)))
transition.updateFrame(node: self.bottomShadowNode, frame: CGRect(origin: CGPoint(x: 0.0, y: configuration.height - defaultVerticalInset), size: CGSize(width: 2.0, height: defaultVerticalInset)))
transition.updateFrame(node: self.middleShadowNode, frame: CGRect(origin: CGPoint(x: 0.0, y: defaultVerticalInset), size: CGSize(width: 2.0, height: configuration.height - defaultVerticalInset * 2.0)))
transition.updateFrame(node: self.maskContainerNode, frame: CGRect(origin: CGPoint(), size: CGSize(width: 2.0, height: configuration.height)))
let availableVerticalHeight: CGFloat = configuration.height - defaultVerticalInset * 2.0
@ -214,7 +225,7 @@ public final class AnimatedNavigationStripeNode: ASDisplayNode {
itemNode.overlayNode.image = self.currentClearBackgroundImage
self.backgroundLineNodes[index] = itemNode
self.insertSubnode(itemNode.lineNode, belowSubnode: self.foregroundLineNode)
self.insertSubnode(itemNode.overlayNode, belowSubnode: self.topShadowNode)
self.topShadowNode.supernode?.insertSubnode(itemNode.overlayNode, belowSubnode: self.topShadowNode)
backgroundItemNodesToOffset.append(itemNode)
}
itemNodeTransition.updateFrame(node: itemNode.lineNode, frame: itemFrame, beginWithCurrentState: true)

View File

@ -148,19 +148,30 @@ public final class NavigationBackgroundNode: ASDisplayNode {
if self.color.lightness > 0.6 {
if #available(iOS 13.0, *) {
self.effectView = UIVisualEffectView(effect: UIBlurEffect(style: .systemMaterialLight))
self.effectView = UIVisualEffectView(effect: UIBlurEffect(style: .systemUltraThinMaterialLight))
} else {
self.effectView = UIVisualEffectView(effect: UIBlurEffect(style: .light))
}
} else {
if #available(iOS 13.0, *) {
self.effectView = UIVisualEffectView(effect: UIBlurEffect(style: .systemMaterialDark))
self.effectView = UIVisualEffectView(effect: UIBlurEffect(style: .systemUltraThinMaterialDark))
} else {
self.effectView = UIVisualEffectView(effect: UIBlurEffect(style: .dark))
}
}
if let effectView = self.effectView {
if let sublayer = effectView.layer.sublayers?[0], let filters = sublayer.filters {
sublayer.filters = filters.filter { filter in
guard let filter = filter as? NSObject else {
return true
}
if String(describing: filter) != "gaussianBlur" {
return false
}
return true
}
}
effectView.frame = self.bounds
self.view.insertSubview(effectView, at: 0)
}
@ -171,9 +182,15 @@ public final class NavigationBackgroundNode: ASDisplayNode {
}
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))
let contentFrame = CGRect(origin: CGPoint(), size: size)
transition.updateFrame(node: self.backgroundNode, frame: contentFrame)
if let effectView = self.effectView, effectView.frame != contentFrame {
transition.updateFrame(layer: effectView.layer, frame: contentFrame)
if let sublayers = effectView.layer.sublayers {
for sublayer in sublayers {
transition.updateFrame(layer: sublayer, frame: contentFrame)
}
}
}
}
}
@ -185,7 +202,7 @@ open class NavigationBar: ASDisplayNode {
var presentationData: NavigationBarPresentationData
private var validLayout: (CGSize, CGFloat, CGFloat, CGFloat, CGFloat, Bool)?
private var validLayout: (CGSize, CGFloat, CGFloat, CGFloat, CGFloat, CGFloat, Bool)?
private var requestedLayout: Bool = false
var requestContainerLayout: (ContainedViewLayoutTransition) -> Void = { _ in }
@ -911,19 +928,22 @@ open class NavigationBar: ASDisplayNode {
if let validLayout = self.validLayout, self.requestedLayout {
self.requestedLayout = false
self.updateLayout(size: validLayout.0, defaultHeight: validLayout.1, additionalHeight: validLayout.2, leftInset: validLayout.3, rightInset: validLayout.4, appearsHidden: validLayout.5, transition: .immediate)
self.updateLayout(size: validLayout.0, defaultHeight: validLayout.1, additionalHeight: validLayout.2, additionalBackgroundHeight: validLayout.3, leftInset: validLayout.4, rightInset: validLayout.5, appearsHidden: validLayout.6, transition: .immediate)
}
}
func updateLayout(size: CGSize, defaultHeight: CGFloat, additionalHeight: CGFloat, leftInset: CGFloat, rightInset: CGFloat, appearsHidden: Bool, transition: ContainedViewLayoutTransition) {
func updateLayout(size: CGSize, defaultHeight: CGFloat, additionalHeight: CGFloat, additionalBackgroundHeight: CGFloat, leftInset: CGFloat, rightInset: CGFloat, appearsHidden: Bool, transition: ContainedViewLayoutTransition) {
if self.layoutSuspended {
return
}
self.validLayout = (size, defaultHeight, additionalHeight, leftInset, rightInset, appearsHidden)
self.validLayout = (size, defaultHeight, additionalHeight, additionalBackgroundHeight, leftInset, rightInset, appearsHidden)
transition.updateFrame(node: self.backgroundNode, frame: CGRect(origin: CGPoint(), size: size))
self.backgroundNode.update(size: size, transition: transition)
let backgroundFrame = CGRect(origin: CGPoint(), size: CGSize(width: size.width, height: size.height + additionalBackgroundHeight))
if self.backgroundNode.frame != backgroundFrame {
transition.updateFrame(node: self.backgroundNode, frame: backgroundFrame)
self.backgroundNode.update(size: backgroundFrame.size, transition: transition)
}
let apparentAdditionalHeight: CGFloat = self.secondaryContentNode != nil ? NavigationBar.defaultSecondaryContentHeight : 0.0
@ -1164,7 +1184,7 @@ open class NavigationBar: ASDisplayNode {
let node = NavigationButtonNode()
node.updateManualText(self.backButtonNode.manualText)
node.color = accentColor
if let (size, defaultHeight, _, _, _, _) = self.validLayout {
if let (size, defaultHeight, _, _, _, _, _) = self.validLayout {
let _ = node.updateLayout(constrainedSize: CGSize(width: size.width, height: defaultHeight))
node.frame = self.backButtonNode.frame
}
@ -1187,7 +1207,7 @@ open class NavigationBar: ASDisplayNode {
}
node.updateItems(items)
node.color = accentColor
if let (size, defaultHeight, _, _, _, _) = self.validLayout {
if let (size, defaultHeight, _, _, _, _, _) = self.validLayout {
let _ = node.updateLayout(constrainedSize: CGSize(width: size.width, height: defaultHeight))
node.frame = self.backButtonNode.frame
}

View File

@ -373,8 +373,12 @@ public enum TabBarItemContextActionType {
deinit {
}
open func updateNavigationBarLayout(_ layout: ContainerViewLayout, transition: ContainedViewLayoutTransition) {
self.applyNavigationBarLayout(layout, additionalBackgroundHeight: 0.0, transition: transition)
}
private func updateNavigationBarLayout(_ layout: ContainerViewLayout, transition: ContainedViewLayoutTransition) {
public func applyNavigationBarLayout(_ layout: ContainerViewLayout, additionalBackgroundHeight: CGFloat, transition: ContainedViewLayoutTransition) {
let statusBarHeight: CGFloat = layout.statusBarHeight ?? 0.0
var defaultNavigationBarHeight: CGFloat
if self._presentedInModal {
@ -406,7 +410,7 @@ public enum TabBarItemContextActionType {
if let _ = navigationBar.contentNode, let _ = navigationBar.secondaryContentNode, !self.displayNavigationBar {
navigationBarFrame.origin.y += NavigationBar.defaultSecondaryContentHeight
}
navigationBar.updateLayout(size: navigationBarFrame.size, defaultHeight: defaultNavigationBarHeight, additionalHeight: 0.0, leftInset: layout.safeInsets.left, rightInset: layout.safeInsets.right, appearsHidden: !self.displayNavigationBar, transition: transition)
navigationBar.updateLayout(size: navigationBarFrame.size, defaultHeight: defaultNavigationBarHeight, additionalHeight: 0.0, additionalBackgroundHeight: additionalBackgroundHeight, leftInset: layout.safeInsets.left, rightInset: layout.safeInsets.right, appearsHidden: !self.displayNavigationBar, transition: transition)
if !transition.isAnimated {
navigationBar.layer.cancelAnimationsRecursive(key: "bounds")
navigationBar.layer.cancelAnimationsRecursive(key: "position")

View File

@ -1,153 +0,0 @@
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

@ -3,6 +3,17 @@ 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
}
private func gatherPositions(_ list: [CGPoint]) -> [CGPoint] {
var result: [CGPoint] = []
for i in 0 ..< list.count / 2 {

View File

@ -89,6 +89,7 @@ swift_library(
"//submodules/WidgetSetupScreen:WidgetSetupScreen",
"//submodules/UIKitRuntimeUtils:UIKitRuntimeUtils",
"//submodules/DebugSettingsUI:DebugSettingsUI",
"//submodules/WallpaperBackgroundNode:WallpaperBackgroundNode",
],
visibility = [
"//visibility:public",

View File

@ -13,6 +13,7 @@ import ChatListUI
import WallpaperResources
import LegacyComponents
import ItemListUI
import WallpaperBackgroundNode
private func generateMaskImage(color: UIColor) -> UIImage? {
return generateImage(CGSize(width: 1.0, height: 80.0), opaque: false, rotatedContext: { size, context in
@ -70,10 +71,7 @@ private final class BubbleSettingsControllerNode: ASDisplayNode, UIScrollViewDel
self.messagesContainerNode.transform = CATransform3DMakeScale(1.0, -1.0, 1.0)
self.chatBackgroundNode.image = chatControllerBackgroundImage(theme: self.presentationData.theme, wallpaper: self.presentationData.chatWallpaper, mediaBox: context.sharedContext.accountManager.mediaBox, knockoutMode: false)
self.chatBackgroundNode.motionEnabled = self.presentationData.chatWallpaper.settings?.motion ?? false
if case .gradient = self.presentationData.chatWallpaper {
self.chatBackgroundNode.imageContentMode = .scaleToFill
}
self.chatBackgroundNode.update(wallpaper: self.presentationData.chatWallpaper)
self.toolbarNode = BubbleSettingsToolbarNode(presentationThemeSettings: self.presentationThemeSettings, presentationData: self.presentationData)

View File

@ -13,6 +13,7 @@ import ChatListUI
import WallpaperResources
import LegacyComponents
import ItemListUI
import WallpaperBackgroundNode
private func generateMaskImage(color: UIColor) -> UIImage? {
return generateImage(CGSize(width: 1.0, height: 80.0), opaque: false, rotatedContext: { size, context in
@ -82,10 +83,7 @@ private final class TextSizeSelectionControllerNode: ASDisplayNode, UIScrollView
self.messagesContainerNode.transform = CATransform3DMakeScale(1.0, -1.0, 1.0)
self.chatBackgroundNode.image = chatControllerBackgroundImage(theme: self.presentationData.theme, wallpaper: self.presentationData.chatWallpaper, mediaBox: context.sharedContext.accountManager.mediaBox, knockoutMode: false)
self.chatBackgroundNode.motionEnabled = self.presentationData.chatWallpaper.settings?.motion ?? false
if case .gradient = self.presentationData.chatWallpaper {
self.chatBackgroundNode.imageContentMode = .scaleToFill
}
self.chatBackgroundNode.update(wallpaper: self.presentationData.chatWallpaper)
self.toolbarNode = TextSelectionToolbarNode(presentationThemeSettings: self.presentationThemeSettings, presentationData: self.presentationData)

View File

@ -10,6 +10,7 @@ import TelegramPresentationData
import AccountContext
import RadialStatusNode
import WallpaperResources
import GradientBackground
private func whiteColorImage(theme: PresentationTheme, color: UIColor) -> Signal<(TransformImageArguments) -> DrawingContext?, NoError> {
return .single({ arguments in
@ -36,6 +37,7 @@ final class SettingsThemeWallpaperNode: ASDisplayNode {
let buttonNode = HighlightTrackingButtonNode()
let backgroundNode = ASDisplayNode()
let imageNode = TransformImageNode()
private var gradientNode: GradientBackgroundNode?
private let statusNode: RadialStatusNode
var pressed: (() -> Void)?
@ -71,6 +73,22 @@ final class SettingsThemeWallpaperNode: ASDisplayNode {
self.buttonNode.frame = CGRect(origin: CGPoint(), size: size)
self.backgroundNode.frame = CGRect(origin: CGPoint(), size: size)
self.imageNode.frame = CGRect(origin: CGPoint(), size: size)
if case .builtin = wallpaper {
if self.gradientNode == nil {
let gradientNode = createGradientBackgroundNode()
self.gradientNode = gradientNode
self.addSubnode(gradientNode)
}
} else if let gradientNode = self.gradientNode {
self.gradientNode = nil
gradientNode.removeFromSupernode()
}
if let gradientNode = self.gradientNode {
gradientNode.frame = CGRect(origin: CGPoint(), size: size)
gradientNode.updateLayout(size: size, transition: .immediate)
}
let state: RadialStatusNodeState = selected ? .check(.white) : .none
self.statusNode.transitionToState(state, animated: false, completion: {})

View File

@ -12,6 +12,7 @@ import AccountContext
import ChatListUI
import WallpaperResources
import LegacyComponents
import WallpaperBackgroundNode
private func generateMaskImage(color: UIColor) -> UIImage? {
return generateImage(CGSize(width: 1.0, height: 80.0), opaque: false, rotatedContext: { size, context in
@ -110,10 +111,7 @@ final class ThemePreviewControllerNode: ASDisplayNode, UIScrollViewDelegate {
if self.instantChatBackgroundNode.image != nil {
self.ready.set(.single(true))
}
if case .gradient = wallpaper {
self.instantChatBackgroundNode.imageContentMode = .scaleToFill
}
self.instantChatBackgroundNode.motionEnabled = previewTheme.chat.defaultWallpaper.settings?.motion ?? false
self.instantChatBackgroundNode.update(wallpaper: wallpaper)
self.instantChatBackgroundNode.view.contentMode = .scaleAspectFill
self.remoteChatBackgroundNode = TransformImageNode()

View File

@ -11,6 +11,7 @@ import TelegramUIPreferences
import ItemListUI
import PresentationDataUtils
import AccountContext
import WallpaperBackgroundNode
struct ChatPreviewMessageItem: Equatable {
static func == (lhs: ChatPreviewMessageItem, rhs: ChatPreviewMessageItem) -> Bool {
@ -95,7 +96,7 @@ class ThemeSettingsChatPreviewItem: ListViewItem, ItemListItem {
}
class ThemeSettingsChatPreviewItemNode: ListViewItemNode {
private let backgroundNode: ASImageNode
private let backgroundNode: WallpaperBackgroundNode
private let topStripeNode: ASDisplayNode
private let bottomStripeNode: ASDisplayNode
private let maskNode: ASImageNode
@ -109,11 +110,7 @@ class ThemeSettingsChatPreviewItemNode: ListViewItemNode {
private let disposable = MetaDisposable()
init() {
self.backgroundNode = ASImageNode()
self.backgroundNode.isLayerBacked = true
self.backgroundNode.displaysAsynchronously = false
self.backgroundNode.displayWithoutProcessing = true
self.backgroundNode.contentMode = .scaleAspectFill
self.backgroundNode = WallpaperBackgroundNode()
self.topStripeNode = ASDisplayNode()
self.topStripeNode.isLayerBacked = true
@ -287,6 +284,8 @@ class ThemeSettingsChatPreviewItemNode: ListViewItemNode {
let backgroundFrame = CGRect(origin: CGPoint(x: 0.0, y: -min(insets.top, separatorHeight)), size: CGSize(width: params.width, height: contentSize.height + min(insets.top, separatorHeight) + min(insets.bottom, separatorHeight)))
strongSelf.backgroundNode.frame = backgroundFrame.insetBy(dx: 0.0, dy: -100.0)
strongSelf.backgroundNode.update(wallpaper: item.wallpaper)
strongSelf.backgroundNode.updateLayout(size: strongSelf.backgroundNode.bounds.size, transition: .immediate)
strongSelf.maskNode.frame = backgroundFrame.insetBy(dx: params.leftInset, dy: 0.0)
strongSelf.topStripeNode.frame = CGRect(origin: CGPoint(x: 0.0, y: -min(insets.top, separatorHeight)), size: CGSize(width: layoutSize.width, height: separatorHeight))
strongSelf.bottomStripeNode.frame = CGRect(origin: CGPoint(x: bottomStripeInset, y: contentSize.height + bottomStripeOffset), size: CGSize(width: layoutSize.width - bottomStripeInset, height: separatorHeight))

View File

@ -500,7 +500,12 @@ public class WallpaperGalleryController: ViewController {
applyWallpaper(wallpaper)
})
} else {
applyWallpaper(wallpaper)
var updatedWallpaper = wallpaper
if var settings = wallpaper.settings {
settings.motion = options.contains(.motion)
updatedWallpaper = updatedWallpaper.withUpdatedSettings(settings)
}
applyWallpaper(updatedWallpaper)
}
default:
break

View File

@ -18,6 +18,7 @@ import GalleryUI
import LocalMediaResources
import WallpaperResources
import AppBundle
import WallpaperBackgroundNode
struct WallpaperGalleryItemArguments {
let colorPreview: Bool
@ -90,6 +91,7 @@ final class WallpaperGalleryItemNode: GalleryItemNode {
let wrapperNode: ASDisplayNode
let imageNode: TransformImageNode
let nativeNode: WallpaperBackgroundNode
private let statusNode: RadialStatusNode
private let blurredNode: BlurredImageNode
let cropNode: WallpaperCropNode
@ -122,6 +124,7 @@ final class WallpaperGalleryItemNode: GalleryItemNode {
self.wrapperNode = ASDisplayNode()
self.imageNode = TransformImageNode()
self.imageNode.contentAnimations = .subsequentUpdates
self.nativeNode = WallpaperBackgroundNode()
self.cropNode = WallpaperCropNode()
self.statusNode = RadialStatusNode(backgroundNodeColor: UIColor(white: 0.0, alpha: 0.6))
self.statusNode.frame = CGRect(x: 0.0, y: 0.0, width: progressDiameter, height: progressDiameter)
@ -471,9 +474,22 @@ final class WallpaperGalleryItemNode: GalleryItemNode {
if self.cropNode.supernode == nil {
self.imageNode.contentMode = .scaleAspectFill
self.wrapperNode.addSubnode(self.imageNode)
self.wrapperNode.addSubnode(self.nativeNode)
} else {
self.imageNode.contentMode = .scaleToFill
}
switch entry {
case let .wallpaper(wallpaper, _):
if case .builtin = wallpaper {
self.nativeNode.isHidden = false
self.nativeNode.update(wallpaper: wallpaper)
} else {
self.nativeNode.isHidden = true
}
default:
self.nativeNode.isHidden = true
}
self.imageNode.setSignal(signal, dispatchOnDisplayLink: false)
self.imageNode.asyncLayout()(TransformImageArguments(corners: ImageCorners(), imageSize: displaySize, boundingSize: displaySize, intrinsicInsets: UIEdgeInsets(), custom: patternArguments))()
@ -660,6 +676,10 @@ final class WallpaperGalleryItemNode: GalleryItemNode {
}
func setMotionEnabled(_ enabled: Bool, animated: Bool) {
if let entry = self.entry, case let .wallpaper(wallpaper, _) = entry, case .builtin = wallpaper {
return
}
if enabled {
let horizontal = UIInterpolatingMotionEffect(keyPath: "center.x", type: .tiltAlongHorizontalAxis)
horizontal.minimumRelativeValue = motionAmount
@ -890,6 +910,8 @@ final class WallpaperGalleryItemNode: GalleryItemNode {
if self.cropNode.supernode == nil {
self.imageNode.frame = self.wrapperNode.bounds
self.nativeNode.frame = self.wrapperNode.bounds
self.nativeNode.updateLayout(size: self.nativeNode.bounds.size, transition: .immediate)
self.blurredNode.frame = self.imageNode.frame
} else {
self.cropNode.frame = self.wrapperNode.bounds

View File

@ -27,6 +27,7 @@ swift_library(
"//submodules/TelegramIntents:TelegramIntents",
"//submodules/AccountContext:AccountContext",
"//submodules/SegmentedControlNode:SegmentedControlNode",
"//submodules/WallpaperBackgroundNode:WallpaperBackgroundNode",
],
visibility = [
"//visibility:public",

View File

@ -16,6 +16,7 @@ import UrlEscaping
import StickerResources
import SaveToCameraRoll
import TelegramStringFormatting
import WallpaperBackgroundNode
public struct ShareControllerAction {
let title: String

View File

@ -138,7 +138,7 @@ final class StickerPreviewControllerNode: ASDisplayNode, UIScrollViewDelegate {
self.textNode.attributedText = NSAttributedString(string: text, font: Font.regular(32.0), textColor: .black)
break
}
self.imageNode.setSignal(chatMessageSticker(account: context.account, file: item.file, small: false))
self.imageNode.setSignal(chatMessageSticker(account: context.account, file: item.file, small: false, onlyFullSize: false))
if let (layout, navigationBarHeight) = self.containerLayout {
self.containerLayoutUpdated(layout, navigationBarHeight: navigationBarHeight, transition: .immediate)

View File

@ -402,7 +402,7 @@ public func chatMessageSticker(postbox: Postbox, file: TelegramMediaFile, small:
return nil
}
if file.immediateThumbnailData != nil && fullSizeData == nil {
if file.immediateThumbnailData != nil && thumbnailData == nil && fullSizeData == nil {
return nil
}

View File

@ -1,12 +1,12 @@
import Postbox
public struct WallpaperSettings: PostboxCoding, Equatable {
public let blur: Bool
public let motion: Bool
public let color: UInt32?
public let bottomColor: UInt32?
public let intensity: Int32?
public let rotation: Int32?
public var blur: Bool
public var motion: Bool
public var color: UInt32?
public var bottomColor: UInt32?
public var intensity: Int32?
public var rotation: Int32?
public init(blur: Bool = false, motion: Bool = false, color: UInt32? = nil, bottomColor: UInt32? = nil, intensity: Int32? = nil, rotation: Int32? = nil) {
self.blur = blur

View File

@ -197,7 +197,7 @@ public func messageBubbleImage(maxCornerRadius: CGFloat, minCornerRadius: CGFloa
borderWidth = UIScreenPixel + innerExtension
borderOffset = -innerExtension / 2.0 + UIScreenPixel / 2.0
} else {
borderWidth = UIScreenPixel * 2.0 + innerExtension
borderWidth = UIScreenPixel + innerExtension
borderOffset = -innerExtension / 2.0 + UIScreenPixel * 2.0 / 2.0
}
context.setLineWidth(borderWidth)

View File

@ -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: 0x1a1a1a, alpha: 0.5),
backgroundColor: UIColor(rgb: 0x1c1c1d, alpha: 0.7).withMultipliedBrightnessBy(1.1),
separatorColor: UIColor(rgb: 0x3d3d40),
badgeBackgroundColor: UIColor(rgb: 0xffffff),
badgeStrokeColor: UIColor(rgb: 0x1c1c1d),

View File

@ -337,18 +337,6 @@ public func makeDefaultDayPresentationTheme(extendingThemeReference: Presentatio
backgroundColors: PresentationThemeGradientColors(topColor: UIColor(rgb: 0x46739e), bottomColor: UIColor(rgb: 0x2a5982)),
buttonColor: .clear
)
let rootTabBar = PresentationThemeRootTabBar(
backgroundColor: UIColor(rgb: 0xffffff, alpha: 0.5),
separatorColor: UIColor(rgb: 0xa3a3a3),
iconColor: UIColor(rgb: 0x959595),
selectedIconColor: UIColor(rgb: 0x007ee5),
textColor: UIColor(rgb: 0x959595),
selectedTextColor: UIColor(rgb: 0x007ee5),
badgeBackgroundColor: UIColor(rgb: 0xff3b30),
badgeStrokeColor: UIColor(rgb: 0xff3b30),
badgeTextColor: UIColor(rgb: 0xffffff)
)
let rootNavigationBar = PresentationThemeRootNavigationBar(
buttonColor: UIColor(rgb: 0x007ee5),
@ -357,7 +345,7 @@ public func makeDefaultDayPresentationTheme(extendingThemeReference: Presentatio
secondaryTextColor: UIColor(rgb: 0x787878),
controlColor: UIColor(rgb: 0x7e8791),
accentTextColor: UIColor(rgb: 0x007ee5),
backgroundColor: UIColor(rgb: 0xffffff, alpha: 0.5),
backgroundColor: UIColor(rgb: 0xffffff, alpha: 0.75),
separatorColor: UIColor(rgb: 0xc8c7cc),
badgeBackgroundColor: UIColor(rgb: 0xff3b30),
badgeStrokeColor: UIColor(rgb: 0xff3b30),
@ -369,6 +357,18 @@ public func makeDefaultDayPresentationTheme(extendingThemeReference: Presentatio
clearButtonBackgroundColor: UIColor(rgb: 0xE3E3E3, alpha: 0.78),
clearButtonForegroundColor: UIColor(rgb: 0x7f7f7f)
)
let rootTabBar = PresentationThemeRootTabBar(
backgroundColor: rootNavigationBar.backgroundColor,
separatorColor: UIColor(rgb: 0xa3a3a3),
iconColor: UIColor(rgb: 0x959595),
selectedIconColor: UIColor(rgb: 0x007ee5),
textColor: UIColor(rgb: 0x959595),
selectedTextColor: UIColor(rgb: 0x007ee5),
badgeBackgroundColor: UIColor(rgb: 0xff3b30),
badgeStrokeColor: UIColor(rgb: 0xff3b30),
badgeTextColor: UIColor(rgb: 0xffffff)
)
let navigationSearchBar = PresentationThemeNavigationSearchBar(
backgroundColor: UIColor(rgb: 0xffffff),
@ -497,7 +497,12 @@ public func makeDefaultDayPresentationTheme(extendingThemeReference: Presentatio
onlineDotColor: UIColor(rgb: 0x4cc91f)
)
let bubbleStrokeColor = serviceBackgroundColor.withMultiplied(hue: 0.999, saturation: 1.667, brightness: 1.1).withAlphaComponent(0.2)
let bubbleStrokeColor: UIColor
if day {
bubbleStrokeColor = serviceBackgroundColor.withMultiplied(hue: 0.999, saturation: 1.667, brightness: 1.1).withAlphaComponent(0.2)
} else {
bubbleStrokeColor = UIColor(white: 0.0, alpha: 0.2)
}
let message = PresentationThemeChatMessage(
incoming: PresentationThemePartedColors(
@ -655,8 +660,8 @@ public func makeDefaultDayPresentationTheme(extendingThemeReference: Presentatio
)
let inputPanel = PresentationThemeChatInputPanel(
panelBackgroundColor: UIColor(rgb: 0xffffff, alpha: 0.5),
panelBackgroundColorNoWallpaper: UIColor(rgb: 0xffffff, alpha: 0.5),
panelBackgroundColor: rootNavigationBar.backgroundColor,
panelBackgroundColorNoWallpaper: rootNavigationBar.backgroundColor,
panelSeparatorColor: UIColor(rgb: 0xb2b2b2),
panelControlAccentColor: UIColor(rgb: 0x007ee5),
panelControlColor: UIColor(rgb: 0x858e99),

View File

@ -222,6 +222,7 @@ swift_library(
"//submodules/DebugSettingsUI:DebugSettingsUI",
"//submodules/ImportStickerPackUI:ImportStickerPackUI",
"//submodules/GradientBackground:GradientBackground",
"//submodules/WallpaperBackgroundNode:WallpaperBackgroundNode",
],
visibility = [
"//visibility:public",

View File

@ -2701,11 +2701,8 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
self.navigationBar?.userInfo = PeerInfoNavigationSourceTag(peerId: peerId)
}
}
self.navigationBar?.allowsCustomTransition = { [weak self] in
guard let strongSelf = self else {
return false
}
return !strongSelf.chatDisplayNode.hasEmbeddedTitleContent
self.navigationBar?.allowsCustomTransition = {
return true
}
self.chatTitleView = ChatTitleView(account: self.context.account, theme: self.presentationData.theme, strings: self.presentationData.strings, dateTimeFormat: self.presentationData.dateTimeFormat, nameDisplayOrder: self.presentationData.nameDisplayOrder)
@ -4564,6 +4561,8 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
}
mappedTransition = (ChatHistoryListViewTransition(historyView: transition.historyView, deleteItems: deleteItems, insertItems: insertItems, updateItems: transition.updateItems, options: options, scrollToItem: scrollToItem, stationaryItemRange: stationaryItemRange, initialData: transition.initialData, keyboardButtonsMessage: transition.keyboardButtonsMessage, cachedData: transition.cachedData, cachedDataMessages: transition.cachedDataMessages, readStateData: transition.readStateData, scrolledToIndex: transition.scrolledToIndex, scrolledToSomeIndex: transition.scrolledToSomeIndex, peerType: transition.peerType, networkType: transition.networkType, animateIn: false, reason: transition.reason, flashIndicators: transition.flashIndicators), updateSizeAndInsets)
}, updateExtraNavigationBarBackgroundHeight: { value in
strongSelf.additionalNavigationBarBackgroundHeight = value
})
if let mappedTransition = mappedTransition {
@ -6742,45 +6741,6 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
}))
}
self.chatDisplayNode.updateHasEmbeddedTitleContent = { [weak self] in
guard let strongSelf = self else {
return
}
let hasEmbeddedTitleContent = strongSelf.chatDisplayNode.hasEmbeddedTitleContent
let isEmbeddedTitleContentHidden = strongSelf.chatDisplayNode.isEmbeddedTitleContentHidden
if strongSelf.hasEmbeddedTitleContent != hasEmbeddedTitleContent {
strongSelf.hasEmbeddedTitleContent = hasEmbeddedTitleContent
if strongSelf.hasEmbeddedTitleContent {
strongSelf.statusBar.statusBarStyle = .White
} else {
strongSelf.statusBar.statusBarStyle = strongSelf.presentationData.theme.rootController.statusBarStyle.style
}
if let navigationBar = strongSelf.navigationBar {
if let navigationBarCopy = navigationBar.view.snapshotContentTree() {
navigationBar.view.superview?.insertSubview(navigationBarCopy, aboveSubview: navigationBar.view)
navigationBarCopy.alpha = 0.0
navigationBarCopy.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.25, timingFunction: kCAMediaTimingFunctionSpring, completion: { [weak navigationBarCopy] _ in
navigationBarCopy?.removeFromSuperview()
})
}
}
strongSelf.updateNavigationBarPresentation()
}
if strongSelf.isEmbeddedTitleContentHidden != isEmbeddedTitleContentHidden {
strongSelf.isEmbeddedTitleContentHidden = isEmbeddedTitleContentHidden
if let navigationBar = strongSelf.navigationBar {
let transition: ContainedViewLayoutTransition = .animated(duration: 0.25, curve: .easeInOut)
transition.updateAlpha(node: navigationBar, alpha: isEmbeddedTitleContentHidden ? 0.0 : 1.0)
}
}
}
self.interfaceInteraction = interfaceInteraction
if let search = self.focusOnSearchAfterAppearance {
@ -7344,8 +7304,21 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
return canManagePin
}
private var suspendNavigationBarLayout: Bool = false
private var suspendedNavigationBarLayout: ContainerViewLayout?
private var additionalNavigationBarBackgroundHeight: CGFloat = 0.0
override public func updateNavigationBarLayout(_ layout: ContainerViewLayout, transition: ContainedViewLayoutTransition) {
if self.suspendNavigationBarLayout {
self.suspendedNavigationBarLayout = layout
return
}
self.applyNavigationBarLayout(layout, additionalBackgroundHeight: self.additionalNavigationBarBackgroundHeight, transition: transition)
}
override public func containerLayoutUpdated(_ layout: ContainerViewLayout, transition: ContainedViewLayoutTransition) {
self.suspendNavigationBarLayout = true
super.containerLayoutUpdated(layout, transition: transition)
self.validLayout = layout
@ -7365,6 +7338,8 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
self.chatDisplayNode.containerLayoutUpdated(layout, navigationBarHeight: self.navigationHeight, transition: transition, listViewTransaction: { updateSizeAndInsets, additionalScrollDistance, scrollToTop, completion in
self.chatDisplayNode.historyNode.updateLayout(transition: transition, updateSizeAndInsets: updateSizeAndInsets, additionalScrollDistance: additionalScrollDistance, scrollToTop: scrollToTop, completion: completion)
}, updateExtraNavigationBarBackgroundHeight: { value in
self.additionalNavigationBarBackgroundHeight = value
})
if case .compact = layout.metrics.widthClass {
@ -7379,6 +7354,12 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
}
}
}
self.suspendNavigationBarLayout = false
if let suspendedNavigationBarLayout = self.suspendedNavigationBarLayout {
self.suspendedNavigationBarLayout = suspendedNavigationBarLayout
self.applyNavigationBarLayout(suspendedNavigationBarLayout, additionalBackgroundHeight: self.additionalNavigationBarBackgroundHeight, transition: transition)
}
}
func updateChatPresentationInterfaceState(animated: Bool = true, interactive: Bool, saveInterfaceState: Bool = false, _ f: (ChatPresentationInterfaceState) -> ChatPresentationInterfaceState, completion: @escaping (ContainedViewLayoutTransition) -> Void = { _ in }) {

View File

@ -16,7 +16,7 @@ import TelegramUniversalVideoContent
import ChatInterfaceState
import FastBlur
import ConfettiEffect
import GradientBackground
import WallpaperBackgroundNode
final class VideoNavigationControllerDropContentItem: NavigationControllerDropContentItem {
let itemNode: OverlayMediaItemNode
@ -60,224 +60,6 @@ private struct ChatControllerNodeDerivedLayoutState {
var upperInputPositionBound: CGFloat?
}
private final class ChatEmbeddedTitleContentNode: ASDisplayNode {
private let context: AccountContext
private let backgroundNode: ASDisplayNode
private let statusBarBackgroundNode: ASDisplayNode
private let videoNode: OverlayUniversalVideoNode
private let disableInternalAnimationIn: Bool
private let isUIHiddenUpdated: () -> Void
private let unembedWhenPortrait: (OverlayMediaItemNode) -> Bool
private var validLayout: (CGSize, CGFloat, CGFloat, CGFloat)?
private let dismissed: () -> Void
private let interactiveExtensionUpdated: (ContainedViewLayoutTransition) -> Void
private(set) var interactiveExtension: CGFloat = 0.0
private var freezeInteractiveExtension = false
private(set) var isUIHidden: Bool = false
var unembedOnLeave: Bool = true
init(context: AccountContext, videoNode: OverlayUniversalVideoNode, disableInternalAnimationIn: Bool, interactiveExtensionUpdated: @escaping (ContainedViewLayoutTransition) -> Void, dismissed: @escaping () -> Void, isUIHiddenUpdated: @escaping () -> Void, unembedWhenPortrait: @escaping (OverlayMediaItemNode) -> Bool) {
self.dismissed = dismissed
self.interactiveExtensionUpdated = interactiveExtensionUpdated
self.isUIHiddenUpdated = isUIHiddenUpdated
self.unembedWhenPortrait = unembedWhenPortrait
self.disableInternalAnimationIn = disableInternalAnimationIn
self.context = context
self.backgroundNode = ASDisplayNode()
self.backgroundNode.backgroundColor = .black
self.statusBarBackgroundNode = ASDisplayNode()
self.statusBarBackgroundNode.backgroundColor = .black
self.videoNode = videoNode
super.init()
self.clipsToBounds = true
self.addSubnode(self.backgroundNode)
self.addSubnode(self.statusBarBackgroundNode)
self.view.addGestureRecognizer(UIPanGestureRecognizer(target: self, action: #selector(self.panGesture(_:))))
self.videoNode.controlsAreShowingUpdated = { [weak self] value in
guard let strongSelf = self else {
return
}
strongSelf.isUIHidden = !value
strongSelf.isUIHiddenUpdated()
}
}
@objc private func panGesture(_ recognizer: UIPanGestureRecognizer) {
switch recognizer.state {
case .began:
break
case .changed:
let translation = recognizer.translation(in: self.view)
func rubberBandingOffset(offset: CGFloat, bandingStart: CGFloat) -> CGFloat {
let bandedOffset = offset - bandingStart
let range: CGFloat = 600.0
let coefficient: CGFloat = 0.4
return bandingStart + (1.0 - (1.0 / ((bandedOffset * coefficient / range) + 1.0))) * range
}
let offset = rubberBandingOffset(offset: translation.y, bandingStart: 0.0)
if translation.y > 80.0 {
self.freezeInteractiveExtension = true
self.expandIntoPiP()
} else {
self.interactiveExtension = max(0.0, offset)
self.interactiveExtensionUpdated(.immediate)
}
case .cancelled, .ended:
if !freezeInteractiveExtension {
self.interactiveExtension = 0.0
self.interactiveExtensionUpdated(.animated(duration: 0.3, curve: .spring))
}
default:
break
}
}
func calculateHeight(width: CGFloat) -> CGFloat {
return self.videoNode.content.dimensions.aspectFilled(CGSize(width: width, height: 16.0)).height
}
func updateLayout(size: CGSize, actualHeight: CGFloat, topInset: CGFloat, interactiveExtension: CGFloat, transition: ContainedViewLayoutTransition, transitionSurface: ASDisplayNode?, navigationBar: NavigationBar?) {
let isFirstTime = self.validLayout == nil
self.validLayout = (size, actualHeight, topInset, interactiveExtension)
let videoSize = CGSize(width: size.width, height: actualHeight)
let videoFrame = CGRect(origin: CGPoint(x: 0.0, y: topInset + interactiveExtension + floor((size.height - actualHeight) / 2.0)), size: CGSize(width: videoSize.width, height: videoSize.height - topInset - interactiveExtension))
if isFirstTime, let transitionSurface = transitionSurface {
let sourceFrame = self.videoNode.view.convert(self.videoNode.bounds, to: transitionSurface.view)
let targetFrame = self.view.convert(videoFrame, to: transitionSurface.view)
var navigationBarCopy: UIView?
var navigationBarContainer: UIView?
var nodeTransition = transition
if self.disableInternalAnimationIn {
nodeTransition = .immediate
} else {
self.context.sharedContext.mediaManager.setOverlayVideoNode(nil)
transitionSurface.addSubnode(self.videoNode)
navigationBarCopy = navigationBar?.view.snapshotView(afterScreenUpdates: true)
let navigationBarContainerValue = UIView()
navigationBarContainer = navigationBarContainerValue
navigationBarContainerValue.frame = targetFrame
navigationBarContainerValue.clipsToBounds = true
transitionSurface.view.addSubview(navigationBarContainerValue)
}
if !self.disableInternalAnimationIn {
navigationBarContainer?.layer.animateFrame(from: sourceFrame, to: targetFrame, duration: 0.25, timingFunction: kCAMediaTimingFunctionSpring)
}
if !self.disableInternalAnimationIn {
if let navigationBar = navigationBar, let navigationBarCopy = navigationBarCopy {
let navigationFrame = navigationBar.view.convert(navigationBar.bounds, to: transitionSurface.view)
let navigationSourceFrame = navigationFrame.offsetBy(dx: -sourceFrame.minX, dy: -sourceFrame.minY)
let navigationTargetFrame = navigationFrame.offsetBy(dx: -targetFrame.minX, dy: -targetFrame.minY)
navigationBarCopy.frame = navigationTargetFrame
navigationBarContainer?.addSubview(navigationBarCopy)
navigationBarCopy.layer.animateFrame(from: navigationSourceFrame, to: navigationTargetFrame, duration: 0.25, timingFunction: kCAMediaTimingFunctionSpring)
navigationBarCopy.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.25, timingFunction: kCAMediaTimingFunctionSpring)
}
}
self.videoNode.updateRoundCorners(false, transition: nodeTransition)
if !self.disableInternalAnimationIn {
self.videoNode.showControls()
}
self.videoNode.updateLayout(targetFrame.size, transition: nodeTransition)
self.videoNode.frame = targetFrame
if self.disableInternalAnimationIn {
self.insertSubnode(self.videoNode, belowSubnode: self.statusBarBackgroundNode)
} else {
self.videoNode.layer.animateFrame(from: sourceFrame, to: targetFrame, duration: 0.25, timingFunction: kCAMediaTimingFunctionSpring, completion: { [weak self] _ in
guard let strongSelf = self else {
return
}
navigationBarContainer?.removeFromSuperview()
strongSelf.insertSubnode(strongSelf.videoNode, belowSubnode: strongSelf.statusBarBackgroundNode)
if let (size, actualHeight, topInset, interactiveExtension) = strongSelf.validLayout {
strongSelf.updateLayout(size: size, actualHeight: actualHeight, topInset: topInset, interactiveExtension: interactiveExtension, transition: .immediate, transitionSurface: nil, navigationBar: nil)
}
})
self.backgroundNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.2)
}
self.videoNode.customClose = { [weak self] in
guard let strongSelf = self else {
return
}
strongSelf.videoNode.customClose = nil
strongSelf.dismissed()
}
}
transition.updateFrame(node: self.backgroundNode, frame: CGRect(origin: CGPoint(), size: size))
transition.updateFrame(node: self.statusBarBackgroundNode, frame: CGRect(origin: CGPoint(), size: CGSize(width: size.width, height: topInset)))
if self.videoNode.supernode == self {
self.videoNode.layer.transform = CATransform3DIdentity
transition.updateFrame(node: self.videoNode, frame: videoFrame)
}
}
func expand(intoLandscape: Bool) {
if intoLandscape {
let unembedWhenPortrait = self.unembedWhenPortrait
self.videoNode.customUnembedWhenPortrait = { videoNode in
unembedWhenPortrait(videoNode)
}
}
self.videoNode.expand()
}
func expandIntoPiP() {
let transition: ContainedViewLayoutTransition = .animated(duration: 0.25, curve: .spring)
self.videoNode.customExpand = nil
self.videoNode.customClose = nil
let previousFrame = self.videoNode.frame
self.context.sharedContext.mediaManager.setOverlayVideoNode(self.videoNode)
self.videoNode.updateRoundCorners(true, transition: transition)
if let targetSuperview = self.videoNode.view.superview {
let sourceFrame = self.view.convert(previousFrame, to: targetSuperview)
let targetFrame = self.videoNode.frame
self.videoNode.frame = sourceFrame
self.videoNode.updateLayout(sourceFrame.size, transition: .immediate)
transition.updateFrame(node: self.videoNode, frame: targetFrame)
self.videoNode.updateLayout(targetFrame.size, transition: transition)
}
self.dismissed()
}
}
enum ChatEmbeddedTitlePeekContent: Equatable {
case none
case peek
}
class ChatControllerNode: ASDisplayNode, UIScrollViewDelegate {
let context: AccountContext
let chatLocation: ChatLocation
@ -285,8 +67,6 @@ class ChatControllerNode: ASDisplayNode, UIScrollViewDelegate {
private weak var controller: ChatControllerImpl?
let navigationBar: NavigationBar?
private let navigationBarBackroundNode: ASDisplayNode
private let navigationBarSeparatorNode: ASDisplayNode
private var backgroundEffectNode: ASDisplayNode?
private var containerBackgroundNode: ASImageNode?
@ -301,7 +81,6 @@ class ChatControllerNode: ASDisplayNode, UIScrollViewDelegate {
}
let backgroundNode: WallpaperBackgroundNode
var gradientBackgroundNode: GradientBackgroundNode?
let backgroundImageDisposable = MetaDisposable()
let historyNode: ChatHistoryListNode
var blurredHistoryNode: ASImageNode?
@ -449,15 +228,7 @@ class ChatControllerNode: ASDisplayNode, UIScrollViewDelegate {
private var displayVideoUnmuteTipDisposable: Disposable?
private var onLayoutCompletions: [(ContainedViewLayoutTransition) -> Void] = []
private var embeddedTitlePeekContent: ChatEmbeddedTitlePeekContent = .none
private var embeddedTitleContentNode: ChatEmbeddedTitleContentNode?
private var dismissedEmbeddedTitleContentNode: ChatEmbeddedTitleContentNode?
var hasEmbeddedTitleContent: Bool {
return self.embeddedTitleContentNode != nil
}
private var didProcessExperimentalEmbedUrl: String?
init(context: AccountContext, chatLocation: ChatLocation, chatLocationContextHolder: Atomic<ChatLocationContextHolder?>, subject: ChatControllerSubject?, controllerInteraction: ChatControllerInteraction, chatPresentationInterfaceState: ChatPresentationInterfaceState, automaticMediaDownloadSettings: MediaAutoDownloadSettings, navigationBar: NavigationBar?, controller: ChatControllerImpl?) {
self.context = context
self.chatLocation = chatLocation
@ -469,12 +240,6 @@ class ChatControllerNode: ASDisplayNode, UIScrollViewDelegate {
self.backgroundNode = WallpaperBackgroundNode()
self.backgroundNode.displaysAsynchronously = false
if chatPresentationInterfaceState.chatWallpaper.isBuiltin {
self.gradientBackgroundNode = createGradientBackgroundNode()
} else {
self.gradientBackgroundNode = nil
}
self.titleAccessoryPanelContainer = ChatControllerTitlePanelNodeContainer()
self.titleAccessoryPanelContainer.clipsToBounds = true
@ -506,12 +271,6 @@ class ChatControllerNode: ASDisplayNode, UIScrollViewDelegate {
self.navigateButtons = ChatHistoryNavigationButtons(theme: self.chatPresentationInterfaceState.theme, dateTimeFormat: self.chatPresentationInterfaceState.dateTimeFormat)
self.navigateButtons.accessibilityElementsHidden = true
self.navigationBarBackroundNode = ASDisplayNode()
self.navigationBarBackroundNode.backgroundColor = chatPresentationInterfaceState.theme.rootController.navigationBar.backgroundColor
self.navigationBarSeparatorNode = ASDisplayNode()
self.navigationBarSeparatorNode.backgroundColor = chatPresentationInterfaceState.theme.rootController.navigationBar.separatorColor
var getContentAreaInScreenSpaceImpl: (() -> CGRect)?
var onTransitionEventImpl: ((ContainedViewLayoutTransition) -> Void)?
@ -532,10 +291,10 @@ class ChatControllerNode: ASDisplayNode, UIScrollViewDelegate {
}
onTransitionEventImpl = { [weak self] transition in
guard let strongSelf = self, let gradientBackgroundNode = strongSelf.gradientBackgroundNode else {
guard let strongSelf = self else {
return
}
gradientBackgroundNode.animateEvent(transition: transition)
strongSelf.backgroundNode.animateEvent(transition: transition)
}
self.controller?.presentationContext.topLevelSubview = { [weak self] in
@ -604,39 +363,28 @@ class ChatControllerNode: ASDisplayNode, UIScrollViewDelegate {
strongSelf.interactiveEmojis = emojis
}
})
if case .gradient = chatPresentationInterfaceState.chatWallpaper {
self.backgroundNode.imageContentMode = .scaleToFill
} else {
self.backgroundNode.imageContentMode = .scaleAspectFill
}
self.backgroundNode.motionEnabled = chatPresentationInterfaceState.chatWallpaper.settings?.motion ?? false
self.backgroundNode.update(wallpaper: chatPresentationInterfaceState.chatWallpaper)
self.historyNode.verticalScrollIndicatorColor = UIColor(white: 0.5, alpha: 0.8)
self.historyNode.enableExtractedBackgrounds = true
self.addSubnode(self.backgroundNode)
if let gradientBackgroundNode = self.gradientBackgroundNode {
self.addSubnode(gradientBackgroundNode)
}
self.addSubnode(self.historyNodeContainer)
self.addSubnode(self.navigateButtons)
self.addSubnode(self.titleAccessoryPanelContainer)
self.addSubnode(self.inputPanelBackgroundNode)
self.addSubnode(self.inputPanelBackgroundSeparatorNode)
self.addSubnode(self.inputContextPanelContainer)
self.addSubnode(self.navigationBarBackroundNode)
self.addSubnode(self.navigationBarSeparatorNode)
self.addSubnode(self.messageTransitionNode)
if !self.context.sharedContext.immediateExperimentalUISettings.playerEmbedding {
self.navigationBarBackroundNode.isHidden = true
self.navigationBarSeparatorNode.isHidden = true
if let navigationBar = self.navigationBar {
self.addSubnode(navigationBar)
}
self.addSubnode(self.titleAccessoryPanelContainer)
self.historyNode.view.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(self.tapGesture(_:))))
@ -798,8 +546,7 @@ class ChatControllerNode: ASDisplayNode, UIScrollViewDelegate {
self.inputMediaNode?.simulateUpdateLayout(isVisible: isInFocus)
}
func containerLayoutUpdated(_ layout: ContainerViewLayout, navigationBarHeight: CGFloat, transition protoTransition: ContainedViewLayoutTransition, listViewTransaction:
(ListViewUpdateSizeAndInsets, CGFloat, Bool, @escaping () -> Void) -> Void) {
func containerLayoutUpdated(_ layout: ContainerViewLayout, navigationBarHeight: CGFloat, transition protoTransition: ContainedViewLayoutTransition, listViewTransaction: (ListViewUpdateSizeAndInsets, CGFloat, Bool, @escaping () -> Void) -> Void, updateExtraNavigationBarBackgroundHeight: (CGFloat) -> Void) {
let transition: ContainedViewLayoutTransition
if let _ = self.scheduledAnimateInAsOverlayFromNode {
transition = .immediate
@ -847,9 +594,6 @@ class ChatControllerNode: ASDisplayNode, UIScrollViewDelegate {
containerNode.clipsToBounds = true
containerNode.cornerRadius = 15.0
containerNode.addSubnode(self.backgroundNode)
if let gradientBackgroundNode = self.gradientBackgroundNode {
containerNode.addSubnode(gradientBackgroundNode)
}
containerNode.addSubnode(self.historyNodeContainer)
if let restrictedNode = self.restrictedNode {
containerNode.addSubnode(restrictedNode)
@ -886,9 +630,6 @@ class ChatControllerNode: ASDisplayNode, UIScrollViewDelegate {
self.containerNode = nil
containerNode.removeFromSupernode()
self.insertSubnode(self.backgroundNode, at: 0)
if let gradientBackgroundNode = self.gradientBackgroundNode {
self.insertSubnode(gradientBackgroundNode, at: 1)
}
self.insertSubnode(self.historyNodeContainer, aboveSubnode: self.backgroundNode)
if let restrictedNode = self.restrictedNode {
self.insertSubnode(restrictedNode, aboveSubnode: self.historyNodeContainer)
@ -952,6 +693,7 @@ class ChatControllerNode: ASDisplayNode, UIScrollViewDelegate {
var dismissedTitleAccessoryPanelNode: ChatTitleAccessoryPanelNode?
var immediatelyLayoutTitleAccessoryPanelNodeAndAnimateAppearance = false
var titleAccessoryPanelHeight: CGFloat?
var titleAccessoryPanelBackgroundHeight: CGFloat?
if let titleAccessoryPanelNode = titlePanelForChatPresentationInterfaceState(self.chatPresentationInterfaceState, context: self.context, currentPanel: self.titleAccessoryPanelNode, interfaceInteraction: self.interfaceInteraction) {
if self.titleAccessoryPanelNode != titleAccessoryPanelNode {
dismissedTitleAccessoryPanelNode = self.titleAccessoryPanelNode
@ -960,7 +702,9 @@ class ChatControllerNode: ASDisplayNode, UIScrollViewDelegate {
self.titleAccessoryPanelContainer.addSubnode(titleAccessoryPanelNode)
}
titleAccessoryPanelHeight = titleAccessoryPanelNode.updateLayout(width: layout.size.width, leftInset: layout.safeInsets.left, rightInset: layout.safeInsets.right, transition: immediatelyLayoutTitleAccessoryPanelNodeAndAnimateAppearance ? .immediate : transition, interfaceState: self.chatPresentationInterfaceState)
let layoutResult = titleAccessoryPanelNode.updateLayout(width: layout.size.width, leftInset: layout.safeInsets.left, rightInset: layout.safeInsets.right, transition: immediatelyLayoutTitleAccessoryPanelNodeAndAnimateAppearance ? .immediate : transition, interfaceState: self.chatPresentationInterfaceState)
titleAccessoryPanelHeight = layoutResult.insetHeight
titleAccessoryPanelBackgroundHeight = layoutResult.backgroundHeight
} else if let titleAccessoryPanelNode = self.titleAccessoryPanelNode {
dismissedTitleAccessoryPanelNode = titleAccessoryPanelNode
self.titleAccessoryPanelNode = nil
@ -1052,135 +796,13 @@ class ChatControllerNode: ASDisplayNode, UIScrollViewDelegate {
let statusBarHeight = layout.insets(options: [.statusBar]).top
func extractExperimentalPlaylistUrl(_ text: String) -> String? {
let prefix = "stream: "
if text.hasPrefix(prefix) {
if let url = URL(string: String(text[text.index(text.startIndex, offsetBy: prefix.count)...])), url.absoluteString.hasSuffix(".m3u8") {
return url.absoluteString
} else {
return nil
}
} else {
return nil
}
}
if let pinnedMessage = self.chatPresentationInterfaceState.pinnedMessage, self.context.sharedContext.immediateExperimentalUISettings.playerEmbedding, self.context.sharedContext.immediateExperimentalUISettings.playlistPlayback, self.embeddedTitleContentNode == nil, let url = extractExperimentalPlaylistUrl(pinnedMessage.message.text), self.didProcessExperimentalEmbedUrl != url {
self.didProcessExperimentalEmbedUrl = url
let context = self.context
let baseNavigationController = self.controller?.navigationController as? NavigationController
let mediaManager = self.context.sharedContext.mediaManager
var expandImpl: (() -> Void)?
let content = PlatformVideoContent(id: .instantPage(MediaId(namespace: 0, id: 0), MediaId(namespace: 0, id: 0)), content: .url(url), streamVideo: true, loopVideo: false)
let overlayNode = OverlayUniversalVideoNode(postbox: self.context.account.postbox, audioSession: self.context.sharedContext.mediaManager.audioSession, manager: self.context.sharedContext.mediaManager.universalVideoManager, content: content, expand: {
expandImpl?()
}, close: { [weak mediaManager] in
mediaManager?.setOverlayVideoNode(nil)
})
self.embeddedTitleContentNode = ChatEmbeddedTitleContentNode(context: self.context, videoNode: overlayNode, disableInternalAnimationIn: true, interactiveExtensionUpdated: { [weak self] transition in
guard let strongSelf = self else {
return
}
strongSelf.requestLayout(transition)
}, dismissed: { [weak self] in
guard let strongSelf = self else {
return
}
if let embeddedTitleContentNode = strongSelf.embeddedTitleContentNode {
strongSelf.embeddedTitleContentNode = nil
strongSelf.dismissedEmbeddedTitleContentNode = embeddedTitleContentNode
strongSelf.requestLayout(.animated(duration: 0.25, curve: .spring))
strongSelf.updateHasEmbeddedTitleContent?()
}
}, isUIHiddenUpdated: { [weak self] in
self?.updateHasEmbeddedTitleContent?()
}, unembedWhenPortrait: { [weak self] itemNode in
guard let strongSelf = self, let itemNode = itemNode as? OverlayUniversalVideoNode else {
return false
}
strongSelf.unembedWhenPortrait(contentNode: itemNode)
return true
})
self.embeddedTitleContentNode?.unembedOnLeave = false
self.updateHasEmbeddedTitleContent?()
overlayNode.controlPlay()
}
if self.chatPresentationInterfaceState.pinnedMessage == nil {
self.didProcessExperimentalEmbedUrl = nil
}
if let embeddedTitleContentNode = self.embeddedTitleContentNode, embeddedTitleContentNode.supernode != nil {
if layout.size.width > layout.size.height {
self.embeddedTitleContentNode = nil
self.dismissedEmbeddedTitleContentNode = embeddedTitleContentNode
embeddedTitleContentNode.expand(intoLandscape: true)
self.updateHasEmbeddedTitleContent?()
}
}
if let embeddedTitleContentNode = self.embeddedTitleContentNode {
let defaultEmbeddedSize = CGSize(width: layout.size.width, height: min(400.0, embeddedTitleContentNode.calculateHeight(width: layout.size.width)) + statusBarHeight + embeddedTitleContentNode.interactiveExtension)
let embeddedSize: CGSize
if let inputHeight = layout.inputHeight, inputHeight > 100.0 {
embeddedSize = CGSize(width: defaultEmbeddedSize.width, height: floor(defaultEmbeddedSize.height * 0.6))
} else {
embeddedSize = defaultEmbeddedSize
}
if embeddedTitleContentNode.supernode == nil {
self.insertSubnode(embeddedTitleContentNode, aboveSubnode: self.navigationBarBackroundNode)
var previousTopInset = insets.top
if case .overlay = self.chatPresentationInterfaceState.mode {
previousTopInset = 44.0
} else {
previousTopInset += navigationBarHeight
}
if case .peek = self.embeddedTitlePeekContent {
previousTopInset += 32.0
}
embeddedTitleContentNode.frame = CGRect(origin: CGPoint(), size: CGSize(width: layout.size.width, height: previousTopInset))
transition.updateFrame(node: embeddedTitleContentNode, frame: CGRect(origin: CGPoint(), size: embeddedSize))
embeddedTitleContentNode.updateLayout(size: embeddedSize, actualHeight: defaultEmbeddedSize.height, topInset: statusBarHeight, interactiveExtension: embeddedTitleContentNode.interactiveExtension, transition: .immediate, transitionSurface: self, navigationBar: self.navigationBar)
} else {
transition.updateFrame(node: embeddedTitleContentNode, frame: CGRect(origin: CGPoint(), size: embeddedSize))
embeddedTitleContentNode.updateLayout(size: embeddedSize, actualHeight: defaultEmbeddedSize.height, topInset: statusBarHeight, interactiveExtension: embeddedTitleContentNode.interactiveExtension, transition: transition, transitionSurface: self, navigationBar: self.navigationBar)
}
insets.top += embeddedSize.height
if case .overlay = self.chatPresentationInterfaceState.mode {
insets.top = 44.0
} else {
if case .overlay = self.chatPresentationInterfaceState.mode {
insets.top = 44.0
} else {
insets.top += navigationBarHeight
}
if case .peek = self.embeddedTitlePeekContent {
insets.top += 32.0
}
insets.top += navigationBarHeight
}
if let dismissedEmbeddedTitleContentNode = self.dismissedEmbeddedTitleContentNode {
self.dismissedEmbeddedTitleContentNode = nil
if transition.isAnimated {
dismissedEmbeddedTitleContentNode.alpha = 0.0
dismissedEmbeddedTitleContentNode.layer.allowsGroupOpacity = true
dismissedEmbeddedTitleContentNode.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.15, completion: { [weak dismissedEmbeddedTitleContentNode] _ in
dismissedEmbeddedTitleContentNode?.removeFromSupernode()
})
transition.updateFrame(node: dismissedEmbeddedTitleContentNode, frame: CGRect(origin: CGPoint(), size: CGSize(width: layout.size.width, height: insets.top)))
} else {
dismissedEmbeddedTitleContentNode.removeFromSupernode()
}
}
transition.updateFrame(node: self.navigationBarBackroundNode, frame: CGRect(origin: CGPoint(), size: CGSize(width: layout.size.width, height: insets.top)))
transition.updateFrame(node: self.navigationBarSeparatorNode, frame: CGRect(origin: CGPoint(x: 0.0, y: insets.top), size: CGSize(width: layout.size.width, height: UIScreenPixel)))
var wrappingInsets = UIEdgeInsets()
if case .overlay = self.chatPresentationInterfaceState.mode {
let containerWidth = horizontalContainerFillingSizeForLayout(layout: layout, sideInset: 8.0 + layout.safeInsets.left)
@ -1286,6 +908,8 @@ class ChatControllerNode: ASDisplayNode, UIScrollViewDelegate {
titleAccessoryPanelFrame = CGRect(origin: CGPoint(x: 0.0, y: 0.0), size: CGSize(width: layout.size.width, height: panelHeight))
insets.top += panelHeight
}
updateExtraNavigationBarBackgroundHeight(titleAccessoryPanelBackgroundHeight ?? 0.0)
var importStatusPanelFrame: CGRect?
if let _ = self.chatImportStatusPanel, let panelHeight = importStatusPanelHeight {
@ -1302,11 +926,6 @@ class ChatControllerNode: ASDisplayNode, UIScrollViewDelegate {
transition.updateFrame(node: self.backgroundNode, frame: contentBounds)
self.backgroundNode.updateLayout(size: contentBounds.size, transition: transition)
if let gradientBackgroundNode = self.gradientBackgroundNode {
transition.updateFrame(node: gradientBackgroundNode, frame: contentBounds)
gradientBackgroundNode.updateLayout(size: contentBounds.size, transition: transition)
}
transition.updateFrame(node: self.historyNodeContainer, frame: contentBounds)
transition.updateBounds(node: self.historyNode, bounds: CGRect(origin: CGPoint(), size: contentBounds.size))
transition.updatePosition(node: self.historyNode, position: CGPoint(x: contentBounds.size.width / 2.0, y: contentBounds.size.height / 2.0))
@ -1599,6 +1218,8 @@ class ChatControllerNode: ASDisplayNode, UIScrollViewDelegate {
if layout.additionalInsets.right > 0.0 {
apparentNavigateButtonsFrame.origin.y -= 16.0
}
apparentInputBackgroundFrame.size.height += 41.0
let previousInputPanelBackgroundFrame = self.inputPanelBackgroundNode.frame
transition.updateFrame(node: self.inputPanelBackgroundNode, frame: apparentInputBackgroundFrame)
@ -1922,7 +1543,7 @@ class ChatControllerNode: ASDisplayNode, UIScrollViewDelegate {
let listBottomInset = self.historyNode.insets.top
if let previousListBottomInset = previousListBottomInset, listBottomInset != previousListBottomInset {
if abs(listBottomInset - previousListBottomInset) > 80.0 {
self.gradientBackgroundNode?.animateEvent(transition: transition)
self.backgroundNode.animateEvent(transition: transition)
}
//self.historyNode.didScrollWithOffset?(listBottomInset - previousListBottomInset, transition, nil)
}
@ -1974,23 +1595,7 @@ class ChatControllerNode: ASDisplayNode, UIScrollViewDelegate {
}
}))
self.backgroundNode.image = chatControllerBackgroundImage(theme: chatPresentationInterfaceState.theme, wallpaper: chatPresentationInterfaceState.chatWallpaper, mediaBox: context.sharedContext.accountManager.mediaBox, knockoutMode: self.context.sharedContext.immediateExperimentalUISettings.knockoutWallpaper)
if case .gradient = chatPresentationInterfaceState.chatWallpaper {
self.backgroundNode.imageContentMode = .scaleToFill
} else {
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.backgroundNode.update(wallpaper: chatPresentationInterfaceState.chatWallpaper)
}
self.historyNode.verticalScrollIndicatorColor = UIColor(white: 0.5, alpha: 0.8)
@ -2012,9 +1617,6 @@ class ChatControllerNode: ASDisplayNode, UIScrollViewDelegate {
}
self.updatePlainInputSeparator(transition: .immediate)
self.inputPanelBackgroundSeparatorNode.backgroundColor = self.chatPresentationInterfaceState.theme.chat.inputPanel.panelSeparatorColor
self.navigationBarBackroundNode.backgroundColor = chatPresentationInterfaceState.theme.rootController.navigationBar.backgroundColor
self.navigationBarSeparatorNode.backgroundColor = chatPresentationInterfaceState.theme.rootController.navigationBar.separatorColor
}
let keepSendButtonEnabled = chatPresentationInterfaceState.interfaceState.forwardMessageIds != nil || chatPresentationInterfaceState.interfaceState.editMessage != nil
@ -2545,6 +2147,7 @@ class ChatControllerNode: ASDisplayNode, UIScrollViewDelegate {
if let (layout, navigationHeight) = self.validLayout {
self.containerLayoutUpdated(layout, navigationBarHeight: navigationHeight, transition: transition, listViewTransaction: { updateSizeAndInsets, additionalScrollDistance, scrollToTop, completion in
self.historyNode.updateLayout(transition: transition, updateSizeAndInsets: updateSizeAndInsets, additionalScrollDistance: additionalScrollDistance, scrollToTop: scrollToTop, completion: completion)
}, updateExtraNavigationBarBackgroundHeight: { _ in
})
}
}
@ -2802,124 +2405,7 @@ class ChatControllerNode: ASDisplayNode, UIScrollViewDelegate {
self.view.insertSubview(ConfettiView(frame: self.view.bounds), aboveSubview: self.historyNode.view)
}
func updateEmbeddedTitlePeekContent(content: NavigationControllerDropContent?) {
if !self.context.sharedContext.immediateExperimentalUISettings.playerEmbedding {
return
}
guard let (_, navigationHeight) = self.validLayout else {
return
}
var peekContent: ChatEmbeddedTitlePeekContent = .none
if let content = content, let item = content.item as? VideoNavigationControllerDropContentItem, let _ = item.itemNode as? OverlayUniversalVideoNode {
if content.position.y < navigationHeight + 32.0 {
peekContent = .peek
}
}
if self.embeddedTitlePeekContent != peekContent {
self.embeddedTitlePeekContent = peekContent
self.requestLayout(.animated(duration: 0.3, curve: .spring))
}
}
var isEmbeddedTitleContentHidden: Bool {
if let embeddedTitleContentNode = self.embeddedTitleContentNode {
return embeddedTitleContentNode.isUIHidden
} else {
return false
}
}
var updateHasEmbeddedTitleContent: (() -> Void)?
func acceptEmbeddedTitlePeekContent(content: NavigationControllerDropContent) -> Bool {
if !self.context.sharedContext.immediateExperimentalUISettings.playerEmbedding {
return false
}
guard let (_, navigationHeight) = self.validLayout else {
return false
}
if content.position.y >= navigationHeight + 32.0 {
return false
}
if let item = content.item as? VideoNavigationControllerDropContentItem, let itemNode = item.itemNode as? OverlayUniversalVideoNode {
let embeddedTitleContentNode = ChatEmbeddedTitleContentNode(context: self.context, videoNode: itemNode, disableInternalAnimationIn: false, interactiveExtensionUpdated: { [weak self] transition in
guard let strongSelf = self else {
return
}
strongSelf.requestLayout(transition)
}, dismissed: { [weak self] in
guard let strongSelf = self else {
return
}
if let embeddedTitleContentNode = strongSelf.embeddedTitleContentNode {
strongSelf.embeddedTitleContentNode = nil
strongSelf.dismissedEmbeddedTitleContentNode = embeddedTitleContentNode
strongSelf.requestLayout(.animated(duration: 0.25, curve: .spring))
strongSelf.updateHasEmbeddedTitleContent?()
}
}, isUIHiddenUpdated: { [weak self] in
self?.updateHasEmbeddedTitleContent?()
}, unembedWhenPortrait: { [weak self] itemNode in
guard let strongSelf = self, let itemNode = itemNode as? OverlayUniversalVideoNode else {
return false
}
strongSelf.unembedWhenPortrait(contentNode: itemNode)
return true
})
self.embeddedTitleContentNode = embeddedTitleContentNode
self.embeddedTitlePeekContent = .none
self.updateHasEmbeddedTitleContent?()
DispatchQueue.main.async {
self.requestLayout(.animated(duration: 0.25, curve: .spring))
}
return true
}
return false
}
private func unembedWhenPortrait(contentNode: OverlayUniversalVideoNode) {
let embeddedTitleContentNode = ChatEmbeddedTitleContentNode(context: self.context, videoNode: contentNode, disableInternalAnimationIn: true, interactiveExtensionUpdated: { [weak self] transition in
guard let strongSelf = self else {
return
}
strongSelf.requestLayout(transition)
}, dismissed: { [weak self] in
guard let strongSelf = self else {
return
}
if let embeddedTitleContentNode = strongSelf.embeddedTitleContentNode {
strongSelf.embeddedTitleContentNode = nil
strongSelf.dismissedEmbeddedTitleContentNode = embeddedTitleContentNode
strongSelf.requestLayout(.animated(duration: 0.25, curve: .spring))
strongSelf.updateHasEmbeddedTitleContent?()
}
}, isUIHiddenUpdated: { [weak self] in
self?.updateHasEmbeddedTitleContent?()
}, unembedWhenPortrait: { [weak self] itemNode in
guard let strongSelf = self, let itemNode = itemNode as? OverlayUniversalVideoNode else {
return false
}
strongSelf.unembedWhenPortrait(contentNode: itemNode)
return true
})
self.embeddedTitleContentNode = embeddedTitleContentNode
self.embeddedTitlePeekContent = .none
self.updateHasEmbeddedTitleContent?()
self.requestLayout(.immediate)
}
func willNavigateAway() {
if let embeddedTitleContentNode = self.embeddedTitleContentNode, embeddedTitleContentNode.unembedOnLeave {
self.embeddedTitleContentNode = nil
self.dismissedEmbeddedTitleContentNode = embeddedTitleContentNode
embeddedTitleContentNode.expandIntoPiP()
self.requestLayout(.animated(duration: 0.25, curve: .spring))
self.updateHasEmbeddedTitleContent?()
}
}
func updateIsBlurred(_ isBlurred: Bool) {

View File

@ -126,32 +126,26 @@ private final class ChatInfoTitlePanelButtonNode: HighlightableButtonNode {
final class ChatInfoTitlePanelNode: ChatTitleAccessoryPanelNode {
private var theme: PresentationTheme?
private let backgroundNode: ASDisplayNode
private let separatorNode: ASDisplayNode
private var buttons: [(ChatInfoTitleButton, ChatInfoTitlePanelButtonNode)] = []
override init() {
self.backgroundNode = ASDisplayNode()
self.backgroundNode.isLayerBacked = true
self.separatorNode = ASDisplayNode()
self.separatorNode.isLayerBacked = true
super.init()
self.addSubnode(self.backgroundNode)
self.addSubnode(self.separatorNode)
}
override func updateLayout(width: CGFloat, leftInset: CGFloat, rightInset: CGFloat, transition: ContainedViewLayoutTransition, interfaceState: ChatPresentationInterfaceState) -> CGFloat {
override func updateLayout(width: CGFloat, leftInset: CGFloat, rightInset: CGFloat, transition: ContainedViewLayoutTransition, interfaceState: ChatPresentationInterfaceState) -> LayoutResult {
let themeUpdated = self.theme !== interfaceState.theme
self.theme = interfaceState.theme
let panelHeight: CGFloat = 55.0
if themeUpdated {
self.backgroundNode.backgroundColor = interfaceState.theme.rootController.navigationBar.backgroundColor
self.separatorNode.backgroundColor = interfaceState.theme.rootController.navigationBar.separatorColor
}
@ -205,11 +199,9 @@ final class ChatInfoTitlePanelNode: ChatTitleAccessoryPanelNode {
}
}
transition.updateFrame(node: self.backgroundNode, frame: CGRect(origin: CGPoint(x: 0.0, y: 0.0), size: CGSize(width: width, height: panelHeight)))
transition.updateFrame(node: self.separatorNode, frame: CGRect(origin: CGPoint(x: 0.0, y: panelHeight - UIScreenPixel), size: CGSize(width: width, height: UIScreenPixel)))
return panelHeight
return LayoutResult(backgroundHeight: panelHeight, insetHeight: panelHeight)
}
@objc func buttonPressed(_ node: HighlightableButtonNode) {

View File

@ -423,7 +423,7 @@ final class ChatMediaInputNode: ChatInputNode {
private var inputNodeInteraction: ChatMediaInputNodeInteraction!
private var trendingInteraction: TrendingPaneInteraction?
private let collectionListPanel: NavigationBackgroundNode
private let collectionListPanel: ASDisplayNode
private let collectionListSeparator: ASDisplayNode
private let collectionListContainer: CollectionListContainerNode
@ -433,7 +433,9 @@ final class ChatMediaInputNode: ChatInputNode {
private let gifListView: ListView
private var searchContainerNode: PaneSearchContainerNode?
private let searchContainerNodeLoadedDisposable = MetaDisposable()
private let paneClippingContainer: ASDisplayNode
private let panesBackgroundNode: ASDisplayNode
private let stickerPane: ChatMediaInputStickerPane
private var animatingStickerPaneOut = false
private let gifPane: ChatMediaInputGifPane
@ -473,14 +475,15 @@ final class ChatMediaInputNode: ChatInputNode {
self.strings = strings
self.fontSize = fontSize
self.gifPaneIsActiveUpdated = gifPaneIsActiveUpdated
self.paneClippingContainer = ASDisplayNode()
self.paneClippingContainer.clipsToBounds = true
self.panesBackgroundNode = ASDisplayNode()
self.themeAndStringsPromise = Promise((theme, strings))
if case let .color(color) = chatWallpaper, UIColor(rgb: color).isEqual(theme.chat.inputPanel.panelBackgroundColorNoWallpaper) {
self.collectionListPanel = NavigationBackgroundNode(color: theme.chat.inputPanel.panelBackgroundColorNoWallpaper)
} else {
self.collectionListPanel = NavigationBackgroundNode(color: theme.chat.inputPanel.panelBackgroundColor)
}
self.collectionListPanel = ASDisplayNode()
self.collectionListPanel.clipsToBounds = true
self.collectionListSeparator = ASDisplayNode()
@ -687,8 +690,10 @@ final class ChatMediaInputNode: ChatInputNode {
return false
}
self.backgroundColor = theme.chat.inputMediaPanel.stickersBackgroundColor.withAlphaComponent(1.0)
self.panesBackgroundNode.backgroundColor = theme.chat.inputMediaPanel.stickersBackgroundColor.withAlphaComponent(1.0)
self.addSubnode(self.paneClippingContainer)
self.paneClippingContainer.addSubnode(panesBackgroundNode)
self.collectionListPanel.addSubnode(self.listView)
self.collectionListPanel.addSubnode(self.gifListView)
self.gifListView.isHidden = true
@ -1086,12 +1091,6 @@ final class ChatMediaInputNode: ChatInputNode {
self.theme = theme
self.strings = strings
if case let .color(color) = chatWallpaper, UIColor(rgb: color).isEqual(theme.chat.inputPanel.panelBackgroundColorNoWallpaper) {
self.collectionListPanel.color = theme.chat.inputPanel.panelBackgroundColorNoWallpaper
} else {
self.collectionListPanel.color = theme.chat.inputPanel.panelBackgroundColor
}
self.collectionListSeparator.backgroundColor = theme.chat.inputMediaPanel.panelSeparatorColor
self.backgroundColor = theme.chat.inputMediaPanel.stickersBackgroundColor.withAlphaComponent(1.0)
@ -1639,7 +1638,6 @@ 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)
@ -1672,11 +1670,7 @@ final class ChatMediaInputNode: ChatInputNode {
case .gifs:
if self.gifPane.supernode == nil {
if !displaySearch {
if let searchContainerNode = self.searchContainerNode {
self.insertSubnode(self.gifPane, belowSubnode: searchContainerNode)
} else {
self.insertSubnode(self.gifPane, belowSubnode: self.collectionListContainer)
}
self.paneClippingContainer.addSubnode(self.gifPane)
if self.searchContainerNode == nil {
self.gifPane.frame = CGRect(origin: CGPoint(x: -width, y: 0.0), size: CGSize(width: width, height: panelHeight))
}
@ -1688,11 +1682,7 @@ final class ChatMediaInputNode: ChatInputNode {
}
case .stickers:
if self.stickerPane.supernode == nil {
if let searchContainerNode = self.searchContainerNode {
self.insertSubnode(self.stickerPane, belowSubnode: searchContainerNode)
} else {
self.insertSubnode(self.stickerPane, belowSubnode: self.collectionListContainer)
}
self.paneClippingContainer.addSubnode(self.stickerPane)
self.stickerPane.frame = CGRect(origin: CGPoint(x: width, y: 0.0), size: CGSize(width: width, height: panelHeight))
}
if self.stickerPane.frame != paneFrame {
@ -1834,6 +1824,10 @@ final class ChatMediaInputNode: ChatInputNode {
self?.gifPane.initializeIfNeeded()
})
}
self.updatePaneClippingContainer(size: CGSize(width: width, height: panelHeight), offset: contentVerticalOffset, transition: transition)
transition.updateFrame(node: self.panesBackgroundNode, frame: CGRect(origin: CGPoint(x: 0.0, y: 0.0), size: CGSize(width: width, height: panelHeight)))
return (standardInputHeight, max(0.0, panelHeight - standardInputHeight))
}
@ -1974,10 +1968,16 @@ 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))
self.updatePaneClippingContainer(size: self.paneClippingContainer.bounds.size, offset: collectionListPanelOffset, transition: transition)
}
private func updatePaneClippingContainer(size: CGSize, offset: CGFloat, transition: ContainedViewLayoutTransition) {
transition.updateFrame(node: self.paneClippingContainer, frame: CGRect(origin: CGPoint(x: 0.0, y: offset + 41.0), size: size))
transition.updateSublayerTransformOffset(layer: self.paneClippingContainer.layer, offset: CGPoint(x: 0.0, y: -offset - 41.0))
}
private func fixPaneScroll(pane: ChatMediaInputPane, state: ChatMediaInputPaneScrollState) {
@ -1996,7 +1996,6 @@ 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

@ -55,7 +55,6 @@ 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)?
@ -92,8 +91,6 @@ 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
@ -122,8 +119,6 @@ final class ChatPinnedMessageTitlePanelNode: ChatTitleAccessoryPanelNode {
self.imageNodeContainer = ASDisplayNode()
super.init()
self.addSubnode(self.backgroundNode)
self.tapButton.highligthedChanged = { [weak self] highlighted in
if let strongSelf = self {
@ -187,12 +182,9 @@ final class ChatPinnedMessageTitlePanelNode: ChatTitleAccessoryPanelNode {
private var theme: PresentationTheme?
override func updateLayout(width: CGFloat, leftInset: CGFloat, rightInset: CGFloat, transition: ContainedViewLayoutTransition, interfaceState: ChatPresentationInterfaceState) -> CGFloat {
override func updateLayout(width: CGFloat, leftInset: CGFloat, rightInset: CGFloat, transition: ContainedViewLayoutTransition, interfaceState: ChatPresentationInterfaceState) -> LayoutResult {
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))
@ -201,7 +193,6 @@ 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.backgroundNode.color = interfaceState.theme.rootController.navigationBar.backgroundColor
self.separatorNode.backgroundColor = interfaceState.theme.rootController.navigationBar.separatorColor
}
@ -326,7 +317,7 @@ final class ChatPinnedMessageTitlePanelNode: ChatTitleAccessoryPanelNode {
}
}
return panelHeight
return LayoutResult(backgroundHeight: panelHeight, insetHeight: panelHeight)
}
private func enqueueTransition(width: CGFloat, panelHeight: CGFloat, leftInset: CGFloat, rightInset: CGFloat, transition: ContainedViewLayoutTransition, animation: PinnedMessageAnimation?, pinnedMessage: ChatPinnedMessage, theme: PresentationTheme, strings: PresentationStrings, nameDisplayOrder: PresentationPersonNameOrder, dateTimeFormat: PresentationDateTimeFormat, accountPeerId: PeerId, firstTime: Bool, isReplyThread: Bool) {

View File

@ -305,7 +305,6 @@ private final class ChatInfoTitlePanelPeerNearbyInfoNode: ASDisplayNode {
}
final class ChatReportPeerTitlePanelNode: ChatTitleAccessoryPanelNode {
private let backgroundNode: NavigationBackgroundNode
private let separatorNode: ASDisplayNode
private let closeButton: HighlightableButtonNode
@ -317,7 +316,6 @@ final class ChatReportPeerTitlePanelNode: ChatTitleAccessoryPanelNode {
private var peerNearbyInfoNode: ChatInfoTitlePanelPeerNearbyInfoNode?
override init() {
self.backgroundNode = NavigationBackgroundNode(color: .clear)
self.separatorNode = ASDisplayNode()
self.separatorNode.isLayerBacked = true
@ -326,23 +324,21 @@ final class ChatReportPeerTitlePanelNode: ChatTitleAccessoryPanelNode {
self.closeButton.displaysAsynchronously = false
super.init()
self.addSubnode(self.backgroundNode)
self.addSubnode(self.separatorNode)
self.closeButton.addTarget(self, action: #selector(self.closePressed), forControlEvents: [.touchUpInside])
self.addSubnode(self.closeButton)
}
override func updateLayout(width: CGFloat, leftInset: CGFloat, rightInset: CGFloat, transition: ContainedViewLayoutTransition, interfaceState: ChatPresentationInterfaceState) -> CGFloat {
override func updateLayout(width: CGFloat, leftInset: CGFloat, rightInset: CGFloat, transition: ContainedViewLayoutTransition, interfaceState: ChatPresentationInterfaceState) -> LayoutResult {
if interfaceState.theme !== self.theme {
self.theme = interfaceState.theme
self.closeButton.setImage(PresentationResourcesChat.chatInputPanelEncircledCloseIconImage(interfaceState.theme), for: [])
self.backgroundNode.color = interfaceState.theme.rootController.navigationBar.backgroundColor
self.separatorNode.backgroundColor = interfaceState.theme.rootController.navigationBar.separatorColor
}
var panelHeight: CGFloat = 40.0
let contentRightInset: CGFloat = 14.0 + rightInset
@ -436,10 +432,8 @@ 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)
let initialPanelHeight = panelHeight
transition.updateFrame(node: self.separatorNode, frame: CGRect(origin: CGPoint(x: 0.0, y: panelHeight - UIScreenPixel), size: CGSize(width: width, height: UIScreenPixel)))
var chatPeer: Peer?
@ -502,7 +496,7 @@ final class ChatReportPeerTitlePanelNode: ChatTitleAccessoryPanelNode {
})
}
return panelHeight
return LayoutResult(backgroundHeight: initialPanelHeight, insetHeight: panelHeight)
}
@objc func buttonPressed(_ view: UIButton) {

View File

@ -5,7 +5,6 @@ import AsyncDisplayKit
import TelegramPresentationData
final class ChatRequestInProgressTitlePanelNode: ChatTitleAccessoryPanelNode {
private let backgroundNode: NavigationBackgroundNode
private let separatorNode: ASDisplayNode
private let titleNode: ImmediateTextNode
@ -13,8 +12,6 @@ final class ChatRequestInProgressTitlePanelNode: ChatTitleAccessoryPanelNode {
private var strings: PresentationStrings?
override init() {
self.backgroundNode = NavigationBackgroundNode(color: .clear)
self.separatorNode = ASDisplayNode()
self.separatorNode.isLayerBacked = true
@ -23,12 +20,11 @@ final class ChatRequestInProgressTitlePanelNode: ChatTitleAccessoryPanelNode {
super.init()
self.addSubnode(self.backgroundNode)
self.addSubnode(self.titleNode)
self.addSubnode(self.separatorNode)
}
override func updateLayout(width: CGFloat, leftInset: CGFloat, rightInset: CGFloat, transition: ContainedViewLayoutTransition, interfaceState: ChatPresentationInterfaceState) -> CGFloat {
override func updateLayout(width: CGFloat, leftInset: CGFloat, rightInset: CGFloat, transition: ContainedViewLayoutTransition, interfaceState: ChatPresentationInterfaceState) -> LayoutResult {
if interfaceState.strings !== self.strings {
self.strings = interfaceState.strings
@ -38,20 +34,17 @@ final class ChatRequestInProgressTitlePanelNode: ChatTitleAccessoryPanelNode {
if interfaceState.theme !== self.theme {
self.theme = interfaceState.theme
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))
transition.updateFrame(node: self.separatorNode, frame: CGRect(origin: CGPoint(x: 0.0, y: panelHeight - UIScreenPixel), size: CGSize(width: width, height: UIScreenPixel)))
return panelHeight
return LayoutResult(backgroundHeight: panelHeight, insetHeight: panelHeight)
}
}

View File

@ -4,9 +4,14 @@ import Display
import AsyncDisplayKit
class ChatTitleAccessoryPanelNode: ASDisplayNode {
struct LayoutResult {
var backgroundHeight: CGFloat
var insetHeight: CGFloat
}
var interfaceInteraction: ChatPanelInterfaceInteraction?
func updateLayout(width: CGFloat, leftInset: CGFloat, rightInset: CGFloat, transition: ContainedViewLayoutTransition, interfaceState: ChatPresentationInterfaceState) -> CGFloat {
return 0.0
func updateLayout(width: CGFloat, leftInset: CGFloat, rightInset: CGFloat, transition: ContainedViewLayoutTransition, interfaceState: ChatPresentationInterfaceState) -> LayoutResult {
preconditionFailure()
}
}

View File

@ -4,7 +4,6 @@ import Display
import AsyncDisplayKit
final class ChatToastAlertPanelNode: ChatTitleAccessoryPanelNode {
private let backgroundNode: NavigationBackgroundNode
private let separatorNode: ASDisplayNode
private let titleNode: ImmediateTextNode
@ -26,8 +25,6 @@ final class ChatToastAlertPanelNode: ChatTitleAccessoryPanelNode {
}
override init() {
self.backgroundNode = NavigationBackgroundNode(color: .clear)
self.separatorNode = ASDisplayNode()
self.separatorNode.isLayerBacked = true
@ -38,19 +35,14 @@ final class ChatToastAlertPanelNode: ChatTitleAccessoryPanelNode {
super.init()
self.addSubnode(self.backgroundNode)
self.addSubnode(self.titleNode)
self.addSubnode(self.separatorNode)
}
override func updateLayout(width: CGFloat, leftInset: CGFloat, rightInset: CGFloat, transition: ContainedViewLayoutTransition, interfaceState: ChatPresentationInterfaceState) -> CGFloat {
override func updateLayout(width: CGFloat, leftInset: CGFloat, rightInset: CGFloat, transition: ContainedViewLayoutTransition, interfaceState: ChatPresentationInterfaceState) -> LayoutResult {
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.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)))
@ -58,6 +50,6 @@ final class ChatToastAlertPanelNode: ChatTitleAccessoryPanelNode {
let titleSize = self.titleNode.updateLayout(CGSize(width: width - leftInset - rightInset - 20.0, height: 100.0))
self.titleNode.frame = CGRect(origin: CGPoint(x: floor((width - titleSize.width) / 2.0), y: floor((panelHeight - titleSize.height) / 2.0)), size: titleSize)
return panelHeight
return LayoutResult(backgroundHeight: panelHeight, insetHeight: panelHeight)
}
}

View File

@ -806,9 +806,8 @@ final class UndoOverlayControllerNode: ViewControllerTracingNode {
override func didLoad() {
super.didLoad()
if self.panelNode.backgroundColor == .clear {
self.panelNode.view.addSubview(self.effectView)
}
self.panelNode.view.addSubview(self.effectView)
}
@objc private func buttonPressed() {

View File

@ -0,0 +1,22 @@
load("@build_bazel_rules_swift//swift:swift.bzl", "swift_library")
swift_library(
name = "WallpaperBackgroundNode",
module_name = "WallpaperBackgroundNode",
srcs = glob([
"Sources/**/*.swift",
]),
copts = [
"-O",
],
deps = [
"//submodules/AsyncDisplayKit:AsyncDisplayKit",
"//submodules/Display:Display",
"//submodules/GradientBackground:GradientBackground",
"//submodules/TelegramPresentationData:TelegramPresentationData",
"//submodules/SyncCore:SyncCore",
],
visibility = [
"//visibility:public",
],
)

View File

@ -1,13 +1,21 @@
import Foundation
import UIKit
import AsyncDisplayKit
import Display
import GradientBackground
import TelegramPresentationData
import SyncCore
private let motionAmount: CGFloat = 32.0
public final class WallpaperBackgroundNode: ASDisplayNode {
let contentNode: ASDisplayNode
private let contentNode: ASDisplayNode
private var gradientBackgroundNode: GradientBackgroundNode?
private var validLayout: CGSize?
private var wallpaper: TelegramWallpaper?
public var motionEnabled: Bool = false {
private var motionEnabled: Bool = false {
didSet {
if oldValue != self.motionEnabled {
if self.motionEnabled {
@ -51,13 +59,13 @@ public final class WallpaperBackgroundNode: ASDisplayNode {
}
}
public var imageContentMode: UIView.ContentMode {
private var imageContentMode: UIView.ContentMode {
didSet {
self.contentNode.contentMode = self.imageContentMode
}
}
func updateScale() {
private func updateScale() {
if self.motionEnabled {
let scale = (self.frame.width + motionAmount * 2.0) / self.frame.width
self.contentNode.transform = CATransform3DMakeScale(scale, scale, 1.0)
@ -78,14 +86,70 @@ public final class WallpaperBackgroundNode: ASDisplayNode {
self.contentNode.frame = self.bounds
self.addSubnode(self.contentNode)
}
public func update(wallpaper: TelegramWallpaper) {
if self.wallpaper == wallpaper {
return
}
self.wallpaper = wallpaper
if wallpaper.isBuiltin {
if self.gradientBackgroundNode == nil {
let gradientBackgroundNode = createGradientBackgroundNode()
self.gradientBackgroundNode = gradientBackgroundNode
self.addSubnode(gradientBackgroundNode)
}
self.contentNode.isHidden = true
} else {
if let gradientBackgroundNode = self.gradientBackgroundNode {
self.gradientBackgroundNode = nil
gradientBackgroundNode.removeFromSupernode()
}
if case .gradient = wallpaper {
self.imageContentMode = .scaleToFill
} else {
self.imageContentMode = .scaleAspectFill
}
self.motionEnabled = wallpaper.settings?.motion ?? false
self.contentNode.isHidden = false
}
if let size = self.validLayout {
self.updateLayout(size: size, transition: .immediate)
}
}
public func updateLayout(size: CGSize, transition: ContainedViewLayoutTransition) {
let isFirstLayout = self.contentNode.frame.isEmpty
let isFirstLayout = self.validLayout == nil
self.validLayout = size
transition.updatePosition(node: self.contentNode, position: CGPoint(x: size.width / 2.0, y: size.height / 2.0))
transition.updateBounds(node: self.contentNode, bounds: CGRect(origin: CGPoint(), size: size))
if let gradientBackgroundNode = self.gradientBackgroundNode {
transition.updateFrame(node: gradientBackgroundNode, frame: CGRect(origin: CGPoint(), size: size))
gradientBackgroundNode.updateLayout(size: size, transition: transition)
}
if isFirstLayout && !self.frame.isEmpty {
self.updateScale()
}
}
public func animateEvent(transition: ContainedViewLayoutTransition) {
guard let wallpaper = self.wallpaper else {
return
}
switch wallpaper {
case let .builtin(settings):
if !settings.motion {
//return
}
default:
break
}
self.gradientBackgroundNode?.animateEvent(transition: transition)
}
}