mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-12-22 22:25:57 +00:00
Various UI Fixes
This commit is contained in:
@@ -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 representation: TelegramMediaImageRepresentation?
|
||||||
var icon = AvatarNodeIcon.none
|
var icon = AvatarNodeIcon.none
|
||||||
if let overrideImage = overrideImage {
|
if let overrideImage = overrideImage {
|
||||||
@@ -222,7 +222,7 @@ public final class AvatarNode: ASDisplayNode {
|
|||||||
|
|
||||||
let theme = account.telegramApplicationContext.currentPresentationData.with { $0 }.theme
|
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.imageReady.set(self.imageNode.ready)
|
||||||
self.imageNode.setSignal(signal)
|
self.imageNode.setSignal(signal)
|
||||||
|
|
||||||
|
|||||||
@@ -430,7 +430,7 @@ class CallListCallItemNode: ItemListRevealOptionsItemNode {
|
|||||||
return (nodeLayout, { [weak self] in
|
return (nodeLayout, { [weak self] in
|
||||||
if let strongSelf = self {
|
if let strongSelf = self {
|
||||||
if let peer = item.topMessage.peers[item.topMessage.id.peerId] {
|
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
|
return (strongSelf.avatarNode.ready, { [weak strongSelf] animated in
|
||||||
|
|||||||
@@ -377,6 +377,7 @@ class ChatControllerNode: ASDisplayNode, UIScrollViewDelegate {
|
|||||||
if let (size, insets) = self.validEmptyNodeLayout {
|
if let (size, insets) = self.validEmptyNodeLayout {
|
||||||
emptyNode.updateLayout(interfaceState: self.chatPresentationInterfaceState, size: size, insets: insets, transition: .immediate)
|
emptyNode.updateLayout(interfaceState: self.chatPresentationInterfaceState, size: size, insets: insets, transition: .immediate)
|
||||||
}
|
}
|
||||||
|
emptyNode.isHidden = self.restrictedNode != nil
|
||||||
self.emptyNode = emptyNode
|
self.emptyNode = emptyNode
|
||||||
self.historyNodeContainer.supernode?.insertSubnode(emptyNode, aboveSubnode: self.historyNodeContainer)
|
self.historyNodeContainer.supernode?.insertSubnode(emptyNode, aboveSubnode: self.historyNodeContainer)
|
||||||
if animated {
|
if animated {
|
||||||
@@ -1330,12 +1331,14 @@ class ChatControllerNode: ASDisplayNode, UIScrollViewDelegate {
|
|||||||
self.historyNodeContainer.isHidden = true
|
self.historyNodeContainer.isHidden = true
|
||||||
self.navigateButtons.isHidden = true
|
self.navigateButtons.isHidden = true
|
||||||
self.loadingNode.isHidden = true
|
self.loadingNode.isHidden = true
|
||||||
|
self.emptyNode?.isHidden = true
|
||||||
} else if let restrictedNode = self.restrictedNode {
|
} else if let restrictedNode = self.restrictedNode {
|
||||||
self.restrictedNode = nil
|
self.restrictedNode = nil
|
||||||
restrictedNode.removeFromSupernode()
|
restrictedNode.removeFromSupernode()
|
||||||
self.historyNodeContainer.isHidden = false
|
self.historyNodeContainer.isHidden = false
|
||||||
self.navigateButtons.isHidden = false
|
self.navigateButtons.isHidden = false
|
||||||
self.loadingNode.isHidden = false
|
self.loadingNode.isHidden = false
|
||||||
|
self.emptyNode?.isHidden = false
|
||||||
}
|
}
|
||||||
|
|
||||||
let layoutTransition: ContainedViewLayoutTransition = transition
|
let layoutTransition: ContainedViewLayoutTransition = transition
|
||||||
|
|||||||
@@ -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 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))
|
let participants = combineLatest(inlineBots, searchPeerMembers(account: account, peerId: peer.id, query: query))
|
||||||
|> map { inlineBots, peers -> (ChatPresentationInputQueryResult?) -> ChatPresentationInputQueryResult? in
|
|> map { inlineBots, peers -> (ChatPresentationInputQueryResult?) -> ChatPresentationInputQueryResult? in
|
||||||
let filteredInlineBots = inlineBots.sorted(by: { $0.1 > $1.1 }).filter { peer, rating in
|
let filteredInlineBots = inlineBots.sorted(by: { $0.1 > $1.1 }).filter { peer, rating in
|
||||||
if rating < 0.14 {
|
if rating < 0.14 {
|
||||||
return false
|
|
||||||
}
|
|
||||||
if peer.indexName.matchesByTokens(normalizedQuery) {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
if let addressName = peer.addressName, addressName.lowercased().hasPrefix(normalizedQuery) {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
return false
|
return false
|
||||||
}.map { $0.0 }
|
}
|
||||||
|
if peer.indexName.matchesByTokens(normalizedQuery) {
|
||||||
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
|
return true
|
||||||
}
|
}
|
||||||
var sortedPeers = filteredInlineBots
|
if let addressName = peer.addressName, addressName.lowercased().hasPrefix(normalizedQuery) {
|
||||||
sortedPeers.append(contentsOf: filteredPeers.sorted(by: { lhs, rhs in
|
return true
|
||||||
let result = lhs.indexName.indexName(.lastNameFirst).compare(rhs.indexName.indexName(.lastNameFirst))
|
}
|
||||||
return result == .orderedAscending
|
return false
|
||||||
}))
|
}.map { $0.0 }
|
||||||
return { _ in return .mentions(sortedPeers) }
|
|
||||||
|
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)
|
return signal |> then(participants)
|
||||||
case let .command(query):
|
case let .command(query):
|
||||||
|
|||||||
@@ -339,7 +339,7 @@ class ChatListItemNode: ItemListRevealOptionsItemNode {
|
|||||||
if peer.id == item.account.peerId {
|
if peer.id == item.account.peerId {
|
||||||
overrideImage = .savedMessagesIcon
|
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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -11,13 +11,15 @@ final class ChatMessageAvatarAccessoryItem: ListViewAccessoryItem {
|
|||||||
private let peer: Peer?
|
private let peer: Peer?
|
||||||
private let messageReference: MessageReference?
|
private let messageReference: MessageReference?
|
||||||
private let messageTimestamp: Int32
|
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.account = account
|
||||||
self.peerId = peerId
|
self.peerId = peerId
|
||||||
self.peer = peer
|
self.peer = peer
|
||||||
self.messageReference = messageReference
|
self.messageReference = messageReference
|
||||||
self.messageTimestamp = messageTimestamp
|
self.messageTimestamp = messageTimestamp
|
||||||
|
self.emptyColor = emptyColor
|
||||||
}
|
}
|
||||||
|
|
||||||
func isEqualToItem(_ other: ListViewAccessoryItem) -> Bool {
|
func isEqualToItem(_ other: ListViewAccessoryItem) -> Bool {
|
||||||
@@ -32,7 +34,7 @@ final class ChatMessageAvatarAccessoryItem: ListViewAccessoryItem {
|
|||||||
let node = ChatMessageAvatarAccessoryItemNode()
|
let node = ChatMessageAvatarAccessoryItemNode()
|
||||||
node.frame = CGRect(origin: CGPoint(), size: CGSize(width: 38.0, height: 38.0))
|
node.frame = CGRect(origin: CGPoint(), size: CGSize(width: 38.0, height: 38.0))
|
||||||
if let peer = self.peer {
|
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
|
return node
|
||||||
}
|
}
|
||||||
@@ -52,7 +54,7 @@ final class ChatMessageAvatarAccessoryItemNode: ListViewAccessoryItemNode {
|
|||||||
self.addSubnode(self.avatarNode)
|
self.addSubnode(self.avatarNode)
|
||||||
}
|
}
|
||||||
|
|
||||||
func setPeer(account: Account, peer: Peer, authorOfMessage: MessageReference?) {
|
func setPeer(account: Account, peer: Peer, authorOfMessage: MessageReference?, emptyColor: UIColor) {
|
||||||
self.avatarNode.setPeer(account: account, peer: peer, authorOfMessage: authorOfMessage)
|
self.avatarNode.setPeer(account: account, peer: peer, authorOfMessage: authorOfMessage, emptyColor: emptyColor)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -184,6 +184,7 @@ class ChatMessageContactBubbleContentNode: ChatMessageBubbleContentNode {
|
|||||||
let buttonHighlightedImage: UIImage
|
let buttonHighlightedImage: UIImage
|
||||||
let titleColor: UIColor
|
let titleColor: UIColor
|
||||||
let titleHighlightedColor: UIColor
|
let titleHighlightedColor: UIColor
|
||||||
|
let avatarPlaceholderColor: UIColor
|
||||||
if item.message.effectivelyIncoming(item.account.peerId) {
|
if item.message.effectivelyIncoming(item.account.peerId) {
|
||||||
buttonImage = PresentationResourcesChat.chatMessageAttachedContentButtonIncoming(item.presentationData.theme.theme)!
|
buttonImage = PresentationResourcesChat.chatMessageAttachedContentButtonIncoming(item.presentationData.theme.theme)!
|
||||||
buttonHighlightedImage = PresentationResourcesChat.chatMessageAttachedContentHighlightedButtonIncoming(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)
|
let bubbleColors = bubbleColorComponents(theme: item.presentationData.theme.theme, incoming: true, wallpaper: !item.presentationData.theme.wallpaper.isEmpty)
|
||||||
titleHighlightedColor = bubbleColors.fill
|
titleHighlightedColor = bubbleColors.fill
|
||||||
|
avatarPlaceholderColor = item.presentationData.theme.theme.chat.bubble.incomingMediaPlaceholderColor
|
||||||
} else {
|
} else {
|
||||||
buttonImage = PresentationResourcesChat.chatMessageAttachedContentButtonOutgoing(item.presentationData.theme.theme)!
|
buttonImage = PresentationResourcesChat.chatMessageAttachedContentButtonOutgoing(item.presentationData.theme.theme)!
|
||||||
buttonHighlightedImage = PresentationResourcesChat.chatMessageAttachedContentHighlightedButtonOutgoing(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)
|
let bubbleColors = bubbleColorComponents(theme: item.presentationData.theme.theme, incoming: false, wallpaper: !item.presentationData.theme.wallpaper.isEmpty)
|
||||||
titleHighlightedColor = bubbleColors.fill
|
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)
|
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] {
|
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 {
|
} else {
|
||||||
strongSelf.avatarNode.setCustomLetters(customLetters)
|
strongSelf.avatarNode.setCustomLetters(customLetters)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -475,7 +475,9 @@ final class ChatMessageInteractiveMediaNode: ASDisplayNode {
|
|||||||
} else if let image = media as? TelegramMediaWebFile {
|
} else if let image = media as? TelegramMediaWebFile {
|
||||||
strongSelf.fetchDisposable.set(chatMessageWebFileInteractiveFetched(account: account, image: image).start())
|
strongSelf.fetchDisposable.set(chatMessageWebFileInteractiveFetched(account: account, image: image).start())
|
||||||
} else if let file = media as? TelegramMediaFile {
|
} 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 {
|
} else if previousAutomaticDownload != automaticDownload, automaticDownload {
|
||||||
|
|||||||
@@ -307,7 +307,7 @@ public final class ChatMessageItem: ListViewItem, CustomStringConvertible {
|
|||||||
}
|
}
|
||||||
if !hasActionMedia && !isBroadcastChannel {
|
if !hasActionMedia && !isBroadcastChannel {
|
||||||
if let effectiveAuthor = effectiveAuthor {
|
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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -92,7 +92,7 @@ final class ChatMessageNotificationItemNode: NotificationItemNode {
|
|||||||
|
|
||||||
var title: String?
|
var title: String?
|
||||||
if let firstMessage = item.messages.first, let peer = messageMainPeer(firstMessage) {
|
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 {
|
if let channel = peer as? TelegramChannel, case .broadcast = channel.info {
|
||||||
title = peer.displayTitle
|
title = peer.displayTitle
|
||||||
|
|||||||
@@ -383,26 +383,39 @@ final class ChatTitleView: UIView, NavigationBarTitleView {
|
|||||||
}
|
}
|
||||||
} else if let channel = peer as? TelegramChannel {
|
} else if let channel = peer as? TelegramChannel {
|
||||||
if let cachedChannelData = peerView.cachedData as? CachedChannelData, let memberCount = cachedChannelData.participantsSummary.memberCount {
|
if let cachedChannelData = peerView.cachedData as? CachedChannelData, let memberCount = cachedChannelData.participantsSummary.memberCount {
|
||||||
if case .group = channel.info, let onlineMemberCount = onlineMemberCount, onlineMemberCount > 1 {
|
if memberCount == 0 {
|
||||||
let string = NSMutableAttributedString()
|
let string: NSAttributedString
|
||||||
|
if case .group = channel.info {
|
||||||
string.append(NSAttributedString(string: "\(strings.Conversation_StatusMembers(Int32(memberCount))), ", font: Font.regular(13.0), textColor: self.theme.rootController.navigationBar.secondaryTextColor))
|
string = NSAttributedString(string: strings.Group_Status, 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))
|
} 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) {
|
if self.infoNode.attributedText == nil || !self.infoNode.attributedText!.isEqual(to: string) {
|
||||||
self.infoNode.attributedText = string
|
self.infoNode.attributedText = string
|
||||||
shouldUpdateLayout = true
|
shouldUpdateLayout = true
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
let membersString: String
|
if case .group = channel.info, let onlineMemberCount = onlineMemberCount, onlineMemberCount > 1 {
|
||||||
if case .group = channel.info {
|
let string = NSMutableAttributedString()
|
||||||
membersString = strings.Conversation_StatusMembers(memberCount)
|
|
||||||
|
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 {
|
} else {
|
||||||
membersString = strings.Conversation_StatusSubscribers(memberCount)
|
let membersString: String
|
||||||
}
|
if case .group = channel.info {
|
||||||
let string = NSAttributedString(string: membersString, font: Font.regular(13.0), textColor: self.theme.rootController.navigationBar.secondaryTextColor)
|
membersString = strings.Conversation_StatusMembers(memberCount)
|
||||||
if self.infoNode.attributedText == nil || !self.infoNode.attributedText!.isEqual(to: string) {
|
} else {
|
||||||
self.infoNode.attributedText = string
|
membersString = strings.Conversation_StatusSubscribers(memberCount)
|
||||||
shouldUpdateLayout = true
|
}
|
||||||
|
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 {
|
} else {
|
||||||
|
|||||||
@@ -156,7 +156,7 @@ final class CommandChatInputPanelItemNode: ListViewItemNode {
|
|||||||
|
|
||||||
strongSelf.arrowNode.setImage(iconImage, for: [])
|
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()
|
let _ = textApply()
|
||||||
|
|
||||||
|
|||||||
@@ -567,7 +567,7 @@ class ContactsPeerItemNode: ItemListRevealOptionsItemNode {
|
|||||||
if peer.id == item.account.peerId, case .generalSearch = item.peerMode {
|
if peer.id == item.account.peerId, case .generalSearch = item.peerMode {
|
||||||
overrideImage = .savedMessagesIcon
|
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):
|
case let .deviceContact(_, contact):
|
||||||
let letters: [String]
|
let letters: [String]
|
||||||
|
|||||||
@@ -124,9 +124,9 @@ final class HorizontalPeerItemNode: ListViewItemNode {
|
|||||||
let itemTheme: SelectablePeerNodeTheme
|
let itemTheme: SelectablePeerNodeTheme
|
||||||
switch item.mode {
|
switch item.mode {
|
||||||
case .list:
|
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:
|
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 currentBadgeBackgroundImage: UIImage?
|
||||||
let badgeAttributedString: NSAttributedString
|
let badgeAttributedString: NSAttributedString
|
||||||
|
|||||||
@@ -622,7 +622,7 @@ class ItemListAvatarAndNameInfoItemNode: ListViewItemNode, ItemListItemNode, Ite
|
|||||||
} else if case .editSettings = item.mode {
|
} else if case .editSettings = item.mode {
|
||||||
overrideImage = AvatarNodeImageOverride.editAvatarIcon
|
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))
|
let avatarFrame = CGRect(origin: CGPoint(x: params.leftInset + 15.0, y: avatarOriginY), size: CGSize(width: 66.0, height: 66.0))
|
||||||
|
|||||||
@@ -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)))
|
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 {
|
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 {
|
} 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))
|
strongSelf.highlightedBackgroundNode.frame = CGRect(origin: CGPoint(x: 0.0, y: -UIScreenPixel), size: CGSize(width: params.width, height: 48.0 + UIScreenPixel + UIScreenPixel))
|
||||||
|
|||||||
@@ -39,7 +39,7 @@ final class JoinLinkPreviewPeerContentNode: ASDisplayNode, ShareContentContainer
|
|||||||
self.peersScrollNode = ASScrollNode()
|
self.peersScrollNode = ASScrollNode()
|
||||||
self.peersScrollNode.view.showsHorizontalScrollIndicator = false
|
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
|
self.peerNodes = members.map { peer in
|
||||||
let node = SelectablePeerNode()
|
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)
|
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.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.addSubnode(self.titleNode)
|
||||||
self.titleNode.attributedText = NSAttributedString(string: title, font: Font.semibold(16.0), textColor: theme.actionSheet.primaryTextColor)
|
self.titleNode.attributedText = NSAttributedString(string: title, font: Font.semibold(16.0), textColor: theme.actionSheet.primaryTextColor)
|
||||||
|
|||||||
@@ -29,9 +29,13 @@ private final class MediaPlayerLoadedState {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private struct MediaPlayerSeekState {
|
||||||
|
let duration: Double
|
||||||
|
}
|
||||||
|
|
||||||
private enum MediaPlayerState {
|
private enum MediaPlayerState {
|
||||||
case empty
|
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 paused(MediaPlayerLoadedState)
|
||||||
case playing(MediaPlayerLoadedState)
|
case playing(MediaPlayerLoadedState)
|
||||||
}
|
}
|
||||||
@@ -119,7 +123,7 @@ private final class MediaPlayerContext {
|
|||||||
if !value {
|
if !value {
|
||||||
strongSelf.pause(lostAudioSession: false)
|
strongSelf.pause(lostAudioSession: false)
|
||||||
}
|
}
|
||||||
case let .seeking(_, _, _, action, _):
|
case let .seeking(_, _, _, _, action, _):
|
||||||
switch action {
|
switch action {
|
||||||
case .pause:
|
case .pause:
|
||||||
if value {
|
if value {
|
||||||
@@ -167,7 +171,7 @@ private final class MediaPlayerContext {
|
|||||||
|
|
||||||
self.tickTimer?.invalidate()
|
self.tickTimer?.invalidate()
|
||||||
|
|
||||||
if case let .seeking(_, _, disposable, _, _) = self.state {
|
if case let .seeking(_, _, _, disposable, _, _) = self.state {
|
||||||
disposable.dispose()
|
disposable.dispose()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -181,7 +185,7 @@ private final class MediaPlayerContext {
|
|||||||
action = .pause
|
action = .pause
|
||||||
case .playing:
|
case .playing:
|
||||||
action = .play
|
action = .play
|
||||||
case let .seeking(_, _, _, currentAction, _):
|
case let .seeking(_, _, _, _, currentAction, _):
|
||||||
action = currentAction
|
action = currentAction
|
||||||
}
|
}
|
||||||
self.seek(timestamp: timestamp, action: action)
|
self.seek(timestamp: timestamp, action: action)
|
||||||
@@ -191,6 +195,7 @@ private final class MediaPlayerContext {
|
|||||||
assert(self.queue.isCurrent())
|
assert(self.queue.isCurrent())
|
||||||
|
|
||||||
var loadedState: MediaPlayerLoadedState?
|
var loadedState: MediaPlayerLoadedState?
|
||||||
|
var seekState: MediaPlayerSeekState?
|
||||||
switch self.state {
|
switch self.state {
|
||||||
case .empty:
|
case .empty:
|
||||||
break
|
break
|
||||||
@@ -198,16 +203,18 @@ private final class MediaPlayerContext {
|
|||||||
loadedState = currentLoadedState
|
loadedState = currentLoadedState
|
||||||
case let .paused(currentLoadedState):
|
case let .paused(currentLoadedState):
|
||||||
loadedState = 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 {
|
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
|
return
|
||||||
} else {
|
} else {
|
||||||
|
seekState = seekStateValue
|
||||||
previousDisposable.dispose()
|
previousDisposable.dispose()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
self.tickTimer?.invalidate()
|
self.tickTimer?.invalidate()
|
||||||
|
var loadedDuration: Double?
|
||||||
if let loadedState = loadedState {
|
if let loadedState = loadedState {
|
||||||
self.seekId += 1
|
self.seekId += 1
|
||||||
|
|
||||||
@@ -231,16 +238,24 @@ private final class MediaPlayerContext {
|
|||||||
audioStatus = audioTrackFrameBuffer.status(at: currentTimestamp)
|
audioStatus = audioTrackFrameBuffer.status(at: currentTimestamp)
|
||||||
duration = max(duration, CMTimeGetSeconds(audioTrackFrameBuffer.duration))
|
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))
|
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))
|
self.playerStatus.set(.single(status))
|
||||||
} else {
|
} 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))
|
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 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()
|
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
|
self.lastStatusUpdateTimestamp = nil
|
||||||
|
|
||||||
@@ -270,7 +285,7 @@ private final class MediaPlayerContext {
|
|||||||
|
|
||||||
assert(self.queue.isCurrent())
|
assert(self.queue.isCurrent())
|
||||||
|
|
||||||
guard case let .seeking(frameSource, _, _, action, _) = self.state else {
|
guard case let .seeking(frameSource, _, _, _, action, _) = self.state else {
|
||||||
assertionFailure()
|
assertionFailure()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -391,8 +406,8 @@ private final class MediaPlayerContext {
|
|||||||
renderer.start()
|
renderer.start()
|
||||||
}
|
}
|
||||||
self.seek(timestamp: 0.0, action: .play)
|
self.seek(timestamp: 0.0, action: .play)
|
||||||
case let .seeking(frameSource, timestamp, disposable, _, enableSound):
|
case let .seeking(frameSource, timestamp, seekState, disposable, _, enableSound):
|
||||||
self.state = .seeking(frameSource: frameSource, timestamp: timestamp, disposable: disposable, action: .play, enableSound: enableSound)
|
self.state = .seeking(frameSource: frameSource, timestamp: timestamp, seekState: seekState, disposable: disposable, action: .play, enableSound: enableSound)
|
||||||
self.lastStatusUpdateTimestamp = nil
|
self.lastStatusUpdateTimestamp = nil
|
||||||
case let .paused(loadedState):
|
case let .paused(loadedState):
|
||||||
if loadedState.lostAudioSession {
|
if loadedState.lostAudioSession {
|
||||||
@@ -435,7 +450,7 @@ private final class MediaPlayerContext {
|
|||||||
loadedState = currentLoadedState
|
loadedState = currentLoadedState
|
||||||
case let .paused(currentLoadedState):
|
case let .paused(currentLoadedState):
|
||||||
loadedState = currentLoadedState
|
loadedState = currentLoadedState
|
||||||
case let .seeking(_, timestamp, disposable, action, _):
|
case let .seeking(_, timestamp, _, disposable, action, _):
|
||||||
if self.enableSound {
|
if self.enableSound {
|
||||||
self.state = .empty
|
self.state = .empty
|
||||||
disposable.dispose()
|
disposable.dispose()
|
||||||
@@ -476,7 +491,7 @@ private final class MediaPlayerContext {
|
|||||||
switch self.state {
|
switch self.state {
|
||||||
case .playing:
|
case .playing:
|
||||||
isPlaying = true
|
isPlaying = true
|
||||||
case let .seeking(_, _, _, action, _):
|
case let .seeking(_, _, _, _, action, _):
|
||||||
switch action {
|
switch action {
|
||||||
case .play:
|
case .play:
|
||||||
isPlaying = true
|
isPlaying = true
|
||||||
@@ -500,8 +515,8 @@ private final class MediaPlayerContext {
|
|||||||
switch self.state {
|
switch self.state {
|
||||||
case .empty:
|
case .empty:
|
||||||
break
|
break
|
||||||
case let .seeking(frameSource, timestamp, disposable, _, enableSound):
|
case let .seeking(frameSource, timestamp, seekState, disposable, _, enableSound):
|
||||||
self.state = .seeking(frameSource: frameSource, timestamp: timestamp, disposable: disposable, action: .pause, enableSound: enableSound)
|
self.state = .seeking(frameSource: frameSource, timestamp: timestamp, seekState: seekState, disposable: disposable, action: .pause, enableSound: enableSound)
|
||||||
self.lastStatusUpdateTimestamp = nil
|
self.lastStatusUpdateTimestamp = nil
|
||||||
case let .paused(loadedState):
|
case let .paused(loadedState):
|
||||||
if lostAudioSession {
|
if lostAudioSession {
|
||||||
@@ -523,7 +538,7 @@ private final class MediaPlayerContext {
|
|||||||
switch self.state {
|
switch self.state {
|
||||||
case .empty:
|
case .empty:
|
||||||
self.play()
|
self.play()
|
||||||
case let .seeking(_, _, _, action, _):
|
case let .seeking(_, _, _, _, action, _):
|
||||||
switch action {
|
switch action {
|
||||||
case .play:
|
case .play:
|
||||||
self.pause(lostAudioSession: false)
|
self.pause(lostAudioSession: false)
|
||||||
@@ -712,7 +727,7 @@ private final class MediaPlayerContext {
|
|||||||
if self.lastStatusUpdateTimestamp == nil || self.lastStatusUpdateTimestamp! < statusTimestamp + 500 {
|
if self.lastStatusUpdateTimestamp == nil || self.lastStatusUpdateTimestamp! < statusTimestamp + 500 {
|
||||||
lastStatusUpdateTimestamp = statusTimestamp
|
lastStatusUpdateTimestamp = statusTimestamp
|
||||||
var reportTimestamp = timestamp
|
var reportTimestamp = timestamp
|
||||||
if case .seeking(_, timestamp, _, _, _) = self.state {
|
if case .seeking(_, timestamp, _, _, _, _) = self.state {
|
||||||
reportTimestamp = timestamp
|
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)
|
let status = MediaPlayerStatus(generationTimestamp: statusTimestamp, duration: duration, dimensions: CGSize(), timestamp: min(max(reportTimestamp, 0.0), duration), baseRate: self.baseRate, seekId: self.seekId, status: playbackStatus)
|
||||||
|
|||||||
@@ -389,7 +389,12 @@ final class MediaPlayerScrubbingNode: ASDisplayNode {
|
|||||||
strongSelf._scrubbingTimestamp.set(.single(nil))
|
strongSelf._scrubbingTimestamp.set(.single(nil))
|
||||||
if let scrubbingTimestampValue = scrubbingTimestampValue, apply {
|
if let scrubbingTimestampValue = scrubbingTimestampValue, apply {
|
||||||
if let statusValue = strongSelf.statusValue {
|
if let statusValue = strongSelf.statusValue {
|
||||||
strongSelf.ignoreSeekId = statusValue.seekId
|
switch statusValue.status {
|
||||||
|
case .buffering:
|
||||||
|
break
|
||||||
|
default:
|
||||||
|
strongSelf.ignoreSeekId = statusValue.seekId
|
||||||
|
}
|
||||||
}
|
}
|
||||||
strongSelf.seek?(scrubbingTimestampValue)
|
strongSelf.seek?(scrubbingTimestampValue)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -165,7 +165,7 @@ final class MentionChatInputPanelItemNode: ListViewItemNode {
|
|||||||
strongSelf.backgroundColor = item.theme.list.plainBackgroundColor
|
strongSelf.backgroundColor = item.theme.list.plainBackgroundColor
|
||||||
strongSelf.highlightedBackgroundNode.backgroundColor = item.theme.list.itemHighlightedBackgroundColor
|
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()
|
let _ = textApply()
|
||||||
|
|
||||||
|
|||||||
@@ -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<UIImage?, NoError>? {
|
func peerAvatarImage(account: Account, peer: Peer, authorOfMessage: MessageReference?, representation: TelegramMediaImageRepresentation?, displayDimensions: CGSize = CGSize(width: 60.0, height: 60.0), emptyColor: UIColor? = nil) -> Signal<UIImage?, NoError>? {
|
||||||
if let imageData = peerAvatarImageData(account: account, peer: peer, authorOfMessage: authorOfMessage, representation: representation) {
|
if let imageData = peerAvatarImageData(account: account, peer: peer, authorOfMessage: authorOfMessage, representation: representation) {
|
||||||
return imageData |> deliverOn(account.graphicsThreadPool)
|
return imageData |> deliverOn(account.graphicsThreadPool)
|
||||||
|> map { data -> UIImage? in
|
|> map { data -> UIImage? in
|
||||||
if let data = data, let image = generateImage(displayDimensions, contextGenerator: { size, context -> Void in
|
return generateImage(displayDimensions, contextGenerator: { size, context -> Void in
|
||||||
if let imageSource = CGImageSourceCreateWithData(data as CFData, nil), let dataImage = CGImageSourceCreateImageAtIndex(imageSource, 0, nil) {
|
if let data = data {
|
||||||
context.setBlendMode(.copy)
|
if let imageSource = CGImageSourceCreateWithData(data as CFData, nil), let dataImage = CGImageSourceCreateImageAtIndex(imageSource, 0, nil) {
|
||||||
context.draw(dataImage, in: CGRect(origin: CGPoint(), size: displayDimensions))
|
context.setBlendMode(.copy)
|
||||||
context.setBlendMode(.destinationOut)
|
context.draw(dataImage, in: CGRect(origin: CGPoint(), size: displayDimensions))
|
||||||
context.draw(roundCorners.cgImage!, 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 {
|
} else {
|
||||||
return nil
|
return nil
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import TelegramCore
|
|||||||
import SwiftSignalKit
|
import SwiftSignalKit
|
||||||
|
|
||||||
func searchPeerMembers(account: Account, peerId: PeerId, query: String) -> Signal<[Peer], NoError> {
|
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 account.postbox.transaction { transaction -> CachedChannelData? in
|
||||||
return transaction.getPeerCachedData(peerId: peerId) as? CachedChannelData
|
return transaction.getPeerCachedData(peerId: peerId) as? CachedChannelData
|
||||||
}
|
}
|
||||||
@@ -18,15 +18,18 @@ func searchPeerMembers(account: Account, peerId: PeerId, query: String) -> Signa
|
|||||||
if normalizedQuery.isEmpty {
|
if normalizedQuery.isEmpty {
|
||||||
return participant.peer
|
return participant.peer
|
||||||
}
|
}
|
||||||
|
if normalizedQuery.isEmpty {
|
||||||
if participant.peer.indexName.matchesByTokens(normalizedQuery) {
|
|
||||||
return participant.peer
|
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
|
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 {
|
if case .ready = state.loadingState {
|
||||||
subscriber.putNext(state.list.map { $0.peer })
|
subscriber.putNext(state.list.map { $0.peer })
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,14 +17,16 @@ final class SelectablePeerNodeTheme {
|
|||||||
let checkBackgroundColor: UIColor
|
let checkBackgroundColor: UIColor
|
||||||
let checkFillColor: UIColor
|
let checkFillColor: UIColor
|
||||||
let checkColor: 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.textColor = textColor
|
||||||
self.secretTextColor = secretTextColor
|
self.secretTextColor = secretTextColor
|
||||||
self.selectedTextColor = selectedTextColor
|
self.selectedTextColor = selectedTextColor
|
||||||
self.checkBackgroundColor = checkBackgroundColor
|
self.checkBackgroundColor = checkBackgroundColor
|
||||||
self.checkFillColor = checkFillColor
|
self.checkFillColor = checkFillColor
|
||||||
self.checkColor = checkColor
|
self.checkColor = checkColor
|
||||||
|
self.avatarPlaceholderColor = avatarPlaceholderColor
|
||||||
}
|
}
|
||||||
|
|
||||||
func isEqual(to: SelectablePeerNodeTheme) -> Bool {
|
func isEqual(to: SelectablePeerNodeTheme) -> Bool {
|
||||||
@@ -49,6 +51,9 @@ final class SelectablePeerNodeTheme {
|
|||||||
if !self.checkColor.isEqual(to.checkColor) {
|
if !self.checkColor.isEqual(to.checkColor) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
if !self.avatarPlaceholderColor.isEqual(to.avatarPlaceholderColor) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -67,7 +72,7 @@ final class SelectablePeerNode: ASDisplayNode {
|
|||||||
|
|
||||||
private var peer: RenderedPeer?
|
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 {
|
didSet {
|
||||||
if !self.theme.isEqual(to: oldValue) {
|
if !self.theme.isEqual(to: oldValue) {
|
||||||
if let peer = self.peer, let mainPeer = peer.chatMainPeer {
|
if let peer = self.peer, let mainPeer = peer.chatMainPeer {
|
||||||
@@ -124,7 +129,7 @@ final class SelectablePeerNode: ASDisplayNode {
|
|||||||
}
|
}
|
||||||
self.textNode.maximumNumberOfLines = UInt(numberOfLines)
|
self.textNode.maximumNumberOfLines = UInt(numberOfLines)
|
||||||
self.textNode.attributedText = NSAttributedString(string: text, font: textFont, textColor: self.currentSelected ? self.theme.selectedTextColor : defaultColor, paragraphAlignment: .center)
|
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()
|
self.setNeedsLayout()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -146,7 +146,7 @@ final class ShareControllerPeerGridItemNode: GridItemNode {
|
|||||||
|
|
||||||
func setup(account: Account, theme: PresentationTheme, strings: PresentationStrings, peer: RenderedPeer, search: Bool) {
|
func setup(account: Account, theme: PresentationTheme, strings: PresentationStrings, peer: RenderedPeer, search: Bool) {
|
||||||
if self.currentState == nil || self.currentState!.0 !== account || self.currentState!.1 != peer {
|
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.theme = itemTheme
|
||||||
self.peerNode.setup(account: account, strings: strings, peer: peer)
|
self.peerNode.setup(account: account, strings: strings, peer: peer)
|
||||||
self.currentState = (account, peer, search)
|
self.currentState = (account, peer, search)
|
||||||
|
|||||||
Reference in New Issue
Block a user