This commit is contained in:
Isaac 2025-12-03 04:21:09 +08:00
parent bd2819e749
commit f6ba92766b
16 changed files with 1378 additions and 205 deletions

View file

@ -7209,7 +7209,10 @@ private final class ChatListLocationContext {
strings: presentationData.strings,
dateTimeFormat: presentationData.dateTimeFormat,
nameDisplayOrder: presentationData.nameDisplayOrder,
displayBackground: false,
content: .custom(presentationData.strings.ChatList_SelectedTopics(Int32(stateAndFilterId.state.selectedThreadIds.count)), nil, false),
activities: nil,
networkState: nil,
tapped: {
},
longTapped: {
@ -7222,7 +7225,10 @@ private final class ChatListLocationContext {
strings: presentationData.strings,
dateTimeFormat: presentationData.dateTimeFormat,
nameDisplayOrder: presentationData.nameDisplayOrder,
displayBackground: false,
content: .peer(peerView: ChatTitleContent.PeerData(peerView: peerView), customTitle: nil, customSubtitle: nil, onlineMemberCount: onlineMemberCount, isScheduledMessages: false, isMuted: nil, customMessageCount: nil, isEnabled: true),
activities: nil,
networkState: nil,
tapped: { [weak self] in
guard let self else {
return

View file

@ -4,5 +4,5 @@ import UIKit
public protocol NavigationBarTitleView {
func animateLayoutTransition()
func updateLayout(size: CGSize, clearBounds: CGRect, transition: ContainedViewLayoutTransition) -> CGRect
func updateLayout(size: CGSize, clearBounds: CGRect, transition: ContainedViewLayoutTransition)
}

View file

@ -41,7 +41,7 @@ final class GalleryTitleView: UIView, NavigationBarTitleView {
self.dateNode.attributedText = NSAttributedString(string: dateText, font: dateFont, textColor: .white)
}
func updateLayout(size: CGSize, clearBounds: CGRect, transition: ContainedViewLayoutTransition) -> CGRect {
func updateLayout(size: CGSize, clearBounds: CGRect, transition: ContainedViewLayoutTransition) {
let leftInset: CGFloat = 0.0
let rightInset: CGFloat = 0.0
@ -55,8 +55,6 @@ final class GalleryTitleView: UIView, NavigationBarTitleView {
self.authorNameNode.frame = CGRect(origin: CGPoint(x: floor((size.width - authorNameSize.width) / 2.0), y: floor((size.height - dateSize.height - authorNameSize.height - labelsSpacing) / 2.0)), size: authorNameSize)
self.dateNode.frame = CGRect(origin: CGPoint(x: floor((size.width - dateSize.width) / 2.0), y: floor((size.height - dateSize.height - authorNameSize.height - labelsSpacing) / 2.0) + authorNameSize.height + labelsSpacing), size: dateSize)
}
return CGRect()
}
func animateLayoutTransition() {

View file

@ -719,7 +719,7 @@ private final class ItemListTextWithSubtitleTitleView: UIView, NavigationBarTitl
}
}
func updateLayout(size: CGSize, clearBounds: CGRect, transition: ContainedViewLayoutTransition) -> CGRect {
func updateLayout(size: CGSize, clearBounds: CGRect, transition: ContainedViewLayoutTransition) {
self.validLayout = (size, clearBounds)
let titleSize = self.titleNode.updateLayout(size)
@ -731,8 +731,6 @@ private final class ItemListTextWithSubtitleTitleView: UIView, NavigationBarTitl
self.titleNode.frame = titleFrame
self.subtitleNode.frame = subtitleFrame
return titleFrame
}
func animateLayoutTransition() {

View file

@ -15,6 +15,7 @@ swift_library(
"//submodules/ComponentFlow",
"//submodules/TelegramPresentationData",
"//submodules/Components/BundleIconComponent",
"//submodules/Components/MultilineTextComponent",
],
visibility = [
"//visibility:public",

View file

@ -4,6 +4,7 @@ import Display
import ComponentFlow
import TelegramPresentationData
import BundleIconComponent
import MultilineTextComponent
extension ComponentTransition {
func animateBlur(layer: CALayer, from: CGFloat, to: CGFloat, delay: Double = 0.0, removeOnCompletion: Bool = true, completion: ((Bool) -> Void)? = nil) {
@ -46,6 +47,7 @@ public final class AnimatedTextComponent: Component {
public let items: [Item]
public let noDelay: Bool
public let animateScale: Bool
public let animateSlide: Bool
public let preferredDirectionIsDown: Bool
public let blur: Bool
@ -55,6 +57,7 @@ public final class AnimatedTextComponent: Component {
items: [Item],
noDelay: Bool = false,
animateScale: Bool = true,
animateSlide: Bool = true,
preferredDirectionIsDown: Bool = false,
blur: Bool = false
) {
@ -63,6 +66,7 @@ public final class AnimatedTextComponent: Component {
self.items = items
self.noDelay = noDelay
self.animateScale = animateScale
self.animateSlide = animateSlide
self.preferredDirectionIsDown = preferredDirectionIsDown
self.blur = blur
}
@ -83,6 +87,9 @@ public final class AnimatedTextComponent: Component {
if lhs.animateScale != rhs.animateScale {
return false
}
if lhs.animateSlide != rhs.animateSlide {
return false
}
if lhs.preferredDirectionIsDown != rhs.preferredDirectionIsDown {
return false
}
@ -238,10 +245,8 @@ public final class AnimatedTextComponent: Component {
var characterOffset: CGPoint = .zero
switch character {
case let .text(text):
characterComponent = AnyComponent(Text(
text: String(text),
font: component.font,
color: component.color
characterComponent = AnyComponent(MultilineTextComponent(
text: .plain(NSAttributedString(string: text, font: component.font, textColor: component.color))
))
case let .icon(iconName, tint, offset):
characterComponent = AnyComponent(BundleIconComponent(
@ -305,7 +310,9 @@ public final class AnimatedTextComponent: Component {
if component.blur {
ComponentTransition.easeInOut(duration: 0.2).animateBlur(layer: characterComponentView.layer, from: transitionBlurRadius, to: 0.0, delay: delayNorm * delayWidth)
}
characterComponentView.layer.animatePosition(from: CGPoint(x: 0.0, y: characterSize.height * offsetNorm), to: CGPoint(), duration: 0.4, delay: delayNorm * delayWidth, timingFunction: kCAMediaTimingFunctionSpring, additive: true)
if component.animateSlide {
characterComponentView.layer.animatePosition(from: CGPoint(x: 0.0, y: characterSize.height * offsetNorm), to: CGPoint(), duration: 0.4, delay: delayNorm * delayWidth, timingFunction: kCAMediaTimingFunctionSpring, additive: true)
}
characterComponentView.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.18, delay: delayNorm * delayWidth)
}
}
@ -342,7 +349,9 @@ public final class AnimatedTextComponent: Component {
} else {
targetY = characterComponentView.center.y - characterComponentView.bounds.height * offsetNorm
}
outScaleTransition.setPosition(view: characterComponentView, position: CGPoint(x: characterComponentView.center.x, y: targetY), delay: delayNorm * delayWidth)
if component.animateSlide {
outScaleTransition.setPosition(view: characterComponentView, position: CGPoint(x: characterComponentView.center.x, y: targetY), delay: delayNorm * delayWidth)
}
outAlphaTransition.setAlpha(view: characterComponentView, alpha: 0.0, delay: delayNorm * delayWidth, completion: { [weak characterComponentView] _ in
characterComponentView?.removeFromSuperview()
})

View file

@ -670,7 +670,7 @@ public final class ChatListHeaderComponent: Component {
chatListTitleView.theme = theme
chatListTitleView.strings = strings
chatListTitleView.setTitle(chatListTitle, animated: false)
let titleContentRect = chatListTitleView.updateLayout(size: chatListTitleContentSize, clearBounds: CGRect(origin: CGPoint(), size: chatListTitleContentSize), transition: transition.containedViewLayoutTransition)
let titleContentRect = chatListTitleView.updateLayoutInternal(size: chatListTitleContentSize, clearBounds: CGRect(origin: CGPoint(), size: chatListTitleContentSize), transition: transition.containedViewLayoutTransition)
centerContentWidth = floor((chatListTitleContentSize.width * 0.5 - titleContentRect.minX) * 2.0)
let centerOffset = sideContentWidth * 0.5

View file

@ -326,7 +326,11 @@ public final class ChatListTitleView: UIView, NavigationBarTitleView, Navigation
}
}
public func updateLayout(size: CGSize, clearBounds: CGRect, transition: ContainedViewLayoutTransition) -> CGRect {
public func updateLayout(size: CGSize, clearBounds: CGRect, transition: ContainedViewLayoutTransition) {
let _ = self.updateLayoutInternal(size: size, clearBounds: clearBounds, transition: transition)
}
public func updateLayoutInternal(size: CGSize, clearBounds: CGRect, transition: ContainedViewLayoutTransition) -> CGRect {
self.validLayout = (size, clearBounds)
var indicatorPadding: CGFloat = 0.0

View file

@ -32,6 +32,7 @@ swift_library(
"//submodules/TelegramUI/Components/MultiAnimationRenderer:MultiAnimationRenderer",
"//submodules/Components/ComponentDisplayAdapters:ComponentDisplayAdapters",
"//submodules/TelegramUI/Components/GlassBackgroundComponent",
"//submodules/TelegramUI/Components/AnimatedTextComponent",
],
visibility = [
"//visibility:public",

File diff suppressed because it is too large Load diff

View file

@ -14,7 +14,6 @@ import PeerPresenceStatusManager
import ChatTitleActivityNode
import LocalizedPeerData
import PhoneNumberFormat
import ChatTitleActivityNode
import AnimatedCountLabelNode
import AccountContext
import ComponentFlow
@ -23,6 +22,7 @@ import AnimationCache
import MultiAnimationRenderer
import ComponentDisplayAdapters
import GlassBackgroundComponent
import AnimatedTextComponent
private let titleFont = Font.with(size: 17.0, design: .regular, weight: .semibold, traits: [.monospacedNumbers])
private let subtitleFont = Font.regular(13.0)
@ -145,13 +145,13 @@ public enum ChatTitleContent: Equatable {
}
}
private enum ChatTitleIcon {
enum ChatTitleIcon {
case none
case lock
case mute
}
private enum ChatTitleCredibilityIcon: Equatable {
enum ChatTitleCredibilityIcon: Equatable {
case none
case fake
case scam
@ -205,7 +205,7 @@ public final class ChatTitleView: UIView, NavigationBarTitleView {
private var pointerInteraction: PointerInteraction?
public var inputActivities: (PeerId, [(Peer, PeerInputActivity)])? {
public var inputActivities: ChatTitleComponent.Activities? {
didSet {
let _ = self.updateStatus()
}
@ -506,51 +506,51 @@ public final class ChatTitleView: UIView, NavigationBarTitleView {
}
state = .info(NSAttributedString(string: infoText, font: subtitleFont, textColor: titleTheme.rootController.navigationBar.secondaryTextColor), .generic)
case .online:
if let (peerId, inputActivities) = self.inputActivities, !inputActivities.isEmpty, inputActivitiesAllowed {
if let inputActivities = self.inputActivities, !inputActivities.items.isEmpty, inputActivitiesAllowed {
var stringValue = ""
var mergedActivity = inputActivities[0].1
for (_, activity) in inputActivities {
if activity != mergedActivity {
var mergedActivity = inputActivities.items[0].activity
for item in inputActivities.items {
if item.activity != mergedActivity {
mergedActivity = .typingText
break
}
}
if peerId.namespace == Namespaces.Peer.CloudUser || peerId.namespace == Namespaces.Peer.SecretChat {
if inputActivities.peerId.namespace == Namespaces.Peer.CloudUser || inputActivities.peerId.namespace == Namespaces.Peer.SecretChat {
switch mergedActivity {
case .typingText:
stringValue = strings.Conversation_typing
case .uploadingFile:
stringValue = strings.Activity_UploadingDocument
case .recordingVoice:
stringValue = strings.Activity_RecordingAudio
case .uploadingPhoto:
stringValue = strings.Activity_UploadingPhoto
case .uploadingVideo:
stringValue = strings.Activity_UploadingVideo
case .playingGame:
stringValue = strings.Activity_PlayingGame
case .recordingInstantVideo:
stringValue = strings.Activity_RecordingVideoMessage
case .uploadingInstantVideo:
stringValue = strings.Activity_UploadingVideoMessage
case .choosingSticker:
stringValue = strings.Activity_ChoosingSticker
case let .seeingEmojiInteraction(emoticon):
stringValue = strings.Activity_EnjoyingAnimations(emoticon).string
case .speakingInGroupCall, .interactingWithEmoji:
stringValue = ""
case .typingText:
stringValue = strings.Conversation_typing
case .uploadingFile:
stringValue = strings.Activity_UploadingDocument
case .recordingVoice:
stringValue = strings.Activity_RecordingAudio
case .uploadingPhoto:
stringValue = strings.Activity_UploadingPhoto
case .uploadingVideo:
stringValue = strings.Activity_UploadingVideo
case .playingGame:
stringValue = strings.Activity_PlayingGame
case .recordingInstantVideo:
stringValue = strings.Activity_RecordingVideoMessage
case .uploadingInstantVideo:
stringValue = strings.Activity_UploadingVideoMessage
case .choosingSticker:
stringValue = strings.Activity_ChoosingSticker
case let .seeingEmojiInteraction(emoticon):
stringValue = strings.Activity_EnjoyingAnimations(emoticon).string
case .speakingInGroupCall, .interactingWithEmoji:
stringValue = ""
}
} else {
if inputActivities.count > 1 {
let peerTitle = EnginePeer(inputActivities[0].0).compactDisplayTitle
if inputActivities.count == 2 {
let secondPeerTitle = EnginePeer(inputActivities[1].0).compactDisplayTitle
stringValue = strings.Chat_MultipleTypingPair(peerTitle, secondPeerTitle).string
if inputActivities.items.count > 1 {
let peerTitle = inputActivities.items[0].peer.compactDisplayTitle
if inputActivities.items.count == 2 {
let secondPeerTitle = inputActivities.items[1].peer.compactDisplayTitle
stringValue = self.strings.Chat_MultipleTypingPair(peerTitle, secondPeerTitle).string
} else {
stringValue = strings.Chat_MultipleTypingMore(peerTitle, String(inputActivities.count - 1)).string
stringValue = self.strings.Chat_MultipleTypingMore(peerTitle, String(inputActivities.items.count - 1)).string
}
} else if let (peer, _) = inputActivities.first {
stringValue = EnginePeer(peer).compactDisplayTitle
} else if let item = inputActivities.items.first {
stringValue = item.peer.compactDisplayTitle
}
}
let color = titleTheme.rootController.navigationBar.accentTextColor
@ -839,7 +839,7 @@ public final class ChatTitleView: UIView, NavigationBarTitleView {
}
}
public func updateLayout(size: CGSize, clearBounds: CGRect, transition: ContainedViewLayoutTransition) -> CGRect {
public func updateLayout(size: CGSize, clearBounds: CGRect, transition: ContainedViewLayoutTransition) {
self.validLayout = (size, clearBounds)
self.button.frame = clearBounds
@ -1068,8 +1068,6 @@ public final class ChatTitleView: UIView, NavigationBarTitleView {
let componentTransition = ComponentTransition(transition)
componentTransition.setFrame(view: self.backgroundView, frame: backgroundFrame)
self.backgroundView.update(size: backgroundFrame.size, cornerRadius: backgroundFrame.height * 0.5, isDark: self.theme.overallDarkAppearance, tintColor: .init(kind: .panel, color: UIColor(white: self.theme.overallDarkAppearance ? 0.0 : 1.0, alpha: 0.6)), isInteractive: false, transition: componentTransition)
return titleFrame
}
@objc private func buttonPressed() {
@ -1144,122 +1142,3 @@ public final class ChatTitleView: UIView, NavigationBarTitleView {
snapshotView.layer.animatePosition(from: CGPoint(), to: CGPoint(x: -offset.x, y: -offset.y), duration: 0.5, timingFunction: kCAMediaTimingFunctionSpring, removeOnCompletion: false, additive: true)
}
}
public final class ChatTitleComponent: Component {
public let context: AccountContext
public let theme: PresentationTheme
public let strings: PresentationStrings
public let dateTimeFormat: PresentationDateTimeFormat
public let nameDisplayOrder: PresentationPersonNameOrder
public let content: ChatTitleContent
public let tapped: () -> Void
public let longTapped: () -> Void
public init(
context: AccountContext,
theme: PresentationTheme,
strings: PresentationStrings,
dateTimeFormat: PresentationDateTimeFormat,
nameDisplayOrder: PresentationPersonNameOrder,
content: ChatTitleContent,
tapped: @escaping () -> Void,
longTapped: @escaping () -> Void
) {
self.context = context
self.theme = theme
self.strings = strings
self.dateTimeFormat = dateTimeFormat
self.nameDisplayOrder = nameDisplayOrder
self.content = content
self.tapped = tapped
self.longTapped = longTapped
}
public static func ==(lhs: ChatTitleComponent, rhs: ChatTitleComponent) -> Bool {
if lhs.context !== rhs.context {
return false
}
if lhs.theme !== rhs.theme {
return false
}
if lhs.strings !== rhs.strings {
return false
}
if lhs.dateTimeFormat != rhs.dateTimeFormat {
return false
}
if lhs.nameDisplayOrder != rhs.nameDisplayOrder {
return false
}
if lhs.content != rhs.content {
return false
}
return true
}
public final class View: UIView {
public private(set) var contentView: ChatTitleView?
private var component: ChatTitleComponent?
override init(frame: CGRect) {
super.init(frame: frame)
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
func update(component: ChatTitleComponent, availableSize: CGSize, state: EmptyComponentState, environment: Environment<Empty>, transition: ComponentTransition) -> CGSize {
self.component = component
let contentView: ChatTitleView
if let current = self.contentView {
contentView = current
} else {
contentView = ChatTitleView(
context: component.context,
theme: component.theme,
strings: component.strings,
dateTimeFormat: component.dateTimeFormat,
nameDisplayOrder: component.nameDisplayOrder,
animationCache: component.context.animationCache,
animationRenderer: component.context.animationRenderer
)
contentView.pressed = { [weak self] in
guard let self else {
return
}
self.component?.tapped()
}
contentView.longPressed = { [weak self] in
guard let self else {
return
}
self.component?.longTapped()
}
contentView.manualLayout = true
self.contentView = contentView
self.addSubview(contentView)
}
if contentView.titleContent != component.content {
contentView.titleContent = component.content
}
contentView.updateThemeAndStrings(theme: component.theme, strings: component.strings)
let _ = contentView.updateLayout(size: availableSize, clearBounds: CGRect(origin: CGPoint(), size: availableSize), transition: transition.containedViewLayoutTransition)
transition.setFrame(view: contentView, frame: CGRect(origin: CGPoint(), size: availableSize))
return availableSize
}
}
public func makeView() -> View {
return View(frame: CGRect())
}
public func update(view: View, availableSize: CGSize, state: EmptyComponentState, environment: Environment<Empty>, transition: ComponentTransition) -> CGSize {
return view.update(component: self, availableSize: availableSize, state: state, environment: environment, transition: transition)
}
}

View file

@ -0,0 +1,96 @@
import Foundation
import UIKit
import Display
import ComponentFlow
import TelegramPresentationData
final class TitleIconComponent: Component {
enum Kind {
case mute
case lock
}
let kind: Kind
let color: UIColor
init(
kind: Kind,
color: UIColor
) {
self.kind = kind
self.color = color
}
static func ==(lhs: TitleIconComponent, rhs: TitleIconComponent) -> Bool {
if lhs.kind != rhs.kind {
return false
}
if lhs.color != rhs.color {
return false
}
return true
}
final class View: UIView {
let iconView: UIImageView
var component: TitleIconComponent?
override init(frame: CGRect) {
self.iconView = UIImageView()
super.init(frame: frame)
self.addSubview(self.iconView)
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
func update(component: TitleIconComponent, availableSize: CGSize, state: EmptyComponentState, environment: Environment<Empty>, transition: ComponentTransition) -> CGSize {
if self.component?.kind != component.kind {
switch component.kind {
case .mute:
self.iconView.image = generateImage(CGSize(width: 9.0, height: 9.0), rotatedContext: { size, context in
context.clear(CGRect(origin: CGPoint(), size: size))
context.setFillColor(UIColor.white.cgColor)
let _ = try? drawSvgPath(context, path: "M2.97607626,2.27306995 L5.1424026,0.18411241 C5.25492443,0.0756092198 5.40753677,0.0146527621 5.56666667,0.0146527621 C5.89803752,0.0146527621 6.16666667,0.273688014 6.16666667,0.593224191 L6.16666667,5.47790407 L8.86069303,8.18395735 C9.05193038,8.37604845 9.04547086,8.68126082 8.84626528,8.86566828 C8.6470597,9.05007573 8.33054317,9.0438469 8.13930581,8.85175581 L0.139306972,0.816042647 C-0.0519303838,0.623951552 -0.0454708626,0.318739175 0.153734717,0.134331724 C0.352940296,-0.0500757275 0.669456833,-0.0438469035 0.860694189,0.148244192 L2.97607626,2.27306995 Z M0.933196438,2.75856564 L6.16666667,8.01539958 L6.16666667,8.40677707 C6.16666667,8.56022375 6.10345256,8.70738566 5.99093074,8.81588885 C5.75661616,9.04183505 5.37671717,9.04183505 5.1424026,8.81588885 L2.59763107,6.36200202 C2.53511895,6.30172247 2.45033431,6.26785777 2.36192881,6.26785777 L1.16666667,6.26785777 C0.614381917,6.26785777 0.166666667,5.83613235 0.166666667,5.30357206 L0.166666667,3.6964292 C0.166666667,3.24138962 0.493527341,2.85996592 0.933196438,2.75856564 Z ")
})?.withRenderingMode(.alwaysTemplate)
case .lock:
self.iconView.image = generateImage(CGSize(width: 9.0, height: 13.0), rotatedContext: { size, context in
context.clear(CGRect(origin: CGPoint(), size: size))
context.translateBy(x: 0.0, y: 1.0)
context.setFillColor(UIColor.white.cgColor)
context.setStrokeColor(UIColor.white.cgColor)
context.setLineWidth(1.32)
let _ = try? drawSvgPath(context, path: "M4.5,0.600000024 C5.88071187,0.600000024 7,1.88484952 7,3.46979169 L7,7.39687502 C7,8.9818172 5.88071187,10.2666667 4.5,10.2666667 C3.11928813,10.2666667 2,8.9818172 2,7.39687502 L2,3.46979169 C2,1.88484952 3.11928813,0.600000024 4.5,0.600000024 S ")
let _ = try? drawSvgPath(context, path: "M1.32,5.65999985 L7.68,5.65999985 C8.40901587,5.65999985 9,6.25098398 9,6.97999985 L9,10.6733332 C9,11.4023491 8.40901587,11.9933332 7.68,11.9933332 L1.32,11.9933332 C0.59098413,11.9933332 1.11022302e-16,11.4023491 0,10.6733332 L2.22044605e-16,6.97999985 C1.11022302e-16,6.25098398 0.59098413,5.65999985 1.32,5.65999985 Z ")
})?.withRenderingMode(.alwaysTemplate)
}
}
let size = CGSize(width: 14.0, height: 14.0)
if let image = self.iconView.image {
let iconFrame = CGRect(origin: CGPoint(x: floorToScreenPixels((size.width - image.size.width) * 0.5), y: floorToScreenPixels((size.height - image.size.height) * 0.5)), size: image.size)
self.iconView.frame = iconFrame
}
self.iconView.tintColor = component.color
return size
}
}
func makeView() -> View {
return View(frame: CGRect())
}
func update(view: View, availableSize: CGSize, state: EmptyComponentState, environment: Environment<Empty>, transition: ComponentTransition) -> CGSize {
return view.update(component: self, availableSize: availableSize, state: state, environment: environment, transition: transition)
}
}

View file

@ -959,7 +959,7 @@ public final class NavigationBarImpl: ASDisplayNode, NavigationBar {
if let titleView = titleView as? NavigationBarTitleView {
let titleWidth = size.width - (leftTitleInset > 0.0 ? leftTitleInset : rightTitleInset) - (rightTitleInset > 0.0 ? rightTitleInset : leftTitleInset)
let _ = titleView.updateLayout(size: titleFrame.size, clearBounds: CGRect(origin: CGPoint(x: leftTitleInset - titleFrame.minX, y: 0.0), size: CGSize(width: titleWidth, height: titleFrame.height)), transition: titleViewTransition)
titleView.updateLayout(size: titleFrame.size, clearBounds: CGRect(origin: CGPoint(x: leftTitleInset - titleFrame.minX, y: 0.0), size: CGSize(width: titleWidth, height: titleFrame.height)), transition: titleViewTransition)
}
do {
@ -1135,7 +1135,7 @@ public final class NavigationBarImpl: ASDisplayNode, NavigationBar {
return nil
}
if self.passthroughTouches && (result == self.view || result == self.buttonsContainerNode.view) {
if self.passthroughTouches && (result == self.view || result == self.buttonsContainerNode.view || result == self.backgroundNode.view || result == self.backgroundNode.backgroundView) {
return nil
}

View file

@ -125,6 +125,8 @@ import PostSuggestionsSettingsScreen
import ChatSendStarsScreen
import ChatSendAsContextMenu
import GlobalControlPanelsContext
import ComponentFlow
import ComponentDisplayAdapters
extension ChatControllerImpl {
func reloadChatLocation(chatLocation: ChatLocation, chatLocationContextHolder: Atomic<ChatLocationContextHolder?>, historyNode: ChatHistoryListNodeImpl, apply: @escaping ((ContainedViewLayoutTransition?) -> Void) -> Void) {
@ -229,17 +231,6 @@ extension ChatControllerImpl {
}
self.navigationBar?.userInfo = contentData.state.navigationUserInfo
if self.chatTitleView?.titleContent != contentData.state.chatTitleContent {
var animateTitleContents = false
if !synchronous, case let .messageOptions(_, _, info) = self.subject, case .reply = info {
animateTitleContents = true
}
if animateTitleContents && self.chatTitleView?.titleContent != nil {
self.chatTitleView?.animateLayoutTransition()
}
self.chatTitleView?.titleContent = contentData.state.chatTitleContent
}
if let infoAvatar = contentData.state.infoAvatar {
switch infoAvatar {
case let .peer(peer, imageOverride, contextActionIsEnabled, accessibilityLabel):
@ -385,6 +376,9 @@ extension ChatControllerImpl {
if previousState.translationState?.isEnabled != contentData.state.translationState?.isEnabled {
animated = true
}
if previousState.chatTitleContent != contentData.state.chatTitleContent {
animated = true
}
var transition: ContainedViewLayoutTransition = animated ? .animated(duration: 0.4, curve: .spring) : .immediate
if let forceAnimationTransition {
@ -394,6 +388,22 @@ extension ChatControllerImpl {
transition = .immediate
}
if let chatTitleContent = contentData.state.chatTitleContent {
var titleTransition = ComponentTransition(transition)
if case .messageOptions = self.subject {
titleTransition = titleTransition.withAnimation(.none)
}
self.chatTitleView?.update(
context: self.context,
theme: self.presentationData.theme,
strings: self.presentationData.strings,
dateTimeFormat: self.presentationData.dateTimeFormat,
nameDisplayOrder: self.presentationData.nameDisplayOrder,
content: chatTitleContent,
transition: titleTransition
)
}
self.updateChatPresentationInterfaceState(transition: transition, interactive: false, { presentationInterfaceState in
var presentationInterfaceState = presentationInterfaceState
presentationInterfaceState = presentationInterfaceState.updatedPeer({ _ in
@ -4787,7 +4797,18 @@ extension ChatControllerImpl {
return true
}
})
strongSelf.chatTitleView?.inputActivities = (peerId, displayActivities)
strongSelf.chatTitleView?.updateActivities(
activities: ChatTitleComponent.Activities(
peerId: peerId,
items: displayActivities.map { item -> ChatTitleComponent.Activities.Item in
return ChatTitleComponent.Activities.Item(
peer: EnginePeer(item.0),
activity: item.1
)
}
),
transition: .spring(duration: 0.4)
)
strongSelf.peerInputActivitiesPromise.set(.single(activities))

View file

@ -295,7 +295,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
let chatThemePromise = Promise<ChatTheme?>()
let chatWallpaperPromise = Promise<TelegramWallpaper?>()
var chatTitleView: ChatTitleView?
var chatTitleView: ChatNavigationBarTitleView?
var leftNavigationButton: ChatNavigationButton?
var rightNavigationButton: ChatNavigationButton?
var secondaryRightNavigationButton: ChatNavigationButton?
@ -5139,14 +5139,10 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
return true
}
self.chatTitleView = ChatTitleView(context: self.context, theme: self.presentationData.theme, strings: self.presentationData.strings, dateTimeFormat: self.presentationData.dateTimeFormat, nameDisplayOrder: self.presentationData.nameDisplayOrder, animationCache: controllerInteraction.presentationContext.animationCache, animationRenderer: controllerInteraction.presentationContext.animationRenderer)
if case .messageOptions = self.subject {
self.chatTitleView?.disableAnimations = true
}
self.chatTitleView = ChatNavigationBarTitleView(frame: CGRect())
self.navigationItem.titleView = self.chatTitleView
self.chatTitleView?.longPressed = { [weak self] in
self.chatTitleView?.longTapAction = { [weak self] in
if let strongSelf = self, let peerView = strongSelf.contentData?.state.peerView, let peer = peerView.peers[peerView.peerId], peer.restrictionText(platform: "ios", contentSettings: strongSelf.context.currentContentSettings.with { $0 }) == nil && !strongSelf.presentationInterfaceState.isNotAccessible {
if case .standard(.previewing) = strongSelf.mode {
} else {
@ -5532,7 +5528,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
self.moreBarButton.addTarget(self, action: #selector(self.moreButtonPressed), forControlEvents: .touchUpInside)
self.navigationItem.titleView = self.chatTitleView
self.chatTitleView?.pressed = { [weak self] in
self.chatTitleView?.tapAction = { [weak self] in
self?.navigationButtonAction(.openChatInfo(expandAvatar: false, section: nil))
}
@ -6098,7 +6094,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
self.networkStateDisposable = (context.account.networkState |> deliverOnMainQueue).startStrict(next: { [weak self] state in
if let strongSelf = self, case .standard(.default) = strongSelf.presentationInterfaceState.mode {
strongSelf.chatTitleView?.networkState = state
strongSelf.chatTitleView?.updateNetworkState(networkState: state, transition: .spring(duration: 0.4))
}
})
@ -6331,8 +6327,6 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
self.navigationBar?.updatePresentationData(NavigationBarPresentationData(theme: navigationBarTheme, strings: NavigationBarStrings(presentationStrings: self.presentationData.strings)), transition: .immediate)
self.chatTitleView?.updateThemeAndStrings(theme: presentationTheme, strings: self.presentationData.strings)
self.moreBarButton.updateColor(color: presentationTheme.chat.inputPanel.panelControlColor)
}
@ -7197,7 +7191,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
self.storedAnimateFromSnapshotState = nil
if let titleViewSnapshotState = snapshotState.titleViewSnapshotState {
self.chatTitleView?.animateFromSnapshot(titleViewSnapshotState)
self.chatTitleView?.animateFromSnapshot(titleViewSnapshotState, direction: .up)
}
if let avatarSnapshotState = snapshotState.avatarSnapshotState {
(self.chatInfoNavigationButton?.buttonItem.customDisplayNode as? ChatAvatarNavigationNode)?.animateFromSnapshot(avatarSnapshotState)
@ -7396,7 +7390,6 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
super.containerLayoutUpdated(layout, transition: transition)
self.validLayout = layout
self.chatTitleView?.layout = layout
switch self.presentationInterfaceState.mode {
case .standard, .inline:

View file

@ -48,7 +48,16 @@ extension ChatControllerImpl {
contentNode.setErrorText(errorText: self.presentationData.strings.QuickReply_ShortcutExistsInlineError)
}
} else {
self.chatTitleView?.titleContent = .custom("\(value)", nil, false)
self.chatTitleView?.update(
context: self.context,
theme: self.presentationData.theme,
strings: self.presentationData.strings,
dateTimeFormat: self.presentationData.dateTimeFormat,
nameDisplayOrder: self.presentationData.nameDisplayOrder,
content: .custom("\(value)", nil, false),
transition: .immediate
)
alertController?.view.endEditing(true)
alertController?.dismissAnimated()
@ -93,7 +102,15 @@ extension ChatControllerImpl {
} else {
linkUrl = link.url
}
self.chatTitleView?.titleContent = .custom(value.isEmpty ? self.presentationData.strings.Business_Links_EditLinkTitle : value, linkUrl, false)
self.chatTitleView?.update(
context: self.context,
theme: self.presentationData.theme,
strings: self.presentationData.strings,
dateTimeFormat: self.presentationData.dateTimeFormat,
nameDisplayOrder: self.presentationData.nameDisplayOrder,
content: .custom(value.isEmpty ? self.presentationData.strings.Business_Links_EditLinkTitle : value, linkUrl, false),
transition: .immediate
)
if case let .customChatContents(customChatContents) = self.subject {
customChatContents.businessLinkUpdate(message: link.message, entities: link.entities, title: value.isEmpty ? nil : value)
}