diff --git a/submodules/AvatarNode/Sources/PeerAvatar.swift b/submodules/AvatarNode/Sources/PeerAvatar.swift index 7d63152342..b022dcd08d 100644 --- a/submodules/AvatarNode/Sources/PeerAvatar.swift +++ b/submodules/AvatarNode/Sources/PeerAvatar.swift @@ -89,7 +89,7 @@ public func peerAvatarCompleteImage(account: Account, peer: EnginePeer, forcePro let clipStyle: AvatarNodeClipStyle if round { - if case let .channel(channel) = peer, channel.flags.contains(.isForum) { + if case let .channel(channel) = peer, channel.isForum { clipStyle = .roundedRect } else { clipStyle = .round diff --git a/submodules/BrowserUI/Sources/BrowserWebContent.swift b/submodules/BrowserUI/Sources/BrowserWebContent.swift index 0d4d13012d..bd4f801433 100644 --- a/submodules/BrowserUI/Sources/BrowserWebContent.swift +++ b/submodules/BrowserUI/Sources/BrowserWebContent.swift @@ -26,9 +26,8 @@ final class BrowserWebContent: UIView, BrowserContent, UIScrollViewDelegate { let configuration = WKWebViewConfiguration() self.webView = WKWebView(frame: CGRect(), configuration: configuration) - if #available(iOSApplicationExtension 9.0, iOS 9.0, *) { - self.webView.allowsLinkPreview = false - } + self.webView.allowsLinkPreview = false + if #available(iOSApplicationExtension 11.0, iOS 11.0, *) { self.webView.scrollView.contentInsetAdjustmentBehavior = .never } diff --git a/submodules/CallListUI/Sources/CallListControllerNode.swift b/submodules/CallListUI/Sources/CallListControllerNode.swift index 9579a547a3..da0a55f504 100644 --- a/submodules/CallListUI/Sources/CallListControllerNode.swift +++ b/submodules/CallListUI/Sources/CallListControllerNode.swift @@ -690,13 +690,13 @@ final class CallListControllerNode: ASDisplayNode { let alpha: CGFloat = isHidden ? 0.0 : 1.0 let previousAlpha = self.emptyTextNode.alpha self.emptyTextNode.alpha = alpha - self.emptyTextNode.layer.animateAlpha(from: previousAlpha, to: alpha, duration: 0.2) + self.emptyTextNode.layer.animateAlpha(from: previousAlpha, to: alpha, duration: 0.25) if previousAlpha.isZero && !alpha.isZero { self.emptyAnimationNode.visibility = true } self.emptyAnimationNode.alpha = alpha - self.emptyAnimationNode.layer.animateAlpha(from: previousAlpha, to: alpha, duration: 0.2, completion: { [weak self] _ in + self.emptyAnimationNode.layer.animateAlpha(from: previousAlpha, to: alpha, duration: 0.25, completion: { [weak self] _ in if let strongSelf = self { if !previousAlpha.isZero && strongSelf.emptyAnimationNode.alpha.isZero { strongSelf.emptyAnimationNode.visibility = false @@ -705,9 +705,9 @@ final class CallListControllerNode: ASDisplayNode { }) self.emptyButtonIconNode.alpha = alpha - self.emptyButtonIconNode.layer.animateAlpha(from: previousAlpha, to: alpha, duration: 0.2) + self.emptyButtonIconNode.layer.animateAlpha(from: previousAlpha, to: alpha, duration: 0.25) self.emptyButtonTextNode.alpha = alpha - self.emptyButtonTextNode.layer.animateAlpha(from: previousAlpha, to: alpha, duration: 0.2) + self.emptyButtonTextNode.layer.animateAlpha(from: previousAlpha, to: alpha, duration: 0.25) self.emptyButtonNode.isUserInteractionEnabled = !isHidden if !isHidden { @@ -733,7 +733,6 @@ final class CallListControllerNode: ASDisplayNode { } self.emptyTextNode.attributedText = NSAttributedString(string: emptyText, font: textFont, textColor: color, paragraphAlignment: .center) - self.emptyButtonTextNode.attributedText = NSAttributedString(string: buttonText, font: buttonFont, textColor: theme.list.itemAccentColor, paragraphAlignment: .center) if let layout = self.containerLayout { diff --git a/submodules/CallListUI/Sources/CallListNodeEntries.swift b/submodules/CallListUI/Sources/CallListNodeEntries.swift index 47f83e21e0..d4a917251e 100644 --- a/submodules/CallListUI/Sources/CallListNodeEntries.swift +++ b/submodules/CallListUI/Sources/CallListNodeEntries.swift @@ -230,7 +230,7 @@ func countMeaningfulCallListEntries(_ entries: [CallListNodeEntry]) -> Int { var count: Int = 0 for entry in entries { switch entry.stableId { - case .setting, .groupCall: + case .setting: break default: count += 1 diff --git a/submodules/ChatListUI/Sources/ChatListController.swift b/submodules/ChatListUI/Sources/ChatListController.swift index 31209f9e0d..76db6b0dd5 100644 --- a/submodules/ChatListUI/Sources/ChatListController.swift +++ b/submodules/ChatListUI/Sources/ChatListController.swift @@ -1205,10 +1205,10 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController let controller = ForumCreateTopicScreen(context: context, peerId: peerId, mode: .create) controller.navigationPresentation = .modal - controller.completion = { [weak controller] title, fileId, _ in + controller.completion = { [weak controller] title, fileId, iconColor, _ in controller?.isInProgress = true - let _ = (context.engine.peers.createForumChannelTopic(id: peerId, title: title, iconColor: ForumCreateTopicScreen.iconColors.randomElement()!, iconFileId: fileId) + let _ = (context.engine.peers.createForumChannelTopic(id: peerId, title: title, iconColor: iconColor, iconFileId: fileId) |> deliverOnMainQueue).start(next: { topicId in let _ = context.sharedContext.navigateToForumThread(context: context, peerId: peerId, threadId: topicId, messageId: nil, navigationController: navigationController, activateInput: .text, keepStack: .never).start() }, error: { _ in @@ -2441,10 +2441,10 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController let controller = ForumCreateTopicScreen(context: context, peerId: peerId, mode: .create) controller.navigationPresentation = .modal - controller.completion = { [weak controller] title, fileId, _ in + controller.completion = { [weak controller] title, fileId, iconColor, _ in controller?.isInProgress = true - let _ = (context.engine.peers.createForumChannelTopic(id: peerId, title: title, iconColor: ForumCreateTopicScreen.iconColors.randomElement()!, iconFileId: fileId) + let _ = (context.engine.peers.createForumChannelTopic(id: peerId, title: title, iconColor: iconColor, iconFileId: fileId) |> deliverOnMainQueue).start(next: { topicId in if let navigationController = (sourceController.navigationController as? NavigationController) { let _ = context.sharedContext.navigateToForumThread(context: context, peerId: peerId, threadId: topicId, messageId: nil, navigationController: navigationController, activateInput: .text, keepStack: .never).start() diff --git a/submodules/ChatListUI/Sources/Node/ChatListItemStrings.swift b/submodules/ChatListUI/Sources/Node/ChatListItemStrings.swift index b4a7b82ea0..47e1f40e48 100644 --- a/submodules/ChatListUI/Sources/Node/ChatListItemStrings.swift +++ b/submodules/ChatListUI/Sources/Node/ChatListItemStrings.swift @@ -127,10 +127,8 @@ public func chatListItemStrings(strings: PresentationStrings, nameDisplayOrder: case _ as TelegramMediaImage: if message.text.isEmpty { messageText = strings.Message_Photo - } else if #available(iOSApplicationExtension 9.0, iOS 9.0, *) { - if enableMediaEmoji { - messageText = "🖼 \(messageText)" - } + } else if enableMediaEmoji { + messageText = "🖼 \(messageText)" } case let fileMedia as TelegramMediaFile: var processed = false @@ -188,7 +186,7 @@ public func chatListItemStrings(strings: PresentationStrings, nameDisplayOrder: if message.text.isEmpty { messageText = strings.Message_Video processed = true - } else if #available(iOSApplicationExtension 9.0, iOS 9.0, *) { + } else { if enableMediaEmoji { if !fileMedia.isAnimated { messageText = "📹 \(messageText)" diff --git a/submodules/ChatSendMessageActionUI/Sources/ChatSendMessageActionSheetControllerNode.swift b/submodules/ChatSendMessageActionUI/Sources/ChatSendMessageActionSheetControllerNode.swift index 7035561189..b1a74d9c1f 100644 --- a/submodules/ChatSendMessageActionUI/Sources/ChatSendMessageActionSheetControllerNode.swift +++ b/submodules/ChatSendMessageActionUI/Sources/ChatSendMessageActionSheetControllerNode.swift @@ -209,15 +209,6 @@ final class ChatSendMessageActionSheetControllerNode: ViewControllerTracingNode, self.cancel = cancel self.effectView = UIVisualEffectView() - if #available(iOS 9.0, *) { - } else { - if self.presentationData.theme.rootController.keyboardColor == .dark { - self.effectView.effect = UIBlurEffect(style: .dark) - } else { - self.effectView.effect = UIBlurEffect(style: .light) - } - self.effectView.alpha = 0.0 - } self.dimNode = ASDisplayNode() self.dimNode.alpha = 1.0 @@ -430,14 +421,7 @@ final class ChatSendMessageActionSheetControllerNode: ViewControllerTracingNode, } self.presentationData = presentationData - if #available(iOS 9.0, *) { - } else { - if self.presentationData.theme.rootController.keyboardColor == .dark { - self.effectView.effect = UIBlurEffect(style: .dark) - } else { - self.effectView.effect = UIBlurEffect(style: .light) - } - } + self.effectView.effect = makeCustomZoomBlurEffect(isLight: self.presentationData.theme.rootController.keyboardColor == .light) self.dimNode.backgroundColor = presentationData.theme.contextMenu.dimColor @@ -465,11 +449,7 @@ final class ChatSendMessageActionSheetControllerNode: ViewControllerTracingNode, self.textInputNode.textView.setContentOffset(self.textInputNode.textView.contentOffset, animated: false) UIView.animate(withDuration: 0.2, animations: { - if #available(iOS 9.0, *) { - self.effectView.effect = makeCustomZoomBlurEffect(isLight: !self.presentationData.theme.overallDarkAppearance) - } else { - self.effectView.alpha = 1.0 - } + self.effectView.effect = makeCustomZoomBlurEffect(isLight: self.presentationData.theme.rootController.keyboardColor == .light) }, completion: { _ in }) self.dimNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.2) self.contentContainerNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.2) @@ -562,12 +542,8 @@ final class ChatSendMessageActionSheetControllerNode: ViewControllerTracingNode, } } - UIView.animate(withDuration: 0.4, animations: { - if #available(iOS 9.0, *) { - self.effectView.effect = nil - } else { - self.effectView.alpha = 0.0 - } + UIView.animate(withDuration: 0.2, animations: { + self.effectView.effect = nil }, completion: { _ in completedEffect = true intermediateCompletion() @@ -596,7 +572,6 @@ final class ChatSendMessageActionSheetControllerNode: ViewControllerTracingNode, } let duration = 0.4 - self.sendButtonNode.layer.animatePosition(from: self.sendButtonNode.position, to: self.sendButtonFrame.center, duration: duration, timingFunction: kCAMediaTimingFunctionSpring, removeOnCompletion: false, completion: { _ in completedButton = true intermediateCompletion() diff --git a/submodules/ComposePollUI/Sources/CreatePollController.swift b/submodules/ComposePollUI/Sources/CreatePollController.swift index b964e37bdd..e157558914 100644 --- a/submodules/ComposePollUI/Sources/CreatePollController.swift +++ b/submodules/ComposePollUI/Sources/CreatePollController.swift @@ -427,7 +427,7 @@ private struct CreatePollControllerState: Equatable { var isEditingSolution: Bool = false } -private func createPollControllerEntries(presentationData: PresentationData, peer: EnginePeer, state: CreatePollControllerState, limitsConfiguration: EngineConfiguration.Limits, defaultIsQuiz: Bool?) -> [CreatePollEntry] { +private func createPollControllerEntries(presentationData: PresentationData, peer: EnginePeer, state: CreatePollControllerState, limitsConfiguration: EngineConfiguration.UserLimits, defaultIsQuiz: Bool?) -> [CreatePollEntry] { var entries: [CreatePollEntry] = [] var textLimitText = ItemListSectionHeaderAccessoryText(value: "", color: .generic) @@ -436,7 +436,7 @@ private func createPollControllerEntries(presentationData: PresentationData, pee textLimitText = ItemListSectionHeaderAccessoryText(value: "\(remainingCount)", color: remainingCount < 0 ? .destructive : .generic) } entries.append(.textHeader(presentationData.strings.CreatePoll_TextHeader, textLimitText)) - entries.append(.text(presentationData.strings.CreatePoll_TextPlaceholder, state.text, Int(limitsConfiguration.maxMediaCaptionLength))) + entries.append(.text(presentationData.strings.CreatePoll_TextPlaceholder, state.text, Int(limitsConfiguration.maxCaptionLength))) let optionsHeaderTitle: String if let defaultIsQuiz = defaultIsQuiz, defaultIsQuiz { optionsHeaderTitle = presentationData.strings.CreatePoll_QuizOptionsHeader @@ -866,7 +866,7 @@ public func createPollController(context: AccountContext, updatedPresentationDat let signal = combineLatest(queue: .mainQueue(), presentationData, statePromise.get(), - context.engine.data.subscribe(TelegramEngine.EngineData.Item.Configuration.Limits()) + context.engine.data.subscribe(TelegramEngine.EngineData.Item.Configuration.UserLimits(isPremium: false)) ) |> map { presentationData, state, limitsConfiguration -> (ItemListControllerState, (ItemListNodeState, Any)) in var presentationData = presentationData diff --git a/submodules/ContextUI/Sources/ContextControllerActionsStackNode.swift b/submodules/ContextUI/Sources/ContextControllerActionsStackNode.swift index cdd597b009..a5d75d0db4 100644 --- a/submodules/ContextUI/Sources/ContextControllerActionsStackNode.swift +++ b/submodules/ContextUI/Sources/ContextControllerActionsStackNode.swift @@ -265,7 +265,7 @@ private final class ContextControllerActionsListActionItemNode: HighlightTrackin textColor: titleColor) } - self.titleLabelNode.isUserInteractionEnabled = self.titleLabelNode.tapAttributeAction != nil + self.titleLabelNode.isUserInteractionEnabled = self.titleLabelNode.tapAttributeAction != nil && self.item.action == nil self.subtitleNode.attributedText = subtitle.flatMap { subtitle in return NSAttributedString( diff --git a/submodules/Display/Source/ContainedViewLayoutTransition.swift b/submodules/Display/Source/ContainedViewLayoutTransition.swift index ccd8868e4d..5686e645fb 100644 --- a/submodules/Display/Source/ContainedViewLayoutTransition.swift +++ b/submodules/Display/Source/ContainedViewLayoutTransition.swift @@ -1860,6 +1860,10 @@ final class ControlledTransitionProperty { let toValue: AnyValue private let completion: ((Bool) -> Void)? + private lazy var animationKey: String = { + return "MyCustomAnimation_\(Unmanaged.passUnretained(self).toOpaque())" + }() + init(layer: CALayer, path: String, fromValue: T, toValue: T, completion: ((Bool) -> Void)?) where T: AnyValueProviding { self.layer = layer self.path = path @@ -1871,7 +1875,7 @@ final class ControlledTransitionProperty { } deinit { - self.layer.removeAnimation(forKey: "MyCustomAnimation_\(Unmanaged.passUnretained(self).toOpaque())") + self.layer.removeAnimation(forKey: self.animationKey) } func update(at fraction: CGFloat) { @@ -1887,7 +1891,7 @@ final class ControlledTransitionProperty { animation.toValue = value.nsValue animation.timingFunction = CAMediaTimingFunction(name: .linear) animation.isRemovedOnCompletion = false - self.layer.add(animation, forKey: "MyCustomAnimation_\(Unmanaged.passUnretained(self).toOpaque())") + self.layer.add(animation, forKey: self.animationKey) } func complete(atEnd: Bool) { diff --git a/submodules/ItemListPeerItem/Sources/ItemListPeerItem.swift b/submodules/ItemListPeerItem/Sources/ItemListPeerItem.swift index 06471c28f0..0c7d4717c7 100644 --- a/submodules/ItemListPeerItem/Sources/ItemListPeerItem.swift +++ b/submodules/ItemListPeerItem/Sources/ItemListPeerItem.swift @@ -1292,7 +1292,12 @@ public class ItemListPeerItemNode: ItemListRevealOptionsItemNode, ItemListItemNo overrideImage = .deletedIcon } strongSelf.avatarNode.imageNode.animateFirstTransition = item.animateFirstAvatarTransition - strongSelf.avatarNode.setPeer(context: item.context, theme: item.presentationData.theme, peer: item.peer, overrideImage: overrideImage, emptyColor: item.presentationData.theme.list.mediaPlaceholderColor, synchronousLoad: synchronousLoad) + + var clipStyle: AvatarNodeClipStyle = .round + if case let .channel(channel) = item.peer, channel.isForum { + clipStyle = .roundedRect + } + strongSelf.avatarNode.setPeer(context: item.context, theme: item.presentationData.theme, peer: item.peer, overrideImage: overrideImage, emptyColor: item.presentationData.theme.list.mediaPlaceholderColor, clipStyle: clipStyle, synchronousLoad: synchronousLoad) } } diff --git a/submodules/LocationUI/Sources/LocationSearchContainerNode.swift b/submodules/LocationUI/Sources/LocationSearchContainerNode.swift index f6c79e6238..4438cb06a3 100644 --- a/submodules/LocationUI/Sources/LocationSearchContainerNode.swift +++ b/submodules/LocationUI/Sources/LocationSearchContainerNode.swift @@ -156,7 +156,7 @@ final class LocationSearchContainerNode: ASDisplayNode { let searchItems = self.searchQuery.get() |> mapToSignal { query -> Signal in if let query = query, !query.isEmpty { - return (.complete() |> delay(0.6, queue: Queue.mainQueue())) + return (.complete() |> delay(1.0, queue: Queue.mainQueue())) |> then(.single(query)) } else { return .single(query) diff --git a/submodules/MtProtoKit/Sources/MTApiEnvironment.m b/submodules/MtProtoKit/Sources/MTApiEnvironment.m index ffdcb74d6f..e39218c327 100644 --- a/submodules/MtProtoKit/Sources/MTApiEnvironment.m +++ b/submodules/MtProtoKit/Sources/MTApiEnvironment.m @@ -711,6 +711,10 @@ NSString *suffix = @""; [platform isEqualToString:@"iPad11,7"]) return @"iPad (8th gen)"; + if ([platform isEqualToString:@"iPad12,1"] || + [platform isEqualToString:@"iPad12,2"]) + return @"iPad (9th gen)"; + if ([platform isEqualToString:@"iPad13,1"] || [platform isEqualToString:@"iPad13,2"]) return @"iPad Air (4th gen)"; diff --git a/submodules/PeerInfoUI/Sources/ChannelBannedMemberController.swift b/submodules/PeerInfoUI/Sources/ChannelBannedMemberController.swift index f825699395..2e0ecd6a3a 100644 --- a/submodules/PeerInfoUI/Sources/ChannelBannedMemberController.swift +++ b/submodules/PeerInfoUI/Sources/ChannelBannedMemberController.swift @@ -466,14 +466,41 @@ public func channelBannedMemberController(context: AccountContext, updatedPresen } else { effectiveRightsFlags = defaultBannedRightsFlags } - if value { - effectiveRightsFlags.remove(rights) - effectiveRightsFlags = effectiveRightsFlags.subtracting(groupPermissionDependencies(rights)) + + + if rights == .banSendMedia { + if value { + effectiveRightsFlags.remove(rights) + for item in banSendMediaSubList() { + effectiveRightsFlags.remove(item.0) + } + } else { + effectiveRightsFlags.insert(rights) + for (right, _) in allGroupPermissionList(peer: EnginePeer(peer), expandMedia: false) { + if groupPermissionDependencies(right).contains(rights) { + effectiveRightsFlags.insert(right) + } + } + + for item in banSendMediaSubList() { + effectiveRightsFlags.insert(item.0) + for (right, _) in allGroupPermissionList(peer: EnginePeer(peer), expandMedia: false) { + if groupPermissionDependencies(right).contains(item.0) { + effectiveRightsFlags.insert(right) + } + } + } + } } else { - effectiveRightsFlags.insert(rights) - for (right, _) in allGroupPermissionList(peer: EnginePeer(peer), expandMedia: false) { - if groupPermissionDependencies(right).contains(rights) { - effectiveRightsFlags.insert(right) + if value { + effectiveRightsFlags.remove(rights) + effectiveRightsFlags = effectiveRightsFlags.subtracting(groupPermissionDependencies(rights)) + } else { + effectiveRightsFlags.insert(rights) + for (right, _) in allGroupPermissionList(peer: EnginePeer(peer), expandMedia: false) { + if groupPermissionDependencies(right).contains(rights) { + effectiveRightsFlags.insert(right) + } } } } diff --git a/submodules/PeerInfoUI/Sources/ChannelMembersSearchContainerNode.swift b/submodules/PeerInfoUI/Sources/ChannelMembersSearchContainerNode.swift index 85cdc75b53..0850513f01 100644 --- a/submodules/PeerInfoUI/Sources/ChannelMembersSearchContainerNode.swift +++ b/submodules/PeerInfoUI/Sources/ChannelMembersSearchContainerNode.swift @@ -826,8 +826,12 @@ public final class ChannelMembersSearchContainerNode: SearchDisplayControllerCon case let .member(_, _, _, banInfo, _): if let banInfo = banInfo { var exceptionsString = "" + let sendMediaRights = banSendMediaSubList().map { $0.0 } for (rights, _) in allGroupPermissionList(peer: .channel(channel), expandMedia: true) { if banInfo.rights.flags.contains(rights) { + if banInfo.rights.flags.contains(.banSendMedia) && sendMediaRights.contains(rights) { + continue + } if !exceptionsString.isEmpty { exceptionsString.append(", ") } @@ -1086,8 +1090,12 @@ public final class ChannelMembersSearchContainerNode: SearchDisplayControllerCon case let .member(_, _, _, banInfo, _): if let banInfo = banInfo { var exceptionsString = "" + let sendMediaRights = banSendMediaSubList().map { $0.0 } for (rights, _) in allGroupPermissionList(peer: .legacyGroup(group), expandMedia: true) { if banInfo.rights.flags.contains(rights) { + if banInfo.rights.flags.contains(.banSendMedia) && sendMediaRights.contains(rights) { + continue + } if !exceptionsString.isEmpty { exceptionsString.append(", ") } diff --git a/submodules/PeerInfoUI/Sources/ChannelPermissionsController.swift b/submodules/PeerInfoUI/Sources/ChannelPermissionsController.swift index 6031dda89c..b79d5c3d47 100644 --- a/submodules/PeerInfoUI/Sources/ChannelPermissionsController.swift +++ b/submodules/PeerInfoUI/Sources/ChannelPermissionsController.swift @@ -341,8 +341,12 @@ private enum ChannelPermissionsEntry: ItemListNodeEntry { case let .member(_, _, _, banInfo, _): var exceptionsString = "" if let banInfo = banInfo { + let sendMediaRights = banSendMediaSubList().map { $0.0 } for (rights, _) in internal_allPossibleGroupPermissionList { if !defaultBannedRights.contains(rights) && banInfo.rights.flags.contains(rights) { + if banInfo.rights.flags.contains(.banSendMedia) && sendMediaRights.contains(rights) { + continue + } if !exceptionsString.isEmpty { exceptionsString.append(", ") } diff --git a/submodules/TelegramBaseController/Sources/TelegramBaseController.swift b/submodules/TelegramBaseController/Sources/TelegramBaseController.swift index 5d344a7a3c..c085b6ccec 100644 --- a/submodules/TelegramBaseController/Sources/TelegramBaseController.swift +++ b/submodules/TelegramBaseController/Sources/TelegramBaseController.swift @@ -303,7 +303,13 @@ open class TelegramBaseController: ViewController, KeyShortcutResponder { disposable.set((callContext.context.panelData |> deliverOnMainQueue).start(next: { panelData in callContext.keep() - subscriber.putNext(panelData) + var updatedPanelData = panelData + if let panelData { + var updatedInfo = panelData.info + updatedInfo.subscribedToScheduled = activeCall.subscribedToScheduled + updatedPanelData = panelData.withInfo(updatedInfo) + } + subscriber.putNext(updatedPanelData) })) } diff --git a/submodules/TelegramCallsUI/Sources/GroupCallNavigationAccessoryPanel.swift b/submodules/TelegramCallsUI/Sources/GroupCallNavigationAccessoryPanel.swift index 94bd233639..3adde6596e 100644 --- a/submodules/TelegramCallsUI/Sources/GroupCallNavigationAccessoryPanel.swift +++ b/submodules/TelegramCallsUI/Sources/GroupCallNavigationAccessoryPanel.swift @@ -64,6 +64,18 @@ public final class GroupCallPanelData { self.activeSpeakers = activeSpeakers self.groupCall = groupCall } + + public func withInfo(_ info: GroupCallInfo) -> GroupCallPanelData { + return GroupCallPanelData( + peerId: self.peerId, + isChannel: self.isChannel, + info: info, + topParticipants: self.topParticipants, + participantCount: self.participantCount, + activeSpeakers: self.activeSpeakers, + groupCall: self.groupCall + ) + } } private final class FakeAudioLevelGenerator { diff --git a/submodules/TelegramCallsUI/Sources/PresentationGroupCall.swift b/submodules/TelegramCallsUI/Sources/PresentationGroupCall.swift index d327f0853d..9af33d1ca0 100644 --- a/submodules/TelegramCallsUI/Sources/PresentationGroupCall.swift +++ b/submodules/TelegramCallsUI/Sources/PresentationGroupCall.swift @@ -116,12 +116,12 @@ public final class AccountGroupCallContextImpl: AccountGroupCallContext { activeSpeakers: Set(), groupCall: nil )))*/ - + let state = engine.calls.getGroupCallParticipants(callId: call.id, accessHash: call.accessHash, offset: "", ssrcs: [], limit: 100, sortAscending: nil) - |> map(Optional.init) - |> `catch` { _ -> Signal in - return .single(nil) - } + |> map(Optional.init) + |> `catch` { _ -> Signal in + return .single(nil) + } self.disposable = (combineLatest(queue: .mainQueue(), state, @@ -139,7 +139,7 @@ public final class AccountGroupCallContextImpl: AccountGroupCallContext { state: state, previousServiceState: nil ) - + strongSelf.participantsContext = context strongSelf.panelDataPromise.set(combineLatest(queue: .mainQueue(), context.state, diff --git a/submodules/TelegramCore/Sources/State/AccountStateManager.swift b/submodules/TelegramCore/Sources/State/AccountStateManager.swift index aeb5bf16f0..5b1a321b0d 100644 --- a/submodules/TelegramCore/Sources/State/AccountStateManager.swift +++ b/submodules/TelegramCore/Sources/State/AccountStateManager.swift @@ -1026,7 +1026,7 @@ public final class AccountStateManager { } let _ = (signal - |> deliverOn(self.queue)).start(next: { [weak self] messages in + |> deliverOn(self.queue)).start(next: { [weak self] messages in if let strongSelf = self { strongSelf.notificationMessagesPipe.putNext(messages) } @@ -1953,6 +1953,9 @@ public func messagesForNotification(transaction: Transaction, id: MessageId, alw } if let channel = message.peers[message.id.peerId] as? TelegramChannel { + if !channel.flags.contains(.isForum) { + threadData = nil + } switch channel.participationStatus { case .kicked, .left: return ([], false, sound, false, threadData) diff --git a/submodules/TelegramCore/Sources/State/ManagedConfigurationUpdates.swift b/submodules/TelegramCore/Sources/State/ManagedConfigurationUpdates.swift index a4bef755a9..2bbf5284a2 100644 --- a/submodules/TelegramCore/Sources/State/ManagedConfigurationUpdates.swift +++ b/submodules/TelegramCore/Sources/State/ManagedConfigurationUpdates.swift @@ -14,7 +14,7 @@ func managedConfigurationUpdates(accountManager: AccountManager mapToSignal { result, defaultHistoryTtl -> Signal in return postbox.transaction { transaction -> Signal in switch result { - case let .config(flags, _, _, _, _, dcOptions, _, chatSizeMax, megagroupSizeMax, forwardedCountMax, _, _, _, _, _, _, _, _, editTimeLimit, revokeTimeLimit, revokePmTimeLimit, _, stickersRecentLimit, _, _, _, _, _, _, _, autoupdateUrlPrefix, gifSearchUsername, venueSearchUsername, imgSearchUsername, _, captionLengthMax, _, webfileDcId, suggestedLangCode, langPackVersion, baseLangPackVersion, reactionsDefault, autologinToken): + case let .config(flags, _, _, _, _, dcOptions, _, chatSizeMax, megagroupSizeMax, forwardedCountMax, _, _, _, _, _, _, _, _, editTimeLimit, revokeTimeLimit, revokePmTimeLimit, _, stickersRecentLimit, _, _, _, _, _, _, _, autoupdateUrlPrefix, gifSearchUsername, venueSearchUsername, imgSearchUsername, _, _, _, webfileDcId, suggestedLangCode, langPackVersion, baseLangPackVersion, reactionsDefault, autologinToken): var addressList: [Int: [MTDatacenterAddress]] = [:] for option in dcOptions { switch option { @@ -61,7 +61,7 @@ func managedConfigurationUpdates(accountManager: AccountManager LimitsConfiguration { return LimitsConfiguration( - maxPinnedChatCount: self.maxPinnedChatCount, - maxArchivedPinnedChatCount: self.maxArchivedPinnedChatCount, maxGroupMemberCount: self.maxGroupMemberCount, maxSupergroupMemberCount: self.maxSupergroupMemberCount, maxMessageForwardBatchSize: self.maxMessageForwardBatchSize, - maxSavedGifCount: self.maxSavedGifCount, maxRecentStickerCount: self.maxRecentStickerCount, - maxFavedStickerCount: self.maxFavedStickerCount, maxMessageEditingInterval: self.maxMessageEditingInterval, - maxMediaCaptionLength: self.maxMediaCaptionLength, canRemoveIncomingMessagesInPrivateChats: self.canRemoveIncomingMessagesInPrivateChats, maxMessageRevokeInterval: self.maxMessageRevokeInterval, maxMessageRevokeIntervalInPrivateChats: self.maxMessageRevokeIntervalInPrivateChats @@ -142,6 +120,7 @@ public extension EngineConfiguration.UserLimits { init(_ userLimitsConfiguration: UserLimitsConfiguration) { self.init( maxPinnedChatCount: userLimitsConfiguration.maxPinnedChatCount, + maxArchivedPinnedChatCount: userLimitsConfiguration.maxArchivedPinnedChatCount, maxChannelsCount: userLimitsConfiguration.maxChannelsCount, maxPublicLinksCount: userLimitsConfiguration.maxPublicLinksCount, maxSavedGifCount: userLimitsConfiguration.maxSavedGifCount, diff --git a/submodules/TelegramCore/Sources/TelegramEngine/Messages/ChatList.swift b/submodules/TelegramCore/Sources/TelegramEngine/Messages/ChatList.swift index 96d56034ed..8fbfbca7e5 100644 --- a/submodules/TelegramCore/Sources/TelegramEngine/Messages/ChatList.swift +++ b/submodules/TelegramCore/Sources/TelegramEngine/Messages/ChatList.swift @@ -457,8 +457,13 @@ extension EngineChatList.Item { let readCounters = readState.flatMap(EnginePeerReadCounters.init) - if let channel = renderedPeer.peer as? TelegramChannel, channel.flags.contains(.isForum) { - draft = nil + if let channel = renderedPeer.peer as? TelegramChannel { + if channel.flags.contains(.isForum) { + draft = nil + } else { + forumTopicDataValue = nil + topForumTopicItems = [] + } } self.init( diff --git a/submodules/TelegramCore/Sources/TelegramEngine/Peers/TogglePeerChatPinned.swift b/submodules/TelegramCore/Sources/TelegramEngine/Peers/TogglePeerChatPinned.swift index 9a903484eb..378b4fe35c 100644 --- a/submodules/TelegramCore/Sources/TelegramEngine/Peers/TogglePeerChatPinned.swift +++ b/submodules/TelegramCore/Sources/TelegramEngine/Peers/TogglePeerChatPinned.swift @@ -17,7 +17,6 @@ func _internal_toggleItemPinned(postbox: Postbox, accountPeerId: PeerId, locatio let isPremium = transaction.getPeer(accountPeerId)?.isPremium ?? false let appConfiguration = transaction.getPreferencesEntry(key: PreferencesKeys.appConfiguration)?.get(AppConfiguration.self) ?? .defaultValue - let limitsConfiguration = transaction.getPreferencesEntry(key: PreferencesKeys.limitsConfiguration)?.get(LimitsConfiguration.self) ?? LimitsConfiguration.defaultValue let userLimitsConfiguration = UserLimitsConfiguration(appConfiguration: appConfiguration, isPremium: isPremium) switch location { @@ -46,7 +45,7 @@ func _internal_toggleItemPinned(postbox: Postbox, accountPeerId: PeerId, locatio if case .root = groupId { limitCount = Int(userLimitsConfiguration.maxPinnedChatCount) } else { - limitCount = Int(limitsConfiguration.maxArchivedPinnedChatCount) + limitCount = Int(userLimitsConfiguration.maxArchivedPinnedChatCount) } let count = sameKind.count + additionalCount diff --git a/submodules/TelegramUI/Components/ForumCreateTopicScreen/Sources/ForumCreateTopicScreen.swift b/submodules/TelegramUI/Components/ForumCreateTopicScreen/Sources/ForumCreateTopicScreen.swift index 8d2c6c72b6..0da02b5a58 100644 --- a/submodules/TelegramUI/Components/ForumCreateTopicScreen/Sources/ForumCreateTopicScreen.swift +++ b/submodules/TelegramUI/Components/ForumCreateTopicScreen/Sources/ForumCreateTopicScreen.swift @@ -95,6 +95,7 @@ private final class TitleFieldComponent: Component { let iconColor: Int32 let text: String let placeholderText: String + let isEditing: Bool let textUpdated: (String) -> Void let iconPressed: () -> Void @@ -108,6 +109,7 @@ private final class TitleFieldComponent: Component { iconColor: Int32, text: String, placeholderText: String, + isEditing: Bool, textUpdated: @escaping (String) -> Void, iconPressed: @escaping () -> Void ) { @@ -120,6 +122,7 @@ private final class TitleFieldComponent: Component { self.iconColor = iconColor self.text = text self.placeholderText = placeholderText + self.isEditing = isEditing self.textUpdated = textUpdated self.iconPressed = iconPressed } @@ -152,6 +155,9 @@ private final class TitleFieldComponent: Component { if lhs.placeholderText != rhs.placeholderText { return false } + if lhs.isEditing != rhs.isEditing { + return false + } return true } @@ -237,6 +243,7 @@ private final class TitleFieldComponent: Component { iconContent = .animation(content: .customEmoji(fileId: component.fileId), size: CGSize(width: 48.0, height: 48.0), placeholderColor: component.placeholderColor, themeColor: component.accentColor, loopMode: .count(2)) self.iconButton.isUserInteractionEnabled = false } + self.iconButton.isUserInteractionEnabled = !component.isEditing let placeholderSize = self.placeholderView.update( transition: .easeInOut(duration: 0.2), @@ -471,15 +478,26 @@ private final class ForumCreateTopicScreenComponent: CombinedComponent { let mode: ForumCreateTopicScreen.Mode let titleUpdated: (String) -> Void let iconUpdated: (Int64?) -> Void + let iconColorUpdated: (Int32) -> Void let isHiddenUpdated: (Bool) -> Void let openPremium: () -> Void - init(context: AccountContext, peerId: EnginePeer.Id, mode: ForumCreateTopicScreen.Mode, titleUpdated: @escaping (String) -> Void, iconUpdated: @escaping (Int64?) -> Void, isHiddenUpdated: @escaping (Bool) -> Void, openPremium: @escaping () -> Void) { + init( + context: AccountContext, + peerId: EnginePeer.Id, + mode: ForumCreateTopicScreen.Mode, + titleUpdated: @escaping (String) -> Void, + iconUpdated: @escaping (Int64?) -> Void, + iconColorUpdated: @escaping (Int32) -> Void, + isHiddenUpdated: @escaping (Bool) -> Void, + openPremium: @escaping () -> Void + ) { self.context = context self.peerId = peerId self.mode = mode self.titleUpdated = titleUpdated self.iconUpdated = iconUpdated + self.iconColorUpdated = iconColorUpdated self.isHiddenUpdated = isHiddenUpdated self.openPremium = openPremium } @@ -501,6 +519,7 @@ private final class ForumCreateTopicScreenComponent: CombinedComponent { private let context: AccountContext private let titleUpdated: (String) -> Void private let iconUpdated: (Int64?) -> Void + private let iconColorUpdated: (Int32) -> Void private let isHiddenUpdated: (Bool) -> Void private let openPremium: () -> Void @@ -520,10 +539,11 @@ private final class ForumCreateTopicScreenComponent: CombinedComponent { private var hasPremium: Bool = false - init(context: AccountContext, mode: ForumCreateTopicScreen.Mode, titleUpdated: @escaping (String) -> Void, iconUpdated: @escaping (Int64?) -> Void, isHiddenUpdated: @escaping (Bool) -> Void, openPremium: @escaping () -> Void) { + init(context: AccountContext, mode: ForumCreateTopicScreen.Mode, titleUpdated: @escaping (String) -> Void, iconUpdated: @escaping (Int64?) -> Void, iconColorUpdated: @escaping (Int32) -> Void, isHiddenUpdated: @escaping (Bool) -> Void, openPremium: @escaping () -> Void) { self.context = context self.titleUpdated = titleUpdated self.iconUpdated = iconUpdated + self.iconColorUpdated = iconColorUpdated self.isHiddenUpdated = isHiddenUpdated self.openPremium = openPremium @@ -534,6 +554,7 @@ private final class ForumCreateTopicScreenComponent: CombinedComponent { self.fileId = 0 self.iconColor = ForumCreateTopicScreen.iconColors.randomElement() ?? 0x0 self.isHidden = false + iconColorUpdated(self.iconColor) case let .edit(threadId, info, isHidden): self.isGeneral = threadId == 1 self.title = info.title @@ -647,6 +668,7 @@ private final class ForumCreateTopicScreenComponent: CombinedComponent { self.iconColor = colors.first ?? 0 } self.updated(transition: .immediate) + self.iconColorUpdated(self.iconColor) self.updateEmojiContent() } @@ -678,6 +700,7 @@ private final class ForumCreateTopicScreenComponent: CombinedComponent { mode: self.mode, titleUpdated: self.titleUpdated, iconUpdated: self.iconUpdated, + iconColorUpdated: self.iconColorUpdated, isHiddenUpdated: self.isHiddenUpdated, openPremium: self.openPremium ) @@ -753,6 +776,11 @@ private final class ForumCreateTopicScreenComponent: CombinedComponent { .position(CGPoint(x: context.availableSize.width / 2.0, y: contentHeight + titleBackground.size.height / 2.0)) ) + var isEditing = false + if case .edit = context.component.mode { + isEditing = true + } + let titleField = titleField.update( component: TitleFieldComponent( context: context.component.context, @@ -764,6 +792,7 @@ private final class ForumCreateTopicScreenComponent: CombinedComponent { iconColor: state.iconColor, text: state.title, placeholderText: environment.strings.CreateTopic_EnterTopicTitlePlaceholder, + isEditing: isEditing, textUpdated: { [weak state] text in state?.updateTitle(text) }, @@ -999,8 +1028,8 @@ public class ForumCreateTopicScreen: ViewControllerComponentContainer { private var doneBarItem: UIBarButtonItem? - private var state: (String, Int64?, Bool?) = ("", nil, nil) - public var completion: (String, Int64?, Bool?) -> Void = { _, _, _ in } + private var state: (title: String, icon: Int64?, iconColor: Int32, isHidden: Bool?) = ("", nil, 0, nil) + public var completion: (_ title: String, _ icon: Int64?, _ iconColor: Int32, _ isHidden: Bool?) -> Void = { _, _, _, _ in } public var isInProgress: Bool = false { didSet { @@ -1021,6 +1050,7 @@ public class ForumCreateTopicScreen: ViewControllerComponentContainer { var titleUpdatedImpl: ((String) -> Void)? var iconUpdatedImpl: ((Int64?) -> Void)? + var iconColorUpdatedImpl: ((Int32) -> Void)? var isHiddenUpdatedImpl: ((Bool) -> Void)? var openPremiumImpl: (() -> Void)? @@ -1028,6 +1058,8 @@ public class ForumCreateTopicScreen: ViewControllerComponentContainer { titleUpdatedImpl?(title) }, iconUpdated: { fileId in iconUpdatedImpl?(fileId) + }, iconColorUpdated: { iconColor in + iconColorUpdatedImpl?(iconColor) }, isHiddenUpdated: { isHidden in isHiddenUpdatedImpl?(isHidden) }, openPremium: { @@ -1045,7 +1077,7 @@ public class ForumCreateTopicScreen: ViewControllerComponentContainer { title = presentationData.strings.CreateTopic_EditTitle doneTitle = presentationData.strings.Common_Done - self.state = (topic.title, topic.icon, threadId == 1 ? isHidden : nil) + self.state = (topic.title, topic.icon, topic.iconColor, threadId == 1 ? isHidden : nil) } self.title = title @@ -1066,23 +1098,28 @@ public class ForumCreateTopicScreen: ViewControllerComponentContainer { } strongSelf.doneBarItem?.isEnabled = !title.isEmpty - strongSelf.state = (title, strongSelf.state.1, strongSelf.state.2) + strongSelf.state = (title, strongSelf.state.icon, strongSelf.state.iconColor, strongSelf.state.isHidden) } iconUpdatedImpl = { [weak self] fileId in guard let strongSelf = self else { return } - - strongSelf.state = (strongSelf.state.0, fileId, strongSelf.state.2) + strongSelf.state = (strongSelf.state.title, fileId, strongSelf.state.iconColor, strongSelf.state.isHidden) + } + + iconColorUpdatedImpl = { [weak self] iconColor in + guard let strongSelf = self else { + return + } + strongSelf.state = (strongSelf.state.title, strongSelf.state.icon, iconColor, strongSelf.state.isHidden) } isHiddenUpdatedImpl = { [weak self] isHidden in guard let strongSelf = self else { return } - - strongSelf.state = (strongSelf.state.0, strongSelf.state.1, isHidden) + strongSelf.state = (strongSelf.state.title, strongSelf.state.icon, strongSelf.state.iconColor, isHidden) } openPremiumImpl = { [weak self] in @@ -1113,6 +1150,6 @@ public class ForumCreateTopicScreen: ViewControllerComponentContainer { } @objc private func createPressed() { - self.completion(self.state.0, self.state.1, self.state.2) + self.completion(self.state.title, self.state.icon, self.state.iconColor, self.state.isHidden) } } diff --git a/submodules/TelegramUI/Sources/AppDelegate.swift b/submodules/TelegramUI/Sources/AppDelegate.swift index 6c233f21da..3c145fc513 100644 --- a/submodules/TelegramUI/Sources/AppDelegate.swift +++ b/submodules/TelegramUI/Sources/AppDelegate.swift @@ -2401,7 +2401,7 @@ private func extractAccountManagerState(records: AccountRecordsView map { messageIds -> MessageId? in if messageIds.isEmpty { return nil diff --git a/submodules/TelegramUI/Sources/ChatController.swift b/submodules/TelegramUI/Sources/ChatController.swift index c218c1d6f8..863a15e0d0 100644 --- a/submodules/TelegramUI/Sources/ChatController.swift +++ b/submodules/TelegramUI/Sources/ChatController.swift @@ -3913,7 +3913,8 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G } if let mediaReference = mediaReference, let peer = message.peers[message.id.peerId] { - legacyMediaEditor(context: strongSelf.context, peer: peer, threadTitle: strongSelf.threadInfo?.title, media: mediaReference, initialCaption: NSAttributedString(string: message.text), snapshots: [], transitionCompletion: nil, getCaptionPanelView: { [weak self] in + let inputText = strongSelf.presentationInterfaceState.interfaceState.effectiveInputState.inputText + legacyMediaEditor(context: strongSelf.context, peer: peer, threadTitle: strongSelf.threadInfo?.title, media: mediaReference, initialCaption: inputText, snapshots: [], transitionCompletion: nil, getCaptionPanelView: { [weak self] in return self?.getCaptionPanelView() }, sendMessagesWithSignals: { [weak self] signals, _, _ in if let strongSelf = self { @@ -7891,7 +7892,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G var webpageUrl: String? for media in message.media { if media is TelegramMediaImage || media is TelegramMediaFile { - inputTextMaxLength = strongSelf.context.currentLimitsConfiguration.with { $0 }.maxMediaCaptionLength + inputTextMaxLength = strongSelf.context.userLimits.maxCaptionLength } else if let webpage = media as? TelegramMediaWebpage, case let .Loaded(content) = webpage.content { webpageUrl = content.url } @@ -8128,16 +8129,15 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G if let strongSelf = self, let peerId = strongSelf.chatLocation.peerId { let presentationData = strongSelf.presentationData - let forwardOptions: Signal - if peerId.namespace == Namespaces.Peer.SecretChat { - forwardOptions = .single(ChatControllerSubject.ForwardOptions(hideNames: true, hideCaptions: false)) - } else { - forwardOptions = strongSelf.presentationInterfaceStatePromise.get() - |> map { state -> ChatControllerSubject.ForwardOptions in - return ChatControllerSubject.ForwardOptions(hideNames: state.interfaceState.forwardOptionsState?.hideNames ?? false, hideCaptions: state.interfaceState.forwardOptionsState?.hideCaptions ?? false) + let forwardOptions = strongSelf.presentationInterfaceStatePromise.get() + |> map { state -> ChatControllerSubject.ForwardOptions in + var hideNames = state.interfaceState.forwardOptionsState?.hideNames ?? false + if peerId.namespace == Namespaces.Peer.SecretChat { + hideNames = true } - |> distinctUntilChanged + return ChatControllerSubject.ForwardOptions(hideNames: hideNames, hideCaptions: state.interfaceState.forwardOptionsState?.hideCaptions ?? false) } + |> distinctUntilChanged let chatController = strongSelf.context.sharedContext.makeChatController(context: strongSelf.context, chatLocation: .peer(id: peerId), subject: .forwardedMessages(peerIds: [peerId], ids: strongSelf.presentationInterfaceState.interfaceState.forwardMessageIds ?? [], options: forwardOptions), botStart: nil, mode: .standard(previewing: true)) chatController.canReadHistory.set(false) @@ -8197,88 +8197,90 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G } } - let canHideNames = hasNotOwnMessages && hasOther - + var canHideNames = hasNotOwnMessages && hasOther + if case let .peer(peerId) = strongSelf.chatLocation, peerId.namespace == Namespaces.Peer.SecretChat { + canHideNames = false + } let hideNames = forwardOptions.hideNames let hideCaptions = forwardOptions.hideCaptions - if case let .peer(peerId) = strongSelf.chatLocation, peerId.namespace == Namespaces.Peer.SecretChat { + if canHideNames { + items.append(.action(ContextMenuActionItem(text: uniquePeerIds.count == 1 ? presentationData.strings.Conversation_ForwardOptions_ShowSendersName : presentationData.strings.Conversation_ForwardOptions_ShowSendersNames, icon: { theme in + if hideNames { + return nil + } else { + return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Check"), color: theme.contextMenu.primaryColor) + } + }, action: { [weak self] _, f in + self?.interfaceInteraction?.updateForwardOptionsState({ current in + var updated = current + updated.hideNames = false + updated.hideCaptions = false + updated.unhideNamesOnCaptionChange = false + return updated + }) + }))) - } else { - if canHideNames { - items.append(.action(ContextMenuActionItem(text: uniquePeerIds.count == 1 ? presentationData.strings.Conversation_ForwardOptions_ShowSendersName : presentationData.strings.Conversation_ForwardOptions_ShowSendersNames, icon: { theme in - if hideNames { - return nil - } else { - return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Check"), color: theme.contextMenu.primaryColor) - } - }, action: { [weak self] _, f in - self?.interfaceInteraction?.updateForwardOptionsState({ current in - var updated = current - updated.hideNames = false - updated.hideCaptions = false - updated.unhideNamesOnCaptionChange = false - return updated - }) - }))) - - items.append(.action(ContextMenuActionItem(text: uniquePeerIds.count == 1 ? presentationData.strings.Conversation_ForwardOptions_HideSendersName : presentationData.strings.Conversation_ForwardOptions_HideSendersNames, icon: { theme in - if hideNames { - return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Check"), color: theme.contextMenu.primaryColor) - } else { - return nil - } - }, action: { _, f in - self?.interfaceInteraction?.updateForwardOptionsState({ current in - var updated = current - updated.hideNames = true - updated.unhideNamesOnCaptionChange = false - return updated - }) - }))) - - items.append(.separator) - } + items.append(.action(ContextMenuActionItem(text: uniquePeerIds.count == 1 ? presentationData.strings.Conversation_ForwardOptions_HideSendersName : presentationData.strings.Conversation_ForwardOptions_HideSendersNames, icon: { theme in + if hideNames { + return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Check"), color: theme.contextMenu.primaryColor) + } else { + return nil + } + }, action: { _, f in + self?.interfaceInteraction?.updateForwardOptionsState({ current in + var updated = current + updated.hideNames = true + updated.unhideNamesOnCaptionChange = false + return updated + }) + }))) - if hasCaptions { - items.append(.action(ContextMenuActionItem(text: presentationData.strings.Conversation_ForwardOptions_ShowCaption, icon: { theme in - if hideCaptions { - return nil - } else { - return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Check"), color: theme.contextMenu.primaryColor) - } - }, action: { [weak self] _, f in - self?.interfaceInteraction?.updateForwardOptionsState({ current in - var updated = current - updated.hideCaptions = false + items.append(.separator) + } + + if hasCaptions { + items.append(.action(ContextMenuActionItem(text: presentationData.strings.Conversation_ForwardOptions_ShowCaption, icon: { theme in + if hideCaptions { + return nil + } else { + return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Check"), color: theme.contextMenu.primaryColor) + } + }, action: { [weak self] _, f in + self?.interfaceInteraction?.updateForwardOptionsState({ current in + var updated = current + updated.hideCaptions = false + if canHideNames { if updated.unhideNamesOnCaptionChange { updated.unhideNamesOnCaptionChange = false updated.hideNames = false } - return updated - }) - }))) - - items.append(.action(ContextMenuActionItem(text: presentationData.strings.Conversation_ForwardOptions_HideCaption, icon: { theme in - if hideCaptions { - return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Check"), color: theme.contextMenu.primaryColor) - } else { - return nil } - }, action: { _, f in - self?.interfaceInteraction?.updateForwardOptionsState({ current in - var updated = current - updated.hideCaptions = true + return updated + }) + }))) + + items.append(.action(ContextMenuActionItem(text: presentationData.strings.Conversation_ForwardOptions_HideCaption, icon: { theme in + if hideCaptions { + return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Check"), color: theme.contextMenu.primaryColor) + } else { + return nil + } + }, action: { _, f in + self?.interfaceInteraction?.updateForwardOptionsState({ current in + var updated = current + updated.hideCaptions = true + if canHideNames { if !updated.hideNames { updated.hideNames = true updated.unhideNamesOnCaptionChange = true } - return updated - }) - }))) - - items.append(.separator) - } + } + return updated + }) + }))) + + items.append(.separator) } items.append(.action(ContextMenuActionItem(text: presentationData.strings.Conversation_ForwardOptions_ChangeRecipient, icon: { theme in return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Forward"), color: theme.contextMenu.primaryColor) }, action: { c, f in @@ -11348,7 +11350,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G } var layout = layout - if case .compact = layout.metrics.widthClass, let _ = self.attachmentController { + if case .compact = layout.metrics.widthClass, let attachmentController = self.attachmentController, attachmentController.window != nil { layout = layout.withUpdatedInputHeight(nil) } @@ -15989,7 +15991,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G self.dismiss() let navigateToLocation: NavigateToChatControllerParams.Location - if let message = messages.first, let threadId = message.threadId, threadId != 1 || (message.peers[message.id.peerId] as? TelegramChannel)?.flags.contains(.isForum) == true { + if let message = messages.first, let threadId = message.threadId, let channel = message.peers[message.id.peerId] as? TelegramChannel, channel.flags.contains(.isForum) { navigateToLocation = .replyThread(ChatReplyThreadMessage(messageId: MessageId(peerId: peer.id, namespace: Namespaces.Message.Cloud, id: Int32(clamping: threadId)), channelMessageId: nil, isChannelPost: false, isForumPost: true, maxMessage: nil, maxReadIncomingMessageId: nil, maxReadOutgoingMessageId: nil, unreadCount: 0, initialFilledHoles: IndexSet(), initialAnchor: .automatic, isNotAvailable: false)) } else { navigateToLocation = .peer(peer) diff --git a/submodules/TelegramUI/Sources/ChatMediaInputStickerGridItem.swift b/submodules/TelegramUI/Sources/ChatMediaInputStickerGridItem.swift index 0cbe2d7bb7..4bb41e754a 100644 --- a/submodules/TelegramUI/Sources/ChatMediaInputStickerGridItem.swift +++ b/submodules/TelegramUI/Sources/ChatMediaInputStickerGridItem.swift @@ -438,7 +438,7 @@ final class ChatMediaInputStickerGridItemNode: GridItemNode { let dimensions = item.stickerItem.file.dimensions ?? PixelDimensions(width: 512, height: 512) let fitSize = item.large ? CGSize(width: 384.0, height: 384.0) : CGSize(width: 160.0, height: 160.0) let fittedDimensions = dimensions.cgSize.aspectFitted(fitSize) - animationNode.setup(source: AnimatedStickerResourceSource(account: item.context.account, resource: item.stickerItem.file.resource, isVideo: item.stickerItem.file.isVideoSticker), width: Int(fittedDimensions.width), height: Int(fittedDimensions.height), playbackMode: .loop, mode: .cached) + animationNode.setup(source: AnimatedStickerResourceSource(account: item.context.account, resource: item.stickerItem.file.resource, isVideo: item.stickerItem.file.isVideoSticker), width: Int(fittedDimensions.width), height: Int(fittedDimensions.height), playbackMode: .loop, mode: .direct(cachePathPrefix: nil)) } } } diff --git a/submodules/TelegramUI/Sources/ChatMessageInstantVideoBubbleContentNode.swift b/submodules/TelegramUI/Sources/ChatMessageInstantVideoBubbleContentNode.swift index 3fdc0070e2..6e8a97de99 100644 --- a/submodules/TelegramUI/Sources/ChatMessageInstantVideoBubbleContentNode.swift +++ b/submodules/TelegramUI/Sources/ChatMessageInstantVideoBubbleContentNode.swift @@ -70,7 +70,6 @@ class ChatMessageInstantVideoBubbleContentNode: ChatMessageBubbleContentNode { self.maskForeground.masksToBounds = true self.maskLayer.addSublayer(self.maskForeground) - self.addSubnode(self.interactiveFileNode) self.addSubnode(self.interactiveVideoNode) self.interactiveVideoNode.requestUpdateLayout = { [weak self] _ in @@ -285,14 +284,9 @@ class ChatMessageInstantVideoBubbleContentNode: ChatMessageBubbleContentNode { return (finalSize, { [weak self] animation, synchronousLoads, applyInfo in if let strongSelf = self { - let firstTime = strongSelf.item == nil strongSelf.item = item strongSelf.isExpanded = isExpanded - if firstTime { - strongSelf.interactiveFileNode.isHidden = true - } - strongSelf.bubbleBackgroundNode?.layer.mask = strongSelf.maskLayer if let bubbleBackdropNode = strongSelf.bubbleBackdropNode, bubbleBackdropNode.hasImage && strongSelf.backdropMaskForeground.superlayer == nil { strongSelf.bubbleBackdropNode?.overrideMask = true diff --git a/submodules/TelegramUI/Sources/ChatMessageInteractiveInstantVideoNode.swift b/submodules/TelegramUI/Sources/ChatMessageInteractiveInstantVideoNode.swift index 554564f166..96aab400b7 100644 --- a/submodules/TelegramUI/Sources/ChatMessageInteractiveInstantVideoNode.swift +++ b/submodules/TelegramUI/Sources/ChatMessageInteractiveInstantVideoNode.swift @@ -1601,7 +1601,9 @@ class ChatMessageInteractiveInstantVideoNode: ASDisplayNode { let duration: Double = 0.2 node.alpha = 1.0 - node.isHidden = false + if node.supernode == nil { + self.supernode?.insertSubnode(node, belowSubnode: self) + } self.alpha = 0.0 self.layer.animateAlpha(from: 1.0, to: 0.0, duration: duration) @@ -1715,7 +1717,7 @@ class ChatMessageInteractiveInstantVideoNode: ASDisplayNode { node.alpha = 0.0 node.layer.animateAlpha(from: 1.0, to: 0.0, duration: duration, completion: { _ in - node.isHidden = true + node.removeFromSupernode() }) node.waveformView?.layer.animateAlpha(from: 1.0, to: 0.0, duration: duration) diff --git a/submodules/TelegramUI/Sources/ChatMessageInteractiveMediaNode.swift b/submodules/TelegramUI/Sources/ChatMessageInteractiveMediaNode.swift index c241ca3da9..3d10f3ae39 100644 --- a/submodules/TelegramUI/Sources/ChatMessageInteractiveMediaNode.swift +++ b/submodules/TelegramUI/Sources/ChatMessageInteractiveMediaNode.swift @@ -1315,7 +1315,7 @@ final class ChatMessageInteractiveMediaNode: ASDisplayNode, GalleryItemTransitio strongSelf.animatedStickerNode = animatedStickerNode let dimensions = updatedAnimatedStickerFile.dimensions ?? PixelDimensions(width: 512, height: 512) let fittedDimensions = dimensions.cgSize.aspectFitted(CGSize(width: 384.0, height: 384.0)) - animatedStickerNode.setup(source: AnimatedStickerResourceSource(account: context.account, resource: updatedAnimatedStickerFile.resource, isVideo: updatedAnimatedStickerFile.isVideo), width: Int(fittedDimensions.width), height: Int(fittedDimensions.height), mode: .cached) + animatedStickerNode.setup(source: AnimatedStickerResourceSource(account: context.account, resource: updatedAnimatedStickerFile.resource, isVideo: updatedAnimatedStickerFile.isVideo), width: Int(fittedDimensions.width), height: Int(fittedDimensions.height), mode: .direct(cachePathPrefix: nil)) strongSelf.pinchContainerNode.contentNode.insertSubnode(animatedStickerNode, aboveSubnode: strongSelf.imageNode) animatedStickerNode.visibility = strongSelf.visibility } @@ -1687,8 +1687,8 @@ final class ChatMessageInteractiveMediaNode: ASDisplayNode, GalleryItemTransitio state = .none badgeContent = nil } else if wideLayout { - if let size = file.size { - let sizeString = "\(dataSizeString(Int(Float(size) * progress), forceDecimal: true, formatting: formatting)) / \(dataSizeString(size, forceDecimal: true, formatting: formatting))" + if let size = file.size, size > 0 && size != .max { + let sizeString = "\(dataSizeString(Int(Float(size) * progress), forceDecimal: true, formatting: formatting)) / \(dataSizeString(size, forceDecimal: true, formatting: formatting))" if let duration = file.duration, !message.flags.contains(.Unsent) { let durationString = file.isAnimated ? gifTitle : stringForDuration(playerDuration > 0 ? playerDuration : duration, position: playerPosition) if isMediaStreamable(message: message, media: file) { @@ -1721,8 +1721,8 @@ final class ChatMessageInteractiveMediaNode: ASDisplayNode, GalleryItemTransitio state = automaticPlayback ? .none : state } } else { - if isMediaStreamable(message: message, media: file), let size = file.size { - let sizeString = "\(dataSizeString(Int(Float(size) * progress), forceDecimal: true, formatting: formatting)) / \(dataSizeString(size, forceDecimal: true, formatting: formatting))" + if isMediaStreamable(message: message, media: file), let fileSize = file.size, fileSize > 0 && fileSize != .max { + let sizeString = "\(dataSizeString(Int64(Float(fileSize) * progress), forceDecimal: true, formatting: formatting)) / \(dataSizeString(fileSize, forceDecimal: true, formatting: formatting))" if message.flags.contains(.Unsent), let duration = file.duration { let durationString = stringForDuration(playerDuration > 0 ? playerDuration : duration, position: playerPosition) @@ -1749,8 +1749,8 @@ final class ChatMessageInteractiveMediaNode: ASDisplayNode, GalleryItemTransitio if let duration = file.duration, !file.isAnimated { let durationString = stringForDuration(playerDuration > 0 ? playerDuration : duration, position: playerPosition) - if automaticPlayback, let size = file.size { - let sizeString = "\(dataSizeString(Int(Float(size) * progress), forceDecimal: true, formatting: formatting)) / \(dataSizeString(size, forceDecimal: true, formatting: formatting))" + if automaticPlayback, let fileSize = file.size, fileSize > 0 && fileSize != .max { + let sizeString = "\(dataSizeString(Int64(Float(fileSize) * progress), forceDecimal: true, formatting: formatting)) / \(dataSizeString(fileSize, forceDecimal: true, formatting: formatting))" mediaDownloadState = .fetching(progress: progress) badgeContent = .mediaDownload(backgroundColor: messageTheme.mediaDateAndStatusFillColor, foregroundColor: messageTheme.mediaDateAndStatusTextColor, duration: durationString, size: active ? sizeString : nil, muted: muted, active: active) } else { @@ -1800,9 +1800,9 @@ final class ChatMessageInteractiveMediaNode: ASDisplayNode, GalleryItemTransitio do { let durationString = file.isAnimated ? gifTitle : stringForDuration(playerDuration > 0 ? playerDuration : (file.duration ?? 0), position: playerPosition) if wideLayout { - if isMediaStreamable(message: message, media: file) { + if isMediaStreamable(message: message, media: file), let fileSize = file.size, fileSize > 0 && fileSize != .max { state = automaticPlayback ? .none : .play(messageTheme.mediaOverlayControlColors.foregroundColor) - badgeContent = .mediaDownload(backgroundColor: messageTheme.mediaDateAndStatusFillColor, foregroundColor: messageTheme.mediaDateAndStatusTextColor, duration: durationString, size: dataSizeString(file.size ?? 0, formatting: formatting), muted: muted, active: true) + badgeContent = .mediaDownload(backgroundColor: messageTheme.mediaDateAndStatusFillColor, foregroundColor: messageTheme.mediaDateAndStatusTextColor, duration: durationString, size: dataSizeString(fileSize, formatting: formatting), muted: muted, active: true) mediaDownloadState = .remote } else { state = automaticPlayback ? .none : state diff --git a/submodules/TelegramUI/Sources/ChatMessageNotificationItem.swift b/submodules/TelegramUI/Sources/ChatMessageNotificationItem.swift index 662a37a751..311ab53b93 100644 --- a/submodules/TelegramUI/Sources/ChatMessageNotificationItem.swift +++ b/submodules/TelegramUI/Sources/ChatMessageNotificationItem.swift @@ -263,19 +263,16 @@ final class ChatMessageNotificationItemNode: NotificationItemNode { } else if item.messages[0].id.peerId.namespace == Namespaces.Peer.CloudGroup { isGroup = true } + title = EnginePeer(peer).displayTitle(strings: item.strings, displayOrder: item.nameDisplayOrder) if isChannel { switch kind { case .image: - title = EnginePeer(peer).displayTitle(strings: item.strings, displayOrder: item.nameDisplayOrder) messageText = presentationData.strings.PUSH_CHANNEL_MESSAGE_PHOTOS_TEXT(Int32(item.messages.count)) case .video: - title = EnginePeer(peer).displayTitle(strings: item.strings, displayOrder: item.nameDisplayOrder) messageText = presentationData.strings.PUSH_CHANNEL_MESSAGE_VIDEOS_TEXT(Int32(item.messages.count)) case .file: - title = EnginePeer(peer).displayTitle(strings: item.strings, displayOrder: item.nameDisplayOrder) messageText = presentationData.strings.PUSH_CHANNEL_MESSAGE_DOCS_TEXT(Int32(item.messages.count)) default: - title = EnginePeer(peer).displayTitle(strings: item.strings, displayOrder: item.nameDisplayOrder) messageText = presentationData.strings.PUSH_CHANNEL_MESSAGES_TEXT(Int32(item.messages.count)) } } else if isGroup, var author = item.messages[0].author { @@ -284,31 +281,23 @@ final class ChatMessageNotificationItemNode: NotificationItemNode { } switch kind { case .image: - title = EnginePeer(peer).displayTitle(strings: item.strings, displayOrder: item.nameDisplayOrder) messageText = presentationData.strings.PUSH_CHAT_MESSAGE_PHOTOS_TEXT(Int32(item.messages.count)).replacingOccurrences(of: "{author}", with: EnginePeer(author).compactDisplayTitle) case .video: - title = EnginePeer(peer).displayTitle(strings: item.strings, displayOrder: item.nameDisplayOrder) messageText = presentationData.strings.PUSH_CHAT_MESSAGE_VIDEOS_TEXT(Int32(item.messages.count)).replacingOccurrences(of: "{author}", with: EnginePeer(author).compactDisplayTitle) case .file: - title = EnginePeer(peer).displayTitle(strings: item.strings, displayOrder: item.nameDisplayOrder) messageText = presentationData.strings.PUSH_CHAT_MESSAGE_DOCS_TEXT(Int32(item.messages.count)).replacingOccurrences(of: "{author}", with: EnginePeer(author).compactDisplayTitle) default: - title = EnginePeer(peer).displayTitle(strings: item.strings, displayOrder: item.nameDisplayOrder) messageText = presentationData.strings.PUSH_CHAT_MESSAGES_TEXT(Int32(item.messages.count)).replacingOccurrences(of: "{author}", with: EnginePeer(author).compactDisplayTitle) } } else { switch kind { case .image: - title = EnginePeer(peer).displayTitle(strings: item.strings, displayOrder: item.nameDisplayOrder) messageText = presentationData.strings.PUSH_MESSAGE_PHOTOS_TEXT(Int32(item.messages.count)) case .video: - title = EnginePeer(peer).displayTitle(strings: item.strings, displayOrder: item.nameDisplayOrder) messageText = presentationData.strings.PUSH_MESSAGE_VIDEOS_TEXT(Int32(item.messages.count)) case .file: - title = EnginePeer(peer).displayTitle(strings: item.strings, displayOrder: item.nameDisplayOrder) messageText = presentationData.strings.PUSH_MESSAGE_FILES_TEXT(Int32(item.messages.count)) default: - title = EnginePeer(peer).displayTitle(strings: item.strings, displayOrder: item.nameDisplayOrder) messageText = presentationData.strings.PUSH_MESSAGES_TEXT(Int32(item.messages.count)) } } @@ -325,6 +314,10 @@ final class ChatMessageNotificationItemNode: NotificationItemNode { title = "📅 \(currentTitle)" } + if let attribute = item.messages.first?.attributes.first(where: { $0 is NotificationInfoMessageAttribute }) as? NotificationInfoMessageAttribute, attribute.flags.contains(.muted), let currentTitle = title { + title = "\(currentTitle) 🔕" + } + let textFont = compact ? Font.regular(15.0) : Font.regular(16.0) let textColor = presentationData.theme.inAppNotification.primaryTextColor var attributedMessageText: NSAttributedString diff --git a/submodules/TelegramUI/Sources/PeerInfo/PeerInfoData.swift b/submodules/TelegramUI/Sources/PeerInfo/PeerInfoData.swift index fe7f59fcae..908b2bb393 100644 --- a/submodules/TelegramUI/Sources/PeerInfo/PeerInfoData.swift +++ b/submodules/TelegramUI/Sources/PeerInfo/PeerInfoData.swift @@ -183,7 +183,8 @@ final class PeerInfoScreenData { let chatPeer: Peer? let cachedData: CachedPeerData? let status: PeerInfoStatusData? - let notificationSettings: TelegramPeerNotificationSettings? + let peerNotificationSettings: TelegramPeerNotificationSettings? + let threadNotificationSettings: TelegramPeerNotificationSettings? let globalNotificationSettings: EngineGlobalNotificationSettings? let isContact: Bool let availablePanes: [PeerInfoPaneKey] @@ -204,7 +205,8 @@ final class PeerInfoScreenData { chatPeer: Peer?, cachedData: CachedPeerData?, status: PeerInfoStatusData?, - notificationSettings: TelegramPeerNotificationSettings?, + peerNotificationSettings: TelegramPeerNotificationSettings?, + threadNotificationSettings: TelegramPeerNotificationSettings?, globalNotificationSettings: EngineGlobalNotificationSettings?, isContact: Bool, availablePanes: [PeerInfoPaneKey], @@ -224,7 +226,8 @@ final class PeerInfoScreenData { self.chatPeer = chatPeer self.cachedData = cachedData self.status = status - self.notificationSettings = notificationSettings + self.peerNotificationSettings = peerNotificationSettings + self.threadNotificationSettings = threadNotificationSettings self.globalNotificationSettings = globalNotificationSettings self.isContact = isContact self.availablePanes = availablePanes @@ -521,7 +524,8 @@ func peerInfoScreenSettingsData(context: AccountContext, peerId: EnginePeer.Id, chatPeer: peer, cachedData: peerView.cachedData, status: nil, - notificationSettings: nil, + peerNotificationSettings: nil, + threadNotificationSettings: nil, globalNotificationSettings: nil, isContact: false, availablePanes: [], @@ -550,7 +554,8 @@ func peerInfoScreenData(context: AccountContext, peerId: PeerId, strings: Presen chatPeer: nil, cachedData: nil, status: nil, - notificationSettings: nil, + peerNotificationSettings: nil, + threadNotificationSettings: nil, globalNotificationSettings: nil, isContact: false, availablePanes: [], @@ -683,7 +688,8 @@ func peerInfoScreenData(context: AccountContext, peerId: PeerId, strings: Presen chatPeer: peerView.peers[peerId], cachedData: peerView.cachedData, status: status, - notificationSettings: peerView.notificationSettings as? TelegramPeerNotificationSettings, + peerNotificationSettings: peerView.notificationSettings as? TelegramPeerNotificationSettings, + threadNotificationSettings: nil, globalNotificationSettings: globalNotificationSettings, isContact: peerView.peerIsContact, availablePanes: availablePanes ?? [], @@ -761,7 +767,8 @@ func peerInfoScreenData(context: AccountContext, peerId: PeerId, strings: Presen chatPeer: peerView.peers[peerId], cachedData: peerView.cachedData, status: status, - notificationSettings: peerView.notificationSettings as? TelegramPeerNotificationSettings, + peerNotificationSettings: peerView.notificationSettings as? TelegramPeerNotificationSettings, + threadNotificationSettings: nil, globalNotificationSettings: globalNotificationSettings, isContact: peerView.peerIsContact, availablePanes: availablePanes ?? [], @@ -948,12 +955,8 @@ func peerInfoScreenData(context: AccountContext, peerId: PeerId, strings: Presen } } - var notificationSettings: TelegramPeerNotificationSettings? - if let threadData = threadData { - notificationSettings = threadData.notificationSettings - } else { - notificationSettings = peerView.notificationSettings as? TelegramPeerNotificationSettings - } + let peerNotificationSettings = peerView.notificationSettings as? TelegramPeerNotificationSettings + let threadNotificationSettings = threadData?.notificationSettings let appConfiguration: AppConfiguration = preferencesView.values[PreferencesKeys.appConfiguration]?.get(AppConfiguration.self) ?? .defaultValue @@ -962,7 +965,8 @@ func peerInfoScreenData(context: AccountContext, peerId: PeerId, strings: Presen chatPeer: peerView.peers[groupId], cachedData: peerView.cachedData, status: status, - notificationSettings: notificationSettings, + peerNotificationSettings: peerNotificationSettings, + threadNotificationSettings: threadNotificationSettings, globalNotificationSettings: globalNotificationSettings, isContact: peerView.peerIsContact, availablePanes: availablePanes ?? [], @@ -1305,3 +1309,42 @@ func peerInfoCanEdit(peer: Peer?, chatLocation: ChatLocation, threadData: Messag } return false } + +func peerInfoIsChatMuted(peer: Peer?, peerNotificationSettings: TelegramPeerNotificationSettings?, threadNotificationSettings: TelegramPeerNotificationSettings?, globalNotificationSettings: EngineGlobalNotificationSettings?) -> Bool { + func isPeerMuted(peer: Peer?, peerNotificationSettings: TelegramPeerNotificationSettings?, globalNotificationSettings: EngineGlobalNotificationSettings?) -> Bool { + var peerIsMuted = false + if let peerNotificationSettings { + if case .muted = peerNotificationSettings.muteState { + peerIsMuted = true + } else if case .default = peerNotificationSettings.muteState, let globalNotificationSettings { + if let peer { + if peer is TelegramUser { + peerIsMuted = !globalNotificationSettings.privateChats.enabled + } else if peer is TelegramGroup { + peerIsMuted = !globalNotificationSettings.groupChats.enabled + } else if let channel = peer as? TelegramChannel { + switch channel.info { + case .group: + peerIsMuted = !globalNotificationSettings.groupChats.enabled + case .broadcast: + peerIsMuted = !globalNotificationSettings.channels.enabled + } + } + } + } + } + return peerIsMuted + } + + var chatIsMuted = false + if let threadNotificationSettings { + if case .muted = threadNotificationSettings.muteState { + chatIsMuted = true + } else if let peerNotificationSettings { + chatIsMuted = isPeerMuted(peer: peer, peerNotificationSettings: peerNotificationSettings, globalNotificationSettings: globalNotificationSettings) + } + } else { + chatIsMuted = isPeerMuted(peer: peer, peerNotificationSettings: peerNotificationSettings, globalNotificationSettings: globalNotificationSettings) + } + return chatIsMuted +} diff --git a/submodules/TelegramUI/Sources/PeerInfo/PeerInfoHeaderNode.swift b/submodules/TelegramUI/Sources/PeerInfo/PeerInfoHeaderNode.swift index b5f4eb2dc5..ac0a55c722 100644 --- a/submodules/TelegramUI/Sources/PeerInfo/PeerInfoHeaderNode.swift +++ b/submodules/TelegramUI/Sources/PeerInfo/PeerInfoHeaderNode.swift @@ -2542,7 +2542,7 @@ final class PeerInfoHeaderNode: ASDisplayNode { private var currentCredibilityIcon: CredibilityIcon? private var currentPanelStatusData: PeerInfoStatusData? - func update(width: CGFloat, containerHeight: CGFloat, containerInset: CGFloat, statusBarHeight: CGFloat, navigationHeight: CGFloat, isModalOverlay: Bool, isMediaOnly: Bool, contentOffset: CGFloat, paneContainerY: CGFloat, presentationData: PresentationData, peer: Peer?, cachedData: CachedPeerData?, threadData: MessageHistoryThreadData?, notificationSettings: TelegramPeerNotificationSettings?, globalNotificationSettings: EngineGlobalNotificationSettings?, statusData: PeerInfoStatusData?, panelStatusData: (PeerInfoStatusData?, PeerInfoStatusData?, CGFloat?), isSecretChat: Bool, isContact: Bool, isSettings: Bool, state: PeerInfoState, metrics: LayoutMetrics, transition: ContainedViewLayoutTransition, additive: Bool) -> CGFloat { + func update(width: CGFloat, containerHeight: CGFloat, containerInset: CGFloat, statusBarHeight: CGFloat, navigationHeight: CGFloat, isModalOverlay: Bool, isMediaOnly: Bool, contentOffset: CGFloat, paneContainerY: CGFloat, presentationData: PresentationData, peer: Peer?, cachedData: CachedPeerData?, threadData: MessageHistoryThreadData?, peerNotificationSettings: TelegramPeerNotificationSettings?, threadNotificationSettings: TelegramPeerNotificationSettings?, globalNotificationSettings: EngineGlobalNotificationSettings?, statusData: PeerInfoStatusData?, panelStatusData: (PeerInfoStatusData?, PeerInfoStatusData?, CGFloat?), isSecretChat: Bool, isContact: Bool, isSettings: Bool, state: PeerInfoState, metrics: LayoutMetrics, deviceMetrics: DeviceMetrics, transition: ContainedViewLayoutTransition, additive: Bool) -> CGFloat { self.state = state self.peer = peer self.threadData = threadData @@ -3456,28 +3456,8 @@ final class PeerInfoHeaderNode: ASDisplayNode { } buttonIcon = .voiceChat case .mute: - var peerIsMuted = false - if let notificationSettings { - if case .muted = notificationSettings.muteState { - peerIsMuted = true - } else if case .default = notificationSettings.muteState, let globalNotificationSettings { - if let peer { - if peer is TelegramUser { - peerIsMuted = !globalNotificationSettings.privateChats.enabled - } else if peer is TelegramGroup { - peerIsMuted = !globalNotificationSettings.groupChats.enabled - } else if let channel = peer as? TelegramChannel { - switch channel.info { - case .group: - peerIsMuted = !globalNotificationSettings.groupChats.enabled - case .broadcast: - peerIsMuted = !globalNotificationSettings.channels.enabled - } - } - } - } - } - if peerIsMuted { + let chatIsMuted = peerInfoIsChatMuted(peer: peer, peerNotificationSettings: peerNotificationSettings, threadNotificationSettings: threadNotificationSettings, globalNotificationSettings: globalNotificationSettings) + if chatIsMuted { buttonText = presentationData.strings.PeerInfo_ButtonUnmute buttonIcon = .unmute } else { diff --git a/submodules/TelegramUI/Sources/PeerInfo/PeerInfoScreen.swift b/submodules/TelegramUI/Sources/PeerInfo/PeerInfoScreen.swift index 6e48b0f56f..a4d7f460d5 100644 --- a/submodules/TelegramUI/Sources/PeerInfo/PeerInfoScreen.swift +++ b/submodules/TelegramUI/Sources/PeerInfo/PeerInfoScreen.swift @@ -3053,7 +3053,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate let controller = ForumCreateTopicScreen(context: strongSelf.context, peerId: strongSelf.peerId, mode: .edit(threadId: threadId, threadInfo: threadData.info, isHidden: threadData.isHidden)) controller.navigationPresentation = .modal let context = strongSelf.context - controller.completion = { [weak controller] title, fileId, isHidden in + controller.completion = { [weak controller] title, fileId, _, isHidden in let _ = (context.engine.peers.editForumChannelTopic(id: peerId, threadId: threadId, title: title, iconFileId: fileId) |> deliverOnMainQueue).start(completed: { controller?.dismiss() @@ -4258,30 +4258,9 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate self.requestCall(isVideo: false, gesture: gesture) case .mute: var displayCustomNotificationSettings = false - - var peerIsMuted = false - if let notificationSettings = self.data?.notificationSettings { - if case .muted = notificationSettings.muteState { - peerIsMuted = true - } else if case .default = notificationSettings.muteState, let globalNotificationSettings = self.data?.globalNotificationSettings { - if let peer = self.data?.peer { - if peer is TelegramUser { - peerIsMuted = !globalNotificationSettings.privateChats.enabled - } else if peer is TelegramGroup { - peerIsMuted = !globalNotificationSettings.groupChats.enabled - } else if let channel = peer as? TelegramChannel { - switch channel.info { - case .group: - peerIsMuted = !globalNotificationSettings.groupChats.enabled - case .broadcast: - peerIsMuted = !globalNotificationSettings.channels.enabled - } - } - } - } - } - - if peerIsMuted { + + let chatIsMuted = peerInfoIsChatMuted(peer: self.data?.peer, peerNotificationSettings: self.data?.peerNotificationSettings, threadNotificationSettings: self.data?.threadNotificationSettings, globalNotificationSettings: self.data?.globalNotificationSettings) + if chatIsMuted { } else { displayCustomNotificationSettings = true } @@ -4358,7 +4337,8 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate items.append(.separator) var isSoundEnabled = true - if let notificationSettings = self.data?.notificationSettings { + let notificationSettings = self.data?.threadNotificationSettings ?? self.data?.peerNotificationSettings + if let notificationSettings { switch notificationSettings.messageSound { case .none: isSoundEnabled = false @@ -4367,53 +4347,34 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate } } - if let notificationSettings = self.data?.notificationSettings, case .muted = notificationSettings.muteState { - items.append(.action(ContextMenuActionItem(text: self.presentationData.strings.PeerInfo_ButtonUnmute, icon: { theme in - return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/SoundOn"), color: theme.contextMenu.primaryColor) - }, action: { [weak self] _, f in - f(.default) - - guard let self else { - return - } - - let _ = self.context.engine.peers.updatePeerMuteSetting(peerId: peerId, threadId: self.chatLocation.threadId, muteInterval: nil).start() - - let iconColor: UIColor = .white - self.controller?.present(UndoOverlayController(presentationData: self.presentationData, content: .universal(animation: "anim_profileunmute", scale: 0.075, colors: [ - "Middle.Group 1.Fill 1": iconColor, - "Top.Group 1.Fill 1": iconColor, - "Bottom.Group 1.Fill 1": iconColor, - "EXAMPLE.Group 1.Fill 1": iconColor, - "Line.Group 1.Stroke 1": iconColor - ], title: nil, text: self.presentationData.strings.PeerInfo_TooltipUnmuted, customUndoText: nil, timeout: nil), elevatedLayout: false, animateInAsReplacement: true, action: { _ in return false }), in: .current) - }))) - } else if !isSoundEnabled { - items.append(.action(ContextMenuActionItem(text: self.presentationData.strings.PeerInfo_EnableSound, icon: { theme in - return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/SoundOn"), color: theme.contextMenu.primaryColor) - }, action: { [weak self] _, f in - f(.default) - - guard let strongSelf = self else { - return - } - let _ = strongSelf.context.engine.peers.updatePeerNotificationSoundInteractive(peerId: peerId, threadId: strongSelf.chatLocation.threadId, sound: .default).start() - - strongSelf.controller?.present(UndoOverlayController(presentationData: strongSelf.presentationData, content: .universal(animation: "anim_sound_on", scale: 0.056, colors: [:], title: nil, text: strongSelf.presentationData.strings.PeerInfo_TooltipSoundEnabled, customUndoText: nil, timeout: nil), elevatedLayout: false, animateInAsReplacement: true, action: { _ in return false }), in: .current) - }))) - } else { - items.append(.action(ContextMenuActionItem(text: self.presentationData.strings.PeerInfo_DisableSound, icon: { theme in - return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/SoundOff"), color: theme.contextMenu.primaryColor) - }, action: { [weak self] _, f in - f(.default) - - guard let strongSelf = self else { - return - } - let _ = strongSelf.context.engine.peers.updatePeerNotificationSoundInteractive(peerId: peerId, threadId: strongSelf.chatLocation.threadId, sound: .none).start() - - strongSelf.controller?.present(UndoOverlayController(presentationData: strongSelf.presentationData, content: .universal(animation: "anim_sound_off", scale: 0.056, colors: [:], title: nil, text: strongSelf.presentationData.strings.PeerInfo_TooltipSoundDisabled, customUndoText: nil, timeout: nil), elevatedLayout: false, animateInAsReplacement: true, action: { _ in return false }), in: .current) - }))) + if !chatIsMuted { + if !isSoundEnabled { + items.append(.action(ContextMenuActionItem(text: self.presentationData.strings.PeerInfo_EnableSound, icon: { theme in + return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/SoundOn"), color: theme.contextMenu.primaryColor) + }, action: { [weak self] _, f in + f(.default) + + guard let strongSelf = self else { + return + } + let _ = strongSelf.context.engine.peers.updatePeerNotificationSoundInteractive(peerId: peerId, threadId: strongSelf.chatLocation.threadId, sound: .default).start() + + strongSelf.controller?.present(UndoOverlayController(presentationData: strongSelf.presentationData, content: .universal(animation: "anim_sound_on", scale: 0.056, colors: [:], title: nil, text: strongSelf.presentationData.strings.PeerInfo_TooltipSoundEnabled, customUndoText: nil, timeout: nil), elevatedLayout: false, animateInAsReplacement: true, action: { _ in return false }), in: .current) + }))) + } else { + items.append(.action(ContextMenuActionItem(text: self.presentationData.strings.PeerInfo_DisableSound, icon: { theme in + return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/SoundOff"), color: theme.contextMenu.primaryColor) + }, action: { [weak self] _, f in + f(.default) + + guard let strongSelf = self else { + return + } + let _ = strongSelf.context.engine.peers.updatePeerNotificationSoundInteractive(peerId: peerId, threadId: strongSelf.chatLocation.threadId, sound: .none).start() + + strongSelf.controller?.present(UndoOverlayController(presentationData: strongSelf.presentationData, content: .universal(animation: "anim_sound_off", scale: 0.056, colors: [:], title: nil, text: strongSelf.presentationData.strings.PeerInfo_TooltipSoundDisabled, customUndoText: nil, timeout: nil), elevatedLayout: false, animateInAsReplacement: true, action: { _ in return false }), in: .current) + }))) + } } let context = self.context @@ -4503,26 +4464,49 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate }) }))) - items.append(.action(ContextMenuActionItem(text: self.presentationData.strings.PeerInfo_MuteForever, textColor: .destructive, icon: { theme in - return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Muted"), color: theme.contextMenu.destructiveColor) - }, action: { [weak self] _, f in - f(.default) - - guard let strongSelf = self else { - return - } - - let _ = strongSelf.context.engine.peers.updatePeerMuteSetting(peerId: peerId, threadId: strongSelf.chatLocation.threadId, muteInterval: Int32.max).start() - - let iconColor: UIColor = .white - strongSelf.controller?.present(UndoOverlayController(presentationData: strongSelf.presentationData, content: .universal(animation: "anim_profilemute", scale: 0.075, colors: [ - "Middle.Group 1.Fill 1": iconColor, - "Top.Group 1.Fill 1": iconColor, - "Bottom.Group 1.Fill 1": iconColor, - "EXAMPLE.Group 1.Fill 1": iconColor, - "Line.Group 1.Stroke 1": iconColor - ], title: nil, text: strongSelf.presentationData.strings.PeerInfo_TooltipMutedForever, customUndoText: nil, timeout: nil), elevatedLayout: false, animateInAsReplacement: true, action: { _ in return false }), in: .current) - }))) + if chatIsMuted { + items.append(.action(ContextMenuActionItem(text: self.presentationData.strings.PeerInfo_ButtonUnmute, icon: { theme in + return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Unmute"), color: theme.contextMenu.primaryColor) + }, action: { [weak self] _, f in + f(.default) + + guard let self else { + return + } + + let _ = self.context.engine.peers.updatePeerMuteSetting(peerId: peerId, threadId: self.chatLocation.threadId, muteInterval: 0).start() + + let iconColor: UIColor = .white + self.controller?.present(UndoOverlayController(presentationData: self.presentationData, content: .universal(animation: "anim_profileunmute", scale: 0.075, colors: [ + "Middle.Group 1.Fill 1": iconColor, + "Top.Group 1.Fill 1": iconColor, + "Bottom.Group 1.Fill 1": iconColor, + "EXAMPLE.Group 1.Fill 1": iconColor, + "Line.Group 1.Stroke 1": iconColor + ], title: nil, text: self.presentationData.strings.PeerInfo_TooltipUnmuted, customUndoText: nil, timeout: nil), elevatedLayout: false, animateInAsReplacement: true, action: { _ in return false }), in: .current) + }))) + } else { + items.append(.action(ContextMenuActionItem(text: self.presentationData.strings.PeerInfo_MuteForever, textColor: .destructive, icon: { theme in + return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Muted"), color: theme.contextMenu.destructiveColor) + }, action: { [weak self] _, f in + f(.default) + + guard let strongSelf = self else { + return + } + + let _ = strongSelf.context.engine.peers.updatePeerMuteSetting(peerId: peerId, threadId: strongSelf.chatLocation.threadId, muteInterval: Int32.max).start() + + let iconColor: UIColor = .white + strongSelf.controller?.present(UndoOverlayController(presentationData: strongSelf.presentationData, content: .universal(animation: "anim_profilemute", scale: 0.075, colors: [ + "Middle.Group 1.Fill 1": iconColor, + "Top.Group 1.Fill 1": iconColor, + "Bottom.Group 1.Fill 1": iconColor, + "EXAMPLE.Group 1.Fill 1": iconColor, + "Line.Group 1.Stroke 1": iconColor + ], title: nil, text: strongSelf.presentationData.strings.PeerInfo_TooltipMutedForever, customUndoText: nil, timeout: nil), elevatedLayout: false, animateInAsReplacement: true, action: { _ in return false }), in: .current) + }))) + } var tip: ContextController.Tip? tip = nil @@ -8687,7 +8671,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate } let headerInset = sectionInset - var headerHeight = self.headerNode.update(width: layout.size.width, containerHeight: layout.size.height, containerInset: headerInset, statusBarHeight: layout.statusBarHeight ?? 0.0, navigationHeight: navigationHeight, isModalOverlay: layout.isModalOverlay, isMediaOnly: self.isMediaOnly, contentOffset: self.isMediaOnly ? 212.0 : self.scrollNode.view.contentOffset.y, paneContainerY: self.paneContainerNode.frame.minY, presentationData: self.presentationData, peer: self.data?.peer, cachedData: self.data?.cachedData, threadData: self.data?.threadData, notificationSettings: self.data?.notificationSettings, globalNotificationSettings: self.data?.globalNotificationSettings, statusData: self.data?.status, panelStatusData: self.customStatusData, isSecretChat: self.peerId.namespace == Namespaces.Peer.SecretChat, isContact: self.data?.isContact ?? false, isSettings: self.isSettings, state: self.state, metrics: layout.metrics, transition: transition, additive: additive) + var headerHeight = self.headerNode.update(width: layout.size.width, containerHeight: layout.size.height, containerInset: headerInset, statusBarHeight: layout.statusBarHeight ?? 0.0, navigationHeight: navigationHeight, isModalOverlay: layout.isModalOverlay, isMediaOnly: self.isMediaOnly, contentOffset: self.isMediaOnly ? 212.0 : self.scrollNode.view.contentOffset.y, paneContainerY: self.paneContainerNode.frame.minY, presentationData: self.presentationData, peer: self.data?.peer, cachedData: self.data?.cachedData, threadData: self.data?.threadData, peerNotificationSettings: self.data?.peerNotificationSettings, threadNotificationSettings: self.data?.threadNotificationSettings, globalNotificationSettings: self.data?.globalNotificationSettings, statusData: self.data?.status, panelStatusData: self.customStatusData, isSecretChat: self.peerId.namespace == Namespaces.Peer.SecretChat, isContact: self.data?.isContact ?? false, isSettings: self.isSettings, state: self.state, metrics: layout.metrics, deviceMetrics: layout.deviceMetrics, transition: transition, additive: additive) if !self.isSettings && !self.state.isEditing { headerHeight += 71.0 } @@ -9052,7 +9036,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate } let headerInset = sectionInset - let _ = self.headerNode.update(width: layout.size.width, containerHeight: layout.size.height, containerInset: headerInset, statusBarHeight: layout.statusBarHeight ?? 0.0, navigationHeight: navigationHeight, isModalOverlay: layout.isModalOverlay, isMediaOnly: self.isMediaOnly, contentOffset: self.isMediaOnly ? 212.0 : offsetY, paneContainerY: self.paneContainerNode.frame.minY, presentationData: self.presentationData, peer: self.data?.peer, cachedData: self.data?.cachedData, threadData: self.data?.threadData, notificationSettings: self.data?.notificationSettings, globalNotificationSettings: self.data?.globalNotificationSettings, statusData: self.data?.status, panelStatusData: self.customStatusData, isSecretChat: self.peerId.namespace == Namespaces.Peer.SecretChat, isContact: self.data?.isContact ?? false, isSettings: self.isSettings, state: self.state, metrics: layout.metrics, transition: transition, additive: additive) + let _ = self.headerNode.update(width: layout.size.width, containerHeight: layout.size.height, containerInset: headerInset, statusBarHeight: layout.statusBarHeight ?? 0.0, navigationHeight: navigationHeight, isModalOverlay: layout.isModalOverlay, isMediaOnly: self.isMediaOnly, contentOffset: self.isMediaOnly ? 212.0 : offsetY, paneContainerY: self.paneContainerNode.frame.minY, presentationData: self.presentationData, peer: self.data?.peer, cachedData: self.data?.cachedData, threadData: self.data?.threadData, peerNotificationSettings: self.data?.peerNotificationSettings, threadNotificationSettings: self.data?.threadNotificationSettings, globalNotificationSettings: self.data?.globalNotificationSettings, statusData: self.data?.status, panelStatusData: self.customStatusData, isSecretChat: self.peerId.namespace == Namespaces.Peer.SecretChat, isContact: self.data?.isContact ?? false, isSettings: self.isSettings, state: self.state, metrics: layout.metrics, deviceMetrics: layout.deviceMetrics, transition: transition, additive: additive) } let paneAreaExpansionDistance: CGFloat = 32.0 @@ -10261,7 +10245,7 @@ private final class PeerInfoNavigationTransitionNode: ASDisplayNode, CustomNavig } let headerInset = sectionInset - topHeight = self.headerNode.update(width: layout.size.width, containerHeight: layout.size.height, containerInset: headerInset, statusBarHeight: layout.statusBarHeight ?? 0.0, navigationHeight: topNavigationBar.bounds.height, isModalOverlay: layout.isModalOverlay, isMediaOnly: false, contentOffset: 0.0, paneContainerY: 0.0, presentationData: self.presentationData, peer: self.screenNode.data?.peer, cachedData: self.screenNode.data?.cachedData, threadData: self.screenNode.data?.threadData, notificationSettings: self.screenNode.data?.notificationSettings, globalNotificationSettings: self.screenNode.data?.globalNotificationSettings, statusData: self.screenNode.data?.status, panelStatusData: (nil, nil, nil), isSecretChat: self.screenNode.peerId.namespace == Namespaces.Peer.SecretChat, isContact: self.screenNode.data?.isContact ?? false, isSettings: self.screenNode.isSettings, state: self.screenNode.state, metrics: layout.metrics, transition: transition, additive: false) + topHeight = self.headerNode.update(width: layout.size.width, containerHeight: layout.size.height, containerInset: headerInset, statusBarHeight: layout.statusBarHeight ?? 0.0, navigationHeight: topNavigationBar.bounds.height, isModalOverlay: layout.isModalOverlay, isMediaOnly: false, contentOffset: 0.0, paneContainerY: 0.0, presentationData: self.presentationData, peer: self.screenNode.data?.peer, cachedData: self.screenNode.data?.cachedData, threadData: self.screenNode.data?.threadData, peerNotificationSettings: self.screenNode.data?.peerNotificationSettings, threadNotificationSettings: self.screenNode.data?.threadNotificationSettings, globalNotificationSettings: self.screenNode.data?.globalNotificationSettings, statusData: self.screenNode.data?.status, panelStatusData: (nil, nil, nil), isSecretChat: self.screenNode.peerId.namespace == Namespaces.Peer.SecretChat, isContact: self.screenNode.data?.isContact ?? false, isSettings: self.screenNode.isSettings, state: self.screenNode.state, metrics: layout.metrics, deviceMetrics: layout.deviceMetrics, transition: transition, additive: false) } let titleScale = (fraction * previousTitleNode.view.bounds.height + (1.0 - fraction) * self.headerNode.titleNodeRawContainer.bounds.height) / previousTitleNode.view.bounds.height diff --git a/submodules/TelegramUI/Sources/PeerMessagesMediaPlaylist.swift b/submodules/TelegramUI/Sources/PeerMessagesMediaPlaylist.swift index 8cc15ce477..ae8af31130 100644 --- a/submodules/TelegramUI/Sources/PeerMessagesMediaPlaylist.swift +++ b/submodules/TelegramUI/Sources/PeerMessagesMediaPlaylist.swift @@ -60,7 +60,7 @@ final class MessageMediaPlaylistItem: SharedMediaPlaylistItem { return MessageMediaPlaylistItemStableId(stableId: message.stableId) } - var playbackData: SharedMediaPlaybackData? { + lazy var playbackData: SharedMediaPlaybackData? = { if let file = extractFileMedia(self.message) { let fileReference = FileMediaReference.message(message: MessageReference(self.message), media: file) let source = SharedMediaPlaybackDataSource.telegramFile(reference: fileReference, isCopyProtected: self.message.isCopyProtected()) @@ -93,9 +93,9 @@ final class MessageMediaPlaylistItem: SharedMediaPlaylistItem { } } return nil - } + }() - var displayData: SharedMediaPlaybackDisplayData? { + lazy var displayData: SharedMediaPlaybackDisplayData? = { if let file = extractFileMedia(self.message) { let text = self.message.text var entities: [MessageTextEntity] = [] @@ -108,40 +108,42 @@ final class MessageMediaPlaylistItem: SharedMediaPlaylistItem { for attribute in file.attributes { switch attribute { - case let .Audio(isVoice, duration, title, performer, _): - if isVoice { - return SharedMediaPlaybackDisplayData.voice(author: self.message.effectiveAuthor, peer: self.message.peers[self.message.id.peerId]) - } else { - var updatedTitle = title - let updatedPerformer = performer - if (title ?? "").isEmpty && (performer ?? "").isEmpty { - updatedTitle = file.fileName ?? "" - } - - let albumArt: SharedMediaPlaybackAlbumArt? - if file.fileName?.lowercased().hasSuffix(".ogg") == true { - albumArt = nil - } else { - albumArt = SharedMediaPlaybackAlbumArt(thumbnailResource: ExternalMusicAlbumArtResource(file: .message(message: MessageReference(self.message), media: file), title: updatedTitle ?? "", performer: updatedPerformer ?? "", isThumbnail: true), fullSizeResource: ExternalMusicAlbumArtResource(file: .message(message: MessageReference(self.message), media: file), title: updatedTitle ?? "", performer: updatedPerformer ?? "", isThumbnail: false)) - } - - return SharedMediaPlaybackDisplayData.music(title: updatedTitle, performer: updatedPerformer, albumArt: albumArt, long: CGFloat(duration) > 10.0 * 60.0, caption: caption) + case let .Audio(isVoice, duration, title, performer, _): + let displayData: SharedMediaPlaybackDisplayData + if isVoice { + displayData = SharedMediaPlaybackDisplayData.voice(author: self.message.effectiveAuthor, peer: self.message.peers[self.message.id.peerId]) + } else { + var updatedTitle = title + let updatedPerformer = performer + if (title ?? "").isEmpty && (performer ?? "").isEmpty { + updatedTitle = file.fileName ?? "" } - case let .Video(_, _, flags): - if flags.contains(.instantRoundVideo) { - return SharedMediaPlaybackDisplayData.instantVideo(author: self.message.effectiveAuthor, peer: self.message.peers[self.message.id.peerId], timestamp: self.message.timestamp) + + let albumArt: SharedMediaPlaybackAlbumArt? + if file.fileName?.lowercased().hasSuffix(".ogg") == true { + albumArt = nil } else { - return nil + albumArt = SharedMediaPlaybackAlbumArt(thumbnailResource: ExternalMusicAlbumArtResource(file: .message(message: MessageReference(self.message), media: file), title: updatedTitle ?? "", performer: updatedPerformer ?? "", isThumbnail: true), fullSizeResource: ExternalMusicAlbumArtResource(file: .message(message: MessageReference(self.message), media: file), title: updatedTitle ?? "", performer: updatedPerformer ?? "", isThumbnail: false)) } - default: - break + + displayData = SharedMediaPlaybackDisplayData.music(title: updatedTitle, performer: updatedPerformer, albumArt: albumArt, long: CGFloat(duration) > 10.0 * 60.0, caption: caption) + } + return displayData + case let .Video(_, _, flags): + if flags.contains(.instantRoundVideo) { + return SharedMediaPlaybackDisplayData.instantVideo(author: self.message.effectiveAuthor, peer: self.message.peers[self.message.id.peerId], timestamp: self.message.timestamp) + } else { + return nil + } + default: + break } } return SharedMediaPlaybackDisplayData.music(title: file.fileName ?? "", performer: self.message.effectiveAuthor?.debugDisplayTitle ?? "", albumArt: nil, long: false, caption: caption) } return nil - } + }() } private enum NavigatedMessageFromViewPosition { diff --git a/submodules/TelegramUI/Sources/PrefetchManager.swift b/submodules/TelegramUI/Sources/PrefetchManager.swift index 00ef7a3755..60b69c7f6e 100644 --- a/submodules/TelegramUI/Sources/PrefetchManager.swift +++ b/submodules/TelegramUI/Sources/PrefetchManager.swift @@ -249,9 +249,11 @@ private final class PrefetchManagerInnerImpl { self.preloadGreetingStickerDisposable.set((self.preloadedGreetingStickerPromise.get() |> mapToSignal { sticker -> Signal in if let sticker = sticker { - let _ = freeMediaFileInteractiveFetched(account: account, userLocation: .other, fileReference: .standalone(media: sticker)).start() - return chatMessageAnimationData(mediaBox: account.postbox.mediaBox, resource: sticker.resource, fitzModifier: nil, isVideo: sticker.isVideoSticker, width: 384, height: 384, synchronousLoad: false) - |> mapToSignal { _ -> Signal in + return freeMediaFileInteractiveFetched(account: account, userLocation: .other, fileReference: .standalone(media: sticker)) + |> map { _ -> Void in + return Void() + } + |> `catch` { _ -> Signal in return .complete() } } else { diff --git a/submodules/WebSearchUI/Sources/WebSearchController.swift b/submodules/WebSearchUI/Sources/WebSearchController.swift index 062f6272c9..d161627afc 100644 --- a/submodules/WebSearchUI/Sources/WebSearchController.swift +++ b/submodules/WebSearchUI/Sources/WebSearchController.swift @@ -295,7 +295,7 @@ public final class WebSearchController: ViewController { let throttledSearchQuery = self.searchQueryPromise.get() |> mapToSignal { query -> Signal in if !query.isEmpty { - return (.complete() |> delay(0.6, queue: Queue.mainQueue())) + return (.complete() |> delay(1.0, queue: Queue.mainQueue())) |> then(.single(query)) } else { return .single(query) diff --git a/submodules/rlottie/LottieInstance.mm b/submodules/rlottie/LottieInstance.mm index 61ac431c8f..f9da05da3e 100755 --- a/submodules/rlottie/LottieInstance.mm +++ b/submodules/rlottie/LottieInstance.mm @@ -61,7 +61,7 @@ _dimensions = CGSizeMake(width, height); - if ((_frameRate > 60) || _animation->duration() > 7.0) { + if ((_frameRate > 60) || _animation->duration() > 9.0) { return nil; } }