Initial downloads list implementation

This commit is contained in:
Ali 2022-02-11 23:49:38 +04:00
parent e87cf3710f
commit c8bc4b7f12
39 changed files with 816 additions and 139 deletions

View File

@ -93,3 +93,10 @@ public func messageMediaFileStatus(context: AccountContext, messageId: MessageId
} }
|> distinctUntilChanged |> distinctUntilChanged
} }
public func messageMediaImageStatus(context: AccountContext, messageId: MessageId, image: TelegramMediaImage) -> Signal<MediaResourceStatus, NoError> {
guard let representation = image.representations.last else {
return .single(.Remote)
}
return context.fetchManager.fetchStatus(category: .image, location: .chat(messageId.peerId), locationKey: .messageId(messageId), resource: representation.resource)
}

View File

@ -22,7 +22,8 @@ swift_library(
"//submodules/OverlayStatusController:OverlayStatusController", "//submodules/OverlayStatusController:OverlayStatusController",
"//submodules/AccountContext:AccountContext", "//submodules/AccountContext:AccountContext",
"//submodules/AppBundle:AppBundle", "//submodules/AppBundle:AppBundle",
"//submodules/GZip:GZip" "//submodules/GZip:GZip",
"//third-party/ZipArchive:ZipArchive",
], ],
visibility = [ visibility = [
"//visibility:public", "//visibility:public",

View File

@ -13,7 +13,7 @@ import PresentationDataUtils
import OverlayStatusController import OverlayStatusController
import AccountContext import AccountContext
import AppBundle import AppBundle
import GZip import ZipArchive
@objc private final class DebugControllerMailComposeDelegate: NSObject, MFMailComposeViewControllerDelegate { @objc private final class DebugControllerMailComposeDelegate: NSObject, MFMailComposeViewControllerDelegate {
public func mailComposeController(_ controller: MFMailComposeViewController, didFinishWith result: MFMailComposeResult, error: Error?) { public func mailComposeController(_ controller: MFMailComposeViewController, didFinishWith result: MFMailComposeResult, error: Error?) {
@ -252,7 +252,19 @@ private enum DebugControllerEntry: ItemListNodeEntry {
} }
} }
let gzippedData = TGGZipData(rawLogData, 1.0) let tempSource = TempBox.shared.tempFile(fileName: "Log.txt")
let tempZip = TempBox.shared.tempFile(fileName: "destination.zip")
let _ = try? rawLogData.write(to: URL(fileURLWithPath: tempSource.path))
SSZipArchive.createZipFile(atPath: tempZip.path, withFilesAtPaths: [tempSource.path])
guard let gzippedData = try? Data(contentsOf: URL(fileURLWithPath: tempZip.path)) else {
return
}
TempBox.shared.dispose(tempSource)
TempBox.shared.dispose(tempZip)
let id = Int64.random(in: Int64.min ... Int64.max) let id = Int64.random(in: Int64.min ... Int64.max)
let fileResource = LocalFileMediaResource(fileId: id, size: gzippedData.count, isSecretRelated: false) let fileResource = LocalFileMediaResource(fileId: id, size: gzippedData.count, isSecretRelated: false)
@ -406,7 +418,19 @@ private enum DebugControllerEntry: ItemListNodeEntry {
} }
} }
let gzippedData = TGGZipData(rawLogData, 1.0) let tempSource = TempBox.shared.tempFile(fileName: "Log.txt")
let tempZip = TempBox.shared.tempFile(fileName: "destination.zip")
let _ = try? rawLogData.write(to: URL(fileURLWithPath: tempSource.path))
SSZipArchive.createZipFile(atPath: tempZip.path, withFilesAtPaths: [tempSource.path])
guard let gzippedData = try? Data(contentsOf: URL(fileURLWithPath: tempZip.path)) else {
return
}
TempBox.shared.dispose(tempSource)
TempBox.shared.dispose(tempZip)
let id = Int64.random(in: Int64.min ... Int64.max) let id = Int64.random(in: Int64.min ... Int64.max)
let fileResource = LocalFileMediaResource(fileId: id, size: gzippedData.count, isSecretRelated: false) let fileResource = LocalFileMediaResource(fileId: id, size: gzippedData.count, isSecretRelated: false)
@ -478,7 +502,19 @@ private enum DebugControllerEntry: ItemListNodeEntry {
} }
} }
let gzippedData = TGGZipData(rawLogData, 1.0) let tempSource = TempBox.shared.tempFile(fileName: "Log.txt")
let tempZip = TempBox.shared.tempFile(fileName: "destination.zip")
let _ = try? rawLogData.write(to: URL(fileURLWithPath: tempSource.path))
SSZipArchive.createZipFile(atPath: tempZip.path, withFilesAtPaths: [tempSource.path])
guard let gzippedData = try? Data(contentsOf: URL(fileURLWithPath: tempZip.path)) else {
return
}
TempBox.shared.dispose(tempSource)
TempBox.shared.dispose(tempZip)
let id = Int64.random(in: Int64.min ... Int64.max) let id = Int64.random(in: Int64.min ... Int64.max)
let fileResource = LocalFileMediaResource(fileId: id, size: gzippedData.count, isSecretRelated: false) let fileResource = LocalFileMediaResource(fileId: id, size: gzippedData.count, isSecretRelated: false)
@ -1055,3 +1091,61 @@ public func debugController(sharedContext: SharedAccountContext, context: Accoun
} }
return controller return controller
} }
public func triggerDebugSendLogsUI(context: AccountContext, additionalInfo: String = "", pushController: @escaping (ViewController) -> Void) {
let _ = (Logger.shared.collectLogs()
|> deliverOnMainQueue).start(next: { logs in
let controller = context.sharedContext.makePeerSelectionController(PeerSelectionControllerParams(context: context, filter: [.onlyWriteable, .excludeDisabled]))
controller.peerSelected = { [weak controller] peer in
let peerId = peer.id
if let strongController = controller {
strongController.dismiss()
let lineFeed = "\n".data(using: .utf8)!
var rawLogData: Data = Data()
for (name, path) in logs {
if !rawLogData.isEmpty {
rawLogData.append(lineFeed)
rawLogData.append(lineFeed)
}
rawLogData.append("------ File: \(name) ------\n".data(using: .utf8)!)
if let data = try? Data(contentsOf: URL(fileURLWithPath: path)) {
rawLogData.append(data)
}
}
if !additionalInfo.isEmpty {
rawLogData.append("------ Additional Info ------\n".data(using: .utf8)!)
rawLogData.append("\(additionalInfo)".data(using: .utf8)!)
}
let tempSource = TempBox.shared.tempFile(fileName: "Log.txt")
let tempZip = TempBox.shared.tempFile(fileName: "destination.zip")
let _ = try? rawLogData.write(to: URL(fileURLWithPath: tempSource.path))
SSZipArchive.createZipFile(atPath: tempZip.path, withFilesAtPaths: [tempSource.path])
guard let gzippedData = try? Data(contentsOf: URL(fileURLWithPath: tempZip.path)) else {
return
}
TempBox.shared.dispose(tempSource)
TempBox.shared.dispose(tempZip)
let id = Int64.random(in: Int64.min ... Int64.max)
let fileResource = LocalFileMediaResource(fileId: id, size: gzippedData.count, isSecretRelated: false)
context.account.postbox.mediaBox.storeResourceData(fileResource.id, data: gzippedData)
let file = TelegramMediaFile(fileId: MediaId(namespace: Namespaces.Media.LocalFile, id: id), partialReference: nil, resource: fileResource, previewRepresentations: [], videoThumbnails: [], immediateThumbnailData: nil, mimeType: "application/text", size: gzippedData.count, attributes: [.FileName(fileName: "Log-iOS-Full.txt.zip")])
let message: EnqueueMessage = .message(text: "", attributes: [], mediaReference: .standalone(media: file), replyToMessageId: nil, localGroupingKey: nil, correlationId: nil)
let _ = enqueueMessages(account: context.account, peerId: peerId, messages: [message]).start()
}
}
pushController(controller)
})
}

View File

@ -0,0 +1,23 @@
load("@build_bazel_rules_swift//swift:swift.bzl", "swift_library")
swift_library(
name = "FetchManagerImpl",
module_name = "FetchManagerImpl",
srcs = glob([
"Sources/**/*.swift",
]),
copts = [
"-warnings-as-errors",
],
deps = [
"//submodules/SSignalKit/SwiftSignalKit:SwiftSignalKit",
"//submodules/Postbox:Postbox",
"//submodules/TelegramCore:TelegramCore",
"//submodules/TelegramUIPreferences:TelegramUIPreferences",
"//submodules/AccountContext:AccountContext",
"//submodules/MediaPlayer:UniversalMediaPlayer",
],
visibility = [
"//visibility:public",
],
)

View File

@ -7,12 +7,12 @@ import TelegramUIPreferences
import AccountContext import AccountContext
import UniversalMediaPlayer import UniversalMediaPlayer
private struct FetchManagerLocationEntryId: Hashable { public struct FetchManagerLocationEntryId: Hashable {
let location: FetchManagerLocation public let location: FetchManagerLocation
let resourceId: MediaResourceId public let resourceId: MediaResourceId
let locationKey: FetchManagerLocationKey public let locationKey: FetchManagerLocationKey
static func ==(lhs: FetchManagerLocationEntryId, rhs: FetchManagerLocationEntryId) -> Bool { public static func ==(lhs: FetchManagerLocationEntryId, rhs: FetchManagerLocationEntryId) -> Bool {
if lhs.location != rhs.location { if lhs.location != rhs.location {
return false return false
} }
@ -25,7 +25,7 @@ private struct FetchManagerLocationEntryId: Hashable {
return true return true
} }
func hash(into hasher: inout Hasher) { public func hash(into hasher: inout Hasher) {
hasher.combine(self.resourceId.hashValue) hasher.combine(self.resourceId.hashValue)
hasher.combine(self.locationKey) hasher.combine(self.locationKey)
} }
@ -116,7 +116,7 @@ private final class FetchManagerCategoryContext {
private let postbox: Postbox private let postbox: Postbox
private let storeManager: DownloadedMediaStoreManager? private let storeManager: DownloadedMediaStoreManager?
private let entryCompleted: (FetchManagerLocationEntryId) -> Void private let entryCompleted: (FetchManagerLocationEntryId) -> Void
private let activeEntriesUpdated: () -> Void private let activeEntriesUpdated: ([FetchManagerEntrySummary]) -> Void
private var topEntryIdAndPriority: (FetchManagerLocationEntryId, FetchManagerPriorityKey)? private var topEntryIdAndPriority: (FetchManagerLocationEntryId, FetchManagerPriorityKey)?
private var entries: [FetchManagerLocationEntryId: FetchManagerLocationEntry] = [:] private var entries: [FetchManagerLocationEntryId: FetchManagerLocationEntry] = [:]
@ -133,7 +133,7 @@ private final class FetchManagerCategoryContext {
return false return false
} }
init(postbox: Postbox, storeManager: DownloadedMediaStoreManager?, entryCompleted: @escaping (FetchManagerLocationEntryId) -> Void, activeEntriesUpdated: @escaping () -> Void) { init(postbox: Postbox, storeManager: DownloadedMediaStoreManager?, entryCompleted: @escaping (FetchManagerLocationEntryId) -> Void, activeEntriesUpdated: @escaping ([FetchManagerEntrySummary]) -> Void) {
self.postbox = postbox self.postbox = postbox
self.storeManager = storeManager self.storeManager = storeManager
self.entryCompleted = entryCompleted self.entryCompleted = entryCompleted
@ -182,6 +182,7 @@ private final class FetchManagerCategoryContext {
} }
var activeContextsUpdated = false var activeContextsUpdated = false
let _ = activeContextsUpdated
if self.maybeFindAndActivateNewTopEntry() { if self.maybeFindAndActivateNewTopEntry() {
activeContextsUpdated = true activeContextsUpdated = true
@ -285,9 +286,7 @@ private final class FetchManagerCategoryContext {
} }
} }
if activeContextsUpdated { self.activeEntriesUpdated(self.entries.values.compactMap(FetchManagerEntrySummary.init).sorted(by: { $0.priority < $1.priority }))
self.activeEntriesUpdated()
}
} }
func maybeFindAndActivateNewTopEntry() -> Bool { func maybeFindAndActivateNewTopEntry() -> Bool {
@ -406,8 +405,12 @@ private final class FetchManagerCategoryContext {
} }
} }
var entriesRemoved = false
let _ = entriesRemoved
if let _ = self.entries[id] { if let _ = self.entries[id] {
self.entries.removeValue(forKey: id) self.entries.removeValue(forKey: id)
entriesRemoved = true
if let statusContext = self.statusContexts[id] { if let statusContext = self.statusContexts[id] {
if statusContext.hasEntry { if statusContext.hasEntry {
@ -426,6 +429,7 @@ private final class FetchManagerCategoryContext {
} }
var activeContextsUpdated = false var activeContextsUpdated = false
let _ = activeContextsUpdated
if let activeContext = self.activeContexts[id] { if let activeContext = self.activeContexts[id] {
activeContext.disposable?.dispose() activeContext.disposable?.dispose()
@ -442,9 +446,7 @@ private final class FetchManagerCategoryContext {
activeContextsUpdated = true activeContextsUpdated = true
} }
if activeContextsUpdated { self.activeEntriesUpdated(self.entries.values.compactMap(FetchManagerEntrySummary.init).sorted(by: { $0.priority < $1.priority }))
self.activeEntriesUpdated()
}
} }
func withFetchStatusContext(_ id: FetchManagerLocationEntryId, _ f: (FetchManagerStatusContext) -> Void) { func withFetchStatusContext(_ id: FetchManagerLocationEntryId, _ f: (FetchManagerStatusContext) -> Void) {
@ -472,6 +474,25 @@ private final class FetchManagerCategoryContext {
} }
} }
public struct FetchManagerEntrySummary: Equatable {
public let id: FetchManagerLocationEntryId
public let mediaReference: AnyMediaReference?
public let resourceReference: MediaResourceReference
public let priority: FetchManagerPriorityKey
}
private extension FetchManagerEntrySummary {
init?(entry: FetchManagerLocationEntry) {
guard let priority = entry.priorityKey else {
return nil
}
self.id = entry.id
self.mediaReference = entry.mediaReference
self.resourceReference = entry.resourceReference
self.priority = priority
}
}
public final class FetchManagerImpl: FetchManager { public final class FetchManagerImpl: FetchManager {
public let queue = Queue.mainQueue() public let queue = Queue.mainQueue()
private let postbox: Postbox private let postbox: Postbox
@ -486,7 +507,12 @@ public final class FetchManagerImpl: FetchManager {
return self.hasUserInitiatedEntriesValue.get() return self.hasUserInitiatedEntriesValue.get()
} }
init(postbox: Postbox, storeManager: DownloadedMediaStoreManager?) { private let entriesSummaryValue = ValuePromise<[FetchManagerEntrySummary]>([], ignoreRepeated: true)
public var entriesSummary: Signal<[FetchManagerEntrySummary], NoError> {
return self.entriesSummaryValue.get()
}
public init(postbox: Postbox, storeManager: DownloadedMediaStoreManager?) {
self.postbox = postbox self.postbox = postbox
self.storeManager = storeManager self.storeManager = storeManager
} }
@ -519,7 +545,7 @@ public final class FetchManagerImpl: FetchManager {
context.cancelEntry(id, isCompleted: true) context.cancelEntry(id, isCompleted: true)
}) })
} }
}, activeEntriesUpdated: { [weak self] in }, activeEntriesUpdated: { [weak self] entries in
queue.async { queue.async {
guard let strongSelf = self else { guard let strongSelf = self else {
return return
@ -532,6 +558,8 @@ public final class FetchManagerImpl: FetchManager {
} }
} }
strongSelf.hasUserInitiatedEntriesValue.set(hasActiveUserInitiatedEntries) strongSelf.hasUserInitiatedEntriesValue.set(hasActiveUserInitiatedEntries)
strongSelf.entriesSummaryValue.set(entries)
} }
}) })
self.categoryContexts[key] = context self.categoryContexts[key] = context

