diff --git a/Telegram/Telegram-iOS/en.lproj/Localizable.strings b/Telegram/Telegram-iOS/en.lproj/Localizable.strings index 4846c0ec09..ced71d78bd 100644 --- a/Telegram/Telegram-iOS/en.lproj/Localizable.strings +++ b/Telegram/Telegram-iOS/en.lproj/Localizable.strings @@ -6760,6 +6760,7 @@ Sorry for the inconvenience."; "Conversation.ForwardOptions.Text" = "What whould you like to do with %1$@ from %2$@?"; "Conversation.ForwardOptions.TextPersonal" = "What whould you like to do with %1$@ from your chat with %2$@?"; +"Conversation.ForwardOptions.TextSaved" = "What whould you like to do with %1$@ from your Saved Messages?"; "Conversation.ForwardOptions.ShowOptions" = "Show Forwarding Options"; "Conversation.ForwardOptions.CancelForwarding" = "Cancel Forwarding"; diff --git a/submodules/CallListUI/Sources/CallListControllerNode.swift b/submodules/CallListUI/Sources/CallListControllerNode.swift index da0a55f504..0812280fd2 100644 --- a/submodules/CallListUI/Sources/CallListControllerNode.swift +++ b/submodules/CallListUI/Sources/CallListControllerNode.swift @@ -710,6 +710,9 @@ final class CallListControllerNode: ASDisplayNode { self.emptyButtonTextNode.layer.animateAlpha(from: previousAlpha, to: alpha, duration: 0.25) self.emptyButtonNode.isUserInteractionEnabled = !isHidden + self.listNode.alpha = 1.0 - alpha + self.listNode.layer.animateAlpha(from: 1.0 - previousAlpha, to: 1.0 - alpha, duration: 0.25) + if !isHidden { let type = self.currentLocationAndType.scope let emptyText: String diff --git a/submodules/ChatListUI/Sources/Node/ChatListItem.swift b/submodules/ChatListUI/Sources/Node/ChatListItem.swift index 38605a929f..841213c27f 100644 --- a/submodules/ChatListUI/Sources/Node/ChatListItem.swift +++ b/submodules/ChatListUI/Sources/Node/ChatListItem.swift @@ -2248,12 +2248,12 @@ class ChatListItemNode: ItemListRevealOptionsItemNode { switch item.content { case let .peer(peerData): if let peer = peerData.messages.last?.author { - if case let .user(user) = peer, let emojiStatus = user.emojiStatus, !premiumConfiguration.isPremiumDisabled { - currentCredibilityIconContent = .animation(content: .customEmoji(fileId: emojiStatus.fileId), size: CGSize(width: 32.0, height: 32.0), placeholderColor: item.presentationData.theme.list.mediaPlaceholderColor, themeColor: item.presentationData.theme.list.itemAccentColor, loopMode: .count(2)) - } else if peer.isScam { + if peer.isScam { currentCredibilityIconContent = .text(color: item.presentationData.theme.chat.message.incoming.scamColor, string: item.presentationData.strings.Message_ScamAccount.uppercased()) } else if peer.isFake { currentCredibilityIconContent = .text(color: item.presentationData.theme.chat.message.incoming.scamColor, string: item.presentationData.strings.Message_FakeAccount.uppercased()) + } else if case let .user(user) = peer, let emojiStatus = user.emojiStatus, !premiumConfiguration.isPremiumDisabled { + currentCredibilityIconContent = .animation(content: .customEmoji(fileId: emojiStatus.fileId), size: CGSize(width: 32.0, height: 32.0), placeholderColor: item.presentationData.theme.list.mediaPlaceholderColor, themeColor: item.presentationData.theme.list.itemAccentColor, loopMode: .count(2)) } else if peer.isVerified { currentCredibilityIconContent = .verified(fillColor: item.presentationData.theme.list.itemCheckColors.fillColor, foregroundColor: item.presentationData.theme.list.itemCheckColors.foregroundColor, sizeType: .compact) } else if peer.isPremium && !premiumConfiguration.isPremiumDisabled { @@ -2264,12 +2264,12 @@ class ChatListItemNode: ItemListRevealOptionsItemNode { break } } else if case let .chat(itemPeer) = contentPeer, let peer = itemPeer.chatMainPeer { - if case let .user(user) = peer, let emojiStatus = user.emojiStatus, !premiumConfiguration.isPremiumDisabled { - currentCredibilityIconContent = .animation(content: .customEmoji(fileId: emojiStatus.fileId), size: CGSize(width: 32.0, height: 32.0), placeholderColor: item.presentationData.theme.list.mediaPlaceholderColor, themeColor: item.presentationData.theme.list.itemAccentColor, loopMode: .count(2)) - } else if peer.isScam { + if peer.isScam { currentCredibilityIconContent = .text(color: item.presentationData.theme.chat.message.incoming.scamColor, string: item.presentationData.strings.Message_ScamAccount.uppercased()) } else if peer.isFake { currentCredibilityIconContent = .text(color: item.presentationData.theme.chat.message.incoming.scamColor, string: item.presentationData.strings.Message_FakeAccount.uppercased()) + } else if case let .user(user) = peer, let emojiStatus = user.emojiStatus, !premiumConfiguration.isPremiumDisabled { + currentCredibilityIconContent = .animation(content: .customEmoji(fileId: emojiStatus.fileId), size: CGSize(width: 32.0, height: 32.0), placeholderColor: item.presentationData.theme.list.mediaPlaceholderColor, themeColor: item.presentationData.theme.list.itemAccentColor, loopMode: .count(2)) } else if peer.isVerified { currentCredibilityIconContent = .verified(fillColor: item.presentationData.theme.list.itemCheckColors.fillColor, foregroundColor: item.presentationData.theme.list.itemCheckColors.foregroundColor, sizeType: .compact) } else if peer.isPremium && !premiumConfiguration.isPremiumDisabled { diff --git a/submodules/LegacyComponents/Sources/PGCamera.m b/submodules/LegacyComponents/Sources/PGCamera.m index 84c5399a6d..af30b63446 100644 --- a/submodules/LegacyComponents/Sources/PGCamera.m +++ b/submodules/LegacyComponents/Sources/PGCamera.m @@ -440,11 +440,10 @@ NSString *const PGCameraAdjustingFocusKey = @"adjustingFocus"; }); }; - NSTimeInterval delta = CFAbsoluteTimeGetCurrent() - _captureStartTime; - if (CFAbsoluteTimeGetCurrent() - _captureStartTime > 0.8) + if (CFAbsoluteTimeGetCurrent() - _captureStartTime > 1.5) startRecording(); else - TGDispatchAfter(0.8 - delta, [[PGCamera cameraQueue] _dispatch_queue], startRecording); + TGDispatchAfter(1.5, [[PGCamera cameraQueue] _dispatch_queue], startRecording); TGDispatchOnMainThread(^ { @@ -500,6 +499,8 @@ NSString *const PGCameraAdjustingFocusKey = @"adjustingFocus"; [[PGCamera cameraQueue] dispatch:^ { strongSelf.captureSession.currentMode = cameraMode; + + _captureStartTime = CFAbsoluteTimeGetCurrent(); if (strongSelf.finishedModeChange != nil) strongSelf.finishedModeChange(); diff --git a/submodules/TelegramUI/Components/StorageUsageScreen/Sources/StorageUsageScreen.swift b/submodules/TelegramUI/Components/StorageUsageScreen/Sources/StorageUsageScreen.swift index 66cf9cd7ca..e379cd1fec 100644 --- a/submodules/TelegramUI/Components/StorageUsageScreen/Sources/StorageUsageScreen.swift +++ b/submodules/TelegramUI/Components/StorageUsageScreen/Sources/StorageUsageScreen.swift @@ -2214,7 +2214,7 @@ final class StorageUsageScreenComponent: Component { let clearingSize = CGSize(width: availableSize.width, height: availableSize.height) clearingNode.frame = CGRect(origin: CGPoint(x: floor((availableSize.width - clearingSize.width) / 2.0), y: floor((availableSize.height - clearingSize.height) / 2.0)), size: clearingSize) - clearingNode.updateLayout(size: clearingSize, transition: .immediate) + clearingNode.updateLayout(size: clearingSize, bottomInset: environment.safeInsets.bottom, transition: .immediate) if animateIn { clearingNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.25, delay: 0.4) @@ -3494,7 +3494,7 @@ private class StorageUsageClearProgressOverlayNode: ASDisplayNode { private let progressDisposable = MetaDisposable() - private var validLayout: CGSize? + private var validLayout: (CGSize, CGFloat)? init(presentationData: PresentationData) { self.presentationData = presentationData @@ -3547,13 +3547,13 @@ private class StorageUsageClearProgressOverlayNode: ASDisplayNode { func setProgress(_ progress: Float) { self.progress = progress - if let size = self.validLayout { - self.updateLayout(size: size, transition: .animated(duration: 0.5, curve: .linear)) + if let (size, bottomInset) = self.validLayout { + self.updateLayout(size: size, bottomInset: bottomInset, transition: .animated(duration: 0.5, curve: .linear)) } } - func updateLayout(size: CGSize, transition: ContainedViewLayoutTransition) { - self.validLayout = size + func updateLayout(size: CGSize, bottomInset: CGFloat, transition: ContainedViewLayoutTransition) { + self.validLayout = (size, bottomInset) transition.updateFrame(view: self.blurredView, frame: CGRect(origin: CGPoint(), size: size)) self.blurredView.update(size: size, transition: transition) @@ -3569,9 +3569,14 @@ private class StorageUsageClearProgressOverlayNode: ASDisplayNode { self.animationNode.frame = animationFrame self.animationNode.updateLayout(size: imageSize) - let progressFrame = CGRect(x: inset, y: size.height - inset - progressHeight, width: size.width - inset * 2.0, height: progressHeight) + var bottomInset = bottomInset + if bottomInset.isZero { + bottomInset = inset + } + + let progressFrame = CGRect(x: inset, y: size.height - bottomInset - progressHeight, width: size.width - inset * 2.0, height: progressHeight) self.progressBackgroundNode.frame = progressFrame - let progressForegroundFrame = CGRect(x: inset, y: size.height - inset - progressHeight, width: floorToScreenPixels(progressFrame.width * CGFloat(self.progress)), height: progressHeight) + let progressForegroundFrame = CGRect(x: inset, y: size.height - bottomInset - progressHeight, width: floorToScreenPixels(progressFrame.width * CGFloat(self.progress)), height: progressHeight) if !self.progressForegroundNode.frame.origin.x.isZero { transition.updateFrame(node: self.progressForegroundNode, frame: progressForegroundFrame, beginWithCurrentState: true) } else { diff --git a/submodules/TelegramUI/Sources/AppDelegate.swift b/submodules/TelegramUI/Sources/AppDelegate.swift index bf0e6f878e..d77804fefc 100644 --- a/submodules/TelegramUI/Sources/AppDelegate.swift +++ b/submodules/TelegramUI/Sources/AppDelegate.swift @@ -2114,18 +2114,18 @@ private func extractAccountManagerState(records: AccountRecordsView Void) -> Bool { if #available(iOS 10.0, *) { var startCallContacts: [INPerson]? - var startCallIsVideo = false + var isVideo = false if let startCallIntent = userActivity.interaction?.intent as? SupportedStartCallIntent { startCallContacts = startCallIntent.contacts - startCallIsVideo = false + isVideo = false } else if let startCallIntent = userActivity.interaction?.intent as? SupportedStartVideoCallIntent { startCallContacts = startCallIntent.contacts - startCallIsVideo = true + isVideo = true } if let startCallContacts = startCallContacts { - let startCall: (Int64) -> Void = { userId in - self.startCallWhenReady(accountId: nil, peerId: PeerId(namespace: Namespaces.Peer.CloudUser, id: PeerId.Id._internalFromInt64Value(userId)), isVideo: startCallIsVideo) + let startCall: (PeerId) -> Void = { peerId in + self.startCallWhenReady(accountId: nil, peerId: peerId, isVideo: isVideo) } func cleanPhoneNumber(_ text: String) -> String { @@ -2163,20 +2163,20 @@ private func extractAccountManagerState(records: AccountRecordsView deliverOnMainQueue).start(next: { peerByContact in var processed = false if let peerByContact = peerByContact { - startCall(peerByContact.id.id._internalGetInt64Value()) + startCall(peerByContact.id) processed = true } else if let handle = contact.customIdentifier, handle.hasPrefix("tg") { let string = handle.suffix(from: handle.index(handle.startIndex, offsetBy: 2)) - if let userId = Int64(string) { - startCall(userId) + if let value = Int64(string) { + startCall(PeerId(value)) processed = true } } if !processed, let handle = contact.personHandle, let value = handle.value { switch handle.type { case .unknown: - if let userId = Int64(value) { - startCall(userId) + if let value = Int64(value) { + startCall(PeerId(value)) processed = true } case .phoneNumber: @@ -2200,7 +2200,7 @@ private func extractAccountManagerState(records: AccountRecordsView deliverOnMainQueue).start(next: { peerId in if let peerId = peerId { - startCall(peerId.id._internalGetInt64Value()) + startCall(peerId) } }) processed = true @@ -2216,8 +2216,8 @@ private func extractAccountManagerState(records: AccountRecordsView map { translationState -> ChatPresentationTranslationState? in - if let translationState, !translationState.fromLang.isEmpty { + if let translationState, !translationState.fromLang.isEmpty && (translationState.fromLang != baseLanguageCode || translationState.isEnabled) { return ChatPresentationTranslationState(isEnabled: translationState.isEnabled, fromLang: translationState.fromLang, toLang: translationState.toLang ?? baseLanguageCode) } else { return nil diff --git a/submodules/TelegramUI/Sources/ChatMessageAnimatedStickerItemNode.swift b/submodules/TelegramUI/Sources/ChatMessageAnimatedStickerItemNode.swift index be0009f633..4debf79fd8 100644 --- a/submodules/TelegramUI/Sources/ChatMessageAnimatedStickerItemNode.swift +++ b/submodules/TelegramUI/Sources/ChatMessageAnimatedStickerItemNode.swift @@ -1050,6 +1050,10 @@ class ChatMessageAnimatedStickerItemNode: ChatMessageItemView { } } + if let subject = item.associatedData.subject, case .forwardedMessages = subject { + needsShareButton = false + } + var isEmoji = false if let _ = telegramDice { imageSize = displaySize diff --git a/submodules/TelegramUI/Sources/ChatMessageBubbleItemNode.swift b/submodules/TelegramUI/Sources/ChatMessageBubbleItemNode.swift index 731862597a..1e6cddcfb6 100644 --- a/submodules/TelegramUI/Sources/ChatMessageBubbleItemNode.swift +++ b/submodules/TelegramUI/Sources/ChatMessageBubbleItemNode.swift @@ -1353,6 +1353,10 @@ class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePreviewItemNode needsShareButton = false } } + + if let subject = item.associatedData.subject, case .forwardedMessages = subject { + needsShareButton = false + } var tmpWidth: CGFloat if allowFullWidth { diff --git a/submodules/TelegramUI/Sources/ChatMessageInstantVideoItemNode.swift b/submodules/TelegramUI/Sources/ChatMessageInstantVideoItemNode.swift index f51c390768..e11a2937fb 100644 --- a/submodules/TelegramUI/Sources/ChatMessageInstantVideoItemNode.swift +++ b/submodules/TelegramUI/Sources/ChatMessageInstantVideoItemNode.swift @@ -362,6 +362,10 @@ class ChatMessageInstantVideoItemNode: ChatMessageItemView, UIGestureRecognizerD } } + if let subject = item.associatedData.subject, case .forwardedMessages = subject { + needsShareButton = false + } + var layoutInsets = layoutConstants.instantVideo.insets if dateHeaderAtBottom { layoutInsets.top += layoutConstants.timestampHeaderHeight diff --git a/submodules/TelegramUI/Sources/ChatMessageStickerItemNode.swift b/submodules/TelegramUI/Sources/ChatMessageStickerItemNode.swift index 5b7e8cb05f..070c7142e4 100644 --- a/submodules/TelegramUI/Sources/ChatMessageStickerItemNode.swift +++ b/submodules/TelegramUI/Sources/ChatMessageStickerItemNode.swift @@ -513,6 +513,10 @@ class ChatMessageStickerItemNode: ChatMessageItemView { } } + if let subject = item.associatedData.subject, case .forwardedMessages = subject { + needsShareButton = false + } + var layoutInsets = UIEdgeInsets(top: mergedTop.merged ? layoutConstants.bubble.mergedSpacing : layoutConstants.bubble.defaultSpacing, left: 0.0, bottom: mergedBottom.merged ? layoutConstants.bubble.mergedSpacing : layoutConstants.bubble.defaultSpacing, right: 0.0) if dateHeaderAtBottom { layoutInsets.top += layoutConstants.timestampHeaderHeight diff --git a/submodules/TelegramUI/Sources/ForwardAccessoryPanelNode.swift b/submodules/TelegramUI/Sources/ForwardAccessoryPanelNode.swift index 2678e8d4bd..efc8bb8395 100644 --- a/submodules/TelegramUI/Sources/ForwardAccessoryPanelNode.swift +++ b/submodules/TelegramUI/Sources/ForwardAccessoryPanelNode.swift @@ -86,7 +86,7 @@ final class ForwardAccessoryPanelNode: AccessoryPanelNode { let messageIds: [MessageId] private var messages: [Message] = [] private var authors: String? - private var sourcePeer: (isPersonal: Bool, displayTitle: String)? + private var sourcePeer: (peerId: PeerId, displayTitle: String)? let closeButton: HighlightableButtonNode let lineNode: ASImageNode @@ -172,7 +172,7 @@ final class ForwardAccessoryPanelNode: AccessoryPanelNode { var uniquePeerIds = Set() var title = "" var text = NSMutableAttributedString(string: "") - var sourcePeer: (Bool, String)? + var sourcePeer: (PeerId, String)? for message in messages { if let author = message.forwardInfo?.author ?? message.effectiveAuthor, !uniquePeerIds.contains(author.id) { uniquePeerIds.insert(author.id) @@ -186,7 +186,7 @@ final class ForwardAccessoryPanelNode: AccessoryPanelNode { } } if let peer = message.peers[message.id.peerId] { - sourcePeer = (peer.id.namespace == Namespaces.Peer.CloudUser, EnginePeer(peer).displayTitle(strings: strongSelf.strings, displayOrder: strongSelf.nameDisplayOrder)) + sourcePeer = (peer.id, EnginePeer(peer).displayTitle(strings: strongSelf.strings, displayOrder: strongSelf.nameDisplayOrder)) } } @@ -361,13 +361,20 @@ final class ForwardAccessoryPanelNode: AccessoryPanelNode { } @objc func closePressed() { - guard let (isPersonal, peerDisplayTitle) = self.sourcePeer else { + guard let (peerId, peerDisplayTitle) = self.sourcePeer else { return } let messageCount = Int32(self.messageIds.count) let messages = self.strings.Conversation_ForwardOptions_Messages(messageCount) - let string = isPersonal ? self.strings.Conversation_ForwardOptions_TextPersonal(messages, peerDisplayTitle) : self.strings.Conversation_ForwardOptions_Text(messages, peerDisplayTitle) - + let string: PresentationStrings.FormattedString + if peerId == self.context.account.peerId { + string = self.strings.Conversation_ForwardOptions_TextSaved(messages) + } else if peerId.namespace == Namespaces.Peer.CloudUser { + string = self.strings.Conversation_ForwardOptions_TextPersonal(messages, peerDisplayTitle) + } else { + string = self.strings.Conversation_ForwardOptions_Text(messages, peerDisplayTitle) + } + let font = Font.regular(floor(self.fontSize.baseDisplaySize * 15.0 / 17.0)) let boldFont = Font.semibold(floor(self.fontSize.baseDisplaySize * 15.0 / 17.0)) let body = MarkdownAttributeSet(font: font, textColor: self.theme.actionSheet.secondaryTextColor) diff --git a/submodules/TelegramUI/Sources/PeerInfo/PeerInfoHeaderNode.swift b/submodules/TelegramUI/Sources/PeerInfo/PeerInfoHeaderNode.swift index 783061912b..ed8fbd51da 100644 --- a/submodules/TelegramUI/Sources/PeerInfo/PeerInfoHeaderNode.swift +++ b/submodules/TelegramUI/Sources/PeerInfo/PeerInfoHeaderNode.swift @@ -3702,10 +3702,25 @@ private class DynamicIslandBlurNode: ASDisplayNode { private var effectView: UIVisualEffectView? private let fadeNode = ASDisplayNode() private let gradientNode = ASImageNode() + + private var hierarchyTrackingNode: HierarchyTrackingNode? + + deinit { + self.animator?.stopAnimation(true) + } override func didLoad() { super.didLoad() + let hierarchyTrackingNode = HierarchyTrackingNode({ [weak self] value in + if !value { + self?.animator?.stopAnimation(true) + self?.animator = nil + } + }) + self.hierarchyTrackingNode = hierarchyTrackingNode + self.addSubnode(hierarchyTrackingNode) + self.fadeNode.backgroundColor = .black self.fadeNode.alpha = 0.0 @@ -3733,25 +3748,33 @@ private class DynamicIslandBlurNode: ASDisplayNode { self.addSubnode(self.fadeNode) } - func prepare() { - guard let effectView = self.effectView, effectView.layer.animation(forKey: "effect") == nil else { - return + private var animator: UIViewPropertyAnimator? + + func prepare() -> Bool { + guard self.animator == nil else { + return false } - UIView.animate(withDuration: 1.0) { - effectView.effect = UIBlurEffect(style: .dark) + let animator = UIViewPropertyAnimator(duration: 1.0, curve: .linear) + self.animator = animator + self.effectView?.effect = nil + animator.addAnimations { [weak self] in + self?.effectView?.effect = UIBlurEffect(style: .dark) } - effectView.layer.speed = 0.0 + return true } func update(_ value: CGFloat) { let fadeAlpha = min(1.0, max(0.0, -0.25 + value * 1.55)) if value > 0.0 { - self.prepare() - self.effectView?.layer.timeOffset = max(0.0, -0.1 + value * 1.1) + var value = value + let updated = self.prepare() + if value > 0.99 && updated { + value = 0.99 + } + self.animator?.fractionComplete = max(0.0, -0.1 + value * 1.1) } else { - self.effectView?.layer.removeAllAnimations() - self.effectView?.layer.speed = 1.0 - self.effectView?.layer.timeOffset = 0.0 + self.animator?.stopAnimation(true) + self.animator = nil self.effectView?.effect = nil } self.fadeNode.alpha = fadeAlpha