Merge commit '09c00161fed42f33bb77775a00a648d9351db3ca'

This commit is contained in:
Ali 2022-02-27 20:34:40 +04:00
commit 12a2c1c948
18 changed files with 430 additions and 292 deletions

View File

@ -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
})
}
}

View 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",
],
)

View 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>

View File

@ -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)
}
}
}

View File

@ -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

View File

@ -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);

View File

@ -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

View File

@ -37,6 +37,7 @@ swift_library(
"//submodules/PresentationDataUtils:PresentationDataUtils",
"//submodules/WallpaperBackgroundNode:WallpaperBackgroundNode",
"//submodules/WebSearchUI:WebSearchUI",
"//submodules/ChatMessageBackground:ChatMessageBackground",
],
visibility = [
"//visibility:public",

View File

@ -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()

View File

@ -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)

View File

@ -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] {

View File

@ -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,

View File

@ -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)
}
}
}

View File

@ -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)

View File

@ -6,6 +6,7 @@ import TelegramCore
import TelegramPresentationData
import ContextUI
import ChatPresentationInterfaceState
import ChatMessageBackground
final class ChatTextInputActionButtonsNode: ASDisplayNode {
private let presentationContext: ChatPresentationContext?

View File

@ -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)

View File

@ -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) {

View File

@ -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