Merge branch 'master' of gitlab.com:peter-iakovlev/telegram-ios into mac-video-calls-temp

# Conflicts:
#	submodules/TgVoipWebrtc/PublicHeaders/TgVoip/OngoingCallThreadLocalContext.h
#	submodules/TgVoipWebrtc/Sources/OngoingCallThreadLocalContext.mm
This commit is contained in:
overtake 2020-08-24 13:26:29 +03:00
commit 287e37850c
62 changed files with 3136 additions and 3021 deletions

View File

@ -2446,6 +2446,7 @@ Unused sets are archived when you add more.";
"Call.StatusBar" = "Touch to return to call %@"; "Call.StatusBar" = "Touch to return to call %@";
"Call.ParticipantVersionOutdatedError" = "%@'s app does not support calls. They need to update their app before you can call them."; "Call.ParticipantVersionOutdatedError" = "%@'s app does not support calls. They need to update their app before you can call them.";
"Call.ParticipantVideoVersionOutdatedError" = "%@'s app does not support video calls. They need to update their app before you can call them.";
"Privacy.Calls" = "Voice Calls"; "Privacy.Calls" = "Voice Calls";
@ -2755,6 +2756,7 @@ Unused sets are archived when you add more.";
"Channel.EditAdmin.CannotEdit" = "You cannot edit the rights of this admin."; "Channel.EditAdmin.CannotEdit" = "You cannot edit the rights of this admin.";
"Call.RateCall" = "Rate This Call"; "Call.RateCall" = "Rate This Call";
"Call.ShareStats" = "Share Statistics";
"Settings.ApplyProxyAlert" = "Are you sure you want to enable this proxy?\nServer: %1$@\nPort: %2$@\n\nYou can change your proxy server later it in the Settings (Data and Storage)."; "Settings.ApplyProxyAlert" = "Are you sure you want to enable this proxy?\nServer: %1$@\nPort: %2$@\n\nYou can change your proxy server later it in the Settings (Data and Storage).";
"Settings.ApplyProxyAlertCredentials" = "Are you sure you want to enable this proxy?\nServer: %1$@\nPort: %2$@\nUsername: %3$@\nPassword: %4$@\n\nYou can change your proxy server later it in the Settings (Data and Storage)."; "Settings.ApplyProxyAlertCredentials" = "Are you sure you want to enable this proxy?\nServer: %1$@\nPort: %2$@\nUsername: %3$@\nPassword: %4$@\n\nYou can change your proxy server later it in the Settings (Data and Storage).";
@ -4002,6 +4004,8 @@ Unused sets are archived when you add more.";
"CallFeedback.ReasonSilentLocal" = "I couldn't hear the other side"; "CallFeedback.ReasonSilentLocal" = "I couldn't hear the other side";
"CallFeedback.ReasonSilentRemote" = "The other side couldn't hear me"; "CallFeedback.ReasonSilentRemote" = "The other side couldn't hear me";
"CallFeedback.ReasonDropped" = "Call ended unexpectedly"; "CallFeedback.ReasonDropped" = "Call ended unexpectedly";
"CallFeedback.VideoReasonDistorted" = "Video was distorted";
"CallFeedback.VideoReasonLowQuality" = "Video was pixelated";
"CallFeedback.AddComment" = "Add an optional comment"; "CallFeedback.AddComment" = "Add an optional comment";
"CallFeedback.IncludeLogs" = "Include technical information"; "CallFeedback.IncludeLogs" = "Include technical information";
"CallFeedback.IncludeLogsInfo" = "This won't reveal the contents of your conversation, but will help us fix the issue sooner."; "CallFeedback.IncludeLogsInfo" = "This won't reveal the contents of your conversation, but will help us fix the issue sooner.";

View File

@ -1 +1 @@
2.2.0 3.4.1

View File

