diff --git a/Telegram/Telegram-iOS/en.lproj/Localizable.strings b/Telegram/Telegram-iOS/en.lproj/Localizable.strings index 55f1dca8ec..4e659aa8fe 100644 --- a/Telegram/Telegram-iOS/en.lproj/Localizable.strings +++ b/Telegram/Telegram-iOS/en.lproj/Localizable.strings @@ -5768,7 +5768,7 @@ Sorry for the inconvenience."; "VoiceChat.EndConfirmationEnd" = "End"; "VoiceChat.InviteMemberToGroupFirstText" = "%1$@ isn't a member of \"%2$@\" yet. Add them to the group?"; -"VoiceChat.InviteMemberToChannelFirstText" = "%1$@ isn't a member of \"%2$@\" yet. Add them to the channel?"; +"VoiceChat.InviteMemberToChannelFirstText" = "%1$@ isn't a subscriber of \"%2$@\" yet. Add them to the channel?"; "VoiceChat.InviteMemberToGroupFirstAdd" = "Add"; "VoiceChat.CreateNewVoiceChatText" = "Voice chat ended. Start a new one?"; @@ -6263,6 +6263,6 @@ Sorry for the inconvenience."; "VoiceChat.CancelSpeakRequest" = "Cancel Request to Speak"; "VoiceChat.RemovePeerConfirmationChannel" = "Are you sure you want to remove %@ from the channel?"; -"VoiceChat.RemoveAndBanPeerConfirmation" = "“Do you want to remove %1$@ from the voice chat and ban them in %2$@?"; +"VoiceChat.RemoveAndBanPeerConfirmation" = "Do you want to remove %1$@ from the voice chat and ban them in %2$@?"; "Notification.VoiceChatStartedChannel" = "Voice chat started"; diff --git a/submodules/InstantPageUI/Sources/InstantPageMediaPlaylist.swift b/submodules/InstantPageUI/Sources/InstantPageMediaPlaylist.swift index 2a69e011ca..2d14f42be4 100644 --- a/submodules/InstantPageUI/Sources/InstantPageMediaPlaylist.swift +++ b/submodules/InstantPageUI/Sources/InstantPageMediaPlaylist.swift @@ -87,7 +87,15 @@ final class InstantPageMediaPlaylistItem: SharedMediaPlaylistItem { if (title ?? "").isEmpty && (performer ?? "").isEmpty { updatedTitle = file.fileName ?? "" } - return SharedMediaPlaybackDisplayData.music(title: updatedTitle, performer: updatedPerformer, albumArt: SharedMediaPlaybackAlbumArt(thumbnailResource: ExternalMusicAlbumArtResource(title: title ?? "", performer: performer ?? "", isThumbnail: true), fullSizeResource: ExternalMusicAlbumArtResource(title: updatedTitle ?? "", performer: updatedPerformer ?? "", isThumbnail: false)), long: false) + + let albumArt: SharedMediaPlaybackAlbumArt? + if file.fileName?.lowercased().hasPrefix(".ogg") == true { + albumArt = nil + } else { + albumArt = SharedMediaPlaybackAlbumArt(thumbnailResource: ExternalMusicAlbumArtResource(title: updatedTitle ?? "", performer: updatedPerformer ?? "", isThumbnail: true), fullSizeResource: ExternalMusicAlbumArtResource(title: updatedTitle ?? "", performer: updatedPerformer ?? "", isThumbnail: false)) + } + + return SharedMediaPlaybackDisplayData.music(title: updatedTitle, performer: updatedPerformer, albumArt: albumArt, long: false) } case let .Video(_, _, flags): if flags.contains(.instantRoundVideo) { diff --git a/submodules/ListMessageItem/Sources/ListMessageFileItemNode.swift b/submodules/ListMessageItem/Sources/ListMessageFileItemNode.swift index 6e7db4b4e1..68edc623f7 100644 --- a/submodules/ListMessageItem/Sources/ListMessageFileItemNode.swift +++ b/submodules/ListMessageItem/Sources/ListMessageFileItemNode.swift @@ -439,7 +439,11 @@ public final class ListMessageFileItemNode: ListMessageNode { descriptionText = NSAttributedString(string: descriptionString, font: descriptionFont, textColor: item.presentationData.theme.theme.list.itemSecondaryTextColor) if !voice { - iconImage = .albumArt(file, SharedMediaPlaybackAlbumArt(thumbnailResource: ExternalMusicAlbumArtResource(title: title ?? "", performer: performer ?? "", isThumbnail: true), fullSizeResource: ExternalMusicAlbumArtResource(title: title ?? "", performer: performer ?? "", isThumbnail: false))) + if file.fileName?.lowercased().hasPrefix(".ogg") == true { + iconImage = .none + } else { + iconImage = .albumArt(file, SharedMediaPlaybackAlbumArt(thumbnailResource: ExternalMusicAlbumArtResource(title: title ?? "", performer: performer ?? "", isThumbnail: true), fullSizeResource: ExternalMusicAlbumArtResource(title: title ?? "", performer: performer ?? "", isThumbnail: false))) + } } else { titleText = NSAttributedString(string: " ", font: audioTitleFont, textColor: item.presentationData.theme.theme.list.itemPrimaryTextColor) descriptionText = NSAttributedString(string: item.message.author?.displayTitle(strings: item.presentationData.strings, displayOrder: .firstLast) ?? " ", font: descriptionFont, textColor: item.presentationData.theme.theme.list.itemSecondaryTextColor) diff --git a/submodules/PeerInfoUI/Sources/ChannelAdminController.swift b/submodules/PeerInfoUI/Sources/ChannelAdminController.swift index fe07260469..aa6e27d728 100644 --- a/submodules/PeerInfoUI/Sources/ChannelAdminController.swift +++ b/submodules/PeerInfoUI/Sources/ChannelAdminController.swift @@ -604,6 +604,7 @@ private func channelAdminControllerEntries(presentationData: PresentationData, s .canEditMessages, .canDeleteMessages, .canInviteUsers, + .canManageCalls, .canAddAdmins ] case .group: diff --git a/submodules/PeerInfoUI/Sources/ChannelMembersSearchContainerNode.swift b/submodules/PeerInfoUI/Sources/ChannelMembersSearchContainerNode.swift index 022edf943d..9e43448063 100644 --- a/submodules/PeerInfoUI/Sources/ChannelMembersSearchContainerNode.swift +++ b/submodules/PeerInfoUI/Sources/ChannelMembersSearchContainerNode.swift @@ -202,6 +202,8 @@ struct ChannelMembersSearchContainerTransition { let insertions: [ListViewInsertItem] let updates: [ListViewUpdateItem] let isSearching: Bool + let isEmpty: Bool + let query: String } private enum GroupMemberCategory { @@ -272,14 +274,14 @@ public final class GroupMembersSearchContext { } } -private func channelMembersSearchContainerPreparedRecentTransition(from fromEntries: [ChannelMembersSearchEntry], to toEntries: [ChannelMembersSearchEntry], isSearching: Bool, context: AccountContext, presentationData: PresentationData, nameSortOrder: PresentationPersonNameOrder, nameDisplayOrder: PresentationPersonNameOrder, interaction: ChannelMembersSearchContainerInteraction) -> ChannelMembersSearchContainerTransition { +private func channelMembersSearchContainerPreparedRecentTransition(from fromEntries: [ChannelMembersSearchEntry], to toEntries: [ChannelMembersSearchEntry], isSearching: Bool, isEmpty: Bool, query: String, context: AccountContext, presentationData: PresentationData, nameSortOrder: PresentationPersonNameOrder, nameDisplayOrder: PresentationPersonNameOrder, interaction: ChannelMembersSearchContainerInteraction) -> ChannelMembersSearchContainerTransition { let (deleteIndices, indicesAndItems, updateIndices) = mergeListsStableWithUpdates(leftList: fromEntries, rightList: toEntries) let deletions = deleteIndices.map { ListViewDeleteItem(index: $0, directionHint: nil) } let insertions = indicesAndItems.map { ListViewInsertItem(index: $0.0, previousIndex: $0.2, item: $0.1.item(context: context, presentationData: presentationData, nameSortOrder: nameSortOrder, nameDisplayOrder: nameDisplayOrder, interaction: interaction), directionHint: nil) } let updates = updateIndices.map { ListViewUpdateItem(index: $0.0, previousIndex: $0.2, item: $0.1.item(context: context, presentationData: presentationData, nameSortOrder: nameSortOrder, nameDisplayOrder: nameDisplayOrder, interaction: interaction), directionHint: nil) } - return ChannelMembersSearchContainerTransition(deletions: deletions, insertions: insertions, updates: updates, isSearching: isSearching) + return ChannelMembersSearchContainerTransition(deletions: deletions, insertions: insertions, updates: updates, isSearching: isSearching, isEmpty: isEmpty, query: query) } private struct ChannelMembersSearchContainerState: Equatable { @@ -295,9 +297,12 @@ public final class ChannelMembersSearchContainerNode: SearchDisplayControllerCon private let emptyQueryListNode: ListView private let listNode: ListView + private let emptyResultsTitleNode: ImmediateTextNode + private let emptyResultsTextNode: ImmediateTextNode + private var enqueuedEmptyQueryTransitions: [(ChannelMembersSearchContainerTransition, Bool)] = [] private var enqueuedTransitions: [(ChannelMembersSearchContainerTransition, Bool)] = [] - private var hasValidLayout = false + private var validLayout: (ContainerViewLayout, CGFloat)? private let searchQuery = Promise() private let emptyQueryDisposable = MetaDisposable() @@ -340,6 +345,18 @@ public final class ChannelMembersSearchContainerNode: SearchDisplayControllerCon return presentationData.strings.VoiceOver_ScrollStatus(row, count).0 } + self.emptyResultsTitleNode = ImmediateTextNode() + self.emptyResultsTitleNode.displaysAsynchronously = false + self.emptyResultsTitleNode.attributedText = NSAttributedString(string: self.presentationData.strings.ChatList_Search_NoResults, font: Font.semibold(17.0), textColor: self.presentationData.theme.list.freeTextColor) + self.emptyResultsTitleNode.textAlignment = .center + self.emptyResultsTitleNode.isHidden = true + + self.emptyResultsTextNode = ImmediateTextNode() + self.emptyResultsTextNode.displaysAsynchronously = false + self.emptyResultsTextNode.maximumNumberOfLines = 0 + self.emptyResultsTextNode.textAlignment = .center + self.emptyResultsTextNode.isHidden = true + super.init() self.emptyQueryListNode.backgroundColor = self.presentationData.theme.chatList.backgroundColor @@ -360,6 +377,9 @@ public final class ChannelMembersSearchContainerNode: SearchDisplayControllerCon } self.addSubnode(self.listNode) + self.addSubnode(self.emptyResultsTitleNode) + self.addSubnode(self.emptyResultsTextNode) + let statePromise = ValuePromise(ChannelMembersSearchContainerState(), ignoreRepeated: true) let stateValue = Atomic(value: ChannelMembersSearchContainerState()) let updateState: ((ChannelMembersSearchContainerState) -> ChannelMembersSearchContainerState) -> Void = { f in @@ -575,7 +595,7 @@ public final class ChannelMembersSearchContainerNode: SearchDisplayControllerCon emptyQueryItems = .single(nil) } - let foundItems = combineLatest(searchQuery.get(), context.account.postbox.peerView(id: peerId) |> take(1)) + let foundItems = combineLatest(self.searchQuery.get(), context.account.postbox.peerView(id: peerId) |> take(1)) |> mapToSignal { query, peerView -> Signal<[ChannelMembersSearchEntry]?, NoError> in guard let query = query, !query.isEmpty else { return .single(nil) @@ -1217,7 +1237,7 @@ public final class ChannelMembersSearchContainerNode: SearchDisplayControllerCon if let strongSelf = self { let previousEntries = previousEmptyQueryItems.swap(entries) let firstTime = previousEntries == nil - let transition = channelMembersSearchContainerPreparedRecentTransition(from: previousEntries ?? [], to: entries ?? [], isSearching: entries != nil, context: context, presentationData: presentationData, nameSortOrder: presentationData.nameSortOrder, nameDisplayOrder: presentationData.nameDisplayOrder, interaction: interaction) + let transition = channelMembersSearchContainerPreparedRecentTransition(from: previousEntries ?? [], to: entries ?? [], isSearching: entries != nil, isEmpty: entries?.isEmpty ?? false, query: "", context: context, presentationData: presentationData, nameSortOrder: presentationData.nameSortOrder, nameDisplayOrder: presentationData.nameDisplayOrder, interaction: interaction) strongSelf.enqueueEmptyQueryTransition(transition, firstTime: firstTime) if entries == nil { @@ -1228,13 +1248,13 @@ public final class ChannelMembersSearchContainerNode: SearchDisplayControllerCon } })) - self.searchDisposable.set((combineLatest(foundItems, self.presentationDataPromise.get()) - |> deliverOnMainQueue).start(next: { [weak self] entries, presentationData in + self.searchDisposable.set((combineLatest(self.searchQuery.get(), foundItems, self.presentationDataPromise.get()) + |> deliverOnMainQueue).start(next: { [weak self] query, entries, presentationData in if let strongSelf = self { let previousEntries = previousSearchItems.swap(entries) updateActivity(false) let firstTime = previousEntries == nil - let transition = channelMembersSearchContainerPreparedRecentTransition(from: previousEntries ?? [], to: entries ?? [], isSearching: entries != nil, context: context, presentationData: presentationData, nameSortOrder: presentationData.nameSortOrder, nameDisplayOrder: presentationData.nameDisplayOrder, interaction: interaction) + let transition = channelMembersSearchContainerPreparedRecentTransition(from: previousEntries ?? [], to: entries ?? [], isSearching: entries != nil, isEmpty: entries?.isEmpty ?? false, query: query ?? "", context: context, presentationData: presentationData, nameSortOrder: presentationData.nameSortOrder, nameDisplayOrder: presentationData.nameDisplayOrder, interaction: interaction) strongSelf.enqueueTransition(transition, firstTime: firstTime) } })) @@ -1293,7 +1313,7 @@ public final class ChannelMembersSearchContainerNode: SearchDisplayControllerCon private func enqueueEmptyQueryTransition(_ transition: ChannelMembersSearchContainerTransition, firstTime: Bool) { enqueuedEmptyQueryTransitions.append((transition, firstTime)) - if self.hasValidLayout { + if let _ = self.validLayout { while !self.enqueuedEmptyQueryTransitions.isEmpty { self.dequeueEmptyQueryTransition() } @@ -1303,7 +1323,7 @@ public final class ChannelMembersSearchContainerNode: SearchDisplayControllerCon private func enqueueTransition(_ transition: ChannelMembersSearchContainerTransition, firstTime: Bool) { enqueuedTransitions.append((transition, firstTime)) - if self.hasValidLayout { + if let _ = self.validLayout { while !self.enqueuedTransitions.isEmpty { self.dequeueTransition() } @@ -1324,8 +1344,22 @@ public final class ChannelMembersSearchContainerNode: SearchDisplayControllerCon let isSearching = transition.isSearching self.listNode.transaction(deleteIndices: transition.deletions, insertIndicesAndItems: transition.insertions, updateIndicesAndItems: transition.updates, options: options, updateSizeAndInsets: nil, updateOpaqueState: nil, completion: { [weak self] _ in - self?.listNode.isHidden = !isSearching - self?.emptyQueryListNode.isHidden = isSearching + guard let strongSelf = self else { + return + } + + strongSelf.listNode.isHidden = !isSearching + strongSelf.emptyQueryListNode.isHidden = isSearching + + strongSelf.emptyResultsTextNode.attributedText = NSAttributedString(string: strongSelf.presentationData.strings.ChatList_Search_NoResultsQueryDescription(transition.query).0, font: Font.regular(15.0), textColor: strongSelf.presentationData.theme.list.freeTextColor) + + let emptyResults = transition.isSearching && transition.isEmpty + strongSelf.emptyResultsTitleNode.isHidden = !emptyResults + strongSelf.emptyResultsTextNode.isHidden = !emptyResults + + if let (layout, navigationBarHeight) = strongSelf.validLayout { + strongSelf.containerLayoutUpdated(layout, navigationBarHeight: navigationBarHeight, transition: .immediate) + } }) } } @@ -1350,6 +1384,9 @@ public final class ChannelMembersSearchContainerNode: SearchDisplayControllerCon override public func containerLayoutUpdated(_ layout: ContainerViewLayout, navigationBarHeight: CGFloat, transition: ContainedViewLayoutTransition) { super.containerLayoutUpdated(layout, navigationBarHeight: navigationBarHeight, transition: transition) + let hadValidLayout = self.validLayout == nil + self.validLayout = (layout, navigationBarHeight) + let (duration, curve) = listViewAnimationDurationAndCurve(transition: transition) var insets = layout.insets(options: [.input]) @@ -1363,8 +1400,18 @@ public final class ChannelMembersSearchContainerNode: SearchDisplayControllerCon self.emptyQueryListNode.frame = CGRect(origin: CGPoint(), size: layout.size) self.emptyQueryListNode.transaction(deleteIndices: [], insertIndicesAndItems: [], updateIndicesAndItems: [], options: [.Synchronous], scrollToItem: nil, updateSizeAndInsets: ListViewUpdateSizeAndInsets(size: layout.size, insets: insets, duration: duration, curve: curve), stationaryItemRange: nil, updateOpaqueState: nil, completion: { _ in }) - if !hasValidLayout { - hasValidLayout = true + let padding: CGFloat = 16.0 + let emptyTitleSize = self.emptyResultsTitleNode.updateLayout(CGSize(width: layout.size.width - layout.safeInsets.left - layout.safeInsets.right - padding * 2.0, height: CGFloat.greatestFiniteMagnitude)) + let emptyTextSize = self.emptyResultsTextNode.updateLayout(CGSize(width: layout.size.width - layout.safeInsets.left - layout.safeInsets.right - padding * 2.0, height: CGFloat.greatestFiniteMagnitude)) + + let emptyTextSpacing: CGFloat = 8.0 + let emptyTotalHeight = emptyTitleSize.height + emptyTextSize.height + emptyTextSpacing + let emptyTitleY = navigationBarHeight + floorToScreenPixels((layout.size.height - navigationBarHeight - max(insets.bottom, layout.intrinsicInsets.bottom) - emptyTotalHeight) / 2.0) + + transition.updateFrame(node: self.emptyResultsTitleNode, frame: CGRect(origin: CGPoint(x: layout.safeInsets.left + padding + (layout.size.width - layout.safeInsets.left - layout.safeInsets.right - padding * 2.0 - emptyTitleSize.width) / 2.0, y: emptyTitleY), size: emptyTitleSize)) + transition.updateFrame(node: self.emptyResultsTextNode, frame: CGRect(origin: CGPoint(x: layout.safeInsets.left + padding + (layout.size.width - layout.safeInsets.left - layout.safeInsets.right - padding * 2.0 - emptyTextSize.width) / 2.0, y: emptyTitleY + emptyTitleSize.height + emptyTextSpacing), size: emptyTextSize)) + + if !hadValidLayout { while !self.enqueuedTransitions.isEmpty { self.dequeueTransition() } diff --git a/submodules/TelegramCallsUI/Sources/VoiceChatJoinScreen.swift b/submodules/TelegramCallsUI/Sources/VoiceChatJoinScreen.swift index 8d863404d1..f54d4f8578 100644 --- a/submodules/TelegramCallsUI/Sources/VoiceChatJoinScreen.swift +++ b/submodules/TelegramCallsUI/Sources/VoiceChatJoinScreen.swift @@ -123,6 +123,7 @@ public final class VoiceChatJoinScreen: ViewController { if let strongSelf = self { if let (peer, call) = peerAndCall { if call.info.id == currentGroupCallId { + strongSelf.dismiss() strongSelf.context.sharedContext.navigateToCurrentCall() return } diff --git a/submodules/TelegramCallsUI/Sources/VoiceChatTitleEditController.swift b/submodules/TelegramCallsUI/Sources/VoiceChatTitleEditController.swift index a5632953b8..38d1ba459a 100644 --- a/submodules/TelegramCallsUI/Sources/VoiceChatTitleEditController.swift +++ b/submodules/TelegramCallsUI/Sources/VoiceChatTitleEditController.swift @@ -430,7 +430,7 @@ func voiceChatTitleEditController(sharedContext: SharedAccountContext, account: dismissImpl?(true) let previousValue = value ?? "" - let newValue = contentNode.value + let newValue = contentNode.value.trimmingCharacters(in: .whitespacesAndNewlines) apply(previousValue != newValue || value == nil ? newValue : nil) } diff --git a/submodules/TelegramUI/Sources/ChatController.swift b/submodules/TelegramUI/Sources/ChatController.swift index 9b259f6ca5..28d86adb34 100644 --- a/submodules/TelegramUI/Sources/ChatController.swift +++ b/submodules/TelegramUI/Sources/ChatController.swift @@ -5368,30 +5368,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G case .mediaRecording: subjectFlags = .banSendMedia } - - if case .mediaRecording = subject, let _ = strongSelf.presentationInterfaceState.activeGroupCallInfo { - let rect = strongSelf.chatDisplayNode.frameForInputActionButton() - if let rect = rect { - strongSelf.mediaRestrictedTooltipController?.dismiss() - let tooltipController = TooltipController(content: .text(strongSelf.presentationInterfaceState.strings.Conversation_VoiceChatMediaRecordingRestricted), baseFontSize: strongSelf.presentationData.listsFontSize.baseDisplaySize) - strongSelf.mediaRestrictedTooltipController = tooltipController - strongSelf.mediaRestrictedTooltipControllerMode = false - tooltipController.dismissed = { [weak tooltipController] _ in - if let strongSelf = self, let tooltipController = tooltipController, strongSelf.mediaRestrictedTooltipController === tooltipController { - strongSelf.mediaRestrictedTooltipController = nil - } - } - strongSelf.present(tooltipController, in: .window(.root), with: TooltipControllerPresentationArguments(sourceNodeAndRect: { - if let strongSelf = self { - return (strongSelf.chatDisplayNode, rect) - } - return nil - })) - } - - return - } - + let bannedPermission: (Int32, Bool)? if let channel = strongSelf.presentationInterfaceState.renderedPeer?.peer as? TelegramChannel { bannedPermission = channel.hasBannedPermission(subjectFlags) @@ -5470,6 +5447,27 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G strongSelf.present(textAlertController(context: strongSelf.context, title: nil, text: banDescription, actions: [TextAlertAction(type: .defaultAction, title: strongSelf.presentationData.strings.Common_OK, action: {})]), in: .window(.root)) } } + + if case .mediaRecording = subject, let _ = strongSelf.presentationInterfaceState.activeGroupCallInfo { + let rect = strongSelf.chatDisplayNode.frameForInputActionButton() + if let rect = rect { + strongSelf.mediaRestrictedTooltipController?.dismiss() + let tooltipController = TooltipController(content: .text(strongSelf.presentationInterfaceState.strings.Conversation_VoiceChatMediaRecordingRestricted), baseFontSize: strongSelf.presentationData.listsFontSize.baseDisplaySize) + strongSelf.mediaRestrictedTooltipController = tooltipController + strongSelf.mediaRestrictedTooltipControllerMode = false + tooltipController.dismissed = { [weak tooltipController] _ in + if let strongSelf = self, let tooltipController = tooltipController, strongSelf.mediaRestrictedTooltipController === tooltipController { + strongSelf.mediaRestrictedTooltipController = nil + } + } + strongSelf.present(tooltipController, in: .window(.root), with: TooltipControllerPresentationArguments(sourceNodeAndRect: { + if let strongSelf = self { + return (strongSelf.chatDisplayNode, rect) + } + return nil + })) + } + } }, displayVideoUnmuteTip: { [weak self] location in guard let strongSelf = self, let layout = strongSelf.validLayout, strongSelf.traceVisibility() && isTopmostChatController(strongSelf) else { return diff --git a/submodules/TelegramUI/Sources/ChatMessageInteractiveFileNode.swift b/submodules/TelegramUI/Sources/ChatMessageInteractiveFileNode.swift index 9816116f58..b31626c166 100644 --- a/submodules/TelegramUI/Sources/ChatMessageInteractiveFileNode.swift +++ b/submodules/TelegramUI/Sources/ChatMessageInteractiveFileNode.swift @@ -917,19 +917,23 @@ final class ChatMessageInteractiveFileNode: ASDisplayNode { if state != .none && self.statusNode == nil { var image: Signal<(TransformImageArguments) -> DrawingContext?, NoError>? = nil + if file.isMusic { - var title: String? - var performer: String? - - for attribute in file.attributes { - if case let .Audio(_, _, titleValue, performerValue, _) = attribute { - title = titleValue - performer = performerValue - break + if file.fileName?.lowercased().hasPrefix(".ogg") == true { + } else { + var title: String? + var performer: String? + + for attribute in file.attributes { + if case let .Audio(_, _, titleValue, performerValue, _) = attribute { + title = titleValue + performer = performerValue + break + } } + + image = playerAlbumArt(postbox: context.account.postbox, fileReference: .message(message: MessageReference(message), media: file), albumArt: .init(thumbnailResource: ExternalMusicAlbumArtResource(title: title ?? "", performer: performer ?? "", isThumbnail: true), fullSizeResource: ExternalMusicAlbumArtResource(title: title ?? "", performer: performer ?? "", isThumbnail: false)), thumbnail: true, overlayColor: UIColor(white: 0.0, alpha: 0.3), drawPlaceholderWhenEmpty: false, attemptSynchronously: !animated) } - - image = playerAlbumArt(postbox: context.account.postbox, fileReference: .message(message: MessageReference(message), media: file), albumArt: .init(thumbnailResource: ExternalMusicAlbumArtResource(title: title ?? "", performer: performer ?? "", isThumbnail: true), fullSizeResource: ExternalMusicAlbumArtResource(title: title ?? "", performer: performer ?? "", isThumbnail: false)), thumbnail: true, overlayColor: UIColor(white: 0.0, alpha: 0.3), drawPlaceholderWhenEmpty: false, attemptSynchronously: !animated) } let statusNode = SemanticStatusNode(backgroundNodeColor: backgroundNodeColor, foregroundNodeColor: foregroundNodeColor, image: image, overlayForegroundNodeColor: presentationData.theme.theme.chat.message.mediaOverlayControlColors.foregroundColor) self.statusNode = statusNode diff --git a/submodules/TelegramUI/Sources/ChatRecentActionsFilterController.swift b/submodules/TelegramUI/Sources/ChatRecentActionsFilterController.swift index eebeba14fa..d4ee155c36 100644 --- a/submodules/TelegramUI/Sources/ChatRecentActionsFilterController.swift +++ b/submodules/TelegramUI/Sources/ChatRecentActionsFilterController.swift @@ -306,6 +306,7 @@ private func channelRecentActionsFilterControllerEntries(presentationData: Prese ([.editMessages], presentationData.strings.Channel_AdminLogFilter_EventsEditedMessages), ([.pinnedMessages], presentationData.strings.Channel_AdminLogFilter_EventsPinned), ([.leave], presentationData.strings.Channel_AdminLogFilter_EventsLeaving), + ([.calls], presentationData.strings.Channel_AdminLogFilter_EventsCalls) ] } diff --git a/submodules/TelegramUI/Sources/PeerInfo/PeerInfoHeaderNode.swift b/submodules/TelegramUI/Sources/PeerInfo/PeerInfoHeaderNode.swift index b8b649baee..5125d523c8 100644 --- a/submodules/TelegramUI/Sources/PeerInfo/PeerInfoHeaderNode.swift +++ b/submodules/TelegramUI/Sources/PeerInfo/PeerInfoHeaderNode.swift @@ -115,8 +115,7 @@ final class PeerInfoHeaderButtonNode: HighlightableButtonNode { let isActiveUpdated = self.isActive != isActive self.isActive = isActive - - if isActiveUpdated { + if isActiveUpdated, !self.containerNode.alpha.isZero { if let snapshotView = self.backgroundNode.view.snapshotContentTree() { snapshotView.frame = self.backgroundNode.view.frame self.view.addSubview(snapshotView) @@ -125,7 +124,7 @@ final class PeerInfoHeaderButtonNode: HighlightableButtonNode { snapshotView?.removeFromSuperview() }) } - if let snapshotView = self.textNode.view.snapshotContentTree() { + if !isExpanded, let snapshotView = self.textNode.view.snapshotContentTree() { snapshotView.frame = self.textNode.view.frame self.view.addSubview(snapshotView) diff --git a/submodules/TelegramUI/Sources/PeerMessagesMediaPlaylist.swift b/submodules/TelegramUI/Sources/PeerMessagesMediaPlaylist.swift index a0524b5d08..49752b3b8b 100644 --- a/submodules/TelegramUI/Sources/PeerMessagesMediaPlaylist.swift +++ b/submodules/TelegramUI/Sources/PeerMessagesMediaPlaylist.swift @@ -115,7 +115,15 @@ final class MessageMediaPlaylistItem: SharedMediaPlaylistItem { if (title ?? "").isEmpty && (performer ?? "").isEmpty { updatedTitle = file.fileName ?? "" } - return SharedMediaPlaybackDisplayData.music(title: updatedTitle, performer: updatedPerformer, albumArt: SharedMediaPlaybackAlbumArt(thumbnailResource: ExternalMusicAlbumArtResource(title: title ?? "", performer: performer ?? "", isThumbnail: true), fullSizeResource: ExternalMusicAlbumArtResource(title: updatedTitle ?? "", performer: updatedPerformer ?? "", isThumbnail: false)), long: duration > 60 * 20) + + let albumArt: SharedMediaPlaybackAlbumArt? + if file.fileName?.lowercased().hasPrefix(".ogg") == true { + albumArt = nil + } else { + albumArt = SharedMediaPlaybackAlbumArt(thumbnailResource: ExternalMusicAlbumArtResource(title: updatedTitle ?? "", performer: updatedPerformer ?? "", isThumbnail: true), fullSizeResource: ExternalMusicAlbumArtResource(title: updatedTitle ?? "", performer: updatedPerformer ?? "", isThumbnail: false)) + } + + return SharedMediaPlaybackDisplayData.music(title: updatedTitle, performer: updatedPerformer, albumArt: albumArt, long: duration > 60 * 20) } case let .Video(_, _, flags): if flags.contains(.instantRoundVideo) {