From fdae5ffdf34110c823f33c3c64df8372803a6be6 Mon Sep 17 00:00:00 2001 From: Ilya Laktyushin Date: Sat, 18 Feb 2023 22:55:02 +0400 Subject: [PATCH 01/21] 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/21] 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/21] 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/21] 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/21] 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/21] 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/21] 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/21] 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/21] 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/21] 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/21] 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/21] 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/21] 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/21] 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/21] 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 } From e9eb3d53be33945730220081b252b5697d9a0fb7 Mon Sep 17 00:00:00 2001 From: Ali <> Date: Wed, 1 Mar 2023 10:24:28 +0400 Subject: [PATCH 16/21] Fix invite link screen for legacy groups --- .../Sources/PeerInfo/PeerInfoScreen.swift | 148 +++++++++++------- 1 file changed, 90 insertions(+), 58 deletions(-) diff --git a/submodules/TelegramUI/Sources/PeerInfo/PeerInfoScreen.swift b/submodules/TelegramUI/Sources/PeerInfo/PeerInfoScreen.swift index d7408752ba..d3f606eec5 100644 --- a/submodules/TelegramUI/Sources/PeerInfo/PeerInfoScreen.swift +++ b/submodules/TelegramUI/Sources/PeerInfo/PeerInfoScreen.swift @@ -10487,67 +10487,99 @@ func presentAddMembersImpl(context: AccountContext, updatedPresentationData: (in return .complete() } } else { - return context.engine.peers.addGroupMember(peerId: groupPeer.id, memberId: memberId) - |> deliverOnMainQueue - |> `catch` { error -> Signal in - switch error { - case .generic: - return .complete() - case .privacy: - let _ = (context.account.postbox.loadedPeerWithId(memberId) - |> deliverOnMainQueue).start(next: { peer in - parentController?.present(textAlertController(context: context, updatedPresentationData: updatedPresentationData, title: nil, text: presentationData.strings.Privacy_GroupsAndChannels_InviteToGroupError(EnginePeer(peer).compactDisplayTitle, EnginePeer(peer).compactDisplayTitle).string, actions: [TextAlertAction(type: .genericAction, title: presentationData.strings.Common_OK, action: {})]), in: .window(.root)) - }) - return .complete() - case .notMutualContact: - let _ = (context.account.postbox.loadedPeerWithId(memberId) - |> deliverOnMainQueue).start(next: { peer in - let text: String - if let peer = peer as? TelegramChannel, case .broadcast = peer.info { - text = presentationData.strings.Channel_AddUserLeftError - } else { - text = presentationData.strings.GroupInfo_AddUserLeftError - } - parentController?.present(textAlertController(context: context, updatedPresentationData: updatedPresentationData, title: nil, text: text, actions: [TextAlertAction(type: .genericAction, title: presentationData.strings.Common_OK, action: {})]), in: .window(.root)) - }) - return .complete() - case .tooManyChannels: - let _ = (context.account.postbox.loadedPeerWithId(memberId) - |> deliverOnMainQueue).start(next: { peer in - parentController?.present(textAlertController(context: context, updatedPresentationData: updatedPresentationData, title: nil, text: presentationData.strings.Invite_ChannelsTooMuch, actions: [TextAlertAction(type: .genericAction, title: presentationData.strings.Common_OK, action: {})]), in: .window(.root)) - }) - return .complete() - case .groupFull: - let signal = context.engine.peers.convertGroupToSupergroup(peerId: groupPeer.id) - |> map(Optional.init) - |> `catch` { error -> Signal in - switch error { - case .tooManyChannels: - Queue.mainQueue().async { - parentController?.push(oldChannelsController(context: context, intent: .upgrade)) + return context.engine.data.get(TelegramEngine.EngineData.Item.Peer.ExportedInvitation(id: groupPeer.id)) + |> mapToSignal { exportedInvitation in + return context.engine.peers.addGroupMember(peerId: groupPeer.id, memberId: memberId) + |> deliverOnMainQueue + |> `catch` { error -> Signal in + if let exportedInvitation, let link = exportedInvitation.link { + let failedPeerIds: [(PeerId, AddGroupMemberError)] = [(memberId, error)] + let _ = (context.engine.data.get( + EngineDataList(failedPeerIds.compactMap { item -> EnginePeer.Id? in + return item.0 + }.map(TelegramEngine.EngineData.Item.Peer.Peer.init(id:))) + ) + |> deliverOnMainQueue).start(next: { peerItems in + let peers = peerItems.compactMap { $0 } + if !peers.isEmpty, let contactsController, let navigationController = contactsController.navigationController as? NavigationController { + var viewControllers = navigationController.viewControllers + + let inviteScreen = SendInviteLinkScreen(context: context, link: link, peers: peers) + + if let index = viewControllers.firstIndex(where: { $0 === contactsController }) { + viewControllers.remove(at: index) + viewControllers.append(inviteScreen) + navigationController.setViewControllers(viewControllers, animated: true) + } else { + navigationController.pushViewController(inviteScreen) + } + } else { + contactsController?.dismiss() } - default: - break - } - return .single(nil) - } - |> mapToSignal { upgradedPeerId -> Signal in - guard let upgradedPeerId = upgradedPeerId else { - return .single(nil) - } - return context.peerChannelMemberCategoriesContextsManager.addMember(engine: context.engine, peerId: upgradedPeerId, memberId: memberId) - |> `catch` { _ -> Signal in - return .complete() - } - |> mapToSignal { _ -> Signal in - } - |> then(.single(upgradedPeerId)) - } - |> deliverOnMainQueue - |> mapToSignal { _ -> Signal in + }) + return .complete() } - return signal + + switch error { + case .generic: + return .complete() + case .privacy: + let _ = (context.account.postbox.loadedPeerWithId(memberId) + |> deliverOnMainQueue).start(next: { peer in + parentController?.present(textAlertController(context: context, updatedPresentationData: updatedPresentationData, title: nil, text: presentationData.strings.Privacy_GroupsAndChannels_InviteToGroupError(EnginePeer(peer).compactDisplayTitle, EnginePeer(peer).compactDisplayTitle).string, actions: [TextAlertAction(type: .genericAction, title: presentationData.strings.Common_OK, action: {})]), in: .window(.root)) + }) + return .complete() + case .notMutualContact: + let _ = (context.account.postbox.loadedPeerWithId(memberId) + |> deliverOnMainQueue).start(next: { peer in + let text: String + if let peer = peer as? TelegramChannel, case .broadcast = peer.info { + text = presentationData.strings.Channel_AddUserLeftError + } else { + text = presentationData.strings.GroupInfo_AddUserLeftError + } + parentController?.present(textAlertController(context: context, updatedPresentationData: updatedPresentationData, title: nil, text: text, actions: [TextAlertAction(type: .genericAction, title: presentationData.strings.Common_OK, action: {})]), in: .window(.root)) + }) + return .complete() + case .tooManyChannels: + let _ = (context.account.postbox.loadedPeerWithId(memberId) + |> deliverOnMainQueue).start(next: { peer in + parentController?.present(textAlertController(context: context, updatedPresentationData: updatedPresentationData, title: nil, text: presentationData.strings.Invite_ChannelsTooMuch, actions: [TextAlertAction(type: .genericAction, title: presentationData.strings.Common_OK, action: {})]), in: .window(.root)) + }) + return .complete() + case .groupFull: + let signal = context.engine.peers.convertGroupToSupergroup(peerId: groupPeer.id) + |> map(Optional.init) + |> `catch` { error -> Signal in + switch error { + case .tooManyChannels: + Queue.mainQueue().async { + parentController?.push(oldChannelsController(context: context, intent: .upgrade)) + } + default: + break + } + return .single(nil) + } + |> mapToSignal { upgradedPeerId -> Signal in + guard let upgradedPeerId = upgradedPeerId else { + return .single(nil) + } + return context.peerChannelMemberCategoriesContextsManager.addMember(engine: context.engine, peerId: upgradedPeerId, memberId: memberId) + |> `catch` { _ -> Signal in + return .complete() + } + |> mapToSignal { _ -> Signal in + } + |> then(.single(upgradedPeerId)) + } + |> deliverOnMainQueue + |> mapToSignal { _ -> Signal in + return .complete() + } + return signal + } } } } From 55c1b9b363273e459196f307e42bfc32484e67de Mon Sep 17 00:00:00 2001 From: Ali <> Date: Wed, 1 Mar 2023 10:24:54 +0400 Subject: [PATCH 17/21] Limit blur effects --- submodules/ChatListUI/Sources/ChatListController.swift | 1 + submodules/Display/Source/DeviceMetrics.swift | 2 +- .../Sources/DefaultDayPresentationTheme.swift | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/submodules/ChatListUI/Sources/ChatListController.swift b/submodules/ChatListUI/Sources/ChatListController.swift index 9534add2be..7d6c60ac96 100644 --- a/submodules/ChatListUI/Sources/ChatListController.swift +++ b/submodules/ChatListUI/Sources/ChatListController.swift @@ -1643,6 +1643,7 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController let batteryPercentage = Int(batteryLevel * 100.0) self.dismissAllUndoControllers() + //TODO:localize self.present(UndoOverlayController(presentationData: presentationData, content: .universal(animation: "lowbattery_30", scale: 1.0, colors: [:], title: "Power Saving mode enabled", text: "\(batteryPercentage)% battery remaining.", customUndoText: "Disable"), elevatedLayout: false, action: { [weak self] action in if case .undo = action, let self { let _ = updateMediaDownloadSettingsInteractively(accountManager: self.context.sharedContext.accountManager, { settings in diff --git a/submodules/Display/Source/DeviceMetrics.swift b/submodules/Display/Source/DeviceMetrics.swift index 283aa0f63c..e98012daca 100644 --- a/submodules/Display/Source/DeviceMetrics.swift +++ b/submodules/Display/Source/DeviceMetrics.swift @@ -14,7 +14,7 @@ public enum DeviceMetrics: CaseIterable, Equatable { var cpuCount: UInt32 = 0 sysctlbyname("hw.ncpu", &cpuCount, &length, nil, 0) - self.isGraphicallyCapable = cpuCount >= 6 + self.isGraphicallyCapable = cpuCount >= 4 } } diff --git a/submodules/TelegramPresentationData/Sources/DefaultDayPresentationTheme.swift b/submodules/TelegramPresentationData/Sources/DefaultDayPresentationTheme.swift index fb41c05549..b9b957bcff 100644 --- a/submodules/TelegramPresentationData/Sources/DefaultDayPresentationTheme.swift +++ b/submodules/TelegramPresentationData/Sources/DefaultDayPresentationTheme.swift @@ -30,7 +30,7 @@ public func selectReactionFillStaticColor(theme: PresentationTheme, wallpaper: T public func dateFillNeedsBlur(theme: PresentationTheme, wallpaper: TelegramWallpaper) -> Bool { if !DeviceMetrics.performance.isGraphicallyCapable { - //return false + return false } if case .builtin = wallpaper { From d088449371f51ef9eecf74ba898f1c32c0350719 Mon Sep 17 00:00:00 2001 From: Ali <> Date: Wed, 1 Mar 2023 16:13:20 +0400 Subject: [PATCH 18/21] Power saving UI improvements --- .../ContainedViewLayoutTransition.swift | 29 ++++++++++++ .../TGPhotoEditorSliderView.h | 1 + .../Sources/TGPhotoEditorSliderView.m | 47 ++++++++++++++++++- .../EnergySavingSettingsScreen.swift | 6 +-- .../EnergyUsageBatteryLevelItem.swift | 39 +++++++++++++-- .../KeepMediaDurationPickerItem.swift | 6 +-- .../Themes/ThemeSettingsController.swift | 42 +++++++++++++---- .../Sources/PeerInfo/PeerInfoScreen.swift | 4 +- .../Sources/SharedAccountContext.swift | 12 ++--- .../Sources/MediaAutoDownloadSettings.swift | 13 +++++ 10 files changed, 172 insertions(+), 27 deletions(-) diff --git a/submodules/Display/Source/ContainedViewLayoutTransition.swift b/submodules/Display/Source/ContainedViewLayoutTransition.swift index b767121111..ccd8868e4d 100644 --- a/submodules/Display/Source/ContainedViewLayoutTransition.swift +++ b/submodules/Display/Source/ContainedViewLayoutTransition.swift @@ -905,6 +905,35 @@ public extension ContainedViewLayoutTransition { } } + func updateTintColor(layer: CALayer, color: UIColor, completion: ((Bool) -> Void)? = nil) { + if let current = layer.layerTintColor, current == color.cgColor { + completion?(true) + return + } + + switch self { + case .immediate: + layer.layerTintColor = color.cgColor + completion?(true) + case let .animated(duration, curve): + let previousColor: CGColor = layer.layerTintColor ?? UIColor.clear.cgColor + layer.layerTintColor = color.cgColor + + layer.animate( + from: previousColor, + to: color.cgColor, + keyPath: "contentsMultiplyColor", + timingFunction: curve.timingFunction, + duration: duration, + delay: 0.0, + mediaTimingFunction: curve.mediaTimingFunction, + removeOnCompletion: true, + additive: false, + completion: completion + ) + } + } + func updateContentsRect(layer: CALayer, contentsRect: CGRect, completion: ((Bool) -> Void)? = nil) { if layer.contentsRect == contentsRect { if let completion = completion { diff --git a/submodules/LegacyComponents/PublicHeaders/LegacyComponents/TGPhotoEditorSliderView.h b/submodules/LegacyComponents/PublicHeaders/LegacyComponents/TGPhotoEditorSliderView.h index b72017d1e0..859a57eb52 100644 --- a/submodules/LegacyComponents/PublicHeaders/LegacyComponents/TGPhotoEditorSliderView.h +++ b/submodules/LegacyComponents/PublicHeaders/LegacyComponents/TGPhotoEditorSliderView.h @@ -40,6 +40,7 @@ @property (nonatomic, assign) CGFloat dotSize; @property (nonatomic, assign) bool enablePanHandling; +@property (nonatomic, assign) bool enableEdgeTap; - (void)setValue:(CGFloat)value animated:(BOOL)animated; diff --git a/submodules/LegacyComponents/Sources/TGPhotoEditorSliderView.m b/submodules/LegacyComponents/Sources/TGPhotoEditorSliderView.m index a9215a4c68..11250f7b87 100644 --- a/submodules/LegacyComponents/Sources/TGPhotoEditorSliderView.m +++ b/submodules/LegacyComponents/Sources/TGPhotoEditorSliderView.m @@ -16,6 +16,7 @@ const CGFloat TGPhotoEditorSliderViewInternalMargin = 7.0f; UIPanGestureRecognizer *_panGestureRecognizer; UITapGestureRecognizer *_tapGestureRecognizer; + UITapGestureRecognizer *_edgeTapGestureRecognizer; UITapGestureRecognizer *_doubleTapGestureRecognizer; UIColor *_backColor; @@ -75,6 +76,10 @@ const CGFloat TGPhotoEditorSliderViewInternalMargin = 7.0f; _tapGestureRecognizer.enabled = false; [self addGestureRecognizer:_tapGestureRecognizer]; + _edgeTapGestureRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleEdgeTap:)]; + _edgeTapGestureRecognizer.enabled = false; + [self addGestureRecognizer:_edgeTapGestureRecognizer]; + _doubleTapGestureRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleDoubleTap:)]; _doubleTapGestureRecognizer.numberOfTapsRequired = 2; [self addGestureRecognizer:_doubleTapGestureRecognizer]; @@ -195,7 +200,7 @@ const CGFloat TGPhotoEditorSliderViewInternalMargin = 7.0f; } if (self.displayEdges) { - CGContextSetFillColorWithColor(context, _startColor.CGColor); + CGContextSetFillColorWithColor(context, _backColor.CGColor); [self drawRectangle:endFrame cornerRadius:self.trackCornerRadius context:context]; } @@ -510,6 +515,46 @@ const CGFloat TGPhotoEditorSliderViewInternalMargin = 7.0f; } } +- (void)setEnableEdgeTap:(bool)enableEdgeTap { + _enableEdgeTap = enableEdgeTap; + _edgeTapGestureRecognizer.enabled = enableEdgeTap; +} + +- (void)handleEdgeTap:(UITapGestureRecognizer *)gestureRecognizer { + bool changed = false; + + if (gestureRecognizer.state == UIGestureRecognizerStateEnded) { + CGPoint touchLocation = [gestureRecognizer locationInView:self]; + CGFloat edgeWidth = 16.0f; + if (touchLocation.x < edgeWidth || touchLocation.x > self.bounds.size.width - edgeWidth) { + CGRect knobRect = CGRectInset(self.knobView.frame, -8.0, -8.0); + if (!CGRectContainsPoint(knobRect, touchLocation)) { + if (touchLocation.x < edgeWidth) { + [self setValue:_minimumValue]; + } else { + [self setValue:_maximumValue]; + } + changed = true; + } + } + } + + if (changed) + { + if (self.interactionBegan != nil) + self.interactionBegan(); + + [self setNeedsLayout]; + [self sendActionsForControlEvents:UIControlEventValueChanged]; + + if (self.interactionEnded != nil) + self.interactionEnded(); + + [_feedbackGenerator selectionChanged]; + [_feedbackGenerator prepare]; + } +} + - (void)handleDoubleTap:(UITapGestureRecognizer *)__unused gestureRecognizer { if (self.reset != nil) diff --git a/submodules/SettingsUI/Sources/Data and Storage/EnergySavingSettingsScreen.swift b/submodules/SettingsUI/Sources/Data and Storage/EnergySavingSettingsScreen.swift index 76cee2ca92..6d286638a8 100644 --- a/submodules/SettingsUI/Sources/Data and Storage/EnergySavingSettingsScreen.swift +++ b/submodules/SettingsUI/Sources/Data and Storage/EnergySavingSettingsScreen.swift @@ -17,8 +17,8 @@ enum ItemType: CaseIterable { case loopStickers case loopEmoji case fullTranslucency - case extendBackgroundWork case autodownloadInBackground + case extendBackgroundWork var settingsKeyPath: WritableKeyPath { switch self { @@ -63,7 +63,7 @@ enum ItemType: CaseIterable { case .loopEmoji: return ( "Settings/Power/PowerIconEmoji", - "Emoli Animations", + "Emoji Animations", "Loop animated emoji in messages, reactions, statuses." ) case .fullTranslucency: @@ -242,7 +242,7 @@ private func energeSavingSettingsScreenEntries( entries.append(.itemsHeader) for type in ItemType.allCases { - entries.append(.item(index: entries.count, type: type, value: settings.energyUsageSettings[keyPath: type.settingsKeyPath], enabled: itemsEnabled)) + entries.append(.item(index: entries.count, type: type, value: settings.energyUsageSettings[keyPath: type.settingsKeyPath] && itemsEnabled, enabled: itemsEnabled)) } return entries diff --git a/submodules/SettingsUI/Sources/Data and Storage/EnergyUsageBatteryLevelItem.swift b/submodules/SettingsUI/Sources/Data and Storage/EnergyUsageBatteryLevelItem.swift index 414ca07458..9c749e476a 100644 --- a/submodules/SettingsUI/Sources/Data and Storage/EnergyUsageBatteryLevelItem.swift +++ b/submodules/SettingsUI/Sources/Data and Storage/EnergyUsageBatteryLevelItem.swift @@ -73,6 +73,7 @@ class EnergyUsageBatteryLevelItemNode: ListViewItemNode { private let batteryImage: UIImage? private let batteryBackgroundNode: ASImageNode + private let batteryForegroundNode: ASImageNode private var item: EnergyUsageBatteryLevelItem? private var layoutParams: ListViewItemLayoutParams? @@ -96,6 +97,7 @@ class EnergyUsageBatteryLevelItemNode: ListViewItemNode { self.batteryImage = UIImage(bundleImageName: "Settings/UsageBatteryFrame") self.batteryBackgroundNode = ASImageNode() + self.batteryForegroundNode = ASImageNode() super.init(layerBacked: false, dynamicBounce: false) @@ -103,12 +105,14 @@ class EnergyUsageBatteryLevelItemNode: ListViewItemNode { self.addSubnode(self.rightTextNode) self.addSubnode(self.centerTextNode) self.addSubnode(self.batteryBackgroundNode) + self.addSubnode(self.batteryForegroundNode) } override func didLoad() { super.didLoad() let sliderView = TGPhotoEditorSliderView() + sliderView.enableEdgeTap = true sliderView.enablePanHandling = true sliderView.trackCornerRadius = 1.0 sliderView.lineSize = 4.0 @@ -223,6 +227,7 @@ class EnergyUsageBatteryLevelItemNode: ListViewItemNode { centralMeasureText = "When Below 99%" strongSelf.batteryBackgroundNode.isHidden = false } + strongSelf.batteryForegroundNode.isHidden = strongSelf.batteryBackgroundNode.isHidden strongSelf.centerTextNode.attributedText = NSAttributedString(string: centralText, font: Font.regular(16.0), textColor: item.theme.list.itemPrimaryTextColor) strongSelf.centerMeasureTextNode.attributedText = NSAttributedString(string: centralMeasureText, font: Font.regular(16.0), textColor: item.theme.list.itemPrimaryTextColor) @@ -254,15 +259,41 @@ class EnergyUsageBatteryLevelItemNode: ListViewItemNode { let contentRect = CGRect(origin: CGPoint(x: 3.0, y: (size.height - 9.0) * 0.5), size: CGSize(width: 20.8, height: 9.0)) context.addPath(UIBezierPath(roundedRect: contentRect, cornerRadius: 2.0).cgPath) context.clip() - - context.setFillColor(UIColor(rgb: 0xFF3B30).cgColor) - context.addPath(UIBezierPath(roundedRect: CGRect(origin: contentRect.origin, size: CGSize(width: contentRect.width * CGFloat(item.value) / 100.0, height: contentRect.height)), cornerRadius: 1.0).cgPath) - context.fillPath() } UIGraphicsPopContext() }) + strongSelf.batteryForegroundNode.image = generateImage(frameImage.size, rotatedContext: { size, context in + UIGraphicsPushContext(context) + + context.clear(CGRect(origin: CGPoint(), size: size)) + + let contentRect = CGRect(origin: CGPoint(x: 3.0, y: (size.height - 9.0) * 0.5), size: CGSize(width: 20.8, height: 9.0)) + context.addPath(UIBezierPath(roundedRect: contentRect, cornerRadius: 2.0).cgPath) + context.clip() + + context.setFillColor(UIColor.white.cgColor) + context.addPath(UIBezierPath(roundedRect: CGRect(origin: contentRect.origin, size: CGSize(width: contentRect.width * CGFloat(item.value) / 100.0, height: contentRect.height)), cornerRadius: 1.0).cgPath) + context.fillPath() + + UIGraphicsPopContext() + }) + + let batteryColor: UIColor + if item.value <= 20 { + batteryColor = UIColor(rgb: 0xFF3B30) + } else { + batteryColor = item.theme.list.itemSwitchColors.positiveColor + } + + if strongSelf.batteryForegroundNode.layer.layerTintColor == nil { + strongSelf.batteryForegroundNode.layer.layerTintColor = batteryColor.cgColor + } else { + ContainedViewLayoutTransition.animated(duration: 0.2, curve: .easeInOut).updateTintColor(layer: strongSelf.batteryForegroundNode.layer, color: batteryColor) + } + strongSelf.batteryBackgroundNode.frame = CGRect(origin: CGPoint(x: centerFrame.minX + centerMeasureTextSize.width + 4.0, y: floor(centerFrame.midY - frameImage.size.height * 0.5)), size: frameImage.size) + strongSelf.batteryForegroundNode.frame = strongSelf.batteryBackgroundNode.frame } if let sliderView = strongSelf.sliderView { diff --git a/submodules/SettingsUI/Sources/Data and Storage/KeepMediaDurationPickerItem.swift b/submodules/SettingsUI/Sources/Data and Storage/KeepMediaDurationPickerItem.swift index ffcd92ba57..4b3cb1da83 100644 --- a/submodules/SettingsUI/Sources/Data and Storage/KeepMediaDurationPickerItem.swift +++ b/submodules/SettingsUI/Sources/Data and Storage/KeepMediaDurationPickerItem.swift @@ -143,9 +143,9 @@ private final class KeepMediaDurationPickerItemNode: ListViewItemNode { sliderView.value = CGFloat(value) sliderView.backgroundColor = item.theme.list.itemBlocksBackgroundColor - sliderView.backColor = item.theme.list.itemSwitchColors.frameColor - sliderView.startColor = item.theme.list.itemSwitchColors.frameColor - sliderView.trackColor = item.theme.list.itemAccentColor + sliderView.backColor = item.theme.list.itemSwitchColors.frameColor.blitOver(item.theme.list.itemBlocksBackgroundColor, alpha: 1.0) + sliderView.startColor = item.theme.list.itemSwitchColors.frameColor.blitOver(item.theme.list.itemBlocksBackgroundColor, alpha: 1.0) + sliderView.trackColor = item.theme.list.itemAccentColor.blitOver(item.theme.list.itemBlocksBackgroundColor, alpha: 1.0) sliderView.knobImage = PresentationResourcesItemList.knobImage(item.theme) sliderView.frame = CGRect(origin: CGPoint(x: params.leftInset + 15.0, y: 37.0), size: CGSize(width: params.width - params.leftInset - params.rightInset - 15.0 * 2.0, height: 44.0)) diff --git a/submodules/SettingsUI/Sources/Themes/ThemeSettingsController.swift b/submodules/SettingsUI/Sources/Themes/ThemeSettingsController.swift index 51aa2c0824..f3fe588854 100644 --- a/submodules/SettingsUI/Sources/Themes/ThemeSettingsController.swift +++ b/submodules/SettingsUI/Sources/Themes/ThemeSettingsController.swift @@ -57,6 +57,7 @@ private final class ThemeSettingsControllerArguments { let openTextSize: () -> Void let openBubbleSettings: () -> Void let openPowerSavingSettings: () -> Void + let openStickersAndEmoji: () -> Void let toggleLargeEmoji: (Bool) -> Void let disableAnimations: (Bool) -> Void let selectAppIcon: (PresentationAppIcon) -> Void @@ -64,7 +65,7 @@ private final class ThemeSettingsControllerArguments { let themeContextAction: (Bool, PresentationThemeReference, ASDisplayNode, ContextGesture?) -> Void let colorContextAction: (Bool, PresentationThemeReference, ThemeSettingsColorOption?, ASDisplayNode, ContextGesture?) -> Void - init(context: AccountContext, selectTheme: @escaping (PresentationThemeReference) -> Void, openThemeSettings: @escaping () -> Void, openWallpaperSettings: @escaping () -> Void, selectAccentColor: @escaping (PresentationThemeAccentColor?) -> Void, openAccentColorPicker: @escaping (PresentationThemeReference, Bool) -> Void, toggleNightTheme: @escaping (Bool) -> Void, openAutoNightTheme: @escaping () -> Void, openTextSize: @escaping () -> Void, openBubbleSettings: @escaping () -> Void, openPowerSavingSettings: @escaping () -> Void, toggleLargeEmoji: @escaping (Bool) -> Void, disableAnimations: @escaping (Bool) -> Void, selectAppIcon: @escaping (PresentationAppIcon) -> Void, editTheme: @escaping (PresentationCloudTheme) -> Void, themeContextAction: @escaping (Bool, PresentationThemeReference, ASDisplayNode, ContextGesture?) -> Void, colorContextAction: @escaping (Bool, PresentationThemeReference, ThemeSettingsColorOption?, ASDisplayNode, ContextGesture?) -> Void) { + init(context: AccountContext, selectTheme: @escaping (PresentationThemeReference) -> Void, openThemeSettings: @escaping () -> Void, openWallpaperSettings: @escaping () -> Void, selectAccentColor: @escaping (PresentationThemeAccentColor?) -> Void, openAccentColorPicker: @escaping (PresentationThemeReference, Bool) -> Void, toggleNightTheme: @escaping (Bool) -> Void, openAutoNightTheme: @escaping () -> Void, openTextSize: @escaping () -> Void, openBubbleSettings: @escaping () -> Void, openPowerSavingSettings: @escaping () -> Void, openStickersAndEmoji: @escaping () -> Void, toggleLargeEmoji: @escaping (Bool) -> Void, disableAnimations: @escaping (Bool) -> Void, selectAppIcon: @escaping (PresentationAppIcon) -> Void, editTheme: @escaping (PresentationCloudTheme) -> Void, themeContextAction: @escaping (Bool, PresentationThemeReference, ASDisplayNode, ContextGesture?) -> Void, colorContextAction: @escaping (Bool, PresentationThemeReference, ThemeSettingsColorOption?, ASDisplayNode, ContextGesture?) -> Void) { self.context = context self.selectTheme = selectTheme self.openThemeSettings = openThemeSettings @@ -76,6 +77,7 @@ private final class ThemeSettingsControllerArguments { self.openTextSize = openTextSize self.openBubbleSettings = openBubbleSettings self.openPowerSavingSettings = openPowerSavingSettings + self.openStickersAndEmoji = openStickersAndEmoji self.toggleLargeEmoji = toggleLargeEmoji self.disableAnimations = disableAnimations self.selectAppIcon = selectAppIcon @@ -101,6 +103,7 @@ public enum ThemeSettingsEntryTag: ItemListItemTag { case accentColor case icon case powerSaving + case stickersAndEmoji case largeEmoji case animations @@ -126,6 +129,7 @@ private enum ThemeSettingsControllerEntry: ItemListNodeEntry { case iconHeader(PresentationTheme, String) case iconItem(PresentationTheme, PresentationStrings, [PresentationAppIcon], Bool, String?) case powerSaving + case stickersAndEmoji case otherHeader(PresentationTheme, String) case largeEmoji(PresentationTheme, String, Bool) case animations(PresentationTheme, String, Bool) @@ -141,7 +145,7 @@ private enum ThemeSettingsControllerEntry: ItemListNodeEntry { return ThemeSettingsControllerSection.message.rawValue case .iconHeader, .iconItem: return ThemeSettingsControllerSection.icon.rawValue - case .powerSaving: + case .powerSaving, .stickersAndEmoji: return ThemeSettingsControllerSection.message.rawValue case .otherHeader, .largeEmoji, .animations, .animationsInfo: return ThemeSettingsControllerSection.other.rawValue @@ -170,18 +174,20 @@ private enum ThemeSettingsControllerEntry: ItemListNodeEntry { return 8 case .powerSaving: return 9 - case .iconHeader: + case .stickersAndEmoji: return 10 - case .iconItem: + case .iconHeader: return 11 - case .otherHeader: + case .iconItem: return 12 - case .largeEmoji: + case .otherHeader: return 13 - case .animations: + case .largeEmoji: return 14 - case .animationsInfo: + case .animations: return 15 + case .animationsInfo: + return 16 } } @@ -259,6 +265,12 @@ private enum ThemeSettingsControllerEntry: ItemListNodeEntry { } else { return false } + case .stickersAndEmoji: + if case .stickersAndEmoji = rhs { + return true + } else { + return false + } case let .otherHeader(lhsTheme, lhsText): if case let .otherHeader(rhsTheme, rhsText) = rhs, lhsTheme === rhsTheme, lhsText == rhsText { return true @@ -338,6 +350,11 @@ private enum ThemeSettingsControllerEntry: ItemListNodeEntry { return ItemListDisclosureItem(presentationData: presentationData, icon: nil, title: "Animations", label: "", labelStyle: .text, sectionId: self.section, style: .blocks, disclosureStyle: .arrow, action: { arguments.openPowerSavingSettings() }) + case .stickersAndEmoji: + //TODO:localize + return ItemListDisclosureItem(presentationData: presentationData, icon: nil, title: "Stickers and Emoji", label: "", labelStyle: .text, sectionId: self.section, style: .blocks, disclosureStyle: .arrow, action: { + arguments.openStickersAndEmoji() + }) case let .otherHeader(_, text): return ItemListSectionHeaderItem(presentationData: presentationData, text: text, sectionId: self.section) case let .largeEmoji(_, title, value): @@ -397,6 +414,7 @@ private func themeSettingsControllerEntries(presentationData: PresentationData, entries.append(.textSize(presentationData.theme, strings.Appearance_TextSizeSetting, textSizeValue)) entries.append(.bubbleSettings(presentationData.theme, strings.Appearance_BubbleCornersSetting, "")) entries.append(.powerSaving) + entries.append(.stickersAndEmoji) if !availableAppIcons.isEmpty { entries.append(.iconHeader(presentationData.theme, strings.Appearance_AppIcon.uppercased())) @@ -460,6 +478,9 @@ public func themeSettingsController(context: AccountContext, focusOnItemTag: The let removedThemeIndexesPromise = Promise>(Set()) let removedThemeIndexes = Atomic>(value: Set()) + let archivedPacks = Promise<[ArchivedStickerPackItem]?>() + archivedPacks.set(.single(nil) |> then(context.engine.stickers.archivedStickerPacks() |> map(Optional.init))) + let animatedEmojiStickers = context.engine.stickers.loadedStickerPack(reference: .animatedEmoji, forceActualized: false) |> map { animatedEmoji -> [String: [StickerPackItem]] in var animatedEmojiStickers: [String: [StickerPackItem]] = [:] @@ -515,6 +536,11 @@ public func themeSettingsController(context: AccountContext, focusOnItemTag: The }) }, openPowerSavingSettings: { pushControllerImpl?(energySavingSettingsScreen(context: context)) + }, openStickersAndEmoji: { + let _ = (archivedPacks.get() |> take(1) |> deliverOnMainQueue).start(next: { archivedStickerPacks in + pushControllerImpl?(installedStickerPacksController(context: context, mode: .general, archivedPacks: archivedStickerPacks, updatedPacks: { _ in + })) + }) }, toggleLargeEmoji: { largeEmoji in let _ = updatePresentationThemeSettingsInteractively(accountManager: context.sharedContext.accountManager, { current in return current.withUpdatedLargeEmoji(largeEmoji) diff --git a/submodules/TelegramUI/Sources/PeerInfo/PeerInfoScreen.swift b/submodules/TelegramUI/Sources/PeerInfo/PeerInfoScreen.swift index d8b490431c..17f1b339b4 100644 --- a/submodules/TelegramUI/Sources/PeerInfo/PeerInfoScreen.swift +++ b/submodules/TelegramUI/Sources/PeerInfo/PeerInfoScreen.swift @@ -841,7 +841,7 @@ private func settingsItems(data: PeerInfoScreenData?, context: AccountContext, p interaction.openPaymentMethod() }))*/ - let stickersLabel: String + /*let stickersLabel: String if let settings = data.globalSettings { stickersLabel = settings.unreadTrendingStickerPacks > 0 ? "\(settings.unreadTrendingStickerPacks)" : "" } else { @@ -849,7 +849,7 @@ private func settingsItems(data: PeerInfoScreenData?, context: AccountContext, p } items[.advanced]!.append(PeerInfoScreenDisclosureItem(id: 5, label: .badge(stickersLabel, presentationData.theme.list.itemAccentColor), text: presentationData.strings.ChatSettings_StickersAndReactions, icon: PresentationResourcesSettings.stickers, action: { interaction.openSettings(.stickers) - })) + }))*/ if let settings = data.globalSettings { if settings.hasPassport { diff --git a/submodules/TelegramUI/Sources/SharedAccountContext.swift b/submodules/TelegramUI/Sources/SharedAccountContext.swift index 0ff73c1529..53713a31bc 100644 --- a/submodules/TelegramUI/Sources/SharedAccountContext.swift +++ b/submodules/TelegramUI/Sources/SharedAccountContext.swift @@ -244,9 +244,9 @@ public final class SharedAccountContextImpl: SharedAccountContext { self.currentInAppNotificationSettings = Atomic(value: initialPresentationDataAndSettings.inAppNotificationSettings) if automaticEnergyUsageShouldBeOnNow(settings: self.currentAutomaticMediaDownloadSettings) { - self.energyUsageSettings = self.currentAutomaticMediaDownloadSettings.energyUsageSettings + self.energyUsageSettings = EnergyUsageSettings.powerSavingDefault } else { - self.energyUsageSettings = EnergyUsageSettings.default + self.energyUsageSettings = self.currentAutomaticMediaDownloadSettings.energyUsageSettings } let presentationData: Signal = .single(initialPresentationDataAndSettings.presentationData) @@ -389,17 +389,17 @@ public final class SharedAccountContextImpl: SharedAccountContext { strongSelf.currentAutomaticMediaDownloadSettings = next if automaticEnergyUsageShouldBeOnNow(settings: next) { - strongSelf.energyUsageSettings = next.energyUsageSettings + strongSelf.energyUsageSettings = EnergyUsageSettings.powerSavingDefault } else { - strongSelf.energyUsageSettings = EnergyUsageSettings.default + strongSelf.energyUsageSettings = next.energyUsageSettings } strongSelf.energyUsageAutomaticDisposable.set((automaticEnergyUsageShouldBeOn(settings: next) |> deliverOnMainQueue).start(next: { value in if let strongSelf = self { if value { - strongSelf.energyUsageSettings = next.energyUsageSettings + strongSelf.energyUsageSettings = EnergyUsageSettings.powerSavingDefault } else { - strongSelf.energyUsageSettings = EnergyUsageSettings.default + strongSelf.energyUsageSettings = next.energyUsageSettings } } })) diff --git a/submodules/TelegramUIPreferences/Sources/MediaAutoDownloadSettings.swift b/submodules/TelegramUIPreferences/Sources/MediaAutoDownloadSettings.swift index 385e73dea5..6849139415 100644 --- a/submodules/TelegramUIPreferences/Sources/MediaAutoDownloadSettings.swift +++ b/submodules/TelegramUIPreferences/Sources/MediaAutoDownloadSettings.swift @@ -283,6 +283,19 @@ public struct EnergyUsageSettings: Codable, Equatable { ) } + public static var powerSavingDefault: EnergyUsageSettings { + return EnergyUsageSettings( + activationThreshold: 10, + autoplayVideo: false, + autoplayGif: false, + loopStickers: false, + loopEmoji: false, + fullTranslucency: false, + extendBackgroundWork: false, + autodownloadInBackground: false + ) + } + public var activationThreshold: Int32 public var autoplayVideo: Bool From 01f8d07630c7e17d21ef0f4dfe3c35b52f5bbc1c Mon Sep 17 00:00:00 2001 From: Ali <> Date: Wed, 1 Mar 2023 16:13:52 +0400 Subject: [PATCH 19/21] Add padding --- .../SendInviteLinkScreen/Sources/SendInviteLinkScreen.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/submodules/TelegramUI/Components/SendInviteLinkScreen/Sources/SendInviteLinkScreen.swift b/submodules/TelegramUI/Components/SendInviteLinkScreen/Sources/SendInviteLinkScreen.swift index 1f40ade44e..96abac18b7 100644 --- a/submodules/TelegramUI/Components/SendInviteLinkScreen/Sources/SendInviteLinkScreen.swift +++ b/submodules/TelegramUI/Components/SendInviteLinkScreen/Sources/SendInviteLinkScreen.swift @@ -381,7 +381,7 @@ private final class SendInviteLinkScreenComponent: Component { maximumNumberOfLines: 0 )), environment: {}, - containerSize: CGSize(width: availableSize.width - sideInset * 2.0, height: 1000.0) + containerSize: CGSize(width: availableSize.width - sideInset * 2.0 - 16.0 * 2.0, height: 1000.0) ) let descriptionTextFrame = CGRect(origin: CGPoint(x: floor((availableSize.width - descriptionTextSize.width) * 0.5), y: contentHeight), size: descriptionTextSize) if let descriptionTextView = self.descriptionText.view { From 51b01c67a158ed3fdde591f7f4dd5e729624d621 Mon Sep 17 00:00:00 2001 From: Ali <> Date: Wed, 1 Mar 2023 16:14:48 +0400 Subject: [PATCH 20/21] Update tgcalls --- submodules/TgVoipWebrtc/tgcalls | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/submodules/TgVoipWebrtc/tgcalls b/submodules/TgVoipWebrtc/tgcalls index b0f186935c..d114d7a3fc 160000 --- a/submodules/TgVoipWebrtc/tgcalls +++ b/submodules/TgVoipWebrtc/tgcalls @@ -1 +1 @@ -Subproject commit b0f186935c88e09be2106c80b9880ba92fb6b2d3 +Subproject commit d114d7a3fc8adb894464a167521cbe871ba8c888 From d351d47b51b73affb5a24525503019b0ae9eff24 Mon Sep 17 00:00:00 2001 From: Ali <> Date: Wed, 1 Mar 2023 16:31:02 +0400 Subject: [PATCH 21/21] Fix build --- .../NotificationService/Sources/NotificationService.swift | 2 +- Telegram/SiriIntents/IntentHandler.swift | 2 +- .../Sources/ReactionListContextMenuContent.swift | 8 ++++---- submodules/TelegramUI/Sources/AppDelegate.swift | 2 +- .../TelegramUI/Sources/NotificationContentContext.swift | 2 +- submodules/TelegramUI/Sources/ShareExtensionContext.swift | 2 +- 6 files changed, 9 insertions(+), 9 deletions(-) diff --git a/Telegram/NotificationService/Sources/NotificationService.swift b/Telegram/NotificationService/Sources/NotificationService.swift index 3d11080ab3..9bf3cf7672 100644 --- a/Telegram/NotificationService/Sources/NotificationService.swift +++ b/Telegram/NotificationService/Sources/NotificationService.swift @@ -680,7 +680,7 @@ private final class NotificationServiceHandler { Logger.shared.logToConsole = loggingSettings.logToConsole Logger.shared.redactSensitiveData = loggingSettings.redactSensitiveData - let networkArguments = NetworkInitializationArguments(apiId: apiId, apiHash: apiHash, languagesCategory: languagesCategory, appVersion: appVersion, voipMaxLayer: 0, voipVersions: [], appData: .single(buildConfig.bundleData(withAppToken: nil, signatureDict: nil)), autolockDeadine: .single(nil), encryptionProvider: OpenSSLEncryptionProvider(), resolvedDeviceName: nil) + let networkArguments = NetworkInitializationArguments(apiId: apiId, apiHash: apiHash, languagesCategory: languagesCategory, appVersion: appVersion, voipMaxLayer: 0, voipVersions: [], appData: .single(buildConfig.bundleData(withAppToken: nil, signatureDict: nil)), autolockDeadine: .single(nil), encryptionProvider: OpenSSLEncryptionProvider(), deviceModelName: nil) let isLockedMessage: String? if let data = try? Data(contentsOf: URL(fileURLWithPath: appLockStatePath(rootPath: rootPath))), let state = try? JSONDecoder().decode(LockState.self, from: data), isAppLocked(state: state) { diff --git a/Telegram/SiriIntents/IntentHandler.swift b/Telegram/SiriIntents/IntentHandler.swift index 50236fb0a0..23670cbb39 100644 --- a/Telegram/SiriIntents/IntentHandler.swift +++ b/Telegram/SiriIntents/IntentHandler.swift @@ -174,7 +174,7 @@ class DefaultIntentHandler: INExtension, INSendMessageIntentHandling, INSearchFo if let accountCache = accountCache { account = .single(accountCache) } else { - account = currentAccount(allocateIfNotExists: false, networkArguments: NetworkInitializationArguments(apiId: apiId, apiHash: apiHash, languagesCategory: languagesCategory, appVersion: appVersion, voipMaxLayer: 0, voipVersions: [], appData: .single(buildConfig.bundleData(withAppToken: nil, signatureDict: nil)), autolockDeadine: .single(nil), encryptionProvider: OpenSSLEncryptionProvider(), resolvedDeviceName: nil), supplementary: true, manager: accountManager, rootPath: rootPath, auxiliaryMethods: accountAuxiliaryMethods, encryptionParameters: encryptionParameters) + account = currentAccount(allocateIfNotExists: false, networkArguments: NetworkInitializationArguments(apiId: apiId, apiHash: apiHash, languagesCategory: languagesCategory, appVersion: appVersion, voipMaxLayer: 0, voipVersions: [], appData: .single(buildConfig.bundleData(withAppToken: nil, signatureDict: nil)), autolockDeadine: .single(nil), encryptionProvider: OpenSSLEncryptionProvider(), deviceModelName: nil), supplementary: true, manager: accountManager, rootPath: rootPath, auxiliaryMethods: accountAuxiliaryMethods, encryptionParameters: encryptionParameters) |> mapToSignal { account -> Signal in if let account = account { switch account { diff --git a/submodules/Components/ReactionListContextMenuContent/Sources/ReactionListContextMenuContent.swift b/submodules/Components/ReactionListContextMenuContent/Sources/ReactionListContextMenuContent.swift index 20cb96b106..2f4e216776 100644 --- a/submodules/Components/ReactionListContextMenuContent/Sources/ReactionListContextMenuContent.swift +++ b/submodules/Components/ReactionListContextMenuContent/Sources/ReactionListContextMenuContent.swift @@ -595,7 +595,7 @@ public final class ReactionListContextMenuContent: ContextControllerItemsContent let titleSize = self.titleLabelNode.updateLayout(CGSize(width: maxTextWidth, height: 100.0)) //TODO:localize - var text = "read" + var text = "" if let timestamp = item.timestamp { let dateText = humanReadableStringForTimestamp(strings: presentationData.strings, dateTimeFormat: presentationData.dateTimeFormat, timestamp: timestamp, alwaysShowTime: false, allowYesterday: true, format: HumanReadableStringFormat( dateFormatString: { value in @@ -619,12 +619,12 @@ public final class ReactionListContextMenuContent: ContextControllerItemsContent } self.textLabelNode.attributedText = NSAttributedString(string: text, font: Font.regular(15.0), textColor: presentationData.theme.contextMenu.secondaryColor) let textSize = self.textLabelNode.updateLayout(CGSize(width: maxTextWidth - 18.0, height: 100.0)) - self.textLabelNode.isHidden = !self.displayReadTimestamps + self.textLabelNode.isHidden = !self.displayReadTimestamps && !text.isEmpty let textSpacing: CGFloat = 2.0 let contentHeight: CGFloat - if self.displayReadTimestamps { + if self.displayReadTimestamps && !text.isEmpty { contentHeight = titleSize.height + textSpacing + textSize.height } else { contentHeight = titleSize.height @@ -642,7 +642,7 @@ public final class ReactionListContextMenuContent: ContextControllerItemsContent let iconSize = CGSize(width: floor(readImage.size.width * fraction), height: floor(readImage.size.height * fraction)) self.readIconView.frame = CGRect(origin: CGPoint(x: titleFrame.minX, y: textFrame.minY + 4.0 - UIScreenPixel), size: iconSize) } - self.readIconView.isHidden = !self.displayReadTimestamps + self.readIconView.isHidden = !self.displayReadTimestamps && !text.isEmpty if let credibilityIconView = self.credibilityIconView, let credibilityIconSize = credibilityIconSize { if let credibilityIconComponentView = credibilityIconView.view { diff --git a/submodules/TelegramUI/Sources/AppDelegate.swift b/submodules/TelegramUI/Sources/AppDelegate.swift index bf335c997f..3a50406c96 100644 --- a/submodules/TelegramUI/Sources/AppDelegate.swift +++ b/submodules/TelegramUI/Sources/AppDelegate.swift @@ -483,7 +483,7 @@ private func extractAccountManagerState(records: AccountRecordsView