Various Improvements

This commit is contained in:
Ilya Laktyushin 2021-09-08 00:41:17 +03:00
parent e5f15bf084
commit 39fad9b0d1
21 changed files with 267 additions and 81 deletions

View File

@ -6796,3 +6796,6 @@ Sorry for the inconvenience.";
"Conversation.ContextMenuSeen_1" = "1 Seen"; "Conversation.ContextMenuSeen_1" = "1 Seen";
"Conversation.ContextMenuSeen_any" = "%@ Seen"; "Conversation.ContextMenuSeen_any" = "%@ Seen";
"VideoChat.RecordingSaved" = "Video chat recording saved to **Saved Messages**.";
"LiveStream.RecordingSaved" = "Live stream recording saved to **Saved Messages**.";

View File

@ -703,7 +703,11 @@ final class ThemeAccentColorControllerNode: ASDisplayNode, UIScrollViewDelegate
let maximumNumberOfColors: Int let maximumNumberOfColors: Int
switch self.state.section { switch self.state.section {
case .accent: case .accent:
if [.classic, .day].contains(self.theme.referenceTheme.baseTheme) {
maximumNumberOfColors = 2 maximumNumberOfColors = 2
} else {
maximumNumberOfColors = 1
}
case .background: case .background:
maximumNumberOfColors = 4 maximumNumberOfColors = 4
case .messages: case .messages:

View File

@ -2613,7 +2613,15 @@ public final class VoiceChatController: ViewController {
if let strongSelf = self { if let strongSelf = self {
strongSelf.call.setShouldBeRecording(false, title: nil, videoOrientation: nil) strongSelf.call.setShouldBeRecording(false, title: nil, videoOrientation: nil)
strongSelf.presentUndoOverlay(content: .forward(savedMessages: true, text: strongSelf.presentationData.strings.VoiceChat_RecordingSaved), action: { [weak self] value in
let text: String
if let channel = strongSelf.peer as? TelegramChannel, case .broadcast = channel.info {
text = strongSelf.presentationData.strings.LiveStream_RecordingSaved
} else {
text = strongSelf.presentationData.strings.VideoChat_RecordingSaved
}
strongSelf.presentUndoOverlay(content: .forward(savedMessages: true, text: text), action: { [weak self] value in
if case .info = value, let strongSelf = self, let navigationController = strongSelf.controller?.navigationController as? NavigationController { if case .info = value, let strongSelf = self, let navigationController = strongSelf.controller?.navigationController as? NavigationController {
let context = strongSelf.context let context = strongSelf.context
strongSelf.controller?.dismiss(completion: { strongSelf.controller?.dismiss(completion: {

View File

@ -34,18 +34,8 @@ public func customizePresentationTheme(_ theme: PresentationTheme, specialMode:
} }
public func makePresentationTheme(settings: TelegramThemeSettings, specialMode: Bool = false, title: String? = nil, serviceBackgroundColor: UIColor? = nil) -> PresentationTheme? { public func makePresentationTheme(settings: TelegramThemeSettings, specialMode: Bool = false, title: String? = nil, serviceBackgroundColor: UIColor? = nil) -> PresentationTheme? {
var baseTheme: TelegramBaseTheme = settings.baseTheme let defaultTheme = makeDefaultPresentationTheme(reference: PresentationBuiltinThemeReference(baseTheme: settings.baseTheme), extendingThemeReference: nil, serviceBackgroundColor: serviceBackgroundColor, preview: false)
var chatWallpaper = settings.wallpaper return customizePresentationTheme(defaultTheme, specialMode: specialMode, editing: true, title: title, accentColor: UIColor(argb: settings.accentColor), outgoingAccentColor: settings.outgoingAccentColor.flatMap { UIColor(argb: $0) }, backgroundColors: [], bubbleColors: settings.messageColors, animateBubbleColors: settings.animateMessageColors, wallpaper: settings.wallpaper)
if specialMode && baseTheme == .tinted {
baseTheme = .night
if let wallpaper = settings.wallpaper {
let colors = (wallpaper.settings?.colors ?? []).map { UIColor(rgb: $0).withMultiplied(hue: 1.0, saturation: 1.0, brightness: 2.25).rgb }
chatWallpaper = settings.wallpaper?.withUpdatedSettings(WallpaperSettings(blur: wallpaper.settings?.blur ?? false, motion: wallpaper.settings?.blur ?? false, colors: colors, intensity: wallpaper.settings?.intensity.flatMap({ -(max(55, $0)) }), rotation: wallpaper.settings?.rotation))
}
}
let defaultTheme = makeDefaultPresentationTheme(reference: PresentationBuiltinThemeReference(baseTheme: baseTheme), extendingThemeReference: nil, serviceBackgroundColor: serviceBackgroundColor, preview: false)
return customizePresentationTheme(defaultTheme, specialMode: specialMode, editing: true, title: title, accentColor: UIColor(argb: settings.accentColor), outgoingAccentColor: settings.outgoingAccentColor.flatMap { UIColor(argb: $0) }, backgroundColors: [], bubbleColors: settings.messageColors, animateBubbleColors: settings.animateMessageColors, wallpaper: chatWallpaper)
} }
public func makePresentationTheme(mediaBox: MediaBox, themeReference: PresentationThemeReference, extendingThemeReference: PresentationThemeReference? = nil, accentColor: UIColor? = nil, outgoingAccentColor: UIColor? = nil, backgroundColors: [UInt32] = [], bubbleColors: [UInt32] = [], animateBubbleColors: Bool? = nil, wallpaper: TelegramWallpaper? = nil, baseColor: PresentationThemeBaseColor? = nil, serviceBackgroundColor: UIColor? = nil, specialMode: Bool = false, preview: Bool = false) -> PresentationTheme? { public func makePresentationTheme(mediaBox: MediaBox, themeReference: PresentationThemeReference, extendingThemeReference: PresentationThemeReference? = nil, accentColor: UIColor? = nil, outgoingAccentColor: UIColor? = nil, backgroundColors: [UInt32] = [], bubbleColors: [UInt32] = [], animateBubbleColors: Bool? = nil, wallpaper: TelegramWallpaper? = nil, baseColor: PresentationThemeBaseColor? = nil, serviceBackgroundColor: UIColor? = nil, specialMode: Bool = false, preview: Bool = false) -> PresentationTheme? {

View File

@ -159,8 +159,11 @@ public enum PresentationResourceKey: Int32 {
case chatInputTextFieldBackgroundImage case chatInputTextFieldBackgroundImage
case chatInputTextFieldClearImage case chatInputTextFieldClearImage
case chatInputPanelSendIconImage
case chatInputPanelSendButtonImage case chatInputPanelSendButtonImage
case chatInputPanelApplyIconImage
case chatInputPanelApplyButtonImage case chatInputPanelApplyButtonImage
case chatInputPanelScheduleIconImage
case chatInputPanelScheduleButtonImage case chatInputPanelScheduleButtonImage
case chatInputPanelVoiceButtonImage case chatInputPanelVoiceButtonImage
case chatInputPanelVideoButtonImage case chatInputPanelVideoButtonImage

View File

@ -428,6 +428,27 @@ public struct PresentationResourcesChat {
}) })
} }
public static func chatInputPanelSendIconImage(_ theme: PresentationTheme) -> UIImage? {
return theme.image(PresentationResourceKey.chatInputPanelSendIconImage.rawValue, { theme in
return generateImage(CGSize(width: 33.0, height: 33.0), rotatedContext: { size, context in
context.clear(CGRect(origin: CGPoint(), size: size))
let color: UIColor
if theme.referenceTheme.baseTheme == .night, theme.chat.message.outgoing.bubble.withWallpaper.fill.count > 1 {
color = .white
} else {
color = theme.chat.inputPanel.actionControlForegroundColor
}
context.setStrokeColor(color.cgColor)
context.setFillColor(color.cgColor)
context.setLineWidth(2.0)
context.setLineCap(.round)
context.setLineJoin(.round)
let _ = try? drawSvgPath(context, path: "M11,14.6666667 L16.4310816,9.40016333 L16.4310816,9.40016333 C16.4694824,9.36292619 16.5305176,9.36292619 16.5689184,9.40016333 L22,14.6666667 S ")
let _ = try? drawSvgPath(context, path: "M16.5,9.33333333 C17.0522847,9.33333333 17.5,9.78104858 17.5,10.3333333 L17.5,24 C17.5,24.5522847 17.0522847,25 16.5,25 C15.9477153,25 15.5,24.5522847 15.5,24 L15.5,10.3333333 C15.5,9.78104858 15.9477153,9.33333333 16.5,9.33333333 Z ")
})
})
}
public static func chatInputPanelApplyButtonImage(_ theme: PresentationTheme) -> UIImage? { public static func chatInputPanelApplyButtonImage(_ theme: PresentationTheme) -> UIImage? {
return theme.image(PresentationResourceKey.chatInputPanelApplyButtonImage.rawValue, { theme in return theme.image(PresentationResourceKey.chatInputPanelApplyButtonImage.rawValue, { theme in
return generateImage(CGSize(width: 33.0, height: 33.0), rotatedContext: { size, context in return generateImage(CGSize(width: 33.0, height: 33.0), rotatedContext: { size, context in
@ -444,6 +465,26 @@ public struct PresentationResourcesChat {
}) })
} }
public static func chatInputPanelApplyIconImage(_ theme: PresentationTheme) -> UIImage? {
return theme.image(PresentationResourceKey.chatInputPanelApplyIconImage.rawValue, { theme in
return generateImage(CGSize(width: 33.0, height: 33.0), rotatedContext: { size, context in
context.clear(CGRect(origin: CGPoint(), size: size))
let color: UIColor
if theme.referenceTheme.baseTheme == .night, theme.chat.message.outgoing.bubble.withWallpaper.fill.count > 1 {
color = .white
} else {
color = theme.chat.inputPanel.actionControlForegroundColor
}
context.setStrokeColor(color.cgColor)
context.setFillColor(color.cgColor)
context.setLineWidth(2.0)
context.setLineCap(.round)
context.setLineJoin(.round)
let _ = try? drawSvgPath(context, path: "M9.33333333,17.2686567 L14.1849216,22.120245 L14.1849216,22.120245 C14.2235835,22.1589069 14.2862668,22.1589069 14.3249287,22.120245 C14.3261558,22.1190179 14.3273504,22.1177588 14.3285113,22.1164689 L24.3333333,11 S ")
})
})
}
public static func chatInputPanelScheduleButtonImage(_ theme: PresentationTheme) -> UIImage? { public static func chatInputPanelScheduleButtonImage(_ theme: PresentationTheme) -> UIImage? {
return theme.image(PresentationResourceKey.chatInputPanelScheduleButtonImage.rawValue, { theme in return theme.image(PresentationResourceKey.chatInputPanelScheduleButtonImage.rawValue, { theme in
return generateImage(CGSize(width: 33.0, height: 33.0), rotatedContext: { size, context in return generateImage(CGSize(width: 33.0, height: 33.0), rotatedContext: { size, context in
@ -463,6 +504,30 @@ public struct PresentationResourcesChat {
}) })
} }
public static func chatInputPanelScheduleIconImage(_ theme: PresentationTheme) -> UIImage? {
return theme.image(PresentationResourceKey.chatInputPanelScheduleIconImage.rawValue, { theme in
return generateImage(CGSize(width: 33.0, height: 33.0), rotatedContext: { size, context in
context.clear(CGRect(origin: CGPoint(), size: size))
let imageRect = CGRect(origin: CGPoint(), size: size)
context.translateBy(x: imageRect.midX, y: imageRect.midY)
context.scaleBy(x: 1.0, y: -1.0)
context.translateBy(x: -imageRect.midX, y: -imageRect.midY)
let color: UIColor
if theme.referenceTheme.baseTheme == .night, theme.chat.message.outgoing.bubble.withWallpaper.fill.count > 1 {
color = .white
} else {
color = theme.chat.inputPanel.actionControlForegroundColor
}
if let image = generateTintedImage(image: UIImage(bundleImageName: "Chat/Input/ScheduleIcon"), color: color) {
context.draw(image.cgImage!, in: CGRect(origin: CGPoint(x: floorToScreenPixels((size.width - image.size.width) / 2.0), y: floorToScreenPixels((size.height - image.size.height) / 2.0)), size: image.size))
}
})
})
}
public static func chatInputPanelVoiceButtonImage(_ theme: PresentationTheme) -> UIImage? { public static func chatInputPanelVoiceButtonImage(_ theme: PresentationTheme) -> UIImage? {
return theme.image(PresentationResourceKey.chatInputPanelVoiceButtonImage.rawValue, { theme in return theme.image(PresentationResourceKey.chatInputPanelVoiceButtonImage.rawValue, { theme in
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Input/Text/IconMicrophone"), color: theme.chat.inputPanel.panelControlColor) return generateTintedImage(image: UIImage(bundleImageName: "Chat/Input/Text/IconMicrophone"), color: theme.chat.inputPanel.panelControlColor)

View File

@ -417,6 +417,8 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
private weak var sendMessageActionsController: ChatSendMessageActionSheetController? private weak var sendMessageActionsController: ChatSendMessageActionSheetController?
private var searchResultsController: ChatSearchResultsController? private var searchResultsController: ChatSearchResultsController?
private weak var themeSceen: ChatThemeScreen?
private weak var currentPinchController: PinchController? private weak var currentPinchController: PinchController?
private weak var currentPinchSourceItemNode: ListViewItemNode? private weak var currentPinchSourceItemNode: ListViewItemNode?
@ -3995,6 +3997,10 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
controllerInteraction.updatedPresentationData = strongSelf.updatedPresentationData controllerInteraction.updatedPresentationData = strongSelf.updatedPresentationData
strongSelf.presentationDataPromise.set(.single(strongSelf.presentationData)) strongSelf.presentationDataPromise.set(.single(strongSelf.presentationData))
if !isFirstTime && previousTheme !== presentationData.theme {
strongSelf.presentCrossfadeSnapshot(delay: 0.2)
}
} }
strongSelf.presentationReady.set(.single(true)) strongSelf.presentationReady.set(.single(true))
} }
@ -8009,6 +8015,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
self.dismissAllTooltips() self.dismissAllTooltips()
self.sendMessageActionsController?.dismiss() self.sendMessageActionsController?.dismiss()
self.themeSceen?.dismiss()
if let _ = self.peekData { if let _ = self.peekData {
self.peekTimerDisposable.set(nil) self.peekTimerDisposable.set(nil)
@ -13303,13 +13310,16 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
self.push(controller) self.push(controller)
} }
private var crossfading = false
private func presentCrossfadeSnapshot(delay: Double) { private func presentCrossfadeSnapshot(delay: Double) {
guard let snapshotView = self.view.snapshotView(afterScreenUpdates: false) else { guard !self.crossfading, let snapshotView = self.view.snapshotView(afterScreenUpdates: false) else {
return return
} }
self.crossfading = true
self.view.addSubview(snapshotView) self.view.addSubview(snapshotView)
snapshotView.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.3, delay: delay, removeOnCompletion: false, completion: { [weak snapshotView] _ in snapshotView.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.3, delay: delay, removeOnCompletion: false, completion: { [weak self, weak snapshotView] _ in
self?.crossfading = false
snapshotView?.removeFromSuperview() snapshotView?.removeFromSuperview()
}) })
} }
@ -13375,6 +13385,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
} }
} }
strongSelf.present(controller, in: .window(.root)) strongSelf.present(controller, in: .window(.root))
strongSelf.themeSceen = controller
}) })
} }

View File

@ -492,7 +492,7 @@ class ChatControllerNode: ASDisplayNode, UIScrollViewDelegate {
self.historyNode.view.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(self.tapGesture(_:)))) self.historyNode.view.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(self.tapGesture(_:))))
self.textInputPanelNode = ChatTextInputPanelNode(presentationInterfaceState: chatPresentationInterfaceState, presentController: { [weak self] controller in self.textInputPanelNode = ChatTextInputPanelNode(presentationInterfaceState: chatPresentationInterfaceState, presentationContext: ChatPresentationContext(backgroundNode: backgroundNode), presentController: { [weak self] controller in
self?.interfaceInteraction?.presentController(controller, nil) self?.interfaceInteraction?.presentController(controller, nil)
}) })
self.textInputPanelNode?.storedInputLanguage = chatPresentationInterfaceState.interfaceState.inputLanguage self.textInputPanelNode?.storedInputLanguage = chatPresentationInterfaceState.interfaceState.inputLanguage
@ -1446,9 +1446,11 @@ class ChatControllerNode: ASDisplayNode, UIScrollViewDelegate {
} }
} }
if inputPanelNodeHandlesTransition { if inputPanelNodeHandlesTransition {
inputPanelNode.updateAbsoluteRect(apparentInputPanelFrame, within: layout.size, transition: .immediate)
inputPanelNode.frame = apparentInputPanelFrame inputPanelNode.frame = apparentInputPanelFrame
inputPanelNode.alpha = 1.0 inputPanelNode.alpha = 1.0
} else { } else {
inputPanelNode.updateAbsoluteRect(apparentInputPanelFrame, within: layout.size, transition: transition)
transition.updateFrame(node: inputPanelNode, frame: apparentInputPanelFrame) transition.updateFrame(node: inputPanelNode, frame: apparentInputPanelFrame)
transition.updateAlpha(node: inputPanelNode, alpha: 1.0) transition.updateAlpha(node: inputPanelNode, alpha: 1.0)
} }

View File

@ -11,6 +11,9 @@ class ChatInputPanelNode: ASDisplayNode {
var interfaceInteraction: ChatPanelInterfaceInteraction? var interfaceInteraction: ChatPanelInterfaceInteraction?
var prevInputPanelNode: ChatInputPanelNode? var prevInputPanelNode: ChatInputPanelNode?
func updateAbsoluteRect(_ rect: CGRect, within containerSize: CGSize, transition: ContainedViewLayoutTransition) {
}
func updateLayout(width: CGFloat, leftInset: CGFloat, rightInset: CGFloat, additionalSideInsets: UIEdgeInsets, maxHeight: CGFloat, isSecondary: Bool, transition: ContainedViewLayoutTransition, interfaceState: ChatPresentationInterfaceState, metrics: LayoutMetrics) -> CGFloat { func updateLayout(width: CGFloat, leftInset: CGFloat, rightInset: CGFloat, additionalSideInsets: UIEdgeInsets, maxHeight: CGFloat, isSecondary: Bool, transition: ContainedViewLayoutTransition, interfaceState: ChatPresentationInterfaceState, metrics: LayoutMetrics) -> CGFloat {
return 0.0 return 0.0
} }

View File

@ -294,7 +294,7 @@ func inputPanelForChatPresentationIntefaceState(_ chatPresentationInterfaceState
textInputPanelNode.context = context textInputPanelNode.context = context
return (textInputPanelNode, nil) return (textInputPanelNode, nil)
} else { } else {
let panel = ChatTextInputPanelNode(presentationInterfaceState: chatPresentationInterfaceState, presentController: { [weak interfaceInteraction] controller in let panel = ChatTextInputPanelNode(presentationInterfaceState: chatPresentationInterfaceState, presentationContext: nil, presentController: { [weak interfaceInteraction] controller in
interfaceInteraction?.presentController(controller, nil) interfaceInteraction?.presentController(controller, nil)
}) })

View File

@ -1308,8 +1308,10 @@ class ChatMessageAnimatedStickerItemNode: ChatMessageItemView {
self?.additionalAnimationNodes.removeAll(where: { $0 === additionalAnimationNode }) self?.additionalAnimationNodes.removeAll(where: { $0 === additionalAnimationNode })
additionalAnimationNode?.removeFromSupernode() additionalAnimationNode?.removeFromSupernode()
} }
additionalAnimationNode.frame = animationNode.frame.insetBy(dx: -animationNode.frame.width, dy: -animationNode.frame.height) var animationFrame = animationNode.frame.insetBy(dx: -animationNode.frame.width, dy: -animationNode.frame.height)
.offsetBy(dx: incoming ? animationNode.frame.width - 10.0 : -animationNode.frame.width + 10.0, dy: 0.0) .offsetBy(dx: incoming ? animationNode.frame.width - 10.0 : -animationNode.frame.width + 10.0, dy: 0.0)
animationFrame = animationFrame.offsetBy(dx: CGFloat.random(in: -30.0 ... 30.0), dy: CGFloat.random(in: -30.0 ... 30.0))
additionalAnimationNode.frame = animationFrame
if incoming { if incoming {
additionalAnimationNode.transform = CATransform3DMakeScale(-1.0, 1.0, 1.0) additionalAnimationNode.transform = CATransform3DMakeScale(-1.0, 1.0, 1.0)
} }

View File

@ -188,13 +188,13 @@ final class ChatMessageBubbleBackdrop: ASDisplayNode {
} }
} }
func update(rect: CGRect, within containerSize: CGSize) { func update(rect: CGRect, within containerSize: CGSize, transition: ContainedViewLayoutTransition = .immediate) {
self.absolutePosition = (rect, containerSize) self.absolutePosition = (rect, containerSize)
if let backgroundContent = self.backgroundContent { if let backgroundContent = self.backgroundContent {
var backgroundFrame = backgroundContent.frame var backgroundFrame = backgroundContent.frame
backgroundFrame.origin.x += rect.minX backgroundFrame.origin.x += rect.minX
backgroundFrame.origin.y += rect.minY backgroundFrame.origin.y += rect.minY
backgroundContent.update(rect: backgroundFrame, within: containerSize) backgroundContent.update(rect: backgroundFrame, within: containerSize, transition: transition)
} }
} }

View File

@ -24,6 +24,7 @@ final class ChatRecentActionsController: TelegramBaseController {
return (self.presentationData, self.presentationDataPromise.get()) return (self.presentationData, self.presentationDataPromise.get())
} }
private var presentationDataDisposable: Disposable? private var presentationDataDisposable: Disposable?
private var didSetPresentationData = false
private var interaction: ChatRecentActionsInteraction! private var interaction: ChatRecentActionsInteraction!
private var panelInteraction: ChatPanelInterfaceInteraction! private var panelInteraction: ChatPanelInterfaceInteraction!
@ -185,10 +186,12 @@ final class ChatRecentActionsController: TelegramBaseController {
} }
} }
let isFirstTime = !strongSelf.didSetPresentationData
strongSelf.presentationData = presentationData strongSelf.presentationData = presentationData
strongSelf.presentationDataPromise.set(.single(presentationData)) strongSelf.presentationDataPromise.set(.single(presentationData))
strongSelf.didSetPresentationData = true
if previousTheme !== presentationData.theme || previousStrings !== presentationData.strings { if isFirstTime || previousTheme !== presentationData.theme || previousStrings !== presentationData.strings {
strongSelf.updateThemeAndStrings() strongSelf.updateThemeAndStrings()
} }
} }

