mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-06-16 05:55:20 +00:00
Merge commit '09c00161fed42f33bb77775a00a648d9351db3ca'
This commit is contained in:
commit
12a2c1c948
@ -372,8 +372,9 @@ public class AttachmentController: ViewController {
|
||||
self.container.position = startPosition
|
||||
let transition = ContainedViewLayoutTransition.animated(duration: 0.4, curve: .spring)
|
||||
transition.animateView(allowUserInteraction: true, {
|
||||
self.animating = false
|
||||
self.container.position = targetPosition
|
||||
}, completion: { _ in
|
||||
self.animating = false
|
||||
})
|
||||
}
|
||||
}
|
||||
|
22
submodules/ChatMessageBackground/BUILD
Normal file
22
submodules/ChatMessageBackground/BUILD
Normal file
@ -0,0 +1,22 @@
|
||||
load("@build_bazel_rules_swift//swift:swift.bzl", "swift_library")
|
||||
|
||||
swift_library(
|
||||
name = "ChatMessageBackground",
|
||||
module_name = "ChatMessageBackground",
|
||||
srcs = glob([
|
||||
"Sources/**/*.swift",
|
||||
]),
|
||||
copts = [
|
||||
"-warnings-as-errors",
|
||||
],
|
||||
deps = [
|
||||
"//submodules/AsyncDisplayKit:AsyncDisplayKit",
|
||||
"//submodules/Display:Display",
|
||||
"//submodules/Postbox:Postbox",
|
||||
"//submodules/TelegramPresentationData:TelegramPresentationData",
|
||||
"//submodules/WallpaperBackgroundNode:WallpaperBackgroundNode",
|
||||
],
|
||||
visibility = [
|
||||
"//visibility:public",
|
||||
],
|
||||
)
|
22
submodules/ChatMessageBackground/Info.plist
Normal file
22
submodules/ChatMessageBackground/Info.plist
Normal file
@ -0,0 +1,22 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CFBundleDevelopmentRegion</key>
|
||||
<string>$(DEVELOPMENT_LANGUAGE)</string>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>$(EXECUTABLE_NAME)</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<key>CFBundleName</key>
|
||||
<string>$(PRODUCT_NAME)</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>FMWK</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>1.0</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>$(CURRENT_PROJECT_VERSION)</string>
|
||||
</dict>
|
||||
</plist>
|
@ -2,13 +2,14 @@ import Foundation
|
||||
import UIKit
|
||||
import AsyncDisplayKit
|
||||
import Display
|
||||
import Postbox
|
||||
import TelegramPresentationData
|
||||
import WallpaperBackgroundNode
|
||||
|
||||
enum ChatMessageBackgroundMergeType: Equatable {
|
||||
public enum ChatMessageBackgroundMergeType: Equatable {
|
||||
case None, Side, Top(side: Bool), Bottom, Both, Extracted
|
||||
|
||||
init(top: Bool, bottom: Bool, side: Bool) {
|
||||
public init(top: Bool, bottom: Bool, side: Bool) {
|
||||
if top && bottom {
|
||||
self = .Both
|
||||
} else if top {
|
||||
@ -29,12 +30,12 @@ enum ChatMessageBackgroundMergeType: Equatable {
|
||||
}
|
||||
}
|
||||
|
||||
enum ChatMessageBackgroundType: Equatable {
|
||||
public enum ChatMessageBackgroundType: Equatable {
|
||||
case none
|
||||
case incoming(ChatMessageBackgroundMergeType)
|
||||
case outgoing(ChatMessageBackgroundMergeType)
|
||||
|
||||
static func ==(lhs: ChatMessageBackgroundType, rhs: ChatMessageBackgroundType) -> Bool {
|
||||
public static func ==(lhs: ChatMessageBackgroundType, rhs: ChatMessageBackgroundType) -> Bool {
|
||||
switch lhs {
|
||||
case .none:
|
||||
if case .none = rhs {
|
||||
@ -58,8 +59,8 @@ enum ChatMessageBackgroundType: Equatable {
|
||||
}
|
||||
}
|
||||
|
||||
class ChatMessageBackground: ASDisplayNode {
|
||||
private(set) var type: ChatMessageBackgroundType?
|
||||
public class ChatMessageBackground: ASDisplayNode {
|
||||
public private(set) var type: ChatMessageBackgroundType?
|
||||
private var currentHighlighted: Bool?
|
||||
private var hasWallpaper: Bool?
|
||||
private var graphics: PrincipalThemeEssentialGraphics?
|
||||
@ -68,11 +69,11 @@ class ChatMessageBackground: ASDisplayNode {
|
||||
private let outlineImageNode: ASImageNode
|
||||
private weak var backgroundNode: WallpaperBackgroundNode?
|
||||
|
||||
var hasImage: Bool {
|
||||
public var hasImage: Bool {
|
||||
self.imageNode.image != nil
|
||||
}
|
||||
|
||||
override init() {
|
||||
public override init() {
|
||||
self.imageNode = ASImageNode()
|
||||
self.imageNode.displaysAsynchronously = false
|
||||
self.imageNode.displayWithoutProcessing = true
|
||||
@ -88,23 +89,23 @@ class ChatMessageBackground: ASDisplayNode {
|
||||
self.addSubnode(self.imageNode)
|
||||
}
|
||||
|
||||
func updateLayout(size: CGSize, transition: ContainedViewLayoutTransition) {
|
||||
public func updateLayout(size: CGSize, transition: ContainedViewLayoutTransition) {
|
||||
transition.updateFrame(node: self.imageNode, frame: CGRect(origin: CGPoint(), size: size).insetBy(dx: -1.0, dy: -1.0))
|
||||
transition.updateFrame(node: self.outlineImageNode, frame: CGRect(origin: CGPoint(), size: size).insetBy(dx: -1.0, dy: -1.0))
|
||||
}
|
||||
|
||||
func updateLayout(size: CGSize, transition: ListViewItemUpdateAnimation) {
|
||||
public func updateLayout(size: CGSize, transition: ListViewItemUpdateAnimation) {
|
||||
transition.animator.updateFrame(layer: self.imageNode.layer, frame: CGRect(origin: CGPoint(), size: size).insetBy(dx: -1.0, dy: -1.0), completion: nil)
|
||||
transition.animator.updateFrame(layer: self.outlineImageNode.layer, frame: CGRect(origin: CGPoint(), size: size).insetBy(dx: -1.0, dy: -1.0), completion: nil)
|
||||
}
|
||||
|
||||
func setMaskMode(_ maskMode: Bool) {
|
||||
public func setMaskMode(_ maskMode: Bool) {
|
||||
if let type = self.type, let hasWallpaper = self.hasWallpaper, let highlighted = self.currentHighlighted, let graphics = self.graphics, let backgroundNode = self.backgroundNode {
|
||||
self.setType(type: type, highlighted: highlighted, graphics: graphics, maskMode: maskMode, hasWallpaper: hasWallpaper, transition: .immediate, backgroundNode: backgroundNode)
|
||||
}
|
||||
}
|
||||
|
||||
func setType(type: ChatMessageBackgroundType, highlighted: Bool, graphics: PrincipalThemeEssentialGraphics, maskMode: Bool, hasWallpaper: Bool, transition: ContainedViewLayoutTransition, backgroundNode: WallpaperBackgroundNode?) {
|
||||
public func setType(type: ChatMessageBackgroundType, highlighted: Bool, graphics: PrincipalThemeEssentialGraphics, maskMode: Bool, hasWallpaper: Bool, transition: ContainedViewLayoutTransition, backgroundNode: WallpaperBackgroundNode?) {
|
||||
let previousType = self.type
|
||||
if let currentType = previousType, currentType == type, self.currentHighlighted == highlighted, self.graphics === graphics, backgroundNode === self.backgroundNode, self.maskMode == maskMode, self.hasWallpaper == hasWallpaper {
|
||||
return
|
||||
@ -244,7 +245,7 @@ class ChatMessageBackground: ASDisplayNode {
|
||||
self.outlineImageNode.image = outlineImage
|
||||
}
|
||||
|
||||
func animateFrom(sourceView: UIView, transition: CombinedTransition) {
|
||||
public func animateFrom(sourceView: UIView, transition: CombinedTransition) {
|
||||
if transition.isAnimated {
|
||||
self.imageNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.1)
|
||||
self.outlineImageNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.1)
|
||||
@ -262,11 +263,11 @@ class ChatMessageBackground: ASDisplayNode {
|
||||
}
|
||||
}
|
||||
|
||||
final class ChatMessageShadowNode: ASDisplayNode {
|
||||
public final class ChatMessageShadowNode: ASDisplayNode {
|
||||
private let contentNode: ASImageNode
|
||||
private var graphics: PrincipalThemeEssentialGraphics?
|
||||
|
||||
override init() {
|
||||
public override init() {
|
||||
self.contentNode = ASImageNode()
|
||||
self.contentNode.isLayerBacked = true
|
||||
self.contentNode.displaysAsynchronously = false
|
||||
@ -281,7 +282,7 @@ final class ChatMessageShadowNode: ASDisplayNode {
|
||||
self.addSubnode(self.contentNode)
|
||||
}
|
||||
|
||||
func setType(type: ChatMessageBackgroundType, hasWallpaper: Bool, graphics: PrincipalThemeEssentialGraphics) {
|
||||
public func setType(type: ChatMessageBackgroundType, hasWallpaper: Bool, graphics: PrincipalThemeEssentialGraphics) {
|
||||
let shadowImage: UIImage?
|
||||
|
||||
if hasWallpaper {
|
||||
@ -334,7 +335,256 @@ final class ChatMessageShadowNode: ASDisplayNode {
|
||||
self.contentNode.image = shadowImage
|
||||
}
|
||||
|
||||
func updateLayout(backgroundFrame: CGRect, transition: ContainedViewLayoutTransition) {
|
||||
public func updateLayout(backgroundFrame: CGRect, transition: ContainedViewLayoutTransition) {
|
||||
transition.updateFrame(node: self.contentNode, frame: CGRect(origin: CGPoint(x: backgroundFrame.minX - 10.0, y: backgroundFrame.minY - 10.0), size: CGSize(width: backgroundFrame.width + 20.0, height: backgroundFrame.height + 20.0)))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private let maskInset: CGFloat = 1.0
|
||||
|
||||
public func bubbleMaskForType(_ type: ChatMessageBackgroundType, graphics: PrincipalThemeEssentialGraphics) -> UIImage? {
|
||||
let image: UIImage?
|
||||
switch type {
|
||||
case .none:
|
||||
image = nil
|
||||
case let .incoming(mergeType):
|
||||
switch mergeType {
|
||||
case .None:
|
||||
image = graphics.chatMessageBackgroundIncomingMaskImage
|
||||
case let .Top(side):
|
||||
if side {
|
||||
image = graphics.chatMessageBackgroundIncomingMergedTopSideMaskImage
|
||||
} else {
|
||||
image = graphics.chatMessageBackgroundIncomingMergedTopMaskImage
|
||||
}
|
||||
case .Bottom:
|
||||
image = graphics.chatMessageBackgroundIncomingMergedBottomMaskImage
|
||||
case .Both:
|
||||
image = graphics.chatMessageBackgroundIncomingMergedBothMaskImage
|
||||
case .Side:
|
||||
image = graphics.chatMessageBackgroundIncomingMergedSideMaskImage
|
||||
case .Extracted:
|
||||
image = graphics.chatMessageBackgroundIncomingExtractedMaskImage
|
||||
}
|
||||
case let .outgoing(mergeType):
|
||||
switch mergeType {
|
||||
case .None:
|
||||
image = graphics.chatMessageBackgroundOutgoingMaskImage
|
||||
case let .Top(side):
|
||||
if side {
|
||||
image = graphics.chatMessageBackgroundOutgoingMergedTopSideMaskImage
|
||||
} else {
|
||||
image = graphics.chatMessageBackgroundOutgoingMergedTopMaskImage
|
||||
}
|
||||
case .Bottom:
|
||||
image = graphics.chatMessageBackgroundOutgoingMergedBottomMaskImage
|
||||
case .Both:
|
||||
image = graphics.chatMessageBackgroundOutgoingMergedBothMaskImage
|
||||
case .Side:
|
||||
image = graphics.chatMessageBackgroundOutgoingMergedSideMaskImage
|
||||
case .Extracted:
|
||||
image = graphics.chatMessageBackgroundOutgoingExtractedMaskImage
|
||||
}
|
||||
}
|
||||
return image
|
||||
}
|
||||
|
||||
public final class ChatMessageBubbleBackdrop: ASDisplayNode {
|
||||
private var backgroundContent: WallpaperBubbleBackgroundNode?
|
||||
|
||||
private var currentType: ChatMessageBackgroundType?
|
||||
private var currentMaskMode: Bool?
|
||||
private var theme: ChatPresentationThemeData?
|
||||
private var essentialGraphics: PrincipalThemeEssentialGraphics?
|
||||
private weak var backgroundNode: WallpaperBackgroundNode?
|
||||
|
||||
private var maskView: UIImageView?
|
||||
private var fixedMaskMode: Bool?
|
||||
|
||||
private var absolutePosition: (CGRect, CGSize)?
|
||||
|
||||
public var hasImage: Bool {
|
||||
return self.backgroundContent != nil
|
||||
}
|
||||
|
||||
public override var frame: CGRect {
|
||||
didSet {
|
||||
if let maskView = self.maskView {
|
||||
let maskFrame = self.bounds.insetBy(dx: -maskInset, dy: -maskInset)
|
||||
if maskView.frame != maskFrame {
|
||||
maskView.frame = maskFrame
|
||||
}
|
||||
}
|
||||
if let backgroundContent = self.backgroundContent {
|
||||
backgroundContent.frame = self.bounds
|
||||
if let (rect, containerSize) = self.absolutePosition {
|
||||
var backgroundFrame = backgroundContent.frame
|
||||
backgroundFrame.origin.x += rect.minX
|
||||
backgroundFrame.origin.y += rect.minY
|
||||
backgroundContent.update(rect: backgroundFrame, within: containerSize, transition: .immediate)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override init() {
|
||||
super.init()
|
||||
|
||||
self.clipsToBounds = true
|
||||
}
|
||||
|
||||
public func setMaskMode(_ maskMode: Bool, mediaBox: MediaBox) {
|
||||
if let currentType = self.currentType, let theme = self.theme, let essentialGraphics = self.essentialGraphics, let backgroundNode = self.backgroundNode {
|
||||
self.setType(type: currentType, theme: theme, essentialGraphics: essentialGraphics, maskMode: maskMode, backgroundNode: backgroundNode)
|
||||
}
|
||||
}
|
||||
|
||||
public func setType(type: ChatMessageBackgroundType, theme: ChatPresentationThemeData, essentialGraphics: PrincipalThemeEssentialGraphics, maskMode inputMaskMode: Bool, backgroundNode: WallpaperBackgroundNode?) {
|
||||
let maskMode = self.fixedMaskMode ?? inputMaskMode
|
||||
|
||||
if self.currentType != type || self.theme != theme || self.currentMaskMode != maskMode || self.essentialGraphics !== essentialGraphics || self.backgroundNode !== backgroundNode {
|
||||
let typeUpdated = self.currentType != type || self.theme != theme || self.currentMaskMode != maskMode || self.backgroundNode !== backgroundNode
|
||||
|
||||
self.currentType = type
|
||||
self.theme = theme
|
||||
self.essentialGraphics = essentialGraphics
|
||||
self.backgroundNode = backgroundNode
|
||||
|
||||
if maskMode != self.currentMaskMode {
|
||||
self.currentMaskMode = maskMode
|
||||
|
||||
if maskMode {
|
||||
let maskView: UIImageView
|
||||
if let current = self.maskView {
|
||||
maskView = current
|
||||
} else {
|
||||
maskView = UIImageView()
|
||||
maskView.frame = self.bounds.insetBy(dx: -maskInset, dy: -maskInset)
|
||||
self.maskView = maskView
|
||||
self.view.mask = maskView
|
||||
}
|
||||
} else {
|
||||
if let _ = self.maskView {
|
||||
self.view.mask = nil
|
||||
self.maskView = nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if let backgroundContent = self.backgroundContent {
|
||||
backgroundContent.frame = self.bounds
|
||||
if let (rect, containerSize) = self.absolutePosition {
|
||||
var backgroundFrame = backgroundContent.frame
|
||||
backgroundFrame.origin.x += rect.minX
|
||||
backgroundFrame.origin.y += rect.minY
|
||||
backgroundContent.update(rect: backgroundFrame, within: containerSize, transition: .immediate)
|
||||
}
|
||||
}
|
||||
|
||||
if typeUpdated {
|
||||
if let backgroundContent = self.backgroundContent {
|
||||
self.backgroundContent = nil
|
||||
backgroundContent.removeFromSupernode()
|
||||
}
|
||||
|
||||
switch type {
|
||||
case .none:
|
||||
break
|
||||
case .incoming:
|
||||
if let backgroundContent = backgroundNode?.makeBubbleBackground(for: .incoming) {
|
||||
backgroundContent.frame = self.bounds
|
||||
if let (rect, containerSize) = self.absolutePosition {
|
||||
var backgroundFrame = backgroundContent.frame
|
||||
backgroundFrame.origin.x += rect.minX
|
||||
backgroundFrame.origin.y += rect.minY
|
||||
backgroundContent.update(rect: backgroundFrame, within: containerSize, transition: .immediate)
|
||||
}
|
||||
self.backgroundContent = backgroundContent
|
||||
self.insertSubnode(backgroundContent, at: 0)
|
||||
}
|
||||
case .outgoing:
|
||||
if let backgroundContent = backgroundNode?.makeBubbleBackground(for: .outgoing) {
|
||||
backgroundContent.frame = self.bounds
|
||||
if let (rect, containerSize) = self.absolutePosition {
|
||||
var backgroundFrame = backgroundContent.frame
|
||||
backgroundFrame.origin.x += rect.minX
|
||||
backgroundFrame.origin.y += rect.minY
|
||||
backgroundContent.update(rect: backgroundFrame, within: containerSize, transition: .immediate)
|
||||
}
|
||||
self.backgroundContent = backgroundContent
|
||||
self.insertSubnode(backgroundContent, at: 0)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if let maskView = self.maskView {
|
||||
maskView.image = bubbleMaskForType(type, graphics: essentialGraphics)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public func update(rect: CGRect, within containerSize: CGSize, transition: ContainedViewLayoutTransition = .immediate) {
|
||||
self.absolutePosition = (rect, containerSize)
|
||||
if let backgroundContent = self.backgroundContent {
|
||||
var backgroundFrame = backgroundContent.frame
|
||||
backgroundFrame.origin.x += rect.minX
|
||||
backgroundFrame.origin.y += rect.minY
|
||||
backgroundContent.update(rect: backgroundFrame, within: containerSize, transition: transition)
|
||||
}
|
||||
}
|
||||
|
||||
public func offset(value: CGPoint, animationCurve: ContainedViewLayoutTransitionCurve, duration: Double) {
|
||||
self.backgroundContent?.offset(value: value, animationCurve: animationCurve, duration: duration)
|
||||
}
|
||||
|
||||
public func offsetSpring(value: CGFloat, duration: Double, damping: CGFloat) {
|
||||
self.backgroundContent?.offsetSpring(value: value, duration: duration, damping: damping)
|
||||
}
|
||||
|
||||
public func updateFrame(_ value: CGRect, transition: ContainedViewLayoutTransition, completion: @escaping () -> Void = {}) {
|
||||
if let maskView = self.maskView {
|
||||
transition.updateFrame(view: maskView, frame: CGRect(origin: CGPoint(x: 0.0, y: 0.0), size: CGSize(width: value.size.width, height: value.size.height)).insetBy(dx: -maskInset, dy: -maskInset))
|
||||
}
|
||||
if let backgroundContent = self.backgroundContent {
|
||||
transition.updateFrame(layer: backgroundContent.layer, frame: CGRect(origin: CGPoint(x: 0.0, y: 0.0), size: CGSize(width: value.size.width, height: value.size.height)))
|
||||
if let (rect, containerSize) = self.absolutePosition {
|
||||
var backgroundFrame = backgroundContent.frame
|
||||
backgroundFrame.origin.x += rect.minX
|
||||
backgroundFrame.origin.y += rect.minY
|
||||
backgroundContent.update(rect: backgroundFrame, within: containerSize, transition: transition)
|
||||
}
|
||||
}
|
||||
transition.updateFrame(node: self, frame: value, completion: { _ in
|
||||
completion()
|
||||
})
|
||||
}
|
||||
|
||||
public func updateFrame(_ value: CGRect, transition: CombinedTransition, completion: @escaping () -> Void = {}) {
|
||||
if let maskView = self.maskView {
|
||||
transition.updateFrame(layer: maskView.layer, frame: CGRect(origin: CGPoint(x: 0.0, y: 0.0), size: CGSize(width: value.size.width, height: value.size.height)).insetBy(dx: -maskInset, dy: -maskInset))
|
||||
}
|
||||
if let backgroundContent = self.backgroundContent {
|
||||
transition.updateFrame(layer: backgroundContent.layer, frame: CGRect(origin: CGPoint(x: 0.0, y: 0.0), size: CGSize(width: value.size.width, height: value.size.height)))
|
||||
if let (rect, containerSize) = self.absolutePosition {
|
||||
var backgroundFrame = backgroundContent.frame
|
||||
backgroundFrame.origin.x += rect.minX
|
||||
backgroundFrame.origin.y += rect.minY
|
||||
backgroundContent.update(rect: backgroundFrame, within: containerSize, transition: transition)
|
||||
}
|
||||
}
|
||||
transition.updateFrame(layer: self.layer, frame: value, completion: { _ in
|
||||
completion()
|
||||
})
|
||||
}
|
||||
|
||||
public func animateFrom(sourceView: UIView, mediaBox: MediaBox, transition: CombinedTransition) {
|
||||
if transition.isAnimated {
|
||||
let previousFrame = self.frame
|
||||
self.updateFrame(CGRect(origin: CGPoint(x: previousFrame.minX, y: sourceView.frame.minY), size: sourceView.frame.size), transition: .immediate)
|
||||
self.updateFrame(previousFrame, transition: transition)
|
||||
|
||||
self.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.1)
|
||||
}
|
||||
}
|
||||
}
|
@ -362,8 +362,6 @@ class CreatePollOptionItemNode: ItemListRevealOptionsItemNode, ItemListItemNode,
|
||||
if let checkNode = strongSelf.checkNode {
|
||||
transition.updateFrame(node: checkNode, frame: checkFrame)
|
||||
checkNode.setSelected(isSelected, animated: true)
|
||||
|
||||
transition.updateAlpha(node: checkNode, alpha: strongSelf.textNode.textView.text.isEmpty ? 0.0 : 1.0)
|
||||
} else {
|
||||
let checkNode = InteractiveCheckNode(theme: CheckNodeTheme(backgroundColor: item.presentationData.theme.list.itemSwitchColors.positiveColor, strokeColor: item.presentationData.theme.list.itemCheckColors.foregroundColor, borderColor: item.presentationData.theme.list.itemCheckColors.strokeColor, overlayBorder: false, hasInset: false, hasShadow: false))
|
||||
checkNode.setSelected(isSelected, animated: false)
|
||||
@ -374,8 +372,10 @@ class CreatePollOptionItemNode: ItemListRevealOptionsItemNode, ItemListItemNode,
|
||||
strongSelf.containerNode.addSubnode(checkNode)
|
||||
checkNode.frame = checkFrame
|
||||
transition.animatePositionAdditive(node: checkNode, offset: CGPoint(x: -checkFrame.maxX, y: 0.0))
|
||||
|
||||
transition.updateAlpha(node: checkNode, alpha: strongSelf.textNode.textView.text.isEmpty ? 0.0 : 1.0)
|
||||
}
|
||||
|
||||
if let checkNode = strongSelf.checkNode {
|
||||
transition.updateAlpha(node: checkNode, alpha: strongSelf.textNode.textView.text.isEmpty && item.placeholder == item.presentationData.strings.CreatePoll_AddOption ? 0.0 : 1.0)
|
||||
}
|
||||
} else if let checkNode = strongSelf.checkNode {
|
||||
strongSelf.checkNode = nil
|
||||
|
@ -1646,7 +1646,7 @@
|
||||
|
||||
_selectedPhotosView.frame = CGRectMake(screenEdges.left + TGPhotoEditorToolbarSize + 66 + _safeAreaInset.left, screenEdges.top + 4 + headerInset, photosViewSize, self.frame.size.height - 4 * 2 - headerInset);
|
||||
|
||||
_landscapeToolbarView.frame = CGRectMake(screenEdges.left, screenEdges.top, TGPhotoEditorToolbarSize + _safeAreaInset.left, self.frame.size.height);
|
||||
_landscapeToolbarView.frame = CGRectMake(screenEdges.left + _safeAreaInset.left, screenEdges.top, TGPhotoEditorToolbarSize + _safeAreaInset.left, self.frame.size.height);
|
||||
}];
|
||||
|
||||
_headerWrapperView.frame = CGRectMake(screenEdges.left + TGPhotoEditorToolbarSize + _safeAreaInset.left, screenEdges.top, self.frame.size.width - TGPhotoEditorToolbarSize - _safeAreaInset.left, 64);
|
||||
|
@ -222,13 +222,21 @@
|
||||
_currentEdgeInsets = edgeInsets;
|
||||
|
||||
CGFloat panelHeight = [_inputPanel updateLayoutSize:frame.size sideInset:0.0];
|
||||
_inputPanelView.frame = CGRectMake(edgeInsets.left, frame.size.height - panelHeight - MAX(edgeInsets.bottom, _keyboardHeight), frame.size.width, panelHeight);
|
||||
|
||||
CGFloat y = 0.0;
|
||||
if (frame.size.width > frame.size.height) {
|
||||
y = edgeInsets.top + frame.size.height;
|
||||
} else {
|
||||
y = edgeInsets.top + frame.size.height - panelHeight - MAX(edgeInsets.bottom, _keyboardHeight);
|
||||
}
|
||||
|
||||
_inputPanelView.frame = CGRectMake(edgeInsets.left, y, frame.size.width, panelHeight);
|
||||
|
||||
CGFloat backgroundHeight = panelHeight;
|
||||
if (_keyboardHeight > 0.0) {
|
||||
backgroundHeight += _keyboardHeight - edgeInsets.bottom;
|
||||
}
|
||||
_backgroundView.frame = CGRectMake(edgeInsets.left, frame.size.height - panelHeight - MAX(edgeInsets.bottom, _keyboardHeight), frame.size.width, backgroundHeight);
|
||||
_backgroundView.frame = CGRectMake(edgeInsets.left, y, frame.size.width, backgroundHeight);
|
||||
}
|
||||
|
||||
@end
|
||||
|
@ -37,6 +37,7 @@ swift_library(
|
||||
"//submodules/PresentationDataUtils:PresentationDataUtils",
|
||||
"//submodules/WallpaperBackgroundNode:WallpaperBackgroundNode",
|
||||
"//submodules/WebSearchUI:WebSearchUI",
|
||||
"//submodules/ChatMessageBackground:ChatMessageBackground",
|
||||
],
|
||||
visibility = [
|
||||
"//visibility:public",
|
||||
|
@ -74,7 +74,7 @@ enum LegacyMediaPickerGallerySource {
|
||||
case selection(item: TGMediaSelectableItem)
|
||||
}
|
||||
|
||||
func presentLegacyMediaPickerGallery(context: AccountContext, peer: EnginePeer?, chatLocation: ChatLocation?, presentationData: PresentationData, source: LegacyMediaPickerGallerySource, immediateThumbnail: UIImage?, selectionContext: TGMediaSelectionContext?, editingContext: TGMediaEditingContext, hasSilentPosting: Bool, hasSchedule: Bool, hasTimer: Bool, updateHiddenMedia: @escaping (String?) -> Void, initialLayout: ContainerViewLayout?, transitionHostView: @escaping () -> UIView?, transitionView: @escaping (String) -> UIView?, completed: @escaping (TGMediaSelectableItem & TGMediaEditableItem, Bool, Int32?) -> Void, presentStickers: ((@escaping (TelegramMediaFile, Bool, UIView, CGRect) -> Void) -> TGPhotoPaintStickersScreen?)?, presentSchedulePicker: @escaping (Bool, @escaping (Int32) -> Void) -> Void, presentTimerPicker: @escaping (@escaping (Int32) -> Void) -> Void, getCaptionPanelView: @escaping () -> TGCaptionPanelView?, present: @escaping (ViewController, Any?) -> Void, finishedTransitionIn: @escaping () -> Void, dismissAll: @escaping () -> Void) {
|
||||
func presentLegacyMediaPickerGallery(context: AccountContext, peer: EnginePeer?, chatLocation: ChatLocation?, presentationData: PresentationData, source: LegacyMediaPickerGallerySource, immediateThumbnail: UIImage?, selectionContext: TGMediaSelectionContext?, editingContext: TGMediaEditingContext, hasSilentPosting: Bool, hasSchedule: Bool, hasTimer: Bool, updateHiddenMedia: @escaping (String?) -> Void, initialLayout: ContainerViewLayout?, transitionHostView: @escaping () -> UIView?, transitionView: @escaping (String) -> UIView?, completed: @escaping (TGMediaSelectableItem & TGMediaEditableItem, Bool, Int32?) -> Void, presentStickers: ((@escaping (TelegramMediaFile, Bool, UIView, CGRect) -> Void) -> TGPhotoPaintStickersScreen?)?, presentSchedulePicker: @escaping (Bool, @escaping (Int32) -> Void) -> Void, presentTimerPicker: @escaping (@escaping (Int32) -> Void) -> Void, getCaptionPanelView: @escaping () -> TGCaptionPanelView?, present: @escaping (ViewController, Any?) -> Void, finishedTransitionIn: @escaping () -> Void, willTransitionOut: @escaping () -> Void, dismissAll: @escaping () -> Void) {
|
||||
let reminder = peer?.id == context.account.peerId
|
||||
|
||||
let legacyController = LegacyController(presentation: .custom, theme: presentationData.theme, initialLayout: nil)
|
||||
@ -168,6 +168,8 @@ func presentLegacyMediaPickerGallery(context: AccountContext, peer: EnginePeer?,
|
||||
}
|
||||
}
|
||||
controller.beginTransitionOut = { item, itemView in
|
||||
willTransitionOut()
|
||||
|
||||
if let item = item as? TGMediaPickerGalleryItem {
|
||||
if let itemView = itemView as? TGMediaPickerGalleryVideoItemView {
|
||||
itemView.stop()
|
||||
|
@ -301,6 +301,7 @@ public final class MediaPickerScreen: ViewController, AttachmentContainable {
|
||||
cameraView.removeCorners()
|
||||
cameraView.pressed = { [weak self] in
|
||||
if let strongSelf = self, !strongSelf.openingMedia {
|
||||
strongSelf.dismissInput()
|
||||
strongSelf.controller?.openCamera?(strongSelf.cameraView)
|
||||
}
|
||||
}
|
||||
@ -500,6 +501,9 @@ public final class MediaPickerScreen: ViewController, AttachmentContainable {
|
||||
self?.controller?.present(c, in: .window(.root), with: a)
|
||||
}, finishedTransitionIn: { [weak self] in
|
||||
self?.openingMedia = false
|
||||
self?.cameraView?.pausePreview()
|
||||
}, willTransitionOut: { [weak self] in
|
||||
self?.cameraView?.resumePreview()
|
||||
}, dismissAll: { [weak self] in
|
||||
self?.controller?.dismissAll()
|
||||
})
|
||||
@ -533,6 +537,9 @@ public final class MediaPickerScreen: ViewController, AttachmentContainable {
|
||||
self?.controller?.present(c, in: .window(.root), with: a, blockInteraction: true)
|
||||
}, finishedTransitionIn: { [weak self] in
|
||||
self?.openingMedia = false
|
||||
self?.cameraView?.pausePreview()
|
||||
}, willTransitionOut: { [weak self] in
|
||||
self?.cameraView?.resumePreview()
|
||||
}, dismissAll: { [weak self] in
|
||||
self?.controller?.dismissAll()
|
||||
})
|
||||
@ -848,6 +855,7 @@ public final class MediaPickerScreen: ViewController, AttachmentContainable {
|
||||
self?.controller?.context.sharedContext.applicationBindings.openSettings()
|
||||
}
|
||||
placeholderNode.cameraPressed = { [weak self] in
|
||||
self?.dismissInput()
|
||||
self?.controller?.openCamera?(nil)
|
||||
}
|
||||
self.containerNode.insertSubnode(placeholderNode, aboveSubnode: self.gridNode)
|
||||
|
@ -11,6 +11,8 @@ import CheckNode
|
||||
import MosaicLayout
|
||||
import WallpaperBackgroundNode
|
||||
import AccountContext
|
||||
import ChatMessageBackground
|
||||
|
||||
|
||||
private class MediaPickerSelectedItemNode: ASDisplayNode {
|
||||
let asset: TGMediaAsset
|
||||
@ -189,12 +191,56 @@ private class MediaPickerSelectedItemNode: ASDisplayNode {
|
||||
}
|
||||
}
|
||||
|
||||
private class MessageBackgroundNode: ASDisplayNode {
|
||||
private let backgroundWallpaperNode: ChatMessageBubbleBackdrop
|
||||
private let backgroundNode: ChatMessageBackground
|
||||
private let shadowNode: ChatMessageShadowNode
|
||||
|
||||
override init() {
|
||||
self.backgroundWallpaperNode = ChatMessageBubbleBackdrop()
|
||||
self.backgroundNode = ChatMessageBackground()
|
||||
self.shadowNode = ChatMessageShadowNode()
|
||||
|
||||
super.init()
|
||||
|
||||
self.addSubnode(self.backgroundWallpaperNode)
|
||||
self.addSubnode(self.backgroundNode)
|
||||
}
|
||||
|
||||
private var absoluteRect: (CGRect, CGSize)?
|
||||
|
||||
func update(size: CGSize, theme: PresentationTheme, wallpaper: TelegramWallpaper, graphics: PrincipalThemeEssentialGraphics, wallpaperBackgroundNode: WallpaperBackgroundNode, transition: ContainedViewLayoutTransition) {
|
||||
|
||||
self.backgroundNode.setType(type: .outgoing(.Extracted), highlighted: false, graphics: graphics, maskMode: false, hasWallpaper: wallpaper.hasWallpaper, transition: transition, backgroundNode: wallpaperBackgroundNode)
|
||||
self.backgroundWallpaperNode.setType(type: .outgoing(.Extracted), theme: ChatPresentationThemeData(theme: theme, wallpaper: wallpaper), essentialGraphics: graphics, maskMode: true, backgroundNode: wallpaperBackgroundNode)
|
||||
self.shadowNode.setType(type: .outgoing(.Extracted), hasWallpaper: wallpaper.hasWallpaper, graphics: graphics)
|
||||
|
||||
let backgroundFrame = CGRect(origin: CGPoint(), size: size)
|
||||
self.backgroundNode.updateLayout(size: backgroundFrame.size, transition: transition)
|
||||
self.backgroundWallpaperNode.updateFrame(backgroundFrame, transition: transition)
|
||||
self.shadowNode.updateLayout(backgroundFrame: backgroundFrame, transition: transition)
|
||||
|
||||
if let (rect, size) = self.absoluteRect {
|
||||
self.updateAbsoluteRect(rect, within: size)
|
||||
}
|
||||
}
|
||||
|
||||
func updateAbsoluteRect(_ rect: CGRect, within containerSize: CGSize) {
|
||||
self.absoluteRect = (rect, containerSize)
|
||||
|
||||
var backgroundWallpaperFrame = self.backgroundWallpaperNode.frame
|
||||
backgroundWallpaperFrame.origin.x += rect.minX
|
||||
backgroundWallpaperFrame.origin.y += rect.minY
|
||||
self.backgroundWallpaperNode.update(rect: backgroundWallpaperFrame, within: containerSize)
|
||||
}
|
||||
}
|
||||
|
||||
final class MediaPickerSelectedListNode: ASDisplayNode, UIScrollViewDelegate, UIGestureRecognizerDelegate {
|
||||
private let context: AccountContext
|
||||
|
||||
fileprivate let wallpaperBackgroundNode: WallpaperBackgroundNode
|
||||
private let scrollNode: ASScrollNode
|
||||
private var backgroundNodes: [Int: ASImageNode] = [:]
|
||||
private var backgroundNodes: [Int: MessageBackgroundNode] = [:]
|
||||
private var itemNodes: [String: MediaPickerSelectedItemNode] = [:]
|
||||
|
||||
private var reorderFeedback: HapticFeedback?
|
||||
@ -210,6 +256,7 @@ final class MediaPickerSelectedListNode: ASDisplayNode, UIScrollViewDelegate, UI
|
||||
init(context: AccountContext) {
|
||||
self.context = context
|
||||
self.wallpaperBackgroundNode = createWallpaperBackgroundNode(context: context, forChatDisplay: true, useSharedAnimationPhase: false, useExperimentalImplementation: context.sharedContext.immediateExperimentalUISettings.experimentalBackground)
|
||||
self.wallpaperBackgroundNode.backgroundColor = .black
|
||||
self.scrollNode = ASScrollNode()
|
||||
|
||||
super.init()
|
||||
@ -230,7 +277,7 @@ final class MediaPickerSelectedListNode: ASDisplayNode, UIScrollViewDelegate, UI
|
||||
self.scrollNode.view.showsVerticalScrollIndicator = false
|
||||
|
||||
self.view.addGestureRecognizer(ReorderingGestureRecognizer(shouldBegin: { [weak self] point in
|
||||
if let strongSelf = self, !strongSelf.scrollNode.view.isDragging {
|
||||
if let strongSelf = self, !strongSelf.scrollNode.view.isDragging && strongSelf.itemNodes.count > 1 {
|
||||
let point = strongSelf.view.convert(point, to: strongSelf.scrollNode.view)
|
||||
for (_, itemNode) in strongSelf.itemNodes {
|
||||
if itemNode.frame.contains(point) {
|
||||
@ -291,6 +338,15 @@ final class MediaPickerSelectedListNode: ASDisplayNode, UIScrollViewDelegate, UI
|
||||
absoluteRect.origin.y = size.height - absoluteRect.origin.y - absoluteRect.size.height
|
||||
itemNode.updateAbsoluteRect(absoluteRect, within: self.bounds.size)
|
||||
}
|
||||
|
||||
for (_, itemNode) in self.backgroundNodes {
|
||||
var absoluteRect = itemNode.frame
|
||||
if let supernode = self.supernode {
|
||||
absoluteRect = supernode.convert(itemNode.bounds, from: itemNode)
|
||||
}
|
||||
absoluteRect.origin.y = size.height - absoluteRect.origin.y - absoluteRect.size.height
|
||||
itemNode.updateAbsoluteRect(absoluteRect, within: self.bounds.size)
|
||||
}
|
||||
}
|
||||
|
||||
private func beginReordering(itemNode: MediaPickerSelectedItemNode) {
|
||||
@ -485,21 +541,24 @@ final class MediaPickerSelectedListNode: ASDisplayNode, UIScrollViewDelegate, UI
|
||||
previewNode.updateFrame(previewNodeFrame, within: size, updateFrame: false)
|
||||
}
|
||||
|
||||
let graphics = PresentationResourcesChat.principalGraphics(theme: theme, wallpaper: wallpaper, bubbleCorners: bubbleCorners)
|
||||
|
||||
var groupIndex = 0
|
||||
for (items, groupSize) in groupLayouts {
|
||||
let groupRect = CGRect(origin: CGPoint(x: insets.left + floorToScreenPixels((size.width - insets.left - insets.right - groupSize.width) / 2.0), y: insets.top + contentHeight), size: groupSize)
|
||||
|
||||
let groupBackgroundNode: ASImageNode
|
||||
let groupBackgroundNode: MessageBackgroundNode
|
||||
if let current = self.backgroundNodes[groupIndex] {
|
||||
groupBackgroundNode = current
|
||||
} else {
|
||||
groupBackgroundNode = ASImageNode()
|
||||
groupBackgroundNode = MessageBackgroundNode()
|
||||
groupBackgroundNode.displaysAsynchronously = false
|
||||
self.backgroundNodes[groupIndex] = groupBackgroundNode
|
||||
self.scrollNode.insertSubnode(groupBackgroundNode, at: 0)
|
||||
}
|
||||
groupBackgroundNode.image = self.graphics?.chatMessageBackgroundOutgoingExtractedImage
|
||||
transition.updateFrame(node: groupBackgroundNode, frame: groupRect.insetBy(dx: -6.0, dy: -3.0).offsetBy(dx: 3.0, dy: 0.0))
|
||||
|
||||
transition.updateFrame(node: groupBackgroundNode, frame: groupRect.insetBy(dx: -5.0, dy: -2.0).offsetBy(dx: 3.0, dy: 0.0))
|
||||
groupBackgroundNode.update(size: groupBackgroundNode.frame.size, theme: theme, wallpaper: wallpaper, graphics: graphics, wallpaperBackgroundNode: self.wallpaperBackgroundNode, transition: transition)
|
||||
|
||||
for (item, itemRect, itemPosition) in items {
|
||||
if let identifier = item.uniqueIdentifier, let itemNode = self.itemNodes[identifier] {
|
||||
|
@ -264,6 +264,7 @@ swift_library(
|
||||
"//submodules/ChatSendMessageActionUI:ChatSendMessageActionUI",
|
||||
"//submodules/ChatTextLinkEditUI:ChatTextLinkEditUI",
|
||||
"//submodules/MediaPickerUI:MediaPickerUI",
|
||||
"//submodules/ChatMessageBackground:ChatMessageBackground",
|
||||
] + select({
|
||||
"@build_bazel_rules_apple//apple:ios_armv7": [],
|
||||
"@build_bazel_rules_apple//apple:ios_arm64": appcenter_targets,
|
||||
|
@ -1,254 +0,0 @@
|
||||
import Foundation
|
||||
import AsyncDisplayKit
|
||||
import Display
|
||||
import Postbox
|
||||
import TelegramPresentationData
|
||||
import WallpaperBackgroundNode
|
||||
|
||||
private let maskInset: CGFloat = 1.0
|
||||
|
||||
func bubbleMaskForType(_ type: ChatMessageBackgroundType, graphics: PrincipalThemeEssentialGraphics) -> UIImage? {
|
||||
let image: UIImage?
|
||||
switch type {
|
||||
case .none:
|
||||
image = nil
|
||||
case let .incoming(mergeType):
|
||||
switch mergeType {
|
||||
case .None:
|
||||
image = graphics.chatMessageBackgroundIncomingMaskImage
|
||||
case let .Top(side):
|
||||
if side {
|
||||
image = graphics.chatMessageBackgroundIncomingMergedTopSideMaskImage
|
||||
} else {
|
||||
image = graphics.chatMessageBackgroundIncomingMergedTopMaskImage
|
||||
}
|
||||
case .Bottom:
|
||||
image = graphics.chatMessageBackgroundIncomingMergedBottomMaskImage
|
||||
case .Both:
|
||||
image = graphics.chatMessageBackgroundIncomingMergedBothMaskImage
|
||||
case .Side:
|
||||
image = graphics.chatMessageBackgroundIncomingMergedSideMaskImage
|
||||
case .Extracted:
|
||||
image = graphics.chatMessageBackgroundIncomingExtractedMaskImage
|
||||
}
|
||||
case let .outgoing(mergeType):
|
||||
switch mergeType {
|
||||
case .None:
|
||||
image = graphics.chatMessageBackgroundOutgoingMaskImage
|
||||
case let .Top(side):
|
||||
if side {
|
||||
image = graphics.chatMessageBackgroundOutgoingMergedTopSideMaskImage
|
||||
} else {
|
||||
image = graphics.chatMessageBackgroundOutgoingMergedTopMaskImage
|
||||
}
|
||||
case .Bottom:
|
||||
image = graphics.chatMessageBackgroundOutgoingMergedBottomMaskImage
|
||||
case .Both:
|
||||
image = graphics.chatMessageBackgroundOutgoingMergedBothMaskImage
|
||||
case .Side:
|
||||
image = graphics.chatMessageBackgroundOutgoingMergedSideMaskImage
|
||||
case .Extracted:
|
||||
image = graphics.chatMessageBackgroundOutgoingExtractedMaskImage
|
||||
}
|
||||
}
|
||||
return image
|
||||
}
|
||||
|
||||
final class ChatMessageBubbleBackdrop: ASDisplayNode {
|
||||
private var backgroundContent: WallpaperBubbleBackgroundNode?
|
||||
|
||||
private var currentType: ChatMessageBackgroundType?
|
||||
private var currentMaskMode: Bool?
|
||||
private var theme: ChatPresentationThemeData?
|
||||
private var essentialGraphics: PrincipalThemeEssentialGraphics?
|
||||
private weak var backgroundNode: WallpaperBackgroundNode?
|
||||
|
||||
private var maskView: UIImageView?
|
||||
private var fixedMaskMode: Bool?
|
||||
|
||||
private var absolutePosition: (CGRect, CGSize)?
|
||||
|
||||
var hasImage: Bool {
|
||||
return self.backgroundContent != nil
|
||||
}
|
||||
|
||||
override var frame: CGRect {
|
||||
didSet {
|
||||
if let maskView = self.maskView {
|
||||
let maskFrame = self.bounds.insetBy(dx: -maskInset, dy: -maskInset)
|
||||
if maskView.frame != maskFrame {
|
||||
maskView.frame = maskFrame
|
||||
}
|
||||
}
|
||||
if let backgroundContent = self.backgroundContent {
|
||||
backgroundContent.frame = self.bounds
|
||||
if let (rect, containerSize) = self.absolutePosition {
|
||||
var backgroundFrame = backgroundContent.frame
|
||||
backgroundFrame.origin.x += rect.minX
|
||||
backgroundFrame.origin.y += rect.minY
|
||||
backgroundContent.update(rect: backgroundFrame, within: containerSize, transition: .immediate)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override init() {
|
||||
super.init()
|
||||
|
||||
self.clipsToBounds = true
|
||||
}
|
||||
|
||||
func setMaskMode(_ maskMode: Bool, mediaBox: MediaBox) {
|
||||
if let currentType = self.currentType, let theme = self.theme, let essentialGraphics = self.essentialGraphics, let backgroundNode = self.backgroundNode {
|
||||
self.setType(type: currentType, theme: theme, essentialGraphics: essentialGraphics, maskMode: maskMode, backgroundNode: backgroundNode)
|
||||
}
|
||||
}
|
||||
|
||||
func setType(type: ChatMessageBackgroundType, theme: ChatPresentationThemeData, essentialGraphics: PrincipalThemeEssentialGraphics, maskMode inputMaskMode: Bool, backgroundNode: WallpaperBackgroundNode?) {
|
||||
let maskMode = self.fixedMaskMode ?? inputMaskMode
|
||||
|
||||
if self.currentType != type || self.theme != theme || self.currentMaskMode != maskMode || self.essentialGraphics !== essentialGraphics || self.backgroundNode !== backgroundNode {
|
||||
let typeUpdated = self.currentType != type || self.theme != theme || self.currentMaskMode != maskMode || self.backgroundNode !== backgroundNode
|
||||
|
||||
self.currentType = type
|
||||
self.theme = theme
|
||||
self.essentialGraphics = essentialGraphics
|
||||
self.backgroundNode = backgroundNode
|
||||
|
||||
if maskMode != self.currentMaskMode {
|
||||
self.currentMaskMode = maskMode
|
||||
|
||||
if maskMode {
|
||||
let maskView: UIImageView
|
||||
if let current = self.maskView {
|
||||
maskView = current
|
||||
} else {
|
||||
maskView = UIImageView()
|
||||
maskView.frame = self.bounds.insetBy(dx: -maskInset, dy: -maskInset)
|
||||
self.maskView = maskView
|
||||
self.view.mask = maskView
|
||||
}
|
||||
} else {
|
||||
if let _ = self.maskView {
|
||||
self.view.mask = nil
|
||||
self.maskView = nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if let backgroundContent = self.backgroundContent {
|
||||
backgroundContent.frame = self.bounds
|
||||
if let (rect, containerSize) = self.absolutePosition {
|
||||
var backgroundFrame = backgroundContent.frame
|
||||
backgroundFrame.origin.x += rect.minX
|
||||
backgroundFrame.origin.y += rect.minY
|
||||
backgroundContent.update(rect: backgroundFrame, within: containerSize, transition: .immediate)
|
||||
}
|
||||
}
|
||||
|
||||
if typeUpdated {
|
||||
if let backgroundContent = self.backgroundContent {
|
||||
self.backgroundContent = nil
|
||||
backgroundContent.removeFromSupernode()
|
||||
}
|
||||
|
||||
switch type {
|
||||
case .none:
|
||||
break
|
||||
case .incoming:
|
||||
if let backgroundContent = backgroundNode?.makeBubbleBackground(for: .incoming) {
|
||||
backgroundContent.frame = self.bounds
|
||||
if let (rect, containerSize) = self.absolutePosition {
|
||||
var backgroundFrame = backgroundContent.frame
|
||||
backgroundFrame.origin.x += rect.minX
|
||||
backgroundFrame.origin.y += rect.minY
|
||||
backgroundContent.update(rect: backgroundFrame, within: containerSize, transition: .immediate)
|
||||
}
|
||||
self.backgroundContent = backgroundContent
|
||||
self.insertSubnode(backgroundContent, at: 0)
|
||||
}
|
||||
case .outgoing:
|
||||
if let backgroundContent = backgroundNode?.makeBubbleBackground(for: .outgoing) {
|
||||
backgroundContent.frame = self.bounds
|
||||
if let (rect, containerSize) = self.absolutePosition {
|
||||
var backgroundFrame = backgroundContent.frame
|
||||
backgroundFrame.origin.x += rect.minX
|
||||
backgroundFrame.origin.y += rect.minY
|
||||
backgroundContent.update(rect: backgroundFrame, within: containerSize, transition: .immediate)
|
||||
}
|
||||
self.backgroundContent = backgroundContent
|
||||
self.insertSubnode(backgroundContent, at: 0)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if let maskView = self.maskView {
|
||||
maskView.image = bubbleMaskForType(type, graphics: essentialGraphics)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func update(rect: CGRect, within containerSize: CGSize, transition: ContainedViewLayoutTransition = .immediate) {
|
||||
self.absolutePosition = (rect, containerSize)
|
||||
if let backgroundContent = self.backgroundContent {
|
||||
var backgroundFrame = backgroundContent.frame
|
||||
backgroundFrame.origin.x += rect.minX
|
||||
backgroundFrame.origin.y += rect.minY
|
||||
backgroundContent.update(rect: backgroundFrame, within: containerSize, transition: transition)
|
||||
}
|
||||
}
|
||||
|
||||
func offset(value: CGPoint, animationCurve: ContainedViewLayoutTransitionCurve, duration: Double) {
|
||||
self.backgroundContent?.offset(value: value, animationCurve: animationCurve, duration: duration)
|
||||
}
|
||||
|
||||
func offsetSpring(value: CGFloat, duration: Double, damping: CGFloat) {
|
||||
self.backgroundContent?.offsetSpring(value: value, duration: duration, damping: damping)
|
||||
}
|
||||
|
||||
func updateFrame(_ value: CGRect, transition: ContainedViewLayoutTransition, completion: @escaping () -> Void = {}) {
|
||||
if let maskView = self.maskView {
|
||||
transition.updateFrame(view: maskView, frame: CGRect(origin: CGPoint(x: 0.0, y: 0.0), size: CGSize(width: value.size.width, height: value.size.height)).insetBy(dx: -maskInset, dy: -maskInset))
|
||||
}
|
||||
if let backgroundContent = self.backgroundContent {
|
||||
transition.updateFrame(layer: backgroundContent.layer, frame: CGRect(origin: CGPoint(x: 0.0, y: 0.0), size: CGSize(width: value.size.width, height: value.size.height)))
|
||||
if let (rect, containerSize) = self.absolutePosition {
|
||||
var backgroundFrame = backgroundContent.frame
|
||||
backgroundFrame.origin.x += rect.minX
|
||||
backgroundFrame.origin.y += rect.minY
|
||||
backgroundContent.update(rect: backgroundFrame, within: containerSize, transition: transition)
|
||||
}
|
||||
}
|
||||
transition.updateFrame(node: self, frame: value, completion: { _ in
|
||||
completion()
|
||||
})
|
||||
}
|
||||
|
||||
func updateFrame(_ value: CGRect, transition: CombinedTransition, completion: @escaping () -> Void = {}) {
|
||||
if let maskView = self.maskView {
|
||||
transition.updateFrame(layer: maskView.layer, frame: CGRect(origin: CGPoint(x: 0.0, y: 0.0), size: CGSize(width: value.size.width, height: value.size.height)).insetBy(dx: -maskInset, dy: -maskInset))
|
||||
}
|
||||
if let backgroundContent = self.backgroundContent {
|
||||
transition.updateFrame(layer: backgroundContent.layer, frame: CGRect(origin: CGPoint(x: 0.0, y: 0.0), size: CGSize(width: value.size.width, height: value.size.height)))
|
||||
if let (rect, containerSize) = self.absolutePosition {
|
||||
var backgroundFrame = backgroundContent.frame
|
||||
backgroundFrame.origin.x += rect.minX
|
||||
backgroundFrame.origin.y += rect.minY
|
||||
backgroundContent.update(rect: backgroundFrame, within: containerSize, transition: transition)
|
||||
}
|
||||
}
|
||||
transition.updateFrame(layer: self.layer, frame: value, completion: { _ in
|
||||
completion()
|
||||
})
|
||||
}
|
||||
|
||||
func animateFrom(sourceView: UIView, mediaBox: MediaBox, transition: CombinedTransition) {
|
||||
if transition.isAnimated {
|
||||
let previousFrame = self.frame
|
||||
self.updateFrame(CGRect(origin: CGPoint(x: previousFrame.minX, y: sourceView.frame.minY), size: sourceView.frame.size), transition: .immediate)
|
||||
self.updateFrame(previousFrame, transition: transition)
|
||||
|
||||
self.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.1)
|
||||
}
|
||||
}
|
||||
}
|
@ -2,6 +2,7 @@ import Foundation
|
||||
import UIKit
|
||||
import AsyncDisplayKit
|
||||
import Display
|
||||
import SwiftSignalKit
|
||||
import Postbox
|
||||
import TelegramCore
|
||||
import TelegramPresentationData
|
||||
@ -21,8 +22,8 @@ import GridMessageSelectionNode
|
||||
import AppBundle
|
||||
import Markdown
|
||||
import WallpaperBackgroundNode
|
||||
import SwiftSignalKit
|
||||
import ChatPresentationInterfaceState
|
||||
import ChatMessageBackground
|
||||
|
||||
enum InternalBubbleTapAction {
|
||||
case action(() -> Void)
|
||||
|
@ -6,6 +6,7 @@ import TelegramCore
|
||||
import TelegramPresentationData
|
||||
import ContextUI
|
||||
import ChatPresentationInterfaceState
|
||||
import ChatMessageBackground
|
||||
|
||||
final class ChatTextInputActionButtonsNode: ASDisplayNode {
|
||||
private let presentationContext: ChatPresentationContext?
|
||||
|
@ -58,10 +58,15 @@ final class HorizontalStickerGridItemNode: GridItemNode {
|
||||
|
||||
private var currentIsPreviewing: Bool = false
|
||||
|
||||
private var setupTimestamp: Double?
|
||||
|
||||
override var isVisibleInGrid: Bool {
|
||||
didSet {
|
||||
if oldValue != self.isVisibleInGrid {
|
||||
if self.isVisibleInGrid {
|
||||
if self.setupTimestamp == nil {
|
||||
self.setupTimestamp = CACurrentMediaTime()
|
||||
}
|
||||
self.animationNode?.visibility = true
|
||||
} else {
|
||||
self.animationNode?.visibility = false
|
||||
@ -158,7 +163,20 @@ final class HorizontalStickerGridItemNode: GridItemNode {
|
||||
self.imageNode.setSignal(chatMessageAnimatedSticker(postbox: account.postbox, file: item.file, small: true, size: fittedDimensions, synchronousLoad: false))
|
||||
}
|
||||
animationNode.started = { [weak self] in
|
||||
self?.imageNode.alpha = 0.0
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
|
||||
strongSelf.imageNode.alpha = 0.0
|
||||
|
||||
let current = CACurrentMediaTime()
|
||||
if let setupTimestamp = strongSelf.setupTimestamp, current - setupTimestamp > 0.3 {
|
||||
if let placeholderNode = strongSelf.placeholderNode, !placeholderNode.alpha.isZero {
|
||||
strongSelf.removePlaceholder(animated: true)
|
||||
}
|
||||
} else {
|
||||
strongSelf.removePlaceholder(animated: false)
|
||||
}
|
||||
}
|
||||
animationNode.setup(source: AnimatedStickerResourceSource(account: account, resource: item.file.resource, isVideo: item.file.isVideoSticker), width: Int(fittedDimensions.width), height: Int(fittedDimensions.height), mode: .cached)
|
||||
|
||||
|
@ -182,7 +182,7 @@ public final class WebSearchController: ViewController {
|
||||
self.interfaceState = self.interfaceState.withUpdatedQuery(query)
|
||||
}
|
||||
|
||||
super.init(navigationBarPresentationData: NavigationBarPresentationData(theme: NavigationBarTheme(rootControllerTheme: presentationData.theme).withUpdatedSeparatorColor(presentationData.theme.rootController.navigationBar.opaqueBackgroundColor), strings: NavigationBarStrings(presentationStrings: presentationData.strings)))
|
||||
super.init(navigationBarPresentationData: NavigationBarPresentationData(theme: NavigationBarTheme(rootControllerTheme: presentationData.theme).withUpdatedSeparatorColor(presentationData.theme.list.plainBackgroundColor).withUpdatedBackgroundColor(presentationData.theme.list.plainBackgroundColor), strings: NavigationBarStrings(presentationStrings: presentationData.strings)))
|
||||
self.statusBar.statusBarStyle = presentationData.theme.rootController.statusBarStyle.style
|
||||
|
||||
self.scrollToTop = { [weak self] in
|
||||
@ -377,8 +377,6 @@ public final class WebSearchController: ViewController {
|
||||
|
||||
self._ready.set(.single(true))
|
||||
self.displayNodeDidLoad()
|
||||
|
||||
self.controllerNode.updateBackgroundAlpha(0.0, transition: .immediate)
|
||||
}
|
||||
|
||||
private func updateInterfaceState(animated: Bool = true, _ f: (WebSearchInterfaceState) -> WebSearchInterfaceState) {
|
||||
|
@ -374,7 +374,7 @@ class WebSearchControllerNode: ASDisplayNode {
|
||||
|
||||
if themeUpdated {
|
||||
self.gridNode.backgroundColor = self.theme.list.plainBackgroundColor
|
||||
self.segmentedBackgroundNode.backgroundColor = self.theme.rootController.navigationBar.opaqueBackgroundColor
|
||||
self.segmentedBackgroundNode.backgroundColor = self.theme.list.plainBackgroundColor
|
||||
self.segmentedSeparatorNode.backgroundColor = self.theme.rootController.navigationBar.separatorColor
|
||||
self.segmentedControlNode.updateTheme(SegmentedControlTheme(theme: self.theme))
|
||||
self.toolbarBackgroundNode.backgroundColor = self.theme.rootController.navigationBar.opaqueBackgroundColor
|
||||
|
Loading…
x
Reference in New Issue
Block a user