View File

@ -97,3 +97,26 @@ public func messageFileMediaResourceStatus(context: AccountContext, file: Telegr
} }
} }
} }
public func messageImageMediaResourceStatus(context: AccountContext, image: TelegramMediaImage, message: Message, isRecentActions: Bool, isSharedMedia: Bool = false, isGlobalSearch: Bool = false) -> Signal<FileMediaResourceStatus, NoError> {
if message.flags.isSending {
return combineLatest(messageMediaImageStatus(context: context, messageId: message.id, image: image), context.account.pendingMessageManager.pendingMessageStatus(message.id) |> map { $0.0 })
|> map { resourceStatus, pendingStatus -> FileMediaResourceStatus in
let mediaStatus: FileMediaResourceMediaStatus
if let pendingStatus = pendingStatus {
mediaStatus = .fetchStatus(.Fetching(isActive: pendingStatus.isRunning, progress: pendingStatus.progress))
} else {
mediaStatus = .fetchStatus(resourceStatus)
}
return FileMediaResourceStatus(mediaStatus: mediaStatus, fetchStatus: resourceStatus)
}
} else {
return messageMediaImageStatus(context: context, messageId: message.id, image: image)
|> map { resourceStatus -> FileMediaResourceStatus in
let mediaStatus: FileMediaResourceMediaStatus
mediaStatus = .fetchStatus(resourceStatus)
return FileMediaResourceStatus(mediaStatus: mediaStatus, fetchStatus: resourceStatus)
}
}
}

View File

@ -92,7 +92,7 @@ final class ChatMediaGalleryThumbnailItem: GalleryThumbnailItem {
} }
case let .file(fileReference): case let .file(fileReference):
if let representation = smallestImageRepresentation(fileReference.media.previewRepresentations) { if let representation = smallestImageRepresentation(fileReference.media.previewRepresentations) {
return (chatWebpageSnippetFile(account: self.account, fileReference: fileReference, representation: representation), representation.dimensions.cgSize) return (chatWebpageSnippetFile(account: self.account, mediaReference: fileReference.abstract, representation: representation), representation.dimensions.cgSize)
} else { } else {
return (.single({ _ in return nil }), CGSize(width: 128.0, height: 128.0)) return (.single({ _ in return nil }), CGSize(width: 128.0, height: 128.0))
} }

View File