View File

@ -247,8 +247,8 @@ final class ChatSendMessageActionSheetControllerNode: ViewControllerTracingNode,
super.init() super.init()
self.sendButtonNode.setImage(PresentationResourcesChat.chatInputPanelSendButtonImage(self.presentationData.theme), for: []) // self.sendButtonNode.setImage(PresentationResourcesChat.chatInputPanelSendButtonImage(self.presentationData.theme), for: [])
self.sendButtonNode.addTarget(self, action: #selector(sendButtonPressed), forControlEvents: .touchUpInside) self.sendButtonNode.addTarget(self, action: #selector(self.sendButtonPressed), forControlEvents: .touchUpInside)
if let attributedText = textInputNode.attributedText, !attributedText.string.isEmpty { if let attributedText = textInputNode.attributedText, !attributedText.string.isEmpty {
self.fromMessageTextNode.attributedText = attributedText self.fromMessageTextNode.attributedText = attributedText
@ -341,6 +341,10 @@ final class ChatSendMessageActionSheetControllerNode: ViewControllerTracingNode,
if #available(iOSApplicationExtension 11.0, iOS 11.0, *) { if #available(iOSApplicationExtension 11.0, iOS 11.0, *) {
self.scrollNode.view.contentInsetAdjustmentBehavior = .never self.scrollNode.view.contentInsetAdjustmentBehavior = .never
} }
if let snapshotView = self.sourceSendButton.view.snapshotView(afterScreenUpdates: false) {
self.sendButtonNode.view.addSubview(snapshotView)
}
} }
func updatePresentationData(_ presentationData: PresentationData) { func updatePresentationData(_ presentationData: PresentationData) {
@ -361,7 +365,7 @@ final class ChatSendMessageActionSheetControllerNode: ViewControllerTracingNode,
self.dimNode.backgroundColor = presentationData.theme.contextMenu.dimColor self.dimNode.backgroundColor = presentationData.theme.contextMenu.dimColor
self.contentContainerNode.backgroundColor = self.presentationData.theme.contextMenu.backgroundColor self.contentContainerNode.backgroundColor = self.presentationData.theme.contextMenu.backgroundColor
self.sendButtonNode.setImage(PresentationResourcesChat.chatInputPanelSendButtonImage(self.presentationData.theme), for: []) // self.sendButtonNode.setImage(PresentationResourcesChat.chatInputPanelSendButtonImage(self.presentationData.theme), for: [])
if let toAttributedText = self.textInputNode.attributedText?.mutableCopy() as? NSMutableAttributedString { if let toAttributedText = self.textInputNode.attributedText?.mutableCopy() as? NSMutableAttributedString {
toAttributedText.addAttribute(NSAttributedString.Key.foregroundColor, value: self.presentationData.theme.chat.message.outgoing.primaryTextColor, range: NSMakeRange(0, (toAttributedText.string as NSString).length)) toAttributedText.addAttribute(NSAttributedString.Key.foregroundColor, value: self.presentationData.theme.chat.message.outgoing.primaryTextColor, range: NSMakeRange(0, (toAttributedText.string as NSString).length))

View File

@ -2,13 +2,18 @@ import Foundation
import UIKit import UIKit
import AsyncDisplayKit import AsyncDisplayKit
import Display import Display
import TelegramCore
import TelegramPresentationData import TelegramPresentationData
import ContextUI import ContextUI
final class ChatTextInputActionButtonsNode: ASDisplayNode { final class ChatTextInputActionButtonsNode: ASDisplayNode {
private let presentationContext: ChatPresentationContext?
private let strings: PresentationStrings private let strings: PresentationStrings
let micButton: ChatTextInputMediaRecordingButton let micButton: ChatTextInputMediaRecordingButton
let sendContainerNode: ASDisplayNode
let backdropNode: ChatMessageBubbleBackdrop
let backgroundNode: ASDisplayNode
let sendButton: HighlightTrackingButtonNode let sendButton: HighlightTrackingButtonNode
var sendButtonRadialStatusNode: ChatSendButtonRadialStatusNode? var sendButtonRadialStatusNode: ChatSendButtonRadialStatusNode?
var sendButtonHasApplyIcon = false var sendButtonHasApplyIcon = false
@ -26,10 +31,21 @@ final class ChatTextInputActionButtonsNode: ASDisplayNode {
var micButtonPointerInteraction: PointerInteraction? var micButtonPointerInteraction: PointerInteraction?
init(theme: PresentationTheme, strings: PresentationStrings, presentController: @escaping (ViewController) -> Void) { private var validLayout: CGSize?
init(presentationInterfaceState: ChatPresentationInterfaceState, presentationContext: ChatPresentationContext?, presentController: @escaping (ViewController) -> Void) {
self.presentationContext = presentationContext
let theme = presentationInterfaceState.theme
let strings = presentationInterfaceState.strings
self.strings = strings self.strings = strings
self.micButton = ChatTextInputMediaRecordingButton(theme: theme, strings: strings, presentController: presentController) self.micButton = ChatTextInputMediaRecordingButton(theme: theme, strings: strings, presentController: presentController)
self.sendContainerNode = ASDisplayNode()
self.backgroundNode = ASDisplayNode()
self.backgroundNode.backgroundColor = theme.chat.inputPanel.actionControlFillColor
self.backgroundNode.clipsToBounds = true
self.backdropNode = ChatMessageBubbleBackdrop()
self.sendButton = HighlightTrackingButtonNode(pointerStyle: .lift) self.sendButton = HighlightTrackingButtonNode(pointerStyle: .lift)
self.expandMediaInputButton = HighlightableButtonNode(pointerStyle: .default) self.expandMediaInputButton = HighlightableButtonNode(pointerStyle: .default)
@ -43,24 +59,32 @@ final class ChatTextInputActionButtonsNode: ASDisplayNode {
if let strongSelf = self { if let strongSelf = self {
if strongSelf.sendButtonHasApplyIcon || !strongSelf.sendButtonLongPressEnabled { if strongSelf.sendButtonHasApplyIcon || !strongSelf.sendButtonLongPressEnabled {
if highlighted { if highlighted {
strongSelf.layer.removeAnimation(forKey: "opacity") strongSelf.sendContainerNode.layer.removeAnimation(forKey: "opacity")
strongSelf.alpha = 0.4 strongSelf.sendContainerNode.alpha = 0.4
} else { } else {
strongSelf.alpha = 1.0 strongSelf.sendContainerNode.alpha = 1.0
strongSelf.layer.animateAlpha(from: 0.4, to: 1.0, duration: 0.2) strongSelf.sendContainerNode.layer.animateAlpha(from: 0.4, to: 1.0, duration: 0.2)
} }
} else { } else {
if highlighted { if highlighted {
strongSelf.sendButton.layer.animateScale(from: 1.0, to: 0.75, duration: 0.4, removeOnCompletion: false) strongSelf.sendContainerNode.layer.animateScale(from: 1.0, to: 0.75, duration: 0.4, removeOnCompletion: false)
} else if let presentationLayer = strongSelf.sendButton.layer.presentation() { } else if let presentationLayer = strongSelf.sendButton.layer.presentation() {
strongSelf.sendButton.layer.animateScale(from: CGFloat((presentationLayer.value(forKeyPath: "transform.scale.y") as? NSNumber)?.floatValue ?? 1.0), to: 1.0, duration: 0.25, removeOnCompletion: false) strongSelf.sendContainerNode.layer.animateScale(from: CGFloat((presentationLayer.value(forKeyPath: "transform.scale.y") as? NSNumber)?.floatValue ?? 1.0), to: 1.0, duration: 0.25, removeOnCompletion: false)
} }
} }
} }
} }
self.view.addSubview(self.micButton) self.view.addSubview(self.micButton)
self.addSubnode(self.sendButton)
self.addSubnode(self.sendContainerNode)
self.sendContainerNode.addSubnode(self.backgroundNode)
if let presentationContext = presentationContext {
let graphics = PresentationResourcesChat.principalGraphics(theme: theme, wallpaper: presentationInterfaceState.chatWallpaper, bubbleCorners: presentationInterfaceState.bubbleCorners)
self.backdropNode.setType(type: .outgoing(.None), theme: ChatPresentationThemeData(theme: theme, wallpaper: presentationInterfaceState.chatWallpaper), essentialGraphics: graphics, maskMode: true, backgroundNode: presentationContext.backgroundNode)
self.backgroundNode.addSubnode(self.backdropNode)
}
self.sendContainerNode.addSubnode(self.sendButton)
self.addSubnode(self.expandMediaInputButton) self.addSubnode(self.expandMediaInputButton)
} }
@ -75,23 +99,51 @@ final class ChatTextInputActionButtonsNode: ASDisplayNode {
return return
} }
if !strongSelf.sendButtonHasApplyIcon { if !strongSelf.sendButtonHasApplyIcon {
strongSelf.sendButtonLongPressed?(strongSelf.sendButton, recognizer) strongSelf.sendButtonLongPressed?(strongSelf.sendContainerNode, recognizer)
} }
} }
self.micButtonPointerInteraction = PointerInteraction(view: self.micButton, style: .circle) self.micButtonPointerInteraction = PointerInteraction(view: self.micButton, style: .circle)
} }
func updateTheme(theme: PresentationTheme) { func updateTheme(theme: PresentationTheme, wallpaper: TelegramWallpaper) {
self.micButton.updateTheme(theme: theme) self.micButton.updateTheme(theme: theme)
self.expandMediaInputButton.setImage(PresentationResourcesChat.chatInputPanelExpandButtonImage(theme), for: []) self.expandMediaInputButton.setImage(PresentationResourcesChat.chatInputPanelExpandButtonImage(theme), for: [])
self.backgroundNode.backgroundColor = theme.chat.inputPanel.actionControlFillColor
if theme.referenceTheme.baseTheme == .night, theme.chat.message.outgoing.bubble.withWallpaper.fill.count > 1 {
self.backdropNode.isHidden = false
} else {
self.backdropNode.isHidden = true
}
let graphics = PresentationResourcesChat.principalGraphics(theme: theme, wallpaper: wallpaper, bubbleCorners: .init(mainRadius: 1, auxiliaryRadius: 1, mergeBubbleCorners: false))
self.backdropNode.setType(type: .outgoing(.None), theme: ChatPresentationThemeData(theme: theme, wallpaper: wallpaper), essentialGraphics: graphics, maskMode: true, backgroundNode: self.presentationContext?.backgroundNode)
}
private var absoluteRect: (CGRect, CGSize)?
func updateAbsoluteRect(_ rect: CGRect, within containerSize: CGSize, transition: ContainedViewLayoutTransition) {
self.absoluteRect = (rect, containerSize)
self.backdropNode.update(rect: rect, within: containerSize, transition: transition)
} }
func updateLayout(size: CGSize, transition: ContainedViewLayoutTransition, interfaceState: ChatPresentationInterfaceState) { func updateLayout(size: CGSize, transition: ContainedViewLayoutTransition, interfaceState: ChatPresentationInterfaceState) {
self.validLayout = size
transition.updateFrame(layer: self.micButton.layer, frame: CGRect(origin: CGPoint(), size: size)) transition.updateFrame(layer: self.micButton.layer, frame: CGRect(origin: CGPoint(), size: size))
self.micButton.layoutItems() self.micButton.layoutItems()
transition.updateFrame(layer: self.sendButton.layer, frame: CGRect(origin: CGPoint(), size: size)) transition.updateFrame(layer: self.sendButton.layer, frame: CGRect(origin: CGPoint(), size: size))
transition.updateFrame(node: self.sendContainerNode, frame: CGRect(origin: CGPoint(), size: size))
let backgroundSize = CGSize(width: 33.0, height: 33.0)
transition.updateFrame(node: self.backgroundNode, frame: CGRect(origin: CGPoint(x: floorToScreenPixels((size.width - backgroundSize.width) / 2.0), y: floorToScreenPixels((size.height - backgroundSize.height) / 2.0)), size: backgroundSize))
self.backgroundNode.cornerRadius = backgroundSize.width / 2.0
transition.updateFrame(node: self.backdropNode, frame: CGRect(origin: CGPoint(x: -2.0, y: -2.0), size: CGSize(width: size.width + 12.0, height: size.height + 2.0)))
if let (rect, containerSize) = self.absoluteRect {
self.backdropNode.update(rect: rect, within: containerSize)
}
var isScheduledMessages = false var isScheduledMessages = false
if case .scheduledMessages = interfaceState.subject { if case .scheduledMessages = interfaceState.subject {
@ -104,12 +156,12 @@ final class ChatTextInputActionButtonsNode: ASDisplayNode {
sendButtonRadialStatusNode = current sendButtonRadialStatusNode = current
} else { } else {
sendButtonRadialStatusNode = ChatSendButtonRadialStatusNode(color: interfaceState.theme.chat.inputPanel.panelControlAccentColor) sendButtonRadialStatusNode = ChatSendButtonRadialStatusNode(color: interfaceState.theme.chat.inputPanel.panelControlAccentColor)
sendButtonRadialStatusNode.alpha = self.sendButton.alpha sendButtonRadialStatusNode.alpha = self.sendContainerNode.alpha
self.sendButtonRadialStatusNode = sendButtonRadialStatusNode self.sendButtonRadialStatusNode = sendButtonRadialStatusNode
self.addSubnode(sendButtonRadialStatusNode) self.addSubnode(sendButtonRadialStatusNode)
} }
transition.updateSublayerTransformScale(layer: self.sendButton.layer, scale: CGPoint(x: 0.7575, y: 0.7575)) transition.updateSublayerTransformScale(layer: self.sendContainerNode.layer, scale: CGPoint(x: 0.7575, y: 0.7575))
let defaultSendButtonSize: CGFloat = 25.0 let defaultSendButtonSize: CGFloat = 25.0
let defaultOriginX = floorToScreenPixels((self.sendButton.bounds.width - defaultSendButtonSize) / 2.0) let defaultOriginX = floorToScreenPixels((self.sendButton.bounds.width - defaultSendButtonSize) / 2.0)
@ -123,7 +175,7 @@ final class ChatTextInputActionButtonsNode: ASDisplayNode {
self.sendButtonRadialStatusNode = nil self.sendButtonRadialStatusNode = nil
sendButtonRadialStatusNode.removeFromSupernode() sendButtonRadialStatusNode.removeFromSupernode()
} }
transition.updateSublayerTransformScale(layer: self.sendButton.layer, scale: CGPoint(x: 1.0, y: 1.0)) transition.updateSublayerTransformScale(layer: self.sendContainerNode.layer, scale: CGPoint(x: 1.0, y: 1.0))
} }
transition.updateFrame(node: self.expandMediaInputButton, frame: CGRect(origin: CGPoint(), size: size)) transition.updateFrame(node: self.expandMediaInputButton, frame: CGRect(origin: CGPoint(), size: size))

View File

@ -432,7 +432,7 @@ class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDelegate {
private let accessoryButtonSpacing: CGFloat = 0.0 private let accessoryButtonSpacing: CGFloat = 0.0
private let accessoryButtonInset: CGFloat = 2.0 private let accessoryButtonInset: CGFloat = 2.0
init(presentationInterfaceState: ChatPresentationInterfaceState, presentController: @escaping (ViewController) -> Void) { init(presentationInterfaceState: ChatPresentationInterfaceState, presentationContext: ChatPresentationContext?, presentController: @escaping (ViewController) -> Void) {
self.presentationInterfaceState = presentationInterfaceState self.presentationInterfaceState = presentationInterfaceState
self.clippingNode = ASDisplayNode() self.clippingNode = ASDisplayNode()
@ -474,7 +474,7 @@ class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDelegate {
self.searchLayoutClearImageNode.isUserInteractionEnabled = false self.searchLayoutClearImageNode.isUserInteractionEnabled = false
self.searchLayoutClearButton.addSubnode(self.searchLayoutClearImageNode) self.searchLayoutClearButton.addSubnode(self.searchLayoutClearImageNode)
self.actionButtons = ChatTextInputActionButtonsNode(theme: presentationInterfaceState.theme, strings: presentationInterfaceState.strings, presentController: presentController) self.actionButtons = ChatTextInputActionButtonsNode(presentationInterfaceState: presentationInterfaceState, presentationContext: presentationContext, presentController: presentController)
self.counterTextNode = ImmediateTextNode() self.counterTextNode = ImmediateTextNode()
self.counterTextNode.textAlignment = .center self.counterTextNode.textAlignment = .center
@ -562,7 +562,7 @@ class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDelegate {
} }
self.actionButtons.sendButton.addTarget(self, action: #selector(self.sendButtonPressed), forControlEvents: .touchUpInside) self.actionButtons.sendButton.addTarget(self, action: #selector(self.sendButtonPressed), forControlEvents: .touchUpInside)
self.actionButtons.sendButton.alpha = 0.0 self.actionButtons.sendContainerNode.alpha = 0.0
self.actionButtons.updateAccessibility() self.actionButtons.updateAccessibility()
self.actionButtons.expandMediaInputButton.addTarget(self, action: #selector(self.expandButtonPressed), forControlEvents: .touchUpInside) self.actionButtons.expandMediaInputButton.addTarget(self, action: #selector(self.expandButtonPressed), forControlEvents: .touchUpInside)
@ -757,6 +757,15 @@ class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDelegate {
return minimalHeight return minimalHeight
} }
private var absoluteRect: (CGRect, CGSize)?
override func updateAbsoluteRect(_ rect: CGRect, within containerSize: CGSize, transition: ContainedViewLayoutTransition) {
self.absoluteRect = (rect, containerSize)
if !self.actionButtons.frame.width.isZero {
self.actionButtons.updateAbsoluteRect(CGRect(origin: rect.origin.offsetBy(dx: self.actionButtons.frame.minX, dy: self.actionButtons.frame.minY), size: self.actionButtons.frame.size), within: containerSize, transition: transition)
}
}
override func updateLayout(width: CGFloat, leftInset: CGFloat, rightInset: CGFloat, additionalSideInsets: UIEdgeInsets, maxHeight: CGFloat, isSecondary: Bool, transition: ContainedViewLayoutTransition, interfaceState: ChatPresentationInterfaceState, metrics: LayoutMetrics) -> CGFloat { override func updateLayout(width: CGFloat, leftInset: CGFloat, rightInset: CGFloat, additionalSideInsets: UIEdgeInsets, maxHeight: CGFloat, isSecondary: Bool, transition: ContainedViewLayoutTransition, interfaceState: ChatPresentationInterfaceState, metrics: LayoutMetrics) -> CGFloat {
let previousAdditionalSideInsets = self.validLayout?.3 let previousAdditionalSideInsets = self.validLayout?.3
self.validLayout = (width, leftInset, rightInset, additionalSideInsets, maxHeight, metrics, isSecondary) self.validLayout = (width, leftInset, rightInset, additionalSideInsets, maxHeight, metrics, isSecondary)
@ -865,7 +874,7 @@ class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDelegate {
self.attachmentButton.setImage(PresentationResourcesChat.chatInputPanelAttachmentButtonImage(interfaceState.theme), for: []) self.attachmentButton.setImage(PresentationResourcesChat.chatInputPanelAttachmentButtonImage(interfaceState.theme), for: [])
} }
self.actionButtons.updateTheme(theme: interfaceState.theme) self.actionButtons.updateTheme(theme: interfaceState.theme, wallpaper: interfaceState.chatWallpaper)
let textFieldMinHeight = calclulateTextFieldMinHeight(interfaceState, metrics: metrics) let textFieldMinHeight = calclulateTextFieldMinHeight(interfaceState, metrics: metrics)
let minimalInputHeight: CGFloat = 2.0 + textFieldMinHeight let minimalInputHeight: CGFloat = 2.0 + textFieldMinHeight
@ -967,7 +976,7 @@ class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDelegate {
if !self.actionButtons.animatingSendButton { if !self.actionButtons.animatingSendButton {
let imageNode = self.actionButtons.sendButton.imageNode let imageNode = self.actionButtons.sendButton.imageNode
if transition.isAnimated && !self.actionButtons.sendButton.alpha.isZero && self.actionButtons.sendButton.layer.animation(forKey: "opacity") == nil, let previousImage = imageNode.image { if transition.isAnimated && !self.actionButtons.sendContainerNode.alpha.isZero && self.actionButtons.sendButton.layer.animation(forKey: "opacity") == nil, let previousImage = imageNode.image {
let tempView = UIImageView(image: previousImage) let tempView = UIImageView(image: previousImage)
self.actionButtons.sendButton.view.addSubview(tempView) self.actionButtons.sendButton.view.addSubview(tempView)
tempView.frame = imageNode.frame tempView.frame = imageNode.frame
@ -981,12 +990,12 @@ class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDelegate {
} }
self.actionButtons.sendButtonHasApplyIcon = sendButtonHasApplyIcon self.actionButtons.sendButtonHasApplyIcon = sendButtonHasApplyIcon
if self.actionButtons.sendButtonHasApplyIcon { if self.actionButtons.sendButtonHasApplyIcon {
self.actionButtons.sendButton.setImage(PresentationResourcesChat.chatInputPanelApplyButtonImage(interfaceState.theme), for: []) self.actionButtons.sendButton.setImage(PresentationResourcesChat.chatInputPanelApplyIconImage(interfaceState.theme), for: [])
} else { } else {
if isScheduledMessages { if isScheduledMessages {
self.actionButtons.sendButton.setImage(PresentationResourcesChat.chatInputPanelScheduleButtonImage(interfaceState.theme), for: []) self.actionButtons.sendButton.setImage(PresentationResourcesChat.chatInputPanelScheduleButtonImage(interfaceState.theme), for: [])
} else { } else {
self.actionButtons.sendButton.setImage(PresentationResourcesChat.chatInputPanelSendButtonImage(interfaceState.theme), for: []) self.actionButtons.sendButton.setImage(PresentationResourcesChat.chatInputPanelSendIconImage(interfaceState.theme), for: [])
} }
} }
} }
@ -1391,6 +1400,9 @@ class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDelegate {
let actionButtonsFrame = CGRect(origin: CGPoint(x: width - rightInset - 43.0 - UIScreenPixel + composeButtonsOffset, y: panelHeight - minimalHeight), size: CGSize(width: 44.0, height: minimalHeight)) let actionButtonsFrame = CGRect(origin: CGPoint(x: width - rightInset - 43.0 - UIScreenPixel + composeButtonsOffset, y: panelHeight - minimalHeight), size: CGSize(width: 44.0, height: minimalHeight))
transition.updateFrame(node: self.actionButtons, frame: actionButtonsFrame) transition.updateFrame(node: self.actionButtons, frame: actionButtonsFrame)
if let (rect, containerSize) = self.absoluteRect {
self.actionButtons.updateAbsoluteRect(CGRect(x: rect.origin.x + actionButtonsFrame.origin.x, y: rect.origin.y + actionButtonsFrame.origin.y, width: actionButtonsFrame.width, height: actionButtonsFrame.height), within: containerSize, transition: transition)
}
if let presentationInterfaceState = self.presentationInterfaceState { if let presentationInterfaceState = self.presentationInterfaceState {
self.actionButtons.updateLayout(size: CGSize(width: 44.0, height: minimalHeight), transition: transition, interfaceState: presentationInterfaceState) self.actionButtons.updateLayout(size: CGSize(width: 44.0, height: minimalHeight), transition: transition, interfaceState: presentationInterfaceState)
@ -1646,9 +1658,6 @@ class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDelegate {
self.menuButton.transform = CATransform3DIdentity self.menuButton.transform = CATransform3DIdentity
self.menuButton.layer.animateScale(from: 0.3, to: 1.0, duration: 0.15, delay: 0, removeOnCompletion: false) self.menuButton.layer.animateScale(from: 0.3, to: 1.0, duration: 0.15, delay: 0, removeOnCompletion: false)
} }
prevPreviewInputPanelNode.sendButton.layer.animateScale(from: 1.0, to: 0.3, duration: 0.15, removeOnCompletion: false)
prevPreviewInputPanelNode.sendButton.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.15, removeOnCompletion: false)
} }
var clippingDelta: CGFloat = 0.0 var clippingDelta: CGFloat = 0.0
@ -1760,23 +1769,22 @@ class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDelegate {
if self.extendedSearchLayout { if self.extendedSearchLayout {
hideMicButton = true hideMicButton = true
if !self.actionButtons.sendButton.alpha.isZero { if !self.actionButtons.sendContainerNode.alpha.isZero {
self.actionButtons.sendButton.alpha = 0.0 self.actionButtons.sendContainerNode.alpha = 0.0
self.actionButtons.sendButtonRadialStatusNode?.alpha = 0.0 self.actionButtons.sendButtonRadialStatusNode?.alpha = 0.0
self.actionButtons.updateAccessibility() self.actionButtons.updateAccessibility()
if animated { if animated {
self.actionButtons.animatingSendButton = true self.actionButtons.animatingSendButton = true
self.actionButtons.sendButton.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.2, completion: { [weak self] _ in self.actionButtons.sendContainerNode.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.2, completion: { [weak self] _ in
if let strongSelf = self { if let strongSelf = self {
strongSelf.actionButtons.animatingSendButton = false strongSelf.actionButtons.animatingSendButton = false
strongSelf.applyUpdateSendButtonIcon() strongSelf.applyUpdateSendButtonIcon()
} }
}) })
self.actionButtons.sendButton.layer.animateScale(from: 1.0, to: 0.2, duration: 0.2) self.actionButtons.sendContainerNode.layer.animateScale(from: 1.0, to: 0.2, duration: 0.2)
self.actionButtons.sendButtonRadialStatusNode?.layer.animateScale(from: 1.0, to: 0.2, duration: 0.2)
self.actionButtons.sendButtonRadialStatusNode?.alpha = 0.0
self.actionButtons.sendButtonRadialStatusNode?.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.2) self.actionButtons.sendButtonRadialStatusNode?.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.2)
self.actionButtons.sendButtonRadialStatusNode?.layer.animateScale(from: 1.0, to: 0.2, duration: 0.2)
} }
} }
if self.searchLayoutClearButton.alpha.isZero { if self.searchLayoutClearButton.alpha.isZero {
@ -1799,30 +1807,30 @@ class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDelegate {
if (hasText || self.keepSendButtonEnabled && !mediaInputIsActive) { if (hasText || self.keepSendButtonEnabled && !mediaInputIsActive) {
hideMicButton = true hideMicButton = true
if self.actionButtons.sendButton.alpha.isZero { if self.actionButtons.sendContainerNode.alpha.isZero {
self.actionButtons.sendButton.alpha = 1.0 self.actionButtons.sendContainerNode.alpha = 1.0
self.actionButtons.sendButtonRadialStatusNode?.alpha = 1.0 self.actionButtons.sendButtonRadialStatusNode?.alpha = 1.0
self.actionButtons.updateAccessibility() self.actionButtons.updateAccessibility()
if animated { if animated {
self.actionButtons.sendButton.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.1) self.actionButtons.sendContainerNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.1)
self.actionButtons.sendButtonRadialStatusNode?.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.1) self.actionButtons.sendButtonRadialStatusNode?.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.1)
if animateWithBounce { if animateWithBounce {
self.actionButtons.sendButton.layer.animateSpring(from: NSNumber(value: Float(0.1)), to: NSNumber(value: Float(1.0)), keyPath: "transform.scale", duration: 0.6) self.actionButtons.sendContainerNode.layer.animateSpring(from: NSNumber(value: Float(0.1)), to: NSNumber(value: Float(1.0)), keyPath: "transform.scale", duration: 0.6)
self.actionButtons.sendButtonRadialStatusNode?.layer.animateSpring(from: NSNumber(value: Float(0.1)), to: NSNumber(value: Float(1.0)), keyPath: "transform.scale", duration: 0.6) self.actionButtons.sendButtonRadialStatusNode?.layer.animateSpring(from: NSNumber(value: Float(0.1)), to: NSNumber(value: Float(1.0)), keyPath: "transform.scale", duration: 0.6)
} else { } else {
self.actionButtons.sendButton.layer.animateScale(from: 0.2, to: 1.0, duration: 0.25) self.actionButtons.sendContainerNode.layer.animateScale(from: 0.2, to: 1.0, duration: 0.25)
self.actionButtons.sendButtonRadialStatusNode?.layer.animateScale(from: 0.2, to: 1.0, duration: 0.25) self.actionButtons.sendButtonRadialStatusNode?.layer.animateScale(from: 0.2, to: 1.0, duration: 0.25)
} }
} }
} }
} else { } else {
if !self.actionButtons.sendButton.alpha.isZero { if !self.actionButtons.sendContainerNode.alpha.isZero {
self.actionButtons.sendButton.alpha = 0.0 self.actionButtons.sendContainerNode.alpha = 0.0
self.actionButtons.sendButtonRadialStatusNode?.alpha = 0.0 self.actionButtons.sendButtonRadialStatusNode?.alpha = 0.0
self.actionButtons.updateAccessibility() self.actionButtons.updateAccessibility()
if animated { if animated {
self.actionButtons.animatingSendButton = true self.actionButtons.animatingSendButton = true
self.actionButtons.sendButton.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.2, completion: { [weak self] _ in self.actionButtons.sendContainerNode.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.2, completion: { [weak self] _ in
if let strongSelf = self { if let strongSelf = self {
strongSelf.actionButtons.animatingSendButton = false strongSelf.actionButtons.animatingSendButton = false
strongSelf.applyUpdateSendButtonIcon() strongSelf.applyUpdateSendButtonIcon()
@ -1914,7 +1922,7 @@ class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDelegate {
} }
@objc func editableTextNodeShouldReturn(_ editableTextNode: ASEditableTextNode) -> Bool { @objc func editableTextNodeShouldReturn(_ editableTextNode: ASEditableTextNode) -> Bool {
if self.actionButtons.sendButton.supernode != nil && !self.actionButtons.sendButton.isHidden && !self.actionButtons.sendButton.alpha.isZero { if self.actionButtons.sendButton.supernode != nil && !self.actionButtons.sendButton.isHidden && !self.actionButtons.sendContainerNode.alpha.isZero {
self.sendButtonPressed() self.sendButtonPressed()
} }
return false return false
@ -1927,12 +1935,12 @@ class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDelegate {
if sendButtonHasApplyIcon != self.actionButtons.sendButtonHasApplyIcon { if sendButtonHasApplyIcon != self.actionButtons.sendButtonHasApplyIcon {
self.actionButtons.sendButtonHasApplyIcon = sendButtonHasApplyIcon self.actionButtons.sendButtonHasApplyIcon = sendButtonHasApplyIcon
if self.actionButtons.sendButtonHasApplyIcon { if self.actionButtons.sendButtonHasApplyIcon {
self.actionButtons.sendButton.setImage(PresentationResourcesChat.chatInputPanelApplyButtonImage(interfaceState.theme), for: []) self.actionButtons.sendButton.setImage(PresentationResourcesChat.chatInputPanelApplyIconImage(interfaceState.theme), for: [])
} else { } else {
if case .scheduledMessages = interfaceState.subject { if case .scheduledMessages = interfaceState.subject {
self.actionButtons.sendButton.setImage(PresentationResourcesChat.chatInputPanelScheduleButtonImage(interfaceState.theme), for: []) self.actionButtons.sendButton.setImage(PresentationResourcesChat.chatInputPanelScheduleIconImage(interfaceState.theme), for: [])
} else { } else {
self.actionButtons.sendButton.setImage(PresentationResourcesChat.chatInputPanelSendButtonImage(interfaceState.theme), for: []) self.actionButtons.sendButton.setImage(PresentationResourcesChat.chatInputPanelSendIconImage(interfaceState.theme), for: [])
} }
} }
} }

View File

@ -856,15 +856,6 @@ private class ChatThemeScreenNode: ViewControllerTracingNode, UIScrollViewDelega
}) })
} }
if animateBackground, let snapshotView = self.cancelButton.view.snapshotView(afterScreenUpdates: false) {
snapshotView.frame = self.cancelButton.frame
self.cancelButton.view.superview?.insertSubview(snapshotView, aboveSubview: self.cancelButton.view)
snapshotView.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.3, delay: delay, removeOnCompletion: false, completion: { [weak snapshotView] _ in
snapshotView?.removeFromSuperview()
})
}
self.listNode.forEachVisibleItemNode { node in self.listNode.forEachVisibleItemNode { node in
if let node = node as? ThemeSettingsThemeItemIconNode { if let node = node as? ThemeSettingsThemeItemIconNode {
node.crossfade() node.crossfade()

View File

@ -1492,6 +1492,8 @@ private final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewD
private var presentationData: PresentationData private var presentationData: PresentationData
fileprivate let cachedDataPromise = Promise<CachedPeerData?>()
let scrollNode: ASScrollNode let scrollNode: ASScrollNode
let headerNode: PeerInfoHeaderNode let headerNode: PeerInfoHeaderNode
@ -2849,6 +2851,7 @@ private final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewD
return return
} }
strongSelf.updateData(data) strongSelf.updateData(data)
strongSelf.cachedDataPromise.set(.single(data.cachedData))
}) })
if let _ = nearbyPeerDistance { if let _ = nearbyPeerDistance {
@ -6509,6 +6512,7 @@ public final class PeerInfoScreenImpl: ViewController, PeerInfoScreen {
fileprivate var presentationData: PresentationData fileprivate var presentationData: PresentationData
private var presentationDataDisposable: Disposable? private var presentationDataDisposable: Disposable?
private let cachedDataPromise = Promise<CachedPeerData?>()
private let accountsAndPeers = Promise<((AccountContext, Peer)?, [(AccountContext, Peer, Int32)])>() private let accountsAndPeers = Promise<((AccountContext, Peer)?, [(AccountContext, Peer, Int32)])>()
private var accountsAndPeersValue: ((AccountContext, Peer)?, [(AccountContext, Peer, Int32)])? private var accountsAndPeersValue: ((AccountContext, Peer)?, [(AccountContext, Peer, Int32)])?
@ -6763,6 +6767,38 @@ public final class PeerInfoScreenImpl: ViewController, PeerInfoScreen {
self?.controllerNode.scrollToTop() self?.controllerNode.scrollToTop()
} }
let presentationDataSignal: Signal<PresentationData, NoError>
if let updatedPresentationData = updatedPresentationData {
presentationDataSignal = updatedPresentationData.signal
} else {
let themeEmoticon: Signal<String?, NoError> = self.cachedDataPromise.get()
|> map { cachedData -> String? in
if let cachedData = cachedData as? CachedUserData {
return cachedData.themeEmoticon
} else if let cachedData = cachedData as? CachedGroupData {
return cachedData.themeEmoticon
} else if let cachedData = cachedData as? CachedChannelData {
return cachedData.themeEmoticon
} else {
return nil
}
}
|> distinctUntilChanged
presentationDataSignal = combineLatest(queue: Queue.mainQueue(), context.sharedContext.presentationData, context.engine.themes.getChatThemes(accountManager: context.sharedContext.accountManager, onlyCached: false), themeEmoticon)
|> map { presentationData, chatThemes, themeEmoticon -> PresentationData in
var presentationData = presentationData
if let themeEmoticon = themeEmoticon, let theme = chatThemes.first(where: { $0.emoji == themeEmoticon }) {
let customTheme = presentationData.theme.overallDarkAppearance ? theme.darkTheme : theme.theme
if let settings = customTheme.settings, let theme = makePresentationTheme(settings: settings) {
presentationData = presentationData.withUpdated(theme: theme)
presentationData = presentationData.withUpdated(chatWallpaper: theme.chat.defaultWallpaper)
}
}
return presentationData
}
}
self.presentationDataDisposable = ((updatedPresentationData?.signal ?? context.sharedContext.presentationData) self.presentationDataDisposable = ((updatedPresentationData?.signal ?? context.sharedContext.presentationData)
|> deliverOnMainQueue).start(next: { [weak self] presentationData in |> deliverOnMainQueue).start(next: { [weak self] presentationData in
if let strongSelf = self { if let strongSelf = self {
@ -6796,6 +6832,7 @@ public final class PeerInfoScreenImpl: ViewController, PeerInfoScreen {
self.displayNode = PeerInfoScreenNode(controller: self, context: self.context, peerId: self.peerId, avatarInitiallyExpanded: self.avatarInitiallyExpanded, isOpenedFromChat: self.isOpenedFromChat, nearbyPeerDistance: self.nearbyPeerDistance, callMessages: self.callMessages, isSettings: self.isSettings, ignoreGroupInCommon: self.ignoreGroupInCommon) self.displayNode = PeerInfoScreenNode(controller: self, context: self.context, peerId: self.peerId, avatarInitiallyExpanded: self.avatarInitiallyExpanded, isOpenedFromChat: self.isOpenedFromChat, nearbyPeerDistance: self.nearbyPeerDistance, callMessages: self.callMessages, isSettings: self.isSettings, ignoreGroupInCommon: self.ignoreGroupInCommon)
self.controllerNode.accountsAndPeers.set(self.accountsAndPeers.get() |> map { $0.1 }) self.controllerNode.accountsAndPeers.set(self.accountsAndPeers.get() |> map { $0.1 })
self.controllerNode.activeSessionsContextAndCount.set(self.activeSessionsContextAndCount.get()) self.controllerNode.activeSessionsContextAndCount.set(self.activeSessionsContextAndCount.get())
self.cachedDataPromise.set(self.controllerNode.cachedDataPromise.get())
self._ready.set(self.controllerNode.ready.get()) self._ready.set(self.controllerNode.ready.get())
super.displayNodeDidLoad() super.displayNodeDidLoad()

View File

@ -227,7 +227,7 @@ class PeerSelectionTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDel
self.textPlaceholderNode.maximumNumberOfLines = 1 self.textPlaceholderNode.maximumNumberOfLines = 1
self.textPlaceholderNode.isUserInteractionEnabled = false self.textPlaceholderNode.isUserInteractionEnabled = false
self.actionButtons = ChatTextInputActionButtonsNode(theme: presentationInterfaceState.theme, strings: presentationInterfaceState.strings, presentController: presentController) self.actionButtons = ChatTextInputActionButtonsNode(presentationInterfaceState: presentationInterfaceState, presentationContext: nil, presentController: presentController)
self.counterTextNode = ImmediateTextNode() self.counterTextNode = ImmediateTextNode()
self.counterTextNode.textAlignment = .center self.counterTextNode.textAlignment = .center
@ -439,7 +439,7 @@ class PeerSelectionTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDel
self.theme = interfaceState.theme self.theme = interfaceState.theme
self.actionButtons.updateTheme(theme: interfaceState.theme) self.actionButtons.updateTheme(theme: interfaceState.theme, wallpaper: interfaceState.chatWallpaper)
let textFieldMinHeight = calclulateTextFieldMinHeight(interfaceState, metrics: metrics) let textFieldMinHeight = calclulateTextFieldMinHeight(interfaceState, metrics: metrics)
let minimalInputHeight: CGFloat = 2.0 + textFieldMinHeight let minimalInputHeight: CGFloat = 2.0 + textFieldMinHeight