From 5278f451f11eaa34a75c5ec323e72102345dbb0f Mon Sep 17 00:00:00 2001 From: Peter Date: Tue, 21 Mar 2017 19:58:26 +0300 Subject: [PATCH] no message --- TelegramCore.xcodeproj/project.pbxproj | 6 - TelegramCore/PendingMessageManager.swift | 184 ++++++++++++++++-- .../PendingMessageUploadedContent.swift | 48 +++++ TelegramCore/StickerViewTracker.swift | 24 --- TelegramCore/TelegramMediaImage.swift | 2 +- 5 files changed, 222 insertions(+), 42 deletions(-) delete mode 100644 TelegramCore/StickerViewTracker.swift diff --git a/TelegramCore.xcodeproj/project.pbxproj b/TelegramCore.xcodeproj/project.pbxproj index c25f87c185..24198eec39 100644 --- a/TelegramCore.xcodeproj/project.pbxproj +++ b/TelegramCore.xcodeproj/project.pbxproj @@ -270,8 +270,6 @@ D07827CB1E02F5B200071108 /* RichText.swift in Sources */ = {isa = PBXBuildFile; fileRef = D07827CA1E02F5B200071108 /* RichText.swift */; }; D08774FC1E3E39F600A97350 /* ManagedGlobalNotificationSettings.swift in Sources */ = {isa = PBXBuildFile; fileRef = D08774FB1E3E39F600A97350 /* ManagedGlobalNotificationSettings.swift */; }; D08774FE1E3E3A3500A97350 /* GlobalNotificationSettings.swift in Sources */ = {isa = PBXBuildFile; fileRef = D08774FD1E3E3A3500A97350 /* GlobalNotificationSettings.swift */; }; - D08F4A631E79C7B800A2AA15 /* StickerViewTracker.swift in Sources */ = {isa = PBXBuildFile; fileRef = D08F4A621E79C7B800A2AA15 /* StickerViewTracker.swift */; }; - D08F4A641E79C7B800A2AA15 /* StickerViewTracker.swift in Sources */ = {isa = PBXBuildFile; fileRef = D08F4A621E79C7B800A2AA15 /* StickerViewTracker.swift */; }; D08F4A661E79CC4A00A2AA15 /* SynchronizeInstalledStickerPacksOperations.swift in Sources */ = {isa = PBXBuildFile; fileRef = D08F4A651E79CC4A00A2AA15 /* SynchronizeInstalledStickerPacksOperations.swift */; }; D08F4A671E79CC4A00A2AA15 /* SynchronizeInstalledStickerPacksOperations.swift in Sources */ = {isa = PBXBuildFile; fileRef = D08F4A651E79CC4A00A2AA15 /* SynchronizeInstalledStickerPacksOperations.swift */; }; D08F4A691E79CECB00A2AA15 /* ManagedSynchronizeInstalledStickerPacksOperations.swift in Sources */ = {isa = PBXBuildFile; fileRef = D08F4A681E79CECB00A2AA15 /* ManagedSynchronizeInstalledStickerPacksOperations.swift */; }; @@ -632,7 +630,6 @@ D07827CA1E02F5B200071108 /* RichText.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RichText.swift; sourceTree = ""; }; D08774FB1E3E39F600A97350 /* ManagedGlobalNotificationSettings.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ManagedGlobalNotificationSettings.swift; sourceTree = ""; }; D08774FD1E3E3A3500A97350 /* GlobalNotificationSettings.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GlobalNotificationSettings.swift; sourceTree = ""; }; - D08F4A621E79C7B800A2AA15 /* StickerViewTracker.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StickerViewTracker.swift; sourceTree = ""; }; D08F4A651E79CC4A00A2AA15 /* SynchronizeInstalledStickerPacksOperations.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SynchronizeInstalledStickerPacksOperations.swift; sourceTree = ""; }; D08F4A681E79CECB00A2AA15 /* ManagedSynchronizeInstalledStickerPacksOperations.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ManagedSynchronizeInstalledStickerPacksOperations.swift; sourceTree = ""; }; D099EA1B1DE72867001AF5A8 /* PeerCommands.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PeerCommands.swift; sourceTree = ""; }; @@ -1044,7 +1041,6 @@ D049EAF41E44DF3300A2CD3A /* AccountState.swift */, D03B0D621D631A8B00955575 /* AccountSettings.swift */, D03B0D631D631A8B00955575 /* AccountViewTracker.swift */, - D08F4A621E79C7B800A2AA15 /* StickerViewTracker.swift */, D03B0D641D631A8B00955575 /* RecentPeers.swift */, D0AB0B911D65E9FA002C78E7 /* ManagedServiceViews.swift */, D0AB0B931D662ECE002C78E7 /* ManagedMessageHistoryHoles.swift */, @@ -1640,7 +1636,6 @@ D0528E651E65C82400E2FEF5 /* UpdateContactName.swift in Sources */, D03121021DA57E93006A2A60 /* TelegramPeerNotificationSettings.swift in Sources */, D0C48F391E8138DF0075317D /* ArchivedStickerPacksInfo.swift in Sources */, - D08F4A631E79C7B800A2AA15 /* StickerViewTracker.swift in Sources */, D03B0CBB1D62233C00955575 /* MergeLists.swift in Sources */, C239BE971E62EE1E00C2C453 /* LoadMessagesIfNecessary.swift in Sources */, D03B0CC11D62235000955575 /* StringFormat.swift in Sources */, @@ -1867,7 +1862,6 @@ D0528E661E65C82400E2FEF5 /* UpdateContactName.swift in Sources */, D0F7B1E81E045C87007EB8A5 /* PeerParticipants.swift in Sources */, D0C48F3A1E8138DF0075317D /* ArchivedStickerPacksInfo.swift in Sources */, - D08F4A641E79C7B800A2AA15 /* StickerViewTracker.swift in Sources */, D049EAD61E43D98500A2CD3A /* RecentMediaItem.swift in Sources */, D0B844331DAB91E0005F29E1 /* NBPhoneNumber.m in Sources */, D001F3F51E128A1C007A8C60 /* PendingMessageManager.swift in Sources */, diff --git a/TelegramCore/PendingMessageManager.swift b/TelegramCore/PendingMessageManager.swift index 41ad4a7ab7..0880dc440e 100644 --- a/TelegramCore/PendingMessageManager.swift +++ b/TelegramCore/PendingMessageManager.swift @@ -15,8 +15,16 @@ public struct PendingMessageStatus: Equatable { } } +private enum PendingMessageState { + case none + case waitingForUploadToStart(Signal) + case uploading + case sending +} + private final class PendingMessageContext { - var disposable: MetaDisposable? + var state: PendingMessageState = .none + let disposable = MetaDisposable() var status: PendingMessageStatus? var statusSubscribers = Bag<(PendingMessageStatus?) -> Void>() } @@ -74,10 +82,12 @@ public final class PendingMessageManager { let addedMessageIds = messageIds.subtracting(self.pendingMessageIds) let removedMessageIds = self.pendingMessageIds.subtracting(messageIds) + var updateUploadingPeerIds = Set() for id in removedMessageIds { if let context = self.messageContexts[id] { - context.disposable?.dispose() - context.disposable = nil + context.state = .none + updateUploadingPeerIds.insert(id.peerId) + context.disposable.dispose() if context.statusSubscribers.isEmpty { self.messageContexts.removeValue(forKey: id) } @@ -89,6 +99,12 @@ public final class PendingMessageManager { } self.pendingMessageIds = messageIds + + if !updateUploadingPeerIds.isEmpty { + for peerId in updateUploadingPeerIds { + self.updateWaitingUploads(peerId: peerId) + } + } } } @@ -102,7 +118,6 @@ public final class PendingMessageManager { messageContext = current } else { messageContext = PendingMessageContext() - messageContext.disposable = MetaDisposable() self.messageContexts[id] = messageContext } @@ -116,7 +131,7 @@ public final class PendingMessageManager { self.queue.async { if let current = self.messageContexts[id] { current.statusSubscribers.remove(index) - if current.statusSubscribers.isEmpty && current.disposable == nil { + if case .none = current.status, current.statusSubscribers.isEmpty { self.messageContexts.removeValue(forKey: id) } } @@ -128,6 +143,24 @@ public final class PendingMessageManager { } } + private func canBeginUploadingMessage(id: MessageId) -> Bool { + assert(self.queue.isCurrent()) + + let messageIdsForPeer: [MessageId] = self.messageContexts.keys.filter({ $0.peerId == id.peerId }).sorted() + for contextId in messageIdsForPeer { + if contextId < id { + let context = self.messageContexts[contextId]! + if case .uploading = context.state { + return false + } + } else { + break + } + } + + return true + } + private func beginSendingMessages(_ ids: [MessageId]) { assert(self.queue.isCurrent()) @@ -137,7 +170,6 @@ public final class PendingMessageManager { messageContext = current } else { messageContext = PendingMessageContext() - messageContext.disposable = MetaDisposable() self.messageContexts[id] = messageContext } @@ -163,7 +195,7 @@ public final class PendingMessageManager { if let strongSelf = self { assert(strongSelf.queue.isCurrent()) - for message in messages { + for message in messages.sorted(by: { $0.id < $1.id }) { guard let messageContext = strongSelf.messageContexts[message.id] else { continue } @@ -172,7 +204,20 @@ public final class PendingMessageManager { continue } - let uploadedContent = uploadedMessageContent(network: strongSelf.network, postbox: strongSelf.postbox, transformOutgoingMessageMedia: strongSelf.transformOutgoingMessageMedia, message: message) + let contentToUpload = messageContentToUpload(network: strongSelf.network, postbox: strongSelf.postbox, transformOutgoingMessageMedia: strongSelf.transformOutgoingMessageMedia, message: message) + + switch contentToUpload { + case let .ready(message, content): + strongSelf.beginSendingMessage(messageContext: messageContext, message: message, content: content) + case let .upload(uploadSignal): + if strongSelf.canBeginUploadingMessage(id: message.id) { + strongSelf.beginUploadingMessage(messageContext: messageContext, id: message.id, uploadSignal: uploadSignal) + } else { + messageContext.state = .waitingForUploadToStart(uploadSignal) + } + } + + /*let uploadedContent = uploadedMessageContent(network: strongSelf.network, postbox: strongSelf.postbox, transformOutgoingMessageMedia: strongSelf.transformOutgoingMessageMedia, message: message) let sendMessage = uploadedContent |> mapToSignal { contentResult -> Signal in @@ -191,11 +236,10 @@ public final class PendingMessageManager { } } - messageContext.disposable?.set((sendMessage |> deliverOn(strongSelf.queue) |> afterDisposed { + messageContext.disposable.set((sendMessage |> deliverOn(strongSelf.queue) |> afterDisposed { if let strongSelf = self { assert(strongSelf.queue.isCurrent()) if let current = strongSelf.messageContexts[message.id] { - current.disposable = nil for subscriber in current.statusSubscribers.copyItems() { subscriber(nil) } @@ -219,12 +263,130 @@ public final class PendingMessageManager { } } } - })) + }))*/ } } })) } + private func beginSendingMessage(messageContext: PendingMessageContext, message: Message, content: PendingMessageUploadedContent) { + messageContext.state = .sending + let sendMessage: Signal = self.sendMessageContent(network: self.network, postbox: self.postbox, stateManager: self.stateManager, message: message, content: content) + |> map { next -> PendingMessageResult in + return .progress(1.0) + } + messageContext.disposable.set((sendMessage |> deliverOn(self.queue) |> afterDisposed { [weak self] in + if let strongSelf = self { + assert(strongSelf.queue.isCurrent()) + if let current = strongSelf.messageContexts[message.id] { + current.status = .none + for subscriber in current.statusSubscribers.copyItems() { + subscriber(nil) + } + if current.statusSubscribers.isEmpty { + strongSelf.messageContexts.removeValue(forKey: message.id) + } + } + } + }).start(next: { [weak self] next in + if let strongSelf = self { + assert(strongSelf.queue.isCurrent()) + + switch next { + case let .progress(progress): + if let current = strongSelf.messageContexts[message.id] { + let status = PendingMessageStatus(progress: progress) + current.status = status + for subscriber in current.statusSubscribers.copyItems() { + subscriber(status) + } + } + } + } + })) + } + + private func beginUploadingMessage(messageContext: PendingMessageContext, id: MessageId, uploadSignal: Signal) { + messageContext.state = .uploading + + messageContext.disposable.set((uploadSignal |> deliverOn(self.queue)).start(next: { [weak self] next in + if let strongSelf = self { + assert(strongSelf.queue.isCurrent()) + + switch next { + case let .progress(progress): + if let current = strongSelf.messageContexts[id] { + let status = PendingMessageStatus(progress: progress) + current.status = status + for subscriber in current.statusSubscribers.copyItems() { + subscriber(status) + } + } + case let .content(message, content): + if let current = strongSelf.messageContexts[id] { + strongSelf.beginSendingMessage(messageContext: current, message: message, content: content) + strongSelf.updateWaitingUploads(peerId: id.peerId) + } + } + } + })) + } + + private func updateWaitingUploads(peerId: PeerId) { + assert(self.queue.isCurrent()) + + let messageIdsForPeer: [MessageId] = self.messageContexts.keys.filter({ $0.peerId == peerId }).sorted() + loop: for contextId in messageIdsForPeer { + let context = self.messageContexts[contextId]! + if case let .waitingForUploadToStart(uploadSignal) = context.state { + if self.canBeginUploadingMessage(id: contextId) { + context.state = .uploading + context.disposable.set((uploadSignal |> deliverOn(self.queue)).start(next: { [weak self] next in + if let strongSelf = self { + assert(strongSelf.queue.isCurrent()) + + switch next { + case let .progress(progress): + if let current = strongSelf.messageContexts[contextId] { + let status = PendingMessageStatus(progress: progress) + current.status = status + for subscriber in current.statusSubscribers.copyItems() { + subscriber(status) + } + } + case let .content(message, content): + if let current = strongSelf.messageContexts[message.id] { + current.state = .sending + + current.disposable.set((strongSelf.sendMessageContent(network: strongSelf.network, postbox: strongSelf.postbox, stateManager: strongSelf.stateManager, message: message, content: content) + |> map { next -> PendingMessageResult in + return .progress(1.0) + }).start(next: { next in + if let strongSelf = self { + assert(strongSelf.queue.isCurrent()) + + switch next { + case let .progress(progress): + if let current = strongSelf.messageContexts[message.id] { + let status = PendingMessageStatus(progress: progress) + current.status = status + for subscriber in current.statusSubscribers.copyItems() { + subscriber(status) + } + } + } + } + })) + } + } + } + })) + } + break loop + } + } + } + private func sendMessageContent(network: Network, postbox: Postbox, stateManager: AccountStateManager, message: Message, content: PendingMessageUploadedContent) -> Signal { return postbox.modify { [weak self] modifier -> Signal in if message.id.peerId.namespace == Namespaces.Peer.SecretChat { diff --git a/TelegramCore/PendingMessageUploadedContent.swift b/TelegramCore/PendingMessageUploadedContent.swift index 3501f31115..6f2c811b3f 100644 --- a/TelegramCore/PendingMessageUploadedContent.swift +++ b/TelegramCore/PendingMessageUploadedContent.swift @@ -20,6 +20,54 @@ enum PendingMessageUploadedContentResult { case content(Message, PendingMessageUploadedContent) } +enum PendingMessageUploadContent { + case ready(Message, PendingMessageUploadedContent) + case upload(Signal) +} + +func messageContentToUpload(network: Network, postbox: Postbox, transformOutgoingMessageMedia: TransformOutgoingMessageMedia?, message: Message) -> PendingMessageUploadContent { + var outgoingChatContextResultAttribute: OutgoingChatContextResultMessageAttribute? + for attribute in message.attributes { + if let attribute = attribute as? OutgoingChatContextResultMessageAttribute { + outgoingChatContextResultAttribute = attribute + } + } + + if let _ = message.forwardInfo { + var forwardSourceInfo: ForwardSourceInfoAttribute? + for attribute in message.attributes { + if let attribute = attribute as? ForwardSourceInfoAttribute { + forwardSourceInfo = attribute + } + } + if let forwardSourceInfo = forwardSourceInfo { + return .ready(message, .forward(forwardSourceInfo)) + } else { + assertionFailure() + return .ready(message, .text(message.text)) + } + } else if let outgoingChatContextResultAttribute = outgoingChatContextResultAttribute { + return .ready(message, .chatContextResult(outgoingChatContextResultAttribute)) + } else if let media = message.media.first { + if let image = media as? TelegramMediaImage, let _ = largestImageRepresentation(image.representations) { + return .upload(uploadedMediaImageContent(network: network, postbox: postbox, image: image, message: message)) + } else if let file = media as? TelegramMediaFile { + if let resource = file.resource as? CloudDocumentMediaResource { + return .ready(message, .media(Api.InputMedia.inputMediaDocument(id: Api.InputDocument.inputDocument(id: resource.fileId, accessHash: resource.accessHash), caption: message.text))) + } else { + return .upload(uploadedMediaFileContent(network: network, postbox: postbox, transformOutgoingMessageMedia: transformOutgoingMessageMedia, file: file, message: message)) + } + } else if let contact = media as? TelegramMediaContact { + let input = Api.InputMedia.inputMediaContact(phoneNumber: contact.phoneNumber, firstName: contact.firstName, lastName: contact.lastName) + return .ready(message, .media(input)) + } else { + return .ready(message, .text(message.text)) + } + } else { + return .ready(message, .text(message.text)) + } +} + func uploadedMessageContent(network: Network, postbox: Postbox, transformOutgoingMessageMedia: TransformOutgoingMessageMedia?, message: Message) -> Signal { var outgoingChatContextResultAttribute: OutgoingChatContextResultMessageAttribute? for attribute in message.attributes { diff --git a/TelegramCore/StickerViewTracker.swift b/TelegramCore/StickerViewTracker.swift deleted file mode 100644 index ab7d14df5b..0000000000 --- a/TelegramCore/StickerViewTracker.swift +++ /dev/null @@ -1,24 +0,0 @@ -import Foundation -#if os(macOS) - import PostboxMac - import SwiftSignalKitMac - import MtProtoKitMac -#else - import Postbox - import SwiftSignalKit - import MtProtoKitDynamic -#endif - -final class StickerViewTracker { - private let postbox: Postbox - private let mediaBox: MediaBox - - init(postbox: Postbox, mediaBox: MediaBox) { - self.postbox = postbox - self.mediaBox = mediaBox - } - - func wrappedStickerInfosView() -> Signal { - return self.postbox.combinedView(keys: [.itemCollectionInfos(namespaces: [Namespaces.ItemCollection.CloudStickerPacks])]) - } -} diff --git a/TelegramCore/TelegramMediaImage.swift b/TelegramCore/TelegramMediaImage.swift index a203e19109..31bd5eab2a 100644 --- a/TelegramCore/TelegramMediaImage.swift +++ b/TelegramCore/TelegramMediaImage.swift @@ -45,7 +45,7 @@ public final class TelegramMediaImage: Media, Equatable { for i in 0 ..< self.representations.count { let representationDimensions = self.representations[i].dimensions - if dimensions.width >= size.width - CGFloat(FLT_EPSILON) && dimensions.height >= size.height - CGFloat(FLT_EPSILON) { + if dimensions.width >= size.width - CGFloat.ulpOfOne && dimensions.height >= size.height - CGFloat.ulpOfOne { if representationDimensions.width >= size.width && representationDimensions.height >= dimensions.height && representationDimensions.width < dimensions.width && representationDimensions.height < dimensions.height { dimensions = representationDimensions index = i