@ -531,7 +531,7 @@ public protocol SharedAccountContext: class {
func makeComposeController(context: AccountContext) -> ViewController func makeComposeController(context: AccountContext) -> ViewController
func makeChatListController(context: AccountContext, groupId: PeerGroupId, controlsHistoryPreload: Bool, hideNetworkActivityStatus: Bool, previewing: Bool, enableDebugActions: Bool) -> ChatListController func makeChatListController(context: AccountContext, groupId: PeerGroupId, controlsHistoryPreload: Bool, hideNetworkActivityStatus: Bool, previewing: Bool, enableDebugActions: Bool) -> ChatListController
func makeChatController(context: AccountContext, chatLocation: ChatLocation, subject: ChatControllerSubject?, botStart: ChatControllerInitialBotStart?, mode: ChatControllerPresentationMode) -> ChatController func makeChatController(context: AccountContext, chatLocation: ChatLocation, subject: ChatControllerSubject?, botStart: ChatControllerInitialBotStart?, mode: ChatControllerPresentationMode) -> ChatController
func makeChatMessagePreviewItem(context: AccountContext, message: Message, theme: PresentationTheme, strings: PresentationStrings, wallpaper: TelegramWallpaper, fontSize: PresentationFontSize, chatBubbleCorners: PresentationChatBubbleCorners, dateTimeFormat: PresentationDateTimeFormat, nameOrder: PresentationPersonNameOrder, forcedResourceStatus: FileMediaResourceStatus?, tapMessage: ((Message) -> Void)?, clickThroughMessage: (() -> Void)?) -> ListViewItem func makeChatMessagePreviewItem(context: AccountContext, messages: [Message], theme: PresentationTheme, strings: PresentationStrings, wallpaper: TelegramWallpaper, fontSize: PresentationFontSize, chatBubbleCorners: PresentationChatBubbleCorners, dateTimeFormat: PresentationDateTimeFormat, nameOrder: PresentationPersonNameOrder, forcedResourceStatus: FileMediaResourceStatus?, tapMessage: ((Message) -> Void)?, clickThroughMessage: (() -> Void)?) -> ListViewItem
func makeChatMessageDateHeaderItem(context: AccountContext, timestamp: Int32, theme: PresentationTheme, strings: PresentationStrings, wallpaper: TelegramWallpaper, fontSize: PresentationFontSize, chatBubbleCorners: PresentationChatBubbleCorners, dateTimeFormat: PresentationDateTimeFormat, nameOrder: PresentationPersonNameOrder) -> ListViewItemHeader func makeChatMessageDateHeaderItem(context: AccountContext, timestamp: Int32, theme: PresentationTheme, strings: PresentationStrings, wallpaper: TelegramWallpaper, fontSize: PresentationFontSize, chatBubbleCorners: PresentationChatBubbleCorners, dateTimeFormat: PresentationDateTimeFormat, nameOrder: PresentationPersonNameOrder) -> ListViewItemHeader
func makePeerSharedMediaController(context: AccountContext, peerId: PeerId) -> ViewController? func makePeerSharedMediaController(context: AccountContext, peerId: PeerId) -> ViewController?
func makeContactSelectionController(_ params: ContactSelectionControllerParams) -> ContactSelectionController func makeContactSelectionController(_ params: ContactSelectionControllerParams) -> ContactSelectionController

View File

@ -94,19 +94,22 @@ public final class PresentationCallVideoView {
public let setOnFirstFrameReceived: (((Float) -> Void)?) -> Void public let setOnFirstFrameReceived: (((Float) -> Void)?) -> Void
public let getOrientation: () -> Orientation public let getOrientation: () -> Orientation
public let setOnOrientationUpdated: (((Orientation) -> Void)?) -> Void public let getAspect: () -> CGFloat
public let setOnOrientationUpdated: (((Orientation, CGFloat) -> Void)?) -> Void
public let setOnIsMirroredUpdated: (((Bool) -> Void)?) -> Void public let setOnIsMirroredUpdated: (((Bool) -> Void)?) -> Void
public init( public init(
view: UIView, view: UIView,
setOnFirstFrameReceived: @escaping (((Float) -> Void)?) -> Void, setOnFirstFrameReceived: @escaping (((Float) -> Void)?) -> Void,
getOrientation: @escaping () -> Orientation, getOrientation: @escaping () -> Orientation,
setOnOrientationUpdated: @escaping (((Orientation) -> Void)?) -> Void, getAspect: @escaping () -> CGFloat,
setOnOrientationUpdated: @escaping (((Orientation, CGFloat) -> Void)?) -> Void,
setOnIsMirroredUpdated: @escaping (((Bool) -> Void)?) -> Void setOnIsMirroredUpdated: @escaping (((Bool) -> Void)?) -> Void
) { ) {
self.view = view self.view = view
self.setOnFirstFrameReceived = setOnFirstFrameReceived self.setOnFirstFrameReceived = setOnFirstFrameReceived
self.getOrientation = getOrientation self.getOrientation = getOrientation
self.getAspect = getAspect
self.setOnOrientationUpdated = setOnOrientationUpdated self.setOnOrientationUpdated = setOnOrientationUpdated
self.setOnIsMirroredUpdated = setOnIsMirroredUpdated self.setOnIsMirroredUpdated = setOnIsMirroredUpdated
} }
@ -137,6 +140,7 @@ public protocol PresentationCall: class {
func toggleIsMuted() func toggleIsMuted()
func setIsMuted(_ value: Bool) func setIsMuted(_ value: Bool)
func requestVideo() func requestVideo()
func setRequestedVideoAspect(_ aspect: Float)
func disableVideo() func disableVideo()
func setOutgoingVideoIsPaused(_ isPaused: Bool) func setOutgoingVideoIsPaused(_ isPaused: Bool)
func switchVideoCamera() func switchVideoCamera()

View File

@ -139,8 +139,8 @@ class CallListCallItem: ListViewItem {
for media in self.topMessage.media { for media in self.topMessage.media {
if let action = media as? TelegramMediaAction { if let action = media as? TelegramMediaAction {
if case let .phoneCall(_, _, _, isVideoValue) = action.action { if case let .phoneCall(_, _, _, isVideoValue) = action.action {
break
isVideo = isVideoValue isVideo = isVideoValue
break
} }
} }
} }

View File

@ -762,7 +762,30 @@ public final class ChatListSearchContainerNode: SearchDisplayControllerContentNo
) )
) )
let location: SearchMessagesLocation let location: SearchMessagesLocation
location = .general(tags: nil) let messageTags: MessageTags?
if query.hasPrefix("%media ") {
messageTags = .photoOrVideo
} else if query.hasPrefix("%photo ") {
messageTags = .photo
} else if query.hasPrefix("%video ") {
messageTags = .video
} else if query.hasPrefix("%file ") {
messageTags = .file
} else if query.hasPrefix("%music ") {
messageTags = .music
} else if query.hasPrefix("%link ") {
messageTags = .webPage
} else if query.hasPrefix("%gif ") {
messageTags = .gif
} else {
messageTags = nil
}
location = .general(tags: messageTags)
var finalQuery = query
if let _ = messageTags, let index = finalQuery.firstIndex(of: " ") {
finalQuery = String(finalQuery.suffix(from: finalQuery.index(after: index)))
}
updateSearchContext { _ in updateSearchContext { _ in
return (nil, true) return (nil, true)
@ -771,22 +794,22 @@ public final class ChatListSearchContainerNode: SearchDisplayControllerContentNo
if filter.contains(.doNotSearchMessages) { if filter.contains(.doNotSearchMessages) {
foundRemoteMessages = .single((([], [:], 0), false)) foundRemoteMessages = .single((([], [:], 0), false))
} else { } else {
if !query.isEmpty { if !finalQuery.isEmpty {
addAppLogEvent(postbox: context.account.postbox, time: Date().timeIntervalSince1970, type: "search_global_query", peerId: nil, data: .dictionary([:])) addAppLogEvent(postbox: context.account.postbox, time: Date().timeIntervalSince1970, type: "search_global_query", peerId: nil, data: .dictionary([:]))
} }
let searchSignal = searchMessages(account: context.account, location: location, query: query, state: nil, limit: 50) let searchSignal = searchMessages(account: context.account, location: location, query: finalQuery, state: nil, limit: 50)
|> map { result, updatedState -> ChatListSearchMessagesResult in |> map { result, updatedState -> ChatListSearchMessagesResult in
return ChatListSearchMessagesResult(query: query, messages: result.messages.sorted(by: { $0.index > $1.index }), readStates: result.readStates, hasMore: !result.completed, state: updatedState) return ChatListSearchMessagesResult(query: finalQuery, messages: result.messages.sorted(by: { $0.index > $1.index }), readStates: result.readStates, hasMore: !result.completed, state: updatedState)
} }
let loadMore = searchContext.get() let loadMore = searchContext.get()
|> mapToSignal { searchContext -> Signal<(([Message], [PeerId: CombinedPeerReadState], Int32), Bool), NoError> in |> mapToSignal { searchContext -> Signal<(([Message], [PeerId: CombinedPeerReadState], Int32), Bool), NoError> in
if let searchContext = searchContext { if let searchContext = searchContext {
if let _ = searchContext.loadMoreIndex { if let _ = searchContext.loadMoreIndex {
return searchMessages(account: context.account, location: location, query: query, state: searchContext.result.state, limit: 80) return searchMessages(account: context.account, location: location, query: finalQuery, state: searchContext.result.state, limit: 80)
|> map { result, updatedState -> ChatListSearchMessagesResult in |> map { result, updatedState -> ChatListSearchMessagesResult in
return ChatListSearchMessagesResult(query: query, messages: result.messages.sorted(by: { $0.index > $1.index }), readStates: result.readStates, hasMore: !result.completed, state: updatedState) return ChatListSearchMessagesResult(query: finalQuery, messages: result.messages.sorted(by: { $0.index > $1.index }), readStates: result.readStates, hasMore: !result.completed, state: updatedState)
} }
|> mapToSignal { foundMessages -> Signal<(([Message], [PeerId: CombinedPeerReadState], Int32), Bool), NoError> in |> mapToSignal { foundMessages -> Signal<(([Message], [PeerId: CombinedPeerReadState], Int32), Bool), NoError> in
updateSearchContext { previous in updateSearchContext { previous in
@ -818,7 +841,7 @@ public final class ChatListSearchContainerNode: SearchDisplayControllerContentNo
} }
let resolvedMessage = .single(nil) let resolvedMessage = .single(nil)
|> then(context.sharedContext.resolveUrl(account: context.account, url: query) |> then(context.sharedContext.resolveUrl(account: context.account, url: finalQuery)
|> mapToSignal { resolvedUrl -> Signal<Message?, NoError> in |> mapToSignal { resolvedUrl -> Signal<Message?, NoError> in
if case let .channelMessage(peerId, messageId) = resolvedUrl { if case let .channelMessage(peerId, messageId) = resolvedUrl {
return downloadMessage(postbox: context.account.postbox, network: context.account.network, messageId: messageId) return downloadMessage(postbox: context.account.postbox, network: context.account.network, messageId: messageId)
@ -904,60 +927,63 @@ public final class ChatListSearchContainerNode: SearchDisplayControllerContentNo
globalExpandType = .none globalExpandType = .none
} }
let lowercasedQuery = query.lowercased() if let _ = messageTags {
if presentationData.strings.DialogList_SavedMessages.lowercased().hasPrefix(lowercasedQuery) || "saved messages".hasPrefix(lowercasedQuery) { } else {
if !existingPeerIds.contains(accountPeer.id), filteredPeer(accountPeer, accountPeer) { let lowercasedQuery = finalQuery.lowercased()
existingPeerIds.insert(accountPeer.id) if presentationData.strings.DialogList_SavedMessages.lowercased().hasPrefix(lowercasedQuery) || "saved messages".hasPrefix(lowercasedQuery) {
entries.append(.localPeer(accountPeer, nil, nil, index, presentationData.theme, presentationData.strings, presentationData.nameSortOrder, presentationData.nameDisplayOrder, localExpandType)) if !existingPeerIds.contains(accountPeer.id), filteredPeer(accountPeer, accountPeer) {
index += 1 existingPeerIds.insert(accountPeer.id)
} entries.append(.localPeer(accountPeer, nil, nil, index, presentationData.theme, presentationData.strings, presentationData.nameSortOrder, presentationData.nameDisplayOrder, localExpandType))
} index += 1
}
var numberOfLocalPeers = 0
for renderedPeer in foundLocalPeers.peers {
if case .expand = localExpandType, numberOfLocalPeers >= 5 {
break
} }
if let peer = renderedPeer.peers[renderedPeer.peerId], peer.id != context.account.peerId, filteredPeer(peer, accountPeer) { var numberOfLocalPeers = 0
if !existingPeerIds.contains(peer.id) { for renderedPeer in foundLocalPeers.peers {
existingPeerIds.insert(peer.id) if case .expand = localExpandType, numberOfLocalPeers >= 5 {
var associatedPeer: Peer? break
if let associatedPeerId = peer.associatedPeerId { }
associatedPeer = renderedPeer.peers[associatedPeerId]
if let peer = renderedPeer.peers[renderedPeer.peerId], peer.id != context.account.peerId, filteredPeer(peer, accountPeer) {
if !existingPeerIds.contains(peer.id) {
existingPeerIds.insert(peer.id)
var associatedPeer: Peer?
if let associatedPeerId = peer.associatedPeerId {
associatedPeer = renderedPeer.peers[associatedPeerId]
}
entries.append(.localPeer(peer, associatedPeer, foundLocalPeers.unread[peer.id], index, presentationData.theme, presentationData.strings, presentationData.nameSortOrder, presentationData.nameDisplayOrder, localExpandType))
index += 1
numberOfLocalPeers += 1
} }
entries.append(.localPeer(peer, associatedPeer, foundLocalPeers.unread[peer.id], index, presentationData.theme, presentationData.strings, presentationData.nameSortOrder, presentationData.nameDisplayOrder, localExpandType)) }
}
for peer in foundRemotePeers.0 {
if case .expand = localExpandType, numberOfLocalPeers >= 5 {
break
}
if !existingPeerIds.contains(peer.peer.id), filteredPeer(peer.peer, accountPeer) {
existingPeerIds.insert(peer.peer.id)
entries.append(.localPeer(peer.peer, nil, nil, index, presentationData.theme, presentationData.strings, presentationData.nameSortOrder, presentationData.nameDisplayOrder, localExpandType))
index += 1 index += 1
numberOfLocalPeers += 1 numberOfLocalPeers += 1
} }
} }
}
for peer in foundRemotePeers.0 {
if case .expand = localExpandType, numberOfLocalPeers >= 5 {
break
}
if !existingPeerIds.contains(peer.peer.id), filteredPeer(peer.peer, accountPeer) {
existingPeerIds.insert(peer.peer.id)
entries.append(.localPeer(peer.peer, nil, nil, index, presentationData.theme, presentationData.strings, presentationData.nameSortOrder, presentationData.nameDisplayOrder, localExpandType))
index += 1
numberOfLocalPeers += 1
}
}
var numberOfGlobalPeers = 0 var numberOfGlobalPeers = 0
index = 0 index = 0
for peer in foundRemotePeers.1 { for peer in foundRemotePeers.1 {
if case .expand = globalExpandType, numberOfGlobalPeers >= 3 { if case .expand = globalExpandType, numberOfGlobalPeers >= 3 {
break break
} }
if !existingPeerIds.contains(peer.peer.id), filteredPeer(peer.peer, accountPeer) { if !existingPeerIds.contains(peer.peer.id), filteredPeer(peer.peer, accountPeer) {
existingPeerIds.insert(peer.peer.id) existingPeerIds.insert(peer.peer.id)
entries.append(.globalPeer(peer, nil, index, presentationData.theme, presentationData.strings, presentationData.nameSortOrder, presentationData.nameDisplayOrder, globalExpandType)) entries.append(.globalPeer(peer, nil, index, presentationData.theme, presentationData.strings, presentationData.nameSortOrder, presentationData.nameDisplayOrder, globalExpandType))
index += 1 index += 1
numberOfGlobalPeers += 1 numberOfGlobalPeers += 1
}
} }
} }
@ -986,8 +1012,8 @@ public final class ChatListSearchContainerNode: SearchDisplayControllerContentNo
} }
} }
if addContact != nil && isViablePhoneNumber(query) { if addContact != nil && isViablePhoneNumber(finalQuery) {
entries.append(.addContact(query, presentationData.theme, presentationData.strings)) entries.append(.addContact(finalQuery, presentationData.theme, presentationData.strings))
} }
return (entries, isSearching) return (entries, isSearching)

View File

@ -945,8 +945,8 @@ public final class Transaction {
self.postbox?.scanMessages(peerId: peerId, namespace: namespace, tag: tag, f) self.postbox?.scanMessages(peerId: peerId, namespace: namespace, tag: tag, f)
} }
public func scanMessageAttributes(peerId: PeerId, namespace: MessageId.Namespace, _ f: (MessageId, [MessageAttribute]) -> Bool) { public func scanMessageAttributes(peerId: PeerId, namespace: MessageId.Namespace, limit: Int, _ f: (MessageId, [MessageAttribute]) -> Bool) {
self.postbox?.scanMessageAttributes(peerId: peerId, namespace: namespace, f) self.postbox?.scanMessageAttributes(peerId: peerId, namespace: namespace, limit: limit, f)
} }
public func invalidateMessageHistoryTagsSummary(peerId: PeerId, namespace: MessageId.Namespace, tagMask: MessageTags) { public func invalidateMessageHistoryTagsSummary(peerId: PeerId, namespace: MessageId.Namespace, tagMask: MessageTags) {
@ -3174,9 +3174,10 @@ public final class Postbox {
} }
} }
fileprivate func scanMessageAttributes(peerId: PeerId, namespace: MessageId.Namespace, _ f: (MessageId, [MessageAttribute]) -> Bool) { fileprivate func scanMessageAttributes(peerId: PeerId, namespace: MessageId.Namespace, limit: Int, _ f: (MessageId, [MessageAttribute]) -> Bool) {
var remainingLimit = limit
var index = MessageIndex.upperBound(peerId: peerId, namespace: namespace) var index = MessageIndex.upperBound(peerId: peerId, namespace: namespace)
while true { while remainingLimit > 0 {
let messages = self.messageHistoryTable.fetch(peerId: peerId, namespace: namespace, tag: nil, from: index, includeFrom: false, to: MessageIndex.lowerBound(peerId: peerId, namespace: namespace), limit: 32) let messages = self.messageHistoryTable.fetch(peerId: peerId, namespace: namespace, tag: nil, from: index, includeFrom: false, to: MessageIndex.lowerBound(peerId: peerId, namespace: namespace), limit: 32)
for message in messages { for message in messages {
let attributes = MessageHistoryTable.renderMessageAttributes(message) let attributes = MessageHistoryTable.renderMessageAttributes(message)
@ -3184,6 +3185,7 @@ public final class Postbox {
break break
} }
} }
remainingLimit -= messages.count
if let last = messages.last { if let last = messages.last {
index = last.index index = last.index
} else { } else {

View File

@ -173,20 +173,20 @@ private final class BubbleSettingsControllerNode: ASDisplayNode, UIScrollViewDel
messages[replyMessageId] = Message(stableId: 3, stableVersion: 0, id: replyMessageId, globallyUniqueId: nil, groupingKey: nil, groupInfo: nil, timestamp: 66000, flags: [], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: peers[otherPeerId], text: self.presentationData.strings.Appearance_ThemePreview_Chat_1_Text, attributes: [], media: [], peers: peers, associatedMessages: SimpleDictionary(), associatedMessageIds: []) messages[replyMessageId] = Message(stableId: 3, stableVersion: 0, id: replyMessageId, globallyUniqueId: nil, groupingKey: nil, groupInfo: nil, timestamp: 66000, flags: [], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: peers[otherPeerId], text: self.presentationData.strings.Appearance_ThemePreview_Chat_1_Text, attributes: [], media: [], peers: peers, associatedMessages: SimpleDictionary(), associatedMessageIds: [])
let message1 = Message(stableId: 4, stableVersion: 0, id: MessageId(peerId: otherPeerId, namespace: 0, id: 4), globallyUniqueId: nil, groupingKey: nil, groupInfo: nil, timestamp: 66003, flags: [], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: peers[otherPeerId], text: self.presentationData.strings.Appearance_ThemePreview_Chat_3_Text, attributes: [], media: [], peers: peers, associatedMessages: messages, associatedMessageIds: []) let message1 = Message(stableId: 4, stableVersion: 0, id: MessageId(peerId: otherPeerId, namespace: 0, id: 4), globallyUniqueId: nil, groupingKey: nil, groupInfo: nil, timestamp: 66003, flags: [], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: peers[otherPeerId], text: self.presentationData.strings.Appearance_ThemePreview_Chat_3_Text, attributes: [], media: [], peers: peers, associatedMessages: messages, associatedMessageIds: [])
items.append(self.context.sharedContext.makeChatMessagePreviewItem(context: self.context, message: message1, theme: self.presentationData.theme, strings: self.presentationData.strings, wallpaper: self.presentationData.chatWallpaper, fontSize: self.presentationData.chatFontSize, chatBubbleCorners: self.presentationData.chatBubbleCorners, dateTimeFormat: self.presentationData.dateTimeFormat, nameOrder: self.presentationData.nameDisplayOrder, forcedResourceStatus: nil, tapMessage: nil, clickThroughMessage: nil)) items.append(self.context.sharedContext.makeChatMessagePreviewItem(context: self.context, messages: [message1], theme: self.presentationData.theme, strings: self.presentationData.strings, wallpaper: self.presentationData.chatWallpaper, fontSize: self.presentationData.chatFontSize, chatBubbleCorners: self.presentationData.chatBubbleCorners, dateTimeFormat: self.presentationData.dateTimeFormat, nameOrder: self.presentationData.nameDisplayOrder, forcedResourceStatus: nil, tapMessage: nil, clickThroughMessage: nil))
let message2 = Message(stableId: 3, stableVersion: 0, id: MessageId(peerId: peerId, namespace: 0, id: 3), globallyUniqueId: nil, groupingKey: nil, groupInfo: nil, timestamp: 66002, flags: [.Incoming], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: peers[peerId], text: self.presentationData.strings.Appearance_ThemePreview_Chat_2_Text, attributes: [ReplyMessageAttribute(messageId: replyMessageId)], media: [], peers: peers, associatedMessages: messages, associatedMessageIds: []) let message2 = Message(stableId: 3, stableVersion: 0, id: MessageId(peerId: peerId, namespace: 0, id: 3), globallyUniqueId: nil, groupingKey: nil, groupInfo: nil, timestamp: 66002, flags: [.Incoming], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: peers[peerId], text: self.presentationData.strings.Appearance_ThemePreview_Chat_2_Text, attributes: [ReplyMessageAttribute(messageId: replyMessageId)], media: [], peers: peers, associatedMessages: messages, associatedMessageIds: [])
items.append(self.context.sharedContext.makeChatMessagePreviewItem(context: self.context, message: message2, theme: self.presentationData.theme, strings: self.presentationData.strings, wallpaper: self.presentationData.chatWallpaper, fontSize: self.presentationData.chatFontSize, chatBubbleCorners: self.presentationData.chatBubbleCorners, dateTimeFormat: self.presentationData.dateTimeFormat, nameOrder: self.presentationData.nameDisplayOrder, forcedResourceStatus: nil, tapMessage: nil, clickThroughMessage: nil)) items.append(self.context.sharedContext.makeChatMessagePreviewItem(context: self.context, messages: [message2], theme: self.presentationData.theme, strings: self.presentationData.strings, wallpaper: self.presentationData.chatWallpaper, fontSize: self.presentationData.chatFontSize, chatBubbleCorners: self.presentationData.chatBubbleCorners, dateTimeFormat: self.presentationData.dateTimeFormat, nameOrder: self.presentationData.nameDisplayOrder, forcedResourceStatus: nil, tapMessage: nil, clickThroughMessage: nil))
let waveformBase64 = "DAAOAAkACQAGAAwADwAMABAADQAPABsAGAALAA0AGAAfABoAHgATABgAGQAYABQADAAVABEAHwANAA0ACQAWABkACQAOAAwACQAfAAAAGQAVAAAAEwATAAAACAAfAAAAHAAAABwAHwAAABcAGQAAABQADgAAABQAHwAAAB8AHwAAAAwADwAAAB8AEwAAABoAFwAAAB8AFAAAAAAAHwAAAAAAHgAAAAAAHwAAAAAAHwAAAAAAHwAAAAAAHwAAAAAAHwAAAAAAAAA=" let waveformBase64 = "DAAOAAkACQAGAAwADwAMABAADQAPABsAGAALAA0AGAAfABoAHgATABgAGQAYABQADAAVABEAHwANAA0ACQAWABkACQAOAAwACQAfAAAAGQAVAAAAEwATAAAACAAfAAAAHAAAABwAHwAAABcAGQAAABQADgAAABQAHwAAAB8AHwAAAAwADwAAAB8AEwAAABoAFwAAAB8AFAAAAAAAHwAAAAAAHgAAAAAAHwAAAAAAHwAAAAAAHwAAAAAAHwAAAAAAHwAAAAAAAAA="
let voiceAttributes: [TelegramMediaFileAttribute] = [.Audio(isVoice: true, duration: 23, title: nil, performer: nil, waveform: MemoryBuffer(data: Data(base64Encoded: waveformBase64)!))] let voiceAttributes: [TelegramMediaFileAttribute] = [.Audio(isVoice: true, duration: 23, title: nil, performer: nil, waveform: MemoryBuffer(data: Data(base64Encoded: waveformBase64)!))]
let voiceMedia = TelegramMediaFile(fileId: MediaId(namespace: 0, id: 0), partialReference: nil, resource: LocalFileMediaResource(fileId: 0), previewRepresentations: [], videoThumbnails: [], immediateThumbnailData: nil, mimeType: "audio/ogg", size: 0, attributes: voiceAttributes) let voiceMedia = TelegramMediaFile(fileId: MediaId(namespace: 0, id: 0), partialReference: nil, resource: LocalFileMediaResource(fileId: 0), previewRepresentations: [], videoThumbnails: [], immediateThumbnailData: nil, mimeType: "audio/ogg", size: 0, attributes: voiceAttributes)
let message3 = Message(stableId: 1, stableVersion: 0, id: MessageId(peerId: peerId, namespace: 0, id: 1), globallyUniqueId: nil, groupingKey: nil, groupInfo: nil, timestamp: 66001, flags: [.Incoming], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: peers[peerId], text: "", attributes: [], media: [voiceMedia], peers: peers, associatedMessages: messages, associatedMessageIds: []) let message3 = Message(stableId: 1, stableVersion: 0, id: MessageId(peerId: peerId, namespace: 0, id: 1), globallyUniqueId: nil, groupingKey: nil, groupInfo: nil, timestamp: 66001, flags: [.Incoming], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: peers[peerId], text: "", attributes: [], media: [voiceMedia], peers: peers, associatedMessages: messages, associatedMessageIds: [])
items.append(self.context.sharedContext.makeChatMessagePreviewItem(context: self.context, message: message3, theme: self.presentationData.theme, strings: self.presentationData.strings, wallpaper: self.presentationData.chatWallpaper, fontSize: self.presentationData.chatFontSize, chatBubbleCorners: self.presentationData.chatBubbleCorners, dateTimeFormat: self.presentationData.dateTimeFormat, nameOrder: self.presentationData.nameDisplayOrder, forcedResourceStatus: FileMediaResourceStatus(mediaStatus: .playbackStatus(.paused), fetchStatus: .Local), tapMessage: nil, clickThroughMessage: nil)) items.append(self.context.sharedContext.makeChatMessagePreviewItem(context: self.context, messages: [message3], theme: self.presentationData.theme, strings: self.presentationData.strings, wallpaper: self.presentationData.chatWallpaper, fontSize: self.presentationData.chatFontSize, chatBubbleCorners: self.presentationData.chatBubbleCorners, dateTimeFormat: self.presentationData.dateTimeFormat, nameOrder: self.presentationData.nameDisplayOrder, forcedResourceStatus: FileMediaResourceStatus(mediaStatus: .playbackStatus(.paused), fetchStatus: .Local), tapMessage: nil, clickThroughMessage: nil))
let message4 = Message(stableId: 2, stableVersion: 0, id: MessageId(peerId: otherPeerId, namespace: 0, id: 2), globallyUniqueId: nil, groupingKey: nil, groupInfo: nil, timestamp: 66001, flags: [], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: peers[otherPeerId], text: self.presentationData.strings.Appearance_ThemePreview_Chat_1_Text, attributes: [], media: [], peers: peers, associatedMessages: messages, associatedMessageIds: []) let message4 = Message(stableId: 2, stableVersion: 0, id: MessageId(peerId: otherPeerId, namespace: 0, id: 2), globallyUniqueId: nil, groupingKey: nil, groupInfo: nil, timestamp: 66001, flags: [], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: peers[otherPeerId], text: self.presentationData.strings.Appearance_ThemePreview_Chat_1_Text, attributes: [], media: [], peers: peers, associatedMessages: messages, associatedMessageIds: [])
items.append(self.context.sharedContext.makeChatMessagePreviewItem(context: self.context, message: message4, theme: self.presentationData.theme, strings: self.presentationData.strings, wallpaper: self.presentationData.chatWallpaper, fontSize: self.presentationData.chatFontSize, chatBubbleCorners: self.presentationData.chatBubbleCorners, dateTimeFormat: self.presentationData.dateTimeFormat, nameOrder: self.presentationData.nameDisplayOrder, forcedResourceStatus: nil, tapMessage: nil, clickThroughMessage: nil)) items.append(self.context.sharedContext.makeChatMessagePreviewItem(context: self.context, messages: [message4], theme: self.presentationData.theme, strings: self.presentationData.strings, wallpaper: self.presentationData.chatWallpaper, fontSize: self.presentationData.chatFontSize, chatBubbleCorners: self.presentationData.chatBubbleCorners, dateTimeFormat: self.presentationData.dateTimeFormat, nameOrder: self.presentationData.nameDisplayOrder, forcedResourceStatus: nil, tapMessage: nil, clickThroughMessage: nil))
let width: CGFloat let width: CGFloat
if case .regular = layout.metrics.widthClass { if case .regular = layout.metrics.widthClass {

View File

@ -43,6 +43,7 @@ private enum DebugControllerSection: Int32 {
case logging case logging
case experiments case experiments
case videoExperiments case videoExperiments
case videoExperiments2
case info case info
} }
@ -73,6 +74,8 @@ private enum DebugControllerEntry: ItemListNodeEntry {
case playerEmbedding(Bool) case playerEmbedding(Bool)
case playlistPlayback(Bool) case playlistPlayback(Bool)
case preferredVideoCodec(Int, String, String?, Bool) case preferredVideoCodec(Int, String, String?, Bool)
case disableVideoAspectScaling(Bool)
case enableVoipTcp(Bool)
case hostInfo(PresentationTheme, String) case hostInfo(PresentationTheme, String)
case versionInfo(PresentationTheme) case versionInfo(PresentationTheme)
@ -90,6 +93,8 @@ private enum DebugControllerEntry: ItemListNodeEntry {
return DebugControllerSection.experiments.rawValue return DebugControllerSection.experiments.rawValue
case .preferredVideoCodec: case .preferredVideoCodec:
return DebugControllerSection.videoExperiments.rawValue return DebugControllerSection.videoExperiments.rawValue
case .disableVideoAspectScaling, .enableVoipTcp:
return DebugControllerSection.videoExperiments2.rawValue
case .hostInfo, .versionInfo: case .hostInfo, .versionInfo:
return DebugControllerSection.info.rawValue return DebugControllerSection.info.rawValue
} }
@ -149,10 +154,14 @@ private enum DebugControllerEntry: ItemListNodeEntry {
return 25 return 25
case let .preferredVideoCodec(index, _, _, _): case let .preferredVideoCodec(index, _, _, _):
return 26 + index return 26 + index
case .hostInfo: case .disableVideoAspectScaling:
return 100 return 100
case .versionInfo: case .enableVoipTcp:
return 101 return 101
case .hostInfo:
return 102
case .versionInfo:
return 103
} }
} }
@ -580,6 +589,26 @@ private enum DebugControllerEntry: ItemListNodeEntry {
}) })
}).start() }).start()
}) })
case let .disableVideoAspectScaling(value):
return ItemListSwitchItem(presentationData: presentationData, title: "Video Cropping Optimization", value: !value, sectionId: self.section, style: .blocks, updated: { value in
let _ = arguments.sharedContext.accountManager.transaction ({ transaction in
transaction.updateSharedData(ApplicationSpecificSharedDataKeys.experimentalUISettings, { settings in
var settings = settings as? ExperimentalUISettings ?? ExperimentalUISettings.defaultSettings
settings.disableVideoAspectScaling = !value
return settings
})
}).start()
})
case let .enableVoipTcp(value):
return ItemListSwitchItem(presentationData: presentationData, title: "Enable VoIP TCP", value: !value, sectionId: self.section, style: .blocks, updated: { value in
let _ = arguments.sharedContext.accountManager.transaction ({ transaction in
transaction.updateSharedData(ApplicationSpecificSharedDataKeys.experimentalUISettings, { settings in
var settings = settings as? ExperimentalUISettings ?? ExperimentalUISettings.defaultSettings
settings.enableVoipTcp = value
return settings
})
}).start()
})
case let .hostInfo(theme, string): case let .hostInfo(theme, string):
return ItemListTextItem(presentationData: presentationData, text: .plain(string), sectionId: self.section) return ItemListTextItem(presentationData: presentationData, text: .plain(string), sectionId: self.section)
case let .versionInfo(theme): case let .versionInfo(theme):
@ -637,6 +666,9 @@ private func debugControllerEntries(presentationData: PresentationData, loggingS
for i in 0 ..< codecs.count { for i in 0 ..< codecs.count {
entries.append(.preferredVideoCodec(i, codecs[i].0, codecs[i].1, experimentalSettings.preferredVideoCodec == codecs[i].1)) entries.append(.preferredVideoCodec(i, codecs[i].0, codecs[i].1, experimentalSettings.preferredVideoCodec == codecs[i].1))
} }
entries.append(.disableVideoAspectScaling(experimentalSettings.disableVideoAspectScaling))
entries.append(.enableVoipTcp(experimentalSettings.enableVoipTcp))
if let backupHostOverride = networkSettings?.backupHostOverride { if let backupHostOverride = networkSettings?.backupHostOverride {
entries.append(.hostInfo(presentationData.theme, "Host: \(backupHostOverride)")) entries.append(.hostInfo(presentationData.theme, "Host: \(backupHostOverride)"))

View File

@ -159,7 +159,7 @@ class ForwardPrivacyChatPreviewItemNode: ListViewItemNode {
let forwardInfo = MessageForwardInfo(author: item.linkEnabled ? peers[peerId] : nil, source: nil, sourceMessageId: nil, date: 0, authorSignature: item.linkEnabled ? nil : item.peerName, psaType: nil) let forwardInfo = MessageForwardInfo(author: item.linkEnabled ? peers[peerId] : nil, source: nil, sourceMessageId: nil, date: 0, authorSignature: item.linkEnabled ? nil : item.peerName, psaType: nil)
let messageItem = item.context.sharedContext.makeChatMessagePreviewItem(context: item.context, message: Message(stableId: 1, stableVersion: 0, id: MessageId(peerId: peerId, namespace: 0, id: 1), globallyUniqueId: nil, groupingKey: nil, groupInfo: nil, timestamp: 66000, flags: [.Incoming], tags: [], globalTags: [], localTags: [], forwardInfo: forwardInfo, author: nil, text: item.strings.Privacy_Forwards_PreviewMessageText, attributes: [], media: [], peers: peers, associatedMessages: messages, associatedMessageIds: []), theme: item.theme, strings: item.strings, wallpaper: item.wallpaper, fontSize: item.fontSize, chatBubbleCorners: item.chatBubbleCorners, dateTimeFormat: item.dateTimeFormat, nameOrder: item.nameDisplayOrder, forcedResourceStatus: nil, tapMessage: nil, clickThroughMessage: nil) let messageItem = item.context.sharedContext.makeChatMessagePreviewItem(context: item.context, messages: [Message(stableId: 1, stableVersion: 0, id: MessageId(peerId: peerId, namespace: 0, id: 1), globallyUniqueId: nil, groupingKey: nil, groupInfo: nil, timestamp: 66000, flags: [.Incoming], tags: [], globalTags: [], localTags: [], forwardInfo: forwardInfo, author: nil, text: item.strings.Privacy_Forwards_PreviewMessageText, attributes: [], media: [], peers: peers, associatedMessages: messages, associatedMessageIds: [])], theme: item.theme, strings: item.strings, wallpaper: item.wallpaper, fontSize: item.fontSize, chatBubbleCorners: item.chatBubbleCorners, dateTimeFormat: item.dateTimeFormat, nameOrder: item.nameDisplayOrder, forcedResourceStatus: nil, tapMessage: nil, clickThroughMessage: nil)
var node: ListViewItemNode? var node: ListViewItemNode?
if let current = currentNode { if let current = currentNode {

View File

@ -319,20 +319,20 @@ private final class TextSizeSelectionControllerNode: ASDisplayNode, UIScrollView
messages[replyMessageId] = Message(stableId: 3, stableVersion: 0, id: replyMessageId, globallyUniqueId: nil, groupingKey: nil, groupInfo: nil, timestamp: 66000, flags: [], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: peers[otherPeerId], text: self.presentationData.strings.Appearance_ThemePreview_Chat_1_Text, attributes: [], media: [], peers: peers, associatedMessages: SimpleDictionary(), associatedMessageIds: []) messages[replyMessageId] = Message(stableId: 3, stableVersion: 0, id: replyMessageId, globallyUniqueId: nil, groupingKey: nil, groupInfo: nil, timestamp: 66000, flags: [], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: peers[otherPeerId], text: self.presentationData.strings.Appearance_ThemePreview_Chat_1_Text, attributes: [], media: [], peers: peers, associatedMessages: SimpleDictionary(), associatedMessageIds: [])
let message1 = Message(stableId: 4, stableVersion: 0, id: MessageId(peerId: otherPeerId, namespace: 0, id: 4), globallyUniqueId: nil, groupingKey: nil, groupInfo: nil, timestamp: 66003, flags: [], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: peers[otherPeerId], text: self.presentationData.strings.Appearance_ThemePreview_Chat_3_Text, attributes: [], media: [], peers: peers, associatedMessages: messages, associatedMessageIds: []) let message1 = Message(stableId: 4, stableVersion: 0, id: MessageId(peerId: otherPeerId, namespace: 0, id: 4), globallyUniqueId: nil, groupingKey: nil, groupInfo: nil, timestamp: 66003, flags: [], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: peers[otherPeerId], text: self.presentationData.strings.Appearance_ThemePreview_Chat_3_Text, attributes: [], media: [], peers: peers, associatedMessages: messages, associatedMessageIds: [])
items.append(self.context.sharedContext.makeChatMessagePreviewItem(context: self.context, message: message1, theme: self.presentationData.theme, strings: self.presentationData.strings, wallpaper: self.presentationData.chatWallpaper, fontSize: self.presentationData.chatFontSize, chatBubbleCorners: self.presentationData.chatBubbleCorners, dateTimeFormat: self.presentationData.dateTimeFormat, nameOrder: self.presentationData.nameDisplayOrder, forcedResourceStatus: nil, tapMessage: nil, clickThroughMessage: nil)) items.append(self.context.sharedContext.makeChatMessagePreviewItem(context: self.context, messages: [message1], theme: self.presentationData.theme, strings: self.presentationData.strings, wallpaper: self.presentationData.chatWallpaper, fontSize: self.presentationData.chatFontSize, chatBubbleCorners: self.presentationData.chatBubbleCorners, dateTimeFormat: self.presentationData.dateTimeFormat, nameOrder: self.presentationData.nameDisplayOrder, forcedResourceStatus: nil, tapMessage: nil, clickThroughMessage: nil))
let message2 = Message(stableId: 3, stableVersion: 0, id: MessageId(peerId: peerId, namespace: 0, id: 3), globallyUniqueId: nil, groupingKey: nil, groupInfo: nil, timestamp: 66002, flags: [.Incoming], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: peers[peerId], text: self.presentationData.strings.Appearance_ThemePreview_Chat_2_Text, attributes: [ReplyMessageAttribute(messageId: replyMessageId)], media: [], peers: peers, associatedMessages: messages, associatedMessageIds: []) let message2 = Message(stableId: 3, stableVersion: 0, id: MessageId(peerId: peerId, namespace: 0, id: 3), globallyUniqueId: nil, groupingKey: nil, groupInfo: nil, timestamp: 66002, flags: [.Incoming], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: peers[peerId], text: self.presentationData.strings.Appearance_ThemePreview_Chat_2_Text, attributes: [ReplyMessageAttribute(messageId: replyMessageId)], media: [], peers: peers, associatedMessages: messages, associatedMessageIds: [])
items.append(self.context.sharedContext.makeChatMessagePreviewItem(context: self.context, message: message2, theme: self.presentationData.theme, strings: self.presentationData.strings, wallpaper: self.presentationData.chatWallpaper, fontSize: self.presentationData.chatFontSize, chatBubbleCorners: self.presentationData.chatBubbleCorners, dateTimeFormat: self.presentationData.dateTimeFormat, nameOrder: self.presentationData.nameDisplayOrder, forcedResourceStatus: nil, tapMessage: nil, clickThroughMessage: nil)) items.append(self.context.sharedContext.makeChatMessagePreviewItem(context: self.context, messages: [message2], theme: self.presentationData.theme, strings: self.presentationData.strings, wallpaper: self.presentationData.chatWallpaper, fontSize: self.presentationData.chatFontSize, chatBubbleCorners: self.presentationData.chatBubbleCorners, dateTimeFormat: self.presentationData.dateTimeFormat, nameOrder: self.presentationData.nameDisplayOrder, forcedResourceStatus: nil, tapMessage: nil, clickThroughMessage: nil))
let waveformBase64 = "DAAOAAkACQAGAAwADwAMABAADQAPABsAGAALAA0AGAAfABoAHgATABgAGQAYABQADAAVABEAHwANAA0ACQAWABkACQAOAAwACQAfAAAAGQAVAAAAEwATAAAACAAfAAAAHAAAABwAHwAAABcAGQAAABQADgAAABQAHwAAAB8AHwAAAAwADwAAAB8AEwAAABoAFwAAAB8AFAAAAAAAHwAAAAAAHgAAAAAAHwAAAAAAHwAAAAAAHwAAAAAAHwAAAAAAHwAAAAAAAAA=" let waveformBase64 = "DAAOAAkACQAGAAwADwAMABAADQAPABsAGAALAA0AGAAfABoAHgATABgAGQAYABQADAAVABEAHwANAA0ACQAWABkACQAOAAwACQAfAAAAGQAVAAAAEwATAAAACAAfAAAAHAAAABwAHwAAABcAGQAAABQADgAAABQAHwAAAB8AHwAAAAwADwAAAB8AEwAAABoAFwAAAB8AFAAAAAAAHwAAAAAAHgAAAAAAHwAAAAAAHwAAAAAAHwAAAAAAHwAAAAAAHwAAAAAAAAA="
let voiceAttributes: [TelegramMediaFileAttribute] = [.Audio(isVoice: true, duration: 23, title: nil, performer: nil, waveform: MemoryBuffer(data: Data(base64Encoded: waveformBase64)!))] let voiceAttributes: [TelegramMediaFileAttribute] = [.Audio(isVoice: true, duration: 23, title: nil, performer: nil, waveform: MemoryBuffer(data: Data(base64Encoded: waveformBase64)!))]
let voiceMedia = TelegramMediaFile(fileId: MediaId(namespace: 0, id: 0), partialReference: nil, resource: LocalFileMediaResource(fileId: 0), previewRepresentations: [], videoThumbnails: [], immediateThumbnailData: nil, mimeType: "audio/ogg", size: 0, attributes: voiceAttributes) let voiceMedia = TelegramMediaFile(fileId: MediaId(namespace: 0, id: 0), partialReference: nil, resource: LocalFileMediaResource(fileId: 0), previewRepresentations: [], videoThumbnails: [], immediateThumbnailData: nil, mimeType: "audio/ogg", size: 0, attributes: voiceAttributes)
let message3 = Message(stableId: 1, stableVersion: 0, id: MessageId(peerId: peerId, namespace: 0, id: 1), globallyUniqueId: nil, groupingKey: nil, groupInfo: nil, timestamp: 66001, flags: [.Incoming], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: peers[peerId], text: "", attributes: [], media: [voiceMedia], peers: peers, associatedMessages: messages, associatedMessageIds: []) let message3 = Message(stableId: 1, stableVersion: 0, id: MessageId(peerId: peerId, namespace: 0, id: 1), globallyUniqueId: nil, groupingKey: nil, groupInfo: nil, timestamp: 66001, flags: [.Incoming], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: peers[peerId], text: "", attributes: [], media: [voiceMedia], peers: peers, associatedMessages: messages, associatedMessageIds: [])
items.append(self.context.sharedContext.makeChatMessagePreviewItem(context: self.context, message: message3, theme: self.presentationData.theme, strings: self.presentationData.strings, wallpaper: self.presentationData.chatWallpaper, fontSize: self.presentationData.chatFontSize, chatBubbleCorners: self.presentationData.chatBubbleCorners, dateTimeFormat: self.presentationData.dateTimeFormat, nameOrder: self.presentationData.nameDisplayOrder, forcedResourceStatus: FileMediaResourceStatus(mediaStatus: .playbackStatus(.paused), fetchStatus: .Local), tapMessage: nil, clickThroughMessage: nil)) items.append(self.context.sharedContext.makeChatMessagePreviewItem(context: self.context, messages: [message3], theme: self.presentationData.theme, strings: self.presentationData.strings, wallpaper: self.presentationData.chatWallpaper, fontSize: self.presentationData.chatFontSize, chatBubbleCorners: self.presentationData.chatBubbleCorners, dateTimeFormat: self.presentationData.dateTimeFormat, nameOrder: self.presentationData.nameDisplayOrder, forcedResourceStatus: FileMediaResourceStatus(mediaStatus: .playbackStatus(.paused), fetchStatus: .Local), tapMessage: nil, clickThroughMessage: nil))
let message4 = Message(stableId: 2, stableVersion: 0, id: MessageId(peerId: otherPeerId, namespace: 0, id: 2), globallyUniqueId: nil, groupingKey: nil, groupInfo: nil, timestamp: 66001, flags: [], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: peers[otherPeerId], text: self.presentationData.strings.Appearance_ThemePreview_Chat_1_Text, attributes: [], media: [], peers: peers, associatedMessages: messages, associatedMessageIds: []) let message4 = Message(stableId: 2, stableVersion: 0, id: MessageId(peerId: otherPeerId, namespace: 0, id: 2), globallyUniqueId: nil, groupingKey: nil, groupInfo: nil, timestamp: 66001, flags: [], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: peers[otherPeerId], text: self.presentationData.strings.Appearance_ThemePreview_Chat_1_Text, attributes: [], media: [], peers: peers, associatedMessages: messages, associatedMessageIds: [])
items.append(self.context.sharedContext.makeChatMessagePreviewItem(context: self.context, message: message4, theme: self.presentationData.theme, strings: self.presentationData.strings, wallpaper: self.presentationData.chatWallpaper, fontSize: self.presentationData.chatFontSize, chatBubbleCorners: self.presentationData.chatBubbleCorners, dateTimeFormat: self.presentationData.dateTimeFormat, nameOrder: self.presentationData.nameDisplayOrder, forcedResourceStatus: nil, tapMessage: nil, clickThroughMessage: nil)) items.append(self.context.sharedContext.makeChatMessagePreviewItem(context: self.context, messages: [message4], theme: self.presentationData.theme, strings: self.presentationData.strings, wallpaper: self.presentationData.chatWallpaper, fontSize: self.presentationData.chatFontSize, chatBubbleCorners: self.presentationData.chatBubbleCorners, dateTimeFormat: self.presentationData.dateTimeFormat, nameOrder: self.presentationData.nameDisplayOrder, forcedResourceStatus: nil, tapMessage: nil, clickThroughMessage: nil))
let width: CGFloat let width: CGFloat
if case .regular = layout.metrics.widthClass { if case .regular = layout.metrics.widthClass {

View File

@ -882,7 +882,7 @@ final class ThemeAccentColorControllerNode: ASDisplayNode, UIScrollViewDelegate
sampleMessages.append(message8) sampleMessages.append(message8)
items = sampleMessages.reversed().map { message in items = sampleMessages.reversed().map { message in
let item = self.context.sharedContext.makeChatMessagePreviewItem(context: self.context, message: message, theme: self.theme, strings: self.presentationData.strings, wallpaper: self.wallpaper, fontSize: self.presentationData.chatFontSize, chatBubbleCorners: self.presentationData.chatBubbleCorners, dateTimeFormat: self.presentationData.dateTimeFormat, nameOrder: self.presentationData.nameDisplayOrder, forcedResourceStatus: !message.media.isEmpty ? FileMediaResourceStatus(mediaStatus: .playbackStatus(.paused), fetchStatus: .Local) : nil, tapMessage: { [weak self] message in let item = self.context.sharedContext.makeChatMessagePreviewItem(context: self.context, messages: [message], theme: self.theme, strings: self.presentationData.strings, wallpaper: self.wallpaper, fontSize: self.presentationData.chatFontSize, chatBubbleCorners: self.presentationData.chatBubbleCorners, dateTimeFormat: self.presentationData.dateTimeFormat, nameOrder: self.presentationData.nameDisplayOrder, forcedResourceStatus: !message.media.isEmpty ? FileMediaResourceStatus(mediaStatus: .playbackStatus(.paused), fetchStatus: .Local) : nil, tapMessage: { [weak self] message in
if message.flags.contains(.Incoming) { if message.flags.contains(.Incoming) {
self?.updateSection(.accent) self?.updateSection(.accent)
self?.requestSectionUpdate?(.accent) self?.requestSectionUpdate?(.accent)

View File

@ -487,7 +487,7 @@ final class ThemePreviewControllerNode: ASDisplayNode, UIScrollViewDelegate {
sampleMessages.append(message8) sampleMessages.append(message8)
items = sampleMessages.reversed().map { message in items = sampleMessages.reversed().map { message in
self.context.sharedContext.makeChatMessagePreviewItem(context: self.context, message: message, theme: self.previewTheme, strings: self.presentationData.strings, wallpaper: self.previewTheme.chat.defaultWallpaper, fontSize: self.presentationData.chatFontSize, chatBubbleCorners: self.presentationData.chatBubbleCorners, dateTimeFormat: self.presentationData.dateTimeFormat, nameOrder: self.presentationData.nameDisplayOrder, forcedResourceStatus: !message.media.isEmpty ? FileMediaResourceStatus(mediaStatus: .playbackStatus(.paused), fetchStatus: .Local) : nil, tapMessage: nil, clickThroughMessage: nil) self.context.sharedContext.makeChatMessagePreviewItem(context: self.context, messages: [message], theme: self.previewTheme, strings: self.presentationData.strings, wallpaper: self.previewTheme.chat.defaultWallpaper, fontSize: self.presentationData.chatFontSize, chatBubbleCorners: self.presentationData.chatBubbleCorners, dateTimeFormat: self.presentationData.dateTimeFormat, nameOrder: self.presentationData.nameDisplayOrder, forcedResourceStatus: !message.media.isEmpty ? FileMediaResourceStatus(mediaStatus: .playbackStatus(.paused), fetchStatus: .Local) : nil, tapMessage: nil, clickThroughMessage: nil)
} }
let width: CGFloat let width: CGFloat

View File

@ -165,7 +165,7 @@ class ThemeSettingsChatPreviewItemNode: ListViewItemNode {
} }
let message = Message(stableId: 1, stableVersion: 0, id: MessageId(peerId: messageItem.outgoing ? otherPeerId : peerId, namespace: 0, id: 1), globallyUniqueId: nil, groupingKey: nil, groupInfo: nil, timestamp: 66000, flags: messageItem.outgoing ? [] : [.Incoming], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: messageItem.outgoing ? TelegramUser(id: otherPeerId, accessHash: nil, firstName: "", lastName: "", username: nil, phone: nil, photo: [], botInfo: nil, restrictionInfo: nil, flags: []) : nil, text: messageItem.text, attributes: messageItem.reply != nil ? [ReplyMessageAttribute(messageId: replyMessageId)] : [], media: [], peers: peers, associatedMessages: messages, associatedMessageIds: []) let message = Message(stableId: 1, stableVersion: 0, id: MessageId(peerId: messageItem.outgoing ? otherPeerId : peerId, namespace: 0, id: 1), globallyUniqueId: nil, groupingKey: nil, groupInfo: nil, timestamp: 66000, flags: messageItem.outgoing ? [] : [.Incoming], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: messageItem.outgoing ? TelegramUser(id: otherPeerId, accessHash: nil, firstName: "", lastName: "", username: nil, phone: nil, photo: [], botInfo: nil, restrictionInfo: nil, flags: []) : nil, text: messageItem.text, attributes: messageItem.reply != nil ? [ReplyMessageAttribute(messageId: replyMessageId)] : [], media: [], peers: peers, associatedMessages: messages, associatedMessageIds: [])
items.append(item.context.sharedContext.makeChatMessagePreviewItem(context: item.context, message: message, theme: item.componentTheme, strings: item.strings, wallpaper: item.wallpaper, fontSize: item.fontSize, chatBubbleCorners: item.chatBubbleCorners, dateTimeFormat: item.dateTimeFormat, nameOrder: item.nameDisplayOrder, forcedResourceStatus: nil, tapMessage: nil, clickThroughMessage: nil)) items.append(item.context.sharedContext.makeChatMessagePreviewItem(context: item.context, messages: [message], theme: item.componentTheme, strings: item.strings, wallpaper: item.wallpaper, fontSize: item.fontSize, chatBubbleCorners: item.chatBubbleCorners, dateTimeFormat: item.dateTimeFormat, nameOrder: item.nameDisplayOrder, forcedResourceStatus: nil, tapMessage: nil, clickThroughMessage: nil))
} }
var nodes: [ListViewItemNode] = [] var nodes: [ListViewItemNode] = []

View File

@ -840,28 +840,13 @@ final class WallpaperGalleryItemNode: GalleryItemNode {
let theme = self.presentationData.theme.withUpdated(preview: true) let theme = self.presentationData.theme.withUpdated(preview: true)
let message1 = Message(stableId: 2, stableVersion: 0, id: MessageId(peerId: peerId, namespace: 0, id: 2), globallyUniqueId: nil, groupingKey: nil, groupInfo: nil, timestamp: 66001, flags: [], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: peers[otherPeerId], text: bottomMessageText, attributes: [], media: [], peers: peers, associatedMessages: messages, associatedMessageIds: []) let message1 = Message(stableId: 2, stableVersion: 0, id: MessageId(peerId: peerId, namespace: 0, id: 2), globallyUniqueId: nil, groupingKey: nil, groupInfo: nil, timestamp: 66001, flags: [], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: peers[otherPeerId], text: bottomMessageText, attributes: [], media: [], peers: peers, associatedMessages: messages, associatedMessageIds: [])
items.append(self.context.sharedContext.makeChatMessagePreviewItem(context: self.context, message: message1, theme: theme, strings: self.presentationData.strings, wallpaper: currentWallpaper, fontSize: self.presentationData.chatFontSize, chatBubbleCorners: self.presentationData.chatBubbleCorners, dateTimeFormat: self.presentationData.dateTimeFormat, nameOrder: self.presentationData.nameDisplayOrder, forcedResourceStatus: nil, tapMessage: nil, clickThroughMessage: nil)) items.append(self.context.sharedContext.makeChatMessagePreviewItem(context: self.context, messages: [message1], theme: theme, strings: self.presentationData.strings, wallpaper: currentWallpaper, fontSize: self.presentationData.chatFontSize, chatBubbleCorners: self.presentationData.chatBubbleCorners, dateTimeFormat: self.presentationData.dateTimeFormat, nameOrder: self.presentationData.nameDisplayOrder, forcedResourceStatus: nil, tapMessage: nil, clickThroughMessage: nil))
let message2 = Message(stableId: 1, stableVersion: 0, id: MessageId(peerId: peerId, namespace: 0, id: 1), globallyUniqueId: nil, groupingKey: nil, groupInfo: nil, timestamp: 66000, flags: [.Incoming], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: peers[peerId], text: topMessageText, attributes: [], media: [], peers: peers, associatedMessages: messages, associatedMessageIds: []) let message2 = Message(stableId: 1, stableVersion: 0, id: MessageId(peerId: peerId, namespace: 0, id: 1), globallyUniqueId: nil, groupingKey: nil, groupInfo: nil, timestamp: 66000, flags: [.Incoming], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: peers[peerId], text: topMessageText, attributes: [], media: [], peers: peers, associatedMessages: messages, associatedMessageIds: [])
items.append(self.context.sharedContext.makeChatMessagePreviewItem(context: self.context, message: message2, theme: theme, strings: self.presentationData.strings, wallpaper: currentWallpaper, fontSize: self.presentationData.chatFontSize, chatBubbleCorners: self.presentationData.chatBubbleCorners, dateTimeFormat: self.presentationData.dateTimeFormat, nameOrder: self.presentationData.nameDisplayOrder, forcedResourceStatus: nil, tapMessage: nil, clickThroughMessage: nil)) items.append(self.context.sharedContext.makeChatMessagePreviewItem(context: self.context, messages: [message2], theme: theme, strings: self.presentationData.strings, wallpaper: currentWallpaper, fontSize: self.presentationData.chatFontSize, chatBubbleCorners: self.presentationData.chatBubbleCorners, dateTimeFormat: self.presentationData.dateTimeFormat, nameOrder: self.presentationData.nameDisplayOrder, forcedResourceStatus: nil, tapMessage: nil, clickThroughMessage: nil))
let params = ListViewItemLayoutParams(width: layout.size.width, leftInset: layout.safeInsets.left, rightInset: layout.safeInsets.right, availableHeight: layout.size.height) let params = ListViewItemLayoutParams(width: layout.size.width, leftInset: layout.safeInsets.left, rightInset: layout.safeInsets.right, availableHeight: layout.size.height)
if let messageNodes = self.messageNodes { if let _ = self.messageNodes {
// for i in 0 ..< items.count {
// let itemNode = messageNodes[i]
// items[i].updateNode(async: { $0() }, node: {
// return itemNode
// }, params: params, previousItem: i == 0 ? nil : items[i - 1], nextItem: i == (items.count - 1) ? nil : items[i + 1], animation: .None, completion: { (layout, apply) in
// let nodeFrame = CGRect(origin: itemNode.frame.origin, size: CGSize(width: layout.size.width, height: layout.size.height))
//
// itemNode.contentSize = layout.contentSize
// itemNode.insets = layout.insets
// itemNode.frame = nodeFrame
// itemNode.isUserInteractionEnabled = false
//
// apply(ListViewItemApply(isOnScreen: true))
// })
// }
} else { } else {
var messageNodes: [ListViewItemNode] = [] var messageNodes: [ListViewItemNode] = []
for i in 0 ..< items.count { for i in 0 ..< items.count {

View File

@ -888,7 +888,7 @@ public final class ShareController: ViewController {
} }
class MessageStoryRenderer { final class MessageStoryRenderer {
private let context: AccountContext private let context: AccountContext
private let presentationData: PresentationData private let presentationData: PresentationData
private let messages: [Message] private let messages: [Message]
@ -909,7 +909,7 @@ class MessageStoryRenderer {
self.instantChatBackgroundNode = WallpaperBackgroundNode() self.instantChatBackgroundNode = WallpaperBackgroundNode()
self.instantChatBackgroundNode.displaysAsynchronously = false self.instantChatBackgroundNode.displaysAsynchronously = false
self.instantChatBackgroundNode.image = chatControllerBackgroundImage(theme: presentationData.theme, wallpaper: .builtin(WallpaperSettings()), mediaBox: context.sharedContext.accountManager.mediaBox, knockoutMode: context.sharedContext.immediateExperimentalUISettings.knockoutWallpaper) self.instantChatBackgroundNode.image = chatControllerBackgroundImage(theme: self.presentationData.theme, wallpaper: self.presentationData.chatWallpaper, mediaBox: context.sharedContext.accountManager.mediaBox, knockoutMode: context.sharedContext.immediateExperimentalUISettings.knockoutWallpaper)
self.messagesContainerNode = ASDisplayNode() self.messagesContainerNode = ASDisplayNode()
self.messagesContainerNode.clipsToBounds = true self.messagesContainerNode.clipsToBounds = true
@ -920,8 +920,8 @@ class MessageStoryRenderer {
self.addressNode = ImmediateTextNode() self.addressNode = ImmediateTextNode()
self.addressNode.displaysAsynchronously = false self.addressNode.displaysAsynchronously = false
self.addressNode.attributedText = NSAttributedString(string: "t.me/\(addressName)/\(message.id.id)", font: Font.medium(14.0), textColor: UIColor(rgb: 0xa8b7c4)) self.addressNode.attributedText = NSAttributedString(string: "t.me/\(addressName)/\(message.id.id)", font: Font.medium(14.0), textColor: UIColor(rgb: 0xffffff))
// self.addressNode.textShadowColor = .black self.addressNode.textShadowColor = UIColor(rgb: 0x929292, alpha: 0.8)
self.containerNode.addSubnode(self.instantChatBackgroundNode) self.containerNode.addSubnode(self.instantChatBackgroundNode)
self.containerNode.addSubnode(self.messagesContainerNode) self.containerNode.addSubnode(self.messagesContainerNode)
@ -952,12 +952,7 @@ class MessageStoryRenderer {
let theme = self.presentationData.theme.withUpdated(preview: true) let theme = self.presentationData.theme.withUpdated(preview: true)
let headerItem = self.context.sharedContext.makeChatMessageDateHeaderItem(context: self.context, timestamp: self.messages.first?.timestamp ?? 0, theme: theme, strings: self.presentationData.strings, wallpaper: self.presentationData.chatWallpaper, fontSize: self.presentationData.chatFontSize, chatBubbleCorners: self.presentationData.chatBubbleCorners, dateTimeFormat: self.presentationData.dateTimeFormat, nameOrder: self.presentationData.nameDisplayOrder) let headerItem = self.context.sharedContext.makeChatMessageDateHeaderItem(context: self.context, timestamp: self.messages.first?.timestamp ?? 0, theme: theme, strings: self.presentationData.strings, wallpaper: self.presentationData.chatWallpaper, fontSize: self.presentationData.chatFontSize, chatBubbleCorners: self.presentationData.chatBubbleCorners, dateTimeFormat: self.presentationData.dateTimeFormat, nameOrder: self.presentationData.nameDisplayOrder)
var items: [ListViewItem] = [] let items: [ListViewItem] = [self.context.sharedContext.makeChatMessagePreviewItem(context: self.context, messages: self.messages, theme: theme, strings: self.presentationData.strings, wallpaper: self.presentationData.theme.chat.defaultWallpaper, fontSize: self.presentationData.chatFontSize, chatBubbleCorners: self.presentationData.chatBubbleCorners, dateTimeFormat: self.presentationData.dateTimeFormat, nameOrder: self.presentationData.nameDisplayOrder, forcedResourceStatus: nil, tapMessage: nil, clickThroughMessage: nil)]
let sampleMessages: [Message] = self.messages
items = sampleMessages.reversed().map { message in
self.context.sharedContext.makeChatMessagePreviewItem(context: self.context, message: message, theme: theme, strings: self.presentationData.strings, wallpaper: self.presentationData.theme.chat.defaultWallpaper, fontSize: self.presentationData.chatFontSize, chatBubbleCorners: self.presentationData.chatBubbleCorners, dateTimeFormat: self.presentationData.dateTimeFormat, nameOrder: self.presentationData.nameDisplayOrder, forcedResourceStatus: nil, tapMessage: nil, clickThroughMessage: nil)
}
let inset: CGFloat = 16.0 let inset: CGFloat = 16.0
let width = layout.size.width - inset * 2.0 let width = layout.size.width - inset * 2.0

View File

@ -96,8 +96,10 @@ public extension MessageTags {
static let unseenPersonalMessage = MessageTags(rawValue: 1 << 5) static let unseenPersonalMessage = MessageTags(rawValue: 1 << 5)
static let liveLocation = MessageTags(rawValue: 1 << 6) static let liveLocation = MessageTags(rawValue: 1 << 6)
static let gif = MessageTags(rawValue: 1 << 7) static let gif = MessageTags(rawValue: 1 << 7)
static let photo = MessageTags(rawValue: 1 << 8)
static let video = MessageTags(rawValue: 1 << 9)
static let all: MessageTags = [.photoOrVideo, .file, .music, .webPage, .voiceOrInstantVideo, .unseenPersonalMessage, .liveLocation, .gif] static let all: MessageTags = [.photoOrVideo, .file, .music, .webPage, .voiceOrInstantVideo, .unseenPersonalMessage, .liveLocation, .gif, .photo, .video]
} }
public extension GlobalMessageTags { public extension GlobalMessageTags {

View File

@ -2046,39 +2046,6 @@ public extension Api {
}) })
} }
public static func sendEncrypted(peer: Api.InputEncryptedChat, randomId: Int64, data: Buffer) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.messages.SentEncryptedMessage>) {
let buffer = Buffer()
buffer.appendInt32(-1451792525)
peer.serialize(buffer, true)
serializeInt64(randomId, buffer: buffer, boxed: false)
serializeBytes(data, buffer: buffer, boxed: false)
return (FunctionDescription(name: "messages.sendEncrypted", parameters: [("peer", peer), ("randomId", randomId), ("data", data)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.messages.SentEncryptedMessage? in
let reader = BufferReader(buffer)
var result: Api.messages.SentEncryptedMessage?
if let signature = reader.readInt32() {
result = Api.parse(reader, signature: signature) as? Api.messages.SentEncryptedMessage
}
return result
})
}
public static func sendEncryptedFile(peer: Api.InputEncryptedChat, randomId: Int64, data: Buffer, file: Api.InputEncryptedFile) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.messages.SentEncryptedMessage>) {
let buffer = Buffer()
buffer.appendInt32(-1701831834)
peer.serialize(buffer, true)
serializeInt64(randomId, buffer: buffer, boxed: false)
serializeBytes(data, buffer: buffer, boxed: false)
file.serialize(buffer, true)
return (FunctionDescription(name: "messages.sendEncryptedFile", parameters: [("peer", peer), ("randomId", randomId), ("data", data), ("file", file)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.messages.SentEncryptedMessage? in
let reader = BufferReader(buffer)
var result: Api.messages.SentEncryptedMessage?
if let signature = reader.readInt32() {
result = Api.parse(reader, signature: signature) as? Api.messages.SentEncryptedMessage
}
return result
})
}
public static func sendEncryptedService(peer: Api.InputEncryptedChat, randomId: Int64, data: Buffer) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.messages.SentEncryptedMessage>) { public static func sendEncryptedService(peer: Api.InputEncryptedChat, randomId: Int64, data: Buffer) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.messages.SentEncryptedMessage>) {
let buffer = Buffer() let buffer = Buffer()
buffer.appendInt32(852769188) buffer.appendInt32(852769188)
@ -3720,6 +3687,41 @@ public extension Api {
return result return result
}) })
} }
public static func sendEncrypted(flags: Int32, peer: Api.InputEncryptedChat, randomId: Int64, data: Buffer) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.messages.SentEncryptedMessage>) {
let buffer = Buffer()
buffer.appendInt32(1157265941)
serializeInt32(flags, buffer: buffer, boxed: false)
peer.serialize(buffer, true)
serializeInt64(randomId, buffer: buffer, boxed: false)
serializeBytes(data, buffer: buffer, boxed: false)
return (FunctionDescription(name: "messages.sendEncrypted", parameters: [("flags", flags), ("peer", peer), ("randomId", randomId), ("data", data)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.messages.SentEncryptedMessage? in
let reader = BufferReader(buffer)
var result: Api.messages.SentEncryptedMessage?
if let signature = reader.readInt32() {
result = Api.parse(reader, signature: signature) as? Api.messages.SentEncryptedMessage
}
return result
})
}
public static func sendEncryptedFile(flags: Int32, peer: Api.InputEncryptedChat, randomId: Int64, data: Buffer, file: Api.InputEncryptedFile) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.messages.SentEncryptedMessage>) {
let buffer = Buffer()
buffer.appendInt32(1431914525)
serializeInt32(flags, buffer: buffer, boxed: false)
peer.serialize(buffer, true)
serializeInt64(randomId, buffer: buffer, boxed: false)
serializeBytes(data, buffer: buffer, boxed: false)
file.serialize(buffer, true)
return (FunctionDescription(name: "messages.sendEncryptedFile", parameters: [("flags", flags), ("peer", peer), ("randomId", randomId), ("data", data), ("file", file)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.messages.SentEncryptedMessage? in
let reader = BufferReader(buffer)
var result: Api.messages.SentEncryptedMessage?
if let signature = reader.readInt32() {
result = Api.parse(reader, signature: signature) as? Api.messages.SentEncryptedMessage
}
return result
})
}
} }
public struct channels { public struct channels {
public static func readHistory(channel: Api.InputChannel, maxId: Int32) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.Bool>) { public static func readHistory(channel: Api.InputChannel, maxId: Int32) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.Bool>) {

View File

@ -24,7 +24,7 @@ protocol CallControllerNodeProtocol: class {
var acceptCall: (() -> Void)? { get set } var acceptCall: (() -> Void)? { get set }
var endCall: (() -> Void)? { get set } var endCall: (() -> Void)? { get set }
var back: (() -> Void)? { get set } var back: (() -> Void)? { get set }
var presentCallRating: ((CallId) -> Void)? { get set } var presentCallRating: ((CallId, Bool) -> Void)? { get set }
var present: ((ViewController) -> Void)? { get set } var present: ((ViewController) -> Void)? { get set }
var callEnded: ((Bool) -> Void)? { get set } var callEnded: ((Bool) -> Void)? { get set }
var dismissedInteractively: (() -> Void)? { get set } var dismissedInteractively: (() -> Void)? { get set }
@ -230,13 +230,13 @@ public final class CallController: ViewController {
let _ = self?.dismiss() let _ = self?.dismiss()
} }
self.controllerNode.presentCallRating = { [weak self] callId in self.controllerNode.presentCallRating = { [weak self] callId, isVideo in
if let strongSelf = self, !strongSelf.presentedCallRating { if let strongSelf = self, !strongSelf.presentedCallRating {
strongSelf.presentedCallRating = true strongSelf.presentedCallRating = true
Queue.mainQueue().after(0.5, { Queue.mainQueue().after(0.5, {
let window = strongSelf.window let window = strongSelf.window
let controller = callRatingController(sharedContext: strongSelf.sharedContext, account: strongSelf.account, callId: callId, userInitiated: false, present: { c, a in let controller = callRatingController(sharedContext: strongSelf.sharedContext, account: strongSelf.account, callId: callId, userInitiated: false, isVideo: isVideo, present: { c, a in
if let window = window { if let window = window {
c.presentationArguments = a c.presentationArguments = a
window.present(c, on: .root, blockInteraction: false, completion: {}) window.present(c, on: .root, blockInteraction: false, completion: {})

View File

@ -42,18 +42,21 @@ private final class CallVideoNode: ASDisplayNode {
private let isFlippedUpdated: (CallVideoNode) -> Void private let isFlippedUpdated: (CallVideoNode) -> Void
private(set) var currentOrientation: PresentationCallVideoView.Orientation private(set) var currentOrientation: PresentationCallVideoView.Orientation
private(set) var currentAspect: CGFloat = 0.0
private var previousVideoHeight: CGFloat?
init(videoView: PresentationCallVideoView, disabledText: String?, assumeReadyAfterTimeout: Bool, isReadyUpdated: @escaping () -> Void, orientationUpdated: @escaping () -> Void, isFlippedUpdated: @escaping (CallVideoNode) -> Void) { init(videoView: PresentationCallVideoView, disabledText: String?, assumeReadyAfterTimeout: Bool, isReadyUpdated: @escaping () -> Void, orientationUpdated: @escaping () -> Void, isFlippedUpdated: @escaping (CallVideoNode) -> Void) {
self.isReadyUpdated = isReadyUpdated self.isReadyUpdated = isReadyUpdated
self.isFlippedUpdated = isFlippedUpdated self.isFlippedUpdated = isFlippedUpdated
self.videoTransformContainer = ASDisplayNode() self.videoTransformContainer = ASDisplayNode()
self.videoTransformContainer.clipsToBounds = true
self.videoView = videoView self.videoView = videoView
videoView.view.clipsToBounds = true videoView.view.clipsToBounds = true
videoView.view.backgroundColor = .black videoView.view.backgroundColor = .black
self.currentOrientation = videoView.getOrientation() self.currentOrientation = videoView.getOrientation()
self.currentAspect = videoView.getAspect()
self.videoPausedNode = ImmediateTextNode() self.videoPausedNode = ImmediateTextNode()
self.videoPausedNode.alpha = 0.0 self.videoPausedNode.alpha = 0.0
@ -89,13 +92,14 @@ private final class CallVideoNode: ASDisplayNode {
} }
} }
self.videoView.setOnOrientationUpdated { [weak self] orientation in self.videoView.setOnOrientationUpdated { [weak self] orientation, aspect in
Queue.mainQueue().async { Queue.mainQueue().async {
guard let strongSelf = self else { guard let strongSelf = self else {
return return
} }
if strongSelf.currentOrientation != orientation { if strongSelf.currentOrientation != orientation || strongSelf.currentAspect != aspect {
strongSelf.currentOrientation = orientation strongSelf.currentOrientation = orientation
strongSelf.currentAspect = aspect
orientationUpdated() orientationUpdated()
} }
} }
@ -164,91 +168,100 @@ private final class CallVideoNode: ASDisplayNode {
}) })
} }
func updateLayout(size: CGSize, cornerRadius: CGFloat, deviceOrientation: UIDeviceOrientation, transition: ContainedViewLayoutTransition) { func updateLayout(size: CGSize, cornerRadius: CGFloat, isOutgoing: Bool, deviceOrientation: UIDeviceOrientation, isCompactLayout: Bool, transition: ContainedViewLayoutTransition) {
self.currentCornerRadius = cornerRadius self.currentCornerRadius = cornerRadius
var rotationAngle: CGFloat var rotationAngle: CGFloat
switch self.currentOrientation { if isOutgoing {
case .rotation0:
rotationAngle = 0.0
case .rotation90:
rotationAngle = -CGFloat.pi / 2.0
case .rotation180:
rotationAngle = -CGFloat.pi
case .rotation270:
rotationAngle = CGFloat.pi / 2.0 rotationAngle = CGFloat.pi / 2.0
}
var additionalAngle: CGFloat = 0.0
switch deviceOrientation {
case .portrait:
additionalAngle = 0.0
case .landscapeLeft:
additionalAngle = CGFloat.pi / 2.0
case .landscapeRight:
additionalAngle = -CGFloat.pi / 2.0
case .portraitUpsideDown:
rotationAngle = -CGFloat.pi
default:
additionalAngle = 0.0
}
rotationAngle += additionalAngle
if abs(rotationAngle - (-CGFloat.pi)) < 1.0 {
rotationAngle = -CGFloat.pi + 0.001
}
var rotateFrame = abs(rotationAngle.remainder(dividingBy: CGFloat.pi)) > 1.0
var originalRotateFrame = rotateFrame
if size.width > size.height {
rotateFrame = !rotateFrame
if rotateFrame {
originalRotateFrame = true
}
} else { } else {
if rotateFrame { switch self.currentOrientation {
originalRotateFrame = false case .rotation0:
rotationAngle = 0.0
case .rotation90:
rotationAngle = CGFloat.pi / 2.0
case .rotation180:
rotationAngle = CGFloat.pi
case .rotation270:
rotationAngle = -CGFloat.pi / 2.0
}
var additionalAngle: CGFloat = 0.0
switch deviceOrientation {
case .portrait:
additionalAngle = 0.0
case .landscapeLeft:
additionalAngle = CGFloat.pi / 2.0
case .landscapeRight:
additionalAngle = -CGFloat.pi / 2.0
case .portraitUpsideDown:
rotationAngle = CGFloat.pi
default:
additionalAngle = 0.0
}
rotationAngle += additionalAngle
if abs(rotationAngle - (-CGFloat.pi)) < 1.0 {
rotationAngle = -CGFloat.pi + 0.001
} }
} }
let videoFrame: CGRect
let scale: CGFloat let rotateFrame = abs(rotationAngle.remainder(dividingBy: CGFloat.pi)) > 1.0
let fittingSize: CGSize
if rotateFrame { if rotateFrame {
let frameSize = CGSize(width: size.height, height: size.width).aspectFitted(size) fittingSize = CGSize(width: size.height, height: size.width)
videoFrame = CGRect(origin: CGPoint(x: floor((size.width - frameSize.width) / 2.0), y: floor((size.height - frameSize.height) / 2.0)), size: frameSize)
if size.width > size.height {
scale = frameSize.height / size.width
} else {
scale = frameSize.width / size.height
}
} else { } else {
videoFrame = CGRect(origin: CGPoint(), size: size) fittingSize = size
if size.width > size.height { }
scale = 1.0
let unboundVideoSize = CGSize(width: self.currentAspect * 10000.0, height: 10000.0)
var fittedVideoSize = unboundVideoSize.fitted(fittingSize)
if fittedVideoSize.width < fittingSize.width || fittedVideoSize.height < fittingSize.height {
let isVideoPortrait = unboundVideoSize.width < unboundVideoSize.height
let isFittingSizePortrait = fittingSize.width < fittingSize.height
if isCompactLayout && isVideoPortrait == isFittingSizePortrait {
fittedVideoSize = unboundVideoSize.aspectFilled(fittingSize)
} else { } else {
scale = 1.0 let maxFittingEdgeDistance: CGFloat
if isCompactLayout {
maxFittingEdgeDistance = 200.0
} else {
maxFittingEdgeDistance = 400.0
}
if fittedVideoSize.width > fittingSize.width - maxFittingEdgeDistance && fittedVideoSize.height > fittingSize.height - maxFittingEdgeDistance {
fittedVideoSize = unboundVideoSize.aspectFilled(fittingSize)
}
} }
} }
let rotatedVideoHeight: CGFloat = max(fittedVideoSize.height, fittedVideoSize.width)
let videoFrame: CGRect = CGRect(origin: CGPoint(), size: fittedVideoSize)
let videoPausedSize = self.videoPausedNode.updateLayout(CGSize(width: size.width - 16.0, height: 100.0)) let videoPausedSize = self.videoPausedNode.updateLayout(CGSize(width: size.width - 16.0, height: 100.0))
transition.updateFrame(node: self.videoPausedNode, frame: CGRect(origin: CGPoint(x: floor((size.width - videoPausedSize.width) / 2.0), y: floor((size.height - videoPausedSize.height) / 2.0)), size: videoPausedSize)) transition.updateFrame(node: self.videoPausedNode, frame: CGRect(origin: CGPoint(x: floor((size.width - videoPausedSize.width) / 2.0), y: floor((size.height - videoPausedSize.height) / 2.0)), size: videoPausedSize))
let previousVideoFrame = self.videoTransformContainer.frame self.videoTransformContainer.bounds = CGRect(origin: CGPoint(), size: videoFrame.size)
self.videoTransformContainer.bounds = CGRect(origin: CGPoint(), size: size) if transition.isAnimated && !videoFrame.height.isZero, let previousVideoHeight = self.previousVideoHeight, !previousVideoHeight.isZero {
if transition.isAnimated && !videoFrame.height.isZero && !previousVideoFrame.height.isZero { let scaleDifference = previousVideoHeight / rotatedVideoHeight
transition.animateTransformScale(node: self.videoTransformContainer, from: previousVideoFrame.height / size.height, additive: true) if abs(scaleDifference - 1.0) > 0.001 {
transition.animateTransformScale(node: self.videoTransformContainer, from: scaleDifference, additive: true)
}
} }
transition.updatePosition(node: self.videoTransformContainer, position: videoFrame.center) self.previousVideoHeight = rotatedVideoHeight
transition.updateSublayerTransformScale(node: self.videoTransformContainer, scale: scale) transition.updatePosition(node: self.videoTransformContainer, position: CGPoint(x: size.width / 2.0, y: size.height / 2.0))
transition.updateTransformRotation(view: self.videoTransformContainer.view, angle: rotationAngle)
let localVideoSize = originalRotateFrame ? CGSize(width: size.height, height: size.width) : size
let localVideoFrame = CGRect(origin: CGPoint(x: floor((size.width - localVideoSize.width) / 2.0), y: floor((size.height - localVideoSize.height) / 2.0)), size: localVideoSize)
let localVideoFrame = CGRect(origin: CGPoint(), size: videoFrame.size)
self.videoView.view.bounds = localVideoFrame self.videoView.view.bounds = localVideoFrame
self.videoView.view.center = localVideoFrame.center self.videoView.view.center = localVideoFrame.center
transition.updateTransformRotation(view: self.videoView.view, angle: rotationAngle) // TODO: properly fix the issue
// On iOS 13 and later metal layer transformation is broken if the layer does not require compositing
self.videoView.view.alpha = 0.995
if let effectView = self.effectView { if let effectView = self.effectView {
transition.updateFrame(view: effectView, frame: videoFrame) transition.updateFrame(view: effectView, frame: localVideoFrame)
} }
transition.updateCornerRadius(layer: self.layer, cornerRadius: self.currentCornerRadius) transition.updateCornerRadius(layer: self.layer, cornerRadius: self.currentCornerRadius)
@ -392,7 +405,7 @@ final class CallControllerNode: ViewControllerTracingNode, CallControllerNodePro
var acceptCall: (() -> Void)? var acceptCall: (() -> Void)?
var endCall: (() -> Void)? var endCall: (() -> Void)?
var back: (() -> Void)? var back: (() -> Void)?
var presentCallRating: ((CallId) -> Void)? var presentCallRating: ((CallId, Bool) -> Void)?
var callEnded: ((Bool) -> Void)? var callEnded: ((Bool) -> Void)?
var dismissedInteractively: (() -> Void)? var dismissedInteractively: (() -> Void)?
var present: ((ViewController) -> Void)? var present: ((ViewController) -> Void)?
@ -419,6 +432,8 @@ final class CallControllerNode: ViewControllerTracingNode, CallControllerNodePro
private var deviceOrientation: UIDeviceOrientation = .portrait private var deviceOrientation: UIDeviceOrientation = .portrait
private var orientationDidChangeObserver: NSObjectProtocol? private var orientationDidChangeObserver: NSObjectProtocol?
private var currentRequestedAspect: CGFloat?
init(sharedContext: SharedAccountContext, account: Account, presentationData: PresentationData, statusBar: StatusBar, debugInfo: Signal<(String, String), NoError>, shouldStayHiddenUntilConnection: Bool = false, easyDebugAccess: Bool, call: PresentationCall) { init(sharedContext: SharedAccountContext, account: Account, presentationData: PresentationData, statusBar: StatusBar, debugInfo: Signal<(String, String), NoError>, shouldStayHiddenUntilConnection: Bool = false, easyDebugAccess: Bool, call: PresentationCall) {
self.sharedContext = sharedContext self.sharedContext = sharedContext
self.account = account self.account = account
@ -922,11 +937,18 @@ final class CallControllerNode: ViewControllerTracingNode, CallControllerNodePro
case let .error(error): case let .error(error):
let text = self.presentationData.strings.Call_StatusFailed let text = self.presentationData.strings.Call_StatusFailed
switch error { switch error {
case .notSupportedByPeer: case let .notSupportedByPeer(isVideo):
if !self.displayedVersionOutdatedAlert, let peer = self.peer { if !self.displayedVersionOutdatedAlert, let peer = self.peer {
self.displayedVersionOutdatedAlert = true self.displayedVersionOutdatedAlert = true
self.present?(textAlertController(sharedContext: self.sharedContext, title: nil, text: self.presentationData.strings.Call_ParticipantVersionOutdatedError(peer.displayTitle(strings: self.presentationData.strings, displayOrder: self.presentationData.nameDisplayOrder)).0, actions: [TextAlertAction(type: .defaultAction, title: self.presentationData.strings.Common_OK, action: { let text: String
if isVideo {
text = self.presentationData.strings.Call_ParticipantVideoVersionOutdatedError(peer.displayTitle(strings: self.presentationData.strings, displayOrder: self.presentationData.nameDisplayOrder)).0
} else {
text = self.presentationData.strings.Call_ParticipantVersionOutdatedError(peer.displayTitle(strings: self.presentationData.strings, displayOrder: self.presentationData.nameDisplayOrder)).0
}
self.present?(textAlertController(sharedContext: self.sharedContext, title: nil, text: text, actions: [TextAlertAction(type: .defaultAction, title: self.presentationData.strings.Common_OK, action: {
})])) })]))
} }
default: default:
@ -1005,8 +1027,10 @@ final class CallControllerNode: ViewControllerTracingNode, CallControllerNodePro
self.updateButtonsMode() self.updateButtonsMode()
self.updateDimVisibility() self.updateDimVisibility()
if self.incomingVideoViewRequested && self.outgoingVideoViewRequested { if self.incomingVideoViewRequested || self.outgoingVideoViewRequested {
self.displayedCameraTooltip = true if self.incomingVideoViewRequested && self.outgoingVideoViewRequested {
self.displayedCameraTooltip = true
}
self.displayedCameraConfirmation = true self.displayedCameraConfirmation = true
} }
if self.incomingVideoViewRequested && !self.outgoingVideoViewRequested && !self.displayedCameraTooltip && (self.toastContent?.isEmpty ?? true) { if self.incomingVideoViewRequested && !self.outgoingVideoViewRequested && !self.displayedCameraTooltip && (self.toastContent?.isEmpty ?? true) {
@ -1019,7 +1043,7 @@ final class CallControllerNode: ViewControllerTracingNode, CallControllerNodePro
if case let .terminated(id, _, reportRating) = callState.state, let callId = id { if case let .terminated(id, _, reportRating) = callState.state, let callId = id {
let presentRating = reportRating || self.forceReportRating let presentRating = reportRating || self.forceReportRating
if presentRating { if presentRating {
self.presentCallRating?(callId) self.presentCallRating?(callId, self.call.isVideo)
} }
self.callEnded?(presentRating) self.callEnded?(presentRating)
} }
@ -1253,12 +1277,12 @@ final class CallControllerNode: ViewControllerTracingNode, CallControllerNodePro
let previewVideoSide = interpolate(from: 350.0, to: 200.0, value: 1.0 - self.pictureInPictureTransitionFraction) let previewVideoSide = interpolate(from: 350.0, to: 200.0, value: 1.0 - self.pictureInPictureTransitionFraction)
var previewVideoSize = layout.size.aspectFitted(CGSize(width: previewVideoSide, height: previewVideoSide)) var previewVideoSize = layout.size.aspectFitted(CGSize(width: previewVideoSide, height: previewVideoSide))
previewVideoSize = CGSize(width: 30.0, height: 45.0).aspectFitted(previewVideoSize) previewVideoSize = CGSize(width: 30.0, height: 45.0).aspectFitted(previewVideoSize)
if let minimizedVideoNode = minimizedVideoNode { if let minimizedVideoNode = self.minimizedVideoNode {
switch minimizedVideoNode.currentOrientation { switch minimizedVideoNode.currentOrientation {
case .rotation90, .rotation270: case .rotation90, .rotation270:
previewVideoSize = CGSize(width: previewVideoSize.height, height: previewVideoSize.width)
default:
break break
default:
previewVideoSize = CGSize(width: previewVideoSize.height, height: previewVideoSize.width)
} }
} }
let previewVideoY: CGFloat let previewVideoY: CGFloat
@ -1305,6 +1329,13 @@ final class CallControllerNode: ViewControllerTracingNode, CallControllerNodePro
func containerLayoutUpdated(_ layout: ContainerViewLayout, navigationBarHeight: CGFloat, transition: ContainedViewLayoutTransition) { func containerLayoutUpdated(_ layout: ContainerViewLayout, navigationBarHeight: CGFloat, transition: ContainedViewLayoutTransition) {
self.validLayout = (layout, navigationBarHeight) self.validLayout = (layout, navigationBarHeight)
var mappedDeviceOrientation = self.deviceOrientation
var isCompactLayout = true
if case .regular = layout.metrics.widthClass, case .regular = layout.metrics.heightClass {
mappedDeviceOrientation = .portrait
isCompactLayout = false
}
if !self.hasVideoNodes { if !self.hasVideoNodes {
self.isUIHidden = false self.isUIHidden = false
} }
@ -1449,7 +1480,7 @@ final class CallControllerNode: ViewControllerTracingNode, CallControllerNodePro
expandedVideoTransition.updateFrame(node: expandedVideoNode, frame: fullscreenVideoFrame) expandedVideoTransition.updateFrame(node: expandedVideoNode, frame: fullscreenVideoFrame)
} }
expandedVideoNode.updateLayout(size: expandedVideoNode.frame.size, cornerRadius: 0.0, deviceOrientation: self.deviceOrientation, transition: expandedVideoTransition) expandedVideoNode.updateLayout(size: expandedVideoNode.frame.size, cornerRadius: 0.0, isOutgoing: expandedVideoNode === self.outgoingVideoNodeValue, deviceOrientation: mappedDeviceOrientation, isCompactLayout: isCompactLayout, transition: expandedVideoTransition)
if self.animateRequestedVideoOnce { if self.animateRequestedVideoOnce {
self.animateRequestedVideoOnce = false self.animateRequestedVideoOnce = false
@ -1499,7 +1530,7 @@ final class CallControllerNode: ViewControllerTracingNode, CallControllerNodePro
self.animationForExpandedVideoSnapshotView = nil self.animationForExpandedVideoSnapshotView = nil
} }
minimizedVideoTransition.updateFrame(node: minimizedVideoNode, frame: previewVideoFrame) minimizedVideoTransition.updateFrame(node: minimizedVideoNode, frame: previewVideoFrame)
minimizedVideoNode.updateLayout(size: previewVideoFrame.size, cornerRadius: interpolate(from: 14.0, to: 24.0, value: self.pictureInPictureTransitionFraction), deviceOrientation: .portrait, transition: minimizedVideoTransition) minimizedVideoNode.updateLayout(size: previewVideoFrame.size, cornerRadius: interpolate(from: 14.0, to: 24.0, value: self.pictureInPictureTransitionFraction), isOutgoing: minimizedVideoNode === self.outgoingVideoNodeValue, deviceOrientation: .portrait, isCompactLayout: false, transition: minimizedVideoTransition)
if transition.isAnimated && didAppear { if transition.isAnimated && didAppear {
minimizedVideoNode.layer.animateSpring(from: 0.1 as NSNumber, to: 1.0 as NSNumber, keyPath: "transform.scale", duration: 0.5) minimizedVideoNode.layer.animateSpring(from: 0.1 as NSNumber, to: 1.0 as NSNumber, keyPath: "transform.scale", duration: 0.5)
} }
@ -1515,6 +1546,43 @@ final class CallControllerNode: ViewControllerTracingNode, CallControllerNodePro
if let debugNode = self.debugNode { if let debugNode = self.debugNode {
transition.updateFrame(node: debugNode, frame: CGRect(origin: CGPoint(), size: layout.size)) transition.updateFrame(node: debugNode, frame: CGRect(origin: CGPoint(), size: layout.size))
} }
let requestedAspect: CGFloat
if case .compact = layout.metrics.widthClass, case .compact = layout.metrics.heightClass {
var isIncomingVideoRotated = false
var rotationCount = 0
switch mappedDeviceOrientation {
case .portrait:
break
case .landscapeLeft:
rotationCount += 1
case .landscapeRight:
rotationCount += 1
case .portraitUpsideDown:
break
default:
break
}
if rotationCount % 2 != 0 {
isIncomingVideoRotated = true
}
if !isIncomingVideoRotated {
requestedAspect = layout.size.width / layout.size.height
} else {
requestedAspect = 0.0
}
} else {
requestedAspect = 0.0
}
if self.currentRequestedAspect != requestedAspect {
self.currentRequestedAspect = requestedAspect
if !self.sharedContext.immediateExperimentalUISettings.disableVideoAspectScaling {
self.call.setRequestedVideoAspect(Float(requestedAspect))
}
}
} }
@objc func keyPressed() { @objc func keyPressed() {

View File

@ -12,6 +12,9 @@ import OverlayStatusController
import AccountContext import AccountContext
private enum CallFeedbackReason: Int32, CaseIterable { private enum CallFeedbackReason: Int32, CaseIterable {
case videoDistorted
case videoLowQuality
case echo case echo
case noise case noise
case interruption case interruption
@ -36,6 +39,19 @@ private enum CallFeedbackReason: Int32, CaseIterable {
return "silent_remote" return "silent_remote"
case .dropped: case .dropped:
return "dropped" return "dropped"
case .videoDistorted:
return "distorted_video"
case .videoLowQuality:
return "pixelated_video"
}
}
var isVideoRelated: Bool {
switch self {
case .videoDistorted, .videoLowQuality:
return true
default:
return false
} }
} }
@ -55,6 +71,10 @@ private enum CallFeedbackReason: Int32, CaseIterable {
return strings.CallFeedback_ReasonSilentRemote return strings.CallFeedback_ReasonSilentRemote
case .dropped: case .dropped:
return strings.CallFeedback_ReasonDropped return strings.CallFeedback_ReasonDropped
case .videoDistorted:
return strings.CallFeedback_VideoReasonDistorted
case .videoLowQuality:
return strings.CallFeedback_VideoReasonLowQuality
} }
} }
} }
@ -214,11 +234,22 @@ private struct CallFeedbackState: Equatable {
} }
} }
private func callFeedbackControllerEntries(theme: PresentationTheme, strings: PresentationStrings, state: CallFeedbackState) -> [CallFeedbackControllerEntry] { private func callFeedbackControllerEntries(theme: PresentationTheme, strings: PresentationStrings, state: CallFeedbackState, isVideo: Bool) -> [CallFeedbackControllerEntry] {
var entries: [CallFeedbackControllerEntry] = [] var entries: [CallFeedbackControllerEntry] = []
entries.append(.reasonsHeader(theme, strings.CallFeedback_WhatWentWrong)) entries.append(.reasonsHeader(theme, strings.CallFeedback_WhatWentWrong))
if isVideo {
for reason in CallFeedbackReason.allCases {
if !reason.isVideoRelated {
continue
}
entries.append(.reason(theme, reason, CallFeedbackReason.localizedString(for: reason, strings: strings), state.reasons.contains(reason)))
}
}
for reason in CallFeedbackReason.allCases { for reason in CallFeedbackReason.allCases {
if reason.isVideoRelated {
continue
}
entries.append(.reason(theme, reason, CallFeedbackReason.localizedString(for: reason, strings: strings), state.reasons.contains(reason))) entries.append(.reason(theme, reason, CallFeedbackReason.localizedString(for: reason, strings: strings), state.reasons.contains(reason)))
} }
@ -230,7 +261,7 @@ private func callFeedbackControllerEntries(theme: PresentationTheme, strings: Pr
return entries return entries
} }
public func callFeedbackController(sharedContext: SharedAccountContext, account: Account, callId: CallId, rating: Int, userInitiated: Bool) -> ViewController { public func callFeedbackController(sharedContext: SharedAccountContext, account: Account, callId: CallId, rating: Int, userInitiated: Bool, isVideo: Bool) -> ViewController {
let initialState = CallFeedbackState() let initialState = CallFeedbackState()
let statePromise = ValuePromise(initialState, ignoreRepeated: true) let statePromise = ValuePromise(initialState, ignoreRepeated: true)
let stateValue = Atomic(value: initialState) let stateValue = Atomic(value: initialState)
@ -290,7 +321,7 @@ public func callFeedbackController(sharedContext: SharedAccountContext, account:
}) })
let controllerState = ItemListControllerState(presentationData: ItemListPresentationData(presentationData), title: .text(presentationData.strings.CallFeedback_Title), leftNavigationButton: leftNavigationButton, rightNavigationButton: rightNavigationButton, backNavigationButton: ItemListBackButton(title: presentationData.strings.Common_Back)) let controllerState = ItemListControllerState(presentationData: ItemListPresentationData(presentationData), title: .text(presentationData.strings.CallFeedback_Title), leftNavigationButton: leftNavigationButton, rightNavigationButton: rightNavigationButton, backNavigationButton: ItemListBackButton(title: presentationData.strings.Common_Back))
let listState = ItemListNodeState(presentationData: ItemListPresentationData(presentationData), entries: callFeedbackControllerEntries(theme: presentationData.theme, strings: presentationData.strings, state: state), style: .blocks, animateChanges: false) let listState = ItemListNodeState(presentationData: ItemListPresentationData(presentationData), entries: callFeedbackControllerEntries(theme: presentationData.theme, strings: presentationData.strings, state: state, isVideo: isVideo), style: .blocks, animateChanges: false)
return (controllerState, (listState, arguments)) return (controllerState, (listState, arguments))
} }

View File

@ -246,7 +246,7 @@ func rateCallAndSendLogs(account: Account, callId: CallId, starsCount: Int, comm
let rate = rateCall(account: account, callId: callId, starsCount: Int32(starsCount), comment: comment, userInitiated: userInitiated) let rate = rateCall(account: account, callId: callId, starsCount: Int32(starsCount), comment: comment, userInitiated: userInitiated)
if includeLogs { if includeLogs {
let id = arc4random64() let id = arc4random64()
let name = "\(callId.id)_\(callId.accessHash).log" let name = "\(callId.id)_\(callId.accessHash).log.json"
let path = callLogsPath(account: account) + "/" + name let path = callLogsPath(account: account) + "/" + name
let file = TelegramMediaFile(fileId: MediaId(namespace: Namespaces.Media.LocalFile, id: id), partialReference: nil, resource: LocalFileReferenceMediaResource(localFilePath: path, randomId: id), previewRepresentations: [], videoThumbnails: [], immediateThumbnailData: nil, mimeType: "application/text", size: nil, attributes: [.FileName(fileName: name)]) let file = TelegramMediaFile(fileId: MediaId(namespace: Namespaces.Media.LocalFile, id: id), partialReference: nil, resource: LocalFileReferenceMediaResource(localFilePath: path, randomId: id), previewRepresentations: [], videoThumbnails: [], immediateThumbnailData: nil, mimeType: "application/text", size: nil, attributes: [.FileName(fileName: name)])
let message = EnqueueMessage.message(text: comment, attributes: [], mediaReference: .standalone(media: file), replyToMessageId: nil, localGroupingKey: nil) let message = EnqueueMessage.message(text: comment, attributes: [], mediaReference: .standalone(media: file), replyToMessageId: nil, localGroupingKey: nil)
@ -266,7 +266,7 @@ func rateCallAndSendLogs(account: Account, callId: CallId, starsCount: Int, comm
} }
} }
public func callRatingController(sharedContext: SharedAccountContext, account: Account, callId: CallId, userInitiated: Bool, present: @escaping (ViewController, Any) -> Void, push: @escaping (ViewController) -> Void) -> AlertController { public func callRatingController(sharedContext: SharedAccountContext, account: Account, callId: CallId, userInitiated: Bool, isVideo: Bool, present: @escaping (ViewController, Any) -> Void, push: @escaping (ViewController) -> Void) -> AlertController {
let presentationData = sharedContext.currentPresentationData.with { $0 } let presentationData = sharedContext.currentPresentationData.with { $0 }
let theme = presentationData.theme let theme = presentationData.theme
let strings = presentationData.strings let strings = presentationData.strings
@ -282,7 +282,7 @@ public func callRatingController(sharedContext: SharedAccountContext, account: A
}, apply: { rating in }, apply: { rating in
dismissImpl?(true) dismissImpl?(true)
if rating < 4 { if rating < 4 {
push(callFeedbackController(sharedContext: sharedContext, account: account, callId: callId, rating: rating, userInitiated: userInitiated)) push(callFeedbackController(sharedContext: sharedContext, account: account, callId: callId, rating: rating, userInitiated: userInitiated, isVideo: isVideo))
} else { } else {
let _ = rateCallAndSendLogs(account: account, callId: callId, starsCount: rating, comment: "", userInitiated: userInitiated, includeLogs: false).start() let _ = rateCallAndSendLogs(account: account, callId: callId, starsCount: rating, comment: "", userInitiated: userInitiated, includeLogs: false).start()
} }

View File

@ -62,7 +62,7 @@ final class LegacyCallControllerNode: ASDisplayNode, CallControllerNodeProtocol
var endCall: (() -> Void)? var endCall: (() -> Void)?
var setIsVideoPaused: ((Bool) -> Void)? var setIsVideoPaused: ((Bool) -> Void)?
var back: (() -> Void)? var back: (() -> Void)?
var presentCallRating: ((CallId) -> Void)? var presentCallRating: ((CallId, Bool) -> Void)?
var callEnded: ((Bool) -> Void)? var callEnded: ((Bool) -> Void)?
var dismissedInteractively: (() -> Void)? var dismissedInteractively: (() -> Void)?
var present: ((ViewController) -> Void)? var present: ((ViewController) -> Void)?
@ -307,7 +307,7 @@ final class LegacyCallControllerNode: ASDisplayNode, CallControllerNodeProtocol
if case let .terminated(id, _, reportRating) = callState.state, let callId = id { if case let .terminated(id, _, reportRating) = callState.state, let callId = id {
let presentRating = reportRating || self.forceReportRating let presentRating = reportRating || self.forceReportRating
if presentRating { if presentRating {
self.presentCallRating?(callId) self.presentCallRating?(callId, false)
} }
self.callEnded?(presentRating) self.callEnded?(presentRating)
} }

View File

@ -169,6 +169,8 @@ public final class PresentationCallImpl: PresentationCall {
public let isOutgoing: Bool public let isOutgoing: Bool
public var isVideo: Bool public var isVideo: Bool
public var isVideoPossible: Bool public var isVideoPossible: Bool
private let enableStunMarking: Bool
private let enableTCP: Bool
public let preferredVideoCodec: String? public let preferredVideoCodec: String?
public let peer: Peer? public let peer: Peer?
@ -184,6 +186,7 @@ public final class PresentationCallImpl: PresentationCall {
private var callContextState: OngoingCallContextState? private var callContextState: OngoingCallContextState?
private var ongoingContext: OngoingCallContext? private var ongoingContext: OngoingCallContext?
private var ongoingContextStateDisposable: Disposable? private var ongoingContextStateDisposable: Disposable?
private var requestedVideoAspect: Float?
private var reception: Int32? private var reception: Int32?
private var receptionDisposable: Disposable? private var receptionDisposable: Disposable?
private var reportedIncomingCall = false private var reportedIncomingCall = false
@ -265,6 +268,8 @@ public final class PresentationCallImpl: PresentationCall {
updatedNetworkType: Signal<NetworkType, NoError>, updatedNetworkType: Signal<NetworkType, NoError>,
startWithVideo: Bool, startWithVideo: Bool,
isVideoPossible: Bool, isVideoPossible: Bool,
enableStunMarking: Bool,
enableTCP: Bool,
preferredVideoCodec: String? preferredVideoCodec: String?
) { ) {
self.account = account self.account = account
@ -292,6 +297,8 @@ public final class PresentationCallImpl: PresentationCall {
self.isOutgoing = isOutgoing self.isOutgoing = isOutgoing
self.isVideo = initialState?.type == .video self.isVideo = initialState?.type == .video
self.isVideoPossible = isVideoPossible self.isVideoPossible = isVideoPossible
self.enableStunMarking = enableStunMarking
self.enableTCP = enableTCP
self.preferredVideoCodec = preferredVideoCodec self.preferredVideoCodec = preferredVideoCodec
self.peer = peer self.peer = peer
self.isVideo = startWithVideo self.isVideo = startWithVideo
@ -606,9 +613,12 @@ public final class PresentationCallImpl: PresentationCall {
if let _ = audioSessionControl, !wasActive || previousControl == nil { if let _ = audioSessionControl, !wasActive || previousControl == nil {
let logName = "\(id.id)_\(id.accessHash)" let logName = "\(id.id)_\(id.accessHash)"
let ongoingContext = OngoingCallContext(account: account, callSessionManager: self.callSessionManager, internalId: self.internalId, proxyServer: proxyServer, initialNetworkType: self.currentNetworkType, updatedNetworkType: self.updatedNetworkType, serializedData: self.serializedData, dataSaving: dataSaving, derivedState: self.derivedState, key: key, isOutgoing: sessionState.isOutgoing, video: self.videoCapturer, connections: connections, maxLayer: maxLayer, version: version, allowP2P: allowsP2P, audioSessionActive: self.audioSessionActive.get(), logName: logName, preferredVideoCodec: self.preferredVideoCodec) let ongoingContext = OngoingCallContext(account: account, callSessionManager: self.callSessionManager, internalId: self.internalId, proxyServer: proxyServer, initialNetworkType: self.currentNetworkType, updatedNetworkType: self.updatedNetworkType, serializedData: self.serializedData, dataSaving: dataSaving, derivedState: self.derivedState, key: key, isOutgoing: sessionState.isOutgoing, video: self.videoCapturer, connections: connections, maxLayer: maxLayer, version: version, allowP2P: allowsP2P, enableTCP: self.enableTCP, enableStunMarking: self.enableStunMarking, audioSessionActive: self.audioSessionActive.get(), logName: logName, preferredVideoCodec: self.preferredVideoCodec)
self.ongoingContext = ongoingContext self.ongoingContext = ongoingContext
ongoingContext.setIsMuted(self.isMutedValue) ongoingContext.setIsMuted(self.isMutedValue)
if let requestedVideoAspect = self.requestedVideoAspect {
ongoingContext.setRequestedVideoAspect(requestedVideoAspect)
}
self.debugInfoValue.set(ongoingContext.debugInfo()) self.debugInfoValue.set(ongoingContext.debugInfo())
@ -848,6 +858,11 @@ public final class PresentationCallImpl: PresentationCall {
} }
} }
public func setRequestedVideoAspect(_ aspect: Float) {
self.requestedVideoAspect = aspect
self.ongoingContext?.setRequestedVideoAspect(aspect)
}
public func disableVideo() { public func disableVideo() {
if let _ = self.videoCapturer { if let _ = self.videoCapturer {
self.videoCapturer = nil self.videoCapturer = nil
@ -909,8 +924,15 @@ public final class PresentationCallImpl: PresentationCall {
return .rotation0 return .rotation0
} }
}, },
getAspect: { [weak view] in
if let view = view {
return view.getAspect()
} else {
return 0.0
}
},
setOnOrientationUpdated: { f in setOnOrientationUpdated: { f in
setOnOrientationUpdated { value in setOnOrientationUpdated { value, aspect in
let mappedValue: PresentationCallVideoView.Orientation let mappedValue: PresentationCallVideoView.Orientation
switch value { switch value {
case .rotation0: case .rotation0:
@ -922,7 +944,7 @@ public final class PresentationCallImpl: PresentationCall {
case .rotation270: case .rotation270:
mappedValue = .rotation270 mappedValue = .rotation270
} }
f?(mappedValue) f?(mappedValue, aspect)
} }
}, },
setOnIsMirroredUpdated: { f in setOnIsMirroredUpdated: { f in
@ -971,8 +993,15 @@ public final class PresentationCallImpl: PresentationCall {
return .rotation0 return .rotation0
} }
}, },
getAspect: { [weak view] in
if let view = view {
return view.getAspect()
} else {
return 0.0
}
},
setOnOrientationUpdated: { f in setOnOrientationUpdated: { f in
setOnOrientationUpdated { value in setOnOrientationUpdated { value, aspect in
let mappedValue: PresentationCallVideoView.Orientation let mappedValue: PresentationCallVideoView.Orientation
switch value { switch value {
case .rotation0: case .rotation0:
@ -984,7 +1013,7 @@ public final class PresentationCallImpl: PresentationCall {
case .rotation270: case .rotation270:
mappedValue = .rotation270 mappedValue = .rotation270
} }
f?(mappedValue) f?(mappedValue, aspect)
} }
}, },
setOnIsMirroredUpdated: { f in setOnIsMirroredUpdated: { f in

View File

@ -17,45 +17,14 @@ private func callKitIntegrationIfEnabled(_ integration: CallKitIntegration?, set
return enabled ? integration : nil return enabled ? integration : nil
} }
private func auxiliaryServers(appConfiguration: AppConfiguration) -> [CallAuxiliaryServer] { private func shouldEnableStunMarking(appConfiguration: AppConfiguration) -> Bool {
guard let data = appConfiguration.data else { guard let data = appConfiguration.data else {
return [] return true
} }
guard let servers = data["rtc_servers"] as? [[String: Any]] else { guard let enableStunMarking = data["voip_enable_stun_marking"] as? Bool else {
return [] return true
} }
var result: [CallAuxiliaryServer] = [] return enableStunMarking
for server in servers {
guard let host = server["host"] as? String else {
continue
}
guard let portString = server["port"] as? String else {
continue
}
guard let username = server["username"] as? String else {
continue
}
guard let password = server["password"] as? String else {
continue
}
guard let port = Int(portString) else {
continue
}
result.append(CallAuxiliaryServer(
host: host,
port: port,
connection: .stun
))
result.append(CallAuxiliaryServer(
host: host,
port: port,
connection: .turn(
username: username,
password: password
)
))
}
return result
} }
private enum CurrentCall { private enum CurrentCall {
@ -309,11 +278,13 @@ public final class PresentationCallManagerImpl: PresentationCallManager {
isOutgoing: false, isOutgoing: false,
peer: firstState.1, peer: firstState.1,
proxyServer: strongSelf.proxyServer, proxyServer: strongSelf.proxyServer,
auxiliaryServers: auxiliaryServers(appConfiguration: appConfiguration), auxiliaryServers: [],
currentNetworkType: firstState.4, currentNetworkType: firstState.4,
updatedNetworkType: firstState.0.networkType, updatedNetworkType: firstState.0.networkType,
startWithVideo: firstState.2.isVideo, startWithVideo: firstState.2.isVideo,
isVideoPossible: firstState.2.isVideoPossible, isVideoPossible: firstState.2.isVideoPossible,
enableStunMarking: shouldEnableStunMarking(appConfiguration: appConfiguration),
enableTCP: experimentalSettings.enableVoipTcp,
preferredVideoCodec: experimentalSettings.preferredVideoCodec preferredVideoCodec: experimentalSettings.preferredVideoCodec
) )
strongSelf.updateCurrentCall(call) strongSelf.updateCurrentCall(call)
@ -551,11 +522,13 @@ public final class PresentationCallManagerImpl: PresentationCallManager {
isOutgoing: true, isOutgoing: true,
peer: nil, peer: nil,
proxyServer: strongSelf.proxyServer, proxyServer: strongSelf.proxyServer,
auxiliaryServers: auxiliaryServers(appConfiguration: appConfiguration), auxiliaryServers: [],
currentNetworkType: currentNetworkType, currentNetworkType: currentNetworkType,
updatedNetworkType: account.networkType, updatedNetworkType: account.networkType,
startWithVideo: isVideo, startWithVideo: isVideo,
isVideoPossible: isVideoPossible, isVideoPossible: isVideoPossible,
enableStunMarking: shouldEnableStunMarking(appConfiguration: appConfiguration),
enableTCP: experimentalSettings.enableVoipTcp,
preferredVideoCodec: experimentalSettings.preferredVideoCodec preferredVideoCodec: experimentalSettings.preferredVideoCodec
) )
strongSelf.updateCurrentCall(call) strongSelf.updateCurrentCall(call)

View File

@ -2878,10 +2878,10 @@ func replayFinalState(accountManager: AccountManager, postbox: Postbox, accountP
} }
// could be the reason for unbounded slowdown, needs investigation // could be the reason for unbounded slowdown, needs investigation
/*for (peerIdAndNamespace, pts) in clearHolesFromPreviousStateForChannelMessagesWithPts { for (peerIdAndNamespace, pts) in clearHolesFromPreviousStateForChannelMessagesWithPts {
var upperMessageId: Int32? var upperMessageId: Int32?
var lowerMessageId: Int32? var lowerMessageId: Int32?
transaction.scanMessageAttributes(peerId: peerIdAndNamespace.peerId, namespace: peerIdAndNamespace.namespace, { id, attributes in transaction.scanMessageAttributes(peerId: peerIdAndNamespace.peerId, namespace: peerIdAndNamespace.namespace, limit: 200, { id, attributes in
for attribute in attributes { for attribute in attributes {
if let attribute = attribute as? ChannelMessageStateVersionAttribute { if let attribute = attribute as? ChannelMessageStateVersionAttribute {
if attribute.pts >= pts { if attribute.pts >= pts {
@ -2906,7 +2906,7 @@ func replayFinalState(accountManager: AccountManager, postbox: Postbox, accountP
transaction.removeHole(peerId: peerIdAndNamespace.peerId, namespace: peerIdAndNamespace.namespace, space: .everywhere, range: lowerMessageId ... upperMessageId) transaction.removeHole(peerId: peerIdAndNamespace.peerId, namespace: peerIdAndNamespace.namespace, space: .everywhere, range: lowerMessageId ... upperMessageId)
} }
} }
}*/ }
if !peerActivityTimestamps.isEmpty { if !peerActivityTimestamps.isEmpty {
updatePeerPresenceLastActivities(transaction: transaction, accountPeerId: accountPeerId, activities: peerActivityTimestamps) updatePeerPresenceLastActivities(transaction: transaction, accountPeerId: accountPeerId, activities: peerActivityTimestamps)

View File

@ -11,44 +11,9 @@ private let minLayer: Int32 = 65
public enum CallSessionError: Equatable { public enum CallSessionError: Equatable {
case generic case generic
case privacyRestricted case privacyRestricted
case notSupportedByPeer case notSupportedByPeer(isVideo: Bool)
case serverProvided(String) case serverProvided(text: String)
case disconnected case disconnected
public static func ==(lhs: CallSessionError, rhs: CallSessionError) -> Bool {
switch lhs {
case .generic:
if case .generic = rhs {
return true
} else {
return false
}
case .privacyRestricted:
if case .privacyRestricted = rhs {
return true
} else {
return false
}
case .notSupportedByPeer:
if case .notSupportedByPeer = rhs {
return true
} else {
return false
}
case let .serverProvided(text):
if case .serverProvided(text) = rhs {
return true
} else {
return false
}
case .disconnected:
if case .disconnected = rhs {
return true
} else {
return false
}
}
}
} }
public enum CallSessionEndedType { public enum CallSessionEndedType {
@ -1204,12 +1169,12 @@ private func requestCallSession(postbox: Postbox, network: Network, peerId: Peer
|> `catch` { error -> Signal<RequestCallSessionResult, NoError> in |> `catch` { error -> Signal<RequestCallSessionResult, NoError> in
switch error.errorDescription { switch error.errorDescription {
case "PARTICIPANT_VERSION_OUTDATED": case "PARTICIPANT_VERSION_OUTDATED":
return .single(.failed(.notSupportedByPeer)) return .single(.failed(.notSupportedByPeer(isVideo: isVideo)))
case "USER_PRIVACY_RESTRICTED": case "USER_PRIVACY_RESTRICTED":
return .single(.failed(.privacyRestricted)) return .single(.failed(.privacyRestricted))
default: default:
if error.errorCode == 406 { if error.errorCode == 406 {
return .single(.failed(.serverProvided(error.errorDescription))) return .single(.failed(.serverProvided(text: error.errorDescription)))
} else { } else {
return .single(.failed(.generic)) return .single(.failed(.generic))
} }

View File

@ -9,6 +9,10 @@ import SyncCore
func messageFilterForTagMask(_ tagMask: MessageTags) -> Api.MessagesFilter? { func messageFilterForTagMask(_ tagMask: MessageTags) -> Api.MessagesFilter? {
if tagMask == .photoOrVideo { if tagMask == .photoOrVideo {
return Api.MessagesFilter.inputMessagesFilterPhotoVideo return Api.MessagesFilter.inputMessagesFilterPhotoVideo
} else if tagMask == .photo {
return Api.MessagesFilter.inputMessagesFilterPhotos
} else if tagMask == .video {
return Api.MessagesFilter.inputMessagesFilterVideo
} else if tagMask == .file { } else if tagMask == .file {
return Api.MessagesFilter.inputMessagesFilterDocument return Api.MessagesFilter.inputMessagesFilterDocument
} else if tagMask == .music { } else if tagMask == .music {

View File

@ -757,6 +757,7 @@ private func boxedDecryptedMessage(transaction: Transaction, message: Message, g
var viaBotName: String? var viaBotName: String?
var entities: [MessageTextEntity]? var entities: [MessageTextEntity]?
var muted: Bool = false
for attribute in message.attributes { for attribute in message.attributes {
if let attribute = attribute as? AutoremoveTimeoutMessageAttribute { if let attribute = attribute as? AutoremoveTimeoutMessageAttribute {
@ -769,6 +770,10 @@ private func boxedDecryptedMessage(transaction: Transaction, message: Message, g
} }
} else if let attribute = attribute as? TextEntitiesMessageAttribute { } else if let attribute = attribute as? TextEntitiesMessageAttribute {
entities = attribute.entities entities = attribute.entities
} else if let attribute = attribute as? NotificationInfoMessageAttribute {
if attribute.flags.contains(.muted) {
muted = true
}
} }
} }
@ -797,6 +802,9 @@ private func boxedDecryptedMessage(transaction: Transaction, message: Message, g
return .layer8(.decryptedMessage(randomId: globallyUniqueId, randomBytes: randomBytes, message: message.text, media: decryptedMedia)) return .layer8(.decryptedMessage(randomId: globallyUniqueId, randomBytes: randomBytes, message: message.text, media: decryptedMedia))
case .layer46: case .layer46:
if muted {
flags |= (1 << 5)
}
if let _ = viaBotName { if let _ = viaBotName {
flags |= (1 << 11) flags |= (1 << 11)
} }
@ -804,6 +812,9 @@ private func boxedDecryptedMessage(transaction: Transaction, message: Message, g
flags |= (1 << 9) flags |= (1 << 9)
return .layer46(.decryptedMessage(flags: flags, randomId: globallyUniqueId, ttl: messageAutoremoveTimeout, message: message.text, media: decryptedMedia, entities: nil, viaBotName: viaBotName, replyToRandomId: replyGlobalId)) return .layer46(.decryptedMessage(flags: flags, randomId: globallyUniqueId, ttl: messageAutoremoveTimeout, message: message.text, media: decryptedMedia, entities: nil, viaBotName: viaBotName, replyToRandomId: replyGlobalId))
case .layer73: case .layer73:
if muted {
flags |= (1 << 5)
}
if let _ = viaBotName { if let _ = viaBotName {
flags |= (1 << 11) flags |= (1 << 11)
} }
@ -818,6 +829,9 @@ private func boxedDecryptedMessage(transaction: Transaction, message: Message, g
} }
return .layer73(.decryptedMessage(flags: flags, randomId: globallyUniqueId, ttl: messageAutoremoveTimeout, message: message.text, media: decryptedMedia, entities: decryptedEntites, viaBotName: viaBotName, replyToRandomId: replyGlobalId, groupedId: message.groupingKey)) return .layer73(.decryptedMessage(flags: flags, randomId: globallyUniqueId, ttl: messageAutoremoveTimeout, message: message.text, media: decryptedMedia, entities: decryptedEntites, viaBotName: viaBotName, replyToRandomId: replyGlobalId, groupedId: message.groupingKey))
case .layer101: case .layer101:
if muted {
flags |= (1 << 5)
}
if let _ = viaBotName { if let _ = viaBotName {
flags |= (1 << 11) flags |= (1 << 11)
} }
@ -889,6 +903,9 @@ private func boxedDecryptedMessage(transaction: Transaction, message: Message, g
} }
if let decryptedMedia = decryptedMedia { if let decryptedMedia = decryptedMedia {
if muted {
flags |= (1 << 5)
}
if let _ = viaBotName { if let _ = viaBotName {
flags |= (1 << 11) flags |= (1 << 11)
} }
@ -913,6 +930,9 @@ private func boxedDecryptedMessage(transaction: Transaction, message: Message, g
} }
if let decryptedMedia = decryptedMedia { if let decryptedMedia = decryptedMedia {
if muted {
flags |= (1 << 5)
}
if let _ = viaBotName { if let _ = viaBotName {
flags |= (1 << 11) flags |= (1 << 11)
} }
@ -944,6 +964,9 @@ private func boxedDecryptedMessage(transaction: Transaction, message: Message, g
} }
if let decryptedMedia = decryptedMedia { if let decryptedMedia = decryptedMedia {
if muted {
flags |= (1 << 5)
}
if let _ = viaBotName { if let _ = viaBotName {
flags |= (1 << 11) flags |= (1 << 11)
} }
@ -969,6 +992,9 @@ private func boxedDecryptedMessage(transaction: Transaction, message: Message, g
case .layer8: case .layer8:
break break
case .layer46: case .layer46:
if muted {
flags |= (1 << 5)
}
if let _ = viaBotName { if let _ = viaBotName {
flags |= (1 << 11) flags |= (1 << 11)
} }
@ -976,6 +1002,9 @@ private func boxedDecryptedMessage(transaction: Transaction, message: Message, g
flags |= (1 << 9) flags |= (1 << 9)
return .layer46(.decryptedMessage(flags: flags, randomId: globallyUniqueId, ttl: messageAutoremoveTimeout, message: message.text, media: decryptedMedia, entities: nil, viaBotName: viaBotName, replyToRandomId: replyGlobalId)) return .layer46(.decryptedMessage(flags: flags, randomId: globallyUniqueId, ttl: messageAutoremoveTimeout, message: message.text, media: decryptedMedia, entities: nil, viaBotName: viaBotName, replyToRandomId: replyGlobalId))
case .layer73: case .layer73:
if muted {
flags |= (1 << 5)
}
if let _ = viaBotName { if let _ = viaBotName {
flags |= (1 << 11) flags |= (1 << 11)
} }
@ -987,6 +1016,9 @@ private func boxedDecryptedMessage(transaction: Transaction, message: Message, g
flags |= (1 << 9) flags |= (1 << 9)
return .layer73(.decryptedMessage(flags: flags, randomId: globallyUniqueId, ttl: messageAutoremoveTimeout, message: message.text, media: decryptedMedia, entities: decryptedEntites, viaBotName: viaBotName, replyToRandomId: replyGlobalId, groupedId: message.groupingKey)) return .layer73(.decryptedMessage(flags: flags, randomId: globallyUniqueId, ttl: messageAutoremoveTimeout, message: message.text, media: decryptedMedia, entities: decryptedEntites, viaBotName: viaBotName, replyToRandomId: replyGlobalId, groupedId: message.groupingKey))
case .layer101: case .layer101:
if muted {
flags |= (1 << 5)
}
if let _ = viaBotName { if let _ = viaBotName {
flags |= (1 << 11) flags |= (1 << 11)
} }
@ -1004,6 +1036,9 @@ private func boxedDecryptedMessage(transaction: Transaction, message: Message, g
case .layer8: case .layer8:
break break
case .layer46: case .layer46:
if muted {
flags |= (1 << 5)
}
if let _ = viaBotName { if let _ = viaBotName {
flags |= (1 << 11) flags |= (1 << 11)
} }
@ -1016,6 +1051,9 @@ private func boxedDecryptedMessage(transaction: Transaction, message: Message, g
} }
return .layer46(.decryptedMessage(flags: flags, randomId: globallyUniqueId, ttl: messageAutoremoveTimeout, message: message.text, media: decryptedMedia, entities: nil, viaBotName: viaBotName, replyToRandomId: replyGlobalId)) return .layer46(.decryptedMessage(flags: flags, randomId: globallyUniqueId, ttl: messageAutoremoveTimeout, message: message.text, media: decryptedMedia, entities: nil, viaBotName: viaBotName, replyToRandomId: replyGlobalId))
case .layer73: case .layer73:
if muted {
flags |= (1 << 5)
}
if let _ = viaBotName { if let _ = viaBotName {
flags |= (1 << 11) flags |= (1 << 11)
} }
@ -1033,6 +1071,9 @@ private func boxedDecryptedMessage(transaction: Transaction, message: Message, g
} }
return .layer73(.decryptedMessage(flags: flags, randomId: globallyUniqueId, ttl: messageAutoremoveTimeout, message: message.text, media: decryptedMedia, entities: decryptedEntites, viaBotName: viaBotName, replyToRandomId: replyGlobalId, groupedId: message.groupingKey)) return .layer73(.decryptedMessage(flags: flags, randomId: globallyUniqueId, ttl: messageAutoremoveTimeout, message: message.text, media: decryptedMedia, entities: decryptedEntites, viaBotName: viaBotName, replyToRandomId: replyGlobalId, groupedId: message.groupingKey))
case .layer101: case .layer101:
if muted {
flags |= (1 << 5)
}
if let _ = viaBotName { if let _ = viaBotName {
flags |= (1 << 11) flags |= (1 << 11)
} }
@ -1055,6 +1096,9 @@ private func boxedDecryptedMessage(transaction: Transaction, message: Message, g
case .layer8: case .layer8:
break break
case .layer46: case .layer46:
if muted {
flags |= (1 << 5)
}
if let _ = viaBotName { if let _ = viaBotName {
flags |= (1 << 11) flags |= (1 << 11)
} }
@ -1062,6 +1106,9 @@ private func boxedDecryptedMessage(transaction: Transaction, message: Message, g
flags |= (1 << 9) flags |= (1 << 9)
return .layer46(.decryptedMessage(flags: flags, randomId: globallyUniqueId, ttl: messageAutoremoveTimeout, message: message.text, media: decryptedMedia, entities: nil, viaBotName: viaBotName, replyToRandomId: replyGlobalId)) return .layer46(.decryptedMessage(flags: flags, randomId: globallyUniqueId, ttl: messageAutoremoveTimeout, message: message.text, media: decryptedMedia, entities: nil, viaBotName: viaBotName, replyToRandomId: replyGlobalId))
case .layer73: case .layer73:
if muted {
flags |= (1 << 5)
}
if let _ = viaBotName { if let _ = viaBotName {
flags |= (1 << 11) flags |= (1 << 11)
} }
@ -1074,6 +1121,9 @@ private func boxedDecryptedMessage(transaction: Transaction, message: Message, g
flags |= (1 << 9) flags |= (1 << 9)
return .layer73(.decryptedMessage(flags: flags, randomId: globallyUniqueId, ttl: messageAutoremoveTimeout, message: message.text, media: decryptedMedia, entities: decryptedEntites, viaBotName: viaBotName, replyToRandomId: replyGlobalId, groupedId: message.groupingKey)) return .layer73(.decryptedMessage(flags: flags, randomId: globallyUniqueId, ttl: messageAutoremoveTimeout, message: message.text, media: decryptedMedia, entities: decryptedEntites, viaBotName: viaBotName, replyToRandomId: replyGlobalId, groupedId: message.groupingKey))
case .layer101: case .layer101:
if muted {
flags |= (1 << 5)
}
if let _ = viaBotName { if let _ = viaBotName {
flags |= (1 << 11) flags |= (1 << 11)
} }
@ -1097,11 +1147,17 @@ private func boxedDecryptedMessage(transaction: Transaction, message: Message, g
return .layer8(.decryptedMessage(randomId: globallyUniqueId, randomBytes: randomBytes, message: message.text, media: .decryptedMessageMediaEmpty)) return .layer8(.decryptedMessage(randomId: globallyUniqueId, randomBytes: randomBytes, message: message.text, media: .decryptedMessageMediaEmpty))
case .layer46: case .layer46:
if muted {
flags |= (1 << 5)
}
if let _ = viaBotName { if let _ = viaBotName {
flags |= (1 << 11) flags |= (1 << 11)
} }
return .layer46(.decryptedMessage(flags: flags, randomId: globallyUniqueId, ttl: messageAutoremoveTimeout, message: message.text, media: .decryptedMessageMediaEmpty, entities: nil, viaBotName: viaBotName, replyToRandomId: replyGlobalId)) return .layer46(.decryptedMessage(flags: flags, randomId: globallyUniqueId, ttl: messageAutoremoveTimeout, message: message.text, media: .decryptedMessageMediaEmpty, entities: nil, viaBotName: viaBotName, replyToRandomId: replyGlobalId))
case .layer73: case .layer73:
if muted {
flags |= (1 << 5)
}
if let _ = viaBotName { if let _ = viaBotName {
flags |= (1 << 11) flags |= (1 << 11)
} }
@ -1111,6 +1167,9 @@ private func boxedDecryptedMessage(transaction: Transaction, message: Message, g
} }
return .layer73(.decryptedMessage(flags: flags, randomId: globallyUniqueId, ttl: messageAutoremoveTimeout, message: message.text, media: .decryptedMessageMediaEmpty, entities: decryptedEntites, viaBotName: viaBotName, replyToRandomId: replyGlobalId, groupedId: message.groupingKey)) return .layer73(.decryptedMessage(flags: flags, randomId: globallyUniqueId, ttl: messageAutoremoveTimeout, message: message.text, media: .decryptedMessageMediaEmpty, entities: decryptedEntites, viaBotName: viaBotName, replyToRandomId: replyGlobalId, groupedId: message.groupingKey))
case .layer101: case .layer101:
if muted {
flags |= (1 << 5)
}
if let _ = viaBotName { if let _ = viaBotName {
flags |= (1 << 11) flags |= (1 << 11)
} }
@ -1375,7 +1434,7 @@ private func sendMessage(auxiliaryMethods: AccountAuxiliaryMethods, postbox: Pos
if let state = transaction.getPeerChatState(messageId.peerId) as? SecretChatState, let peer = transaction.getPeer(messageId.peerId) as? TelegramSecretChat { if let state = transaction.getPeerChatState(messageId.peerId) as? SecretChatState, let peer = transaction.getPeer(messageId.peerId) as? TelegramSecretChat {
if let message = transaction.getMessage(messageId), let globallyUniqueId = message.globallyUniqueId { if let message = transaction.getMessage(messageId), let globallyUniqueId = message.globallyUniqueId {
let decryptedMessage = boxedDecryptedMessage(transaction: transaction, message: message, globallyUniqueId: globallyUniqueId, uploadedFile: file, thumbnailData: thumbnailData, layer: layer) let decryptedMessage = boxedDecryptedMessage(transaction: transaction, message: message, globallyUniqueId: globallyUniqueId, uploadedFile: file, thumbnailData: thumbnailData, layer: layer)
return sendBoxedDecryptedMessage(postbox: postbox, network: network, peer: peer, state: state, operationIndex: tagLocalIndex, decryptedMessage: decryptedMessage, globallyUniqueId: globallyUniqueId, file: file, asService: wasDelivered, wasDelivered: wasDelivered) return sendBoxedDecryptedMessage(postbox: postbox, network: network, peer: peer, state: state, operationIndex: tagLocalIndex, decryptedMessage: decryptedMessage, globallyUniqueId: globallyUniqueId, file: file, silent: message.muted, asService: wasDelivered, wasDelivered: wasDelivered)
|> mapToSignal { result in |> mapToSignal { result in
return postbox.transaction { transaction -> Void in return postbox.transaction { transaction -> Void in
let forceRemove: Bool let forceRemove: Bool
@ -1469,7 +1528,7 @@ private func sendServiceActionMessage(postbox: Postbox, network: Network, peerId
return postbox.transaction { transaction -> Signal<Void, NoError> in return postbox.transaction { transaction -> Signal<Void, NoError> in
if let state = transaction.getPeerChatState(peerId) as? SecretChatState, let peer = transaction.getPeer(peerId) as? TelegramSecretChat { if let state = transaction.getPeerChatState(peerId) as? SecretChatState, let peer = transaction.getPeer(peerId) as? TelegramSecretChat {
let decryptedMessage = boxedDecryptedSecretMessageAction(action: action) let decryptedMessage = boxedDecryptedSecretMessageAction(action: action)
return sendBoxedDecryptedMessage(postbox: postbox, network: network, peer: peer, state: state, operationIndex: tagLocalIndex, decryptedMessage: decryptedMessage, globallyUniqueId: action.globallyUniqueId, file: nil, asService: true, wasDelivered: wasDelivered) return sendBoxedDecryptedMessage(postbox: postbox, network: network, peer: peer, state: state, operationIndex: tagLocalIndex, decryptedMessage: decryptedMessage, globallyUniqueId: action.globallyUniqueId, file: nil, silent: false, asService: true, wasDelivered: wasDelivered)
|> mapToSignal { result in |> mapToSignal { result in
return postbox.transaction { transaction -> Void in return postbox.transaction { transaction -> Void in
let forceRemove: Bool let forceRemove: Bool
@ -1528,7 +1587,7 @@ private enum SendBoxedDecryptedMessageResult {
case error(SendBoxedDecryptedMessageError) case error(SendBoxedDecryptedMessageError)
} }
private func sendBoxedDecryptedMessage(postbox: Postbox, network: Network, peer: TelegramSecretChat, state: SecretChatState, operationIndex: Int32, decryptedMessage: BoxedDecryptedMessage, globallyUniqueId: Int64, file: SecretChatOutgoingFile?, asService: Bool, wasDelivered: Bool) -> Signal<SendBoxedDecryptedMessageResult, NoError> { private func sendBoxedDecryptedMessage(postbox: Postbox, network: Network, peer: TelegramSecretChat, state: SecretChatState, operationIndex: Int32, decryptedMessage: BoxedDecryptedMessage, globallyUniqueId: Int64, file: SecretChatOutgoingFile?, silent: Bool, asService: Bool, wasDelivered: Bool) -> Signal<SendBoxedDecryptedMessageResult, NoError> {
let payload = Buffer() let payload = Buffer()
var sequenceInfo: SecretChatOperationSequenceInfo? var sequenceInfo: SecretChatOperationSequenceInfo?
var maybeParameters: SecretChatEncryptionParameters? var maybeParameters: SecretChatEncryptionParameters?
@ -1573,6 +1632,11 @@ private func sendBoxedDecryptedMessage(postbox: Postbox, network: Network, peer:
let sendMessage: Signal<Api.messages.SentEncryptedMessage, MTRpcError> let sendMessage: Signal<Api.messages.SentEncryptedMessage, MTRpcError>
let inputPeer = Api.InputEncryptedChat.inputEncryptedChat(chatId: peer.id.id, accessHash: peer.accessHash) let inputPeer = Api.InputEncryptedChat.inputEncryptedChat(chatId: peer.id.id, accessHash: peer.accessHash)
var flags: Int32 = 0
if silent {
flags |= (1 << 0)
}
if asService { if asService {
let actionRandomId: Int64 let actionRandomId: Int64
if wasDelivered { if wasDelivered {
@ -1583,9 +1647,9 @@ private func sendBoxedDecryptedMessage(postbox: Postbox, network: Network, peer:
sendMessage = network.request(Api.functions.messages.sendEncryptedService(peer: inputPeer, randomId: actionRandomId, data: Buffer(data: encryptedPayload))) sendMessage = network.request(Api.functions.messages.sendEncryptedService(peer: inputPeer, randomId: actionRandomId, data: Buffer(data: encryptedPayload)))
} else { } else {
if let file = file { if let file = file {
sendMessage = network.request(Api.functions.messages.sendEncryptedFile(peer: inputPeer, randomId: globallyUniqueId, data: Buffer(data: encryptedPayload), file: file.reference.apiInputFile)) sendMessage = network.request(Api.functions.messages.sendEncryptedFile(flags: flags, peer: inputPeer, randomId: globallyUniqueId, data: Buffer(data: encryptedPayload), file: file.reference.apiInputFile))
} else { } else {
sendMessage = network.request(Api.functions.messages.sendEncrypted(peer: inputPeer, randomId: globallyUniqueId, data: Buffer(data: encryptedPayload))) sendMessage = network.request(Api.functions.messages.sendEncrypted(flags: flags, peer: inputPeer, randomId: globallyUniqueId, data: Buffer(data: encryptedPayload)))
} }
} }
return sendMessage return sendMessage

View File

@ -686,7 +686,7 @@ private func maximumMediaAutoremoveTimeout(_ media: [Media]) -> Int32 {
private func parseMessage(peerId: PeerId, authorId: PeerId, tagLocalIndex: Int32, timestamp: Int32, apiMessage: SecretApi46.DecryptedMessage, file: SecretChatFileReference?, messageIdForGloballyUniqueMessageId: (Int64) -> MessageId?) -> (StoreMessage, [(MediaResource, Data)])? { private func parseMessage(peerId: PeerId, authorId: PeerId, tagLocalIndex: Int32, timestamp: Int32, apiMessage: SecretApi46.DecryptedMessage, file: SecretChatFileReference?, messageIdForGloballyUniqueMessageId: (Int64) -> MessageId?) -> (StoreMessage, [(MediaResource, Data)])? {
switch apiMessage { switch apiMessage {
case let .decryptedMessage(_, randomId, ttl, message, media, entities, viaBotName, replyToRandomId): case let .decryptedMessage(flags, randomId, ttl, message, media, entities, viaBotName, replyToRandomId):
var text = message var text = message
var parsedMedia: [Media] = [] var parsedMedia: [Media] = []
var attributes: [MessageAttribute] = [] var attributes: [MessageAttribute] = []
@ -698,6 +698,10 @@ private func parseMessage(peerId: PeerId, authorId: PeerId, tagLocalIndex: Int32
attributes.append(InlineBotMessageAttribute(peerId: nil, title: viaBotName)) attributes.append(InlineBotMessageAttribute(peerId: nil, title: viaBotName))
} }
if (flags & 1 << 5) != 0 {
attributes.append(NotificationInfoMessageAttribute(flags: .muted))
}
if let media = media { if let media = media {
switch media { switch media {
case let .decryptedMessageMediaPhoto(thumb, thumbW, thumbH, w, h, size, key, iv, caption): case let .decryptedMessageMediaPhoto(thumb, thumbW, thumbH, w, h, size, key, iv, caption):
@ -882,7 +886,7 @@ private func parseEntities(_ entities: [SecretApi73.MessageEntity]) -> TextEntit
private func parseMessage(peerId: PeerId, authorId: PeerId, tagLocalIndex: Int32, timestamp: Int32, apiMessage: SecretApi73.DecryptedMessage, file: SecretChatFileReference?, messageIdForGloballyUniqueMessageId: (Int64) -> MessageId?) -> (StoreMessage, [(MediaResource, Data)])? { private func parseMessage(peerId: PeerId, authorId: PeerId, tagLocalIndex: Int32, timestamp: Int32, apiMessage: SecretApi73.DecryptedMessage, file: SecretChatFileReference?, messageIdForGloballyUniqueMessageId: (Int64) -> MessageId?) -> (StoreMessage, [(MediaResource, Data)])? {
switch apiMessage { switch apiMessage {
case let .decryptedMessage(_, randomId, ttl, message, media, entities, viaBotName, replyToRandomId, groupedId): case let .decryptedMessage(flags, randomId, ttl, message, media, entities, viaBotName, replyToRandomId, groupedId):
var text = message var text = message
var parsedMedia: [Media] = [] var parsedMedia: [Media] = []
var attributes: [MessageAttribute] = [] var attributes: [MessageAttribute] = []
@ -896,6 +900,10 @@ private func parseMessage(peerId: PeerId, authorId: PeerId, tagLocalIndex: Int32
attributes.append(InlineBotMessageAttribute(peerId: nil, title: viaBotName)) attributes.append(InlineBotMessageAttribute(peerId: nil, title: viaBotName))
} }
if (flags & 1 << 5) != 0 {
attributes.append(NotificationInfoMessageAttribute(flags: .muted))
}
if let media = media { if let media = media {
switch media { switch media {
case let .decryptedMessageMediaPhoto(thumb, thumbW, thumbH, w, h, size, key, iv, caption): case let .decryptedMessageMediaPhoto(thumb, thumbW, thumbH, w, h, size, key, iv, caption):
@ -1116,7 +1124,7 @@ private func parseEntities(_ entities: [SecretApi101.MessageEntity]) -> TextEnti
private func parseMessage(peerId: PeerId, authorId: PeerId, tagLocalIndex: Int32, timestamp: Int32, apiMessage: SecretApi101.DecryptedMessage, file: SecretChatFileReference?, messageIdForGloballyUniqueMessageId: (Int64) -> MessageId?) -> (StoreMessage, [(MediaResource, Data)])? { private func parseMessage(peerId: PeerId, authorId: PeerId, tagLocalIndex: Int32, timestamp: Int32, apiMessage: SecretApi101.DecryptedMessage, file: SecretChatFileReference?, messageIdForGloballyUniqueMessageId: (Int64) -> MessageId?) -> (StoreMessage, [(MediaResource, Data)])? {
switch apiMessage { switch apiMessage {
case let .decryptedMessage(_, randomId, ttl, message, media, entities, viaBotName, replyToRandomId, groupedId): case let .decryptedMessage(flags, randomId, ttl, message, media, entities, viaBotName, replyToRandomId, groupedId):
var text = message var text = message
var parsedMedia: [Media] = [] var parsedMedia: [Media] = []
var attributes: [MessageAttribute] = [] var attributes: [MessageAttribute] = []
@ -1130,6 +1138,10 @@ private func parseMessage(peerId: PeerId, authorId: PeerId, tagLocalIndex: Int32
attributes.append(InlineBotMessageAttribute(peerId: nil, title: viaBotName)) attributes.append(InlineBotMessageAttribute(peerId: nil, title: viaBotName))
} }
if (flags & 1 << 5) != 0 {
attributes.append(NotificationInfoMessageAttribute(flags: .muted))
}
if let media = media { if let media = media {
switch media { switch media {
case let .decryptedMessageMediaPhoto(thumb, thumbW, thumbH, w, h, size, key, iv, caption): case let .decryptedMessageMediaPhoto(thumb, thumbW, thumbH, w, h, size, key, iv, caption):

View File

@ -192,20 +192,7 @@ public func searchMessages(account: Account, location: SearchMessagesLocation, q
} }
} }
let filter: Api.MessagesFilter let filter: Api.MessagesFilter = tags.flatMap { messageFilterForTagMask($0) } ?? .inputMessagesFilterEmpty
if let tags = tags {
if tags.contains(.file) {
filter = .inputMessagesFilterDocument
} else if tags.contains(.music) {
filter = .inputMessagesFilterMusic
} else if tags.contains(.webPage) {
filter = .inputMessagesFilterUrl
} else {
filter = .inputMessagesFilterEmpty
}
} else {
filter = .inputMessagesFilterEmpty
}
remoteSearchResult = account.postbox.transaction { transaction -> (peer: Peer, additionalPeer: Peer?, from: Peer?)? in remoteSearchResult = account.postbox.transaction { transaction -> (peer: Peer, additionalPeer: Peer?, from: Peer?)? in
guard let peer = transaction.getPeer(peerId) else { guard let peer = transaction.getPeer(peerId) else {
return nil return nil

View File

@ -30,6 +30,7 @@ public func tagsForStoreMessage(incoming: Bool, attributes: [MessageAttribute],
if let _ = attachment as? TelegramMediaImage { if let _ = attachment as? TelegramMediaImage {
if !isSecret { if !isSecret {
tags.insert(.photoOrVideo) tags.insert(.photoOrVideo)
tags.insert(.photo)
} }
} else if let file = attachment as? TelegramMediaFile { } else if let file = attachment as? TelegramMediaFile {
var refinedTag: MessageTags? = .file var refinedTag: MessageTags? = .file
@ -41,7 +42,7 @@ public func tagsForStoreMessage(incoming: Bool, attributes: [MessageAttribute],
refinedTag = .voiceOrInstantVideo refinedTag = .voiceOrInstantVideo
} else { } else {
if !isSecret { if !isSecret {
refinedTag = .photoOrVideo refinedTag = [.photoOrVideo, .video]
} else { } else {
refinedTag = nil refinedTag = nil
} }

View File

@ -308,10 +308,13 @@ public final class PrincipalThemeEssentialGraphics {
self.clockFreeMinImage = emptyImage self.clockFreeMinImage = emptyImage
self.dateAndStatusMediaBackground = emptyImage self.dateAndStatusMediaBackground = emptyImage
self.dateAndStatusFreeBackground = emptyImage self.dateAndStatusFreeBackground = emptyImage
self.incomingDateAndStatusImpressionIcon = emptyImage
self.outgoingDateAndStatusImpressionIcon = emptyImage let impressionCountImage = UIImage(bundleImageName: "Chat/Message/ImpressionCount")!
self.mediaImpressionIcon = emptyImage self.incomingDateAndStatusImpressionIcon = generateTintedImage(image: impressionCountImage, color: theme.message.incoming.secondaryTextColor)!
self.freeImpressionIcon = emptyImage self.outgoingDateAndStatusImpressionIcon = generateTintedImage(image: impressionCountImage, color: theme.message.outgoing.secondaryTextColor)!
self.mediaImpressionIcon = generateTintedImage(image: impressionCountImage, color: .white)!
self.freeImpressionIcon = generateTintedImage(image: impressionCountImage, color: serviceColor.primaryText)!
self.radialIndicatorFileIconIncoming = emptyImage self.radialIndicatorFileIconIncoming = emptyImage
self.radialIndicatorFileIconOutgoing = emptyImage self.radialIndicatorFileIconOutgoing = emptyImage
} else { } else {

View File

@ -1731,9 +1731,9 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
} }
}, completed: {}) }, completed: {})
} }
}, rateCall: { [weak self] message, callId in }, rateCall: { [weak self] message, callId, isVideo in
if let strongSelf = self { if let strongSelf = self {
let controller = callRatingController(sharedContext: strongSelf.context.sharedContext, account: strongSelf.context.account, callId: callId, userInitiated: true, present: { [weak self] c, a in let controller = callRatingController(sharedContext: strongSelf.context.sharedContext, account: strongSelf.context.account, callId: callId, userInitiated: true, isVideo: isVideo, present: { [weak self] c, a in
if let strongSelf = self { if let strongSelf = self {
strongSelf.present(c, in: .window(.root), with: a) strongSelf.present(c, in: .window(.root), with: a)
} }

View File

@ -99,7 +99,7 @@ public final class ChatControllerInteraction {
let navigateToFirstDateMessage: (Int32) -> Void let navigateToFirstDateMessage: (Int32) -> Void
let requestRedeliveryOfFailedMessages: (MessageId) -> Void let requestRedeliveryOfFailedMessages: (MessageId) -> Void
let addContact: (String) -> Void let addContact: (String) -> Void
let rateCall: (Message, CallId) -> Void let rateCall: (Message, CallId, Bool) -> Void
let requestSelectMessagePollOptions: (MessageId, [Data]) -> Void let requestSelectMessagePollOptions: (MessageId, [Data]) -> Void
let requestOpenMessagePollResults: (MessageId, MediaId) -> Void let requestOpenMessagePollResults: (MessageId, MediaId) -> Void
let openAppStorePage: () -> Void let openAppStorePage: () -> Void
@ -138,7 +138,7 @@ public final class ChatControllerInteraction {
var searchTextHighightState: (String, [MessageIndex])? var searchTextHighightState: (String, [MessageIndex])?
var seenOneTimeAnimatedMedia = Set<MessageId>() var seenOneTimeAnimatedMedia = Set<MessageId>()
init(openMessage: @escaping (Message, ChatControllerInteractionOpenMessageMode) -> Bool, openPeer: @escaping (PeerId?, ChatControllerInteractionNavigateToPeer, Message?) -> Void, openPeerMention: @escaping (String) -> Void, openMessageContextMenu: @escaping (Message, Bool, ASDisplayNode, CGRect, UIGestureRecognizer?) -> Void, openMessageContextActions: @escaping (Message, ASDisplayNode, CGRect, ContextGesture?) -> Void, navigateToMessage: @escaping (MessageId, MessageId) -> Void, tapMessage: ((Message) -> Void)?, clickThroughMessage: @escaping () -> Void, toggleMessagesSelection: @escaping ([MessageId], Bool) -> Void, sendCurrentMessage: @escaping (Bool) -> Void, sendMessage: @escaping (String) -> Void, sendSticker: @escaping (FileMediaReference, Bool, ASDisplayNode, CGRect) -> Bool, sendGif: @escaping (FileMediaReference, ASDisplayNode, CGRect) -> Bool, sendBotContextResultAsGif: @escaping (ChatContextResultCollection, ChatContextResult, ASDisplayNode, CGRect) -> Bool, requestMessageActionCallback: @escaping (MessageId, MemoryBuffer?, Bool, Bool) -> Void, requestMessageActionUrlAuth: @escaping (String, MessageId, Int32) -> Void, activateSwitchInline: @escaping (PeerId?, String) -> Void, openUrl: @escaping (String, Bool, Bool?, Message?) -> Void, shareCurrentLocation: @escaping () -> Void, shareAccountContact: @escaping () -> Void, sendBotCommand: @escaping (MessageId?, String) -> Void, openInstantPage: @escaping (Message, ChatMessageItemAssociatedData?) -> Void, openWallpaper: @escaping (Message) -> Void, openTheme: @escaping (Message) -> Void, openHashtag: @escaping (String?, String) -> Void, updateInputState: @escaping ((ChatTextInputState) -> ChatTextInputState) -> Void, updateInputMode: @escaping ((ChatInputMode) -> ChatInputMode) -> Void, openMessageShareMenu: @escaping (MessageId) -> Void, presentController: @escaping (ViewController, Any?) -> Void, navigationController: @escaping () -> NavigationController?, chatControllerNode: @escaping () -> ASDisplayNode?, reactionContainerNode: @escaping () -> ReactionSelectionParentNode?, presentGlobalOverlayController: @escaping (ViewController, Any?) -> Void, callPeer: @escaping (PeerId, Bool) -> Void, longTap: @escaping (ChatControllerInteractionLongTapAction, Message?) -> Void, openCheckoutOrReceipt: @escaping (MessageId) -> Void, openSearch: @escaping () -> Void, setupReply: @escaping (MessageId) -> Void, canSetupReply: @escaping (Message) -> ChatControllerInteractionSwipeAction, navigateToFirstDateMessage: @escaping(Int32) ->Void, requestRedeliveryOfFailedMessages: @escaping (MessageId) -> Void, addContact: @escaping (String) -> Void, rateCall: @escaping (Message, CallId) -> Void, requestSelectMessagePollOptions: @escaping (MessageId, [Data]) -> Void, requestOpenMessagePollResults: @escaping (MessageId, MediaId) -> Void, openAppStorePage: @escaping () -> Void, displayMessageTooltip: @escaping (MessageId, String, ASDisplayNode?, CGRect?) -> Void, seekToTimecode: @escaping (Message, Double, Bool) -> Void, scheduleCurrentMessage: @escaping () -> Void, sendScheduledMessagesNow: @escaping ([MessageId]) -> Void, editScheduledMessagesTime: @escaping ([MessageId]) -> Void, performTextSelectionAction: @escaping (UInt32, NSAttributedString, TextSelectionAction) -> Void, updateMessageLike: @escaping (MessageId, Bool) -> Void, openMessageReactions: @escaping (MessageId) -> Void, displaySwipeToReplyHint: @escaping () -> Void, dismissReplyMarkupMessage: @escaping (Message) -> Void, openMessagePollResults: @escaping (MessageId, Data) -> Void, openPollCreation: @escaping (Bool?) -> Void, displayPollSolution: @escaping (TelegramMediaPollResults.Solution, ASDisplayNode) -> Void, displayPsa: @escaping (String, ASDisplayNode) -> Void, displayDiceTooltip: @escaping (TelegramMediaDice) -> Void, animateDiceSuccess: @escaping () -> Void, greetingStickerNode: @escaping () -> (ASDisplayNode, ASDisplayNode, ASDisplayNode, () -> Void)?, openPeerContextMenu: @escaping (Peer, ASDisplayNode, CGRect, ContextGesture?) -> Void, requestMessageUpdate: @escaping (MessageId) -> Void, cancelInteractiveKeyboardGestures: @escaping () -> Void, automaticMediaDownloadSettings: MediaAutoDownloadSettings, pollActionState: ChatInterfacePollActionState, stickerSettings: ChatInterfaceStickerSettings) { init(openMessage: @escaping (Message, ChatControllerInteractionOpenMessageMode) -> Bool, openPeer: @escaping (PeerId?, ChatControllerInteractionNavigateToPeer, Message?) -> Void, openPeerMention: @escaping (String) -> Void, openMessageContextMenu: @escaping (Message, Bool, ASDisplayNode, CGRect, UIGestureRecognizer?) -> Void, openMessageContextActions: @escaping (Message, ASDisplayNode, CGRect, ContextGesture?) -> Void, navigateToMessage: @escaping (MessageId, MessageId) -> Void, tapMessage: ((Message) -> Void)?, clickThroughMessage: @escaping () -> Void, toggleMessagesSelection: @escaping ([MessageId], Bool) -> Void, sendCurrentMessage: @escaping (Bool) -> Void, sendMessage: @escaping (String) -> Void, sendSticker: @escaping (FileMediaReference, Bool, ASDisplayNode, CGRect) -> Bool, sendGif: @escaping (FileMediaReference, ASDisplayNode, CGRect) -> Bool, sendBotContextResultAsGif: @escaping (ChatContextResultCollection, ChatContextResult, ASDisplayNode, CGRect) -> Bool, requestMessageActionCallback: @escaping (MessageId, MemoryBuffer?, Bool, Bool) -> Void, requestMessageActionUrlAuth: @escaping (String, MessageId, Int32) -> Void, activateSwitchInline: @escaping (PeerId?, String) -> Void, openUrl: @escaping (String, Bool, Bool?, Message?) -> Void, shareCurrentLocation: @escaping () -> Void, shareAccountContact: @escaping () -> Void, sendBotCommand: @escaping (MessageId?, String) -> Void, openInstantPage: @escaping (Message, ChatMessageItemAssociatedData?) -> Void, openWallpaper: @escaping (Message) -> Void, openTheme: @escaping (Message) -> Void, openHashtag: @escaping (String?, String) -> Void, updateInputState: @escaping ((ChatTextInputState) -> ChatTextInputState) -> Void, updateInputMode: @escaping ((ChatInputMode) -> ChatInputMode) -> Void, openMessageShareMenu: @escaping (MessageId) -> Void, presentController: @escaping (ViewController, Any?) -> Void, navigationController: @escaping () -> NavigationController?, chatControllerNode: @escaping () -> ASDisplayNode?, reactionContainerNode: @escaping () -> ReactionSelectionParentNode?, presentGlobalOverlayController: @escaping (ViewController, Any?) -> Void, callPeer: @escaping (PeerId, Bool) -> Void, longTap: @escaping (ChatControllerInteractionLongTapAction, Message?) -> Void, openCheckoutOrReceipt: @escaping (MessageId) -> Void, openSearch: @escaping () -> Void, setupReply: @escaping (MessageId) -> Void, canSetupReply: @escaping (Message) -> ChatControllerInteractionSwipeAction, navigateToFirstDateMessage: @escaping(Int32) ->Void, requestRedeliveryOfFailedMessages: @escaping (MessageId) -> Void, addContact: @escaping (String) -> Void, rateCall: @escaping (Message, CallId, Bool) -> Void, requestSelectMessagePollOptions: @escaping (MessageId, [Data]) -> Void, requestOpenMessagePollResults: @escaping (MessageId, MediaId) -> Void, openAppStorePage: @escaping () -> Void, displayMessageTooltip: @escaping (MessageId, String, ASDisplayNode?, CGRect?) -> Void, seekToTimecode: @escaping (Message, Double, Bool) -> Void, scheduleCurrentMessage: @escaping () -> Void, sendScheduledMessagesNow: @escaping ([MessageId]) -> Void, editScheduledMessagesTime: @escaping ([MessageId]) -> Void, performTextSelectionAction: @escaping (UInt32, NSAttributedString, TextSelectionAction) -> Void, updateMessageLike: @escaping (MessageId, Bool) -> Void, openMessageReactions: @escaping (MessageId) -> Void, displaySwipeToReplyHint: @escaping () -> Void, dismissReplyMarkupMessage: @escaping (Message) -> Void, openMessagePollResults: @escaping (MessageId, Data) -> Void, openPollCreation: @escaping (Bool?) -> Void, displayPollSolution: @escaping (TelegramMediaPollResults.Solution, ASDisplayNode) -> Void, displayPsa: @escaping (String, ASDisplayNode) -> Void, displayDiceTooltip: @escaping (TelegramMediaDice) -> Void, animateDiceSuccess: @escaping () -> Void, greetingStickerNode: @escaping () -> (ASDisplayNode, ASDisplayNode, ASDisplayNode, () -> Void)?, openPeerContextMenu: @escaping (Peer, ASDisplayNode, CGRect, ContextGesture?) -> Void, requestMessageUpdate: @escaping (MessageId) -> Void, cancelInteractiveKeyboardGestures: @escaping () -> Void, automaticMediaDownloadSettings: MediaAutoDownloadSettings, pollActionState: ChatInterfacePollActionState, stickerSettings: ChatInterfaceStickerSettings) {
self.openMessage = openMessage self.openMessage = openMessage
self.openPeer = openPeer self.openPeer = openPeer
self.openPeerMention = openPeerMention self.openPeerMention = openPeerMention
@ -228,7 +228,7 @@ public final class ChatControllerInteraction {
}, navigateToFirstDateMessage: { _ in }, navigateToFirstDateMessage: { _ in
}, requestRedeliveryOfFailedMessages: { _ in }, requestRedeliveryOfFailedMessages: { _ in
}, addContact: { _ in }, addContact: { _ in
}, rateCall: { _, _ in }, rateCall: { _, _, _ in
}, requestSelectMessagePollOptions: { _, _ in }, requestSelectMessagePollOptions: { _, _ in
}, requestOpenMessagePollResults: { _, _ in }, requestOpenMessagePollResults: { _, _ in
}, openAppStorePage: { }, openAppStorePage: {

View File

@ -1484,7 +1484,7 @@ public final class ChatHistoryListNode: ListView, ChatHistoryNode {
strongSelf._buttonKeyboardMessage.set(.single(transition.keyboardButtonsMessage)) strongSelf._buttonKeyboardMessage.set(.single(transition.keyboardButtonsMessage))
} }
/*if transition.animateIn || animateIn { if transition.animateIn || animateIn {
let heightNorm = strongSelf.bounds.height - strongSelf.insets.top let heightNorm = strongSelf.bounds.height - strongSelf.insets.top
strongSelf.forEachVisibleItemNode { itemNode in strongSelf.forEachVisibleItemNode { itemNode in
if let itemNode = itemNode as? ChatMessageItemView { if let itemNode = itemNode as? ChatMessageItemView {
@ -1502,7 +1502,7 @@ public final class ChatHistoryListNode: ListView, ChatHistoryNode {
itemNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.15, delay: delay) itemNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.15, delay: delay)
itemNode.layer.animateScale(from: 0.9, to: 1.0, duration: 0.4, delay: delay, timingFunction: kCAMediaTimingFunctionSpring) itemNode.layer.animateScale(from: 0.9, to: 1.0, duration: 0.4, delay: delay, timingFunction: kCAMediaTimingFunctionSpring)
} }
}*/ }
if let scrolledToIndex = transition.scrolledToIndex { if let scrolledToIndex = transition.scrolledToIndex {
if let strongSelf = self { if let strongSelf = self {

View File

@ -405,20 +405,22 @@ func contextMenuForChatPresentationIntefaceState(chatPresentationInterfaceState:
if data.messageActions.options.contains(.rateCall) { if data.messageActions.options.contains(.rateCall) {
var callId: CallId? var callId: CallId?
var isVideo: Bool = false
for media in message.media { for media in message.media {
if let action = media as? TelegramMediaAction, case let .phoneCall(id, discardReason, _, _) = action.action { if let action = media as? TelegramMediaAction, case let .phoneCall(id, discardReason, _, isVideoValue) = action.action {
isVideo = isVideoValue
if discardReason != .busy && discardReason != .missed { if discardReason != .busy && discardReason != .missed {
if let logName = callLogNameForId(id: id, account: context.account) { if let logName = callLogNameForId(id: id, account: context.account) {
let logsPath = callLogsPath(account: context.account) let logsPath = callLogsPath(account: context.account)
let logPath = logsPath + "/" + logName let logPath = logsPath + "/" + logName
let start = logName.index(logName.startIndex, offsetBy: "\(id)".count + 1) let start = logName.index(logName.startIndex, offsetBy: "\(id)".count + 1)
let end = logName.index(logName.endIndex, offsetBy: -4) let end = logName.index(logName.endIndex, offsetBy: -4 - 5)
let accessHash = logName[start..<end] let accessHash = logName[start..<end]
if let accessHash = Int64(accessHash) { if let accessHash = Int64(accessHash) {
callId = CallId(id: id, accessHash: accessHash) callId = CallId(id: id, accessHash: accessHash)
} }
actions.append(.action(ContextMenuActionItem(text: "Share Statistics", icon: { theme in actions.append(.action(ContextMenuActionItem(text: chatPresentationInterfaceState.strings.Call_ShareStats, icon: { theme in
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Forward"), color: theme.actionSheet.primaryTextColor) return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Forward"), color: theme.actionSheet.primaryTextColor)
}, action: { _, f in }, action: { _, f in
f(.dismissWithoutContent) f(.dismissWithoutContent)
@ -446,7 +448,7 @@ func contextMenuForChatPresentationIntefaceState(chatPresentationInterfaceState:
actions.append(.action(ContextMenuActionItem(text: chatPresentationInterfaceState.strings.Call_RateCall, icon: { theme in actions.append(.action(ContextMenuActionItem(text: chatPresentationInterfaceState.strings.Call_RateCall, icon: { theme in
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Rate"), color: theme.actionSheet.primaryTextColor) return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Rate"), color: theme.actionSheet.primaryTextColor)
}, action: { _, f in }, action: { _, f in
let _ = controllerInteraction.rateCall(message, callId) let _ = controllerInteraction.rateCall(message, callId, isVideo)
f(.dismissWithoutContent) f(.dismissWithoutContent)
}))) })))
} }

View File

@ -1109,7 +1109,7 @@ class ChatMessageAnimatedStickerItemNode: ChatMessageItemView {
|> deliverOnMainQueue |> deliverOnMainQueue
} }
let beatingHearts: [UInt32] = [0x2764, 0x1F90E, 0x1F9E1, 0x1F49A, 0x1F49C, 0x1F49B, 0x1F5A4, 0x1F90D] let beatingHearts: [UInt32] = [0x2764, 0x1F90E, 0x1F9E1, 0x1F499, 0x1F49A, 0x1F49C, 0x1F49B, 0x1F5A4, 0x1F90D]
let peach = 0x1F351 let peach = 0x1F351
if let text = self.item?.message.text, let firstScalar = text.unicodeScalars.first, beatingHearts.contains(firstScalar.value) || firstScalar.value == peach { if let text = self.item?.message.text, let firstScalar = text.unicodeScalars.first, beatingHearts.contains(firstScalar.value) || firstScalar.value == peach {

View File

@ -282,6 +282,7 @@ final class ChatMessageAttachedContentNode: ASDisplayNode {
let currentAdditionalImageBadgeNode = self.additionalImageBadgeNode let currentAdditionalImageBadgeNode = self.additionalImageBadgeNode
return { presentationData, automaticDownloadSettings, associatedData, attributes, context, controllerInteraction, message, messageRead, title, subtitle, text, entities, mediaAndFlags, mediaBadge, actionIcon, actionTitle, displayLine, layoutConstants, constrainedSize in return { presentationData, automaticDownloadSettings, associatedData, attributes, context, controllerInteraction, message, messageRead, title, subtitle, text, entities, mediaAndFlags, mediaBadge, actionIcon, actionTitle, displayLine, layoutConstants, constrainedSize in
let isPreview = presentationData.isPreview
let fontSize: CGFloat = floor(presentationData.fontSize.baseDisplaySize * 15.0 / 17.0) let fontSize: CGFloat = floor(presentationData.fontSize.baseDisplaySize * 15.0 / 17.0)
let titleFont = Font.semibold(fontSize) let titleFont = Font.semibold(fontSize)
@ -526,7 +527,6 @@ final class ChatMessageAttachedContentNode: ASDisplayNode {
let imageMode = !((refineContentImageLayout == nil && refineContentFileLayout == nil && contentInstantVideoSizeAndApply == nil) || preferMediaBeforeText) let imageMode = !((refineContentImageLayout == nil && refineContentFileLayout == nil && contentInstantVideoSizeAndApply == nil) || preferMediaBeforeText)
statusInText = !imageMode statusInText = !imageMode
if let count = webpageGalleryMediaCount { if let count = webpageGalleryMediaCount {
additionalImageBadgeContent = .text(inset: 0.0, backgroundColor: presentationData.theme.theme.chat.message.mediaDateAndStatusFillColor, foregroundColor: presentationData.theme.theme.chat.message.mediaDateAndStatusTextColor, text: NSAttributedString(string: presentationData.strings.Items_NOfM("1", "\(count)").0)) additionalImageBadgeContent = .text(inset: 0.0, backgroundColor: presentationData.theme.theme.chat.message.mediaDateAndStatusFillColor, foregroundColor: presentationData.theme.theme.chat.message.mediaDateAndStatusTextColor, text: NSAttributedString(string: presentationData.strings.Items_NOfM("1", "\(count)").0))
skipStandardStatus = imageMode skipStandardStatus = imageMode
@ -658,7 +658,7 @@ final class ChatMessageAttachedContentNode: ASDisplayNode {
} }
var continueActionButtonLayout: ((CGFloat) -> (CGSize, () -> ChatMessageAttachedContentButtonNode))? var continueActionButtonLayout: ((CGFloat) -> (CGSize, () -> ChatMessageAttachedContentButtonNode))?
if let actionTitle = actionTitle { if let actionTitle = actionTitle, !isPreview {
let buttonImage: UIImage let buttonImage: UIImage
let buttonHighlightedImage: UIImage let buttonHighlightedImage: UIImage
var buttonIconImage: UIImage? var buttonIconImage: UIImage?
@ -781,6 +781,8 @@ final class ChatMessageAttachedContentNode: ASDisplayNode {
strongSelf.lineNode.frame = CGRect(origin: CGPoint(x: 13.0, y: insets.top), size: CGSize(width: 2.0, height: adjustedLineHeight - insets.top - insets.bottom - 2.0)) strongSelf.lineNode.frame = CGRect(origin: CGPoint(x: 13.0, y: insets.top), size: CGSize(width: 2.0, height: adjustedLineHeight - insets.top - insets.bottom - 2.0))
strongSelf.lineNode.isHidden = !displayLine strongSelf.lineNode.isHidden = !displayLine
strongSelf.textNode.displaysAsynchronously = !isPreview
let _ = textApply() let _ = textApply()
if let imageFrame = imageFrame { if let imageFrame = imageFrame {

View File

@ -759,6 +759,7 @@ class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePrevewItemNode
currentForwardInfo: (Peer?, String?)?, currentForwardInfo: (Peer?, String?)?,
isSelected: Bool? isSelected: Bool?
) -> (ListViewItemNodeLayout, (ListViewItemUpdateAnimation, Bool) -> Void) { ) -> (ListViewItemNodeLayout, (ListViewItemUpdateAnimation, Bool) -> Void) {
let isPreview = item.presentationData.isPreview
let accessibilityData = ChatMessageAccessibilityData(item: item, isSelected: isSelected) let accessibilityData = ChatMessageAccessibilityData(item: item, isSelected: isSelected)
let fontSize = floor(item.presentationData.fontSize.baseDisplaySize * 14.0 / 17.0) let fontSize = floor(item.presentationData.fontSize.baseDisplaySize * 14.0 / 17.0)
@ -848,11 +849,7 @@ class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePrevewItemNode
} }
} }
if hasAvatar { avatarInset = hasAvatar ? layoutConstants.avatarDiameter : 0.0
avatarInset = layoutConstants.avatarDiameter
} else {
avatarInset = 0.0
}
let isFailed = item.content.firstMessage.effectivelyFailed(timestamp: item.context.account.network.getApproximateRemoteTimestamp()) let isFailed = item.content.firstMessage.effectivelyFailed(timestamp: item.context.account.network.getApproximateRemoteTimestamp())
@ -907,7 +904,7 @@ class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePrevewItemNode
} }
} }
if item.presentationData.isPreview { if isPreview {
needShareButton = false needShareButton = false
} }
@ -992,7 +989,7 @@ class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePrevewItemNode
} }
} else if let attribute = attribute as? ReplyMessageAttribute { } else if let attribute = attribute as? ReplyMessageAttribute {
replyMessage = firstMessage.associatedMessages[attribute.messageId] replyMessage = firstMessage.associatedMessages[attribute.messageId]
} else if let attribute = attribute as? ReplyMarkupMessageAttribute, attribute.flags.contains(.inline), !attribute.rows.isEmpty { } else if let attribute = attribute as? ReplyMarkupMessageAttribute, attribute.flags.contains(.inline), !attribute.rows.isEmpty && !isPreview {
replyMarkup = attribute replyMarkup = attribute
} }
} }

View File

@ -496,6 +496,7 @@ class ChatMessageDateAndStatusNode: ASDisplayNode {
let _ = dateApply() let _ = dateApply()
if let currentImpressionIcon = currentImpressionIcon { if let currentImpressionIcon = currentImpressionIcon {
currentImpressionIcon.displaysAsynchronously = !presentationData.isPreview
if currentImpressionIcon.image !== impressionImage { if currentImpressionIcon.image !== impressionImage {
currentImpressionIcon.image = impressionImage currentImpressionIcon.image = impressionImage
} }
@ -508,7 +509,7 @@ class ChatMessageDateAndStatusNode: ASDisplayNode {
impressionIcon.removeFromSupernode() impressionIcon.removeFromSupernode()
strongSelf.impressionIcon = nil strongSelf.impressionIcon = nil
} }
strongSelf.impressionIcon?.displaysAsynchronously = !presentationData.isPreview
strongSelf.dateNode.frame = CGRect(origin: CGPoint(x: leftInset + backgroundInsets.left + impressionWidth, y: backgroundInsets.top + 1.0 + offset), size: date.size) strongSelf.dateNode.frame = CGRect(origin: CGPoint(x: leftInset + backgroundInsets.left + impressionWidth, y: backgroundInsets.top + 1.0 + offset), size: date.size)

View File

@ -868,7 +868,7 @@ final class ChatMessageInteractiveFileNode: ASDisplayNode {
statusNode.backgroundNodeColor = backgroundNodeColor statusNode.backgroundNodeColor = backgroundNodeColor
} }
if state != .none && isVoice && self.playbackAudioLevelView == nil { if state != .none && isVoice && self.playbackAudioLevelView == nil && false {
let blobFrame = progressFrame.insetBy(dx: -12.0, dy: -12.0) let blobFrame = progressFrame.insetBy(dx: -12.0, dy: -12.0)
let playbackAudioLevelView = VoiceBlobView( let playbackAudioLevelView = VoiceBlobView(
frame: blobFrame, frame: blobFrame,

View File

@ -425,7 +425,7 @@ final class ChatRecentActionsControllerNode: ViewControllerTracingNode {
}, navigateToFirstDateMessage: { _ in }, navigateToFirstDateMessage: { _ in
}, requestRedeliveryOfFailedMessages: { _ in }, requestRedeliveryOfFailedMessages: { _ in
}, addContact: { _ in }, addContact: { _ in
}, rateCall: { _, _ in }, rateCall: { _, _, _ in
}, requestSelectMessagePollOptions: { _, _ in }, requestSelectMessagePollOptions: { _, _ in
}, requestOpenMessagePollResults: { _, _ in }, requestOpenMessagePollResults: { _, _ in
}, openAppStorePage: { [weak self] in }, openAppStorePage: { [weak self] in

View File

@ -3,6 +3,7 @@ import UIKit
import Display import Display
import AsyncDisplayKit import AsyncDisplayKit
import SwiftSignalKit import SwiftSignalKit
import SyncCore
import TelegramPresentationData import TelegramPresentationData
import AccountContext import AccountContext
import ContextUI import ContextUI
@ -67,8 +68,10 @@ final class ChatSendMessageActionSheetController: ViewController {
} }
var reminders = false var reminders = false
if case let .peer(peerId) = self.interfaceState.chatLocation, peerId == context.account.peerId { var isSecret = false
reminders = true if case let .peer(peerId) = self.interfaceState.chatLocation {
reminders = peerId == context.account.peerId
isSecret = peerId.namespace == Namespaces.Peer.SecretChat
} }
self.displayNode = ChatSendMessageActionSheetControllerNode(context: self.context, reminders: reminders, gesture: gesture, sendButtonFrame: self.sendButtonFrame, textInputNode: self.textInputNode, forwardedCount: forwardedCount, send: { [weak self] in self.displayNode = ChatSendMessageActionSheetControllerNode(context: self.context, reminders: reminders, gesture: gesture, sendButtonFrame: self.sendButtonFrame, textInputNode: self.textInputNode, forwardedCount: forwardedCount, send: { [weak self] in
@ -77,7 +80,7 @@ final class ChatSendMessageActionSheetController: ViewController {
}, sendSilently: { [weak self] in }, sendSilently: { [weak self] in
self?.controllerInteraction?.sendCurrentMessage(true) self?.controllerInteraction?.sendCurrentMessage(true)
self?.dismiss(cancel: false) self?.dismiss(cancel: false)
}, schedule: { [weak self] in }, schedule: isSecret ? nil : { [weak self] in
self?.controllerInteraction?.scheduleCurrentMessage() self?.controllerInteraction?.scheduleCurrentMessage()
self?.dismiss(cancel: false) self?.dismiss(cancel: false)
}, cancel: { [weak self] in }, cancel: { [weak self] in

View File

@ -241,9 +241,11 @@ final class ChatSendMessageActionSheetControllerNode: ViewControllerTracingNode,
sendSilently?() sendSilently?()
})) }))
} }
contentNodes.append(ActionSheetItemNode(theme: self.presentationData.theme, title: reminders ? self.presentationData.strings.Conversation_SendMessage_SetReminder: self.presentationData.strings.Conversation_SendMessage_ScheduleMessage, icon: .schedule, hasSeparator: false, action: { if let _ = schedule {
schedule?() contentNodes.append(ActionSheetItemNode(theme: self.presentationData.theme, title: reminders ? self.presentationData.strings.Conversation_SendMessage_SetReminder: self.presentationData.strings.Conversation_SendMessage_ScheduleMessage, icon: .schedule, hasSeparator: false, action: {
})) schedule?()
}))
}
self.contentNodes = contentNodes self.contentNodes = contentNodes
super.init() super.init()

View File

@ -84,12 +84,6 @@ final class ChatTextInputActionButtonsNode: ASDisplayNode {
self.micButtonPointerInteraction = PointerInteraction(view: self.micButton, style: .circle) self.micButtonPointerInteraction = PointerInteraction(view: self.micButton, style: .circle)
} }
@objc func handleLongPress(_ gestureRecognizer: UILongPressGestureRecognizer) {
if !self.sendButtonHasApplyIcon && gestureRecognizer.state == .began {
//self.sendButtonLongPressed?()
}
}
func updateTheme(theme: PresentationTheme) { func updateTheme(theme: PresentationTheme) {
self.micButton.updateTheme(theme: theme) self.micButton.updateTheme(theme: theme)
self.expandMediaInputButton.setImage(PresentationResourcesChat.chatInputPanelExpandButtonImage(theme), for: []) self.expandMediaInputButton.setImage(PresentationResourcesChat.chatInputPanelExpandButtonImage(theme), for: [])

View File

@ -809,7 +809,7 @@ class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDelegate {
self.textPlaceholderNode.frame = CGRect(origin: self.textPlaceholderNode.frame.origin, size: placeholderSize) self.textPlaceholderNode.frame = CGRect(origin: self.textPlaceholderNode.frame.origin, size: placeholderSize)
} }
self.actionButtons.sendButtonLongPressEnabled = peer.id.namespace != Namespaces.Peer.SecretChat && !interfaceState.isScheduledMessages self.actionButtons.sendButtonLongPressEnabled = !interfaceState.isScheduledMessages
} }
let sendButtonHasApplyIcon = interfaceState.interfaceState.editMessage != nil let sendButtonHasApplyIcon = interfaceState.interfaceState.editMessage != nil

View File

@ -121,7 +121,7 @@ private final class DrawingStickersScreenNode: ViewControllerTracingNode {
}, navigateToFirstDateMessage: { _ in }, navigateToFirstDateMessage: { _ in
}, requestRedeliveryOfFailedMessages: { _ in }, requestRedeliveryOfFailedMessages: { _ in
}, addContact: { _ in }, addContact: { _ in
}, rateCall: { _, _ in }, rateCall: { _, _, _ in
}, requestSelectMessagePollOptions: { _, _ in }, requestSelectMessagePollOptions: { _, _ in
}, requestOpenMessagePollResults: { _, _ in }, requestOpenMessagePollResults: { _, _ in
}, openAppStorePage: { }, openAppStorePage: {

View File

@ -108,7 +108,7 @@ final class OverlayAudioPlayerControllerNode: ViewControllerTracingNode, UIGestu
}, navigateToFirstDateMessage: { _ in }, navigateToFirstDateMessage: { _ in
}, requestRedeliveryOfFailedMessages: { _ in }, requestRedeliveryOfFailedMessages: { _ in
}, addContact: { _ in }, addContact: { _ in
}, rateCall: { _, _ in }, rateCall: { _, _, _ in
}, requestSelectMessagePollOptions: { _, _ in }, requestSelectMessagePollOptions: { _, _ in
}, requestOpenMessagePollResults: { _, _ in }, requestOpenMessagePollResults: { _, _ in
}, openAppStorePage: { }, openAppStorePage: {

View File

@ -1930,7 +1930,7 @@ private final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewD
}, navigateToFirstDateMessage: { _ in }, navigateToFirstDateMessage: { _ in
}, requestRedeliveryOfFailedMessages: { _ in }, requestRedeliveryOfFailedMessages: { _ in
}, addContact: { _ in }, addContact: { _ in
}, rateCall: { _, _ in }, rateCall: { _, _, _ in
}, requestSelectMessagePollOptions: { _, _ in }, requestSelectMessagePollOptions: { _, _ in
}, requestOpenMessagePollResults: { _, _ in }, requestOpenMessagePollResults: { _, _ in
}, openAppStorePage: { }, openAppStorePage: {

View File

@ -413,7 +413,7 @@ public class PeerMediaCollectionController: TelegramBaseController {
}, navigateToFirstDateMessage: { _ in }, navigateToFirstDateMessage: { _ in
}, requestRedeliveryOfFailedMessages: { _ in }, requestRedeliveryOfFailedMessages: { _ in
}, addContact: { _ in }, addContact: { _ in
}, rateCall: { _, _ in }, rateCall: { _, _, _ in
}, requestSelectMessagePollOptions: { _, _ in }, requestSelectMessagePollOptions: { _, _ in
}, requestOpenMessagePollResults: { _, _ in }, requestOpenMessagePollResults: { _, _ in
}, openAppStorePage: { }, openAppStorePage: {

View File

@ -38,7 +38,7 @@ private final class PrefetchManagerImpl {
|> map { networkType -> MediaAutoDownloadNetworkType in |> map { networkType -> MediaAutoDownloadNetworkType in
switch networkType { switch networkType {
case .none, .cellular: case .none, .cellular:
return.cellular return .cellular
case .wifi: case .wifi:
return .wifi return .wifi
} }

View File

@ -1148,7 +1148,7 @@ public final class SharedAccountContextImpl: SharedAccountContext {
return PeerSelectionControllerImpl(params) return PeerSelectionControllerImpl(params)
} }
public func makeChatMessagePreviewItem(context: AccountContext, message: Message, theme: PresentationTheme, strings: PresentationStrings, wallpaper: TelegramWallpaper, fontSize: PresentationFontSize, chatBubbleCorners: PresentationChatBubbleCorners, dateTimeFormat: PresentationDateTimeFormat, nameOrder: PresentationPersonNameOrder, forcedResourceStatus: FileMediaResourceStatus?, tapMessage: ((Message) -> Void)? = nil, clickThroughMessage: (() -> Void)? = nil) -> ListViewItem { public func makeChatMessagePreviewItem(context: AccountContext, messages: [Message], theme: PresentationTheme, strings: PresentationStrings, wallpaper: TelegramWallpaper, fontSize: PresentationFontSize, chatBubbleCorners: PresentationChatBubbleCorners, dateTimeFormat: PresentationDateTimeFormat, nameOrder: PresentationPersonNameOrder, forcedResourceStatus: FileMediaResourceStatus?, tapMessage: ((Message) -> Void)? = nil, clickThroughMessage: (() -> Void)? = nil) -> ListViewItem {
let controllerInteraction: ChatControllerInteraction let controllerInteraction: ChatControllerInteraction
if tapMessage != nil || clickThroughMessage != nil { if tapMessage != nil || clickThroughMessage != nil {
controllerInteraction = ChatControllerInteraction(openMessage: { _, _ in controllerInteraction = ChatControllerInteraction(openMessage: { _, _ in
@ -1171,7 +1171,7 @@ public final class SharedAccountContextImpl: SharedAccountContext {
}, navigateToFirstDateMessage: { _ in }, navigateToFirstDateMessage: { _ in
}, requestRedeliveryOfFailedMessages: { _ in }, requestRedeliveryOfFailedMessages: { _ in
}, addContact: { _ in }, addContact: { _ in
}, rateCall: { _, _ in }, rateCall: { _, _, _ in
}, requestSelectMessagePollOptions: { _, _ in }, requestSelectMessagePollOptions: { _, _ in
}, requestOpenMessagePollResults: { _, _ in }, requestOpenMessagePollResults: { _, _ in
}, openAppStorePage: { }, openAppStorePage: {
@ -1202,7 +1202,17 @@ public final class SharedAccountContextImpl: SharedAccountContext {
controllerInteraction = defaultChatControllerInteraction controllerInteraction = defaultChatControllerInteraction
} }
return ChatMessageItem(presentationData: ChatPresentationData(theme: ChatPresentationThemeData(theme: theme, wallpaper: wallpaper), fontSize: fontSize, strings: strings, dateTimeFormat: dateTimeFormat, nameDisplayOrder: nameOrder, disableAnimations: false, largeEmoji: false, chatBubbleCorners: chatBubbleCorners, animatedEmojiScale: 1.0, isPreview: true), context: context, chatLocation: .peer(message.id.peerId), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .contact, automaticDownloadNetworkType: .cellular, isRecentActions: false, isScheduledMessages: false, contactsPeerIds: Set(), animatedEmojiStickers: [:], forcedResourceStatus: forcedResourceStatus), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, attributes: ChatMessageEntryAttributes()), disableDate: true, additionalContent: nil) let content: ChatMessageItemContent
let chatLocation: ChatLocation
if messages.count > 1 {
content = .group(messages: messages.map { ($0, true, .none, ChatMessageEntryAttributes()) })
chatLocation = .peer(messages.first!.id.peerId)
} else {
content = .message(message: messages.first!, read: true, selection: .none, attributes: ChatMessageEntryAttributes())
chatLocation = .peer(messages.first!.id.peerId)
}
return ChatMessageItem(presentationData: ChatPresentationData(theme: ChatPresentationThemeData(theme: theme, wallpaper: wallpaper), fontSize: fontSize, strings: strings, dateTimeFormat: dateTimeFormat, nameDisplayOrder: nameOrder, disableAnimations: false, largeEmoji: false, chatBubbleCorners: chatBubbleCorners, animatedEmojiScale: 1.0, isPreview: true), context: context, chatLocation: chatLocation, associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .contact, automaticDownloadNetworkType: .cellular, isRecentActions: false, isScheduledMessages: false, contactsPeerIds: Set(), animatedEmojiStickers: [:], forcedResourceStatus: forcedResourceStatus), controllerInteraction: controllerInteraction, content: content, disableDate: true, additionalContent: nil)
} }
public func makeChatMessageDateHeaderItem(context: AccountContext, timestamp: Int32, theme: PresentationTheme, strings: PresentationStrings, wallpaper: TelegramWallpaper, fontSize: PresentationFontSize, chatBubbleCorners: PresentationChatBubbleCorners, dateTimeFormat: PresentationDateTimeFormat, nameOrder: PresentationPersonNameOrder) -> ListViewItemHeader { public func makeChatMessageDateHeaderItem(context: AccountContext, timestamp: Int32, theme: PresentationTheme, strings: PresentationStrings, wallpaper: TelegramWallpaper, fontSize: PresentationFontSize, chatBubbleCorners: PresentationChatBubbleCorners, dateTimeFormat: PresentationDateTimeFormat, nameOrder: PresentationPersonNameOrder) -> ListViewItemHeader {

View File

@ -127,25 +127,6 @@ public final class TelegramRootController: NavigationController {
self.accountSettingsController = accountSettingsController self.accountSettingsController = accountSettingsController
self.rootTabController = tabBarController self.rootTabController = tabBarController
self.pushViewController(tabBarController, animated: false) self.pushViewController(tabBarController, animated: false)
// Queue.mainQueue().after(2.0) {
// let messageId = MessageId(peerId: PeerId(namespace: 2, id: 1488156064), namespace: 0, id: 528)
// let _ = ((self.context.account.postbox.transaction { transaction in
// return transaction.getMessage(messageId)
// }) |> deliverOnMainQueue).start(next: { [weak self] message in
// guard let strongSelf = self, let message = message else {
// return
// }
//
// let layout = ContainerViewLayout(size: CGSize(width: 414.0, height: 896.0), metrics: LayoutMetrics(widthClass: .compact, heightClass: .compact), deviceMetrics: .iPhoneX, intrinsicInsets: UIEdgeInsets(), safeInsets: UIEdgeInsets(), statusBarHeight: 0.0, inputHeight: nil, inputHeightIsInteractivellyChanging: false, inVoiceOver: false)
// let renderer = MessageStoryRenderer(context: strongSelf.context, message: message)
// let image = renderer.update(layout: layout)
//
// let node = renderer.containerNode
// node.frame = CGRect(origin: CGPoint(), size: layout.size)
// strongSelf.displayNode.addSubnode(node)
// })
// }
} }
public func updateRootControllers(showCallsTab: Bool) { public func updateRootControllers(showCallsTab: Bool) {
@ -193,134 +174,3 @@ public final class TelegramRootController: NavigationController {
presentedLegacyShortcutCamera(context: self.context, saveCapturedMedia: false, saveEditedPhotos: false, mediaGrouping: true, parentController: controller) presentedLegacyShortcutCamera(context: self.context, saveCapturedMedia: false, saveEditedPhotos: false, mediaGrouping: true, parentController: controller)
} }
} }
class MessageStoryRenderer {
private let context: AccountContext
private let presentationData: PresentationData
private let message: Message
let containerNode: ASDisplayNode
private let instantChatBackgroundNode: WallpaperBackgroundNode
private let messagesContainerNode: ASDisplayNode
private var dateHeaderNode: ListViewItemHeaderNode?
private var messageNodes: [ListViewItemNode]?
private let addressNode: ImmediateTextNode
init(context: AccountContext, message: Message) {
self.context = context
self.presentationData = context.sharedContext.currentPresentationData.with { $0 }
self.message = message
self.containerNode = ASDisplayNode()
self.instantChatBackgroundNode = WallpaperBackgroundNode()
self.instantChatBackgroundNode.displaysAsynchronously = false
self.instantChatBackgroundNode.image = chatControllerBackgroundImage(theme: presentationData.theme, wallpaper: .builtin(WallpaperSettings()), mediaBox: context.sharedContext.accountManager.mediaBox, knockoutMode: context.sharedContext.immediateExperimentalUISettings.knockoutWallpaper)
self.messagesContainerNode = ASDisplayNode()
self.messagesContainerNode.clipsToBounds = true
self.messagesContainerNode.transform = CATransform3DMakeScale(1.0, -1.0, 1.0)
let peer = message.peers[message.id.peerId]!
self.addressNode = ImmediateTextNode()
self.addressNode.displaysAsynchronously = false
self.addressNode.attributedText = NSAttributedString(string: "t.me/\(peer.addressName ?? "")", font: Font.medium(14.0), textColor: UIColor(rgb: 0xa8b7c4))
// self.addressNode.textShadowColor = .black
self.containerNode.addSubnode(self.instantChatBackgroundNode)
self.containerNode.addSubnode(self.messagesContainerNode)
self.containerNode.addSubnode(self.addressNode)
}
// func update(layout: ContainerViewLayout, completion: (UIImage?) -> Void) {
// self.updateMessagesLayout(layout: layout)
//
// Queue.mainQueue().after(0.01) {
// UIGraphicsBeginImageContextWithOptions(layout.size, false, 3.0)
// self.containerNode.view.drawHierarchy(in: CGRect(origin: CGPoint(), size: layout.size), afterScreenUpdates: true)
// let img = UIGraphicsGetImageFromCurrentImageContext()
// UIGraphicsEndImageContext()
// completion(img)
// }
// }
private func updateMessagesLayout(layout: ContainerViewLayout) {
let size = layout.size
self.containerNode.frame = CGRect(origin: CGPoint(), size: layout.size)
self.instantChatBackgroundNode.frame = CGRect(origin: CGPoint(), size: layout.size)
self.instantChatBackgroundNode.updateLayout(size: size, transition: .immediate)
self.messagesContainerNode.frame = CGRect(origin: CGPoint(), size: layout.size)
let addressLayout = self.addressNode.updateLayout(size)
let theme = self.presentationData.theme.withUpdated(preview: true)
let headerItem = self.context.sharedContext.makeChatMessageDateHeaderItem(context: self.context, timestamp: self.message.timestamp, theme: theme, strings: self.presentationData.strings, wallpaper: self.presentationData.chatWallpaper, fontSize: self.presentationData.chatFontSize, chatBubbleCorners: self.presentationData.chatBubbleCorners, dateTimeFormat: self.presentationData.dateTimeFormat, nameOrder: self.presentationData.nameDisplayOrder)
var items: [ListViewItem] = []
let sampleMessages: [Message] = [self.message]
items = sampleMessages.reversed().map { message in
self.context.sharedContext.makeChatMessagePreviewItem(context: self.context, message: message, theme: theme, strings: self.presentationData.strings, wallpaper: self.presentationData.theme.chat.defaultWallpaper, fontSize: self.presentationData.chatFontSize, chatBubbleCorners: self.presentationData.chatBubbleCorners, dateTimeFormat: self.presentationData.dateTimeFormat, nameOrder: self.presentationData.nameDisplayOrder, forcedResourceStatus: nil, tapMessage: nil, clickThroughMessage: nil)
}
let inset: CGFloat = 16.0
let width = layout.size.width - inset * 2.0
let params = ListViewItemLayoutParams(width: width, leftInset: layout.safeInsets.left, rightInset: layout.safeInsets.right, availableHeight: layout.size.height)
if let messageNodes = self.messageNodes {
for i in 0 ..< items.count {
let itemNode = messageNodes[i]
items[i].updateNode(async: { $0() }, node: {
return itemNode
}, params: params, previousItem: i == 0 ? nil : items[i - 1], nextItem: i == (items.count - 1) ? nil : items[i + 1], animation: .None, completion: { (layout, apply) in
let nodeFrame = CGRect(origin: CGPoint(x: 0.0, y: floor((size.height - layout.size.height) / 2.0)), size: CGSize(width: width, height: layout.size.height))
itemNode.contentSize = layout.contentSize
itemNode.insets = layout.insets
itemNode.frame = nodeFrame
itemNode.isUserInteractionEnabled = false
apply(ListViewItemApply(isOnScreen: true))
})
}
} else {
var messageNodes: [ListViewItemNode] = []
for i in 0 ..< items.count {
var itemNode: ListViewItemNode?
items[i].nodeConfiguredForParams(async: { $0() }, params: params, synchronousLoads: true, previousItem: i == 0 ? nil : items[i - 1], nextItem: i == (items.count - 1) ? nil : items[i + 1], completion: { node, apply in
itemNode = node
apply().1(ListViewItemApply(isOnScreen: true))
})
itemNode!.subnodeTransform = CATransform3DMakeScale(-1.0, 1.0, 1.0)
itemNode!.isUserInteractionEnabled = false
messageNodes.append(itemNode!)
self.messagesContainerNode.addSubnode(itemNode!)
}
self.messageNodes = messageNodes
}
var bottomOffset: CGFloat = 0.0
if let messageNodes = self.messageNodes {
for itemNode in messageNodes {
itemNode.frame = CGRect(origin: CGPoint(x: inset, y: floor((size.height - itemNode.frame.height) / 2.0)), size: itemNode.frame.size)
bottomOffset += itemNode.frame.maxY
itemNode.updateFrame(itemNode.frame, within: layout.size)
}
}
self.addressNode.frame = CGRect(origin: CGPoint(x: inset + 16.0, y: bottomOffset + 3.0), size: CGSize(width: addressLayout.width, height: addressLayout.height + 3.0))
let dateHeaderNode: ListViewItemHeaderNode
if let currentDateHeaderNode = self.dateHeaderNode {
dateHeaderNode = currentDateHeaderNode
headerItem.updateNode(dateHeaderNode, previous: nil, next: headerItem)
} else {
dateHeaderNode = headerItem.node()
dateHeaderNode.subnodeTransform = CATransform3DMakeScale(-1.0, 1.0, 1.0)
self.messagesContainerNode.addSubnode(dateHeaderNode)
self.dateHeaderNode = dateHeaderNode
}
dateHeaderNode.frame = CGRect(origin: CGPoint(x: 0.0, y: bottomOffset), size: CGSize(width: layout.size.width, height: headerItem.height))
dateHeaderNode.updateLayout(size: self.containerNode.frame.size, leftInset: layout.safeInsets.left, rightInset: layout.safeInsets.right)
}
}

View File

@ -12,6 +12,8 @@ public struct ExperimentalUISettings: Equatable, PreferencesEntry {
public var playerEmbedding: Bool public var playerEmbedding: Bool
public var playlistPlayback: Bool public var playlistPlayback: Bool
public var preferredVideoCodec: String? public var preferredVideoCodec: String?
public var disableVideoAspectScaling: Bool
public var enableVoipTcp: Bool
public static var defaultSettings: ExperimentalUISettings { public static var defaultSettings: ExperimentalUISettings {
return ExperimentalUISettings( return ExperimentalUISettings(
@ -23,7 +25,9 @@ public struct ExperimentalUISettings: Equatable, PreferencesEntry {
foldersTabAtBottom: false, foldersTabAtBottom: false,
playerEmbedding: false, playerEmbedding: false,
playlistPlayback: false, playlistPlayback: false,
preferredVideoCodec: nil preferredVideoCodec: nil,
disableVideoAspectScaling: false,
enableVoipTcp: false
) )
} }
@ -36,7 +40,9 @@ public struct ExperimentalUISettings: Equatable, PreferencesEntry {
foldersTabAtBottom: Bool, foldersTabAtBottom: Bool,
playerEmbedding: Bool, playerEmbedding: Bool,
playlistPlayback: Bool, playlistPlayback: Bool,
preferredVideoCodec: String? preferredVideoCodec: String?,
disableVideoAspectScaling: Bool,
enableVoipTcp: Bool
) { ) {
self.keepChatNavigationStack = keepChatNavigationStack self.keepChatNavigationStack = keepChatNavigationStack
self.skipReadHistory = skipReadHistory self.skipReadHistory = skipReadHistory
@ -47,6 +53,8 @@ public struct ExperimentalUISettings: Equatable, PreferencesEntry {
self.playerEmbedding = playerEmbedding self.playerEmbedding = playerEmbedding
self.playlistPlayback = playlistPlayback self.playlistPlayback = playlistPlayback
self.preferredVideoCodec = preferredVideoCodec self.preferredVideoCodec = preferredVideoCodec
self.disableVideoAspectScaling = disableVideoAspectScaling
self.enableVoipTcp = enableVoipTcp
} }
public init(decoder: PostboxDecoder) { public init(decoder: PostboxDecoder) {
@ -59,6 +67,8 @@ public struct ExperimentalUISettings: Equatable, PreferencesEntry {
self.playerEmbedding = decoder.decodeInt32ForKey("playerEmbedding", orElse: 0) != 0 self.playerEmbedding = decoder.decodeInt32ForKey("playerEmbedding", orElse: 0) != 0
self.playlistPlayback = decoder.decodeInt32ForKey("playlistPlayback", orElse: 0) != 0 self.playlistPlayback = decoder.decodeInt32ForKey("playlistPlayback", orElse: 0) != 0
self.preferredVideoCodec = decoder.decodeOptionalStringForKey("preferredVideoCodec") self.preferredVideoCodec = decoder.decodeOptionalStringForKey("preferredVideoCodec")
self.disableVideoAspectScaling = decoder.decodeInt32ForKey("disableVideoAspectScaling", orElse: 0) != 0
self.enableVoipTcp = decoder.decodeInt32ForKey("enableVoipTcp", orElse: 0) != 0
} }
public func encode(_ encoder: PostboxEncoder) { public func encode(_ encoder: PostboxEncoder) {
@ -73,6 +83,8 @@ public struct ExperimentalUISettings: Equatable, PreferencesEntry {
if let preferredVideoCodec = self.preferredVideoCodec { if let preferredVideoCodec = self.preferredVideoCodec {
encoder.encodeString(preferredVideoCodec, forKey: "preferredVideoCodec") encoder.encodeString(preferredVideoCodec, forKey: "preferredVideoCodec")
} }
encoder.encodeInt32(self.disableVideoAspectScaling ? 1 : 0, forKey: "disableVideoAspectScaling")
encoder.encodeInt32(self.enableVoipTcp ? 1 : 0, forKey: "enableVoipTcp")
} }
public func isEqual(to: PreferencesEntry) -> Bool { public func isEqual(to: PreferencesEntry) -> Bool {

View File

@ -34,8 +34,6 @@ private func callConnectionDescriptionsWebrtc(_ connection: CallSessionConnectio
} }
} }
private let callLogsLimit = 20
public func callLogNameForId(id: Int64, account: Account) -> String? { public func callLogNameForId(id: Int64, account: Account) -> String? {
let path = callLogsPath(account: account) let path = callLogsPath(account: account)
let namePrefix = "\(id)_" let namePrefix = "\(id)_"
@ -63,26 +61,25 @@ private func cleanupCallLogs(account: Account) {
try? fileManager.createDirectory(atPath: path, withIntermediateDirectories: true, attributes: nil) try? fileManager.createDirectory(atPath: path, withIntermediateDirectories: true, attributes: nil)
} }
var oldest: (URL, Date)? = nil var oldest: [(URL, Date)] = []
var count = 0 var count = 0
if let enumerator = FileManager.default.enumerator(at: URL(fileURLWithPath: path), includingPropertiesForKeys: [.contentModificationDateKey], options: [.skipsHiddenFiles, .skipsSubdirectoryDescendants], errorHandler: nil) { if let enumerator = FileManager.default.enumerator(at: URL(fileURLWithPath: path), includingPropertiesForKeys: [.contentModificationDateKey], options: [.skipsHiddenFiles, .skipsSubdirectoryDescendants], errorHandler: nil) {
for url in enumerator { for url in enumerator {
if let url = url as? URL { if let url = url as? URL {
if let date = (try? url.resourceValues(forKeys: Set([.contentModificationDateKey])))?.contentModificationDate { if let date = (try? url.resourceValues(forKeys: Set([.contentModificationDateKey])))?.contentModificationDate {
if let currentOldest = oldest { oldest.append((url, date))
if date < currentOldest.1 {
oldest = (url, date)
}
} else {
oldest = (url, date)
}
count += 1 count += 1
} }
} }
} }
} }
if count > callLogsLimit, let oldest = oldest { let callLogsLimit = 40
try? fileManager.removeItem(atPath: oldest.0.path) if count > callLogsLimit {
oldest.sort(by: { $0.1 > $1.1 })
while oldest.count > callLogsLimit {
try? fileManager.removeItem(atPath: oldest[oldest.count - 1].0.path)
oldest.removeLast()
}
} }
} }
@ -271,6 +268,7 @@ private protocol OngoingCallThreadLocalContextProtocol: class {
func nativeSetIsMuted(_ value: Bool) func nativeSetIsMuted(_ value: Bool)
func nativeSetIsLowBatteryLevel(_ value: Bool) func nativeSetIsLowBatteryLevel(_ value: Bool)
func nativeRequestVideo(_ capturer: OngoingCallVideoCapturer) func nativeRequestVideo(_ capturer: OngoingCallVideoCapturer)
func nativeSetRequestedVideoAspect(_ aspect: Float)
func nativeDisableVideo() func nativeDisableVideo()
func nativeStop(_ completion: @escaping (String?, Int64, Int64, Int64, Int64) -> Void) func nativeStop(_ completion: @escaping (String?, Int64, Int64, Int64, Int64) -> Void)
func nativeBeginTermination() func nativeBeginTermination()
@ -309,6 +307,9 @@ extension OngoingCallThreadLocalContext: OngoingCallThreadLocalContextProtocol {
func nativeRequestVideo(_ capturer: OngoingCallVideoCapturer) { func nativeRequestVideo(_ capturer: OngoingCallVideoCapturer) {
} }
func nativeSetRequestedVideoAspect(_ aspect: Float) {
}
func nativeDisableVideo() { func nativeDisableVideo() {
} }
@ -347,10 +348,24 @@ public final class OngoingCallVideoCapturer {
setOnFirstFrameReceived: { [weak view] f in setOnFirstFrameReceived: { [weak view] f in
view?.setOnFirstFrameReceived(f) view?.setOnFirstFrameReceived(f)
}, },
getOrientation: { getOrientation: { [weak view] in
return .rotation0 if let view = view {
return OngoingCallVideoOrientation(view.orientation)
} else {
return .rotation0
}
}, },
setOnOrientationUpdated: { _ in getAspect: { [weak view] in
if let view = view {
return view.aspect
} else {
return 0.0
}
},
setOnOrientationUpdated: { [weak view] f in
view?.setOnOrientationUpdated { value, aspect in
f?(OngoingCallVideoOrientation(value), aspect)
}
}, },
setOnIsMirroredUpdated: { [weak view] f in setOnIsMirroredUpdated: { [weak view] f in
view?.setOnIsMirroredUpdated(f) view?.setOnIsMirroredUpdated(f)
@ -392,6 +407,10 @@ extension OngoingCallThreadLocalContextWebrtc: OngoingCallThreadLocalContextProt
self.requestVideo(capturer.impl) self.requestVideo(capturer.impl)
} }
func nativeSetRequestedVideoAspect(_ aspect: Float) {
self.setRequestedVideoAspect(aspect)
}
func nativeDisableVideo() { func nativeDisableVideo() {
self.disableVideo() self.disableVideo()
} }
@ -456,11 +475,11 @@ private extension OngoingCallVideoOrientation {
case .orientation0: case .orientation0:
self = .rotation0 self = .rotation0
case .orientation90: case .orientation90:
self = .rotation270 self = .rotation90
case .orientation180: case .orientation180:
self = .rotation180 self = .rotation180
case .orientation270: case .orientation270:
self = .rotation90 self = .rotation270
@unknown default: @unknown default:
self = .rotation0 self = .rotation0
} }
@ -471,19 +490,22 @@ public final class OngoingCallContextPresentationCallVideoView {
public let view: UIView public let view: UIView
public let setOnFirstFrameReceived: (((Float) -> Void)?) -> Void public let setOnFirstFrameReceived: (((Float) -> Void)?) -> Void
public let getOrientation: () -> OngoingCallVideoOrientation public let getOrientation: () -> OngoingCallVideoOrientation
public let setOnOrientationUpdated: (((OngoingCallVideoOrientation) -> Void)?) -> Void public let getAspect: () -> CGFloat
public let setOnOrientationUpdated: (((OngoingCallVideoOrientation, CGFloat) -> Void)?) -> Void
public let setOnIsMirroredUpdated: (((Bool) -> Void)?) -> Void public let setOnIsMirroredUpdated: (((Bool) -> Void)?) -> Void
public init( public init(
view: UIView, view: UIView,
setOnFirstFrameReceived: @escaping (((Float) -> Void)?) -> Void, setOnFirstFrameReceived: @escaping (((Float) -> Void)?) -> Void,
getOrientation: @escaping () -> OngoingCallVideoOrientation, getOrientation: @escaping () -> OngoingCallVideoOrientation,
setOnOrientationUpdated: @escaping (((OngoingCallVideoOrientation) -> Void)?) -> Void, getAspect: @escaping () -> CGFloat,
setOnOrientationUpdated: @escaping (((OngoingCallVideoOrientation, CGFloat) -> Void)?) -> Void,
setOnIsMirroredUpdated: @escaping (((Bool) -> Void)?) -> Void setOnIsMirroredUpdated: @escaping (((Bool) -> Void)?) -> Void
) { ) {
self.view = view self.view = view
self.setOnFirstFrameReceived = setOnFirstFrameReceived self.setOnFirstFrameReceived = setOnFirstFrameReceived
self.getOrientation = getOrientation self.getOrientation = getOrientation
self.getAspect = getAspect
self.setOnOrientationUpdated = setOnOrientationUpdated self.setOnOrientationUpdated = setOnOrientationUpdated
self.setOnIsMirroredUpdated = setOnIsMirroredUpdated self.setOnIsMirroredUpdated = setOnIsMirroredUpdated
} }
@ -541,6 +563,9 @@ public final class OngoingCallContext {
return OngoingCallThreadLocalContext.maxLayer() return OngoingCallThreadLocalContext.maxLayer()
} }
private let tempLogFile: TempBoxFile
private let tempStatsLogFile: TempBoxFile
public static func versions(includeExperimental: Bool, includeReference: Bool) -> [(version: String, supportsVideo: Bool)] { public static func versions(includeExperimental: Bool, includeReference: Bool) -> [(version: String, supportsVideo: Bool)] {
var result: [(version: String, supportsVideo: Bool)] = [(OngoingCallThreadLocalContext.version(), false)] var result: [(version: String, supportsVideo: Bool)] = [(OngoingCallThreadLocalContext.version(), false)]
if includeExperimental { if includeExperimental {
@ -551,7 +576,7 @@ public final class OngoingCallContext {
return result return result
} }
public init(account: Account, callSessionManager: CallSessionManager, internalId: CallSessionInternalId, proxyServer: ProxyServerSettings?, initialNetworkType: NetworkType, updatedNetworkType: Signal<NetworkType, NoError>, serializedData: String?, dataSaving: VoiceCallDataSaving, derivedState: VoipDerivedState, key: Data, isOutgoing: Bool, video: OngoingCallVideoCapturer?, connections: CallSessionConnectionSet, maxLayer: Int32, version: String, allowP2P: Bool, audioSessionActive: Signal<Bool, NoError>, logName: String, preferredVideoCodec: String?) { public init(account: Account, callSessionManager: CallSessionManager, internalId: CallSessionInternalId, proxyServer: ProxyServerSettings?, initialNetworkType: NetworkType, updatedNetworkType: Signal<NetworkType, NoError>, serializedData: String?, dataSaving: VoiceCallDataSaving, derivedState: VoipDerivedState, key: Data, isOutgoing: Bool, video: OngoingCallVideoCapturer?, connections: CallSessionConnectionSet, maxLayer: Int32, version: String, allowP2P: Bool, enableTCP: Bool, enableStunMarking: Bool, audioSessionActive: Signal<Bool, NoError>, logName: String, preferredVideoCodec: String?) {
let _ = setupLogs let _ = setupLogs
OngoingCallThreadLocalContext.applyServerConfig(serializedData) OngoingCallThreadLocalContext.applyServerConfig(serializedData)
@ -560,6 +585,11 @@ public final class OngoingCallContext {
self.callSessionManager = callSessionManager self.callSessionManager = callSessionManager
self.logPath = logName.isEmpty ? "" : callLogsPath(account: self.account) + "/" + logName + ".log" self.logPath = logName.isEmpty ? "" : callLogsPath(account: self.account) + "/" + logName + ".log"
let logPath = self.logPath let logPath = self.logPath
self.tempLogFile = TempBox.shared.tempFile(fileName: "CallLog.txt")
let tempLogPath = self.tempLogFile.path
self.tempStatsLogFile = TempBox.shared.tempFile(fileName: "CallStats.json")
let tempStatsLogPath = self.tempStatsLogFile.path
let queue = self.queue let queue = self.queue
@ -581,11 +611,6 @@ public final class OngoingCallContext {
} }
} }
let screenSize = UIScreen.main.bounds.size
let portraitSize = CGSize(width: min(screenSize.width, screenSize.height), height: max(screenSize.width, screenSize.height))
let preferredAspectRatio = portraitSize.width / portraitSize.height
let unfilteredConnections = [connections.primary] + connections.alternatives let unfilteredConnections = [connections.primary] + connections.alternatives
var processedConnections: [CallSessionConnection] = [] var processedConnections: [CallSessionConnection] = []
var filteredConnections: [OngoingCallConnectionDescriptionWebrtc] = [] var filteredConnections: [OngoingCallConnectionDescriptionWebrtc] = []
@ -597,9 +622,9 @@ public final class OngoingCallContext {
filteredConnections.append(contentsOf: callConnectionDescriptionsWebrtc(connection)) filteredConnections.append(contentsOf: callConnectionDescriptionsWebrtc(connection))
} }
let context = OngoingCallThreadLocalContextWebrtc(version: version, queue: OngoingCallThreadLocalContextQueueImpl(queue: queue), proxy: voipProxyServer, networkType: ongoingNetworkTypeForTypeWebrtc(initialNetworkType), dataSaving: ongoingDataSavingForTypeWebrtc(dataSaving), derivedState: derivedState.data, key: key, isOutgoing: isOutgoing, connections: filteredConnections, maxLayer: maxLayer, allowP2P: allowP2P, logPath: logPath, sendSignalingData: { [weak callSessionManager] data in let context = OngoingCallThreadLocalContextWebrtc(version: version, queue: OngoingCallThreadLocalContextQueueImpl(queue: queue), proxy: voipProxyServer, networkType: ongoingNetworkTypeForTypeWebrtc(initialNetworkType), dataSaving: ongoingDataSavingForTypeWebrtc(dataSaving), derivedState: derivedState.data, key: key, isOutgoing: isOutgoing, connections: filteredConnections, maxLayer: maxLayer, allowP2P: allowP2P, allowTCP: enableTCP, enableStunMarking: enableStunMarking, logPath: tempLogPath, statsLogPath: tempStatsLogPath, sendSignalingData: { [weak callSessionManager] data in
callSessionManager?.sendSignalingData(internalId: internalId, data: data) callSessionManager?.sendSignalingData(internalId: internalId, data: data)
}, videoCapturer: video?.impl, preferredAspectRatio: Float(preferredAspectRatio), preferredVideoCodec: preferredVideoCodec) }, videoCapturer: video?.impl, preferredVideoCodec: preferredVideoCodec)
strongSelf.contextRef = Unmanaged.passRetained(OngoingCallThreadLocalContextHolder(context)) strongSelf.contextRef = Unmanaged.passRetained(OngoingCallThreadLocalContextHolder(context))
context.stateChanged = { [weak callSessionManager] state, videoState, remoteVideoState, remoteAudioState, remoteBatteryLevel, _ in context.stateChanged = { [weak callSessionManager] state, videoState, remoteVideoState, remoteAudioState, remoteBatteryLevel, _ in
@ -748,10 +773,15 @@ public final class OngoingCallContext {
public func stop(callId: CallId? = nil, sendDebugLogs: Bool = false, debugLogValue: Promise<String?>) { public func stop(callId: CallId? = nil, sendDebugLogs: Bool = false, debugLogValue: Promise<String?>) {
let account = self.account let account = self.account
let logPath = self.logPath let logPath = self.logPath
var statsLogPath = ""
if !logPath.isEmpty {
statsLogPath = logPath + ".json"
}
let tempLogPath = self.tempLogFile.path
let tempStatsLogPath = self.tempStatsLogFile.path
self.withContextThenDeallocate { context in self.withContextThenDeallocate { context in
context.nativeStop { debugLog, bytesSentWifi, bytesReceivedWifi, bytesSentMobile, bytesReceivedMobile in context.nativeStop { debugLog, bytesSentWifi, bytesReceivedWifi, bytesSentMobile, bytesReceivedMobile in
debugLogValue.set(.single(debugLog))
let delta = NetworkUsageStatsConnectionsEntry( let delta = NetworkUsageStatsConnectionsEntry(
cellular: NetworkUsageStatsDirectionsEntry( cellular: NetworkUsageStatsDirectionsEntry(
incoming: bytesReceivedMobile, incoming: bytesReceivedMobile,
@ -761,17 +791,22 @@ public final class OngoingCallContext {
outgoing: bytesSentWifi)) outgoing: bytesSentWifi))
updateAccountNetworkUsageStats(account: self.account, category: .call, delta: delta) updateAccountNetworkUsageStats(account: self.account, category: .call, delta: delta)
if !logPath.isEmpty, let debugLog = debugLog { if !logPath.isEmpty {
let logsPath = callLogsPath(account: account) let logsPath = callLogsPath(account: account)
let _ = try? FileManager.default.createDirectory(atPath: logsPath, withIntermediateDirectories: true, attributes: nil) let _ = try? FileManager.default.createDirectory(atPath: logsPath, withIntermediateDirectories: true, attributes: nil)
if let data = debugLog.data(using: .utf8) { let _ = try? FileManager.default.moveItem(atPath: tempLogPath, toPath: logPath)
let _ = try? data.write(to: URL(fileURLWithPath: logPath))
}
} }
if let callId = callId, let debugLog = debugLog { if !statsLogPath.isEmpty {
let logsPath = callLogsPath(account: account)
let _ = try? FileManager.default.createDirectory(atPath: logsPath, withIntermediateDirectories: true, attributes: nil)
let _ = try? FileManager.default.moveItem(atPath: tempStatsLogPath, toPath: statsLogPath)
}
if let callId = callId, !statsLogPath.isEmpty, let data = try? Data(contentsOf: URL(fileURLWithPath: statsLogPath)), let dataString = String(data: data, encoding: .utf8) {
debugLogValue.set(.single(dataString))
if sendDebugLogs { if sendDebugLogs {
let _ = saveCallDebugLog(network: self.account.network, callId: callId, log: debugLog).start() let _ = saveCallDebugLog(network: self.account.network, callId: callId, log: dataString).start()
} }
} }
} }
@ -800,6 +835,12 @@ public final class OngoingCallContext {
} }
} }
public func setRequestedVideoAspect(_ aspect: Float) {
self.withContext { context in
context.nativeSetRequestedVideoAspect(aspect)
}
}
public func disableVideo() { public func disableVideo() {
self.withContext { context in self.withContext { context in
context.nativeDisableVideo() context.nativeDisableVideo()
@ -837,9 +878,16 @@ public final class OngoingCallContext {
return .rotation0 return .rotation0
} }
}, },
getAspect: { [weak view] in
if let view = view {
return view.aspect
} else {
return 0.0
}
},
setOnOrientationUpdated: { [weak view] f in setOnOrientationUpdated: { [weak view] f in
view?.setOnOrientationUpdated { value in view?.setOnOrientationUpdated { value, aspect in
f?(OngoingCallVideoOrientation(value)) f?(OngoingCallVideoOrientation(value), aspect)
} }
}, },
setOnIsMirroredUpdated: { [weak view] f in setOnIsMirroredUpdated: { [weak view] f in

View File

@ -1,3 +1,5 @@
use_gn_build = True
webrtc_libs = [ webrtc_libs = [
"libwebrtc.a", "libwebrtc.a",
] ]
@ -70,7 +72,7 @@ genrule(
) )
cc_library( cc_library(
name = "webrtc_lib_gn", name = "webrtc_lib_gn" if not use_gn_build else "webrtc_lib",
srcs = [":" + x for x in webrtc_libs], srcs = [":" + x for x in webrtc_libs],
visibility = ["//visibility:public"], visibility = ["//visibility:public"],
) )
@ -2182,7 +2184,7 @@ objc_library(
) )
objc_library( objc_library(
name = "webrtc_lib", name = "webrtc_lib_custom" if use_gn_build else "webrtc_lib",
enable_modules = True, enable_modules = True,
module_name = "webrtc", module_name = "webrtc",
srcs = combined_sources, srcs = combined_sources,