diff --git a/submodules/CallListUI/Sources/CallListCallItem.swift b/submodules/CallListUI/Sources/CallListCallItem.swift index 17ae28f7d7..6726c4c1ba 100644 --- a/submodules/CallListUI/Sources/CallListCallItem.swift +++ b/submodules/CallListUI/Sources/CallListCallItem.swift @@ -412,8 +412,8 @@ class CallListCallItemNode: ItemListRevealOptionsItemNode { } else if case let .conferenceCall(conferenceCall) = action.action { isConference = true - if let peer = message.author, !conferenceAvatars.contains(where: { $0.id == peer.id }) { - conferenceAvatars.append(peer) + if let peer = message.peers[message.id.peerId], !conferenceAvatars.contains(where: { $0.id == peer.id }) { + conferenceAvatars.append(EnginePeer(peer)) } for id in conferenceCall.otherParticipants { diff --git a/submodules/CounterControllerTitleView/BUILD b/submodules/CounterControllerTitleView/BUILD index f63f0315bb..133249360f 100644 --- a/submodules/CounterControllerTitleView/BUILD +++ b/submodules/CounterControllerTitleView/BUILD @@ -13,6 +13,7 @@ swift_library( "//submodules/AsyncDisplayKit:AsyncDisplayKit", "//submodules/Display:Display", "//submodules/TelegramPresentationData:TelegramPresentationData", + "//submodules/ComponentFlow", ], visibility = [ "//visibility:public", diff --git a/submodules/CounterControllerTitleView/Sources/CounterControllerTitleView.swift b/submodules/CounterControllerTitleView/Sources/CounterControllerTitleView.swift index 5685a37fcf..4b1fb6b824 100644 --- a/submodules/CounterControllerTitleView/Sources/CounterControllerTitleView.swift +++ b/submodules/CounterControllerTitleView/Sources/CounterControllerTitleView.swift @@ -3,6 +3,7 @@ import UIKit import Display import AsyncDisplayKit import TelegramPresentationData +import ComponentFlow public struct CounterControllerTitle: Equatable { public var title: String @@ -16,24 +17,28 @@ public struct CounterControllerTitle: Equatable { public final class CounterControllerTitleView: UIView { private let titleNode: ImmediateTextNode - private let subtitleNode: ImmediateTextNode + + private var subtitleNode: ImmediateTextNode + private var disappearingSubtitleNode: ImmediateTextNode? public var title: CounterControllerTitle = CounterControllerTitle(title: "", counter: nil) { didSet { if self.title != oldValue { - self.update() + self.update(animated: oldValue.title.isEmpty == self.title.title.isEmpty) } } } public var theme: PresentationTheme { didSet { - self.update() + self.update(animated: false) } } private var primaryTextColor: UIColor? private var secondaryTextColor: UIColor? + + private var nextLayoutTransition: ContainedViewLayoutTransition? public func updateTextColors(primary: UIColor?, secondary: UIColor?, transition: ContainedViewLayoutTransition) { self.primaryTextColor = primary @@ -52,18 +57,40 @@ public final class CounterControllerTitleView: UIView { } } - self.update() + self.update(animated: false) } - private func update() { + private func update(animated: Bool) { let primaryTextColor = self.primaryTextColor ?? self.theme.rootController.navigationBar.primaryTextColor let secondaryTextColor = self.secondaryTextColor ?? self.theme.rootController.navigationBar.secondaryTextColor self.titleNode.attributedText = NSAttributedString(string: self.title.title, font: Font.semibold(17.0), textColor: primaryTextColor) - self.subtitleNode.attributedText = NSAttributedString(string: self.title.counter ?? "", font: Font.with(size: 13.0, traits: .monospacedNumbers), textColor: secondaryTextColor) + + let subtitleText = NSAttributedString(string: self.title.counter ?? "", font: Font.with(size: 13.0, traits: .monospacedNumbers), textColor: secondaryTextColor) + if let previousSubtitleText = self.subtitleNode.attributedText, previousSubtitleText.string.isEmpty != subtitleText.string.isEmpty && subtitleText.string.isEmpty { + if let disappearingSubtitleNode = self.disappearingSubtitleNode { + self.disappearingSubtitleNode = nil + disappearingSubtitleNode.removeFromSupernode() + } + + self.disappearingSubtitleNode = self.subtitleNode + + self.subtitleNode = ImmediateTextNode() + self.subtitleNode.displaysAsynchronously = false + self.subtitleNode.maximumNumberOfLines = 1 + self.subtitleNode.truncationType = .end + self.subtitleNode.isOpaque = false + self.subtitleNode.attributedText = subtitleText + self.addSubnode(self.subtitleNode) + } else { + self.subtitleNode.attributedText = subtitleText + } self.accessibilityLabel = self.title.title self.accessibilityValue = self.title.counter + if animated { + self.nextLayoutTransition = .animated(duration: 0.4, curve: .spring) + } self.setNeedsLayout() } @@ -110,11 +137,31 @@ public final class CounterControllerTitleView: UIView { } else { combinedHeight = titleSize.height } + + var transition: ContainedViewLayoutTransition = .immediate + if let nextLayoutTransition = self.nextLayoutTransition { + if !self.titleNode.bounds.isEmpty { + transition = nextLayoutTransition + } + self.nextLayoutTransition = nil + } let titleFrame = CGRect(origin: CGPoint(x: floor((size.width - titleSize.width) / 2.0), y: floor((size.height - combinedHeight) / 2.0)), size: titleSize) - self.titleNode.frame = titleFrame + self.titleNode.bounds = CGRect(origin: CGPoint(), size: titleFrame.size) + transition.updatePosition(node: self.titleNode, position: titleFrame.center) let subtitleFrame = CGRect(origin: CGPoint(x: floor((size.width - subtitleSize.width) / 2.0), y: floor((size.height - combinedHeight) / 2.0) + titleSize.height + spacing), size: subtitleSize) - self.subtitleNode.frame = subtitleFrame + self.subtitleNode.bounds = CGRect(origin: CGPoint(), size: subtitleFrame.size) + transition.updatePosition(node: self.subtitleNode, position: subtitleFrame.center) + transition.updateTransformScale(node: self.subtitleNode, scale: self.title.counter != nil ? 1.0 : 0.001) + transition.updateAlpha(node: self.subtitleNode, alpha: self.title.counter != nil ? 1.0 : 0.0) + + if let disappearingSubtitleNode = self.disappearingSubtitleNode { + transition.updatePosition(node: disappearingSubtitleNode, position: subtitleFrame.center) + transition.updateTransformScale(node: disappearingSubtitleNode, scale: self.title.counter != nil ? 1.0 : 0.001) + transition.updateAlpha(node: disappearingSubtitleNode, alpha: self.title.counter != nil ? 1.0 : 0.0, completion: { [weak disappearingSubtitleNode] _ in + disappearingSubtitleNode?.removeFromSupernode() + }) + } } } diff --git a/submodules/PeerInfoUI/Sources/ItemListCallListItem.swift b/submodules/PeerInfoUI/Sources/ItemListCallListItem.swift index e9e3d243c4..23bb4f30d1 100644 --- a/submodules/PeerInfoUI/Sources/ItemListCallListItem.swift +++ b/submodules/PeerInfoUI/Sources/ItemListCallListItem.swift @@ -65,58 +65,75 @@ private func stringForCallType(message: Message, strings: PresentationStrings) - var string = "" for media in message.media { switch media { - case let action as TelegramMediaAction: - switch action.action { - case let .phoneCall(_, discardReason, _, isVideo): - let incoming = message.flags.contains(.Incoming) - if let discardReason = discardReason { - switch discardReason { - case .disconnect: - if isVideo { - string = strings.Notification_VideoCallCanceled - } else { - string = strings.Notification_CallCanceled - } - case .missed, .busy: - if incoming { - if isVideo { - string = strings.Notification_VideoCallMissed - } else { - string = strings.Notification_CallMissed - } - } else { - if isVideo { - string = strings.Notification_VideoCallCanceled - } else { - string = strings.Notification_CallCanceled - } - } - case .hangup: - break - } + case let action as TelegramMediaAction: + switch action.action { + case let .phoneCall(_, discardReason, _, isVideo): + let incoming = message.flags.contains(.Incoming) + if let discardReason = discardReason { + switch discardReason { + case .disconnect: + if isVideo { + string = strings.Notification_VideoCallCanceled + } else { + string = strings.Notification_CallCanceled } - - if string.isEmpty { - if incoming { - if isVideo { - string = strings.Notification_VideoCallIncoming - } else { - string = strings.Notification_CallIncoming - } + case .missed, .busy: + if incoming { + if isVideo { + string = strings.Notification_VideoCallMissed } else { - if isVideo { - string = strings.Notification_VideoCallOutgoing - } else { - string = strings.Notification_CallOutgoing - } + string = strings.Notification_CallMissed + } + } else { + if isVideo { + string = strings.Notification_VideoCallCanceled + } else { + string = strings.Notification_CallCanceled } } - default: + case .hangup: break + } + } + + if string.isEmpty { + if incoming { + if isVideo { + string = strings.Notification_VideoCallIncoming + } else { + string = strings.Notification_CallIncoming + } + } else { + if isVideo { + string = strings.Notification_VideoCallOutgoing + } else { + string = strings.Notification_CallOutgoing + } + } + } + case let .conferenceCall(conferenceCall): + let incoming = message.flags.contains(.Incoming) + + let missedTimeout: Int32 = 30 + let currentTime = Int32(Date().timeIntervalSince1970) + + if conferenceCall.flags.contains(.isMissed) { + string = strings.Chat_CallMessage_DeclinedGroupCall + } else if conferenceCall.duration == nil && message.timestamp < currentTime - missedTimeout { + string = strings.Chat_CallMessage_MissedGroupCall + } else { + if incoming { + string = strings.Chat_CallMessage_IncomingGroupCall + } else { + string = strings.Chat_CallMessage_OutgoingGroupCall + } } - default: break + } + + default: + break } } return string diff --git a/submodules/TelegramCore/Sources/State/AccountViewTracker.swift b/submodules/TelegramCore/Sources/State/AccountViewTracker.swift index 3246214fce..a30015757c 100644 --- a/submodules/TelegramCore/Sources/State/AccountViewTracker.swift +++ b/submodules/TelegramCore/Sources/State/AccountViewTracker.swift @@ -2373,9 +2373,6 @@ public final class AccountViewTracker { }() let groupingPredicate: (Message, Message) -> Bool = { lhs, rhs in - if lhs.id.peerId != rhs.id.peerId { - return false - } let lhsTimestamp = ((lhs.timestamp + timezoneOffset) / (granularity)) * (granularity) let rhsTimestamp = ((rhs.timestamp + timezoneOffset) / (granularity)) * (granularity) if lhsTimestamp != rhsTimestamp { @@ -2400,6 +2397,7 @@ public final class AccountViewTracker { } } } + var rhsVideo = false var rhsMissed = false var rhsOther = false @@ -2422,6 +2420,14 @@ public final class AccountViewTracker { if lhsMissed != rhsMissed || lhsOther != rhsOther || lhsVideo != rhsVideo || lhsConferenceId != rhsConferenceId { return false } + + if lhsConferenceId != nil && rhsConferenceId != nil { + } else { + if lhs.id.peerId != rhs.id.peerId { + return false + } + } + return true }