mirror of
https://github.com/TelegramMessenger/Telegram-iOS.git
synced 2026-07-06 03:33:41 +02:00
Glass
This commit is contained in:
parent
bd2819e749
commit
f6ba92766b
16 changed files with 1378 additions and 205 deletions
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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() {
|
||||
|
|
|
|||
|
|
@ -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() {
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ swift_library(
|
|||
"//submodules/ComponentFlow",
|
||||
"//submodules/TelegramPresentationData",
|
||||
"//submodules/Components/BundleIconComponent",
|
||||
"//submodules/Components/MultilineTextComponent",
|
||||
],
|
||||
visibility = [
|
||||
"//visibility:public",
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
})
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
@ -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
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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))
|
||||
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue