From 43d05b877b7dba2e5da49d3b5e014187ea0c8741 Mon Sep 17 00:00:00 2001 From: Peter <> Date: Wed, 21 Nov 2018 20:21:40 +0300 Subject: [PATCH] Various UI Fixes --- TelegramUI/AvatarNode.swift | 4 +- TelegramUI/CallListCallItem.swift | 2 +- TelegramUI/ChatControllerNode.swift | 3 + .../ChatInterfaceStateContextQueries.swift | 59 ++++++++++--------- TelegramUI/ChatListItem.swift | 2 +- .../ChatMessageAvatarAccessoryItem.swift | 10 ++-- .../ChatMessageContactBubbleContentNode.swift | 5 +- .../ChatMessageInteractiveMediaNode.swift | 4 +- TelegramUI/ChatMessageItem.swift | 2 +- TelegramUI/ChatMessageNotificationItem.swift | 2 +- TelegramUI/ChatTitleView.swift | 41 ++++++++----- TelegramUI/CommandChatInputPanelItem.swift | 2 +- TelegramUI/ContactsPeerItem.swift | 2 +- TelegramUI/HorizontalPeerItem.swift | 4 +- TelegramUI/ItemListAvatarAndNameItem.swift | 2 +- TelegramUI/ItemListPeerItem.swift | 4 +- .../JoinLinkPreviewPeerContentNode.swift | 4 +- TelegramUI/MediaPlayer.swift | 49 +++++++++------ TelegramUI/MediaPlayerScrubbingNode.swift | 7 ++- TelegramUI/MentionChatInputPanelItem.swift | 2 +- TelegramUI/PeerAvatar.swift | 26 ++++---- TelegramUI/SearchPeerMembers.swift | 21 ++++--- TelegramUI/SelectablePeerNode.swift | 11 +++- TelegramUI/ShareControllerPeerGridItem.swift | 2 +- 24 files changed, 163 insertions(+), 107 deletions(-) diff --git a/TelegramUI/AvatarNode.swift b/TelegramUI/AvatarNode.swift index ad392cb431..a8efa67685 100644 --- a/TelegramUI/AvatarNode.swift +++ b/TelegramUI/AvatarNode.swift @@ -192,7 +192,7 @@ public final class AvatarNode: ASDisplayNode { } } - public func setPeer(account: Account, peer: Peer, authorOfMessage: MessageReference? = nil, overrideImage: AvatarNodeImageOverride? = nil) { + public func setPeer(account: Account, peer: Peer, authorOfMessage: MessageReference? = nil, overrideImage: AvatarNodeImageOverride? = nil, emptyColor: UIColor? = nil) { var representation: TelegramMediaImageRepresentation? var icon = AvatarNodeIcon.none if let overrideImage = overrideImage { @@ -222,7 +222,7 @@ public final class AvatarNode: ASDisplayNode { let theme = account.telegramApplicationContext.currentPresentationData.with { $0 }.theme - if let signal = peerAvatarImage(account: account, peer: peer, authorOfMessage: authorOfMessage, representation: representation) { + if let signal = peerAvatarImage(account: account, peer: peer, authorOfMessage: authorOfMessage, representation: representation, emptyColor: emptyColor) { self.imageReady.set(self.imageNode.ready) self.imageNode.setSignal(signal) diff --git a/TelegramUI/CallListCallItem.swift b/TelegramUI/CallListCallItem.swift index a89c4069f0..bc94b438f3 100644 --- a/TelegramUI/CallListCallItem.swift +++ b/TelegramUI/CallListCallItem.swift @@ -430,7 +430,7 @@ class CallListCallItemNode: ItemListRevealOptionsItemNode { return (nodeLayout, { [weak self] in if let strongSelf = self { if let peer = item.topMessage.peers[item.topMessage.id.peerId] { - strongSelf.avatarNode.setPeer(account: item.account, peer: peer) + strongSelf.avatarNode.setPeer(account: item.account, peer: peer, emptyColor: item.theme.list.mediaPlaceholderColor) } return (strongSelf.avatarNode.ready, { [weak strongSelf] animated in diff --git a/TelegramUI/ChatControllerNode.swift b/TelegramUI/ChatControllerNode.swift index 420c4e9768..dd2a72029c 100644 --- a/TelegramUI/ChatControllerNode.swift +++ b/TelegramUI/ChatControllerNode.swift @@ -377,6 +377,7 @@ class ChatControllerNode: ASDisplayNode, UIScrollViewDelegate { if let (size, insets) = self.validEmptyNodeLayout { emptyNode.updateLayout(interfaceState: self.chatPresentationInterfaceState, size: size, insets: insets, transition: .immediate) } + emptyNode.isHidden = self.restrictedNode != nil self.emptyNode = emptyNode self.historyNodeContainer.supernode?.insertSubnode(emptyNode, aboveSubnode: self.historyNodeContainer) if animated { @@ -1330,12 +1331,14 @@ class ChatControllerNode: ASDisplayNode, UIScrollViewDelegate { self.historyNodeContainer.isHidden = true self.navigateButtons.isHidden = true self.loadingNode.isHidden = true + self.emptyNode?.isHidden = true } else if let restrictedNode = self.restrictedNode { self.restrictedNode = nil restrictedNode.removeFromSupernode() self.historyNodeContainer.isHidden = false self.navigateButtons.isHidden = false self.loadingNode.isHidden = false + self.emptyNode?.isHidden = false } let layoutTransition: ContainedViewLayoutTransition = transition diff --git a/TelegramUI/ChatInterfaceStateContextQueries.swift b/TelegramUI/ChatInterfaceStateContextQueries.swift index 3047b6dad5..8850d6ddef 100644 --- a/TelegramUI/ChatInterfaceStateContextQueries.swift +++ b/TelegramUI/ChatInterfaceStateContextQueries.swift @@ -132,38 +132,41 @@ private func updatedContextQueryResultStateForQuery(account: Account, peer: Peer let inlineBots: Signal<[(Peer, Double)], NoError> = types.contains(.contextBots) ? recentlyUsedInlineBots(postbox: account.postbox) : .single([]) let participants = combineLatest(inlineBots, searchPeerMembers(account: account, peerId: peer.id, query: query)) - |> map { inlineBots, peers -> (ChatPresentationInputQueryResult?) -> ChatPresentationInputQueryResult? in - let filteredInlineBots = inlineBots.sorted(by: { $0.1 > $1.1 }).filter { peer, rating in - if rating < 0.14 { - return false - } - if peer.indexName.matchesByTokens(normalizedQuery) { - return true - } - if let addressName = peer.addressName, addressName.lowercased().hasPrefix(normalizedQuery) { - return true - } + |> map { inlineBots, peers -> (ChatPresentationInputQueryResult?) -> ChatPresentationInputQueryResult? in + let filteredInlineBots = inlineBots.sorted(by: { $0.1 > $1.1 }).filter { peer, rating in + if rating < 0.14 { return false - }.map { $0.0 } - - let inlineBotPeerIds = Set(filteredInlineBots.map { $0.id }) - - let filteredPeers = peers.filter { peer in - if inlineBotPeerIds.contains(peer.id) { - return false - } - if !types.contains(.accountPeer) && peer.id == account.peerId { - return false - } + } + if peer.indexName.matchesByTokens(normalizedQuery) { return true } - var sortedPeers = filteredInlineBots - sortedPeers.append(contentsOf: filteredPeers.sorted(by: { lhs, rhs in - let result = lhs.indexName.indexName(.lastNameFirst).compare(rhs.indexName.indexName(.lastNameFirst)) - return result == .orderedAscending - })) - return { _ in return .mentions(sortedPeers) } + if let addressName = peer.addressName, addressName.lowercased().hasPrefix(normalizedQuery) { + return true + } + return false + }.map { $0.0 } + + let inlineBotPeerIds = Set(filteredInlineBots.map { $0.id }) + + let filteredPeers = peers.filter { peer in + if inlineBotPeerIds.contains(peer.id) { + return false + } + if !types.contains(.accountPeer) && peer.id == account.peerId { + return false + } + return true } + var sortedPeers = filteredInlineBots + sortedPeers.append(contentsOf: filteredPeers.sorted(by: { lhs, rhs in + let result = lhs.indexName.indexName(.lastNameFirst).compare(rhs.indexName.indexName(.lastNameFirst)) + return result == .orderedAscending + })) + sortedPeers = sortedPeers.filter { peer in + return !peer.displayTitle.isEmpty + } + return { _ in return .mentions(sortedPeers) } + } return signal |> then(participants) case let .command(query): diff --git a/TelegramUI/ChatListItem.swift b/TelegramUI/ChatListItem.swift index 94e5404b88..4f434dd9d4 100644 --- a/TelegramUI/ChatListItem.swift +++ b/TelegramUI/ChatListItem.swift @@ -339,7 +339,7 @@ class ChatListItemNode: ItemListRevealOptionsItemNode { if peer.id == item.account.peerId { overrideImage = .savedMessagesIcon } - self.avatarNode.setPeer(account: item.account, peer: peer, overrideImage: overrideImage) + self.avatarNode.setPeer(account: item.account, peer: peer, overrideImage: overrideImage, emptyColor: item.presentationData.theme.list.mediaPlaceholderColor) } } diff --git a/TelegramUI/ChatMessageAvatarAccessoryItem.swift b/TelegramUI/ChatMessageAvatarAccessoryItem.swift index b179f97d43..a34884529e 100644 --- a/TelegramUI/ChatMessageAvatarAccessoryItem.swift +++ b/TelegramUI/ChatMessageAvatarAccessoryItem.swift @@ -11,13 +11,15 @@ final class ChatMessageAvatarAccessoryItem: ListViewAccessoryItem { private let peer: Peer? private let messageReference: MessageReference? private let messageTimestamp: Int32 + private let emptyColor: UIColor - init(account: Account, peerId: PeerId, peer: Peer?, messageReference: MessageReference?, messageTimestamp: Int32) { + init(account: Account, peerId: PeerId, peer: Peer?, messageReference: MessageReference?, messageTimestamp: Int32, emptyColor: UIColor) { self.account = account self.peerId = peerId self.peer = peer self.messageReference = messageReference self.messageTimestamp = messageTimestamp + self.emptyColor = emptyColor } func isEqualToItem(_ other: ListViewAccessoryItem) -> Bool { @@ -32,7 +34,7 @@ final class ChatMessageAvatarAccessoryItem: ListViewAccessoryItem { let node = ChatMessageAvatarAccessoryItemNode() node.frame = CGRect(origin: CGPoint(), size: CGSize(width: 38.0, height: 38.0)) if let peer = self.peer { - node.setPeer(account: account, peer: peer, authorOfMessage: self.messageReference) + node.setPeer(account: account, peer: peer, authorOfMessage: self.messageReference, emptyColor: self.emptyColor) } return node } @@ -52,7 +54,7 @@ final class ChatMessageAvatarAccessoryItemNode: ListViewAccessoryItemNode { self.addSubnode(self.avatarNode) } - func setPeer(account: Account, peer: Peer, authorOfMessage: MessageReference?) { - self.avatarNode.setPeer(account: account, peer: peer, authorOfMessage: authorOfMessage) + func setPeer(account: Account, peer: Peer, authorOfMessage: MessageReference?, emptyColor: UIColor) { + self.avatarNode.setPeer(account: account, peer: peer, authorOfMessage: authorOfMessage, emptyColor: emptyColor) } } diff --git a/TelegramUI/ChatMessageContactBubbleContentNode.swift b/TelegramUI/ChatMessageContactBubbleContentNode.swift index 5e1a40cbb8..34b4407c76 100644 --- a/TelegramUI/ChatMessageContactBubbleContentNode.swift +++ b/TelegramUI/ChatMessageContactBubbleContentNode.swift @@ -184,6 +184,7 @@ class ChatMessageContactBubbleContentNode: ChatMessageBubbleContentNode { let buttonHighlightedImage: UIImage let titleColor: UIColor let titleHighlightedColor: UIColor + let avatarPlaceholderColor: UIColor if item.message.effectivelyIncoming(item.account.peerId) { buttonImage = PresentationResourcesChat.chatMessageAttachedContentButtonIncoming(item.presentationData.theme.theme)! buttonHighlightedImage = PresentationResourcesChat.chatMessageAttachedContentHighlightedButtonIncoming(item.presentationData.theme.theme)! @@ -191,6 +192,7 @@ class ChatMessageContactBubbleContentNode: ChatMessageBubbleContentNode { let bubbleColors = bubbleColorComponents(theme: item.presentationData.theme.theme, incoming: true, wallpaper: !item.presentationData.theme.wallpaper.isEmpty) titleHighlightedColor = bubbleColors.fill + avatarPlaceholderColor = item.presentationData.theme.theme.chat.bubble.incomingMediaPlaceholderColor } else { buttonImage = PresentationResourcesChat.chatMessageAttachedContentButtonOutgoing(item.presentationData.theme.theme)! buttonHighlightedImage = PresentationResourcesChat.chatMessageAttachedContentHighlightedButtonOutgoing(item.presentationData.theme.theme)! @@ -198,6 +200,7 @@ class ChatMessageContactBubbleContentNode: ChatMessageBubbleContentNode { let bubbleColors = bubbleColorComponents(theme: item.presentationData.theme.theme, incoming: false, wallpaper: !item.presentationData.theme.wallpaper.isEmpty) titleHighlightedColor = bubbleColors.fill + avatarPlaceholderColor = item.presentationData.theme.theme.chat.bubble.outgoingMediaPlaceholderColor } let (buttonWidth, continueLayout) = makeButtonLayout(constrainedSize.width, buttonImage, buttonHighlightedImage, nil, nil, item.presentationData.strings.Conversation_ViewContactDetails, titleColor, titleHighlightedColor) @@ -286,7 +289,7 @@ class ChatMessageContactBubbleContentNode: ChatMessageBubbleContentNode { } if let peerId = selectedContact?.peerId, let peer = item.message.peers[peerId] { - strongSelf.avatarNode.setPeer(account: item.account, peer: peer) + strongSelf.avatarNode.setPeer(account: item.account, peer: peer, emptyColor: avatarPlaceholderColor) } else { strongSelf.avatarNode.setCustomLetters(customLetters) } diff --git a/TelegramUI/ChatMessageInteractiveMediaNode.swift b/TelegramUI/ChatMessageInteractiveMediaNode.swift index b84535f554..9772804d5d 100644 --- a/TelegramUI/ChatMessageInteractiveMediaNode.swift +++ b/TelegramUI/ChatMessageInteractiveMediaNode.swift @@ -475,7 +475,9 @@ final class ChatMessageInteractiveMediaNode: ASDisplayNode { } else if let image = media as? TelegramMediaWebFile { strongSelf.fetchDisposable.set(chatMessageWebFileInteractiveFetched(account: account, image: image).start()) } else if let file = media as? TelegramMediaFile { - strongSelf.fetchDisposable.set(messageMediaFileInteractiveFetched(account: account, message: message, file: file, userInitiated: false).start()) + if automaticPlayback || !file.isAnimated { + strongSelf.fetchDisposable.set(messageMediaFileInteractiveFetched(account: account, message: message, file: file, userInitiated: false).start()) + } } } } else if previousAutomaticDownload != automaticDownload, automaticDownload { diff --git a/TelegramUI/ChatMessageItem.swift b/TelegramUI/ChatMessageItem.swift index 5c719a441e..d7406bb50d 100644 --- a/TelegramUI/ChatMessageItem.swift +++ b/TelegramUI/ChatMessageItem.swift @@ -307,7 +307,7 @@ public final class ChatMessageItem: ListViewItem, CustomStringConvertible { } if !hasActionMedia && !isBroadcastChannel { if let effectiveAuthor = effectiveAuthor { - accessoryItem = ChatMessageAvatarAccessoryItem(account: account, peerId: effectiveAuthor.id, peer: effectiveAuthor, messageReference: MessageReference(message), messageTimestamp: content.index.timestamp) + accessoryItem = ChatMessageAvatarAccessoryItem(account: account, peerId: effectiveAuthor.id, peer: effectiveAuthor, messageReference: MessageReference(message), messageTimestamp: content.index.timestamp, emptyColor: presentationData.theme.theme.chat.bubble.incoming.withoutWallpaper.fill) } } } diff --git a/TelegramUI/ChatMessageNotificationItem.swift b/TelegramUI/ChatMessageNotificationItem.swift index 38e1ddb7a6..9900f2ce90 100644 --- a/TelegramUI/ChatMessageNotificationItem.swift +++ b/TelegramUI/ChatMessageNotificationItem.swift @@ -92,7 +92,7 @@ final class ChatMessageNotificationItemNode: NotificationItemNode { var title: String? if let firstMessage = item.messages.first, let peer = messageMainPeer(firstMessage) { - self.avatarNode.setPeer(account: item.account, peer: peer) + self.avatarNode.setPeer(account: item.account, peer: peer, emptyColor: presentationData.theme.list.mediaPlaceholderColor) if let channel = peer as? TelegramChannel, case .broadcast = channel.info { title = peer.displayTitle diff --git a/TelegramUI/ChatTitleView.swift b/TelegramUI/ChatTitleView.swift index 3e04b268ad..0587418598 100644 --- a/TelegramUI/ChatTitleView.swift +++ b/TelegramUI/ChatTitleView.swift @@ -383,26 +383,39 @@ final class ChatTitleView: UIView, NavigationBarTitleView { } } else if let channel = peer as? TelegramChannel { if let cachedChannelData = peerView.cachedData as? CachedChannelData, let memberCount = cachedChannelData.participantsSummary.memberCount { - if case .group = channel.info, let onlineMemberCount = onlineMemberCount, onlineMemberCount > 1 { - let string = NSMutableAttributedString() - - string.append(NSAttributedString(string: "\(strings.Conversation_StatusMembers(Int32(memberCount))), ", font: Font.regular(13.0), textColor: self.theme.rootController.navigationBar.secondaryTextColor)) - string.append(NSAttributedString(string: strings.Conversation_StatusOnline(Int32(onlineMemberCount)), font: Font.regular(13.0), textColor: self.theme.rootController.navigationBar.secondaryTextColor)) + if memberCount == 0 { + let string: NSAttributedString + if case .group = channel.info { + string = NSAttributedString(string: strings.Group_Status, font: Font.regular(13.0), textColor: self.theme.rootController.navigationBar.secondaryTextColor) + } else { + string = NSAttributedString(string: strings.Channel_Status, font: Font.regular(13.0), textColor: self.theme.rootController.navigationBar.secondaryTextColor) + } if self.infoNode.attributedText == nil || !self.infoNode.attributedText!.isEqual(to: string) { self.infoNode.attributedText = string shouldUpdateLayout = true } } else { - let membersString: String - if case .group = channel.info { - membersString = strings.Conversation_StatusMembers(memberCount) + if case .group = channel.info, let onlineMemberCount = onlineMemberCount, onlineMemberCount > 1 { + let string = NSMutableAttributedString() + + string.append(NSAttributedString(string: "\(strings.Conversation_StatusMembers(Int32(memberCount))), ", font: Font.regular(13.0), textColor: self.theme.rootController.navigationBar.secondaryTextColor)) + string.append(NSAttributedString(string: strings.Conversation_StatusOnline(Int32(onlineMemberCount)), font: Font.regular(13.0), textColor: self.theme.rootController.navigationBar.secondaryTextColor)) + if self.infoNode.attributedText == nil || !self.infoNode.attributedText!.isEqual(to: string) { + self.infoNode.attributedText = string + shouldUpdateLayout = true + } } else { - membersString = strings.Conversation_StatusSubscribers(memberCount) - } - let string = NSAttributedString(string: membersString, font: Font.regular(13.0), textColor: self.theme.rootController.navigationBar.secondaryTextColor) - if self.infoNode.attributedText == nil || !self.infoNode.attributedText!.isEqual(to: string) { - self.infoNode.attributedText = string - shouldUpdateLayout = true + let membersString: String + if case .group = channel.info { + membersString = strings.Conversation_StatusMembers(memberCount) + } else { + membersString = strings.Conversation_StatusSubscribers(memberCount) + } + let string = NSAttributedString(string: membersString, font: Font.regular(13.0), textColor: self.theme.rootController.navigationBar.secondaryTextColor) + if self.infoNode.attributedText == nil || !self.infoNode.attributedText!.isEqual(to: string) { + self.infoNode.attributedText = string + shouldUpdateLayout = true + } } } } else { diff --git a/TelegramUI/CommandChatInputPanelItem.swift b/TelegramUI/CommandChatInputPanelItem.swift index a514728250..c2e4273bba 100644 --- a/TelegramUI/CommandChatInputPanelItem.swift +++ b/TelegramUI/CommandChatInputPanelItem.swift @@ -156,7 +156,7 @@ final class CommandChatInputPanelItemNode: ListViewItemNode { strongSelf.arrowNode.setImage(iconImage, for: []) - strongSelf.avatarNode.setPeer(account: item.account, peer: item.command.peer) + strongSelf.avatarNode.setPeer(account: item.account, peer: item.command.peer, emptyColor: item.theme.list.mediaPlaceholderColor) let _ = textApply() diff --git a/TelegramUI/ContactsPeerItem.swift b/TelegramUI/ContactsPeerItem.swift index 37e2ea5c52..c8be96a765 100644 --- a/TelegramUI/ContactsPeerItem.swift +++ b/TelegramUI/ContactsPeerItem.swift @@ -567,7 +567,7 @@ class ContactsPeerItemNode: ItemListRevealOptionsItemNode { if peer.id == item.account.peerId, case .generalSearch = item.peerMode { overrideImage = .savedMessagesIcon } - strongSelf.avatarNode.setPeer(account: item.account, peer: peer, overrideImage: overrideImage) + strongSelf.avatarNode.setPeer(account: item.account, peer: peer, overrideImage: overrideImage, emptyColor: item.theme.list.mediaPlaceholderColor) } case let .deviceContact(_, contact): let letters: [String] diff --git a/TelegramUI/HorizontalPeerItem.swift b/TelegramUI/HorizontalPeerItem.swift index 2fb76cbf96..98ec1b9f86 100644 --- a/TelegramUI/HorizontalPeerItem.swift +++ b/TelegramUI/HorizontalPeerItem.swift @@ -124,9 +124,9 @@ final class HorizontalPeerItemNode: ListViewItemNode { let itemTheme: SelectablePeerNodeTheme switch item.mode { case .list: - itemTheme = SelectablePeerNodeTheme(textColor: item.theme.list.itemPrimaryTextColor, secretTextColor: item.theme.chatList.secretTitleColor, selectedTextColor: item.theme.list.itemAccentColor, checkBackgroundColor: item.theme.list.plainBackgroundColor, checkFillColor: item.theme.list.itemAccentColor, checkColor: item.theme.list.plainBackgroundColor) + itemTheme = SelectablePeerNodeTheme(textColor: item.theme.list.itemPrimaryTextColor, secretTextColor: item.theme.chatList.secretTitleColor, selectedTextColor: item.theme.list.itemAccentColor, checkBackgroundColor: item.theme.list.plainBackgroundColor, checkFillColor: item.theme.list.itemAccentColor, checkColor: item.theme.list.plainBackgroundColor, avatarPlaceholderColor: item.theme.list.mediaPlaceholderColor) case .actionSheet: - itemTheme = SelectablePeerNodeTheme(textColor: item.theme.actionSheet.primaryTextColor, secretTextColor: item.theme.chatList.secretTitleColor, selectedTextColor: item.theme.actionSheet.controlAccentColor, checkBackgroundColor: item.theme.actionSheet.opaqueItemBackgroundColor, checkFillColor: item.theme.actionSheet.controlAccentColor, checkColor: item.theme.actionSheet.opaqueItemBackgroundColor) + itemTheme = SelectablePeerNodeTheme(textColor: item.theme.actionSheet.primaryTextColor, secretTextColor: item.theme.chatList.secretTitleColor, selectedTextColor: item.theme.actionSheet.controlAccentColor, checkBackgroundColor: item.theme.actionSheet.opaqueItemBackgroundColor, checkFillColor: item.theme.actionSheet.controlAccentColor, checkColor: item.theme.actionSheet.opaqueItemBackgroundColor, avatarPlaceholderColor: item.theme.list.mediaPlaceholderColor) } let currentBadgeBackgroundImage: UIImage? let badgeAttributedString: NSAttributedString diff --git a/TelegramUI/ItemListAvatarAndNameItem.swift b/TelegramUI/ItemListAvatarAndNameItem.swift index 310ca13899..276942a6d7 100644 --- a/TelegramUI/ItemListAvatarAndNameItem.swift +++ b/TelegramUI/ItemListAvatarAndNameItem.swift @@ -622,7 +622,7 @@ class ItemListAvatarAndNameInfoItemNode: ListViewItemNode, ItemListItemNode, Ite } else if case .editSettings = item.mode { overrideImage = AvatarNodeImageOverride.editAvatarIcon } - strongSelf.avatarNode.setPeer(account: item.account, peer: peer, overrideImage: overrideImage) + strongSelf.avatarNode.setPeer(account: item.account, peer: peer, overrideImage: overrideImage, emptyColor: item.theme.list.mediaPlaceholderColor) } let avatarFrame = CGRect(origin: CGPoint(x: params.leftInset + 15.0, y: avatarOriginY), size: CGSize(width: 66.0, height: 66.0)) diff --git a/TelegramUI/ItemListPeerItem.swift b/TelegramUI/ItemListPeerItem.swift index fa5437fa11..162cf3e825 100644 --- a/TelegramUI/ItemListPeerItem.swift +++ b/TelegramUI/ItemListPeerItem.swift @@ -601,9 +601,9 @@ class ItemListPeerItemNode: ItemListRevealOptionsItemNode { transition.updateFrame(node: strongSelf.avatarNode, frame: CGRect(origin: CGPoint(x: params.leftInset + revealOffset + editingOffset + 12.0, y: 4.0), size: CGSize(width: 40.0, height: 40.0))) if item.peer.id == item.account.peerId, case .threatSelfAsSaved = item.aliasHandling { - strongSelf.avatarNode.setPeer(account: item.account, peer: item.peer, overrideImage: .savedMessagesIcon) + strongSelf.avatarNode.setPeer(account: item.account, peer: item.peer, overrideImage: .savedMessagesIcon, emptyColor: item.theme.list.mediaPlaceholderColor) } else { - strongSelf.avatarNode.setPeer(account: item.account, peer: item.peer) + strongSelf.avatarNode.setPeer(account: item.account, peer: item.peer, emptyColor: item.theme.list.mediaPlaceholderColor) } strongSelf.highlightedBackgroundNode.frame = CGRect(origin: CGPoint(x: 0.0, y: -UIScreenPixel), size: CGSize(width: params.width, height: 48.0 + UIScreenPixel + UIScreenPixel)) diff --git a/TelegramUI/JoinLinkPreviewPeerContentNode.swift b/TelegramUI/JoinLinkPreviewPeerContentNode.swift index 1a3813d142..784eade0a5 100644 --- a/TelegramUI/JoinLinkPreviewPeerContentNode.swift +++ b/TelegramUI/JoinLinkPreviewPeerContentNode.swift @@ -39,7 +39,7 @@ final class JoinLinkPreviewPeerContentNode: ASDisplayNode, ShareContentContainer self.peersScrollNode = ASScrollNode() self.peersScrollNode.view.showsHorizontalScrollIndicator = false - let itemTheme = SelectablePeerNodeTheme(textColor: theme.actionSheet.primaryTextColor, secretTextColor: .green, selectedTextColor: theme.actionSheet.controlAccentColor, checkBackgroundColor: theme.actionSheet.opaqueItemBackgroundColor, checkFillColor: theme.actionSheet.controlAccentColor, checkColor: theme.actionSheet.opaqueItemBackgroundColor) + let itemTheme = SelectablePeerNodeTheme(textColor: theme.actionSheet.primaryTextColor, secretTextColor: .green, selectedTextColor: theme.actionSheet.controlAccentColor, checkBackgroundColor: theme.actionSheet.opaqueItemBackgroundColor, checkFillColor: theme.actionSheet.controlAccentColor, checkColor: theme.actionSheet.opaqueItemBackgroundColor, avatarPlaceholderColor: theme.list.mediaPlaceholderColor) self.peerNodes = members.map { peer in let node = SelectablePeerNode() @@ -59,7 +59,7 @@ final class JoinLinkPreviewPeerContentNode: ASDisplayNode, ShareContentContainer let peer = TelegramGroup(id: PeerId(namespace: 0, id: 0), title: title, photo: image.flatMap { [$0] } ?? [], participantCount: Int(memberCount), role: .member, membership: .Left, flags: [], migrationReference: nil, creationDate: 0, version: 0) self.addSubnode(self.avatarNode) - self.avatarNode.setPeer(account: account, peer: peer) + self.avatarNode.setPeer(account: account, peer: peer, emptyColor: theme.list.mediaPlaceholderColor) self.addSubnode(self.titleNode) self.titleNode.attributedText = NSAttributedString(string: title, font: Font.semibold(16.0), textColor: theme.actionSheet.primaryTextColor) diff --git a/TelegramUI/MediaPlayer.swift b/TelegramUI/MediaPlayer.swift index 6c7486e65f..70cb22566b 100644 --- a/TelegramUI/MediaPlayer.swift +++ b/TelegramUI/MediaPlayer.swift @@ -29,9 +29,13 @@ private final class MediaPlayerLoadedState { } } +private struct MediaPlayerSeekState { + let duration: Double +} + private enum MediaPlayerState { case empty - case seeking(frameSource: MediaFrameSource, timestamp: Double, disposable: Disposable, action: MediaPlayerPlaybackAction, enableSound: Bool) + case seeking(frameSource: MediaFrameSource, timestamp: Double, seekState: MediaPlayerSeekState?, disposable: Disposable, action: MediaPlayerPlaybackAction, enableSound: Bool) case paused(MediaPlayerLoadedState) case playing(MediaPlayerLoadedState) } @@ -119,7 +123,7 @@ private final class MediaPlayerContext { if !value { strongSelf.pause(lostAudioSession: false) } - case let .seeking(_, _, _, action, _): + case let .seeking(_, _, _, _, action, _): switch action { case .pause: if value { @@ -167,7 +171,7 @@ private final class MediaPlayerContext { self.tickTimer?.invalidate() - if case let .seeking(_, _, disposable, _, _) = self.state { + if case let .seeking(_, _, _, disposable, _, _) = self.state { disposable.dispose() } } @@ -181,7 +185,7 @@ private final class MediaPlayerContext { action = .pause case .playing: action = .play - case let .seeking(_, _, _, currentAction, _): + case let .seeking(_, _, _, _, currentAction, _): action = currentAction } self.seek(timestamp: timestamp, action: action) @@ -191,6 +195,7 @@ private final class MediaPlayerContext { assert(self.queue.isCurrent()) var loadedState: MediaPlayerLoadedState? + var seekState: MediaPlayerSeekState? switch self.state { case .empty: break @@ -198,16 +203,18 @@ private final class MediaPlayerContext { loadedState = currentLoadedState case let .paused(currentLoadedState): loadedState = currentLoadedState - case let .seeking(previousFrameSource, previousTimestamp, previousDisposable, _, previousEnableSound): + case let .seeking(previousFrameSource, previousTimestamp, seekStateValue, previousDisposable, _, previousEnableSound): if previousTimestamp.isEqual(to: timestamp) && self.enableSound == previousEnableSound { - self.state = .seeking(frameSource: previousFrameSource, timestamp: previousTimestamp, disposable: previousDisposable, action: action, enableSound: self.enableSound) + self.state = .seeking(frameSource: previousFrameSource, timestamp: previousTimestamp, seekState: seekStateValue, disposable: previousDisposable, action: action, enableSound: self.enableSound) return } else { + seekState = seekStateValue previousDisposable.dispose() } } self.tickTimer?.invalidate() + var loadedDuration: Double? if let loadedState = loadedState { self.seekId += 1 @@ -231,16 +238,24 @@ private final class MediaPlayerContext { audioStatus = audioTrackFrameBuffer.status(at: currentTimestamp) duration = max(duration, CMTimeGetSeconds(audioTrackFrameBuffer.duration)) } + loadedDuration = duration let status = MediaPlayerStatus(generationTimestamp: CACurrentMediaTime(), duration: duration, dimensions: CGSize(), timestamp: min(max(timestamp, 0.0), duration), baseRate: self.baseRate, seekId: self.seekId, status: .buffering(initial: false, whilePlaying: action == .play)) self.playerStatus.set(.single(status)) } else { - let status = MediaPlayerStatus(generationTimestamp: CACurrentMediaTime(), duration: 0.0, dimensions: CGSize(), timestamp: 0.0, baseRate: self.baseRate, seekId: self.seekId, status: .buffering(initial: false, whilePlaying: action == .play)) + let duration = seekState?.duration ?? 0.0 + let status = MediaPlayerStatus(generationTimestamp: CACurrentMediaTime(), duration: duration, dimensions: CGSize(), timestamp: min(max(timestamp, 0.0), duration), baseRate: self.baseRate, seekId: self.seekId, status: .buffering(initial: false, whilePlaying: action == .play)) self.playerStatus.set(.single(status)) } let frameSource = FFMpegMediaFrameSource(queue: self.queue, postbox: self.postbox, resourceReference: self.resourceReference, streamable: self.streamable, video: self.video, preferSoftwareDecoding: self.preferSoftwareDecoding, fetchAutomatically: self.fetchAutomatically) let disposable = MetaDisposable() - self.state = .seeking(frameSource: frameSource, timestamp: timestamp, disposable: disposable, action: action, enableSound: self.enableSound) + let updatedSeekState: MediaPlayerSeekState? + if let loadedDuration = loadedDuration { + updatedSeekState = MediaPlayerSeekState(duration: loadedDuration) + } else { + updatedSeekState = seekState + } + self.state = .seeking(frameSource: frameSource, timestamp: timestamp, seekState: updatedSeekState, disposable: disposable, action: action, enableSound: self.enableSound) self.lastStatusUpdateTimestamp = nil @@ -270,7 +285,7 @@ private final class MediaPlayerContext { assert(self.queue.isCurrent()) - guard case let .seeking(frameSource, _, _, action, _) = self.state else { + guard case let .seeking(frameSource, _, _, _, action, _) = self.state else { assertionFailure() return } @@ -391,8 +406,8 @@ private final class MediaPlayerContext { renderer.start() } self.seek(timestamp: 0.0, action: .play) - case let .seeking(frameSource, timestamp, disposable, _, enableSound): - self.state = .seeking(frameSource: frameSource, timestamp: timestamp, disposable: disposable, action: .play, enableSound: enableSound) + case let .seeking(frameSource, timestamp, seekState, disposable, _, enableSound): + self.state = .seeking(frameSource: frameSource, timestamp: timestamp, seekState: seekState, disposable: disposable, action: .play, enableSound: enableSound) self.lastStatusUpdateTimestamp = nil case let .paused(loadedState): if loadedState.lostAudioSession { @@ -435,7 +450,7 @@ private final class MediaPlayerContext { loadedState = currentLoadedState case let .paused(currentLoadedState): loadedState = currentLoadedState - case let .seeking(_, timestamp, disposable, action, _): + case let .seeking(_, timestamp, _, disposable, action, _): if self.enableSound { self.state = .empty disposable.dispose() @@ -476,7 +491,7 @@ private final class MediaPlayerContext { switch self.state { case .playing: isPlaying = true - case let .seeking(_, _, _, action, _): + case let .seeking(_, _, _, _, action, _): switch action { case .play: isPlaying = true @@ -500,8 +515,8 @@ private final class MediaPlayerContext { switch self.state { case .empty: break - case let .seeking(frameSource, timestamp, disposable, _, enableSound): - self.state = .seeking(frameSource: frameSource, timestamp: timestamp, disposable: disposable, action: .pause, enableSound: enableSound) + case let .seeking(frameSource, timestamp, seekState, disposable, _, enableSound): + self.state = .seeking(frameSource: frameSource, timestamp: timestamp, seekState: seekState, disposable: disposable, action: .pause, enableSound: enableSound) self.lastStatusUpdateTimestamp = nil case let .paused(loadedState): if lostAudioSession { @@ -523,7 +538,7 @@ private final class MediaPlayerContext { switch self.state { case .empty: self.play() - case let .seeking(_, _, _, action, _): + case let .seeking(_, _, _, _, action, _): switch action { case .play: self.pause(lostAudioSession: false) @@ -712,7 +727,7 @@ private final class MediaPlayerContext { if self.lastStatusUpdateTimestamp == nil || self.lastStatusUpdateTimestamp! < statusTimestamp + 500 { lastStatusUpdateTimestamp = statusTimestamp var reportTimestamp = timestamp - if case .seeking(_, timestamp, _, _, _) = self.state { + if case .seeking(_, timestamp, _, _, _, _) = self.state { reportTimestamp = timestamp } let status = MediaPlayerStatus(generationTimestamp: statusTimestamp, duration: duration, dimensions: CGSize(), timestamp: min(max(reportTimestamp, 0.0), duration), baseRate: self.baseRate, seekId: self.seekId, status: playbackStatus) diff --git a/TelegramUI/MediaPlayerScrubbingNode.swift b/TelegramUI/MediaPlayerScrubbingNode.swift index b82244a758..81c5467f52 100644 --- a/TelegramUI/MediaPlayerScrubbingNode.swift +++ b/TelegramUI/MediaPlayerScrubbingNode.swift @@ -389,7 +389,12 @@ final class MediaPlayerScrubbingNode: ASDisplayNode { strongSelf._scrubbingTimestamp.set(.single(nil)) if let scrubbingTimestampValue = scrubbingTimestampValue, apply { if let statusValue = strongSelf.statusValue { - strongSelf.ignoreSeekId = statusValue.seekId + switch statusValue.status { + case .buffering: + break + default: + strongSelf.ignoreSeekId = statusValue.seekId + } } strongSelf.seek?(scrubbingTimestampValue) } diff --git a/TelegramUI/MentionChatInputPanelItem.swift b/TelegramUI/MentionChatInputPanelItem.swift index 682b5e3a74..a64706b04d 100644 --- a/TelegramUI/MentionChatInputPanelItem.swift +++ b/TelegramUI/MentionChatInputPanelItem.swift @@ -165,7 +165,7 @@ final class MentionChatInputPanelItemNode: ListViewItemNode { strongSelf.backgroundColor = item.theme.list.plainBackgroundColor strongSelf.highlightedBackgroundNode.backgroundColor = item.theme.list.itemHighlightedBackgroundColor - strongSelf.avatarNode.setPeer(account: item.account, peer: item.peer) + strongSelf.avatarNode.setPeer(account: item.account, peer: item.peer, emptyColor: item.theme.list.mediaPlaceholderColor) let _ = textApply() diff --git a/TelegramUI/PeerAvatar.swift b/TelegramUI/PeerAvatar.swift index 984f1b5f36..87835e8470 100644 --- a/TelegramUI/PeerAvatar.swift +++ b/TelegramUI/PeerAvatar.swift @@ -62,22 +62,24 @@ public func peerAvatarImageData(account: Account, peer: Peer, authorOfMessage: M } } -func peerAvatarImage(account: Account, peer: Peer, authorOfMessage: MessageReference?, representation: TelegramMediaImageRepresentation?, displayDimensions: CGSize = CGSize(width: 60.0, height: 60.0)) -> Signal? { +func peerAvatarImage(account: Account, peer: Peer, authorOfMessage: MessageReference?, representation: TelegramMediaImageRepresentation?, displayDimensions: CGSize = CGSize(width: 60.0, height: 60.0), emptyColor: UIColor? = nil) -> Signal? { if let imageData = peerAvatarImageData(account: account, peer: peer, authorOfMessage: authorOfMessage, representation: representation) { return imageData |> deliverOn(account.graphicsThreadPool) |> map { data -> UIImage? in - if let data = data, let image = generateImage(displayDimensions, contextGenerator: { size, context -> Void in - if let imageSource = CGImageSourceCreateWithData(data as CFData, nil), let dataImage = CGImageSourceCreateImageAtIndex(imageSource, 0, nil) { - context.setBlendMode(.copy) - context.draw(dataImage, in: CGRect(origin: CGPoint(), size: displayDimensions)) - context.setBlendMode(.destinationOut) - context.draw(roundCorners.cgImage!, in: CGRect(origin: CGPoint(), size: displayDimensions)) + return generateImage(displayDimensions, contextGenerator: { size, context -> Void in + if let data = data { + if let imageSource = CGImageSourceCreateWithData(data as CFData, nil), let dataImage = CGImageSourceCreateImageAtIndex(imageSource, 0, nil) { + context.setBlendMode(.copy) + context.draw(dataImage, in: CGRect(origin: CGPoint(), size: displayDimensions)) + context.setBlendMode(.destinationOut) + context.draw(roundCorners.cgImage!, in: CGRect(origin: CGPoint(), size: displayDimensions)) + } + } else if let emptyColor = emptyColor { + context.clear(CGRect(origin: CGPoint(), size: displayDimensions)) + context.setFillColor(emptyColor.cgColor) + context.fillEllipse(in: CGRect(origin: CGPoint(), size: displayDimensions)) } - }) { - return image - } else { - return nil - } + }) } } else { return nil diff --git a/TelegramUI/SearchPeerMembers.swift b/TelegramUI/SearchPeerMembers.swift index a1bcba2277..f0fe46f6fb 100644 --- a/TelegramUI/SearchPeerMembers.swift +++ b/TelegramUI/SearchPeerMembers.swift @@ -4,7 +4,7 @@ import TelegramCore import SwiftSignalKit func searchPeerMembers(account: Account, peerId: PeerId, query: String) -> Signal<[Peer], NoError> { - if peerId.namespace == Namespaces.Peer.CloudChannel && !query.isEmpty { + if peerId.namespace == Namespaces.Peer.CloudChannel { return account.postbox.transaction { transaction -> CachedChannelData? in return transaction.getPeerCachedData(peerId: peerId) as? CachedChannelData } @@ -18,15 +18,18 @@ func searchPeerMembers(account: Account, peerId: PeerId, query: String) -> Signa if normalizedQuery.isEmpty { return participant.peer } - - if participant.peer.indexName.matchesByTokens(normalizedQuery) { + if normalizedQuery.isEmpty { return participant.peer + } else { + if participant.peer.indexName.matchesByTokens(normalizedQuery) { + return participant.peer + } + if let addressName = participant.peer.addressName, addressName.lowercased().hasPrefix(normalizedQuery) { + return participant.peer + } + + return nil } - if let addressName = participant.peer.addressName, addressName.lowercased().hasPrefix(normalizedQuery) { - return participant.peer - } - - return nil }) } }) @@ -38,7 +41,7 @@ func searchPeerMembers(account: Account, peerId: PeerId, query: String) -> Signa } return Signal { subscriber in - let (disposable, _) = account.telegramApplicationContext.peerChannelMemberCategoriesContextsManager.recent(postbox: account.postbox, network: account.network, accountPeerId: account.peerId, peerId: peerId, searchQuery: query, updated: { state in + let (disposable, _) = account.telegramApplicationContext.peerChannelMemberCategoriesContextsManager.recent(postbox: account.postbox, network: account.network, accountPeerId: account.peerId, peerId: peerId, searchQuery: query.isEmpty ? nil : query, updated: { state in if case .ready = state.loadingState { subscriber.putNext(state.list.map { $0.peer }) } diff --git a/TelegramUI/SelectablePeerNode.swift b/TelegramUI/SelectablePeerNode.swift index 48ebbac22d..84a2ba77ba 100644 --- a/TelegramUI/SelectablePeerNode.swift +++ b/TelegramUI/SelectablePeerNode.swift @@ -17,14 +17,16 @@ final class SelectablePeerNodeTheme { let checkBackgroundColor: UIColor let checkFillColor: UIColor let checkColor: UIColor + let avatarPlaceholderColor: UIColor - init(textColor: UIColor, secretTextColor: UIColor, selectedTextColor: UIColor, checkBackgroundColor: UIColor, checkFillColor: UIColor, checkColor: UIColor) { + init(textColor: UIColor, secretTextColor: UIColor, selectedTextColor: UIColor, checkBackgroundColor: UIColor, checkFillColor: UIColor, checkColor: UIColor, avatarPlaceholderColor: UIColor) { self.textColor = textColor self.secretTextColor = secretTextColor self.selectedTextColor = selectedTextColor self.checkBackgroundColor = checkBackgroundColor self.checkFillColor = checkFillColor self.checkColor = checkColor + self.avatarPlaceholderColor = avatarPlaceholderColor } func isEqual(to: SelectablePeerNodeTheme) -> Bool { @@ -49,6 +51,9 @@ final class SelectablePeerNodeTheme { if !self.checkColor.isEqual(to.checkColor) { return false } + if !self.avatarPlaceholderColor.isEqual(to.avatarPlaceholderColor) { + return false + } return true } } @@ -67,7 +72,7 @@ final class SelectablePeerNode: ASDisplayNode { private var peer: RenderedPeer? - var theme: SelectablePeerNodeTheme = SelectablePeerNodeTheme(textColor: .black, secretTextColor: .green, selectedTextColor: .blue, checkBackgroundColor: .white, checkFillColor: .blue, checkColor: .white) { + var theme: SelectablePeerNodeTheme = SelectablePeerNodeTheme(textColor: .black, secretTextColor: .green, selectedTextColor: .blue, checkBackgroundColor: .white, checkFillColor: .blue, checkColor: .white, avatarPlaceholderColor: .white) { didSet { if !self.theme.isEqual(to: oldValue) { if let peer = self.peer, let mainPeer = peer.chatMainPeer { @@ -124,7 +129,7 @@ final class SelectablePeerNode: ASDisplayNode { } self.textNode.maximumNumberOfLines = UInt(numberOfLines) self.textNode.attributedText = NSAttributedString(string: text, font: textFont, textColor: self.currentSelected ? self.theme.selectedTextColor : defaultColor, paragraphAlignment: .center) - self.avatarNode.setPeer(account: account, peer: mainPeer, overrideImage: overrideImage) + self.avatarNode.setPeer(account: account, peer: mainPeer, overrideImage: overrideImage, emptyColor: self.theme.avatarPlaceholderColor) self.setNeedsLayout() } diff --git a/TelegramUI/ShareControllerPeerGridItem.swift b/TelegramUI/ShareControllerPeerGridItem.swift index eafdc1cbcc..0a1cf5cc55 100644 --- a/TelegramUI/ShareControllerPeerGridItem.swift +++ b/TelegramUI/ShareControllerPeerGridItem.swift @@ -146,7 +146,7 @@ final class ShareControllerPeerGridItemNode: GridItemNode { func setup(account: Account, theme: PresentationTheme, strings: PresentationStrings, peer: RenderedPeer, search: Bool) { if self.currentState == nil || self.currentState!.0 !== account || self.currentState!.1 != peer { - let itemTheme = SelectablePeerNodeTheme(textColor: theme.actionSheet.primaryTextColor, secretTextColor: theme.chatList.secretTitleColor, selectedTextColor: theme.actionSheet.controlAccentColor, checkBackgroundColor: theme.actionSheet.opaqueItemBackgroundColor, checkFillColor: theme.actionSheet.controlAccentColor, checkColor: theme.actionSheet.checkContentColor) + let itemTheme = SelectablePeerNodeTheme(textColor: theme.actionSheet.primaryTextColor, secretTextColor: theme.chatList.secretTitleColor, selectedTextColor: theme.actionSheet.controlAccentColor, checkBackgroundColor: theme.actionSheet.opaqueItemBackgroundColor, checkFillColor: theme.actionSheet.controlAccentColor, checkColor: theme.actionSheet.checkContentColor, avatarPlaceholderColor: theme.list.mediaPlaceholderColor) self.peerNode.theme = itemTheme self.peerNode.setup(account: account, strings: strings, peer: peer) self.currentState = (account, peer, search)