From fdae5ffdf34110c823f33c3c64df8372803a6be6 Mon Sep 17 00:00:00 2001 From: Ilya Laktyushin Date: Sat, 18 Feb 2023 22:55:02 +0400 Subject: [PATCH 01/15] Cherry-pick some fixes --- .../Telegram-iOS/en.lproj/Localizable.strings | 45 +++++--- ...tionSequencePhoneEntryControllerNode.swift | 4 +- .../Source/Base/Transition.swift | 4 + .../Source/Components/Button.swift | 2 +- .../Sources/BlurredBackgroundComponent.swift | 10 +- .../Navigation/NavigationController.swift | 11 +- submodules/Display/Source/NavigationBar.swift | 2 +- .../Sources/MediaPickerGridItem.swift | 11 ++ .../Sources/MediaPickerScreen.swift | 7 ++ .../Sources/EmojiHeaderComponent.swift | 4 +- .../RecentSessionScreen.swift | 71 +++++++++++- .../TelegramUI/Sources/ChatController.swift | 102 ++---------------- .../Sources/ChatControllerNode.swift | 12 ++- .../Sources/ChatHistoryListNode.swift | 15 ++- .../ChatInterfaceStateContextMenus.swift | 22 ++-- .../ChatInterfaceTitlePanelNodes.swift | 3 + .../ChatInviteRequestsTitlePanelNode.swift | 2 +- .../Sources/ChatMessageItemView.swift | 15 ++- .../ChatPinnedMessageTitlePanelNode.swift | 2 +- .../ChatReportPeerTitlePanelNode.swift | 15 ++- .../ChatRequestInProgressTitlePanelNode.swift | 2 +- .../Sources/ChatTitleAccessoryPanelNode.swift | 1 + .../Sources/ChatToastAlertPanelNode.swift | 2 +- .../Sources/ChatTranslationPanelNode.swift | 28 +++-- submodules/TelegramUI/Sources/OpenUrl.swift | 36 +++---- .../Sources/PeerInfo/PeerInfoScreen.swift | 4 +- .../UrlHandling/Sources/UrlHandling.swift | 4 +- 27 files changed, 255 insertions(+), 181 deletions(-) diff --git a/Telegram/Telegram-iOS/en.lproj/Localizable.strings b/Telegram/Telegram-iOS/en.lproj/Localizable.strings index afa80d1900..360145e7b5 100644 --- a/Telegram/Telegram-iOS/en.lproj/Localizable.strings +++ b/Telegram/Telegram-iOS/en.lproj/Localizable.strings @@ -384,7 +384,7 @@ "Tour.Text2" = "**Telegram** delivers messages\nfaster than any other application."; "Tour.Title3" = "Powerful"; -"Tour.Text3" = "**Telegram** has no limits on\nthe size of your chats and media."; +"Tour.Text3" = "**Telegram** has no limits on\nthe size of your media and chats."; "Tour.Title4" = "Secure"; "Tour.Text4" = "**Telegram** keeps your messages\nsafe from hacker attacks."; @@ -393,30 +393,30 @@ "Tour.Text5" = "**Telegram** lets you access your\nmessages from multiple devices."; "Tour.Title6" = "Free"; -"Tour.Text6" = "**Telegram** provides free unlimited cloud storage\nfor chats and media."; +"Tour.Text6" = "**Telegram** provides free unlimited\ncloud storage for chats and media."; "Tour.StartButton" = "Start Messaging"; // Login -"Login.PhoneAndCountryHelp" = "Please confirm your country code and enter your phone number."; +"Login.PhoneAndCountryHelp" = "Please confirm your country code\nand enter your phone number."; "Login.CodeSentInternal" = "We've sent the code to the **Telegram** app on your other device"; -"Login.HaveNotReceivedCodeInternal" = "Haven't received the code?"; -"Login.CodeSentSms" = "We have sent you an SMS with the code"; +"Login.HaveNotReceivedCodeInternal" = "Didn't get the code?"; +"Login.CodeSentSms" = "We've sent you an SMS with the code"; "Login.Code" = "Code"; -"Login.WillCallYou" = "You can request a voice call in %@"; -"Login.CallRequestState2" = "Requesting a call from Telegram..."; +"Login.WillCallYou" = "Telegram will call you in %@"; +"Login.CallRequestState2" = "Requesting a call from Telegram…"; "Login.CallRequestState3" = "Telegram dialed your number\n[Didn't get the code?]"; -"Login.EmailNotConfiguredError" = "Please set up an email account."; +"Login.EmailNotConfiguredError" = "An email account is required so that you can send us details about the error.\n\nPlease go to your device‘s settings > Passwords & Accounts > Add account and set up an email account."; "Login.EmailCodeSubject" = "%@, no code"; "Login.EmailCodeBody" = "My phone number is:\n%@\nI can't get an activation code for Telegram."; -"Login.UnknownError" = "An error occurred. Please try again later"; -"Login.InvalidCodeError" = "You have entered an invalid code. Please try again."; +"Login.UnknownError" = "An error occurred, please try again later."; +"Login.InvalidCodeError" = "Invalid code, please try again."; "Login.NetworkError" = "Please check your internet connection and try again."; -"Login.CodeExpiredError" = "Code expired. Please try again."; -"Login.CodeFloodError" = "Limit exceeded. Please try again later."; -"Login.InvalidPhoneError" = "Invalid phone number. Please try again."; -"Login.InvalidFirstNameError" = "Invalid first name. Please try again."; -"Login.InvalidLastNameError" = "Invalid last name. Please try again."; +"Login.CodeExpiredError" = "Code expired, please start over."; +"Login.CodeFloodError" = "Too many attempts, please try again later."; +"Login.InvalidPhoneError" = "Invalid phone number, please try again."; +"Login.InvalidFirstNameError" = "This first name is not allowed, please try another."; +"Login.InvalidLastNameError" = "Sorry, this last name can't be used."; "Login.InvalidPhoneEmailSubject" = "Invalid phone number: %@"; "Login.InvalidPhoneEmailBody" = "I'm trying to use my mobile phone number: %1$@\nBut Telegram says it's invalid. Please help.\n\nApp version: %2$@\nOS version: %3$@\nLocale: %4$@\nMNC: %5$@"; @@ -438,8 +438,8 @@ "Login.InfoAvatarPhoto" = "photo"; "Login.InfoFirstNamePlaceholder" = "First Name"; "Login.InfoLastNamePlaceholder" = "Last Name"; -"Login.InfoDeletePhoto" = "Delete Photo"; -"Login.InfoHelp" = "Enter your name and add a profile picture."; +"Login.InfoDeletePhoto" = "Remove Photo"; +"Login.InfoHelp" = "Enter your name and add a profile photo."; // Login.SelectCountry "Login.SelectCountry.Title" = "Country"; @@ -8919,3 +8919,14 @@ Sorry for the inconvenience."; "ImportStickerPack.ImportingEmojis" = "Importing Emojis"; "ImportStickerPack.CreateNewEmojiPack" = "Create a New Emoji Pack"; + +"VoiceOver.Chat.Sending" = "Sending"; +"VoiceOver.Chat.Failed" = "Failed to send"; + +"VoiceOver.Chat.PlayedByRecipient" = "Played by recipient"; +"VoiceOver.Chat.PlayedByRecipients" = "Played by recipients"; + +"VoiceOver.Chat.NotPlayedByRecipient" = "Not played by recipient"; +"VoiceOver.Chat.NotPlayedByRecipients" = "Not played by recipients"; + +"VoiceOver.Chat.ReplyingToMessage" = "In reply to message: %@"; diff --git a/submodules/AuthorizationUI/Sources/AuthorizationSequencePhoneEntryControllerNode.swift b/submodules/AuthorizationUI/Sources/AuthorizationSequencePhoneEntryControllerNode.swift index d28dfd9e8c..3aa3319f14 100644 --- a/submodules/AuthorizationUI/Sources/AuthorizationSequencePhoneEntryControllerNode.swift +++ b/submodules/AuthorizationUI/Sources/AuthorizationSequencePhoneEntryControllerNode.swift @@ -782,8 +782,8 @@ final class PhoneConfirmationController: ViewController { self.dimNode.backgroundColor = UIColor(white: 0.0, alpha: 0.4) self.backgroundNode = ASDisplayNode() - self.backgroundNode.backgroundColor = theme.list.plainBackgroundColor - self.backgroundNode.cornerRadius = 11.0 + self.backgroundNode.backgroundColor = theme.list.itemBlocksBackgroundColor + self.backgroundNode.cornerRadius = 24.0 self.textNode = ImmediateTextNode() self.textNode.displaysAsynchronously = false diff --git a/submodules/ComponentFlow/Source/Base/Transition.swift b/submodules/ComponentFlow/Source/Base/Transition.swift index 2e81ec8f4d..b6f58e0e06 100644 --- a/submodules/ComponentFlow/Source/Base/Transition.swift +++ b/submodules/ComponentFlow/Source/Base/Transition.swift @@ -119,6 +119,10 @@ public struct Transition { public static func easeInOut(duration: Double) -> Transition { return Transition(animation: .curve(duration: duration, curve: .easeInOut)) } + + public static func spring(duration: Double) -> Transition { + return Transition(animation: .curve(duration: duration, curve: .spring)) + } public init(animation: Animation) { self.animation = animation diff --git a/submodules/ComponentFlow/Source/Components/Button.swift b/submodules/ComponentFlow/Source/Components/Button.swift index ed1e57024e..9b64fffeda 100644 --- a/submodules/ComponentFlow/Source/Components/Button.swift +++ b/submodules/ComponentFlow/Source/Components/Button.swift @@ -126,7 +126,7 @@ public final class Button: Component { alpha = 1.0 } } else { - alpha = 0.4 + alpha = 0.3 } transition.setAlpha(view: self.contentView, alpha: alpha) } diff --git a/submodules/Components/BlurredBackgroundComponent/Sources/BlurredBackgroundComponent.swift b/submodules/Components/BlurredBackgroundComponent/Sources/BlurredBackgroundComponent.swift index df5f156d2a..ed008b2184 100644 --- a/submodules/Components/BlurredBackgroundComponent/Sources/BlurredBackgroundComponent.swift +++ b/submodules/Components/BlurredBackgroundComponent/Sources/BlurredBackgroundComponent.swift @@ -7,13 +7,16 @@ import ComponentDisplayAdapters public final class BlurredBackgroundComponent: Component { public let color: UIColor public let tintContainerView: UIView? + public let cornerRadius: CGFloat public init( color: UIColor, - tintContainerView: UIView? = nil + tintContainerView: UIView? = nil, + cornerRadius: CGFloat = 0.0 ) { self.color = color self.tintContainerView = tintContainerView + self.cornerRadius = cornerRadius } public static func ==(lhs: BlurredBackgroundComponent, rhs: BlurredBackgroundComponent) -> Bool { @@ -23,6 +26,9 @@ public final class BlurredBackgroundComponent: Component { if lhs.tintContainerView !== rhs.tintContainerView { return false } + if lhs.cornerRadius != rhs.cornerRadius { + return false + } return true } @@ -106,7 +112,7 @@ public final class BlurredBackgroundComponent: Component { view.frame = CGRect(origin: CGPoint(), size: availableSize) }*/ - self.update(size: availableSize, transition: transition.containedViewLayoutTransition) + self.update(size: availableSize, cornerRadius: component.cornerRadius, transition: transition.containedViewLayoutTransition) if let tintContainerView = self.tintContainerView { transition.setFrame(view: tintContainerView, frame: CGRect(origin: CGPoint(), size: availableSize)) diff --git a/submodules/Display/Source/Navigation/NavigationController.swift b/submodules/Display/Source/Navigation/NavigationController.swift index 8bb2c46f06..ab7167d9be 100644 --- a/submodules/Display/Source/Navigation/NavigationController.swift +++ b/submodules/Display/Source/Navigation/NavigationController.swift @@ -1193,22 +1193,25 @@ open class NavigationController: UINavigationController, ContainableController, split.isInFocus = true } + var masterTopHasOpaque = topHasOpaque + var detailTopHasOpaque = topHasOpaque + if let controller = split.masterControllers.last { - if topHasOpaque { + if masterTopHasOpaque { controller.displayNode.accessibilityElementsHidden = true } else { if controller.isOpaqueWhenInOverlay || controller.blocksBackgroundWhenInOverlay { - topHasOpaque = true + masterTopHasOpaque = true } controller.displayNode.accessibilityElementsHidden = false } } if let controller = split.detailControllers.last { - if topHasOpaque { + if detailTopHasOpaque { controller.displayNode.accessibilityElementsHidden = true } else { if controller.isOpaqueWhenInOverlay || controller.blocksBackgroundWhenInOverlay { - topHasOpaque = true + detailTopHasOpaque = true } controller.displayNode.accessibilityElementsHidden = false } diff --git a/submodules/Display/Source/NavigationBar.swift b/submodules/Display/Source/NavigationBar.swift index fd839d4f14..797b72409f 100644 --- a/submodules/Display/Source/NavigationBar.swift +++ b/submodules/Display/Source/NavigationBar.swift @@ -9,7 +9,7 @@ open class SparseNode: ASDisplayNode { if self.alpha.isZero { return nil } - if !self.bounds.contains(point) { + if !self.bounds.inset(by: self.hitTestSlop).contains(point) { return nil } for view in self.view.subviews.reversed() { diff --git a/submodules/MediaPickerUI/Sources/MediaPickerGridItem.swift b/submodules/MediaPickerUI/Sources/MediaPickerGridItem.swift index 4d549e9b53..a1082e8001 100644 --- a/submodules/MediaPickerUI/Sources/MediaPickerGridItem.swift +++ b/submodules/MediaPickerUI/Sources/MediaPickerGridItem.swift @@ -87,6 +87,8 @@ final class MediaPickerGridItemNode: GridItemNode { private let typeIconNode: ASImageNode private let durationNode: ImmediateTextNode + private let activateAreaNode: AccessibilityAreaNode + private var interaction: MediaPickerInteraction? private var theme: PresentationTheme? @@ -114,10 +116,14 @@ final class MediaPickerGridItemNode: GridItemNode { self.typeIconNode.displayWithoutProcessing = true self.durationNode = ImmediateTextNode() + + self.activateAreaNode = AccessibilityAreaNode() + self.activateAreaNode.accessibilityTraits = [.image] super.init() self.addSubnode(self.imageNode) + self.addSubnode(self.activateAreaNode) self.imageNode.contentUpdated = { [weak self] image in self?.spoilerNode?.setImage(image) @@ -285,6 +291,10 @@ final class MediaPickerGridItemNode: GridItemNode { let editingContext = interaction.editingState let asset = fetchResult.object(at: index) + if #available(iOS 15.0, *) { + self.activateAreaNode.accessibilityLabel = "Photo \(asset.creationDate?.formatted(date: .abbreviated, time: .standard) ?? "")" + } + let editedSignal = Signal { subscriber in if let signal = editingContext.thumbnailImageSignal(forIdentifier: asset.localIdentifier) { let disposable = signal.start(next: { next in @@ -411,6 +421,7 @@ final class MediaPickerGridItemNode: GridItemNode { self.imageNode.frame = self.bounds self.gradientNode.frame = CGRect(x: 0.0, y: self.bounds.height - 24.0, width: self.bounds.width, height: 24.0) self.typeIconNode.frame = CGRect(x: 0.0, y: self.bounds.height - 20.0, width: 19.0, height: 19.0) + self.activateAreaNode.frame = self.bounds if self.durationNode.supernode != nil { let durationSize = self.durationNode.updateLayout(self.bounds.size) diff --git a/submodules/MediaPickerUI/Sources/MediaPickerScreen.swift b/submodules/MediaPickerUI/Sources/MediaPickerScreen.swift index 1a334237b8..3c8960f0c3 100644 --- a/submodules/MediaPickerUI/Sources/MediaPickerScreen.swift +++ b/submodules/MediaPickerUI/Sources/MediaPickerScreen.swift @@ -192,6 +192,7 @@ public final class MediaPickerScreen: ViewController, AttachmentContainable { private let backgroundNode: NavigationBackgroundNode private let gridNode: GridNode fileprivate var cameraView: TGAttachmentCameraView? + private var cameraActivateAreaNode: AccessibilityAreaNode private var placeholderNode: MediaPickerPlaceholderNode? private var manageNode: MediaPickerManageNode? private var scrollingArea: SparseItemGridScrollingArea @@ -233,6 +234,10 @@ public final class MediaPickerScreen: ViewController, AttachmentContainable { self.gridNode = GridNode() self.scrollingArea = SparseItemGridScrollingArea() + self.cameraActivateAreaNode = AccessibilityAreaNode() + self.cameraActivateAreaNode.accessibilityLabel = "Camera" + self.cameraActivateAreaNode.accessibilityTraits = [.button] + super.init() if case .assets(nil) = controller.subject { @@ -416,6 +421,7 @@ public final class MediaPickerScreen: ViewController, AttachmentContainable { cameraView.startPreview() self.gridNode.scrollView.addSubview(cameraView) + self.gridNode.addSubnode(self.cameraActivateAreaNode) } else { self.containerNode.clipsToBounds = true } @@ -1067,6 +1073,7 @@ public final class MediaPickerScreen: ViewController, AttachmentContainable { if let cameraView = self.cameraView { if let cameraRect = cameraRect { transition.updateFrame(view: cameraView, frame: cameraRect) + self.cameraActivateAreaNode.frame = cameraRect cameraView.isHidden = false } else { cameraView.isHidden = true diff --git a/submodules/PremiumUI/Sources/EmojiHeaderComponent.swift b/submodules/PremiumUI/Sources/EmojiHeaderComponent.swift index 03cc8821bb..cc28b6c698 100644 --- a/submodules/PremiumUI/Sources/EmojiHeaderComponent.swift +++ b/submodules/PremiumUI/Sources/EmojiHeaderComponent.swift @@ -110,7 +110,9 @@ class EmojiHeaderComponent: Component { } self.statusView.isHidden = false - containerView = containerView.subviews[1].subviews[1] + if containerView.subviews.count > 1 && containerView.subviews[1].subviews.count > 1 { + containerView = containerView.subviews[1].subviews[1] + } let initialPosition = self.statusView.center let targetPosition = self.statusView.superview!.convert(self.statusView.center, to: containerView) diff --git a/submodules/SettingsUI/Sources/Privacy and Security/RecentSessionScreen.swift b/submodules/SettingsUI/Sources/Privacy and Security/RecentSessionScreen.swift index f5a7c8aced..7847792e6e 100644 --- a/submodules/SettingsUI/Sources/Privacy and Security/RecentSessionScreen.swift +++ b/submodules/SettingsUI/Sources/Privacy and Security/RecentSessionScreen.swift @@ -187,8 +187,10 @@ private class RecentSessionScreenNode: ViewControllerTracingNode, UIScrollViewDe private let acceptHeaderNode: ImmediateTextNode private let secretChatsTitleNode: ImmediateTextNode private let secretChatsSwitchNode: SwitchNode + private let secretChatsActivateAreaNode: AccessibilityAreaNode private let incomingCallsTitleNode: ImmediateTextNode private let incomingCallsSwitchNode: SwitchNode + private let incomingCallsActivateAreaNode: AccessibilityAreaNode private let acceptSeparatorNode: ASDisplayNode private let cancelButton: HighlightableButtonNode @@ -264,8 +266,13 @@ private class RecentSessionScreenNode: ViewControllerTracingNode, UIScrollViewDe self.incomingCallsTitleNode = ImmediateTextNode() self.incomingCallsSwitchNode = SwitchNode() + self.secretChatsActivateAreaNode = AccessibilityAreaNode() + self.incomingCallsActivateAreaNode = AccessibilityAreaNode() + self.cancelButton = HighlightableButtonNode() self.cancelButton.setImage(closeButtonImage(theme: self.presentationData.theme), for: .normal) + self.cancelButton.accessibilityLabel = presentationData.strings.Common_Close + self.cancelButton.accessibilityTraits = [.button] self.terminateButton = SolidRoundedButtonNode(theme: SolidRoundedButtonTheme(backgroundColor: self.presentationData.theme.list.itemBlocksBackgroundColor, foregroundColor: self.presentationData.theme.list.itemDestructiveColor), font: .regular, height: 44.0, cornerRadius: 11.0, gloss: false) @@ -341,6 +348,9 @@ private class RecentSessionScreenNode: ViewControllerTracingNode, UIScrollViewDe self.secretChatsSwitchNode.isOn = session.flags.contains(.acceptsSecretChats) self.incomingCallsSwitchNode.isOn = session.flags.contains(.acceptsIncomingCalls) + self.secretChatsActivateAreaNode.accessibilityValue = self.secretChatsSwitchNode.isOn ? presentationData.strings.VoiceOver_Common_On : presentationData.strings.VoiceOver_Common_Off + self.incomingCallsActivateAreaNode.accessibilityValue = self.incomingCallsSwitchNode.isOn ? presentationData.strings.VoiceOver_Common_On : presentationData.strings.VoiceOver_Common_Off + if !session.flags.contains(.passwordPending) && session.apiId != 22 { hasIncomingCalls = true if ![2040, 2496].contains(session.apiId) { @@ -385,24 +395,42 @@ private class RecentSessionScreenNode: ViewControllerTracingNode, UIScrollViewDe } self.titleNode.attributedText = NSAttributedString(string: title, font: Font.regular(30.0), textColor: textColor) + self.titleNode.accessibilityLabel = title + self.titleNode.isAccessibilityElement = true + self.textNode.attributedText = NSAttributedString(string: subtitle, font: Font.regular(17.0), textColor: subtitleActive ? accentColor : secondaryTextColor) + self.textNode.accessibilityLabel = subtitle + self.textNode.isAccessibilityElement = true self.deviceTitleNode.attributedText = NSAttributedString(string: deviceTitle, font: Font.regular(17.0), textColor: textColor) self.deviceValueNode.attributedText = NSAttributedString(string: device, font: Font.regular(17.0), textColor: secondaryTextColor) - + self.deviceValueNode.accessibilityLabel = deviceTitle + self.deviceValueNode.accessibilityValue = device + self.deviceValueNode.isAccessibilityElement = true + self.firstSeparatorNode = ASDisplayNode() self.firstSeparatorNode.backgroundColor = self.presentationData.theme.list.itemBlocksSeparatorColor self.ipTitleNode.attributedText = NSAttributedString(string: self.presentationData.strings.AuthSessions_View_IP, font: Font.regular(17.0), textColor: textColor) self.ipValueNode.attributedText = NSAttributedString(string: ip, font: Font.regular(17.0), textColor: secondaryTextColor) + self.ipValueNode.accessibilityLabel = self.presentationData.strings.AuthSessions_View_IP + self.ipValueNode.accessibilityValue = ip + self.ipValueNode.isAccessibilityElement = true self.secondSeparatorNode = ASDisplayNode() self.secondSeparatorNode.backgroundColor = self.presentationData.theme.list.itemBlocksSeparatorColor self.locationTitleNode.attributedText = NSAttributedString(string: self.presentationData.strings.AuthSessions_View_Location, font: Font.regular(17.0), textColor: textColor) + self.locationValueNode.attributedText = NSAttributedString(string: location, font: Font.regular(17.0), textColor: secondaryTextColor) + self.locationValueNode.accessibilityLabel = self.presentationData.strings.AuthSessions_View_Location + self.locationValueNode.accessibilityValue = location + self.locationValueNode.isAccessibilityElement = true + self.locationInfoNode.attributedText = NSAttributedString(string: self.presentationData.strings.AuthSessions_View_LocationInfo, font: Font.regular(13.0), textColor: secondaryTextColor) self.locationInfoNode.maximumNumberOfLines = 4 + self.locationInfoNode.accessibilityLabel = self.presentationData.strings.AuthSessions_View_LocationInfo + self.locationInfoNode.isAccessibilityElement = true self.acceptBackgroundNode = ASDisplayNode() self.acceptBackgroundNode.clipsToBounds = true @@ -410,9 +438,18 @@ private class RecentSessionScreenNode: ViewControllerTracingNode, UIScrollViewDe self.acceptBackgroundNode.backgroundColor = self.presentationData.theme.list.itemBlocksBackgroundColor self.acceptHeaderNode.attributedText = NSAttributedString(string: self.presentationData.strings.AuthSessions_View_AcceptTitle.uppercased(), font: Font.regular(17.0), textColor: textColor) + self.acceptHeaderNode.accessibilityLabel = self.presentationData.strings.AuthSessions_View_AcceptTitle + self.acceptHeaderNode.isAccessibilityElement = true + self.secretChatsTitleNode.attributedText = NSAttributedString(string: self.presentationData.strings.AuthSessions_View_AcceptSecretChats, font: Font.regular(17.0), textColor: textColor) self.incomingCallsTitleNode.attributedText = NSAttributedString(string: self.presentationData.strings.AuthSessions_View_AcceptIncomingCalls, font: Font.regular(17.0), textColor: textColor) + self.secretChatsActivateAreaNode.accessibilityLabel = self.presentationData.strings.AuthSessions_View_AcceptSecretChats + self.secretChatsActivateAreaNode.accessibilityHint = self.presentationData.strings.VoiceOver_Common_SwitchHint + + self.incomingCallsActivateAreaNode.accessibilityLabel = self.presentationData.strings.AuthSessions_View_AcceptIncomingCalls + self.incomingCallsActivateAreaNode.accessibilityHint = self.presentationData.strings.VoiceOver_Common_SwitchHint + self.acceptSeparatorNode = ASDisplayNode() self.acceptSeparatorNode.backgroundColor = self.presentationData.theme.list.itemBlocksSeparatorColor @@ -463,23 +500,49 @@ private class RecentSessionScreenNode: ViewControllerTracingNode, UIScrollViewDe if hasSecretChats { self.contentContainerNode.addSubnode(self.secretChatsTitleNode) self.contentContainerNode.addSubnode(self.secretChatsSwitchNode) + self.contentContainerNode.addSubnode(self.secretChatsActivateAreaNode) self.secretChatsSwitchNode.valueUpdated = { [weak self] value in if let strongSelf = self { strongSelf.updateAcceptSecretChats?(value) + + strongSelf.secretChatsActivateAreaNode.accessibilityValue = value ? presentationData.strings.VoiceOver_Common_On : presentationData.strings.VoiceOver_Common_Off } } + self.secretChatsActivateAreaNode.activate = { [weak self] in + guard let strongSelf = self else { + return false + } + let value = !strongSelf.secretChatsSwitchNode.isOn + strongSelf.updateAcceptSecretChats?(value) + strongSelf.secretChatsActivateAreaNode.accessibilityValue = value ? presentationData.strings.VoiceOver_Common_On : presentationData.strings.VoiceOver_Common_Off + return true + } + self.contentContainerNode.addSubnode(self.acceptSeparatorNode) } self.contentContainerNode.addSubnode(self.incomingCallsTitleNode) self.contentContainerNode.addSubnode(self.incomingCallsSwitchNode) + self.contentContainerNode.addSubnode(self.incomingCallsActivateAreaNode) self.incomingCallsSwitchNode.valueUpdated = { [weak self] value in if let strongSelf = self { strongSelf.updateAcceptIncomingCalls?(value) + + strongSelf.incomingCallsActivateAreaNode.accessibilityValue = value ? presentationData.strings.VoiceOver_Common_On : presentationData.strings.VoiceOver_Common_Off } } + + self.incomingCallsActivateAreaNode.activate = { [weak self] in + guard let strongSelf = self else { + return false + } + let value = !strongSelf.incomingCallsSwitchNode.isOn + strongSelf.updateAcceptIncomingCalls?(value) + strongSelf.incomingCallsActivateAreaNode.accessibilityValue = value ? presentationData.strings.VoiceOver_Common_On : presentationData.strings.VoiceOver_Common_Off + return true + } } self.cancelButton.addTarget(self, action: #selector(self.cancelButtonPressed), forControlEvents: .touchUpInside) @@ -800,6 +863,7 @@ private class RecentSessionScreenNode: ViewControllerTracingNode, UIScrollViewDe let switchSize = switchView.bounds.size self.secretChatsSwitchNode.frame = CGRect(origin: CGPoint(x: fieldFrame.maxX - switchSize.width - inset, y: secretFrame.minY + floorToScreenPixels((fieldItemHeight - switchSize.height) / 2.0)), size: switchSize) + self.secretChatsActivateAreaNode.frame = CGRect(origin: CGPoint(x: secretFrame.minX, y: secretFrame.minY), size: CGSize(width: fieldFrame.width, height: fieldItemHeight)) } } @@ -815,7 +879,8 @@ private class RecentSessionScreenNode: ViewControllerTracingNode, UIScrollViewDe } let switchSize = switchView.bounds.size - self.incomingCallsSwitchNode.frame = CGRect(origin: CGPoint(x: fieldFrame.maxX - switchSize.width - inset, y: secretFrame.maxY - fieldItemHeight + floorToScreenPixels((fieldItemHeight - switchSize.height) / 2.0)), size: switchSize) + self.incomingCallsSwitchNode.frame = CGRect(origin: CGPoint(x: fieldFrame.maxX - switchSize.width - inset, y: secretFrame.maxY - fieldItemHeight + floorToScreenPixels((fieldItemHeight - switchSize.height) / 2.0)), size: switchSize) + self.incomingCallsActivateAreaNode.frame = CGRect(origin: CGPoint(x: secretFrame.minX, y: secretFrame.maxY - fieldItemHeight), size: CGSize(width: fieldFrame.width, height: fieldItemHeight)) } if let _ = self.acceptBackgroundNode.supernode { @@ -833,8 +898,10 @@ private class RecentSessionScreenNode: ViewControllerTracingNode, UIScrollViewDe if isCurrent { contentHeight -= 68.0 self.terminateButton.isHidden = true + self.terminateButton.isAccessibilityElement = false } else { self.terminateButton.isHidden = false + self.terminateButton.isAccessibilityElement = true } let sideInset = floor((layout.size.width - width) / 2.0) diff --git a/submodules/TelegramUI/Sources/ChatController.swift b/submodules/TelegramUI/Sources/ChatController.swift index f1af62e80b..fe513a77cd 100644 --- a/submodules/TelegramUI/Sources/ChatController.swift +++ b/submodules/TelegramUI/Sources/ChatController.swift @@ -7202,8 +7202,9 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G } mappedTransition = (ChatHistoryListViewTransition(historyView: transition.historyView, deleteItems: deleteItems, insertItems: insertItems, updateItems: transition.updateItems, options: options, scrollToItem: scrollToItem, stationaryItemRange: stationaryItemRange, initialData: transition.initialData, keyboardButtonsMessage: transition.keyboardButtonsMessage, cachedData: transition.cachedData, cachedDataMessages: transition.cachedDataMessages, readStateData: transition.readStateData, scrolledToIndex: transition.scrolledToIndex, scrolledToSomeIndex: transition.scrolledToSomeIndex, peerType: transition.peerType, networkType: transition.networkType, animateIn: false, reason: transition.reason, flashIndicators: transition.flashIndicators), updateSizeAndInsets) - }, updateExtraNavigationBarBackgroundHeight: { value, _ in + }, updateExtraNavigationBarBackgroundHeight: { value, hitTestSlop, _ in strongSelf.additionalNavigationBarBackgroundHeight = value + strongSelf.additionalNavigationBarHitTestSlop = hitTestSlop }) if let mappedTransition = mappedTransition { @@ -11063,6 +11064,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G private var suspendNavigationBarLayout: Bool = false private var suspendedNavigationBarLayout: ContainerViewLayout? private var additionalNavigationBarBackgroundHeight: CGFloat = 0.0 + private var additionalNavigationBarHitTestSlop: CGFloat = 0.0 override public func updateNavigationBarLayout(_ layout: ContainerViewLayout, transition: ContainedViewLayoutTransition) { if self.suspendNavigationBarLayout { @@ -11099,9 +11101,10 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G var navigationBarTransition = transition self.chatDisplayNode.containerLayoutUpdated(layout, navigationBarHeight: self.navigationLayout(layout: layout).navigationFrame.maxY, transition: transition, listViewTransaction: { updateSizeAndInsets, additionalScrollDistance, scrollToTop, completion in self.chatDisplayNode.historyNode.updateLayout(transition: transition, updateSizeAndInsets: updateSizeAndInsets, additionalScrollDistance: additionalScrollDistance, scrollToTop: scrollToTop, completion: completion) - }, updateExtraNavigationBarBackgroundHeight: { value, extraNavigationTransition in + }, updateExtraNavigationBarBackgroundHeight: { value, hitTestSlop, extraNavigationTransition in navigationBarTransition = extraNavigationTransition self.additionalNavigationBarBackgroundHeight = value + self.additionalNavigationBarHitTestSlop = hitTestSlop }) if case .compact = layout.metrics.widthClass { @@ -11122,6 +11125,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G self.suspendedNavigationBarLayout = suspendedNavigationBarLayout self.applyNavigationBarLayout(suspendedNavigationBarLayout, navigationLayout: self.navigationLayout(layout: layout), additionalBackgroundHeight: self.additionalNavigationBarBackgroundHeight, transition: navigationBarTransition) } + self.navigationBar?.additionalContentNode.hitTestSlop = UIEdgeInsets(top: 0.0, left: 0.0, bottom: self.additionalNavigationBarHitTestSlop, right: 0.0) } func updateChatPresentationInterfaceState(animated: Bool = true, interactive: Bool, saveInterfaceState: Bool = false, _ f: (ChatPresentationInterfaceState) -> ChatPresentationInterfaceState, completion: @escaping (ContainedViewLayoutTransition) -> Void = { _ in }) { @@ -16701,101 +16705,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G self.chatDisplayNode.dismissInput() self.present(actionSheet, in: .window(.root)) } - - func avatarPreviewingController(from sourceView: UIView) -> (UIViewController, CGRect)? { - guard let layout = self.validLayout else { - return nil - } - guard let buttonView = (self.chatInfoNavigationButton?.buttonItem.customDisplayNode as? ChatAvatarNavigationNode)?.avatarNode.view else { - return nil - } - if let peer = self.presentationInterfaceState.renderedPeer?.chatMainPeer, peer.smallProfileImage != nil { - let galleryController = AvatarGalleryController(context: self.context, peer: peer, remoteEntries: nil, replaceRootController: { controller, ready in - }, synchronousLoad: true) - galleryController.setHintWillBePresentedInPreviewingContext(true) - galleryController.containerLayoutUpdated(ContainerViewLayout(size: CGSize(width: self.view.bounds.size.width, height: self.view.bounds.size.height), metrics: LayoutMetrics(), deviceMetrics: layout.deviceMetrics, intrinsicInsets: UIEdgeInsets(), safeInsets: UIEdgeInsets(), additionalInsets: UIEdgeInsets(), statusBarHeight: nil, inputHeight: nil, inputHeightIsInteractivellyChanging: false, inVoiceOver: false), transition: .immediate) - return (galleryController, buttonView.convert(buttonView.bounds, to: sourceView)) - } - return nil - } - - func previewingController(from sourceView: UIView, for location: CGPoint) -> (UIViewController, CGRect)? { - guard let layout = self.validLayout, case .phone = layout.deviceMetrics.type, let view = self.chatDisplayNode.view.hitTest(location, with: nil), view.isDescendant(of: self.chatDisplayNode.historyNode.view) else { - return nil - } - let historyPoint = sourceView.convert(location, to: self.chatDisplayNode.historyNode.view) - var result: (Message, ChatMessagePeekPreviewContent)? - self.chatDisplayNode.historyNode.forEachItemNode { itemNode in - if let itemNode = itemNode as? ChatMessageItemView { - if itemNode.frame.contains(historyPoint) { - if let value = itemNode.peekPreviewContent(at: self.chatDisplayNode.historyNode.view.convert(historyPoint, to: itemNode.view)) { - result = value - } - } - } - } - if let (message, content) = result { - switch content { - case let .media(media): - var selectedTransitionNode: (ASDisplayNode, CGRect, () -> (UIView?, UIView?))? - self.chatDisplayNode.historyNode.forEachItemNode { itemNode in - if let itemNode = itemNode as? ChatMessageItemView { - if let result = itemNode.transitionNode(id: message.id, media: media) { - selectedTransitionNode = result - } - } - } - - if let selectedTransitionNode = selectedTransitionNode { - if let previewData = chatMessagePreviewControllerData(context: self.context, chatLocation: self.chatLocation, chatLocationContextHolder: self.chatLocationContextHolder, message: message, standalone: false, reverseMessageGalleryOrder: false, navigationController: self.effectiveNavigationController) { - switch previewData { - case let .gallery(gallery): - gallery.setHintWillBePresentedInPreviewingContext(true) - let rect = selectedTransitionNode.0.view.convert(selectedTransitionNode.0.bounds, to: sourceView) - let sourceRect = rect.insetBy(dx: -2.0, dy: -2.0) - gallery.containerLayoutUpdated(ContainerViewLayout(size: CGSize(width: self.view.bounds.size.width, height: self.view.bounds.size.height), metrics: LayoutMetrics(), deviceMetrics: layout.deviceMetrics, intrinsicInsets: UIEdgeInsets(), safeInsets: UIEdgeInsets(), additionalInsets: UIEdgeInsets(), statusBarHeight: nil, inputHeight: nil, inputHeightIsInteractivellyChanging: false, inVoiceOver: false), transition: .immediate) - return (gallery, sourceRect) - case .instantPage: - break - } - } - } - case let .url(node, rect, string, concealed): - var parsedUrlValue: URL? - if let parsed = URL(string: string) { - parsedUrlValue = parsed - } else if let encoded = (string as NSString).addingPercentEncoding(withAllowedCharacters: .urlQueryValueAllowed), let parsed = URL(string: encoded) { - parsedUrlValue = parsed - } - - if let parsedUrlValue = parsedUrlValue { - if concealed, (parsedUrlValue.scheme == "http" || parsedUrlValue.scheme == "https"), !isConcealedUrlWhitelisted(parsedUrlValue) { - return nil - } - } else { - return nil - } - - let targetRect = node.view.convert(rect, to: sourceView) - let sourceRect = CGRect(origin: CGPoint(x: floor(targetRect.midX), y: floor(targetRect.midY)), size: CGSize(width: 1.0, height: 1.0)) - if let parsedUrl = parsedUrlValue { - if parsedUrl.scheme == "http" || parsedUrl.scheme == "https" { - if #available(iOSApplicationExtension 9.0, iOS 9.0, *) { - let controller = SFSafariViewController(url: parsedUrl) - if #available(iOSApplicationExtension 10.0, iOS 10.0, *) { - controller.preferredBarTintColor = self.presentationData.theme.rootController.navigationBar.opaqueBackgroundColor - controller.preferredControlTintColor = self.presentationData.theme.rootController.navigationBar.accentTextColor - } - return (controller, sourceRect) - } - } - } - } - } - return nil - } - private func presentBanMessageOptions(accountPeerId: PeerId, author: Peer, messageIds: Set, options: ChatAvailableMessageActionOptions) { guard let peerId = self.chatLocation.peerId else { return diff --git a/submodules/TelegramUI/Sources/ChatControllerNode.swift b/submodules/TelegramUI/Sources/ChatControllerNode.swift index a97d0f94f4..03b935eb6b 100644 --- a/submodules/TelegramUI/Sources/ChatControllerNode.swift +++ b/submodules/TelegramUI/Sources/ChatControllerNode.swift @@ -259,7 +259,7 @@ class ChatControllerNode: ASDisplayNode, UIScrollViewDelegate { if let (layout, navigationHeight) = self.validLayout { self.containerLayoutUpdated(layout, navigationBarHeight: navigationHeight, transition: .immediate, listViewTransaction: { _, _, _, _ in - }, updateExtraNavigationBarBackgroundHeight: { _, _ in + }, updateExtraNavigationBarBackgroundHeight: { _, _, _ in }) } } @@ -829,7 +829,7 @@ class ChatControllerNode: ASDisplayNode, UIScrollViewDelegate { } } - func containerLayoutUpdated(_ layout: ContainerViewLayout, navigationBarHeight: CGFloat, transition protoTransition: ContainedViewLayoutTransition, listViewTransaction: (ListViewUpdateSizeAndInsets, CGFloat, Bool, @escaping () -> Void) -> Void, updateExtraNavigationBarBackgroundHeight: (CGFloat, ContainedViewLayoutTransition) -> Void) { + func containerLayoutUpdated(_ layout: ContainerViewLayout, navigationBarHeight: CGFloat, transition protoTransition: ContainedViewLayoutTransition, listViewTransaction: (ListViewUpdateSizeAndInsets, CGFloat, Bool, @escaping () -> Void) -> Void, updateExtraNavigationBarBackgroundHeight: (CGFloat, CGFloat, ContainedViewLayoutTransition) -> Void) { let transition: ContainedViewLayoutTransition if let _ = self.scheduledAnimateInAsOverlayFromNode { transition = .immediate @@ -1068,6 +1068,7 @@ class ChatControllerNode: ASDisplayNode, UIScrollViewDelegate { var immediatelyLayoutTitleAccessoryPanelNodeAndAnimateAppearance = false var titleAccessoryPanelHeight: CGFloat? var titleAccessoryPanelBackgroundHeight: CGFloat? + var titleAccessoryPanelHitTestSlop: CGFloat? var extraTransition = transition if let titleAccessoryPanelNode = titlePanelForChatPresentationInterfaceState(self.chatPresentationInterfaceState, context: self.context, currentPanel: self.titleAccessoryPanelNode, controllerInteraction: self.controllerInteraction, interfaceInteraction: self.interfaceInteraction) { if self.titleAccessoryPanelNode != titleAccessoryPanelNode { @@ -1085,6 +1086,7 @@ class ChatControllerNode: ASDisplayNode, UIScrollViewDelegate { let layoutResult = titleAccessoryPanelNode.updateLayout(width: layout.size.width, leftInset: layout.safeInsets.left, rightInset: layout.safeInsets.right, transition: immediatelyLayoutTitleAccessoryPanelNodeAndAnimateAppearance ? .immediate : transition, interfaceState: self.chatPresentationInterfaceState) titleAccessoryPanelHeight = layoutResult.insetHeight titleAccessoryPanelBackgroundHeight = layoutResult.backgroundHeight + titleAccessoryPanelHitTestSlop = layoutResult.hitTestSlop if immediatelyLayoutTitleAccessoryPanelNodeAndAnimateAppearance { titleAccessoryPanelNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.2) titleAccessoryPanelNode.subnodeTransform = CATransform3DMakeTranslation(0.0, -layoutResult.backgroundHeight, 0.0) @@ -1460,11 +1462,13 @@ class ChatControllerNode: ASDisplayNode, UIScrollViewDelegate { transition.updateFrame(node: self.inputContextOverTextPanelContainer, frame: CGRect(origin: CGPoint(x: 0.0, y: 0.0), size: CGSize(width: layout.size.width, height: layout.size.height))) var extraNavigationBarHeight: CGFloat = 0.0 + var extraNavigationBarHitTestSlop: CGFloat = 0.0 var titleAccessoryPanelFrame: CGRect? if let _ = self.titleAccessoryPanelNode, let panelHeight = titleAccessoryPanelHeight { titleAccessoryPanelFrame = CGRect(origin: CGPoint(x: 0.0, y: 0.0), size: CGSize(width: layout.size.width, height: panelHeight)) insets.top += panelHeight extraNavigationBarHeight += titleAccessoryPanelBackgroundHeight ?? 0.0 + extraNavigationBarHitTestSlop = titleAccessoryPanelHitTestSlop ?? 0.0 } var translationPanelFrame: CGRect? @@ -1474,7 +1478,7 @@ class ChatControllerNode: ASDisplayNode, UIScrollViewDelegate { extraNavigationBarHeight += panelHeight } - updateExtraNavigationBarBackgroundHeight(extraNavigationBarHeight, extraTransition) + updateExtraNavigationBarBackgroundHeight(extraNavigationBarHeight, extraNavigationBarHitTestSlop, extraTransition) var importStatusPanelFrame: CGRect? if let _ = self.chatImportStatusPanel, let panelHeight = importStatusPanelHeight { @@ -3029,7 +3033,7 @@ class ChatControllerNode: ASDisplayNode, UIScrollViewDelegate { if let (layout, navigationHeight) = self.validLayout { self.containerLayoutUpdated(layout, navigationBarHeight: navigationHeight, transition: transition, listViewTransaction: { updateSizeAndInsets, additionalScrollDistance, scrollToTop, completion in self.historyNode.updateLayout(transition: transition, updateSizeAndInsets: updateSizeAndInsets, additionalScrollDistance: additionalScrollDistance, scrollToTop: scrollToTop, completion: completion) - }, updateExtraNavigationBarBackgroundHeight: { _, _ in + }, updateExtraNavigationBarBackgroundHeight: { _, _, _ in }) } } diff --git a/submodules/TelegramUI/Sources/ChatHistoryListNode.swift b/submodules/TelegramUI/Sources/ChatHistoryListNode.swift index 9ff00cdb4f..43db38fa4d 100644 --- a/submodules/TelegramUI/Sources/ChatHistoryListNode.swift +++ b/submodules/TelegramUI/Sources/ChatHistoryListNode.swift @@ -1241,12 +1241,17 @@ public final class ChatHistoryListNode: ListView, ChatHistoryNode { var translateToLanguage: String? if let translationState, isPremium && translationState.isEnabled { - translateToLanguage = translationState.toLang ?? presentationData.strings.baseLanguageCode - if translateToLanguage == "nb" { - translateToLanguage = "no" - } else if translateToLanguage == "pt-br" { - translateToLanguage = "pt" + var languageCode = translationState.toLang ?? presentationData.strings.baseLanguageCode + let rawSuffix = "-raw" + if languageCode.hasSuffix(rawSuffix) { + languageCode = String(languageCode.dropLast(rawSuffix.count)) } + if languageCode == "nb" { + languageCode = "no" + } else if languageCode == "pt-br" { + languageCode = "pt" + } + translateToLanguage = languageCode } let associatedData = extractAssociatedData(chatLocation: chatLocation, view: view, automaticDownloadNetworkType: networkType, animatedEmojiStickers: animatedEmojiStickers, additionalAnimatedEmojiStickers: additionalAnimatedEmojiStickers, subject: subject, currentlyPlayingMessageId: currentlyPlayingMessageIdAndType?.0, isCopyProtectionEnabled: isCopyProtectionEnabled, availableReactions: availableReactions, defaultReaction: defaultReaction, isPremium: isPremium, alwaysDisplayTranscribeButton: alwaysDisplayTranscribeButton, accountPeer: accountPeer, topicAuthorId: topicAuthorId, hasBots: chatHasBots, translateToLanguage: translateToLanguage) diff --git a/submodules/TelegramUI/Sources/ChatInterfaceStateContextMenus.swift b/submodules/TelegramUI/Sources/ChatInterfaceStateContextMenus.swift index 3e32ac62f4..ad12e51f40 100644 --- a/submodules/TelegramUI/Sources/ChatInterfaceStateContextMenus.swift +++ b/submodules/TelegramUI/Sources/ChatInterfaceStateContextMenus.swift @@ -1062,15 +1062,21 @@ func contextMenuForChatPresentationInterfaceState(chatPresentationInterfaceState } } - if !messageText.isEmpty || resourceAvailable || diceEmoji != nil { - let isCopyProtected = chatPresentationInterfaceState.copyProtectionEnabled || message.isCopyProtected() - let message = messages[0] - var isExpired = false - for media in message.media { - if let _ = media as? TelegramMediaExpiredContent { - isExpired = true - } + let message = messages[0] + var isExpired = false + var isImage = false + for media in message.media { + if let _ = media as? TelegramMediaExpiredContent { + isExpired = true } + if media is TelegramMediaImage { + isImage = true + } + } + + if !messageText.isEmpty || (resourceAvailable && isImage) || diceEmoji != nil { + let isCopyProtected = chatPresentationInterfaceState.copyProtectionEnabled || message.isCopyProtected() + if !isExpired { if !isPoll { if !isCopyProtected { diff --git a/submodules/TelegramUI/Sources/ChatInterfaceTitlePanelNodes.swift b/submodules/TelegramUI/Sources/ChatInterfaceTitlePanelNodes.swift index 91eff93325..dd2d188c44 100644 --- a/submodules/TelegramUI/Sources/ChatInterfaceTitlePanelNodes.swift +++ b/submodules/TelegramUI/Sources/ChatInterfaceTitlePanelNodes.swift @@ -52,6 +52,9 @@ func titlePanelForChatPresentationInterfaceState(_ chatPresentationInterfaceStat if inhibitTitlePanelDisplay, let selectedContextValue = selectedContext { switch selectedContextValue { case .pinnedMessage: + if case .peer = chatPresentationInterfaceState.chatLocation { + selectedContext = nil + } break default: selectedContext = nil diff --git a/submodules/TelegramUI/Sources/ChatInviteRequestsTitlePanelNode.swift b/submodules/TelegramUI/Sources/ChatInviteRequestsTitlePanelNode.swift index c0baac19b2..50c9f7d6c3 100644 --- a/submodules/TelegramUI/Sources/ChatInviteRequestsTitlePanelNode.swift +++ b/submodules/TelegramUI/Sources/ChatInviteRequestsTitlePanelNode.swift @@ -208,7 +208,7 @@ final class ChatInviteRequestsTitlePanelNode: ChatTitleAccessoryPanelNode { self.activateAreaNode.frame = CGRect(origin: .zero, size: CGSize(width: width, height: panelHeight)) self.activateAreaNode.accessibilityLabel = interfaceState.strings.Conversation_RequestsToJoin(self.count) - return LayoutResult(backgroundHeight: initialPanelHeight, insetHeight: panelHeight) + return LayoutResult(backgroundHeight: initialPanelHeight, insetHeight: panelHeight, hitTestSlop: 0.0) } @objc func buttonPressed() { diff --git a/submodules/TelegramUI/Sources/ChatMessageItemView.swift b/submodules/TelegramUI/Sources/ChatMessageItemView.swift index 5783330741..e0b8eeb2ad 100644 --- a/submodules/TelegramUI/Sources/ChatMessageItemView.swift +++ b/submodules/TelegramUI/Sources/ChatMessageItemView.swift @@ -232,6 +232,9 @@ final class ChatMessageAccessibilityData { } } else if let file = media as? TelegramMediaFile { var isSpecialFile = false + + let isVideo = file.isInstantVideo + for attribute in file.attributes { switch attribute { case let .Sticker(displayText, _, _): @@ -259,6 +262,9 @@ final class ChatMessageAccessibilityData { } } case let .Audio(isVoice, duration, title, performer, _): + if isVideo { + continue + } isSpecialFile = true if isSelected == nil { hint = item.presentationData.strings.VoiceOver_Chat_PlayHint @@ -573,6 +579,7 @@ final class ChatMessageAccessibilityData { } var (label, value) = dataForMessage(item.message, false) + var replyValue: String? for attribute in item.message.attributes { if let attribute = attribute as? TextEntitiesMessageAttribute { @@ -613,8 +620,8 @@ final class ChatMessageAccessibilityData { replyLabel = item.presentationData.strings.VoiceOver_Chat_ReplyToYourMessage } -// let (replyMessageLabel, replyMessageValue) = dataForMessage(replyMessage, true) -// replyLabel += "\(replyLabel): \(replyMessageLabel), \(replyMessageValue)" + let (_, replyMessageValue) = dataForMessage(replyMessage, true) + replyValue = replyMessageValue label = "\(replyLabel) . \(label)" } @@ -666,6 +673,10 @@ final class ChatMessageAccessibilityData { customActions.append(ChatMessageAccessibilityCustomAction(name: item.presentationData.strings.VoiceOver_MessageContextOpenMessageMenu, target: nil, selector: #selector(self.noop), action: .options)) } + if let replyValue { + value = "\(value). \(item.presentationData.strings.VoiceOver_Chat_ReplyingToMessage(replyValue).string)" + } + self.label = label self.value = value self.hint = hint diff --git a/submodules/TelegramUI/Sources/ChatPinnedMessageTitlePanelNode.swift b/submodules/TelegramUI/Sources/ChatPinnedMessageTitlePanelNode.swift index 44e2e04fe3..0b7a23c3d7 100644 --- a/submodules/TelegramUI/Sources/ChatPinnedMessageTitlePanelNode.swift +++ b/submodules/TelegramUI/Sources/ChatPinnedMessageTitlePanelNode.swift @@ -522,7 +522,7 @@ final class ChatPinnedMessageTitlePanelNode: ChatTitleAccessoryPanelNode { } }*/ - return LayoutResult(backgroundHeight: panelHeight, insetHeight: panelHeight) + return LayoutResult(backgroundHeight: panelHeight, insetHeight: panelHeight, hitTestSlop: 0.0) } private func enqueueTransition(width: CGFloat, panelHeight: CGFloat, leftInset: CGFloat, rightInset: CGFloat, transition: ContainedViewLayoutTransition, animation: PinnedMessageAnimation?, pinnedMessage: ChatPinnedMessage, theme: PresentationTheme, strings: PresentationStrings, nameDisplayOrder: PresentationPersonNameOrder, dateTimeFormat: PresentationDateTimeFormat, accountPeerId: PeerId, firstTime: Bool, isReplyThread: Bool, translateToLanguage: String?) { diff --git a/submodules/TelegramUI/Sources/ChatReportPeerTitlePanelNode.swift b/submodules/TelegramUI/Sources/ChatReportPeerTitlePanelNode.swift index 89b0544ab0..d04a66cebb 100644 --- a/submodules/TelegramUI/Sources/ChatReportPeerTitlePanelNode.swift +++ b/submodules/TelegramUI/Sources/ChatReportPeerTitlePanelNode.swift @@ -168,6 +168,14 @@ private final class ChatInfoTitlePanelInviteInfoNode: ASDisplayNode { } } + override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? { + let result = super.hitTest(point, with: event) + if result == self.view { + return nil + } + return result + } + func update(width: CGFloat, theme: PresentationTheme, strings: PresentationStrings, wallpaper: TelegramWallpaper, chatPeer: Peer, invitedBy: Peer, transition: ContainedViewLayoutTransition) -> CGFloat { let primaryTextColor = serviceMessageColorComponents(theme: theme, wallpaper: wallpaper).primaryText @@ -603,6 +611,7 @@ final class ChatReportPeerTitlePanelNode: ChatTitleAccessoryPanelNode { if let renderedPeer = interfaceState.renderedPeer { chatPeer = renderedPeer.peers[renderedPeer.peerId] } + var hitTestSlop: CGFloat = 0.0 if let chatPeer = chatPeer, (updatedButtons.contains(.block) || updatedButtons.contains(.reportSpam) || updatedButtons.contains(.reportUserSpam)), let invitedBy = interfaceState.contactStatus?.invitedBy { var inviteInfoTransition = transition let inviteInfoNode: ChatInfoTitlePanelInviteInfoNode @@ -623,6 +632,7 @@ final class ChatReportPeerTitlePanelNode: ChatTitleAccessoryPanelNode { let inviteHeight = inviteInfoNode.update(width: width, theme: interfaceState.theme, strings: interfaceState.strings, wallpaper: interfaceState.chatWallpaper, chatPeer: chatPeer, invitedBy: invitedBy, transition: inviteInfoTransition) inviteInfoTransition.updateFrame(node: inviteInfoNode, frame: CGRect(origin: CGPoint(x: 0.0, y: panelHeight + panelInset), size: CGSize(width: width, height: inviteHeight))) panelHeight += inviteHeight + hitTestSlop = -inviteHeight } } else if let inviteInfoNode = self.inviteInfoNode { self.inviteInfoNode = nil @@ -658,7 +668,7 @@ final class ChatReportPeerTitlePanelNode: ChatTitleAccessoryPanelNode { peerNearbyInfoNode?.removeFromSupernode() }) } - return LayoutResult(backgroundHeight: initialPanelHeight, insetHeight: panelHeight + panelInset) + return LayoutResult(backgroundHeight: initialPanelHeight, insetHeight: panelHeight + panelInset, hitTestSlop: hitTestSlop) } @objc func buttonPressed(_ view: UIButton) { @@ -698,6 +708,9 @@ final class ChatReportPeerTitlePanelNode: ChatTitleAccessoryPanelNode { return result } } + if point.y > 40.0 { + return nil + } return super.hitTest(point, with: event) } } diff --git a/submodules/TelegramUI/Sources/ChatRequestInProgressTitlePanelNode.swift b/submodules/TelegramUI/Sources/ChatRequestInProgressTitlePanelNode.swift index b716e487dc..9148b24047 100644 --- a/submodules/TelegramUI/Sources/ChatRequestInProgressTitlePanelNode.swift +++ b/submodules/TelegramUI/Sources/ChatRequestInProgressTitlePanelNode.swift @@ -56,6 +56,6 @@ final class ChatRequestInProgressTitlePanelNode: ChatTitleAccessoryPanelNode { self.activateAreaNode.frame = CGRect(origin: .zero, size: CGSize(width: width, height: panelHeight)) self.activateAreaNode.accessibilityLabel = interfaceState.strings.Channel_NotificationLoading - return LayoutResult(backgroundHeight: panelHeight, insetHeight: panelHeight) + return LayoutResult(backgroundHeight: panelHeight, insetHeight: panelHeight, hitTestSlop: 0.0) } } diff --git a/submodules/TelegramUI/Sources/ChatTitleAccessoryPanelNode.swift b/submodules/TelegramUI/Sources/ChatTitleAccessoryPanelNode.swift index 5a07973883..f7973f8c49 100644 --- a/submodules/TelegramUI/Sources/ChatTitleAccessoryPanelNode.swift +++ b/submodules/TelegramUI/Sources/ChatTitleAccessoryPanelNode.swift @@ -8,6 +8,7 @@ class ChatTitleAccessoryPanelNode: ASDisplayNode { struct LayoutResult { var backgroundHeight: CGFloat var insetHeight: CGFloat + var hitTestSlop: CGFloat } var interfaceInteraction: ChatPanelInterfaceInteraction? diff --git a/submodules/TelegramUI/Sources/ChatToastAlertPanelNode.swift b/submodules/TelegramUI/Sources/ChatToastAlertPanelNode.swift index 5020093f6c..0ab0c145fa 100644 --- a/submodules/TelegramUI/Sources/ChatToastAlertPanelNode.swift +++ b/submodules/TelegramUI/Sources/ChatToastAlertPanelNode.swift @@ -59,6 +59,6 @@ final class ChatToastAlertPanelNode: ChatTitleAccessoryPanelNode { self.activateAreaNode.frame = CGRect(origin: .zero, size: CGSize(width: width, height: panelHeight)) self.activateAreaNode.accessibilityLabel = self.titleNode.attributedText?.string ?? "" - return LayoutResult(backgroundHeight: panelHeight, insetHeight: panelHeight) + return LayoutResult(backgroundHeight: panelHeight, insetHeight: panelHeight, hitTestSlop: 0.0) } } diff --git a/submodules/TelegramUI/Sources/ChatTranslationPanelNode.swift b/submodules/TelegramUI/Sources/ChatTranslationPanelNode.swift index eec1aaf56e..919d13cd24 100644 --- a/submodules/TelegramUI/Sources/ChatTranslationPanelNode.swift +++ b/submodules/TelegramUI/Sources/ChatTranslationPanelNode.swift @@ -634,13 +634,13 @@ private final class TranslationLanguagesContextMenuContent: ContextControllerIte if minVisibleIndex <= maxVisibleIndex { for index in minVisibleIndex ... maxVisibleIndex { - let height = self.languages[index].0.isEmpty ? separatorHeight : itemHeight - var itemFrame = CGRect(origin: CGPoint(x: 0.0, y: CGFloat(index) * itemHeight), size: CGSize(width: size.width, height: height)) - if index > separatorIndex { - itemFrame.origin.y += separatorHeight - itemHeight - } - if index < self.languages.count { + let height = self.languages[index].0.isEmpty ? separatorHeight : itemHeight + var itemFrame = CGRect(origin: CGPoint(x: 0.0, y: CGFloat(index) * itemHeight), size: CGSize(width: size.width, height: height)) + if index > separatorIndex { + itemFrame.origin.y += separatorHeight - itemHeight + } + let (languageCode, displayTitle) = self.languages[index] validIds.insert(index) @@ -690,7 +690,21 @@ private final class TranslationLanguagesContextMenuContent: ContextControllerIte self.presentationData = presentationData - let size = CGSize(width: constrainedSize.width, height: CGFloat(self.languages.count) * itemHeight) + var separatorIndex = 0 + for i in 0 ..< self.languages.count { + if self.languages[i].0.isEmpty { + separatorIndex = i + break + } + } + + var contentHeight: CGFloat + if separatorIndex != 0 { + contentHeight = CGFloat(self.languages.count - 1) * itemHeight + separatorHeight + } else { + contentHeight = CGFloat(self.languages.count) * itemHeight + } + let size = CGSize(width: constrainedSize.width, height: contentHeight) let containerSize = CGSize(width: size.width, height: min(constrainedSize.height, size.height)) self.currentSize = containerSize diff --git a/submodules/TelegramUI/Sources/OpenUrl.swift b/submodules/TelegramUI/Sources/OpenUrl.swift index 1cc5499d27..aff1160039 100644 --- a/submodules/TelegramUI/Sources/OpenUrl.swift +++ b/submodules/TelegramUI/Sources/OpenUrl.swift @@ -884,17 +884,19 @@ func openExternalUrlImpl(context: AccountContext, urlContext: OpenURLContext, ur |> take(1) |> map { sharedData, accessChallengeData -> WebBrowserSettings in let passcodeSettings = sharedData.entries[ApplicationSpecificSharedDataKeys.presentationPasscodeSettings]?.get(PresentationPasscodeSettings.self) ?? PresentationPasscodeSettings.defaultSettings + + var settings: WebBrowserSettings + if let current = sharedData.entries[ApplicationSpecificSharedDataKeys.webBrowserSettings]?.get(WebBrowserSettings.self) { + settings = current + } else { + settings = .defaultSettings + } if accessChallengeData.data.isLockable { - if passcodeSettings.autolockTimeout != nil { - return WebBrowserSettings(defaultWebBrowser: "Safari") + if passcodeSettings.autolockTimeout != nil && settings.defaultWebBrowser == nil { + settings = WebBrowserSettings(defaultWebBrowser: "safari") } } - - if let current = sharedData.entries[ApplicationSpecificSharedDataKeys.webBrowserSettings]?.get(WebBrowserSettings.self) { - return current - } else { - return WebBrowserSettings.defaultSettings - } + return settings } let _ = (settings @@ -902,19 +904,13 @@ func openExternalUrlImpl(context: AccountContext, urlContext: OpenURLContext, ur if settings.defaultWebBrowser == nil { // let controller = BrowserScreen(context: context, subject: .webPage(parsedUrl.absoluteString)) // navigationController?.pushViewController(controller) - if #available(iOSApplicationExtension 9.0, iOS 9.0, *) { - if let window = navigationController?.view.window { - let controller = SFSafariViewController(url: parsedUrl) - if #available(iOSApplicationExtension 10.0, iOS 10.0, *) { - controller.preferredBarTintColor = presentationData.theme.rootController.navigationBar.opaqueBackgroundColor - controller.preferredControlTintColor = presentationData.theme.rootController.navigationBar.accentTextColor - } - window.rootViewController?.present(controller, animated: true) - } else { - context.sharedContext.applicationBindings.openUrl(parsedUrl.absoluteString) - } + if let window = navigationController?.view.window { + let controller = SFSafariViewController(url: parsedUrl) + controller.preferredBarTintColor = presentationData.theme.rootController.navigationBar.opaqueBackgroundColor + controller.preferredControlTintColor = presentationData.theme.rootController.navigationBar.accentTextColor + window.rootViewController?.present(controller, animated: true) } else { - context.sharedContext.applicationBindings.openUrl(url) + context.sharedContext.applicationBindings.openUrl(parsedUrl.absoluteString) } } else { let openInOptions = availableOpenInOptions(context: context, item: .url(url: url)) diff --git a/submodules/TelegramUI/Sources/PeerInfo/PeerInfoScreen.swift b/submodules/TelegramUI/Sources/PeerInfo/PeerInfoScreen.swift index 5c4c349eea..e1d31e5833 100644 --- a/submodules/TelegramUI/Sources/PeerInfo/PeerInfoScreen.swift +++ b/submodules/TelegramUI/Sources/PeerInfo/PeerInfoScreen.swift @@ -4649,13 +4649,13 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate }))) } - if user.botInfo == nil && data.isContact { + if user.botInfo == nil && data.isContact, let peer = strongSelf.data?.peer as? TelegramUser, let phone = peer.phone { items.append(.action(ContextMenuActionItem(text: presentationData.strings.Profile_ShareContactButton, icon: { theme in generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Forward"), color: theme.contextMenu.primaryColor) }, action: { [weak self] _, f in f(.dismissWithoutContent) - if let strongSelf = self, let peer = strongSelf.data?.peer as? TelegramUser, let phone = peer.phone { + if let strongSelf = self { let contact = TelegramMediaContact(firstName: peer.firstName ?? "", lastName: peer.lastName ?? "", phoneNumber: phone, peerId: peer.id, vCardData: nil) let shareController = ShareController(context: strongSelf.context, subject: .media(.standalone(media: contact)), updatedPresentationData: strongSelf.controller?.updatedPresentationData) shareController.completed = { [weak self] peerIds in diff --git a/submodules/UrlHandling/Sources/UrlHandling.swift b/submodules/UrlHandling/Sources/UrlHandling.swift index 75d38106de..963614e1d9 100644 --- a/submodules/UrlHandling/Sources/UrlHandling.swift +++ b/submodules/UrlHandling/Sources/UrlHandling.swift @@ -958,8 +958,8 @@ public func resolveUrlImpl(context: AccountContext, peerId: PeerId?, url: String for scheme in schemes { let basePrefix = scheme + basePath + "/" var url = url - if (url.lowercased().hasPrefix(scheme) && url.lowercased().hasSuffix(".\(basePath)")) { - url = basePrefix + String(url[scheme.endIndex...]).replacingOccurrences(of: ".\(basePath)", with: "") + if (url.lowercased().hasPrefix(scheme) && (url.lowercased().hasSuffix(".\(basePath)") || url.lowercased().contains(".\(basePath)/"))) { + url = basePrefix + String(url[scheme.endIndex...]).replacingOccurrences(of: ".\(basePath)/", with: "").replacingOccurrences(of: ".\(basePath)", with: "") } if url.lowercased().hasPrefix(basePrefix) { if let internalUrl = parseInternalUrl(query: String(url[basePrefix.endIndex...])) { From 0b736f95f5957b927122bc9fa56cedecb574b459 Mon Sep 17 00:00:00 2001 From: Ali <> Date: Sat, 18 Feb 2023 23:05:26 +0400 Subject: [PATCH 02/15] Restore checking code --- submodules/Stripe/Sources/STPBINRange.m | 1 + submodules/Stripe/Sources/STPCardValidator.m | 11 ++++++----- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/submodules/Stripe/Sources/STPBINRange.m b/submodules/Stripe/Sources/STPBINRange.m index 29d9a2b9ba..b3c18e8d4e 100755 --- a/submodules/Stripe/Sources/STPBINRange.m +++ b/submodules/Stripe/Sources/STPBINRange.m @@ -68,6 +68,7 @@ @[@"492960", @"492960", @13, @(STPCardBrandVisa)], @[@"8600", @"8600", @16, @(STPCardBrandOther)], @[@"9860", @"9860", @16, @(STPCardBrandOther)], + @[@"2", @"2", @16, @(STPCardBrandUnknown)], ]; NSMutableArray *binRanges = [NSMutableArray array]; for (NSArray *range in ranges) { diff --git a/submodules/Stripe/Sources/STPCardValidator.m b/submodules/Stripe/Sources/STPCardValidator.m index e94e2fb492..6d3a5902ff 100755 --- a/submodules/Stripe/Sources/STPCardValidator.m +++ b/submodules/Stripe/Sources/STPCardValidator.m @@ -153,13 +153,14 @@ static NSString * _Nonnull stringByRemovingCharactersFromSet(NSString * _Nonnull return STPCardValidationStateIncomplete; } - BOOL isValidLuhn = [self stringIsValidLuhn:sanitizedNumber]; - return isValidLuhn ? STPCardValidationStateValid : STPCardValidationStateInvalid; + //BOOL isValidLuhn = [self stringIsValidLuhn:sanitizedNumber]; + //return isValidLuhn ? STPCardValidationStateValid : STPCardValidationStateInvalid; - /*STPBINRange *binRange = [STPBINRange mostSpecificBINRangeForNumber:sanitizedNumber]; + STPBINRange *binRange = [STPBINRange mostSpecificBINRangeForNumber:sanitizedNumber]; if (binRange.brand == STPCardBrandUnknown && validatingCardBrand) { - return STPCardValidationStateInvalid; + //return STPCardValidationStateInvalid; } + if (sanitizedNumber.length == binRange.length) { BOOL isValidLuhn = [self stringIsValidLuhn:sanitizedNumber]; return isValidLuhn ? STPCardValidationStateValid : STPCardValidationStateInvalid; @@ -167,7 +168,7 @@ static NSString * _Nonnull stringByRemovingCharactersFromSet(NSString * _Nonnull return STPCardValidationStateInvalid; } else { return STPCardValidationStateIncomplete; - }*/ + } } + (STPCardValidationState)validationStateForCard:(nonnull STPCardParams *)card inCurrentYear:(NSInteger)currentYear currentMonth:(NSInteger)currentMonth { From cb108c1b48359cc2fbf897ee76a14bf4f3991a1d Mon Sep 17 00:00:00 2001 From: Ali <> Date: Sat, 18 Feb 2023 23:06:01 +0400 Subject: [PATCH 03/15] Bump version --- versions.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/versions.json b/versions.json index 49abfb2822..c737cdbe30 100644 --- a/versions.json +++ b/versions.json @@ -1,5 +1,5 @@ { - "app": "9.4.2", + "app": "9.4.3", "bazel": "5.3.1", "xcode": "14.2" } From 0f33b3fa4527863e86f78e420e4108aefe977a3f Mon Sep 17 00:00:00 2001 From: Ilya Laktyushin Date: Sun, 19 Feb 2023 00:04:37 +0400 Subject: [PATCH 04/15] Fix bot keyboard not showing up if text field is focused --- submodules/TelegramUI/Sources/ChatControllerNode.swift | 2 ++ submodules/TelegramUI/Sources/ChatTextInputPanelNode.swift | 3 ++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/submodules/TelegramUI/Sources/ChatControllerNode.swift b/submodules/TelegramUI/Sources/ChatControllerNode.swift index 03b935eb6b..02019ca3dc 100644 --- a/submodules/TelegramUI/Sources/ChatControllerNode.swift +++ b/submodules/TelegramUI/Sources/ChatControllerNode.swift @@ -2508,7 +2508,9 @@ class ChatControllerNode: ASDisplayNode, UIScrollViewDelegate { } else { if let inputPanelNode = self.inputPanelNode as? ChatTextInputPanelNode { if inputPanelNode.isFocused { + inputPanelNode.skipPresentationInterfaceStateUpdate = true self.context.sharedContext.mainWindow?.simulateKeyboardDismiss(transition: .animated(duration: 0.5, curve: .spring)) + inputPanelNode.skipPresentationInterfaceStateUpdate = false } } } diff --git a/submodules/TelegramUI/Sources/ChatTextInputPanelNode.swift b/submodules/TelegramUI/Sources/ChatTextInputPanelNode.swift index 1e8f3ff186..e86b38b41b 100644 --- a/submodules/TelegramUI/Sources/ChatTextInputPanelNode.swift +++ b/submodules/TelegramUI/Sources/ChatTextInputPanelNode.swift @@ -3235,12 +3235,13 @@ class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDelegate { self.inputMenu.activate() } + var skipPresentationInterfaceStateUpdate = false func editableTextNodeDidFinishEditing(_ editableTextNode: ASEditableTextNode) { self.storedInputLanguage = editableTextNode.textInputMode.primaryLanguage self.inputMenu.deactivate() self.dismissedEmojiSuggestionPosition = nil - if let presentationInterfaceState = self.presentationInterfaceState { + if let presentationInterfaceState = self.presentationInterfaceState, !self.skipPresentationInterfaceStateUpdate { if let peer = presentationInterfaceState.renderedPeer?.peer as? TelegramUser, peer.botInfo != nil, let keyboardButtonsMessage = presentationInterfaceState.keyboardButtonsMessage, let keyboardMarkup = keyboardButtonsMessage.visibleButtonKeyboardMarkup, keyboardMarkup.flags.contains(.persistent) { self.interfaceInteraction?.updateInputModeAndDismissedButtonKeyboardMessageId { _ in return (.inputButtons(persistent: true), nil) From 79cfa574b5ddb8a583297a5f128d79b6d1f57ec0 Mon Sep 17 00:00:00 2001 From: Mike Renoir <> Date: Tue, 21 Feb 2023 18:22:59 +0400 Subject: [PATCH 05/15] bug fixes --- .../MtProtoKit/MTApiEnvironment.h | 4 +-- .../MtProtoKit/Sources/MTApiEnvironment.m | 26 +++++++------------ .../Sources/Network/Network.swift | 8 +++--- .../Sources/State/ApplyUpdateMessage.swift | 2 +- 4 files changed, 17 insertions(+), 23 deletions(-) diff --git a/submodules/MtProtoKit/PublicHeaders/MtProtoKit/MTApiEnvironment.h b/submodules/MtProtoKit/PublicHeaders/MtProtoKit/MTApiEnvironment.h index bb9059b3d7..7d71e9f620 100644 --- a/submodules/MtProtoKit/PublicHeaders/MtProtoKit/MTApiEnvironment.h +++ b/submodules/MtProtoKit/PublicHeaders/MtProtoKit/MTApiEnvironment.h @@ -55,7 +55,7 @@ @property (nonatomic) int32_t apiId; @property (nonatomic, strong, readonly) NSString * _Nullable deviceModel; -@property (nonatomic, strong, readonly) NSDictionary * _Nullable resolvedDeviceName; +@property (nonatomic, strong, readonly) NSString * _Nullable deviceModelName; @property (nonatomic, strong, readonly) NSString * _Nullable systemVersion; @property (nonatomic, strong) NSString * _Nullable appVersion; @@ -83,6 +83,6 @@ - (MTApiEnvironment * _Nonnull)withUpdatedNetworkSettings:(MTNetworkSettings * _Nullable)networkSettings; - (MTApiEnvironment * _Nonnull)withUpdatedSystemCode:(NSData * _Nullable)systemCode; --(id _Nonnull)initWithResolvedDeviceName:(NSDictionary * _Nullable)resolvedDeviceName; +-(id _Nonnull)initWithDeviceModelName:(NSString * _Nullable)deviceModelName; @end diff --git a/submodules/MtProtoKit/Sources/MTApiEnvironment.m b/submodules/MtProtoKit/Sources/MTApiEnvironment.m index ead804a2d9..c47ec16eab 100644 --- a/submodules/MtProtoKit/Sources/MTApiEnvironment.m +++ b/submodules/MtProtoKit/Sources/MTApiEnvironment.m @@ -428,7 +428,7 @@ static NSData *base64_decode(NSString *str) { @implementation MTApiEnvironment -(instancetype)init { - self = [self initWithResolvedDeviceName:nil]; + self = [self initWithDeviceModelName:nil]; if (self != nil) { @@ -436,22 +436,16 @@ static NSData *base64_decode(NSString *str) { return self; } --(id _Nonnull)initWithResolvedDeviceName:(NSDictionary * _Nullable)resolvedDeviceName { +-(id _Nonnull)initWithDeviceModelName:(NSString * _Nullable)deviceModelName { self = [super init]; if (self != nil) { - if (resolvedDeviceName != nil) { - NSString *model = [self platformString]; - NSString* resolved = resolvedDeviceName[model]; - if (resolved != nil) { - _deviceModel = resolved; - } else { - _deviceModel = model; - } + if (deviceModelName != nil) { + _deviceModel = deviceModelName; } else { _deviceModel = [self platformString]; } - _resolvedDeviceName = resolvedDeviceName; + _deviceModelName = deviceModelName; #if TARGET_OS_IPHONE _systemVersion = [[UIDevice currentDevice] systemVersion]; #else @@ -791,7 +785,7 @@ NSString *suffix = @""; } - (MTApiEnvironment *)withUpdatedLangPackCode:(NSString *)langPackCode { - MTApiEnvironment *result = [[MTApiEnvironment alloc] initWithResolvedDeviceName:_resolvedDeviceName]; + MTApiEnvironment *result = [[MTApiEnvironment alloc] initWithDeviceModelName:_deviceModelName]; result.apiId = self.apiId; result.appVersion = self.appVersion; @@ -815,7 +809,7 @@ NSString *suffix = @""; } - (instancetype)copyWithZone:(NSZone *)__unused zone { - MTApiEnvironment *result = [[MTApiEnvironment alloc] initWithResolvedDeviceName:_resolvedDeviceName]; + MTApiEnvironment *result = [[MTApiEnvironment alloc] initWithDeviceModelName:_deviceModelName]; result.apiId = self.apiId; result.appVersion = self.appVersion; @@ -839,7 +833,7 @@ NSString *suffix = @""; } - (MTApiEnvironment *)withUpdatedSocksProxySettings:(MTSocksProxySettings *)socksProxySettings { - MTApiEnvironment *result = [[MTApiEnvironment alloc] initWithResolvedDeviceName:_resolvedDeviceName]; + MTApiEnvironment *result = [[MTApiEnvironment alloc] initWithDeviceModelName:_deviceModelName]; result.apiId = self.apiId; result.appVersion = self.appVersion; @@ -863,7 +857,7 @@ NSString *suffix = @""; } - (MTApiEnvironment *)withUpdatedNetworkSettings:(MTNetworkSettings *)networkSettings { - MTApiEnvironment *result = [[MTApiEnvironment alloc] initWithResolvedDeviceName:_resolvedDeviceName]; + MTApiEnvironment *result = [[MTApiEnvironment alloc] initWithDeviceModelName:_deviceModelName]; result.apiId = self.apiId; result.appVersion = self.appVersion; @@ -887,7 +881,7 @@ NSString *suffix = @""; } - (MTApiEnvironment *)withUpdatedSystemCode:(NSData *)systemCode { - MTApiEnvironment *result = [[MTApiEnvironment alloc] initWithResolvedDeviceName:_resolvedDeviceName]; + MTApiEnvironment *result = [[MTApiEnvironment alloc] initWithDeviceModelName:_deviceModelName]; result.apiId = self.apiId; result.appVersion = self.appVersion; diff --git a/submodules/TelegramCore/Sources/Network/Network.swift b/submodules/TelegramCore/Sources/Network/Network.swift index c8d553c96b..97af603714 100644 --- a/submodules/TelegramCore/Sources/Network/Network.swift +++ b/submodules/TelegramCore/Sources/Network/Network.swift @@ -432,8 +432,8 @@ public struct NetworkInitializationArguments { public let appData: Signal public let autolockDeadine: Signal public let encryptionProvider: EncryptionProvider - public let resolvedDeviceName:[String: String]? - public init(apiId: Int32, apiHash: String, languagesCategory: String, appVersion: String, voipMaxLayer: Int32, voipVersions: [CallSessionManagerImplementationVersion], appData: Signal, autolockDeadine: Signal, encryptionProvider: EncryptionProvider, resolvedDeviceName:[String: String]?) { + public let deviceModelName:String? + public init(apiId: Int32, apiHash: String, languagesCategory: String, appVersion: String, voipMaxLayer: Int32, voipVersions: [CallSessionManagerImplementationVersion], appData: Signal, autolockDeadine: Signal, encryptionProvider: EncryptionProvider, deviceModelName:String?) { self.apiId = apiId self.apiHash = apiHash self.languagesCategory = languagesCategory @@ -443,7 +443,7 @@ public struct NetworkInitializationArguments { self.appData = appData self.autolockDeadine = autolockDeadine self.encryptionProvider = encryptionProvider - self.resolvedDeviceName = resolvedDeviceName + self.deviceModelName = deviceModelName } } #if os(iOS) @@ -458,7 +458,7 @@ func initializedNetwork(accountId: AccountRecordId, arguments: NetworkInitializa let serialization = Serialization() - var apiEnvironment = MTApiEnvironment(resolvedDeviceName: arguments.resolvedDeviceName) + var apiEnvironment = MTApiEnvironment(deviceModelName: arguments.deviceModelName) apiEnvironment.apiId = arguments.apiId apiEnvironment.langPack = arguments.languagesCategory diff --git a/submodules/TelegramCore/Sources/State/ApplyUpdateMessage.swift b/submodules/TelegramCore/Sources/State/ApplyUpdateMessage.swift index bfa4f25f75..2215e349a6 100644 --- a/submodules/TelegramCore/Sources/State/ApplyUpdateMessage.swift +++ b/submodules/TelegramCore/Sources/State/ApplyUpdateMessage.swift @@ -370,7 +370,7 @@ func applyUpdateGroupMessages(postbox: Postbox, stateManager: AccountStateManage mapping.append((message, MessageIndex(id: id, timestamp: storeMessage.timestamp), storeMessage)) } } else { - assertionFailure() + // assertionFailure() } } else { assertionFailure() From 016519968c260a1082a4a1bcefd2ba25d91cc2e5 Mon Sep 17 00:00:00 2001 From: Ali <> Date: Wed, 22 Feb 2023 20:58:56 +0400 Subject: [PATCH 06/15] Bump version --- versions.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/versions.json b/versions.json index c737cdbe30..f220850f42 100644 --- a/versions.json +++ b/versions.json @@ -1,5 +1,5 @@ { - "app": "9.4.3", + "app": "9.5", "bazel": "5.3.1", "xcode": "14.2" } From 21fbe0d033ab3b04a38371e944006bc02f7842b9 Mon Sep 17 00:00:00 2001 From: Ali <> Date: Tue, 21 Feb 2023 22:13:21 +0400 Subject: [PATCH 07/15] Optimizations --- .../Sources/MultilineTextWithEntitiesComponent.swift | 2 +- .../LegacyComponents/Sources/TGMediaAvatarMenuMixin.m | 2 +- submodules/ManagedFile/Sources/ManagedFile.swift | 6 ++++-- .../Sources/SparseItemGridScrollingArea.swift | 2 +- 4 files changed, 7 insertions(+), 5 deletions(-) diff --git a/submodules/Components/MultilineTextWithEntitiesComponent/Sources/MultilineTextWithEntitiesComponent.swift b/submodules/Components/MultilineTextWithEntitiesComponent/Sources/MultilineTextWithEntitiesComponent.swift index c48a0bf5e5..99543a244b 100644 --- a/submodules/Components/MultilineTextWithEntitiesComponent/Sources/MultilineTextWithEntitiesComponent.swift +++ b/submodules/Components/MultilineTextWithEntitiesComponent/Sources/MultilineTextWithEntitiesComponent.swift @@ -172,7 +172,7 @@ public final class MultilineTextWithEntitiesComponent: Component { self.textNode.longTapAttributeAction = component.longTapAction if case let .curve(duration, _) = transition.animation, let previousText = previousText, previousText != attributedString.string { - if let snapshotView = self.snapshotView(afterScreenUpdates: false) { + if let snapshotView = self.snapshotContentTree() { snapshotView.center = self.center self.superview?.addSubview(snapshotView) diff --git a/submodules/LegacyComponents/Sources/TGMediaAvatarMenuMixin.m b/submodules/LegacyComponents/Sources/TGMediaAvatarMenuMixin.m index 1f91db27ef..6d41c82b63 100644 --- a/submodules/LegacyComponents/Sources/TGMediaAvatarMenuMixin.m +++ b/submodules/LegacyComponents/Sources/TGMediaAvatarMenuMixin.m @@ -205,7 +205,7 @@ return; [strongController dismissAnimated:true]; - if (strongSelf != nil) { + if (strongSelf != nil && strongSelf.requestAvatarEditor) { strongSelf.requestAvatarEditor(^(UIImage *image, void (^commit)(void)) { __strong TGMediaAvatarMenuMixin *strongSelf = weakSelf; if (strongSelf == nil) diff --git a/submodules/ManagedFile/Sources/ManagedFile.swift b/submodules/ManagedFile/Sources/ManagedFile.swift index ba5c4a5cbf..34ddd4eadc 100644 --- a/submodules/ManagedFile/Sources/ManagedFile.swift +++ b/submodules/ManagedFile/Sources/ManagedFile.swift @@ -61,8 +61,10 @@ public final class ManagedFile { if let queue = self.queue { assert(queue.isCurrent()) } - close(self.fd) - self.isClosed = true + if !self.isClosed { + close(self.fd) + self.isClosed = true + } } public func write(_ data: UnsafeRawPointer, count: Int) -> Int { diff --git a/submodules/SparseItemGrid/Sources/SparseItemGridScrollingArea.swift b/submodules/SparseItemGrid/Sources/SparseItemGridScrollingArea.swift index e29e306800..fa1099becf 100644 --- a/submodules/SparseItemGrid/Sources/SparseItemGridScrollingArea.swift +++ b/submodules/SparseItemGrid/Sources/SparseItemGridScrollingArea.swift @@ -628,7 +628,7 @@ public final class RollingText: Component { self.containerView.layer.removeAnimation(forKey: "opacity") } - if let snapshotView = self.containerView.snapshotView(afterScreenUpdates: true) { + if let snapshotView = self.containerView.snapshotContentTree() { let horizontalOffset = boundingRect.width - snapshotView.frame.width let verticalOffset: CGFloat = 12.0 From fd07f15edcf74de2fb997bd1688872a1e6892de8 Mon Sep 17 00:00:00 2001 From: Ali <> Date: Wed, 22 Feb 2023 20:58:08 +0400 Subject: [PATCH 08/15] Defensive Coding --- submodules/Postbox/Sources/Coding.swift | 100 +++++++++++++++++++----- 1 file changed, 80 insertions(+), 20 deletions(-) diff --git a/submodules/Postbox/Sources/Coding.swift b/submodules/Postbox/Sources/Coding.swift index fdbabbf8ef..794aacb0bb 100644 --- a/submodules/Postbox/Sources/Coding.swift +++ b/submodules/Postbox/Sources/Coding.swift @@ -727,27 +727,57 @@ public final class PostboxDecoder { case .Double: offset += 8 case .String: - var length: Int32 = 0 - memcpy(&length, bytes + offset, 4) - offset += 4 + Int(length) + if offset + 4 > length { + offset = 0 + return false + } + + var valueLength: Int32 = 0 + memcpy(&valueLength, bytes + offset, 4) + offset += 4 + Int(valueLength) case .Object: - var length: Int32 = 0 - memcpy(&length, bytes + (offset + 4), 4) - offset += 8 + Int(length) + if offset + 4 > length { + offset = 0 + return false + } + + var valueLength: Int32 = 0 + memcpy(&valueLength, bytes + (offset + 4), 4) + offset += 8 + Int(valueLength) case .Int32Array: - var length: Int32 = 0 - memcpy(&length, bytes + offset, 4) - offset += 4 + Int(length) * 4 + if offset + 4 > length { + offset = 0 + return false + } + + var valueLength: Int32 = 0 + memcpy(&valueLength, bytes + offset, 4) + offset += 4 + Int(valueLength) * 4 case .Int64Array: - var length: Int32 = 0 - memcpy(&length, bytes + offset, 4) - offset += 4 + Int(length) * 8 + if offset + 4 > length { + offset = 0 + return false + } + + var valueLength: Int32 = 0 + memcpy(&valueLength, bytes + offset, 4) + offset += 4 + Int(valueLength) * 8 case .ObjectArray: + if offset + 4 > length { + offset = 0 + return false + } + var subLength: Int32 = 0 memcpy(&subLength, bytes + offset, 4) offset += 4 var i: Int32 = 0 while i < subLength { + if offset + 4 + 4 > length { + offset = 0 + return false + } + var objectLength: Int32 = 0 memcpy(&objectLength, bytes + (offset + 4), 4) offset += 8 + Int(objectLength) @@ -759,32 +789,62 @@ public final class PostboxDecoder { } return true case .ObjectDictionary: - var length: Int32 = 0 - memcpy(&length, bytes + offset, 4) + if offset + 4 > length { + offset = 0 + return false + } + + var valueLength: Int32 = 0 + memcpy(&valueLength, bytes + offset, 4) offset += 4 var i: Int32 = 0 - while i < length { + while i < valueLength { + if offset + 4 + 4 > length { + offset = 0 + return false + } + var keyLength: Int32 = 0 memcpy(&keyLength, bytes + (offset + 4), 4) offset += 8 + Int(keyLength) + if offset + 4 + 4 > length { + offset = 0 + return false + } + var valueLength: Int32 = 0 memcpy(&valueLength, bytes + (offset + 4), 4) offset += 8 + Int(valueLength) i += 1 } case .Bytes: - var length: Int32 = 0 - memcpy(&length, bytes + offset, 4) - offset += 4 + Int(length) + if offset + 4 > length { + offset = 0 + return false + } + + var valueLength: Int32 = 0 + memcpy(&valueLength, bytes + offset, 4) + offset += 4 + Int(valueLength) case .Nil: break case .StringArray, .BytesArray: - var length: Int32 = 0 - memcpy(&length, bytes + offset, 4) + if offset + 4 > length { + offset = 0 + return false + } + + var valueLength: Int32 = 0 + memcpy(&valueLength, bytes + offset, 4) offset += 4 var i: Int32 = 0 while i < length { + if offset + 4 > length { + offset = 0 + return false + } + var stringLength: Int32 = 0 memcpy(&stringLength, bytes + offset, 4) offset += 4 + Int(stringLength) From 0430ea5e493ed6ddcc97246b5a35c3ea630fecf4 Mon Sep 17 00:00:00 2001 From: Ali <> Date: Wed, 22 Feb 2023 21:22:37 +0400 Subject: [PATCH 09/15] Trigger build --- Random.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Random.txt b/Random.txt index c6648d1db0..74c153479b 100644 --- a/Random.txt +++ b/Random.txt @@ -1 +1 @@ -44eed22b384449bcec8962f2fddbfebd +3a64b94cc76109006731756f85403c85 From 5beffde0ad3930fa84dc7561b9076ac51ee242e3 Mon Sep 17 00:00:00 2001 From: Ali <> Date: Fri, 24 Feb 2023 12:12:38 +0400 Subject: [PATCH 10/15] Merge crash fix --- .../Sources/TelegramEngine/Messages/AdMessages.swift | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/submodules/TelegramCore/Sources/TelegramEngine/Messages/AdMessages.swift b/submodules/TelegramCore/Sources/TelegramEngine/Messages/AdMessages.swift index e0fba0edc0..9c96846a99 100644 --- a/submodules/TelegramCore/Sources/TelegramEngine/Messages/AdMessages.swift +++ b/submodules/TelegramCore/Sources/TelegramEngine/Messages/AdMessages.swift @@ -234,10 +234,13 @@ private class AdMessagesHistoryContextImpl { } messagePeers[author.id] = author + + let messageHash = (self.text.hashValue &+ 31 &* peerId.hashValue) &* 31 &+ author.id.hashValue + let messageStableVersion = UInt32(bitPattern: Int32(truncatingIfNeeded: messageHash)) return Message( stableId: 0, - stableVersion: 0, + stableVersion: messageStableVersion, id: MessageId(peerId: peerId, namespace: Namespaces.Message.Local, id: 0), globallyUniqueId: nil, groupingKey: nil, From faf22b7001a8e027e3b1060ab61f0dffefd51c8f Mon Sep 17 00:00:00 2001 From: Ali <> Date: Thu, 23 Feb 2023 23:56:16 +0400 Subject: [PATCH 11/15] Fix decoding --- submodules/Postbox/Sources/Coding.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/submodules/Postbox/Sources/Coding.swift b/submodules/Postbox/Sources/Coding.swift index 794aacb0bb..a776900255 100644 --- a/submodules/Postbox/Sources/Coding.swift +++ b/submodules/Postbox/Sources/Coding.swift @@ -839,7 +839,7 @@ public final class PostboxDecoder { memcpy(&valueLength, bytes + offset, 4) offset += 4 var i: Int32 = 0 - while i < length { + while i < valueLength { if offset + 4 > length { offset = 0 return false From cb4641b41e0163c24c6bb36dfd55432371b16675 Mon Sep 17 00:00:00 2001 From: Ali <> Date: Fri, 24 Feb 2023 12:11:15 +0400 Subject: [PATCH 12/15] Always display join preview on iPad --- .../Sources/JoinLinkPreviewControllerNode.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/submodules/JoinLinkPreviewUI/Sources/JoinLinkPreviewControllerNode.swift b/submodules/JoinLinkPreviewUI/Sources/JoinLinkPreviewControllerNode.swift index 14159d8e10..c2fde45fa9 100644 --- a/submodules/JoinLinkPreviewUI/Sources/JoinLinkPreviewControllerNode.swift +++ b/submodules/JoinLinkPreviewUI/Sources/JoinLinkPreviewControllerNode.swift @@ -236,7 +236,7 @@ final class JoinLinkPreviewControllerNode: ViewControllerTracingNode, UIScrollVi if let contentNode = self.contentNode { transition.updateFrame(node: contentNode, frame: CGRect(origin: CGPoint(x: floor((contentContainerFrame.size.width - contentFrame.size.width) / 2.0), y: 0.0), size: gridSize)) - contentNode.updateLayout(size: gridSize, isLandscape: layout.size.width > layout.size.height, bottomInset: 0.0, transition: transition) + contentNode.updateLayout(size: gridSize, isLandscape: layout.size.width > layout.size.height && layout.metrics.widthClass == .compact, bottomInset: 0.0, transition: transition) } } From 841b50da6b8441d9e317722ae22451aa3fa94e8d Mon Sep 17 00:00:00 2001 From: Ali <> Date: Fri, 24 Feb 2023 12:11:43 +0400 Subject: [PATCH 13/15] Fix calls ringing in background --- .../Sources/CallKitIntegration.swift | 29 +++++++++++++++++-- .../TelegramUI/Sources/AppDelegate.swift | 15 +++++++++- 2 files changed, 41 insertions(+), 3 deletions(-) diff --git a/submodules/TelegramCallsUI/Sources/CallKitIntegration.swift b/submodules/TelegramCallsUI/Sources/CallKitIntegration.swift index a17e0eabee..e33ed339f7 100644 --- a/submodules/TelegramCallsUI/Sources/CallKitIntegration.swift +++ b/submodules/TelegramCallsUI/Sources/CallKitIntegration.swift @@ -36,6 +36,11 @@ public final class CallKitIntegration { var audioSessionActive: Signal { return self.audioSessionActivePromise.get() } + + private let hasActiveCallsValue = ValuePromise(false, ignoreRepeated: true) + public var hasActiveCalls: Signal { + return self.hasActiveCallsValue.get() + } private static let sharedInstance: CallKitIntegration? = CallKitIntegration() public static var shared: CallKitIntegration? { @@ -50,7 +55,7 @@ public final class CallKitIntegration { audioSessionActivationChanged: @escaping (Bool) -> Void ) { if #available(iOSApplicationExtension 10.0, iOS 10.0, *) { - (sharedProviderDelegate as? CallKitProviderDelegate)?.setup(audioSessionActivePromise: self.audioSessionActivePromise, startCall: startCall, answerCall: answerCall, endCall: endCall, setCallMuted: setCallMuted, audioSessionActivationChanged: audioSessionActivationChanged) + (sharedProviderDelegate as? CallKitProviderDelegate)?.setup(audioSessionActivePromise: self.audioSessionActivePromise, startCall: startCall, answerCall: answerCall, endCall: endCall, setCallMuted: setCallMuted, audioSessionActivationChanged: audioSessionActivationChanged, hasActiveCallsValue: hasActiveCallsValue) } } @@ -130,6 +135,7 @@ class CallKitProviderDelegate: NSObject, CXProviderDelegate { private var endCall: ((UUID) -> Signal)? private var setCallMuted: ((UUID, Bool) -> Void)? private var audioSessionActivationChanged: ((Bool) -> Void)? + private var hasActiveCallsValue: ValuePromise? private var isAudioSessionActive: Bool = false private var pendingVoiceChatOutputMode: AudioSessionOutputMode? @@ -138,6 +144,12 @@ class CallKitProviderDelegate: NSObject, CXProviderDelegate { fileprivate var audioSessionActivePromise: ValuePromise? + private var activeCalls = Set() { + didSet { + self.hasActiveCallsValue?.set(!self.activeCalls.isEmpty) + } + } + override init() { self.provider = CXProvider(configuration: CallKitProviderDelegate.providerConfiguration()) @@ -146,13 +158,14 @@ class CallKitProviderDelegate: NSObject, CXProviderDelegate { self.provider.setDelegate(self, queue: nil) } - func setup(audioSessionActivePromise: ValuePromise, startCall: @escaping (AccountContext, UUID, EnginePeer.Id?, String, Bool) -> Signal, answerCall: @escaping (UUID) -> Void, endCall: @escaping (UUID) -> Signal, setCallMuted: @escaping (UUID, Bool) -> Void, audioSessionActivationChanged: @escaping (Bool) -> Void) { + func setup(audioSessionActivePromise: ValuePromise, startCall: @escaping (AccountContext, UUID, EnginePeer.Id?, String, Bool) -> Signal, answerCall: @escaping (UUID) -> Void, endCall: @escaping (UUID) -> Signal, setCallMuted: @escaping (UUID, Bool) -> Void, audioSessionActivationChanged: @escaping (Bool) -> Void, hasActiveCallsValue: ValuePromise) { self.audioSessionActivePromise = audioSessionActivePromise self.startCall = startCall self.answerCall = answerCall self.endCall = endCall self.setCallMuted = setCallMuted self.audioSessionActivationChanged = audioSessionActivationChanged + self.hasActiveCallsValue = hasActiveCallsValue } private static func providerConfiguration() -> CXProviderConfiguration { @@ -185,12 +198,16 @@ class CallKitProviderDelegate: NSObject, CXProviderDelegate { let endCallAction = CXEndCallAction(call: uuid) let transaction = CXTransaction(action: endCallAction) self.requestTransaction(transaction) + + self.activeCalls.remove(uuid) } func dropCall(uuid: UUID) { Logger.shared.log("CallKitIntegration", "report call ended \(uuid)") self.provider.reportCall(with: uuid, endedAt: nil, reason: CXCallEndedReason.remoteEnded) + + self.activeCalls.remove(uuid) } func answerCall(uuid: UUID) { @@ -231,6 +248,8 @@ class CallKitProviderDelegate: NSObject, CXProviderDelegate { update.supportsDTMF = false self.provider.reportCall(with: uuid, updated: update) + + self.activeCalls.insert(uuid) }) } @@ -261,6 +280,10 @@ class CallKitProviderDelegate: NSObject, CXProviderDelegate { OngoingCallContext.setupAudioSession() self.provider.reportNewIncomingCall(with: uuid, update: update, completion: { error in + if error == nil { + self.activeCalls.insert(uuid) + } + completion?(error as NSError?) }) } @@ -279,6 +302,8 @@ class CallKitProviderDelegate: NSObject, CXProviderDelegate { func providerDidReset(_ provider: CXProvider) { Logger.shared.log("CallKitIntegration", "providerDidReset") + + self.activeCalls.removeAll() } func provider(_ provider: CXProvider, perform action: CXStartCallAction) { diff --git a/submodules/TelegramUI/Sources/AppDelegate.swift b/submodules/TelegramUI/Sources/AppDelegate.swift index 7f80ca3dcb..4a8b3f28b8 100644 --- a/submodules/TelegramUI/Sources/AppDelegate.swift +++ b/submodules/TelegramUI/Sources/AppDelegate.swift @@ -571,7 +571,20 @@ private func extractAccountManagerState(records: AccountRecordsView = .single(false) + if CallKitIntegration.isAvailable, let callKitIntegration = CallKitIntegration.shared { + hasActiveCalls = callKitIntegration.hasActiveCalls + } + self.hasActiveAudioSession.set( + combineLatest(queue: .mainQueue(), + hasActiveCalls, + MediaManagerImpl.globalAudioSession.isActive() + ) + |> map { hasActiveCalls, isActive -> Bool in + return hasActiveCalls || isActive + } + |> distinctUntilChanged + ) let applicationBindings = TelegramApplicationBindings(isMainApp: true, appBundleId: baseAppBundleId, appBuildType: buildConfig.isAppStoreBuild ? .public : .internal, containerPath: appGroupUrl.path, appSpecificScheme: buildConfig.appSpecificUrlScheme, openUrl: { url in var parsedUrl = URL(string: url) From 082927b21b633394b8f5f8dd379a46807fcca39f Mon Sep 17 00:00:00 2001 From: Ali <> Date: Fri, 24 Feb 2023 19:24:17 +0400 Subject: [PATCH 14/15] Cache eviction: switch to queue to avoid stack explosion --- .../Utils/AutomaticCacheEviction.swift | 22 +++++++++++-------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/submodules/TelegramCore/Sources/Utils/AutomaticCacheEviction.swift b/submodules/TelegramCore/Sources/Utils/AutomaticCacheEviction.swift index e5f5febbf8..629c8b15bd 100644 --- a/submodules/TelegramCore/Sources/Utils/AutomaticCacheEviction.swift +++ b/submodules/TelegramCore/Sources/Utils/AutomaticCacheEviction.swift @@ -105,9 +105,17 @@ final class AutomaticCacheEvictionContext { |> mapToSignal { channelCategoryMapping -> Signal in var signals: Signal = .complete() - var matchingPeers = 0 + let listSignal = Signal { subscriber in + for peerId in peerIds { + subscriber.putNext(peerId) + } + + subscriber.putCompletion() + + return EmptyDisposable + } - for peerId in peerIds { + signals = listSignal |> mapToQueue { peerId -> Signal in let timeout: Int32 if let value = settings.exceptions.first(where: { $0.key == peerId }) { timeout = value.value @@ -127,15 +135,13 @@ final class AutomaticCacheEvictionContext { } if timeout == Int32.max { - continue + return .complete() } - matchingPeers += 1 - let minPeerTimestamp = Int32(CFAbsoluteTimeGetCurrent() + NSTimeIntervalSince1970) - timeout //let minPeerTimestamp = Int32(CFAbsoluteTimeGetCurrent() + NSTimeIntervalSince1970) - signals = signals |> then(mediaBox.storageBox.all(peerId: peerId) + return mediaBox.storageBox.all(peerId: peerId) |> mapToSignal { peerResourceIds -> Signal in return Signal { subscriber in var isCancelled = false @@ -178,11 +184,9 @@ final class AutomaticCacheEvictionContext { isCancelled = true } } - }) + } } - Logger.shared.log("AutomaticCacheEviction", "have \(matchingPeers) peers with data") - return signals } }).start() From 88d812d30bb6b3ca1a713f7e7f2c701dd7d43ab4 Mon Sep 17 00:00:00 2001 From: Mike Renoir <> Date: Tue, 28 Feb 2023 16:10:26 +0400 Subject: [PATCH 15/15] check deleted account better --- submodules/TelegramCore/Sources/Utils/PeerUtils.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/submodules/TelegramCore/Sources/Utils/PeerUtils.swift b/submodules/TelegramCore/Sources/Utils/PeerUtils.swift index 760a055a88..8f15e1daa5 100644 --- a/submodules/TelegramCore/Sources/Utils/PeerUtils.swift +++ b/submodules/TelegramCore/Sources/Utils/PeerUtils.swift @@ -141,7 +141,7 @@ public extension Peer { var isDeleted: Bool { switch self { case let user as TelegramUser: - return user.firstName == nil && user.lastName == nil && user.phone == nil + return user.firstName == nil && user.lastName == nil default: return false }