@ -95,30 +95,30 @@ private struct FetchControls {
} }
private enum FileIconImage: Equatable { private enum FileIconImage: Equatable {
case imageRepresentation(TelegramMediaFile, TelegramMediaImageRepresentation) case imageRepresentation(Media, TelegramMediaImageRepresentation)
case albumArt(TelegramMediaFile, SharedMediaPlaybackAlbumArt) case albumArt(TelegramMediaFile, SharedMediaPlaybackAlbumArt)
case roundVideo(TelegramMediaFile) case roundVideo(TelegramMediaFile)
static func ==(lhs: FileIconImage, rhs: FileIconImage) -> Bool { static func ==(lhs: FileIconImage, rhs: FileIconImage) -> Bool {
switch lhs { switch lhs {
case let .imageRepresentation(file, value): case let .imageRepresentation(lhsMedia, lhsValue):
if case .imageRepresentation(file, value) = rhs { if case let .imageRepresentation(rhsMedia, rhsValue) = rhs, lhsMedia.isEqual(to: rhsMedia), lhsValue == rhsValue {
return true return true
} else { } else {
return false return false
} }
case let .albumArt(file, value): case let .albumArt(file, value):
if case .albumArt(file, value) = rhs { if case .albumArt(file, value) = rhs {
return true return true
} else { } else {
return false return false
} }
case let .roundVideo(file): case let .roundVideo(file):
if case .roundVideo(file) = rhs { if case .roundVideo(file) = rhs {
return true return true
} else { } else {
return false return false
} }
} }
} }
} }
@ -155,6 +155,7 @@ public final class ListMessageFileItemNode: ListMessageNode {
private let offsetContainerNode: ASDisplayNode private let offsetContainerNode: ASDisplayNode
private var backgroundNode: ASDisplayNode?
private let highlightedBackgroundNode: ASDisplayNode private let highlightedBackgroundNode: ASDisplayNode
public let separatorNode: ASDisplayNode public let separatorNode: ASDisplayNode
@ -402,7 +403,7 @@ public final class ListMessageFileItemNode: ListMessageNode {
let message = item.message let message = item.message
var selectedMedia: TelegramMediaFile? var selectedMedia: Media?
for media in message.media { for media in message.media {
if let file = media as? TelegramMediaFile { if let file = media as? TelegramMediaFile {
selectedMedia = file selectedMedia = file
@ -539,6 +540,34 @@ public final class ListMessageFileItemNode: ListMessageNode {
} }
break break
} else if let image = media as? TelegramMediaImage {
selectedMedia = image
//TODO:localize
let fileName: String = "Photo"
titleText = NSAttributedString(string: fileName, font: titleFont, textColor: item.presentationData.theme.theme.list.itemPrimaryTextColor)
if let representation = smallestImageRepresentation(image.representations) {
iconImage = .imageRepresentation(image, representation)
}
let dateString = stringForFullDate(timestamp: item.message.timestamp, strings: item.presentationData.strings, dateTimeFormat: item.presentationData.dateTimeFormat)
var descriptionString: String = ""
if !item.isGlobalSearchResult {
descriptionString = "\(dateString)"
}
if item.isGlobalSearchResult {
let authorString = stringForFullAuthorName(message: EngineMessage(item.message), strings: item.presentationData.strings, nameDisplayOrder: item.presentationData.nameDisplayOrder, accountPeerId: item.context.account.peerId)
if descriptionString.isEmpty {
descriptionString = authorString
} else {
descriptionString = "\(descriptionString)\(authorString)"
}
}
descriptionText = NSAttributedString(string: descriptionString, font: descriptionFont, textColor: item.presentationData.theme.theme.list.itemSecondaryTextColor)
} }
} }
@ -570,38 +599,57 @@ public final class ListMessageFileItemNode: ListMessageNode {
let context = item.context let context = item.context
updatedFetchControls = FetchControls(fetch: { [weak self] in updatedFetchControls = FetchControls(fetch: { [weak self] in
if let strongSelf = self { if let strongSelf = self {
strongSelf.fetchDisposable.set(messageMediaFileInteractiveFetched(context: context, message: message, file: selectedMedia, userInitiated: true).start()) if let file = selectedMedia as? TelegramMediaFile {
strongSelf.fetchDisposable.set(messageMediaFileInteractiveFetched(context: context, message: message, file: file, userInitiated: true).start())
} else if let image = selectedMedia as? TelegramMediaImage, let representation = image.representations.last {
strongSelf.fetchDisposable.set(messageMediaImageInteractiveFetched(context: context, message: message, image: image, resource: representation.resource, userInitiated: true, storeToDownloadsPeerType: nil).start())
}
} }
}, cancel: { }, cancel: {
messageMediaFileCancelInteractiveFetch(context: context, messageId: message.id, file: selectedMedia) if let file = selectedMedia as? TelegramMediaFile {
messageMediaFileCancelInteractiveFetch(context: context, messageId: message.id, file: file)
} else if let image = selectedMedia as? TelegramMediaImage, let representation = image.representations.last {
messageMediaImageCancelInteractiveFetch(context: context, messageId: message.id, image: image, resource: representation.resource)
}
}) })
} }
if statusUpdated { if statusUpdated {
updatedStatusSignal = messageFileMediaResourceStatus(context: item.context, file: selectedMedia, message: message, isRecentActions: false, isSharedMedia: true, isGlobalSearch: item.isGlobalSearchResult) if let file = selectedMedia as? TelegramMediaFile {
|> mapToSignal { value -> Signal<FileMediaResourceStatus, NoError> in updatedStatusSignal = messageFileMediaResourceStatus(context: item.context, file: file, message: message, isRecentActions: false, isSharedMedia: true, isGlobalSearch: item.isGlobalSearchResult)
if case .Fetching = value.fetchStatus { |> mapToSignal { value -> Signal<FileMediaResourceStatus, NoError> in
return .single(value) |> delay(0.1, queue: Queue.concurrentDefaultQueue()) if case .Fetching = value.fetchStatus {
} else { return .single(value) |> delay(0.1, queue: Queue.concurrentDefaultQueue())
return .single(value) } else {
return .single(value)
}
} }
}
if isAudio || isInstantVideo {
if isAudio || isInstantVideo { if let currentUpdatedStatusSignal = updatedStatusSignal {
if let currentUpdatedStatusSignal = updatedStatusSignal { updatedStatusSignal = currentUpdatedStatusSignal
updatedStatusSignal = currentUpdatedStatusSignal |> map { status in
|> map { status in switch status.mediaStatus {
switch status.mediaStatus { case .fetchStatus:
case .fetchStatus: return FileMediaResourceStatus(mediaStatus: .fetchStatus(.Local), fetchStatus: status.fetchStatus)
return FileMediaResourceStatus(mediaStatus: .fetchStatus(.Local), fetchStatus: status.fetchStatus) case .playbackStatus:
case .playbackStatus: return status
return status }
} }
} }
} }
} if isVoice {
if isVoice { updatedPlaybackStatusSignal = messageFileMediaPlaybackStatus(context: item.context, file: file, message: message, isRecentActions: false, isGlobalSearch: item.isGlobalSearchResult)
updatedPlaybackStatusSignal = messageFileMediaPlaybackStatus(context: item.context, file: selectedMedia, message: message, isRecentActions: false, isGlobalSearch: item.isGlobalSearchResult) }
} else if let image = selectedMedia as? TelegramMediaImage {
updatedStatusSignal = messageImageMediaResourceStatus(context: item.context, image: image, message: message, isRecentActions: false, isSharedMedia: true, isGlobalSearch: item.isGlobalSearchResult)
|> mapToSignal { value -> Signal<FileMediaResourceStatus, NoError> in
if case .Fetching = value.fetchStatus {
return .single(value) |> delay(0.1, queue: Queue.concurrentDefaultQueue())
} else {
return .single(value)
}
}
} }
} }
} }
@ -684,8 +732,14 @@ public final class ListMessageFileItemNode: ListMessageNode {
if currentIconImage != iconImage { if currentIconImage != iconImage {
if let iconImage = iconImage { if let iconImage = iconImage {
switch iconImage { switch iconImage {
case let .imageRepresentation(file, representation): case let .imageRepresentation(media, representation):
updateIconImageSignal = chatWebpageSnippetFile(account: item.context.account, fileReference: .message(message: MessageReference(message), media: file), representation: representation) if let file = media as? TelegramMediaFile {
updateIconImageSignal = chatWebpageSnippetFile(account: item.context.account, mediaReference: FileMediaReference.message(message: MessageReference(message), media: file).abstract, representation: representation)
} else if let image = media as? TelegramMediaImage {
updateIconImageSignal = mediaGridMessagePhoto(account: item.context.account, photoReference: ImageMediaReference.message(message: MessageReference(message), media: image))
} else {
updateIconImageSignal = .complete()
}
case let .albumArt(file, albumArt): case let .albumArt(file, albumArt):
updateIconImageSignal = playerAlbumArt(postbox: item.context.account.postbox, engine: item.context.engine, fileReference: .message(message: MessageReference(message), media: file), albumArt: albumArt, thumbnail: true, overlayColor: UIColor(white: 0.0, alpha: 0.3), emptyColor: item.presentationData.theme.theme.list.itemAccentColor) updateIconImageSignal = playerAlbumArt(postbox: item.context.account.postbox, engine: item.context.engine, fileReference: .message(message: MessageReference(message), media: file), albumArt: albumArt, thumbnail: true, overlayColor: UIColor(white: 0.0, alpha: 0.3), emptyColor: item.presentationData.theme.theme.list.itemAccentColor)
case let .roundVideo(file): case let .roundVideo(file):
@ -746,6 +800,18 @@ public final class ListMessageFileItemNode: ListMessageNode {
strongSelf.currentLeftOffset = leftOffset strongSelf.currentLeftOffset = leftOffset
if let _ = updatedTheme { if let _ = updatedTheme {
if item.displayBackground {
let backgroundNode: ASDisplayNode
if let current = strongSelf.backgroundNode {
backgroundNode = current
} else {
backgroundNode = ASDisplayNode()
strongSelf.backgroundNode = backgroundNode
strongSelf.insertSubnode(backgroundNode, at: 0)
}
backgroundNode.backgroundColor = item.presentationData.theme.theme.list.itemBlocksBackgroundColor
}
strongSelf.separatorNode.backgroundColor = item.presentationData.theme.theme.list.itemPlainSeparatorColor strongSelf.separatorNode.backgroundColor = item.presentationData.theme.theme.list.itemPlainSeparatorColor
strongSelf.highlightedBackgroundNode.backgroundColor = item.presentationData.theme.theme.list.itemHighlightedBackgroundColor strongSelf.highlightedBackgroundNode.backgroundColor = item.presentationData.theme.theme.list.itemHighlightedBackgroundColor
strongSelf.linearProgressNode?.updateTheme(theme: item.presentationData.theme.theme) strongSelf.linearProgressNode?.updateTheme(theme: item.presentationData.theme.theme)
@ -778,6 +844,10 @@ public final class ListMessageFileItemNode: ListMessageNode {
transition.updateFrame(node: strongSelf.separatorNode, frame: CGRect(origin: CGPoint(x: leftInset + leftOffset, y: nodeLayout.contentSize.height - UIScreenPixel), size: CGSize(width: params.width - leftInset - leftOffset, height: UIScreenPixel))) transition.updateFrame(node: strongSelf.separatorNode, frame: CGRect(origin: CGPoint(x: leftInset + leftOffset, y: nodeLayout.contentSize.height - UIScreenPixel), size: CGSize(width: params.width - leftInset - leftOffset, height: UIScreenPixel)))
strongSelf.highlightedBackgroundNode.frame = CGRect(origin: CGPoint(x: 0.0, y: -UIScreenPixel - nodeLayout.insets.top), size: CGSize(width: params.width, height: nodeLayout.size.height + UIScreenPixel)) strongSelf.highlightedBackgroundNode.frame = CGRect(origin: CGPoint(x: 0.0, y: -UIScreenPixel - nodeLayout.insets.top), size: CGSize(width: params.width, height: nodeLayout.size.height + UIScreenPixel))
if let backgroundNode = strongSelf.backgroundNode {
backgroundNode.frame = CGRect(origin: CGPoint(x: 0.0, y: -nodeLayout.insets.top), size: CGSize(width: params.width, height: nodeLayout.size.height))
}
transition.updateFrame(node: strongSelf.titleNode, frame: CGRect(origin: CGPoint(x: leftOffset + leftInset, y: 9.0), size: titleNodeLayout.size)) transition.updateFrame(node: strongSelf.titleNode, frame: CGRect(origin: CGPoint(x: leftOffset + leftInset, y: 9.0), size: titleNodeLayout.size))
let _ = titleNodeApply() let _ = titleNodeApply()

View File

@ -51,12 +51,13 @@ public final class ListMessageItem: ListViewItem {
public let selection: ChatHistoryMessageSelection public let selection: ChatHistoryMessageSelection
let hintIsLink: Bool let hintIsLink: Bool
let isGlobalSearchResult: Bool let isGlobalSearchResult: Bool
let displayBackground: Bool
let header: ListViewItemHeader? let header: ListViewItemHeader?
public let selectable: Bool = true public let selectable: Bool = true
public init(presentationData: ChatPresentationData, context: AccountContext, chatLocation: ChatLocation, interaction: ListMessageItemInteraction, message: Message, selection: ChatHistoryMessageSelection, displayHeader: Bool, customHeader: ListViewItemHeader? = nil, hintIsLink: Bool = false, isGlobalSearchResult: Bool = false) { public init(presentationData: ChatPresentationData, context: AccountContext, chatLocation: ChatLocation, interaction: ListMessageItemInteraction, message: Message, selection: ChatHistoryMessageSelection, displayHeader: Bool, customHeader: ListViewItemHeader? = nil, hintIsLink: Bool = false, isGlobalSearchResult: Bool = false, displayBackground: Bool = false) {
self.presentationData = presentationData self.presentationData = presentationData
self.context = context self.context = context
self.chatLocation = chatLocation self.chatLocation = chatLocation
@ -72,6 +73,7 @@ public final class ListMessageItem: ListViewItem {
self.selection = selection self.selection = selection
self.hintIsLink = hintIsLink self.hintIsLink = hintIsLink
self.isGlobalSearchResult = isGlobalSearchResult self.isGlobalSearchResult = isGlobalSearchResult
self.displayBackground = displayBackground
} }
public func nodeConfiguredForParams(async: @escaping (@escaping () -> Void) -> Void, params: ListViewItemLayoutParams, synchronousLoads: Bool, previousItem: ListViewItem?, nextItem: ListViewItem?, completion: @escaping (ListViewItemNode, @escaping () -> (Signal<Void, NoError>?, (ListViewItemApply) -> Void)) -> Void) { public func nodeConfiguredForParams(async: @escaping (@escaping () -> Void) -> Void, params: ListViewItemLayoutParams, synchronousLoads: Bool, previousItem: ListViewItem?, nextItem: ListViewItem?, completion: @escaping (ListViewItemNode, @escaping () -> (Signal<Void, NoError>?, (ListViewItemApply) -> Void)) -> Void) {
@ -82,6 +84,9 @@ public final class ListMessageItem: ListViewItem {
if let _ = media as? TelegramMediaFile { if let _ = media as? TelegramMediaFile {
viewClassName = ListMessageFileItemNode.self viewClassName = ListMessageFileItemNode.self
break break
} else if let _ = media as? TelegramMediaImage {
viewClassName = ListMessageFileItemNode.self
break
} }
} }
} }

View File

@ -528,7 +528,7 @@ public final class ListMessageSnippetItemNode: ListMessageNode {
if let imageReference = iconImageReferenceAndRepresentation.0.concrete(TelegramMediaImage.self) { if let imageReference = iconImageReferenceAndRepresentation.0.concrete(TelegramMediaImage.self) {
updateIconImageSignal = chatWebpageSnippetPhoto(account: item.context.account, photoReference: imageReference) updateIconImageSignal = chatWebpageSnippetPhoto(account: item.context.account, photoReference: imageReference)
} else if let fileReference = iconImageReferenceAndRepresentation.0.concrete(TelegramMediaFile.self) { } else if let fileReference = iconImageReferenceAndRepresentation.0.concrete(TelegramMediaFile.self) {
updateIconImageSignal = chatWebpageSnippetFile(account: item.context.account, fileReference: fileReference, representation: iconImageReferenceAndRepresentation.1) updateIconImageSignal = chatWebpageSnippetFile(account: item.context.account, mediaReference: fileReference.abstract, representation: iconImageReferenceAndRepresentation.1)
} }
} else { } else {
updateIconImageSignal = .complete() updateIconImageSignal = .complete()

View File

@ -11,9 +11,10 @@ extern "C" {
bool MTLogEnabled(); bool MTLogEnabled();
void MTLog(NSString *format, ...); void MTLog(NSString *format, ...);
void MTLogWithPrefix(NSString *(^getLogPrefix)(), NSString *format, ...);
void MTShortLog(NSString *format, ...); void MTShortLog(NSString *format, ...);
void MTLogSetLoggingFunction(void (*function)(NSString *, va_list args)); void MTLogSetLoggingFunction(void (*function)(NSString *));
void MTLogSetShortLoggingFunction(void (*function)(NSString *, va_list args)); void MTLogSetShortLoggingFunction(void (*function)(NSString *));
void MTLogSetEnabled(bool); void MTLogSetEnabled(bool);
#ifdef __cplusplus #ifdef __cplusplus

View File

@ -53,6 +53,8 @@
@property (nonatomic) id requiredAuthToken; @property (nonatomic) id requiredAuthToken;
@property (nonatomic) NSInteger authTokenMasterDatacenterId; @property (nonatomic) NSInteger authTokenMasterDatacenterId;
@property (nonatomic, strong) NSString *(^getLogPrefix)();
- (instancetype)initWithContext:(MTContext *)context datacenterId:(NSInteger)datacenterId usageCalculationInfo:(MTNetworkUsageCalculationInfo *)usageCalculationInfo requiredAuthToken:(id)requiredAuthToken authTokenMasterDatacenterId:(NSInteger)authTokenMasterDatacenterId; - (instancetype)initWithContext:(MTContext *)context datacenterId:(NSInteger)datacenterId usageCalculationInfo:(MTNetworkUsageCalculationInfo *)usageCalculationInfo requiredAuthToken:(id)requiredAuthToken authTokenMasterDatacenterId:(NSInteger)authTokenMasterDatacenterId;
- (void)setUsageCalculationInfo:(MTNetworkUsageCalculationInfo *)usageCalculationInfo; - (void)setUsageCalculationInfo:(MTNetworkUsageCalculationInfo *)usageCalculationInfo;

View File

@ -43,8 +43,9 @@
@property (nonatomic, strong, readonly) MTSocksProxySettings * _Nullable proxySettings; @property (nonatomic, strong, readonly) MTSocksProxySettings * _Nullable proxySettings;
@property (nonatomic) bool simultaneousTransactionsEnabled; @property (nonatomic) bool simultaneousTransactionsEnabled;
@property (nonatomic) bool reportTransportConnectionContextUpdateStates; @property (nonatomic) bool reportTransportConnectionContextUpdateStates;
@property (nonatomic, strong) NSString * _Nullable (^ _Nullable getLogPrefix)();
- (instancetype _Nonnull)initWithDelegate:(id<MTTransportDelegate> _Nullable)delegate context:(MTContext * _Nonnull)context datacenterId:(NSInteger)datacenterId schemes:(NSArray<MTTransportScheme *> * _Nonnull)schemes proxySettings:(MTSocksProxySettings * _Null_unspecified)proxySettings usageCalculationInfo:(MTNetworkUsageCalculationInfo * _Nullable)usageCalculationInfo; - (instancetype _Nonnull)initWithDelegate:(id<MTTransportDelegate> _Nullable)delegate context:(MTContext * _Nonnull)context datacenterId:(NSInteger)datacenterId schemes:(NSArray<MTTransportScheme *> * _Nonnull)schemes proxySettings:(MTSocksProxySettings * _Null_unspecified)proxySettings usageCalculationInfo:(MTNetworkUsageCalculationInfo * _Nullable)usageCalculationInfo getLogPrefix:(NSString * _Nullable (^ _Nullable)())getLogPrefix;
- (void)setUsageCalculationInfo:(MTNetworkUsageCalculationInfo * _Null_unspecified)usageCalculationInfo; - (void)setUsageCalculationInfo:(MTNetworkUsageCalculationInfo * _Null_unspecified)usageCalculationInfo;

View File

@ -151,6 +151,8 @@ typedef enum GCDAsyncSocketError GCDAsyncSocketError;
@property (nonatomic) bool useTcpNodelay; @property (nonatomic) bool useTcpNodelay;
@property (nonatomic, strong) MTNetworkUsageCalculationInfo *usageCalculationInfo; @property (nonatomic, strong) MTNetworkUsageCalculationInfo *usageCalculationInfo;
@property (nonatomic, strong) NSString *(^getLogPrefix)();
/** /**
* GCDAsyncSocket uses the standard delegate paradigm, * GCDAsyncSocket uses the standard delegate paradigm,
* but executes all delegate callbacks on a given delegate dispatch queue. * but executes all delegate callbacks on a given delegate dispatch queue.

View File

@ -2468,7 +2468,7 @@ enum GCDAsyncSocketConfig
freeifaddrs(ifaddr); freeifaddrs(ifaddr);
if (MTLogEnabled()) { if (MTLogEnabled()) {
MTLog(@"Connection time: %f ms, interface: %@", (CFAbsoluteTimeGetCurrent() - startTime) * 1000.0f, isWifi ? @"Wifi" : @"WAN"); MTLogWithPrefix(_getLogPrefix, @"Connection time: %f ms, interface: %@", (CFAbsoluteTimeGetCurrent() - startTime) * 1000.0f, isWifi ? @"Wifi" : @"WAN");
} }
dispatch_async(socketQueue, ^{ @autoreleasepool { dispatch_async(socketQueue, ^{ @autoreleasepool {

View File

@ -95,7 +95,7 @@
MTPayloadData payloadData; MTPayloadData payloadData;
NSData *data = [self payloadData:&payloadData context:context address:address]; NSData *data = [self payloadData:&payloadData context:context address:address];
MTTcpConnection *connection = [[MTTcpConnection alloc] initWithContext:context datacenterId:datacenterId scheme:[[MTTransportScheme alloc] initWithTransportClass:[MTTcpTransport class] address:address media:false] interface:nil usageCalculationInfo:nil]; MTTcpConnection *connection = [[MTTcpConnection alloc] initWithContext:context datacenterId:datacenterId scheme:[[MTTransportScheme alloc] initWithTransportClass:[MTTcpTransport class] address:address media:false] interface:nil usageCalculationInfo:nil getLogPrefix:nil];
__weak MTTcpConnection *weakConnection = connection; __weak MTTcpConnection *weakConnection = connection;
connection.connectionOpened = ^ connection.connectionOpened = ^
{ {

View File

@ -1,7 +1,7 @@
#import <MtProtoKit/MTLogging.h> #import <MtProtoKit/MTLogging.h>
static void (*loggingFunction)(NSString *, va_list args) = NULL; static void (*loggingFunction)(NSString *) = NULL;
static void (*shortLoggingFunction)(NSString *, va_list args) = NULL; static void (*shortLoggingFunction)(NSString *) = NULL;
static bool MTLogEnabledValue = true; static bool MTLogEnabledValue = true;
bool MTLogEnabled() { bool MTLogEnabled() {
@ -12,7 +12,24 @@ void MTLog(NSString *format, ...) {
va_list L; va_list L;
va_start(L, format); va_start(L, format);
if (loggingFunction != NULL) { if (loggingFunction != NULL) {
loggingFunction(format, L); NSString *string = [[NSString alloc] initWithFormat:format arguments:L];
loggingFunction(string);
}
va_end(L);
}
void MTLogWithPrefix(NSString *(^getLogPrefix)(), NSString *format, ...) {
va_list L;
va_start(L, format);
if (loggingFunction != NULL) {
NSString *string = [[NSString alloc] initWithFormat:format arguments:L];
if (getLogPrefix) {
NSString *prefix = getLogPrefix();
if (prefix) {
string = [prefix stringByAppendingString:string];
}
}
loggingFunction(string);
} }
va_end(L); va_end(L);
} }
@ -21,16 +38,17 @@ void MTShortLog(NSString *format, ...) {
va_list L; va_list L;
va_start(L, format); va_start(L, format);
if (shortLoggingFunction != NULL) { if (shortLoggingFunction != NULL) {
shortLoggingFunction(format, L); NSString *string = [[NSString alloc] initWithFormat:format arguments:L];
shortLoggingFunction(string);
} }
va_end(L); va_end(L);
} }
void MTLogSetLoggingFunction(void (*function)(NSString *, va_list args)) { void MTLogSetLoggingFunction(void (*function)(NSString *)) {
loggingFunction = function; loggingFunction = function;
} }
void MTLogSetShortLoggingFunction(void (*function)(NSString *, va_list args)) { void MTLogSetShortLoggingFunction(void (*function)(NSString *)) {
shortLoggingFunction = function; shortLoggingFunction = function;
} }

View File

@ -201,7 +201,7 @@ static const NSUInteger MTMaxUnacknowledgedMessageCount = 64;
if ((_mtState & MTProtoStatePaused) == 0) if ((_mtState & MTProtoStatePaused) == 0)
{ {
if (MTLogEnabled()) { if (MTLogEnabled()) {
MTLog(@"[MTProto#%p@%p pause]", self, _context); MTLogWithPrefix(_getLogPrefix, @"[MTProto#%p@%p pause]", self, _context);
} }
MTShortLog(@"[MTProto#%p@%p pause]", self, _context); MTShortLog(@"[MTProto#%p@%p pause]", self, _context);
@ -220,7 +220,7 @@ static const NSUInteger MTMaxUnacknowledgedMessageCount = 64;
if (_mtState & MTProtoStatePaused) if (_mtState & MTProtoStatePaused)
{ {
if (MTLogEnabled()) { if (MTLogEnabled()) {
MTLog(@"[MTProto#%p@%p resume]", self, _context); MTLogWithPrefix(_getLogPrefix, @"[MTProto#%p@%p resume]", self, _context);
} }
MTShortLog(@"[MTProto#%p@%p resume]", self, _context); MTShortLog(@"[MTProto#%p@%p resume]", self, _context);
@ -274,7 +274,7 @@ static const NSUInteger MTMaxUnacknowledgedMessageCount = 64;
[[MTProto managerQueue] dispatchOnQueue:^ [[MTProto managerQueue] dispatchOnQueue:^
{ {
if (MTLogEnabled()) { if (MTLogEnabled()) {
MTLog(@"[MTProto#%p@%p changing transport %@#%p to %@#%p]", self, _context, [_transport class] == nil ? @"" : NSStringFromClass([_transport class]), _transport, [transport class] == nil ? @"" : NSStringFromClass([transport class]), transport); MTLogWithPrefix(_getLogPrefix, @"[MTProto#%p@%p changing transport %@#%p to %@#%p]", self, _context, [_transport class] == nil ? @"" : NSStringFromClass([_transport class]), _transport, [transport class] == nil ? @"" : NSStringFromClass([transport class]), transport);
} }
[self allTransactionsMayHaveFailed]; [self allTransactionsMayHaveFailed];
@ -331,7 +331,7 @@ static const NSUInteger MTMaxUnacknowledgedMessageCount = 64;
} }
} else { } else {
assert(transportSchemes.count != 0); assert(transportSchemes.count != 0);
MTTransport *transport = [[MTTcpTransport alloc] initWithDelegate:self context:_context datacenterId:_datacenterId schemes:transportSchemes proxySettings:_context.apiEnvironment.socksProxySettings usageCalculationInfo:_usageCalculationInfo]; MTTransport *transport = [[MTTcpTransport alloc] initWithDelegate:self context:_context datacenterId:_datacenterId schemes:transportSchemes proxySettings:_context.apiEnvironment.socksProxySettings usageCalculationInfo:_usageCalculationInfo getLogPrefix:_getLogPrefix];
[self setTransport:transport]; [self setTransport:transport];
} }
@ -343,7 +343,7 @@ static const NSUInteger MTMaxUnacknowledgedMessageCount = 64;
[[MTProto managerQueue] dispatchOnQueue:^ [[MTProto managerQueue] dispatchOnQueue:^
{ {
if (MTLogEnabled()) { if (MTLogEnabled()) {
MTLog(@"[MTProto#%p@%p resetting session]", self, _context); MTLogWithPrefix(_getLogPrefix, @"[MTProto#%p@%p resetting session]", self, _context);
} }
MTShortLog(@"[MTProto#%p@%p resetting session]", self, _context); MTShortLog(@"[MTProto#%p@%p resetting session]", self, _context);
@ -383,9 +383,9 @@ static const NSUInteger MTMaxUnacknowledgedMessageCount = 64;
if (!alreadySyncing) if (!alreadySyncing)
{ {
if (MTLogEnabled()) { if (MTLogEnabled()) {
MTLog(@"[MTProto#%p@%p begin time sync]", self, _context); MTLogWithPrefix(_getLogPrefix, @"[MTProto#%p@%p begin time sync]", self, _context);
} }
MTShortLog(@"[MTProto#%p@%p begin time sync]", self, _context); MTLogWithPrefix(_getLogPrefix, @"[MTProto#%p@%p begin time sync]", self, _context);
MTTimeSyncMessageService *timeSyncService = [[MTTimeSyncMessageService alloc] init]; MTTimeSyncMessageService *timeSyncService = [[MTTimeSyncMessageService alloc] init];
timeSyncService.delegate = self; timeSyncService.delegate = self;
@ -416,7 +416,7 @@ static const NSUInteger MTMaxUnacknowledgedMessageCount = 64;
} }
if (MTLogEnabled()) { if (MTLogEnabled()) {
MTLog(@"[MTProto#%p@%p service tasks state: %d, resend: %s]", self, _context, _mtState, haveResendMessagesPending ? "yes" : "no"); MTLogWithPrefix(_getLogPrefix, @"[MTProto#%p@%p service tasks state: %d, resend: %s]", self, _context, _mtState, haveResendMessagesPending ? "yes" : "no");
} }
MTShortLog(@"[MTProto#%p@%p service tasks state: %d, resend: %s]", self, _context, _mtState, haveResendMessagesPending ? "yes" : "no"); MTShortLog(@"[MTProto#%p@%p service tasks state: %d, resend: %s]", self, _context, _mtState, haveResendMessagesPending ? "yes" : "no");
@ -467,7 +467,7 @@ static const NSUInteger MTMaxUnacknowledgedMessageCount = 64;
if (notifyAboutServiceTask) if (notifyAboutServiceTask)
{ {
if (MTLogEnabled()) { if (MTLogEnabled()) {
MTLog(@"[MTProto#%p@%p service tasks state: %d, resend: %s]", self, _context, _mtState, "yes"); MTLogWithPrefix(_getLogPrefix, @"[MTProto#%p@%p service tasks state: %d, resend: %s]", self, _context, _mtState, "yes");
} }
MTShortLog(@"[MTProto#%p@%p service tasks state: %d, resend: %s]", self, _context, _mtState, "yes"); MTShortLog(@"[MTProto#%p@%p service tasks state: %d, resend: %s]", self, _context, _mtState, "yes");
@ -520,7 +520,7 @@ static const NSUInteger MTMaxUnacknowledgedMessageCount = 64;
if (!performingServiceTasks) if (!performingServiceTasks)
{ {
if (MTLogEnabled()) { if (MTLogEnabled()) {
MTLog(@"[MTProto#%p@%p service tasks state: %d, resend: %s]", self, _context, _mtState, "no"); MTLogWithPrefix(_getLogPrefix, @"[MTProto#%p@%p service tasks state: %d, resend: %s]", self, _context, _mtState, "no");
} }
MTShortLog(@"[MTProto#%p@%p service tasks state: %d, resend: %s]", self, _context, _mtState, "no"); MTShortLog(@"[MTProto#%p@%p service tasks state: %d, resend: %s]", self, _context, _mtState, "no");
@ -682,7 +682,7 @@ static const NSUInteger MTMaxUnacknowledgedMessageCount = 64;
return; return;
if (MTLogEnabled()) { if (MTLogEnabled()) {
MTLog(@"[MTProto#%p@%p network state: %s]", self, _context, isNetworkAvailable ? "available" : "waiting"); MTLogWithPrefix(_getLogPrefix, @"[MTProto#%p@%p network state: %s]", self, _context, isNetworkAvailable ? "available" : "waiting");
} }
for (id<MTMessageService> messageService in _messageServices) for (id<MTMessageService> messageService in _messageServices)
@ -713,7 +713,7 @@ static const NSUInteger MTMaxUnacknowledgedMessageCount = 64;
return; return;
if (MTLogEnabled()) { if (MTLogEnabled()) {
MTLog(@"[MTProto#%p@%p transport #%p connection state: %s]", self, _context, transport, isConnected ? "connected" : "connecting"); MTLogWithPrefix(_getLogPrefix, @"[MTProto#%p@%p transport #%p connection state: %s]", self, _context, transport, isConnected ? "connected" : "connecting");
} }
for (id<MTMessageService> messageService in _messageServices) for (id<MTMessageService> messageService in _messageServices)
@ -740,7 +740,7 @@ static const NSUInteger MTMaxUnacknowledgedMessageCount = 64;
return; return;
if (MTLogEnabled()) { if (MTLogEnabled()) {
MTLog(@"[MTProto#%p@%p connection context update state: %s]", self, _context, isUpdatingConnectionContext ? "updating" : "up to date"); MTLogWithPrefix(_getLogPrefix, @"[MTProto#%p@%p connection context update state: %s]", self, _context, isUpdatingConnectionContext ? "updating" : "up to date");
} }
for (id<MTMessageService> messageService in _messageServices) for (id<MTMessageService> messageService in _messageServices)
@ -1048,7 +1048,7 @@ static const NSUInteger MTMaxUnacknowledgedMessageCount = 64;
if (MTLogEnabled()) { if (MTLogEnabled()) {
NSString *messageDescription = [self outgoingMessageDescription:outgoingMessage messageId:messageId messageSeqNo:messageSeqNo]; NSString *messageDescription = [self outgoingMessageDescription:outgoingMessage messageId:messageId messageSeqNo:messageSeqNo];
MTLog(@"[MTProto#%p@%p preparing %@]", self, _context, messageDescription); MTLogWithPrefix(_getLogPrefix, @"[MTProto#%p@%p preparing %@]", self, _context, messageDescription);
} }
NSString *shortMessageDescription = [self outgoingShortMessageDescription:outgoingMessage messageId:messageId messageSeqNo:messageSeqNo]; NSString *shortMessageDescription = [self outgoingShortMessageDescription:outgoingMessage messageId:messageId messageSeqNo:messageSeqNo];
MTShortLog(@"[MTProto#%p@%p preparing %@]", self, _context, shortMessageDescription); MTShortLog(@"[MTProto#%p@%p preparing %@]", self, _context, shortMessageDescription);
@ -1094,7 +1094,7 @@ static const NSUInteger MTMaxUnacknowledgedMessageCount = 64;
if (monotonityViolated) if (monotonityViolated)
{ {
if (MTLogEnabled()) { if (MTLogEnabled()) {
MTLog(@"[MTProto#%p@%p client message id monotonity violated]", self, _context); MTLogWithPrefix(_getLogPrefix, @"[MTProto#%p@%p client message id monotonity violated]", self, _context);
} }
MTShortLog(@"[MTProto#%p@%p client message id monotonity violated]", self, _context); MTShortLog(@"[MTProto#%p@%p client message id monotonity violated]", self, _context);
@ -1283,7 +1283,7 @@ static const NSUInteger MTMaxUnacknowledgedMessageCount = 64;
} }
if (MTLogEnabled()) { if (MTLogEnabled()) {
MTLog(@"[MTProto#%p@%p transport did not accept transactions with messages (%@)]", self, _context, idsString); MTLogWithPrefix(_getLogPrefix, @"[MTProto#%p@%p transport did not accept transactions with messages (%@)]", self, _context, idsString);
} }
} }
}]; }];
@ -1339,7 +1339,7 @@ static const NSUInteger MTMaxUnacknowledgedMessageCount = 64;
MTOutputStream *decryptedOs = [[MTOutputStream alloc] init]; MTOutputStream *decryptedOs = [[MTOutputStream alloc] init];
if (MTLogEnabled()) { if (MTLogEnabled()) {
MTLog(@"[MTProto#%p@%p sending time fix ping (%" PRId64 "/%" PRId32 ", %" PRId64 ")]", self, _context, timeFixMessageId, timeFixSeqNo, _sessionInfo.sessionId); MTLogWithPrefix(_getLogPrefix, @"[MTProto#%p@%p sending time fix ping (%" PRId64 "/%" PRId32 ", %" PRId64 ")]", self, _context, timeFixMessageId, timeFixSeqNo, _sessionInfo.sessionId);
} }
MTShortLog(@"[MTProto#%p@%p sending time fix ping (%" PRId64 "/%" PRId32 ", %" PRId64 ")]", self, _context, timeFixMessageId, timeFixSeqNo, _sessionInfo.sessionId); MTShortLog(@"[MTProto#%p@%p sending time fix ping (%" PRId64 "/%" PRId32 ", %" PRId64 ")]", self, _context, timeFixMessageId, timeFixSeqNo, _sessionInfo.sessionId);
@ -1455,7 +1455,7 @@ static const NSUInteger MTMaxUnacknowledgedMessageCount = 64;
[idsString appendFormat:@"%lld", [nMessageId longLongValue]]; [idsString appendFormat:@"%lld", [nMessageId longLongValue]];
} }
if (MTLogEnabled()) { if (MTLogEnabled()) {
MTLog(@" container (%" PRId64 ") of (%@), in %" PRId64 "", containerMessageId, idsString, sessionInfo.sessionId); MTLogWithPrefix(_getLogPrefix, @" container (%" PRId64 ") of (%@), in %" PRId64 "", containerMessageId, idsString, sessionInfo.sessionId);
} }
MTShortLog(@" container (%" PRId64 ") of (%@), in %" PRId64 "", containerMessageId, idsString, sessionInfo.sessionId); MTShortLog(@" container (%" PRId64 ") of (%@), in %" PRId64 "", containerMessageId, idsString, sessionInfo.sessionId);
} }
@ -1931,7 +1931,7 @@ static NSString *dumpHexString(NSData *data, int maxLength) {
[data getBytes:&protocolErrorCode range:NSMakeRange(0, 4)]; [data getBytes:&protocolErrorCode range:NSMakeRange(0, 4)];
if (MTLogEnabled()) { if (MTLogEnabled()) {
MTLog(@"[MTProto#%p@%p protocol error %" PRId32 "", self, _context, protocolErrorCode); MTLogWithPrefix(_getLogPrefix, @"[MTProto#%p@%p protocol error %" PRId32 "", self, _context, protocolErrorCode);
} }
MTShortLog(@"[MTProto#%p@%p protocol error %" PRId32 "", self, _context, protocolErrorCode); MTShortLog(@"[MTProto#%p@%p protocol error %" PRId32 "", self, _context, protocolErrorCode);
@ -1991,7 +1991,7 @@ static NSString *dumpHexString(NSData *data, int maxLength) {
MTRpcError *rpcError = maybeInternalMessage; MTRpcError *rpcError = maybeInternalMessage;
if (rpcError.errorCode == 401 && [rpcError.errorDescription isEqualToString:@"AUTH_KEY_PERM_EMPTY"]) { if (rpcError.errorCode == 401 && [rpcError.errorDescription isEqualToString:@"AUTH_KEY_PERM_EMPTY"]) {
if (MTLogEnabled()) { if (MTLogEnabled()) {
MTLog(@"[MTProto#%p@%p received AUTH_KEY_PERM_EMPTY]", self, _context); MTLogWithPrefix(_getLogPrefix, @"[MTProto#%p@%p received AUTH_KEY_PERM_EMPTY]", self, _context);
} }
MTShortLog(@"[MTProto#%p@%p received AUTH_KEY_PERM_EMPTY]", self, _context); MTShortLog(@"[MTProto#%p@%p received AUTH_KEY_PERM_EMPTY]", self, _context);
[self handleMissingKey:scheme]; [self handleMissingKey:scheme];
@ -2004,7 +2004,7 @@ static NSString *dumpHexString(NSData *data, int maxLength) {
} }
if (parseError) { if (parseError) {
if (MTLogEnabled()) { if (MTLogEnabled()) {
MTLog(@"[MTProto#%p@%p incoming data parse error, header: %d:%@]", self, _context, (int)decryptedData.length, dumpHexString(decryptedData, 128)); MTLogWithPrefix(_getLogPrefix, @"[MTProto#%p@%p incoming data parse error, header: %d:%@]", self, _context, (int)decryptedData.length, dumpHexString(decryptedData, 128));
} }
MTShortLog(@"[MTProto#%p@%p incoming data parse error, header: %d:%@]", self, _context, (int)decryptedData.length, dumpHexString(decryptedData, 128)); MTShortLog(@"[MTProto#%p@%p incoming data parse error, header: %d:%@]", self, _context, (int)decryptedData.length, dumpHexString(decryptedData, 128));
@ -2026,7 +2026,7 @@ static NSString *dumpHexString(NSData *data, int maxLength) {
} }
} else { } else {
if (MTLogEnabled()) { if (MTLogEnabled()) {
MTLog(@"[MTProto#%p@%p couldn't decrypt incoming data]", self, _context); MTLogWithPrefix(_getLogPrefix, @"[MTProto#%p@%p couldn't decrypt incoming data]", self, _context);
} }
MTShortLog(@"[MTProto#%p@%p couldn't decrypt incoming data]", self, _context); MTShortLog(@"[MTProto#%p@%p couldn't decrypt incoming data]", self, _context);
@ -2046,7 +2046,7 @@ static NSString *dumpHexString(NSData *data, int maxLength) {
if (_useUnauthorizedMode) { if (_useUnauthorizedMode) {
if (MTLogEnabled()) { if (MTLogEnabled()) {
MTLog(@"[MTProto#%p@%p don't handleMissingKey when useUnauthorizedMode]", self, _context); MTLogWithPrefix(_getLogPrefix, @"[MTProto#%p@%p don't handleMissingKey when useUnauthorizedMode]", self, _context);
} }
return; return;
} }
@ -2055,7 +2055,7 @@ static NSString *dumpHexString(NSData *data, int maxLength) {
[self getAuthKeyForCurrentScheme:scheme createIfNeeded:false authInfoSelector:&authInfoSelector]; [self getAuthKeyForCurrentScheme:scheme createIfNeeded:false authInfoSelector:&authInfoSelector];
if (MTLogEnabled()) { if (MTLogEnabled()) {
MTLog(@"[MTProto#%p@%p missing key %lld selector %d useExplicitAuthKey: %lld, canResetAuthData: %s]", self, _context, _validAuthInfo.authInfo.authKeyId, authInfoSelector, _useExplicitAuthKey.authKeyId, _canResetAuthData ? "true" : "false"); MTLogWithPrefix(_getLogPrefix, @"[MTProto#%p@%p missing key %lld selector %d useExplicitAuthKey: %lld, canResetAuthData: %s]", self, _context, _validAuthInfo.authInfo.authKeyId, authInfoSelector, _useExplicitAuthKey.authKeyId, _canResetAuthData ? "true" : "false");
} }
if (_useExplicitAuthKey != nil) { if (_useExplicitAuthKey != nil) {
@ -2346,7 +2346,7 @@ static bool isDataEqualToDataConstTime(NSData *data1, NSData *data2) {
if ([_sessionInfo messageProcessed:incomingMessage.messageId]) if ([_sessionInfo messageProcessed:incomingMessage.messageId])
{ {
if (MTLogEnabled()) { if (MTLogEnabled()) {
MTLog(@"[MTProto#%p@%p received duplicate message %" PRId64 "]", self, _context, incomingMessage.messageId); MTLogWithPrefix(_getLogPrefix, @"[MTProto#%p@%p received duplicate message %" PRId64 "]", self, _context, incomingMessage.messageId);
} }
MTShortLog(@"[MTProto#%p@%p received duplicate message %" PRId64 "]", self, _context, incomingMessage.messageId); MTShortLog(@"[MTProto#%p@%p received duplicate message %" PRId64 "]", self, _context, incomingMessage.messageId);
[_sessionInfo scheduleMessageConfirmation:incomingMessage.messageId size:incomingMessage.size]; [_sessionInfo scheduleMessageConfirmation:incomingMessage.messageId size:incomingMessage.size];
@ -2358,7 +2358,7 @@ static bool isDataEqualToDataConstTime(NSData *data1, NSData *data2) {
} }
if (MTLogEnabled()) { if (MTLogEnabled()) {
MTLog(@"[MTProto#%p@%p [%d] received %@]", self, _context, totalSize, [self incomingMessageDescription:incomingMessage]); MTLogWithPrefix(_getLogPrefix, @"[MTProto#%p@%p [%d] received %@]", self, _context, totalSize, [self incomingMessageDescription:incomingMessage]);
} }
[_sessionInfo setMessageProcessed:incomingMessage.messageId]; [_sessionInfo setMessageProcessed:incomingMessage.messageId];
@ -2473,7 +2473,7 @@ static bool isDataEqualToDataConstTime(NSData *data1, NSData *data2) {
int64_t requestMessageId = ((MTMsgDetailedResponseInfoMessage *)detailedInfoMessage).requestMessageId; int64_t requestMessageId = ((MTMsgDetailedResponseInfoMessage *)detailedInfoMessage).requestMessageId;
if (MTLogEnabled()) { if (MTLogEnabled()) {
MTLog(@"[MTProto#%p@%p detailed info %" PRId64 " is for %" PRId64 "", self, _context, incomingMessage.messageId, requestMessageId); MTLogWithPrefix(_getLogPrefix, @"[MTProto#%p@%p detailed info %" PRId64 " is for %" PRId64 "", self, _context, incomingMessage.messageId, requestMessageId);
} }
MTShortLog(@"[MTProto#%p@%p detailed info %" PRId64 " is for %" PRId64 "", self, _context, incomingMessage.messageId, requestMessageId); MTShortLog(@"[MTProto#%p@%p detailed info %" PRId64 " is for %" PRId64 "", self, _context, incomingMessage.messageId, requestMessageId);
@ -2496,7 +2496,7 @@ static bool isDataEqualToDataConstTime(NSData *data1, NSData *data2) {
{ {
[self requestMessageWithId:detailedInfoMessage.responseMessageId]; [self requestMessageWithId:detailedInfoMessage.responseMessageId];
if (MTLogEnabled()) { if (MTLogEnabled()) {
MTLog(@"[MTProto#%p@%p will request message %" PRId64 "", self, _context, detailedInfoMessage.responseMessageId); MTLogWithPrefix(_getLogPrefix, @"[MTProto#%p@%p will request message %" PRId64 "", self, _context, detailedInfoMessage.responseMessageId);
} }
MTShortLog(@"[MTProto#%p@%p will request message %" PRId64 "", self, _context, detailedInfoMessage.responseMessageId); MTShortLog(@"[MTProto#%p@%p will request message %" PRId64 "", self, _context, detailedInfoMessage.responseMessageId);
} }

View File

@ -66,7 +66,7 @@
MTContext *proxyContext = [[MTContext alloc] initWithSerialization:context.serialization encryptionProvider:context.encryptionProvider apiEnvironment:[[context apiEnvironment] withUpdatedSocksProxySettings:settings] isTestingEnvironment:context.isTestingEnvironment useTempAuthKeys:false]; MTContext *proxyContext = [[MTContext alloc] initWithSerialization:context.serialization encryptionProvider:context.encryptionProvider apiEnvironment:[[context apiEnvironment] withUpdatedSocksProxySettings:settings] isTestingEnvironment:context.isTestingEnvironment useTempAuthKeys:false];
MTTcpConnection *connection = [[MTTcpConnection alloc] initWithContext:proxyContext datacenterId:datacenterId scheme:[[MTTransportScheme alloc] initWithTransportClass:[MTTcpConnection class] address:address media:false] interface:nil usageCalculationInfo:nil]; MTTcpConnection *connection = [[MTTcpConnection alloc] initWithContext:proxyContext datacenterId:datacenterId scheme:[[MTTransportScheme alloc] initWithTransportClass:[MTTcpConnection class] address:address media:false] interface:nil usageCalculationInfo:nil getLogPrefix:nil];
__weak MTTcpConnection *weakConnection = connection; __weak MTTcpConnection *weakConnection = connection;
__block NSTimeInterval startTime = CFAbsoluteTimeGetCurrent(); __block NSTimeInterval startTime = CFAbsoluteTimeGetCurrent();
connection.connectionOpened = ^ { connection.connectionOpened = ^ {

View File

@ -32,9 +32,11 @@
@property (nonatomic, strong, readonly) MTTransportScheme *scheme; @property (nonatomic, strong, readonly) MTTransportScheme *scheme;
@property (nonatomic, strong, readonly) NSString *interface; @property (nonatomic, strong, readonly) NSString *interface;
@property (nonatomic, strong) NSString *(^getLogPrefix)();
+ (MTQueue *)tcpQueue; + (MTQueue *)tcpQueue;
- (instancetype)initWithContext:(MTContext *)context datacenterId:(NSInteger)datacenterId scheme:(MTTransportScheme *)scheme interface:(NSString *)interface usageCalculationInfo:(MTNetworkUsageCalculationInfo *)usageCalculationInfo; - (instancetype)initWithContext:(MTContext *)context datacenterId:(NSInteger)datacenterId scheme:(MTTransportScheme *)scheme interface:(NSString *)interface usageCalculationInfo:(MTNetworkUsageCalculationInfo *)usageCalculationInfo getLogPrefix:(NSString *(^)())getLogPrefix;
- (void)setUsageCalculationInfo:(MTNetworkUsageCalculationInfo *)usageCalculationInfo; - (void)setUsageCalculationInfo:(MTNetworkUsageCalculationInfo *)usageCalculationInfo;

View File

@ -689,7 +689,7 @@ struct ctr_state {
return queue; return queue;
} }
- (instancetype)initWithContext:(MTContext *)context datacenterId:(NSInteger)datacenterId scheme:(MTTransportScheme *)scheme interface:(NSString *)interface usageCalculationInfo:(MTNetworkUsageCalculationInfo *)usageCalculationInfo - (instancetype)initWithContext:(MTContext *)context datacenterId:(NSInteger)datacenterId scheme:(MTTransportScheme *)scheme interface:(NSString *)interface usageCalculationInfo:(MTNetworkUsageCalculationInfo *)usageCalculationInfo getLogPrefix:(NSString *(^)())getLogPrefix
{ {
#ifdef DEBUG #ifdef DEBUG
NSAssert(scheme != nil, @"scheme should not be nil"); NSAssert(scheme != nil, @"scheme should not be nil");
@ -700,6 +700,8 @@ struct ctr_state {
{ {
_internalId = [[MTInternalId(MTTcpConnection) alloc] init]; _internalId = [[MTInternalId(MTTcpConnection) alloc] init];
_getLogPrefix = [getLogPrefix copy];
_encryptionProvider = context.encryptionProvider; _encryptionProvider = context.encryptionProvider;
_scheme = scheme; _scheme = scheme;
@ -799,6 +801,7 @@ struct ctr_state {
if (_socket == nil) if (_socket == nil)
{ {
_socket = [[GCDAsyncSocket alloc] initWithDelegate:self delegateQueue:[[MTTcpConnection tcpQueue] nativeQueue]]; _socket = [[GCDAsyncSocket alloc] initWithDelegate:self delegateQueue:[[MTTcpConnection tcpQueue] nativeQueue]];
_socket.getLogPrefix = _getLogPrefix;
_socket.usageCalculationInfo = _usageCalculationInfo; _socket.usageCalculationInfo = _usageCalculationInfo;
NSString *addressIp = _scheme.address.ip; NSString *addressIp = _scheme.address.ip;

View File

@ -82,7 +82,7 @@ static const NSTimeInterval MTTcpTransportSleepWatchdogTimeout = 60.0;
return queue; return queue;
} }
- (instancetype)initWithDelegate:(id<MTTransportDelegate>)delegate context:(MTContext *)context datacenterId:(NSInteger)datacenterId schemes:(NSArray<MTTransportScheme *> * _Nonnull)schemes proxySettings:(MTSocksProxySettings *)proxySettings usageCalculationInfo:(MTNetworkUsageCalculationInfo *)usageCalculationInfo - (instancetype)initWithDelegate:(id<MTTransportDelegate>)delegate context:(MTContext *)context datacenterId:(NSInteger)datacenterId schemes:(NSArray<MTTransportScheme *> * _Nonnull)schemes proxySettings:(MTSocksProxySettings *)proxySettings usageCalculationInfo:(MTNetworkUsageCalculationInfo *)usageCalculationInfo getLogPrefix:(NSString *(^)())getLogPrefix
{ {
#ifdef DEBUG #ifdef DEBUG
NSAssert(context != nil, @"context should not be nil"); NSAssert(context != nil, @"context should not be nil");
@ -90,7 +90,7 @@ static const NSTimeInterval MTTcpTransportSleepWatchdogTimeout = 60.0;
NSAssert(schemes.count != 0, @"schemes should not be empty"); NSAssert(schemes.count != 0, @"schemes should not be empty");
#endif #endif
self = [super initWithDelegate:delegate context:context datacenterId:datacenterId schemes:schemes proxySettings:proxySettings usageCalculationInfo:usageCalculationInfo]; self = [super initWithDelegate:delegate context:context datacenterId:datacenterId schemes:schemes proxySettings:proxySettings usageCalculationInfo:usageCalculationInfo getLogPrefix:getLogPrefix];
if (self != nil) if (self != nil)
{ {
_context = context; _context = context;
@ -196,7 +196,7 @@ static const NSTimeInterval MTTcpTransportSleepWatchdogTimeout = 60.0;
[self startConnectionWatchdogTimer:scheme]; [self startConnectionWatchdogTimer:scheme];
[self startSleepWatchdogTimer]; [self startSleepWatchdogTimer];
transportContext.connection = [[MTTcpConnection alloc] initWithContext:context datacenterId:_datacenterId scheme:scheme interface:nil usageCalculationInfo:_usageCalculationInfo]; transportContext.connection = [[MTTcpConnection alloc] initWithContext:context datacenterId:_datacenterId scheme:scheme interface:nil usageCalculationInfo:_usageCalculationInfo getLogPrefix:self.getLogPrefix];
transportContext.connection.delegate = self; transportContext.connection.delegate = self;
[transportContext.connection start]; [transportContext.connection start];
} }

View File

@ -12,7 +12,7 @@
@implementation MTTransport @implementation MTTransport
- (instancetype)initWithDelegate:(id<MTTransportDelegate>)delegate context:(MTContext *)context datacenterId:(NSInteger)datacenterId schemes:(NSArray<MTTransportScheme *> * _Nonnull)schemes proxySettings:(MTSocksProxySettings *)proxySettings usageCalculationInfo:(MTNetworkUsageCalculationInfo *)__unused usageCalculationInfo - (instancetype)initWithDelegate:(id<MTTransportDelegate>)delegate context:(MTContext *)context datacenterId:(NSInteger)datacenterId schemes:(NSArray<MTTransportScheme *> * _Nonnull)schemes proxySettings:(MTSocksProxySettings *)proxySettings usageCalculationInfo:(MTNetworkUsageCalculationInfo *)__unused usageCalculationInfo getLogPrefix:(NSString * _Nullable (^ _Nullable)())getLogPrefix
{ {
#ifdef DEBUG #ifdef DEBUG
NSAssert(context != nil, @"context should not be nil"); NSAssert(context != nil, @"context should not be nil");
@ -25,6 +25,7 @@
_context = context; _context = context;
_datacenterId = datacenterId; _datacenterId = datacenterId;
_proxySettings = proxySettings; _proxySettings = proxySettings;
_getLogPrefix = [getLogPrefix copy];
_networkAvailability = [[MTNetworkAvailability alloc] initWithDelegate:self]; _networkAvailability = [[MTNetworkAvailability alloc] initWithDelegate:self];

View File

@ -13,15 +13,15 @@ void setBridgingShortTraceFunction(void (*f)(NSString *, NSString *)) {
bridgingShortTrace = f; bridgingShortTrace = f;
} }
static void TGTelegramLoggingFunction(NSString *format, va_list args) { static void TGTelegramLoggingFunction(NSString *format) {
if (bridgingTrace) { if (bridgingTrace) {
bridgingTrace(@"MT", [[NSString alloc] initWithFormat:format arguments:args]); bridgingTrace(@"MT", format);
} }
} }
static void TGTelegramShortLoggingFunction(NSString *format, va_list args) { static void TGTelegramShortLoggingFunction(NSString *format) {
if (bridgingShortTrace) { if (bridgingShortTrace) {
bridgingShortTrace(@"MT", [[NSString alloc] initWithFormat:format arguments:args]); bridgingShortTrace(@"MT", format);
} }
} }

View File

@ -1768,7 +1768,7 @@ public func chatMessageWebFileCancelInteractiveFetch(account: Account, image: Te
return account.postbox.mediaBox.cancelInteractiveResourceFetch(image.resource) return account.postbox.mediaBox.cancelInteractiveResourceFetch(image.resource)
} }
public func chatWebpageSnippetFileData(account: Account, fileReference: FileMediaReference, resource: MediaResource) -> Signal<Data?, NoError> { public func chatWebpageSnippetFileData(account: Account, mediaReference: AnyMediaReference, resource: MediaResource) -> Signal<Data?, NoError> {
let resourceData = account.postbox.mediaBox.resourceData(resource) let resourceData = account.postbox.mediaBox.resourceData(resource)
|> map { next in |> map { next in
return next.size == 0 ? nil : try? Data(contentsOf: URL(fileURLWithPath: next.path), options: .mappedIfSafe) return next.size == 0 ? nil : try? Data(contentsOf: URL(fileURLWithPath: next.path), options: .mappedIfSafe)
@ -1782,7 +1782,7 @@ public func chatWebpageSnippetFileData(account: Account, fileReference: FileMedi
}, completed: { }, completed: {
subscriber.putCompletion() subscriber.putCompletion()
})) }))
disposable.add(fetchedMediaResource(mediaBox: account.postbox.mediaBox, reference: fileReference.resourceReference(resource)).start()) disposable.add(fetchedMediaResource(mediaBox: account.postbox.mediaBox, reference: mediaReference.resourceReference(resource)).start())
return disposable return disposable
} }
} }
@ -1810,8 +1810,8 @@ public func chatWebpageSnippetPhotoData(account: Account, photoReference: ImageM
} }
} }
public func chatWebpageSnippetFile(account: Account, fileReference: FileMediaReference, representation: TelegramMediaImageRepresentation) -> Signal<(TransformImageArguments) -> DrawingContext?, NoError> { public func chatWebpageSnippetFile(account: Account, mediaReference: AnyMediaReference, representation: TelegramMediaImageRepresentation) -> Signal<(TransformImageArguments) -> DrawingContext?, NoError> {
let signal = chatWebpageSnippetFileData(account: account, fileReference: fileReference, resource: representation.resource) let signal = chatWebpageSnippetFileData(account: account, mediaReference: mediaReference, resource: representation.resource)
return signal |> map { fullSizeData in return signal |> map { fullSizeData in
return { arguments in return { arguments in

View File

@ -97,6 +97,8 @@ swift_library(
"//submodules/QrCodeUI:QrCodeUI", "//submodules/QrCodeUI:QrCodeUI",
"//submodules/AnimatedStickerNode:AnimatedStickerNode", "//submodules/AnimatedStickerNode:AnimatedStickerNode",
"//submodules/TelegramAnimatedStickerNode:TelegramAnimatedStickerNode", "//submodules/TelegramAnimatedStickerNode:TelegramAnimatedStickerNode",
"//submodules/FetchManagerImpl:FetchManagerImpl",
"//submodules/ListMessageItem:ListMessageItem",
], ],
visibility = [ visibility = [
"//visibility:public", "//visibility:public",

View File

@ -0,0 +1,337 @@
import Foundation
import UIKit
import Display
import AsyncDisplayKit
import SwiftSignalKit
import Postbox
import TelegramCore
import TelegramPresentationData
import TelegramUIPreferences
import ItemListUI
import PresentationDataUtils
import AccountContext
import ReactionImageComponent
import WebPBinding
import FetchManagerImpl
import ListMessageItem
import ListSectionHeaderNode
private struct DownloadItem: Equatable {
let resourceId: MediaResourceId
let message: Message
let priority: FetchManagerPriorityKey
static func ==(lhs: DownloadItem, rhs: DownloadItem) -> Bool {
if lhs.resourceId != rhs.resourceId {
return false
}
if lhs.message.id != rhs.message.id {
return false
}
if lhs.priority != rhs.priority {
return false
}
return true
}
}
private final class DownloadsControllerArguments {
let context: AccountContext
init(
context: AccountContext
) {
self.context = context
}
}
private enum DownloadsControllerSection: Int32 {
case items
}
public final class DownloadsItemHeader: ListViewItemHeader {
public let id: ListViewItemNode.HeaderId
public let title: String
public let stickDirection: ListViewItemHeaderStickDirection = .top
public let stickOverInsets: Bool = true
public let theme: PresentationTheme
public let height: CGFloat = 28.0
public init(id: ListViewItemNode.HeaderId, title: String, theme: PresentationTheme) {
self.id = id
self.title = title
self.theme = theme
}
public func combinesWith(other: ListViewItemHeader) -> Bool {
if let other = other as? DownloadsItemHeader, other.id == self.id {
return true
} else {
return false
}
}
public func node(synchronousLoad: Bool) -> ListViewItemHeaderNode {
return DownloadsItemHeaderNode(title: self.title, theme: self.theme)
}
public func updateNode(_ node: ListViewItemHeaderNode, previous: ListViewItemHeader?, next: ListViewItemHeader?) {
(node as? DownloadsItemHeaderNode)?.update(title: self.title)
}
}
public final class DownloadsItemHeaderNode: ListViewItemHeaderNode {
private var title: String
private var theme: PresentationTheme
private var validLayout: (size: CGSize, leftInset: CGFloat, rightInset: CGFloat)?
private let sectionHeaderNode: ListSectionHeaderNode
public init(title: String, theme: PresentationTheme) {
self.title = title
self.theme = theme
self.sectionHeaderNode = ListSectionHeaderNode(theme: theme)
super.init()
self.sectionHeaderNode.title = title
self.sectionHeaderNode.action = nil
self.addSubnode(self.sectionHeaderNode)
}
public func updateTheme(theme: PresentationTheme) {
self.theme = theme
self.sectionHeaderNode.updateTheme(theme: theme)
}
public func update(title: String) {
self.sectionHeaderNode.title = title
self.sectionHeaderNode.action = nil
if let (size, leftInset, rightInset) = self.validLayout {
self.sectionHeaderNode.updateLayout(size: size, leftInset: leftInset, rightInset: rightInset)
}
}
override public func updateLayout(size: CGSize, leftInset: CGFloat, rightInset: CGFloat) {
self.validLayout = (size, leftInset, rightInset)
self.sectionHeaderNode.frame = CGRect(origin: CGPoint(), size: size)
self.sectionHeaderNode.updateLayout(size: size, leftInset: leftInset, rightInset: rightInset)
}
override public func animateRemoved(duration: Double) {
self.alpha = 0.0
self.layer.animateAlpha(from: 1.0, to: 0.0, duration: duration, removeOnCompletion: true)
}
}
private enum DownloadsControllerEntry: ItemListNodeEntry {
enum StableId: Hashable {
case item(MediaResourceId)
}
case item(item: DownloadItem)
var section: ItemListSectionId {
switch self {
case .item:
return DownloadsControllerSection.items.rawValue
}
}
var stableId: StableId {
switch self {
case let .item(item):
return .item(item.resourceId)
}
}
var sortId: FetchManagerPriorityKey {
switch self {
case let .item(item):
return item.priority
}
}
static func ==(lhs: DownloadsControllerEntry, rhs: DownloadsControllerEntry) -> Bool {
switch lhs {
case let .item(item):
if case .item(item) = rhs {
return true
} else {
return false
}
}
}
static func <(lhs: DownloadsControllerEntry, rhs: DownloadsControllerEntry) -> Bool {
return lhs.sortId < rhs.sortId
}
func item(presentationData: ItemListPresentationData, arguments: Any) -> ListViewItem {
let arguments = arguments as! DownloadsControllerArguments
let _ = arguments
switch self {
case let .item(item):
let listInteraction = ListMessageItemInteraction(openMessage: { message, mode -> Bool in
return false
}, openMessageContextMenu: { message, _, node, rect, gesture in
}, toggleMessagesSelection: { messageId, selected in
}, openUrl: { url, _, _, message in
}, openInstantPage: { message, data in
}, longTap: { action, message in
}, getHiddenMedia: {
return [:]
})
let presentationData = arguments.context.sharedContext.currentPresentationData.with({ $0 })
return ListMessageItem(presentationData: ChatPresentationData(presentationData: presentationData), context: arguments.context, chatLocation: .peer(item.message.id.peerId), interaction: listInteraction, message: item.message, selection: .none, displayHeader: false, customHeader: nil/*DownloadsItemHeader(id: ListViewItemNode.HeaderId(space: 0, id: item.message.id.peerId), title: item.message.peers[item.message.id.peerId].flatMap(EnginePeer.init)?.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder) ?? "", theme: presentationData.theme)*/, hintIsLink: false, isGlobalSearchResult: false)
}
}
}
private struct DownloadsControllerState: Equatable {
var hasReaction: Bool = false
}
private func downloadsControllerEntries(
presentationData: PresentationData,
items: [DownloadItem],
state: DownloadsControllerState
) -> [DownloadsControllerEntry] {
var entries: [DownloadsControllerEntry] = []
var index = 0
for item in items {
entries.append(.item(
item: item
))
index += 1
}
return entries
}
public func downloadsController(
context: AccountContext,
updatedPresentationData: (initial: PresentationData, signal: Signal<PresentationData, NoError>)? = nil
) -> ViewController {
let statePromise = ValuePromise(DownloadsControllerState(), ignoreRepeated: true)
let stateValue = Atomic(value: DownloadsControllerState())
let updateState: ((DownloadsControllerState) -> DownloadsControllerState) -> Void = { f in
statePromise.set(stateValue.modify { f($0) })
}
let _ = updateState
var dismissImpl: (() -> Void)?
let _ = dismissImpl
let actionsDisposable = DisposableSet()
let arguments = DownloadsControllerArguments(
context: context
)
let settings = context.account.postbox.preferencesView(keys: [PreferencesKeys.reactionSettings])
|> map { preferencesView -> ReactionSettings in
let reactionSettings: ReactionSettings
if let entry = preferencesView.values[PreferencesKeys.reactionSettings], let value = entry.get(ReactionSettings.self) {
reactionSettings = value
} else {
reactionSettings = .default
}
return reactionSettings
}
let downloadItems: Signal<[DownloadItem], NoError> = (context.fetchManager as! FetchManagerImpl).entriesSummary
|> mapToSignal { entries -> Signal<[DownloadItem], NoError> in
var itemSignals: [Signal<DownloadItem?, NoError>] = []
for entry in entries {
switch entry.id.locationKey {
case let .messageId(id):
itemSignals.append(context.account.postbox.transaction { transaction -> DownloadItem? in
if let message = transaction.getMessage(id) {
return DownloadItem(resourceId: entry.resourceReference.resource.id, message: message, priority: entry.priority)
}
return nil
})
default:
break
}
}
return combineLatest(queue: .mainQueue(), itemSignals)
|> map { items -> [DownloadItem] in
return items.compactMap { $0 }
}
}
let presentationData = updatedPresentationData?.signal ?? context.sharedContext.presentationData
let signal = combineLatest(queue: .mainQueue(),
presentationData,
statePromise.get(),
context.engine.stickers.availableReactions(),
settings,
downloadItems
)
|> deliverOnMainQueue
|> map { presentationData, state, availableReactions, settings, downloadItems -> (ItemListControllerState, (ItemListNodeState, Any)) in
//TODO:localize
let title: String = "Downloads"
let entries = downloadsControllerEntries(
presentationData: presentationData,
items: downloadItems,
state: state
)
let controllerState = ItemListControllerState(
presentationData: ItemListPresentationData(presentationData),
title: .text(title),
leftNavigationButton: nil,
rightNavigationButton: nil,
backNavigationButton: ItemListBackButton(title: presentationData.strings.Common_Back),
animateChanges: false
)
let listState = ItemListNodeState(
presentationData: ItemListPresentationData(presentationData),
entries: entries,
style: .plain,
animateChanges: true
)
return (controllerState, (listState, arguments))
}
|> afterDisposed {
actionsDisposable.dispose()
}
let controller = ItemListController(context: context, state: signal)
controller.didScrollWithOffset = { [weak controller] offset, transition, _ in
guard let controller = controller else {
return
}
controller.forEachItemNode { itemNode in
if let itemNode = itemNode as? ReactionChatPreviewItemNode {
itemNode.standaloneReactionAnimation?.addRelativeContentOffset(CGPoint(x: 0.0, y: offset), transition: transition)
}
}
}
dismissImpl = { [weak controller] in
guard let controller = controller else {
return
}
controller.dismiss()
}
return controller
}

View File

@ -7,6 +7,17 @@ protocol TelegramCloudMediaResource: TelegramMediaResource {
func apiInputLocation(fileReference: Data?) -> Api.InputFileLocation? func apiInputLocation(fileReference: Data?) -> Api.InputFileLocation?
} }
public func extractMediaResourceDebugInfo(resource: MediaResource) -> String? {
if let resource = resource as? TelegramCloudMediaResource {
guard let inputLocation = resource.apiInputLocation(fileReference: nil) else {
return nil
}
return String(describing: inputLocation)
} else {
return nil
}
}
public protocol TelegramMultipartFetchableResource: TelegramMediaResource { public protocol TelegramMultipartFetchableResource: TelegramMediaResource {
var datacenterId: Int { get } var datacenterId: Int { get }
} }

View File

@ -43,6 +43,7 @@ class Download: NSObject, MTRequestMessageServiceDelegate {
let context: MTContext let context: MTContext
let mtProto: MTProto let mtProto: MTProto
let requestService: MTRequestMessageService let requestService: MTRequestMessageService
private let logPrefix = Atomic<String?>(value: nil)
private var shouldKeepConnectionDisposable: Disposable? private var shouldKeepConnectionDisposable: Disposable?
@ -59,6 +60,10 @@ class Download: NSObject, MTRequestMessageServiceDelegate {
} }
self.mtProto = MTProto(context: self.context, datacenterId: datacenterId, usageCalculationInfo: usageInfo, requiredAuthToken: requiredAuthToken, authTokenMasterDatacenterId: authTokenMasterDatacenterId) self.mtProto = MTProto(context: self.context, datacenterId: datacenterId, usageCalculationInfo: usageInfo, requiredAuthToken: requiredAuthToken, authTokenMasterDatacenterId: authTokenMasterDatacenterId)
let logPrefix = self.logPrefix
self.mtProto.getLogPrefix = {
return logPrefix.with { $0 }
}
self.mtProto.cdn = isCdn self.mtProto.cdn = isCdn
self.mtProto.useTempAuthKeys = self.context.useTempAuthKeys && !isCdn self.mtProto.useTempAuthKeys = self.context.useTempAuthKeys && !isCdn
self.mtProto.media = isMedia self.mtProto.media = isMedia
@ -375,7 +380,7 @@ class Download: NSObject, MTRequestMessageServiceDelegate {
} }
} }
func rawRequest(_ data: (FunctionDescription, Buffer, (Buffer) -> Any?), automaticFloodWait: Bool = true, failOnServerErrors: Bool = false) -> Signal<(Any, Double), (MTRpcError, Double)> { func rawRequest(_ data: (FunctionDescription, Buffer, (Buffer) -> Any?), automaticFloodWait: Bool = true, failOnServerErrors: Bool = false, logPrefix: String = "") -> Signal<(Any, Double), (MTRpcError, Double)> {
let requestService = self.requestService let requestService = self.requestService
return Signal { subscriber in return Signal { subscriber in
let request = MTRequest() let request = MTRequest()

View File

@ -256,6 +256,7 @@ swift_library(
"//submodules/TabBarUI:TabBarUI", "//submodules/TabBarUI:TabBarUI",
"//submodules/SoftwareVideo:SoftwareVideo", "//submodules/SoftwareVideo:SoftwareVideo",
"//submodules/ManagedFile:ManagedFile", "//submodules/ManagedFile:ManagedFile",
"//submodules/FetchManagerImpl:FetchManagerImpl",
] + select({ ] + select({
"@build_bazel_rules_apple//apple:ios_armv7": [], "@build_bazel_rules_apple//apple:ios_armv7": [],
"@build_bazel_rules_apple//apple:ios_arm64": appcenter_targets, "@build_bazel_rules_apple//apple:ios_arm64": appcenter_targets,

View File

@ -17,6 +17,7 @@ import TelegramBaseController
import AsyncDisplayKit import AsyncDisplayKit
import PresentationDataUtils import PresentationDataUtils
import MeshAnimationCache import MeshAnimationCache
import FetchManagerImpl
private final class DeviceSpecificContactImportContext { private final class DeviceSpecificContactImportContext {
let disposable = MetaDisposable() let disposable = MetaDisposable()

View File

@ -26,6 +26,7 @@ import TelegramNotices
import ReactionListContextMenuContent import ReactionListContextMenuContent
import TelegramUIPreferences import TelegramUIPreferences
import Translate import Translate
import DebugSettingsUI
private struct MessageContextMenuData { private struct MessageContextMenuData {
let starStatus: Bool? let starStatus: Bool?
@ -565,7 +566,7 @@ func contextMenuForChatPresentationInterfaceState(chatPresentationInterfaceState
return transaction.getCombinedPeerReadState(messages[0].id.peerId) return transaction.getCombinedPeerReadState(messages[0].id.peerId)
} }
let dataSignal: Signal<(MessageContextMenuData, [MessageId: ChatUpdatingMessageMedia], CachedPeerData?, AppConfiguration, Bool, Int32, AvailableReactions?, TranslationSettings), NoError> = combineLatest( let dataSignal: Signal<(MessageContextMenuData, [MessageId: ChatUpdatingMessageMedia], CachedPeerData?, AppConfiguration, Bool, Int32, AvailableReactions?, TranslationSettings, LoggingSettings), NoError> = combineLatest(
loadLimits, loadLimits,
loadStickerSaveStatusSignal, loadStickerSaveStatusSignal,
loadResourceStatusSignal, loadResourceStatusSignal,
@ -576,9 +577,9 @@ func contextMenuForChatPresentationInterfaceState(chatPresentationInterfaceState
readState, readState,
ApplicationSpecificNotice.getMessageViewsPrivacyTips(accountManager: context.sharedContext.accountManager), ApplicationSpecificNotice.getMessageViewsPrivacyTips(accountManager: context.sharedContext.accountManager),
context.engine.stickers.availableReactions(), context.engine.stickers.availableReactions(),
context.sharedContext.accountManager.sharedData(keys: [ApplicationSpecificSharedDataKeys.translationSettings]) context.sharedContext.accountManager.sharedData(keys: [ApplicationSpecificSharedDataKeys.translationSettings, SharedDataKeys.loggingSettings])
) )
|> map { limitsAndAppConfig, stickerSaveStatus, resourceStatus, messageActions, updatingMessageMedia, cachedData, readState, messageViewsPrivacyTips, availableReactions, sharedData -> (MessageContextMenuData, [MessageId: ChatUpdatingMessageMedia], CachedPeerData?, AppConfiguration, Bool, Int32, AvailableReactions?, TranslationSettings) in |> map { limitsAndAppConfig, stickerSaveStatus, resourceStatus, messageActions, updatingMessageMedia, cachedData, readState, messageViewsPrivacyTips, availableReactions, sharedData -> (MessageContextMenuData, [MessageId: ChatUpdatingMessageMedia], CachedPeerData?, AppConfiguration, Bool, Int32, AvailableReactions?, TranslationSettings, LoggingSettings) in
let (limitsConfiguration, appConfig) = limitsAndAppConfig let (limitsConfiguration, appConfig) = limitsAndAppConfig
var canEdit = false var canEdit = false
if !isAction { if !isAction {
@ -598,12 +599,19 @@ func contextMenuForChatPresentationInterfaceState(chatPresentationInterfaceState
translationSettings = TranslationSettings.defaultSettings translationSettings = TranslationSettings.defaultSettings
} }
return (MessageContextMenuData(starStatus: stickerSaveStatus, canReply: canReply, canPin: canPin, canEdit: canEdit, canSelect: canSelect, resourceStatus: resourceStatus, messageActions: messageActions), updatingMessageMedia, cachedData, appConfig, isMessageRead, messageViewsPrivacyTips, availableReactions, translationSettings) let loggingSettings: LoggingSettings
if let current = sharedData.entries[SharedDataKeys.loggingSettings]?.get(LoggingSettings.self) {
loggingSettings = current
} else {
loggingSettings = LoggingSettings.defaultSettings
}
return (MessageContextMenuData(starStatus: stickerSaveStatus, canReply: canReply, canPin: canPin, canEdit: canEdit, canSelect: canSelect, resourceStatus: resourceStatus, messageActions: messageActions), updatingMessageMedia, cachedData, appConfig, isMessageRead, messageViewsPrivacyTips, availableReactions, translationSettings, loggingSettings)
} }
return dataSignal return dataSignal
|> deliverOnMainQueue |> deliverOnMainQueue
|> map { data, updatingMessageMedia, cachedData, appConfig, isMessageRead, messageViewsPrivacyTips, availableReactions, translationSettings -> ContextController.Items in |> map { data, updatingMessageMedia, cachedData, appConfig, isMessageRead, messageViewsPrivacyTips, availableReactions, translationSettings, loggingSettings -> ContextController.Items in
var actions: [ContextMenuItem] = [] var actions: [ContextMenuItem] = []
var isPinnedMessages = false var isPinnedMessages = false
@ -867,6 +875,32 @@ func contextMenuForChatPresentationInterfaceState(chatPresentationInterfaceState
} }
} }
var downloadableMediaResourceInfos: [String] = []
for media in message.media {
if let file = media as? TelegramMediaFile {
if let info = extractMediaResourceDebugInfo(resource: file.resource) {
downloadableMediaResourceInfos.append(info)
}
} else if let image = media as? TelegramMediaImage {
for representation in image.representations {
if let info = extractMediaResourceDebugInfo(resource: representation.resource) {
downloadableMediaResourceInfos.append(info)
}
}
}
}
if (loggingSettings.logToFile || loggingSettings.logToConsole) && !downloadableMediaResourceInfos.isEmpty {
actions.append(.action(ContextMenuActionItem(text: "Send Logs", icon: { theme in
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Message"), color: theme.actionSheet.primaryTextColor)
}, action: { _, f in
triggerDebugSendLogsUI(context: context, additionalInfo: "User has requested download logs for \(downloadableMediaResourceInfos)", pushController: { c in
controllerInteraction.navigationController()?.pushViewController(c)
})
f(.default)
})))
}
var threadId: Int64? var threadId: Int64?
var threadMessageCount: Int = 0 var threadMessageCount: Int = 0
if case .peer = chatPresentationInterfaceState.chatLocation, let channel = chatPresentationInterfaceState.renderedPeer?.peer as? TelegramChannel, case .group = channel.info { if case .peer = chatPresentationInterfaceState.chatLocation, let channel = chatPresentationInterfaceState.renderedPeer?.peer as? TelegramChannel, case .group = channel.info {

View File

@ -189,7 +189,7 @@ class ChatMessageReplyInfoNode: ASDisplayNode {
if fileReference.media.isVideo { if fileReference.media.isVideo {
updateImageSignal = chatMessageVideoThumbnail(account: context.account, fileReference: fileReference) updateImageSignal = chatMessageVideoThumbnail(account: context.account, fileReference: fileReference)
} else if let iconImageRepresentation = smallestImageRepresentation(fileReference.media.previewRepresentations) { } else if let iconImageRepresentation = smallestImageRepresentation(fileReference.media.previewRepresentations) {
updateImageSignal = chatWebpageSnippetFile(account: context.account, fileReference: fileReference, representation: iconImageRepresentation) updateImageSignal = chatWebpageSnippetFile(account: context.account, mediaReference: fileReference.abstract, representation: iconImageRepresentation)
} }
} }
} }

View File

@ -457,7 +457,7 @@ final class ChatPinnedMessageTitlePanelNode: ChatTitleAccessoryPanelNode {
} else if fileReference.media.isVideo { } else if fileReference.media.isVideo {
updateImageSignal = chatMessageVideoThumbnail(account: context.account, fileReference: fileReference) updateImageSignal = chatMessageVideoThumbnail(account: context.account, fileReference: fileReference)
} else if let iconImageRepresentation = smallestImageRepresentation(fileReference.media.previewRepresentations) { } else if let iconImageRepresentation = smallestImageRepresentation(fileReference.media.previewRepresentations) {
updateImageSignal = chatWebpageSnippetFile(account: context.account, fileReference: fileReference, representation: iconImageRepresentation) updateImageSignal = chatWebpageSnippetFile(account: context.account, mediaReference: fileReference.abstract, representation: iconImageRepresentation)
} }
} }
} else { } else {

View File

@ -226,7 +226,7 @@ final class EditAccessoryPanelNode: AccessoryPanelNode {
if fileReference.media.isVideo { if fileReference.media.isVideo {
updateImageSignal = chatMessageVideoThumbnail(account: self.context.account, fileReference: fileReference) updateImageSignal = chatMessageVideoThumbnail(account: self.context.account, fileReference: fileReference)
} else if let iconImageRepresentation = smallestImageRepresentation(fileReference.media.previewRepresentations) { } else if let iconImageRepresentation = smallestImageRepresentation(fileReference.media.previewRepresentations) {
updateImageSignal = chatWebpageSnippetFile(account: self.context.account, fileReference: fileReference, representation: iconImageRepresentation) updateImageSignal = chatWebpageSnippetFile(account: self.context.account, mediaReference: fileReference.abstract, representation: iconImageRepresentation)
} }
} }
} else { } else {

View File

@ -1,2 +0,0 @@
import Foundation
import Postbox

View File

@ -403,6 +403,7 @@ private enum PeerInfoSettingsSection {
case avatar case avatar
case edit case edit
case proxy case proxy
case downloads
case savedMessages case savedMessages
case recentCalls case recentCalls
case devices case devices
@ -662,10 +663,14 @@ private func settingsItems(data: PeerInfoScreenData?, context: AccountContext, p
} }
} }
items[.shortcuts]!.append(PeerInfoScreenDisclosureItem(id: 0, text: presentationData.strings.Settings_SavedMessages, icon: PresentationResourcesSettings.savedMessages, action: { //TODO:localize
items[.shortcuts]!.append(PeerInfoScreenDisclosureItem(id: 0, text: "Downloads", icon: PresentationResourcesSettings.savedMessages, action: {
interaction.openSettings(.downloads)
}))
items[.shortcuts]!.append(PeerInfoScreenDisclosureItem(id: 1, text: presentationData.strings.Settings_SavedMessages, icon: PresentationResourcesSettings.savedMessages, action: {
interaction.openSettings(.savedMessages) interaction.openSettings(.savedMessages)
})) }))
items[.shortcuts]!.append(PeerInfoScreenDisclosureItem(id: 1, text: presentationData.strings.CallSettings_RecentCalls, icon: PresentationResourcesSettings.recentCalls, action: { items[.shortcuts]!.append(PeerInfoScreenDisclosureItem(id: 2, text: presentationData.strings.CallSettings_RecentCalls, icon: PresentationResourcesSettings.recentCalls, action: {
interaction.openSettings(.recentCalls) interaction.openSettings(.recentCalls)
})) }))
@ -680,10 +685,10 @@ private func settingsItems(data: PeerInfoScreenData?, context: AccountContext, p
devicesLabel = "" devicesLabel = ""
} }
items[.shortcuts]!.append(PeerInfoScreenDisclosureItem(id: 2, label: .text(devicesLabel), text: presentationData.strings.Settings_Devices, icon: PresentationResourcesSettings.devices, action: { items[.shortcuts]!.append(PeerInfoScreenDisclosureItem(id: 3, label: .text(devicesLabel), text: presentationData.strings.Settings_Devices, icon: PresentationResourcesSettings.devices, action: {
interaction.openSettings(.devices) interaction.openSettings(.devices)
})) }))
items[.shortcuts]!.append(PeerInfoScreenDisclosureItem(id: 3, text: presentationData.strings.Settings_ChatFolders, icon: PresentationResourcesSettings.chatFolders, action: { items[.shortcuts]!.append(PeerInfoScreenDisclosureItem(id: 4, text: presentationData.strings.Settings_ChatFolders, icon: PresentationResourcesSettings.chatFolders, action: {
interaction.openSettings(.chatFolders) interaction.openSettings(.chatFolders)
})) }))
@ -5527,6 +5532,8 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate
self.headerNode.navigationButtonContainer.performAction?(.edit, nil, nil) self.headerNode.navigationButtonContainer.performAction?(.edit, nil, nil)
case .proxy: case .proxy:
self.controller?.push(proxySettingsController(context: self.context)) self.controller?.push(proxySettingsController(context: self.context))
case .downloads:
self.controller?.push(downloadsController(context: self.context, updatedPresentationData: self.controller?.updatedPresentationData))
case .savedMessages: case .savedMessages:
if let controller = self.controller, let navigationController = controller.navigationController as? NavigationController { if let controller = self.controller, let navigationController = controller.navigationController as? NavigationController {
self.context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: self.context, chatLocation: .peer(self.context.account.peerId))) self.context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: self.context, chatLocation: .peer(self.context.account.peerId)))

View File

@ -196,7 +196,7 @@ final class ReplyAccessoryPanelNode: AccessoryPanelNode {
if fileReference.media.isVideo { if fileReference.media.isVideo {
updateImageSignal = chatMessageVideoThumbnail(account: context.account, fileReference: fileReference) updateImageSignal = chatMessageVideoThumbnail(account: context.account, fileReference: fileReference)
} else if let iconImageRepresentation = smallestImageRepresentation(fileReference.media.previewRepresentations) { } else if let iconImageRepresentation = smallestImageRepresentation(fileReference.media.previewRepresentations) {
updateImageSignal = chatWebpageSnippetFile(account: context.account, fileReference: fileReference, representation: iconImageRepresentation) updateImageSignal = chatWebpageSnippetFile(account: context.account, mediaReference: fileReference.abstract, representation: iconImageRepresentation)
} }
} }
} else { } else {

View File

@ -556,7 +556,7 @@ final class WatchMediaHandler: WatchRequestHandler {
imageSignal = chatMessageVideoThumbnail(account: context.account, fileReference: fileReference) imageSignal = chatMessageVideoThumbnail(account: context.account, fileReference: fileReference)
roundVideo = fileReference.media.isInstantVideo roundVideo = fileReference.media.isInstantVideo
} else if let iconImageRepresentation = smallestImageRepresentation(fileReference.media.previewRepresentations) { } else if let iconImageRepresentation = smallestImageRepresentation(fileReference.media.previewRepresentations) {
imageSignal = chatWebpageSnippetFile(account: context.account, fileReference: fileReference, representation: iconImageRepresentation) imageSignal = chatWebpageSnippetFile(account: context.account, mediaReference: fileReference.abstract, representation: iconImageRepresentation)
} }
} }
} }