diff --git a/Telegram/NotificationService/Sources/NotificationService.swift b/Telegram/NotificationService/Sources/NotificationService.swift index 552754ecfb..3916e3af62 100644 --- a/Telegram/NotificationService/Sources/NotificationService.swift +++ b/Telegram/NotificationService/Sources/NotificationService.swift @@ -1214,6 +1214,7 @@ private final class NotificationServiceHandler { let collectedData = Atomic(value: DataValue()) return standaloneMultipartFetch( + accountPeerId: stateManager.accountPeerId, postbox: stateManager.postbox, network: stateManager.network, resource: resource, @@ -1304,6 +1305,7 @@ private final class NotificationServiceHandler { fetchNotificationSoundSignal = Signal { subscriber in let collectedData = Atomic(value: Data()) return standaloneMultipartFetch( + accountPeerId: stateManager.accountPeerId, postbox: stateManager.postbox, network: stateManager.network, resource: resource, diff --git a/submodules/ChatListUI/Sources/ChatListController.swift b/submodules/ChatListUI/Sources/ChatListController.swift index 7c51ad45e9..7657ce16de 100644 --- a/submodules/ChatListUI/Sources/ChatListController.swift +++ b/submodules/ChatListUI/Sources/ChatListController.swift @@ -2304,6 +2304,11 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController } self.chatListDisplayNode.clearHighlightAnimated(true) + + if let fullScreenEffectView = self.fullScreenEffectView { + self.fullScreenEffectView = nil + fullScreenEffectView.removeFromSuperview() + } } func requestUpdateHeaderContent(transition: ContainedViewLayoutTransition) { @@ -2526,25 +2531,37 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController searchContentNode.updateListVisibleContentOffset(.known(0.0)) self.chatListDisplayNode.scrollToTop() } - - #if DEBUG && false - var fullScreenEffectView: RippleEffectView? - if let current = self.fullScreenEffectView { - fullScreenEffectView = current - self.view.window?.addSubview(current) - current.sourceView = self.view - } else { - if let value = RippleEffectView(test: false) { - fullScreenEffectView = value - self.fullScreenEffectView = value - self.view.window?.addSubview(value) - value.sourceView = self.view + } + + public func animateStoryUploadRipple() { + if let componentView = self.headerContentView.view as? ChatListHeaderComponent.View { + if let transitionView = componentView.storyPeerListView()?.transitionViewForItem(peerId: self.context.account.peerId) { + let localRect = transitionView.convert(transitionView.bounds, to: self.view) + self.animateRipple(centerLocation: localRect.center) } } - if let fullScreenEffectView { - fullScreenEffectView.frame = CGRect(origin: CGPoint(), size: layout.size) + } + + public func animateRipple(centerLocation: CGPoint) { + if let fullScreenEffectView = self.fullScreenEffectView { + self.fullScreenEffectView = nil + fullScreenEffectView.removeFromSuperview() + } + + if let value = RippleEffectView(centerLocation: centerLocation, completion: { [weak self] in + guard let self else { + return + } + if let fullScreenEffectView = self.fullScreenEffectView { + self.fullScreenEffectView = nil + fullScreenEffectView.removeFromSuperview() + } + }) { + self.fullScreenEffectView = value + value.sourceView = self.view + self.view.addSubview(value) + value.frame = CGRect(origin: CGPoint(), size: self.view.bounds.size) } - #endif } private func updateLayout(layout: ContainerViewLayout, transition: ContainedViewLayoutTransition) { diff --git a/submodules/TelegramApi/Sources/Api0.swift b/submodules/TelegramApi/Sources/Api0.swift index a90dde3b9d..b9edd1f132 100644 --- a/submodules/TelegramApi/Sources/Api0.swift +++ b/submodules/TelegramApi/Sources/Api0.swift @@ -786,9 +786,10 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = { dict[1087454222] = { return Api.StickerSetCovered.parse_stickerSetFullCovered($0) } dict[872932635] = { return Api.StickerSetCovered.parse_stickerSetMultiCovered($0) } dict[2008112412] = { return Api.StickerSetCovered.parse_stickerSetNoCovered($0) } - dict[-1526488475] = { return Api.StoryItem.parse_storyItem($0) } + dict[-1882351956] = { return Api.StoryItem.parse_storyItem($0) } dict[1374088783] = { return Api.StoryItem.parse_storyItemDeleted($0) } - dict[90474706] = { return Api.StoryView.parse_storyView($0) } + dict[-1491424062] = { return Api.StoryView.parse_storyView($0) } + dict[1368082392] = { return Api.StoryViews.parse_storyViews($0) } dict[1964978502] = { return Api.TextWithEntities.parse_textWithEntities($0) } dict[-1609668650] = { return Api.Theme.parse_theme($0) } dict[-94849324] = { return Api.ThemeSettings.parse_themeSettings($0) } @@ -1156,6 +1157,7 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = { dict[276907596] = { return Api.storage.FileType.parse_fileWebp($0) } dict[1214632796] = { return Api.stories.AllStories.parse_allStories($0) } dict[1340440049] = { return Api.stories.Stories.parse_stories($0) } + dict[-560009955] = { return Api.stories.StoryViews.parse_storyViews($0) } dict[-79726676] = { return Api.stories.StoryViewsList.parse_storyViewsList($0) } dict[543450958] = { return Api.updates.ChannelDifference.parse_channelDifference($0) } dict[1041346555] = { return Api.updates.ChannelDifference.parse_channelDifferenceEmpty($0) } @@ -1712,6 +1714,8 @@ public extension Api { _1.serialize(buffer, boxed) case let _1 as Api.StoryView: _1.serialize(buffer, boxed) + case let _1 as Api.StoryViews: + _1.serialize(buffer, boxed) case let _1 as Api.TextWithEntities: _1.serialize(buffer, boxed) case let _1 as Api.Theme: @@ -2020,6 +2024,8 @@ public extension Api { _1.serialize(buffer, boxed) case let _1 as Api.stories.Stories: _1.serialize(buffer, boxed) + case let _1 as Api.stories.StoryViews: + _1.serialize(buffer, boxed) case let _1 as Api.stories.StoryViewsList: _1.serialize(buffer, boxed) case let _1 as Api.updates.ChannelDifference: diff --git a/submodules/TelegramApi/Sources/Api21.swift b/submodules/TelegramApi/Sources/Api21.swift index 7bf545bdd1..d54457a6e9 100644 --- a/submodules/TelegramApi/Sources/Api21.swift +++ b/submodules/TelegramApi/Sources/Api21.swift @@ -328,14 +328,14 @@ public extension Api { } public extension Api { indirect enum StoryItem: TypeConstructorDescription { - case storyItem(flags: Int32, id: Int32, date: Int32, caption: String?, entities: [Api.MessageEntity]?, media: Api.MessageMedia, privacy: [Api.PrivacyRule]?, recentViewers: [Int64]?, viewsCount: Int32?) + case storyItem(flags: Int32, id: Int32, date: Int32, caption: String?, entities: [Api.MessageEntity]?, media: Api.MessageMedia, privacy: [Api.PrivacyRule]?, views: Api.StoryViews?) case storyItemDeleted(id: Int32) public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { switch self { - case .storyItem(let flags, let id, let date, let caption, let entities, let media, let privacy, let recentViewers, let viewsCount): + case .storyItem(let flags, let id, let date, let caption, let entities, let media, let privacy, let views): if boxed { - buffer.appendInt32(-1526488475) + buffer.appendInt32(-1882351956) } serializeInt32(flags, buffer: buffer, boxed: false) serializeInt32(id, buffer: buffer, boxed: false) @@ -352,12 +352,7 @@ public extension Api { for item in privacy! { item.serialize(buffer, true) }} - if Int(flags) & Int(1 << 3) != 0 {buffer.appendInt32(481674261) - buffer.appendInt32(Int32(recentViewers!.count)) - for item in recentViewers! { - serializeInt64(item, buffer: buffer, boxed: false) - }} - if Int(flags) & Int(1 << 3) != 0 {serializeInt32(viewsCount!, buffer: buffer, boxed: false)} + if Int(flags) & Int(1 << 3) != 0 {views!.serialize(buffer, true)} break case .storyItemDeleted(let id): if boxed { @@ -370,8 +365,8 @@ public extension Api { public func descriptionFields() -> (String, [(String, Any)]) { switch self { - case .storyItem(let flags, let id, let date, let caption, let entities, let media, let privacy, let recentViewers, let viewsCount): - return ("storyItem", [("flags", flags as Any), ("id", id as Any), ("date", date as Any), ("caption", caption as Any), ("entities", entities as Any), ("media", media as Any), ("privacy", privacy as Any), ("recentViewers", recentViewers as Any), ("viewsCount", viewsCount as Any)]) + case .storyItem(let flags, let id, let date, let caption, let entities, let media, let privacy, let views): + return ("storyItem", [("flags", flags as Any), ("id", id as Any), ("date", date as Any), ("caption", caption as Any), ("entities", entities as Any), ("media", media as Any), ("privacy", privacy as Any), ("views", views as Any)]) case .storyItemDeleted(let id): return ("storyItemDeleted", [("id", id as Any)]) } @@ -398,12 +393,10 @@ public extension Api { if Int(_1!) & Int(1 << 2) != 0 {if let _ = reader.readInt32() { _7 = Api.parseVector(reader, elementSignature: 0, elementType: Api.PrivacyRule.self) } } - var _8: [Int64]? - if Int(_1!) & Int(1 << 3) != 0 {if let _ = reader.readInt32() { - _8 = Api.parseVector(reader, elementSignature: 570911930, elementType: Int64.self) + var _8: Api.StoryViews? + if Int(_1!) & Int(1 << 3) != 0 {if let signature = reader.readInt32() { + _8 = Api.parse(reader, signature: signature) as? Api.StoryViews } } - var _9: Int32? - if Int(_1!) & Int(1 << 3) != 0 {_9 = reader.readInt32() } let _c1 = _1 != nil let _c2 = _2 != nil let _c3 = _3 != nil @@ -412,9 +405,8 @@ public extension Api { let _c6 = _6 != nil let _c7 = (Int(_1!) & Int(1 << 2) == 0) || _7 != nil let _c8 = (Int(_1!) & Int(1 << 3) == 0) || _8 != nil - let _c9 = (Int(_1!) & Int(1 << 3) == 0) || _9 != nil - if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 && _c8 && _c9 { - return Api.StoryItem.storyItem(flags: _1!, id: _2!, date: _3!, caption: _4, entities: _5, media: _6!, privacy: _7, recentViewers: _8, viewsCount: _9) + if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 && _c8 { + return Api.StoryItem.storyItem(flags: _1!, id: _2!, date: _3!, caption: _4, entities: _5, media: _6!, privacy: _7, views: _8) } else { return nil @@ -436,16 +428,16 @@ public extension Api { } public extension Api { enum StoryView: TypeConstructorDescription { - case storyView(userId: Int64, date: Int64) + case storyView(userId: Int64, date: Int32) public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { switch self { case .storyView(let userId, let date): if boxed { - buffer.appendInt32(90474706) + buffer.appendInt32(-1491424062) } serializeInt64(userId, buffer: buffer, boxed: false) - serializeInt64(date, buffer: buffer, boxed: false) + serializeInt32(date, buffer: buffer, boxed: false) break } } @@ -460,8 +452,8 @@ public extension Api { public static func parse_storyView(_ reader: BufferReader) -> StoryView? { var _1: Int64? _1 = reader.readInt64() - var _2: Int64? - _2 = reader.readInt64() + var _2: Int32? + _2 = reader.readInt32() let _c1 = _1 != nil let _c2 = _2 != nil if _c1 && _c2 { @@ -474,6 +466,52 @@ public extension Api { } } +public extension Api { + enum StoryViews: TypeConstructorDescription { + case storyViews(recentViewers: [Int64], viewsCount: Int32) + + public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .storyViews(let recentViewers, let viewsCount): + if boxed { + buffer.appendInt32(1368082392) + } + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(recentViewers.count)) + for item in recentViewers { + serializeInt64(item, buffer: buffer, boxed: false) + } + serializeInt32(viewsCount, buffer: buffer, boxed: false) + break + } + } + + public func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .storyViews(let recentViewers, let viewsCount): + return ("storyViews", [("recentViewers", recentViewers as Any), ("viewsCount", viewsCount as Any)]) + } + } + + public static func parse_storyViews(_ reader: BufferReader) -> StoryViews? { + var _1: [Int64]? + if let _ = reader.readInt32() { + _1 = Api.parseVector(reader, elementSignature: 570911930, elementType: Int64.self) + } + var _2: Int32? + _2 = reader.readInt32() + let _c1 = _1 != nil + let _c2 = _2 != nil + if _c1 && _c2 { + return Api.StoryViews.storyViews(recentViewers: _1!, viewsCount: _2!) + } + else { + return nil + } + } + + } +} public extension Api { enum TextWithEntities: TypeConstructorDescription { case textWithEntities(text: String, entities: [Api.MessageEntity]) diff --git a/submodules/TelegramApi/Sources/Api29.swift b/submodules/TelegramApi/Sources/Api29.swift index dcf6449cb9..cef4b7ef8e 100644 --- a/submodules/TelegramApi/Sources/Api29.swift +++ b/submodules/TelegramApi/Sources/Api29.swift @@ -474,6 +474,58 @@ public extension Api.stories { } } +public extension Api.stories { + enum StoryViews: TypeConstructorDescription { + case storyViews(views: [Api.StoryViews], users: [Api.User]) + + public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .storyViews(let views, let users): + if boxed { + buffer.appendInt32(-560009955) + } + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(views.count)) + for item in views { + item.serialize(buffer, true) + } + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(users.count)) + for item in users { + item.serialize(buffer, true) + } + break + } + } + + public func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .storyViews(let views, let users): + return ("storyViews", [("views", views as Any), ("users", users as Any)]) + } + } + + public static func parse_storyViews(_ reader: BufferReader) -> StoryViews? { + var _1: [Api.StoryViews]? + if let _ = reader.readInt32() { + _1 = Api.parseVector(reader, elementSignature: 0, elementType: Api.StoryViews.self) + } + var _2: [Api.User]? + if let _ = reader.readInt32() { + _2 = Api.parseVector(reader, elementSignature: 0, elementType: Api.User.self) + } + let _c1 = _1 != nil + let _c2 = _2 != nil + if _c1 && _c2 { + return Api.stories.StoryViews.storyViews(views: _1!, users: _2!) + } + else { + return nil + } + } + + } +} public extension Api.stories { enum StoryViewsList: TypeConstructorDescription { case storyViewsList(count: Int32, views: [Api.StoryView], users: [Api.User]) diff --git a/submodules/TelegramApi/Sources/Api30.swift b/submodules/TelegramApi/Sources/Api30.swift index 17d3839480..c025f204e2 100644 --- a/submodules/TelegramApi/Sources/Api30.swift +++ b/submodules/TelegramApi/Sources/Api30.swift @@ -8508,14 +8508,53 @@ public extension Api.functions.stories { } } public extension Api.functions.stories { - static func getStoryViews(id: Int32, offsetDate: Int32, offsetId: Int32, limit: Int32) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + static func getStoriesByID(userId: Api.InputUser, id: [Int32]) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { let buffer = Buffer() - buffer.appendInt32(-2075944968) + buffer.appendInt32(1779814214) + userId.serialize(buffer, true) + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(id.count)) + for item in id { + serializeInt32(item, buffer: buffer, boxed: false) + } + return (FunctionDescription(name: "stories.getStoriesByID", parameters: [("userId", String(describing: userId)), ("id", String(describing: id))]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.stories.Stories? in + let reader = BufferReader(buffer) + var result: Api.stories.Stories? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.stories.Stories + } + return result + }) + } +} +public extension Api.functions.stories { + static func getStoriesViews(id: [Int32]) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(-1703553370) + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(id.count)) + for item in id { + serializeInt32(item, buffer: buffer, boxed: false) + } + return (FunctionDescription(name: "stories.getStoriesViews", parameters: [("id", String(describing: id))]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.stories.StoryViews? in + let reader = BufferReader(buffer) + var result: Api.stories.StoryViews? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.stories.StoryViews + } + return result + }) + } +} +public extension Api.functions.stories { + static func getStoryViewsList(id: Int32, offsetDate: Int32, offsetId: Int64, limit: Int32) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(1262182039) serializeInt32(id, buffer: buffer, boxed: false) serializeInt32(offsetDate, buffer: buffer, boxed: false) - serializeInt32(offsetId, buffer: buffer, boxed: false) + serializeInt64(offsetId, buffer: buffer, boxed: false) serializeInt32(limit, buffer: buffer, boxed: false) - return (FunctionDescription(name: "stories.getStoryViews", parameters: [("id", String(describing: id)), ("offsetDate", String(describing: offsetDate)), ("offsetId", String(describing: offsetId)), ("limit", String(describing: limit))]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.stories.StoryViewsList? in + return (FunctionDescription(name: "stories.getStoryViewsList", parameters: [("id", String(describing: id)), ("offsetDate", String(describing: offsetDate)), ("offsetId", String(describing: offsetId)), ("limit", String(describing: limit))]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.stories.StoryViewsList? in let reader = BufferReader(buffer) var result: Api.stories.StoryViewsList? if let signature = reader.readInt32() { diff --git a/submodules/TelegramCore/Sources/Network/FetchV2.swift b/submodules/TelegramCore/Sources/Network/FetchV2.swift index d695b025a8..830e96ddfc 100644 --- a/submodules/TelegramCore/Sources/Network/FetchV2.swift +++ b/submodules/TelegramCore/Sources/Network/FetchV2.swift @@ -191,6 +191,7 @@ private final class FetchImpl { private final class Impl { private let queue: Queue + private let accountPeerId: PeerId private let postbox: Postbox private let network: Network private let mediaReferenceRevalidationContext: MediaReferenceRevalidationContext? @@ -220,6 +221,7 @@ private final class FetchImpl { init( queue: Queue, + accountPeerId: PeerId, postbox: Postbox, network: Network, mediaReferenceRevalidationContext: MediaReferenceRevalidationContext?, @@ -237,6 +239,7 @@ private final class FetchImpl { ) { self.queue = queue + self.accountPeerId = accountPeerId self.postbox = postbox self.network = network self.mediaReferenceRevalidationContext = mediaReferenceRevalidationContext @@ -471,6 +474,7 @@ private final class FetchImpl { let fetchLocation = state.fetchLocation state.disposable = (revalidateMediaResourceReference( + accountPeerId: self.accountPeerId, postbox: self.postbox, network: self.network, revalidationContext: mediaReferenceRevalidationContext, @@ -716,6 +720,7 @@ private final class FetchImpl { init( + accountPeerId: PeerId, postbox: Postbox, network: Network, mediaReferenceRevalidationContext: MediaReferenceRevalidationContext?, @@ -736,6 +741,7 @@ private final class FetchImpl { self.impl = QueueLocalObject(queue: queue, generate: { return Impl( queue: queue, + accountPeerId: accountPeerId, postbox: postbox, network: network, mediaReferenceRevalidationContext: mediaReferenceRevalidationContext, @@ -756,6 +762,7 @@ private final class FetchImpl { } func multipartFetchV2( + accountPeerId: PeerId, postbox: Postbox, network: Network, mediaReferenceRevalidationContext: MediaReferenceRevalidationContext?, @@ -771,6 +778,7 @@ func multipartFetchV2( ) -> Signal { return Signal { subscriber in let impl = FetchImpl( + accountPeerId: accountPeerId, postbox: postbox, network: network, mediaReferenceRevalidationContext: mediaReferenceRevalidationContext, diff --git a/submodules/TelegramCore/Sources/Network/FetchedMediaResource.swift b/submodules/TelegramCore/Sources/Network/FetchedMediaResource.swift index 84b2b2d3e5..70f51b3807 100644 --- a/submodules/TelegramCore/Sources/Network/FetchedMediaResource.swift +++ b/submodules/TelegramCore/Sources/Network/FetchedMediaResource.swift @@ -307,6 +307,7 @@ private enum MediaReferenceRevalidationKey: Hashable { case attachBot(peer: PeerReference) case notificationSoundList case customEmoji(fileId: Int64) + case story(peer: PeerReference, id: Int32) } private final class MediaReferenceRevalidationItemContext { @@ -658,6 +659,31 @@ final class MediaReferenceRevalidationContext { } } + func story(accountPeerId: PeerId, postbox: Postbox, network: Network, background: Bool, peer: PeerReference, id: Int32) -> Signal { + return self.genericItem(key: .story(peer: peer, id: id), background: background, request: { next, error in + return (_internal_getStoryById(accountPeerId: accountPeerId, postbox: postbox, network: network, peer: peer, id: id) + |> castError(RevalidateMediaReferenceError.self) + |> mapToSignal { result -> Signal in + if let result = result { + return .single(result) + } else { + return .fail(.generic) + } + }).start(next: { value in + next(value) + }, error: { _ in + error(.generic) + }) + }) + |> mapToSignal { next -> Signal in + if let next = next as? StoryListContext.Item { + return .single(next) + } else { + return .fail(.generic) + } + } + } + func notificationSoundList(postbox: Postbox, network: Network, background: Bool) -> Signal<[TelegramMediaFile], RevalidateMediaReferenceError> { return self.genericItem(key: .notificationSoundList, background: background, request: { next, error in return (requestNotificationSoundList(network: network, hash: 0) @@ -682,7 +708,7 @@ struct RevalidatedMediaResource { let updatedReference: MediaResourceReference? } -func revalidateMediaResourceReference(postbox: Postbox, network: Network, revalidationContext: MediaReferenceRevalidationContext, info: TelegramCloudMediaResourceFetchInfo, resource: MediaResource) -> Signal { +func revalidateMediaResourceReference(accountPeerId: PeerId, postbox: Postbox, network: Network, revalidationContext: MediaReferenceRevalidationContext, info: TelegramCloudMediaResourceFetchInfo, resource: MediaResource) -> Signal { var updatedReference = info.reference if case let .media(media, resource) = updatedReference { if case let .message(messageReference, mediaValue) = media { @@ -805,6 +831,14 @@ func revalidateMediaResourceReference(postbox: Postbox, network: Network, revali } return .fail(.generic) } + case let .story(peer, id, _): + return revalidationContext.story(accountPeerId: accountPeerId, postbox: postbox, network: network, background: info.preferBackgroundReferenceRevalidation, peer: peer, id: id) + |> mapToSignal { storyItem -> Signal in + if let updatedResource = findUpdatedMediaResource(media: storyItem.media._asMedia(), previousMedia: nil, resource: resource) { + return .single(RevalidatedMediaResource(updatedResource: updatedResource, updatedReference: nil)) + } + return .fail(.generic) + } case let .standalone(media): if let file = media as? TelegramMediaFile { for attribute in file.attributes { diff --git a/submodules/TelegramCore/Sources/Network/MultipartFetch.swift b/submodules/TelegramCore/Sources/Network/MultipartFetch.swift index 3bd4c3dbe0..6fe352baf3 100644 --- a/submodules/TelegramCore/Sources/Network/MultipartFetch.swift +++ b/submodules/TelegramCore/Sources/Network/MultipartFetch.swift @@ -473,6 +473,7 @@ private final class MultipartFetchManager { var completeSize: Int64? var completeSizeReported = false + let accountPeerId: PeerId let postbox: Postbox let network: Network let networkStatsContext: NetworkStatsContext? @@ -505,7 +506,7 @@ private final class MultipartFetchManager { private var fetchSpeedRecords: [FetchSpeedRecord] = [] private var totalFetchedByteCount: Int = 0 - init(resource: TelegramMediaResource, parameters: MediaResourceFetchParameters?, size: Int64?, intervals: Signal<[(Range, MediaBoxFetchPriority)], NoError>, encryptionKey: SecretFileEncryptionKey?, decryptedSize: Int64?, location: MultipartFetchMasterLocation, postbox: Postbox, network: Network, networkStatsContext: NetworkStatsContext?, revalidationContext: MediaReferenceRevalidationContext?, partReady: @escaping (Int64, Data) -> Void, reportCompleteSize: @escaping (Int64) -> Void, finishWithError: @escaping (MediaResourceDataFetchError) -> Void, useMainConnection: Bool) { + init(resource: TelegramMediaResource, parameters: MediaResourceFetchParameters?, size: Int64?, intervals: Signal<[(Range, MediaBoxFetchPriority)], NoError>, encryptionKey: SecretFileEncryptionKey?, decryptedSize: Int64?, location: MultipartFetchMasterLocation, accountPeerId: PeerId, postbox: Postbox, network: Network, networkStatsContext: NetworkStatsContext?, revalidationContext: MediaReferenceRevalidationContext?, partReady: @escaping (Int64, Data) -> Void, reportCompleteSize: @escaping (Int64) -> Void, finishWithError: @escaping (MediaResourceDataFetchError) -> Void, useMainConnection: Bool) { self.resource = resource self.parameters = parameters self.consumerId = Int64.random(in: Int64.min ... Int64.max) @@ -555,6 +556,7 @@ private final class MultipartFetchManager { } self.state = MultipartDownloadState(encryptionKey: encryptionKey, decryptedSize: decryptedSize) + self.accountPeerId = accountPeerId self.postbox = postbox self.network = network self.networkStatsContext = networkStatsContext @@ -836,7 +838,7 @@ private final class MultipartFetchManager { strongSelf.fetchingParts.removeAll() if let info = strongSelf.parameters?.info as? TelegramCloudMediaResourceFetchInfo, let revalidationContext = strongSelf.revalidationContext { - strongSelf.revalidateMediaReferenceDisposable.set((revalidateMediaResourceReference(postbox: strongSelf.postbox, network: strongSelf.network, revalidationContext: revalidationContext, info: info, resource: strongSelf.resource) + strongSelf.revalidateMediaReferenceDisposable.set((revalidateMediaResourceReference(accountPeerId: strongSelf.accountPeerId, postbox: strongSelf.postbox, network: strongSelf.network, revalidationContext: revalidationContext, info: info, resource: strongSelf.resource) |> deliverOn(strongSelf.queue)).start(next: { validationResult in if let strongSelf = self { strongSelf.revalidatingMediaReference = false @@ -897,8 +899,9 @@ private final class MultipartFetchManager { } } -public func standaloneMultipartFetch(postbox: Postbox, network: Network, resource: TelegramMediaResource, datacenterId: Int, size: Int64?, intervals: Signal<[(Range, MediaBoxFetchPriority)], NoError>, parameters: MediaResourceFetchParameters?, encryptionKey: SecretFileEncryptionKey? = nil, decryptedSize: Int32? = nil, continueInBackground: Bool = false, useMainConnection: Bool = false) -> Signal { +public func standaloneMultipartFetch(accountPeerId: PeerId, postbox: Postbox, network: Network, resource: TelegramMediaResource, datacenterId: Int, size: Int64?, intervals: Signal<[(Range, MediaBoxFetchPriority)], NoError>, parameters: MediaResourceFetchParameters?, encryptionKey: SecretFileEncryptionKey? = nil, decryptedSize: Int32? = nil, continueInBackground: Bool = false, useMainConnection: Bool = false) -> Signal { return multipartFetch( + accountPeerId: accountPeerId, postbox: postbox, network: network, mediaReferenceRevalidationContext: nil, @@ -921,6 +924,7 @@ public func resourceFetchInfo(resource: TelegramMediaResource) -> MediaResourceF } private func multipartFetchV1( + accountPeerId: PeerId, postbox: Postbox, network: Network, mediaReferenceRevalidationContext: MediaReferenceRevalidationContext?, @@ -992,7 +996,7 @@ private func multipartFetchV1( subscriber.putNext(.reset) } - let manager = MultipartFetchManager(resource: resource, parameters: parameters, size: size, intervals: intervals, encryptionKey: encryptionKey, decryptedSize: decryptedSize, location: location, postbox: postbox, network: network, networkStatsContext: networkStatsContext, revalidationContext: mediaReferenceRevalidationContext, partReady: { dataOffset, data in + let manager = MultipartFetchManager(resource: resource, parameters: parameters, size: size, intervals: intervals, encryptionKey: encryptionKey, decryptedSize: decryptedSize, location: location, accountPeerId: accountPeerId, postbox: postbox, network: network, networkStatsContext: networkStatsContext, revalidationContext: mediaReferenceRevalidationContext, partReady: { dataOffset, data in subscriber.putNext(.dataPart(resourceOffset: dataOffset, data: data, range: 0 ..< Int64(data.count), complete: false)) }, reportCompleteSize: { size in subscriber.putNext(.resourceSizeUpdated(size)) @@ -1013,6 +1017,7 @@ private func multipartFetchV1( } func multipartFetch( + accountPeerId: PeerId, postbox: Postbox, network: Network, mediaReferenceRevalidationContext: MediaReferenceRevalidationContext?, @@ -1029,6 +1034,7 @@ func multipartFetch( ) -> Signal { if network.useExperimentalFeatures, let _ = resource as? TelegramCloudMediaResource, !(resource is SecretFileMediaResource) { return multipartFetchV2( + accountPeerId: accountPeerId, postbox: postbox, network: network, mediaReferenceRevalidationContext: mediaReferenceRevalidationContext, @@ -1044,6 +1050,7 @@ func multipartFetch( ) } return multipartFetchV1( + accountPeerId: accountPeerId, postbox: postbox, network: network, mediaReferenceRevalidationContext: mediaReferenceRevalidationContext, diff --git a/submodules/TelegramCore/Sources/PendingMessages/PendingMessageUploadedContent.swift b/submodules/TelegramCore/Sources/PendingMessages/PendingMessageUploadedContent.swift index a2b7c6add1..1fad085335 100644 --- a/submodules/TelegramCore/Sources/PendingMessages/PendingMessageUploadedContent.swift +++ b/submodules/TelegramCore/Sources/PendingMessages/PendingMessageUploadedContent.swift @@ -52,11 +52,11 @@ enum MessageContentToUpload { } } -func messageContentToUpload(network: Network, postbox: Postbox, auxiliaryMethods: AccountAuxiliaryMethods, transformOutgoingMessageMedia: TransformOutgoingMessageMedia?, messageMediaPreuploadManager: MessageMediaPreuploadManager, revalidationContext: MediaReferenceRevalidationContext, forceReupload: Bool, isGrouped: Bool, message: Message) -> MessageContentToUpload { - return messageContentToUpload(network: network, postbox: postbox, auxiliaryMethods: auxiliaryMethods, transformOutgoingMessageMedia: transformOutgoingMessageMedia, messageMediaPreuploadManager: messageMediaPreuploadManager, revalidationContext: revalidationContext, forceReupload: forceReupload, isGrouped: isGrouped, peerId: message.id.peerId, messageId: message.id, attributes: message.attributes, text: message.text, media: message.media) +func messageContentToUpload(accountPeerId: PeerId, network: Network, postbox: Postbox, auxiliaryMethods: AccountAuxiliaryMethods, transformOutgoingMessageMedia: TransformOutgoingMessageMedia?, messageMediaPreuploadManager: MessageMediaPreuploadManager, revalidationContext: MediaReferenceRevalidationContext, forceReupload: Bool, isGrouped: Bool, message: Message) -> MessageContentToUpload { + return messageContentToUpload(accountPeerId: accountPeerId, network: network, postbox: postbox, auxiliaryMethods: auxiliaryMethods, transformOutgoingMessageMedia: transformOutgoingMessageMedia, messageMediaPreuploadManager: messageMediaPreuploadManager, revalidationContext: revalidationContext, forceReupload: forceReupload, isGrouped: isGrouped, peerId: message.id.peerId, messageId: message.id, attributes: message.attributes, text: message.text, media: message.media) } -func messageContentToUpload(network: Network, postbox: Postbox, auxiliaryMethods: AccountAuxiliaryMethods, transformOutgoingMessageMedia: TransformOutgoingMessageMedia?, messageMediaPreuploadManager: MessageMediaPreuploadManager, revalidationContext: MediaReferenceRevalidationContext, forceReupload: Bool, isGrouped: Bool, peerId: PeerId, messageId: MessageId?, attributes: [MessageAttribute], text: String, media: [Media]) -> MessageContentToUpload { +func messageContentToUpload(accountPeerId: PeerId, network: Network, postbox: Postbox, auxiliaryMethods: AccountAuxiliaryMethods, transformOutgoingMessageMedia: TransformOutgoingMessageMedia?, messageMediaPreuploadManager: MessageMediaPreuploadManager, revalidationContext: MediaReferenceRevalidationContext, forceReupload: Bool, isGrouped: Bool, peerId: PeerId, messageId: MessageId?, attributes: [MessageAttribute], text: String, media: [Media]) -> MessageContentToUpload { var contextResult: OutgoingChatContextResultMessageAttribute? var autoremoveMessageAttribute: AutoremoveTimeoutMessageAttribute? var autoclearMessageAttribute: AutoclearTimeoutMessageAttribute? @@ -87,14 +87,14 @@ func messageContentToUpload(network: Network, postbox: Postbox, auxiliaryMethods return .immediate(.content(PendingMessageUploadedContentAndReuploadInfo(content: .forward(forwardInfo), reuploadInfo: nil, cacheReferenceKey: nil)), .text) } else if let contextResult = contextResult { return .immediate(.content(PendingMessageUploadedContentAndReuploadInfo(content: .chatContextResult(contextResult), reuploadInfo: nil, cacheReferenceKey: nil)), .text) - } else if let media = media.first, let mediaResult = mediaContentToUpload(network: network, postbox: postbox, auxiliaryMethods: auxiliaryMethods, transformOutgoingMessageMedia: transformOutgoingMessageMedia, messageMediaPreuploadManager: messageMediaPreuploadManager, revalidationContext: revalidationContext, forceReupload: forceReupload, isGrouped: isGrouped, peerId: peerId, media: media, text: text, autoremoveMessageAttribute: autoremoveMessageAttribute, autoclearMessageAttribute: autoclearMessageAttribute, messageId: messageId, attributes: attributes) { + } else if let media = media.first, let mediaResult = mediaContentToUpload(accountPeerId: accountPeerId, network: network, postbox: postbox, auxiliaryMethods: auxiliaryMethods, transformOutgoingMessageMedia: transformOutgoingMessageMedia, messageMediaPreuploadManager: messageMediaPreuploadManager, revalidationContext: revalidationContext, forceReupload: forceReupload, isGrouped: isGrouped, peerId: peerId, media: media, text: text, autoremoveMessageAttribute: autoremoveMessageAttribute, autoclearMessageAttribute: autoclearMessageAttribute, messageId: messageId, attributes: attributes) { return .signal(mediaResult, .media) } else { return .signal(.single(.content(PendingMessageUploadedContentAndReuploadInfo(content: .text(text), reuploadInfo: nil, cacheReferenceKey: nil))), .text) } } -func mediaContentToUpload(network: Network, postbox: Postbox, auxiliaryMethods: AccountAuxiliaryMethods, transformOutgoingMessageMedia: TransformOutgoingMessageMedia?, messageMediaPreuploadManager: MessageMediaPreuploadManager, revalidationContext: MediaReferenceRevalidationContext, forceReupload: Bool, isGrouped: Bool, peerId: PeerId, media: Media, text: String, autoremoveMessageAttribute: AutoremoveTimeoutMessageAttribute?, autoclearMessageAttribute: AutoclearTimeoutMessageAttribute?, messageId: MessageId?, attributes: [MessageAttribute]) -> Signal? { +func mediaContentToUpload(accountPeerId: PeerId, network: Network, postbox: Postbox, auxiliaryMethods: AccountAuxiliaryMethods, transformOutgoingMessageMedia: TransformOutgoingMessageMedia?, messageMediaPreuploadManager: MessageMediaPreuploadManager, revalidationContext: MediaReferenceRevalidationContext, forceReupload: Bool, isGrouped: Bool, peerId: PeerId, media: Media, text: String, autoremoveMessageAttribute: AutoremoveTimeoutMessageAttribute?, autoclearMessageAttribute: AutoclearTimeoutMessageAttribute?, messageId: MessageId?, attributes: [MessageAttribute]) -> Signal? { if let image = media as? TelegramMediaImage, let largest = largestImageRepresentation(image.representations) { if peerId.namespace == Namespaces.Peer.SecretChat, let resource = largest.resource as? SecretFileMediaResource { return .single(.content(PendingMessageUploadedContentAndReuploadInfo(content: .secretMedia(.inputEncryptedFile(id: resource.fileId, accessHash: resource.accessHash), resource.decryptedSize, resource.key), reuploadInfo: nil, cacheReferenceKey: nil))) @@ -123,7 +123,7 @@ func mediaContentToUpload(network: Network, postbox: Postbox, auxiliaryMethods: } else { mediaReference = .savedGif(media: file) } - return revalidateMediaResourceReference(postbox: postbox, network: network, revalidationContext: revalidationContext, info: TelegramCloudMediaResourceFetchInfo(reference: mediaReference.resourceReference(file.resource), preferBackgroundReferenceRevalidation: false, continueInBackground: false), resource: resource) + return revalidateMediaResourceReference(accountPeerId: accountPeerId, postbox: postbox, network: network, revalidationContext: revalidationContext, info: TelegramCloudMediaResourceFetchInfo(reference: mediaReference.resourceReference(file.resource), preferBackgroundReferenceRevalidation: false, continueInBackground: false), resource: resource) |> mapError { _ -> PendingMessageUploadError in return .generic } diff --git a/submodules/TelegramCore/Sources/PendingMessages/PendingUpdateMessageManager.swift b/submodules/TelegramCore/Sources/PendingMessages/PendingUpdateMessageManager.swift index 175e05f812..5c53c72480 100644 --- a/submodules/TelegramCore/Sources/PendingMessages/PendingUpdateMessageManager.swift +++ b/submodules/TelegramCore/Sources/PendingMessages/PendingUpdateMessageManager.swift @@ -75,7 +75,7 @@ private final class PendingUpdateMessageManagerImpl { self.contexts[messageId] = context let queue = self.queue - disposable.set((requestEditMessage(postbox: self.postbox, network: self.network, stateManager: self.stateManager, transformOutgoingMessageMedia: self.transformOutgoingMessageMedia, messageMediaPreuploadManager: self.messageMediaPreuploadManager, mediaReferenceRevalidationContext: self.mediaReferenceRevalidationContext, messageId: messageId, text: text, media: media, entities: entities, inlineStickers: inlineStickers, disableUrlPreview: disableUrlPreview, scheduleTime: nil) + disposable.set((requestEditMessage(accountPeerId: self.stateManager.accountPeerId, postbox: self.postbox, network: self.network, stateManager: self.stateManager, transformOutgoingMessageMedia: self.transformOutgoingMessageMedia, messageMediaPreuploadManager: self.messageMediaPreuploadManager, mediaReferenceRevalidationContext: self.mediaReferenceRevalidationContext, messageId: messageId, text: text, media: media, entities: entities, inlineStickers: inlineStickers, disableUrlPreview: disableUrlPreview, scheduleTime: nil) |> deliverOn(self.queue)).start(next: { [weak self, weak context] value in queue.async { guard let strongSelf = self, let initialContext = context else { diff --git a/submodules/TelegramCore/Sources/PendingMessages/RequestEditMessage.swift b/submodules/TelegramCore/Sources/PendingMessages/RequestEditMessage.swift index 529ce2b8f3..64b6f1a2b0 100644 --- a/submodules/TelegramCore/Sources/PendingMessages/RequestEditMessage.swift +++ b/submodules/TelegramCore/Sources/PendingMessages/RequestEditMessage.swift @@ -28,14 +28,14 @@ public enum RequestEditMessageError { } func _internal_requestEditMessage(account: Account, messageId: MessageId, text: String, media: RequestEditMessageMedia, entities: TextEntitiesMessageAttribute?, inlineStickers: [MediaId: Media], disableUrlPreview: Bool = false, scheduleTime: Int32? = nil) -> Signal { - return requestEditMessage(postbox: account.postbox, network: account.network, stateManager: account.stateManager, transformOutgoingMessageMedia: account.transformOutgoingMessageMedia, messageMediaPreuploadManager: account.messageMediaPreuploadManager, mediaReferenceRevalidationContext: account.mediaReferenceRevalidationContext, messageId: messageId, text: text, media: media, entities: entities, inlineStickers: inlineStickers, disableUrlPreview: disableUrlPreview, scheduleTime: scheduleTime) + return requestEditMessage(accountPeerId: account.peerId, postbox: account.postbox, network: account.network, stateManager: account.stateManager, transformOutgoingMessageMedia: account.transformOutgoingMessageMedia, messageMediaPreuploadManager: account.messageMediaPreuploadManager, mediaReferenceRevalidationContext: account.mediaReferenceRevalidationContext, messageId: messageId, text: text, media: media, entities: entities, inlineStickers: inlineStickers, disableUrlPreview: disableUrlPreview, scheduleTime: scheduleTime) } -func requestEditMessage(postbox: Postbox, network: Network, stateManager: AccountStateManager, transformOutgoingMessageMedia: TransformOutgoingMessageMedia?, messageMediaPreuploadManager: MessageMediaPreuploadManager, mediaReferenceRevalidationContext: MediaReferenceRevalidationContext, messageId: MessageId, text: String, media: RequestEditMessageMedia, entities: TextEntitiesMessageAttribute?, inlineStickers: [MediaId: Media], disableUrlPreview: Bool, scheduleTime: Int32?) -> Signal { - return requestEditMessageInternal(postbox: postbox, network: network, stateManager: stateManager, transformOutgoingMessageMedia: transformOutgoingMessageMedia, messageMediaPreuploadManager: messageMediaPreuploadManager, mediaReferenceRevalidationContext: mediaReferenceRevalidationContext, messageId: messageId, text: text, media: media, entities: entities, inlineStickers: inlineStickers, disableUrlPreview: disableUrlPreview, scheduleTime: scheduleTime, forceReupload: false) +func requestEditMessage(accountPeerId: PeerId, postbox: Postbox, network: Network, stateManager: AccountStateManager, transformOutgoingMessageMedia: TransformOutgoingMessageMedia?, messageMediaPreuploadManager: MessageMediaPreuploadManager, mediaReferenceRevalidationContext: MediaReferenceRevalidationContext, messageId: MessageId, text: String, media: RequestEditMessageMedia, entities: TextEntitiesMessageAttribute?, inlineStickers: [MediaId: Media], disableUrlPreview: Bool, scheduleTime: Int32?) -> Signal { + return requestEditMessageInternal(accountPeerId: accountPeerId, postbox: postbox, network: network, stateManager: stateManager, transformOutgoingMessageMedia: transformOutgoingMessageMedia, messageMediaPreuploadManager: messageMediaPreuploadManager, mediaReferenceRevalidationContext: mediaReferenceRevalidationContext, messageId: messageId, text: text, media: media, entities: entities, inlineStickers: inlineStickers, disableUrlPreview: disableUrlPreview, scheduleTime: scheduleTime, forceReupload: false) |> `catch` { error -> Signal in if case .invalidReference = error { - return requestEditMessageInternal(postbox: postbox, network: network, stateManager: stateManager, transformOutgoingMessageMedia: transformOutgoingMessageMedia, messageMediaPreuploadManager: messageMediaPreuploadManager, mediaReferenceRevalidationContext: mediaReferenceRevalidationContext, messageId: messageId, text: text, media: media, entities: entities, inlineStickers: inlineStickers, disableUrlPreview: disableUrlPreview, scheduleTime: scheduleTime, forceReupload: true) + return requestEditMessageInternal(accountPeerId: accountPeerId, postbox: postbox, network: network, stateManager: stateManager, transformOutgoingMessageMedia: transformOutgoingMessageMedia, messageMediaPreuploadManager: messageMediaPreuploadManager, mediaReferenceRevalidationContext: mediaReferenceRevalidationContext, messageId: messageId, text: text, media: media, entities: entities, inlineStickers: inlineStickers, disableUrlPreview: disableUrlPreview, scheduleTime: scheduleTime, forceReupload: true) } else { return .fail(error) } @@ -50,7 +50,7 @@ func requestEditMessage(postbox: Postbox, network: Network, stateManager: Accoun } } -private func requestEditMessageInternal(postbox: Postbox, network: Network, stateManager: AccountStateManager, transformOutgoingMessageMedia: TransformOutgoingMessageMedia?, messageMediaPreuploadManager: MessageMediaPreuploadManager, mediaReferenceRevalidationContext: MediaReferenceRevalidationContext, messageId: MessageId, text: String, media: RequestEditMessageMedia, entities: TextEntitiesMessageAttribute?, inlineStickers: [MediaId: Media], disableUrlPreview: Bool, scheduleTime: Int32?, forceReupload: Bool) -> Signal { +private func requestEditMessageInternal(accountPeerId: PeerId, postbox: Postbox, network: Network, stateManager: AccountStateManager, transformOutgoingMessageMedia: TransformOutgoingMessageMedia?, messageMediaPreuploadManager: MessageMediaPreuploadManager, mediaReferenceRevalidationContext: MediaReferenceRevalidationContext, messageId: MessageId, text: String, media: RequestEditMessageMedia, entities: TextEntitiesMessageAttribute?, inlineStickers: [MediaId: Media], disableUrlPreview: Bool, scheduleTime: Int32?, forceReupload: Bool) -> Signal { let uploadedMedia: Signal switch media { case .keep: @@ -59,7 +59,7 @@ private func requestEditMessageInternal(postbox: Postbox, network: Network, stat case let .update(media): let generateUploadSignal: (Bool) -> Signal? = { forceReupload in let augmentedMedia = augmentMediaWithReference(media) - return mediaContentToUpload(network: network, postbox: postbox, auxiliaryMethods: stateManager.auxiliaryMethods, transformOutgoingMessageMedia: transformOutgoingMessageMedia, messageMediaPreuploadManager: messageMediaPreuploadManager, revalidationContext: mediaReferenceRevalidationContext, forceReupload: forceReupload, isGrouped: false, peerId: messageId.peerId, media: augmentedMedia, text: "", autoremoveMessageAttribute: nil, autoclearMessageAttribute: nil, messageId: nil, attributes: []) + return mediaContentToUpload(accountPeerId: accountPeerId, network: network, postbox: postbox, auxiliaryMethods: stateManager.auxiliaryMethods, transformOutgoingMessageMedia: transformOutgoingMessageMedia, messageMediaPreuploadManager: messageMediaPreuploadManager, revalidationContext: mediaReferenceRevalidationContext, forceReupload: forceReupload, isGrouped: false, peerId: messageId.peerId, media: augmentedMedia, text: "", autoremoveMessageAttribute: nil, autoclearMessageAttribute: nil, messageId: nil, attributes: []) } if let uploadSignal = generateUploadSignal(forceReupload) { uploadedMedia = .single(.progress(0.027)) diff --git a/submodules/TelegramCore/Sources/State/AccountStateManagementUtils.swift b/submodules/TelegramCore/Sources/State/AccountStateManagementUtils.swift index 2e2dbfe767..74f309b39d 100644 --- a/submodules/TelegramCore/Sources/State/AccountStateManagementUtils.swift +++ b/submodules/TelegramCore/Sources/State/AccountStateManagementUtils.swift @@ -4333,62 +4333,10 @@ func replayFinalState( case .userStories(let userId, let stories), .userStoriesSlice(_, let userId, let stories): let peerId = PeerId(namespace: Namespaces.Peer.CloudUser, id: PeerId.Id._internalFromInt64Value(userId)) for storyItem in stories { - switch storyItem { - case let .storyItemDeleted(id): - storyUpdates.append(InternalStoryUpdate.deleted(id)) - case let .storyItem(flags, id, date, _, _, media, privacy, recentViewers, viewCount): - let _ = flags - let (parsedMedia, _, _, _) = textMediaAndExpirationTimerFromApiMedia(media, peerId) - if let parsedMedia = parsedMedia { - var seenPeers: [EnginePeer] = [] - if let recentViewers = recentViewers { - for id in recentViewers { - if let peer = transaction.getPeer(PeerId(namespace: Namespaces.Peer.CloudUser, id: PeerId.Id._internalFromInt64Value(id))) { - seenPeers.append(EnginePeer(peer)) - } - } - } - - var parsedPrivacy: EngineStoryPrivacy? - if let privacy = privacy { - var base: EngineStoryPrivacy.Base = .everyone - var additionalPeerIds: [EnginePeer.Id] = [] - for rule in privacy { - switch rule { - case .privacyValueAllowAll: - base = .everyone - case .privacyValueAllowContacts: - base = .contacts - case .privacyValueAllowCloseFriends: - base = .closeFriends - case let .privacyValueAllowUsers(users): - for id in users { - additionalPeerIds.append(EnginePeer.Id(namespace: Namespaces.Peer.CloudUser, id: EnginePeer.Id.Id._internalFromInt64Value(id))) - } - case let .privacyValueAllowChatParticipants(chats): - for id in chats { - if let peer = transaction.getPeer(EnginePeer.Id(namespace: Namespaces.Peer.CloudGroup, id: EnginePeer.Id.Id._internalFromInt64Value(id))) { - additionalPeerIds.append(peer.id) - } else if let peer = transaction.getPeer(EnginePeer.Id(namespace: Namespaces.Peer.CloudChannel, id: EnginePeer.Id.Id._internalFromInt64Value(id))) { - additionalPeerIds.append(peer.id) - } - } - default: - break - } - } - parsedPrivacy = EngineStoryPrivacy(base: base, additionallyIncludePeers: additionalPeerIds) - } - - storyUpdates.append(InternalStoryUpdate.added(peerId: peerId, item: StoryListContext.Item( - id: id, - timestamp: date, - media: EngineMedia(parsedMedia), - seenCount: viewCount.flatMap(Int.init) ?? 0, - seenPeers: seenPeers, - privacy: parsedPrivacy - ))) - } + if let parsedItem = _internal_parseApiStoryItem(transaction: transaction, peerId: peerId, apiStory: storyItem) { + storyUpdates.append(InternalStoryUpdate.added(peerId: peerId, item: parsedItem)) + } else { + storyUpdates.append(InternalStoryUpdate.deleted(peerId: peerId, id: storyItem.id)) } } } diff --git a/submodules/TelegramCore/Sources/State/AccountTaskManager.swift b/submodules/TelegramCore/Sources/State/AccountTaskManager.swift index 2b070fcf86..40e2e003b4 100644 --- a/submodules/TelegramCore/Sources/State/AccountTaskManager.swift +++ b/submodules/TelegramCore/Sources/State/AccountTaskManager.swift @@ -7,6 +7,7 @@ import TelegramApi final class AccountTaskManager { private final class Impl { private let queue: Queue + private let accountPeerId: PeerId private let stateManager: AccountStateManager private let accountManager: AccountManager private let networkArguments: NetworkInitializationArguments @@ -22,9 +23,10 @@ final class AccountTaskManager { private var isUpdating: Bool = false - init(queue: Queue, stateManager: AccountStateManager, accountManager: AccountManager, + init(queue: Queue, accountPeerId: PeerId, stateManager: AccountStateManager, accountManager: AccountManager, networkArguments: NetworkInitializationArguments, viewTracker: AccountViewTracker, mediaReferenceRevalidationContext: MediaReferenceRevalidationContext, isMainApp: Bool, testingEnvironment: Bool) { self.queue = queue + self.accountPeerId = accountPeerId self.stateManager = stateManager self.accountManager = accountManager self.networkArguments = networkArguments @@ -73,9 +75,9 @@ final class AccountTaskManager { tasks.add(managedSynchronizeInstalledStickerPacksOperations(postbox: self.stateManager.postbox, network: self.stateManager.network, stateManager: self.stateManager, namespace: .masks).start()) tasks.add(managedSynchronizeInstalledStickerPacksOperations(postbox: self.stateManager.postbox, network: self.stateManager.network, stateManager: self.stateManager, namespace: .emoji).start()) tasks.add(managedSynchronizeMarkFeaturedStickerPacksAsSeenOperations(postbox: self.stateManager.postbox, network: self.stateManager.network).start()) - tasks.add(managedSynchronizeRecentlyUsedMediaOperations(postbox: self.stateManager.postbox, network: self.stateManager.network, category: .stickers, revalidationContext: self.mediaReferenceRevalidationContext).start()) - tasks.add(managedSynchronizeSavedGifsOperations(postbox: self.stateManager.postbox, network: self.stateManager.network, revalidationContext: self.mediaReferenceRevalidationContext).start()) - tasks.add(managedSynchronizeSavedStickersOperations(postbox: self.stateManager.postbox, network: self.stateManager.network, revalidationContext: self.mediaReferenceRevalidationContext).start()) + tasks.add(managedSynchronizeRecentlyUsedMediaOperations(accountPeerId: self.accountPeerId, postbox: self.stateManager.postbox, network: self.stateManager.network, category: .stickers, revalidationContext: self.mediaReferenceRevalidationContext).start()) + tasks.add(managedSynchronizeSavedGifsOperations(accountPeerId: self.accountPeerId, postbox: self.stateManager.postbox, network: self.stateManager.network, revalidationContext: self.mediaReferenceRevalidationContext).start()) + tasks.add(managedSynchronizeSavedStickersOperations(accountPeerId: self.accountPeerId, postbox: self.stateManager.postbox, network: self.stateManager.network, revalidationContext: self.mediaReferenceRevalidationContext).start()) tasks.add(_internal_managedRecentlyUsedInlineBots(postbox: self.stateManager.postbox, network: self.stateManager.network, accountPeerId: self.stateManager.accountPeerId).start()) tasks.add(managedSynchronizeConsumeMessageContentOperations(postbox: self.stateManager.postbox, network: self.stateManager.network, stateManager: self.stateManager).start()) tasks.add(managedConsumePersonalMessagesActions(postbox: self.stateManager.postbox, network: self.stateManager.network, stateManager: self.stateManager).start()) @@ -146,7 +148,7 @@ final class AccountTaskManager { let queue = Account.sharedQueue self.queue = queue self.impl = QueueLocalObject(queue: queue, generate: { - return Impl(queue: queue, stateManager: stateManager, accountManager: accountManager, networkArguments: networkArguments, viewTracker: viewTracker, mediaReferenceRevalidationContext: mediaReferenceRevalidationContext, isMainApp: isMainApp, testingEnvironment: testingEnvironment) + return Impl(queue: queue, accountPeerId: stateManager.accountPeerId, stateManager: stateManager, accountManager: accountManager, networkArguments: networkArguments, viewTracker: viewTracker, mediaReferenceRevalidationContext: mediaReferenceRevalidationContext, isMainApp: isMainApp, testingEnvironment: testingEnvironment) }) } } diff --git a/submodules/TelegramCore/Sources/State/Fetch.swift b/submodules/TelegramCore/Sources/State/Fetch.swift index 831354282a..22e1683026 100644 --- a/submodules/TelegramCore/Sources/State/Fetch.swift +++ b/submodules/TelegramCore/Sources/State/Fetch.swift @@ -23,7 +23,7 @@ private final class MediaResourceDataCopyFile : MediaResourceDataFetchCopyLocalI } public func fetchCloudMediaLocation(account: Account, resource: TelegramMediaResource, datacenterId: Int, size: Int64?, intervals: Signal<[(Range, MediaBoxFetchPriority)], NoError>, parameters: MediaResourceFetchParameters?) -> Signal { - return multipartFetch(postbox: account.postbox, network: account.network, mediaReferenceRevalidationContext: account.mediaReferenceRevalidationContext, networkStatsContext: account.networkStatsContext, resource: resource, datacenterId: datacenterId, size: size, intervals: intervals, parameters: parameters) + return multipartFetch(accountPeerId: account.peerId, postbox: account.postbox, network: account.network, mediaReferenceRevalidationContext: account.mediaReferenceRevalidationContext, networkStatsContext: account.networkStatsContext, resource: resource, datacenterId: datacenterId, size: size, intervals: intervals, parameters: parameters) } private func fetchLocalFileResource(path: String, move: Bool) -> Signal { diff --git a/submodules/TelegramCore/Sources/State/FetchSecretFileResource.swift b/submodules/TelegramCore/Sources/State/FetchSecretFileResource.swift index 13491cbbf3..7784f5ac42 100644 --- a/submodules/TelegramCore/Sources/State/FetchSecretFileResource.swift +++ b/submodules/TelegramCore/Sources/State/FetchSecretFileResource.swift @@ -5,5 +5,5 @@ import MtProtoKit func fetchSecretFileResource(account: Account, resource: SecretFileMediaResource, intervals: Signal<[(Range, MediaBoxFetchPriority)], NoError>, parameters: MediaResourceFetchParameters?) -> Signal { - return multipartFetch(postbox: account.postbox, network: account.network, mediaReferenceRevalidationContext: account.mediaReferenceRevalidationContext, networkStatsContext: account.networkStatsContext, resource: resource, datacenterId: resource.datacenterId, size: resource.size, intervals: intervals, parameters: parameters, encryptionKey: resource.key, decryptedSize: resource.decryptedSize) + return multipartFetch(accountPeerId: account.peerId, postbox: account.postbox, network: account.network, mediaReferenceRevalidationContext: account.mediaReferenceRevalidationContext, networkStatsContext: account.networkStatsContext, resource: resource, datacenterId: resource.datacenterId, size: resource.size, intervals: intervals, parameters: parameters, encryptionKey: resource.key, decryptedSize: resource.decryptedSize) } diff --git a/submodules/TelegramCore/Sources/State/ManagedSynchronizeRecentlyUsedMediaOperations.swift b/submodules/TelegramCore/Sources/State/ManagedSynchronizeRecentlyUsedMediaOperations.swift index 8ba6b7bce0..d5949cfe7a 100644 --- a/submodules/TelegramCore/Sources/State/ManagedSynchronizeRecentlyUsedMediaOperations.swift +++ b/submodules/TelegramCore/Sources/State/ManagedSynchronizeRecentlyUsedMediaOperations.swift @@ -65,7 +65,7 @@ private func withTakenOperation(postbox: Postbox, peerId: PeerId, tag: PeerOpera } |> switchToLatest } -func managedSynchronizeRecentlyUsedMediaOperations(postbox: Postbox, network: Network, category: RecentlyUsedMediaCategory, revalidationContext: MediaReferenceRevalidationContext) -> Signal { +func managedSynchronizeRecentlyUsedMediaOperations(accountPeerId: PeerId, postbox: Postbox, network: Network, category: RecentlyUsedMediaCategory, revalidationContext: MediaReferenceRevalidationContext) -> Signal { return Signal { _ in let tag: PeerOperationLogTag switch category { @@ -88,7 +88,7 @@ func managedSynchronizeRecentlyUsedMediaOperations(postbox: Postbox, network: Ne let signal = withTakenOperation(postbox: postbox, peerId: entry.peerId, tag: tag, tagLocalIndex: entry.tagLocalIndex, { transaction, entry -> Signal in if let entry = entry { if let operation = entry.contents as? SynchronizeRecentlyUsedMediaOperation { - return synchronizeRecentlyUsedMedia(transaction: transaction, postbox: postbox, network: network, revalidationContext: revalidationContext, operation: operation) + return synchronizeRecentlyUsedMedia(transaction: transaction, accountPeerId: accountPeerId, postbox: postbox, network: network, revalidationContext: revalidationContext, operation: operation) } else { assertionFailure() } @@ -120,7 +120,7 @@ private enum SaveRecentlyUsedMediaError { case invalidReference } -private func synchronizeRecentlyUsedMedia(transaction: Transaction, postbox: Postbox, network: Network, revalidationContext: MediaReferenceRevalidationContext, operation: SynchronizeRecentlyUsedMediaOperation) -> Signal { +private func synchronizeRecentlyUsedMedia(transaction: Transaction, accountPeerId: PeerId, postbox: Postbox, network: Network, revalidationContext: MediaReferenceRevalidationContext, operation: SynchronizeRecentlyUsedMediaOperation) -> Signal { switch operation.content { case let .add(id, accessHash, fileReference): guard let fileReference = fileReference else { @@ -150,7 +150,7 @@ private func synchronizeRecentlyUsedMedia(transaction: Transaction, postbox: Pos case .generic: return .fail(.generic) case .invalidReference: - return revalidateMediaResourceReference(postbox: postbox, network: network, revalidationContext: revalidationContext, info: TelegramCloudMediaResourceFetchInfo(reference: fileReference.resourceReference(fileReference.media.resource), preferBackgroundReferenceRevalidation: false, continueInBackground: false), resource: fileReference.media.resource) + return revalidateMediaResourceReference(accountPeerId: accountPeerId, postbox: postbox, network: network, revalidationContext: revalidationContext, info: TelegramCloudMediaResourceFetchInfo(reference: fileReference.resourceReference(fileReference.media.resource), preferBackgroundReferenceRevalidation: false, continueInBackground: false), resource: fileReference.media.resource) |> mapError { _ -> SaveRecentlyUsedMediaError in return .generic } diff --git a/submodules/TelegramCore/Sources/State/ManagedSynchronizeSavedGifsOperations.swift b/submodules/TelegramCore/Sources/State/ManagedSynchronizeSavedGifsOperations.swift index d3eb590859..88e02c3f81 100644 --- a/submodules/TelegramCore/Sources/State/ManagedSynchronizeSavedGifsOperations.swift +++ b/submodules/TelegramCore/Sources/State/ManagedSynchronizeSavedGifsOperations.swift @@ -49,7 +49,7 @@ private final class ManagedSynchronizeSavedGifsOperationsHelper { } } -private func withTakenOperation(postbox: Postbox, peerId: PeerId, tag: PeerOperationLogTag, tagLocalIndex: Int32, _ f: @escaping (Transaction, PeerMergedOperationLogEntry?) -> Signal) -> Signal { +private func withTakenOperation(accountPeerId: PeerId, postbox: Postbox, peerId: PeerId, tag: PeerOperationLogTag, tagLocalIndex: Int32, _ f: @escaping (Transaction, PeerMergedOperationLogEntry?) -> Signal) -> Signal { return postbox.transaction { transaction -> Signal in var result: PeerMergedOperationLogEntry? transaction.operationLogUpdateEntry(peerId: peerId, tag: tag, tagLocalIndex: tagLocalIndex, { entry in @@ -65,7 +65,7 @@ private func withTakenOperation(postbox: Postbox, peerId: PeerId, tag: PeerOpera } |> switchToLatest } -func managedSynchronizeSavedGifsOperations(postbox: Postbox, network: Network, revalidationContext: MediaReferenceRevalidationContext) -> Signal { +func managedSynchronizeSavedGifsOperations(accountPeerId: PeerId, postbox: Postbox, network: Network, revalidationContext: MediaReferenceRevalidationContext) -> Signal { return Signal { _ in let tag: PeerOperationLogTag = OperationLogTags.SynchronizeSavedGifs @@ -81,10 +81,10 @@ func managedSynchronizeSavedGifsOperations(postbox: Postbox, network: Network, r } for (entry, disposable) in beginOperations { - let signal = withTakenOperation(postbox: postbox, peerId: entry.peerId, tag: tag, tagLocalIndex: entry.tagLocalIndex, { transaction, entry -> Signal in + let signal = withTakenOperation(accountPeerId: accountPeerId, postbox: postbox, peerId: entry.peerId, tag: tag, tagLocalIndex: entry.tagLocalIndex, { transaction, entry -> Signal in if let entry = entry { if let operation = entry.contents as? SynchronizeSavedGifsOperation { - return synchronizeSavedGifs(transaction: transaction, postbox: postbox, network: network, revalidationContext: revalidationContext, operation: operation) + return synchronizeSavedGifs(transaction: transaction, accountPeerId: accountPeerId, postbox: postbox, network: network, revalidationContext: revalidationContext, operation: operation) } else { assertionFailure() } @@ -116,7 +116,7 @@ private enum SaveGifError { case invalidReference } -private func synchronizeSavedGifs(transaction: Transaction, postbox: Postbox, network: Network, revalidationContext: MediaReferenceRevalidationContext, operation: SynchronizeSavedGifsOperation) -> Signal { +private func synchronizeSavedGifs(transaction: Transaction, accountPeerId: PeerId, postbox: Postbox, network: Network, revalidationContext: MediaReferenceRevalidationContext, operation: SynchronizeSavedGifsOperation) -> Signal { switch operation.content { case let .add(id, accessHash, fileReference): guard let fileReference = fileReference else { @@ -146,7 +146,7 @@ private func synchronizeSavedGifs(transaction: Transaction, postbox: Postbox, ne case .generic: return .fail(.generic) case .invalidReference: - return revalidateMediaResourceReference(postbox: postbox, network: network, revalidationContext: revalidationContext, info: TelegramCloudMediaResourceFetchInfo(reference: fileReference.resourceReference(fileReference.media.resource), preferBackgroundReferenceRevalidation: false, continueInBackground: false), resource: fileReference.media.resource) + return revalidateMediaResourceReference(accountPeerId: accountPeerId, postbox: postbox, network: network, revalidationContext: revalidationContext, info: TelegramCloudMediaResourceFetchInfo(reference: fileReference.resourceReference(fileReference.media.resource), preferBackgroundReferenceRevalidation: false, continueInBackground: false), resource: fileReference.media.resource) |> mapError { _ -> SaveGifError in return .generic } diff --git a/submodules/TelegramCore/Sources/State/ManagedSynchronizeSavedStickersOperations.swift b/submodules/TelegramCore/Sources/State/ManagedSynchronizeSavedStickersOperations.swift index 179ebd4170..369acdbc31 100644 --- a/submodules/TelegramCore/Sources/State/ManagedSynchronizeSavedStickersOperations.swift +++ b/submodules/TelegramCore/Sources/State/ManagedSynchronizeSavedStickersOperations.swift @@ -65,7 +65,7 @@ private func withTakenOperation(postbox: Postbox, peerId: PeerId, tag: PeerOpera } |> switchToLatest } -func managedSynchronizeSavedStickersOperations(postbox: Postbox, network: Network, revalidationContext: MediaReferenceRevalidationContext) -> Signal { +func managedSynchronizeSavedStickersOperations(accountPeerId: PeerId, postbox: Postbox, network: Network, revalidationContext: MediaReferenceRevalidationContext) -> Signal { return Signal { _ in let tag: PeerOperationLogTag = OperationLogTags.SynchronizeSavedStickers @@ -84,7 +84,7 @@ func managedSynchronizeSavedStickersOperations(postbox: Postbox, network: Networ let signal = withTakenOperation(postbox: postbox, peerId: entry.peerId, tag: tag, tagLocalIndex: entry.tagLocalIndex, { transaction, entry -> Signal in if let entry = entry { if let operation = entry.contents as? SynchronizeSavedStickersOperation { - return synchronizeSavedStickers(transaction: transaction, postbox: postbox, network: network, revalidationContext: revalidationContext, operation: operation) + return synchronizeSavedStickers(transaction: transaction, accountPeerId: accountPeerId, postbox: postbox, network: network, revalidationContext: revalidationContext, operation: operation) } else { assertionFailure() } @@ -116,7 +116,7 @@ private enum SaveStickerError { case invalidReference } -private func synchronizeSavedStickers(transaction: Transaction, postbox: Postbox, network: Network, revalidationContext: MediaReferenceRevalidationContext, operation: SynchronizeSavedStickersOperation) -> Signal { +private func synchronizeSavedStickers(transaction: Transaction, accountPeerId: PeerId, postbox: Postbox, network: Network, revalidationContext: MediaReferenceRevalidationContext, operation: SynchronizeSavedStickersOperation) -> Signal { switch operation.content { case let .add(id, accessHash, fileReference): guard let fileReference = fileReference else { @@ -146,7 +146,7 @@ private func synchronizeSavedStickers(transaction: Transaction, postbox: Postbox case .generic: return .fail(.generic) case .invalidReference: - return revalidateMediaResourceReference(postbox: postbox, network: network, revalidationContext: revalidationContext, info: TelegramCloudMediaResourceFetchInfo(reference: fileReference.resourceReference(fileReference.media.resource), preferBackgroundReferenceRevalidation: false, continueInBackground: false), resource: fileReference.media.resource) + return revalidateMediaResourceReference(accountPeerId: accountPeerId, postbox: postbox, network: network, revalidationContext: revalidationContext, info: TelegramCloudMediaResourceFetchInfo(reference: fileReference.resourceReference(fileReference.media.resource), preferBackgroundReferenceRevalidation: false, continueInBackground: false), resource: fileReference.media.resource) |> mapError { _ -> SaveStickerError in return .generic } diff --git a/submodules/TelegramCore/Sources/State/PendingMessageManager.swift b/submodules/TelegramCore/Sources/State/PendingMessageManager.swift index 097328eb4d..f6d18ad042 100644 --- a/submodules/TelegramCore/Sources/State/PendingMessageManager.swift +++ b/submodules/TelegramCore/Sources/State/PendingMessageManager.swift @@ -403,7 +403,7 @@ public final class PendingMessageManager { return lhs.1.index < rhs.1.index }) { if case let .collectingInfo(message) = messageContext.state { - let contentToUpload = messageContentToUpload(network: strongSelf.network, postbox: strongSelf.postbox, auxiliaryMethods: strongSelf.auxiliaryMethods, transformOutgoingMessageMedia: strongSelf.transformOutgoingMessageMedia, messageMediaPreuploadManager: strongSelf.messageMediaPreuploadManager, revalidationContext: strongSelf.revalidationContext, forceReupload: messageContext.forcedReuploadOnce, isGrouped: message.groupingKey != nil, message: message) + let contentToUpload = messageContentToUpload(accountPeerId: strongSelf.accountPeerId, network: strongSelf.network, postbox: strongSelf.postbox, auxiliaryMethods: strongSelf.auxiliaryMethods, transformOutgoingMessageMedia: strongSelf.transformOutgoingMessageMedia, messageMediaPreuploadManager: strongSelf.messageMediaPreuploadManager, revalidationContext: strongSelf.revalidationContext, forceReupload: messageContext.forcedReuploadOnce, isGrouped: message.groupingKey != nil, message: message) messageContext.contentType = contentToUpload.type switch contentToUpload { case let .immediate(result, type): diff --git a/submodules/TelegramCore/Sources/SyncCore/SyncCore_MediaReference.swift b/submodules/TelegramCore/Sources/SyncCore/SyncCore_MediaReference.swift index c6e8cdd91c..66f409e0fd 100644 --- a/submodules/TelegramCore/Sources/SyncCore/SyncCore_MediaReference.swift +++ b/submodules/TelegramCore/Sources/SyncCore/SyncCore_MediaReference.swift @@ -251,6 +251,7 @@ public enum AnyMediaReference: Equatable { case avatarList(peer: PeerReference, media: Media) case attachBot(peer: PeerReference, media: Media) case customEmoji(media: Media) + case story(peer: PeerReference, id: Int32, media: Media) public static func ==(lhs: AnyMediaReference, rhs: AnyMediaReference) -> Bool { switch lhs { @@ -302,6 +303,12 @@ public enum AnyMediaReference: Equatable { } else { return false } + case let .story(lhsPeer, lhsId, lhsMedia): + if case let .story(rhsPeer, rhsId, rhsMedia) = rhs, lhsPeer == rhsPeer, lhsId == rhsId, lhsMedia.isEqual(to: rhsMedia) { + return true + } else { + return false + } } } @@ -323,6 +330,8 @@ public enum AnyMediaReference: Equatable { return nil case .customEmoji: return nil + case .story: + return nil } } @@ -360,6 +369,10 @@ public enum AnyMediaReference: Equatable { if let media = media as? T { return .customEmoji(media: media) } + case let .story(peer, id, media): + if let media = media as? T { + return .story(peer: peer, id: id, media: media) + } } return nil } @@ -382,6 +395,8 @@ public enum AnyMediaReference: Equatable { return media case let .customEmoji(media): return media + case let .story(_, _, media): + return media } } @@ -462,6 +477,7 @@ public enum MediaReference { case avatarList case attachBot case customEmoji + case story } case standalone(media: T) @@ -472,6 +488,7 @@ public enum MediaReference { case avatarList(peer: PeerReference, media: T) case attachBot(peer: PeerReference, media: T) case customEmoji(media: T) + case story(peer: PeerReference, id: Int32, media: T) public init?(decoder: PostboxDecoder) { guard let caseIdValue = decoder.decodeOptionalInt32ForKey("_r"), let caseId = CodingCase(rawValue: caseIdValue) else { @@ -523,6 +540,13 @@ public enum MediaReference { return nil } self = .customEmoji(media: media) + case .story: + let peer = decoder.decodeObjectForKey("pr", decoder: { PeerReference(decoder: $0) }) as! PeerReference + guard let media = decoder.decodeObjectForKey("m") as? T else { + return nil + } + let id = decoder.decodeInt32ForKey("sid", orElse: 0) + self = .story(peer: peer, id: id, media: media) } } @@ -557,6 +581,11 @@ public enum MediaReference { case let .customEmoji(media): encoder.encodeInt32(CodingCase.customEmoji.rawValue, forKey: "_r") encoder.encodeObject(media, forKey: "m") + case let .story(peer, id, media): + encoder.encodeInt32(CodingCase.story.rawValue, forKey: "_r") + encoder.encodeObject(peer, forKey: "pr") + encoder.encodeInt32(id, forKey: "sid") + encoder.encodeObject(media, forKey: "m") } } @@ -578,6 +607,8 @@ public enum MediaReference { return .attachBot(peer: peer, media: media) case let .customEmoji(media): return .customEmoji(media: media) + case let .story(peer, id, media): + return .story(peer: peer, id: id, media: media) } } @@ -603,6 +634,8 @@ public enum MediaReference { return media case let .customEmoji(media): return media + case let .story(_, _, media): + return media } } diff --git a/submodules/TelegramCore/Sources/SyncCore/SyncCore_TextEntitiesMessageAttribute.swift b/submodules/TelegramCore/Sources/SyncCore/SyncCore_TextEntitiesMessageAttribute.swift index 74dfbbc048..ec31b3f55d 100644 --- a/submodules/TelegramCore/Sources/SyncCore/SyncCore_TextEntitiesMessageAttribute.swift +++ b/submodules/TelegramCore/Sources/SyncCore/SyncCore_TextEntitiesMessageAttribute.swift @@ -255,6 +255,17 @@ public struct MessageTextEntity: PostboxCoding, Codable, Equatable { } } +extension MessageTextEntity { + var associatedPeerIds: [PeerId] { + switch self.type { + case let .TextMention(peerId): + return [peerId] + default: + return [] + } + } +} + public class TextEntitiesMessageAttribute: MessageAttribute, Equatable { public let entities: [MessageTextEntity] diff --git a/submodules/TelegramCore/Sources/TelegramEngine/Messages/Stories.swift b/submodules/TelegramCore/Sources/TelegramEngine/Messages/Stories.swift index 94c4f14062..f6c451a81a 100644 --- a/submodules/TelegramCore/Sources/TelegramEngine/Messages/Stories.swift +++ b/submodules/TelegramCore/Sources/TelegramEngine/Messages/Stories.swift @@ -24,7 +24,10 @@ public struct EngineStoryPrivacy: Equatable { } } -func _internal_uploadStory(account: Account, media: EngineStoryInputMedia, text: String?, entities: [MessageTextEntity]?, privacy: EngineStoryPrivacy) -> Signal { +func _internal_uploadStory(account: Account, media: EngineStoryInputMedia, text: String, entities: [MessageTextEntity], privacy: EngineStoryPrivacy) -> Signal { + let originalMedia: Media + let contentToUpload: MessageContentToUpload + switch media { case let .image(dimensions, data): let resource = LocalFileMediaResource(fileId: Int64.random(in: Int64.min ... Int64.max)) @@ -38,8 +41,10 @@ func _internal_uploadStory(account: Account, media: EngineStoryInputMedia, text: partialReference: nil, flags: [] ) + originalMedia = imageMedia - let contentToUpload = messageContentToUpload( + contentToUpload = messageContentToUpload( + accountPeerId: account.peerId, network: account.network, postbox: account.postbox, auxiliaryMethods: account.auxiliaryMethods, @@ -54,103 +59,6 @@ func _internal_uploadStory(account: Account, media: EngineStoryInputMedia, text: text: "", media: [imageMedia] ) - let contentSignal: Signal - switch contentToUpload { - case let .immediate(result, _): - contentSignal = .single(result) - case let .signal(signal, _): - contentSignal = signal - } - - return contentSignal - |> map(Optional.init) - |> `catch` { _ -> Signal in - return .single(nil) - } - |> mapToSignal { result -> Signal in - return account.postbox.transaction { transaction -> Signal in - var privacyRules: [Api.InputPrivacyRule] - switch privacy.base { - case .everyone: - privacyRules = [.inputPrivacyValueAllowAll] - case .contacts: - privacyRules = [.inputPrivacyValueAllowContacts] - case .closeFriends: - privacyRules = [.inputPrivacyValueAllowCloseFriends] - } - var privacyUsers: [Api.InputUser] = [] - var privacyChats: [Int64] = [] - for peerId in privacy.additionallyIncludePeers { - if let peer = transaction.getPeer(peerId) { - if let _ = peer as? TelegramUser { - if let inputUser = apiInputUser(peer) { - privacyUsers.append(inputUser) - } - } else if peer is TelegramGroup || peer is TelegramChannel { - privacyChats.append(peer.id.id._internalGetInt64Value()) - } - } - } - if !privacyUsers.isEmpty { - privacyRules.append(.inputPrivacyValueAllowUsers(users: privacyUsers)) - } - if !privacyChats.isEmpty { - privacyRules.append(.inputPrivacyValueAllowChatParticipants(chats: privacyChats)) - } - - switch result { - case let .content(content): - switch content.content { - case let .media(inputMedia, _): - var flags: Int32 = 0 - var inputEntities: [Api.MessageEntity]? - if let text = text, !text.isEmpty { - flags |= (1 << 0) - if let entities = entities, !entities.isEmpty { - flags |= (1 << 1) - inputEntities = apiEntitiesFromMessageTextEntities(entities, associatedPeers: SimpleDictionary()) - } - } - return account.network.request(Api.functions.stories.sendStory(flags: 0, media: inputMedia, caption: text, entities: inputEntities, privacyRules: privacyRules)) - |> map(Optional.init) - |> `catch` { _ -> Signal in - return .single(nil) - } - |> mapToSignal { updates -> Signal in - if let updates = updates { - for update in updates.allUpdates { - if case let .updateStories(stories) = update { - switch stories { - case .userStories(let userId, let apiStories), .userStoriesSlice(_, let userId, let apiStories): - if PeerId(namespace: Namespaces.Peer.CloudUser, id: PeerId.Id._internalFromInt64Value(userId)) == account.peerId, apiStories.count == 1 { - switch apiStories[0] { - case let .storyItem(_, _, _, _, _, media, _, _, _): - let (parsedMedia, _, _, _) = textMediaAndExpirationTimerFromApiMedia(media, account.peerId) - if let parsedMedia = parsedMedia { - applyMediaResourceChanges(from: imageMedia, to: parsedMedia, postbox: account.postbox, force: false) - } - default: - break - } - } - } - } - } - - account.stateManager.addUpdates(updates) - } - - return .complete() - } - default: - return .complete() - } - default: - return .complete() - } - } - |> switchToLatest - } case let .video(dimensions, duration, resource): let fileMedia = TelegramMediaFile( fileId: MediaId(namespace: Namespaces.Media.LocalFile, id: MediaId.Id.random(in: MediaId.Id.min ... MediaId.Id.max)), @@ -165,8 +73,10 @@ func _internal_uploadStory(account: Account, media: EngineStoryInputMedia, text: TelegramMediaFileAttribute.Video(duration: duration, size: dimensions, flags: .supportsStreaming) ] ) + originalMedia = fileMedia - let contentToUpload = messageContentToUpload( + contentToUpload = messageContentToUpload( + accountPeerId: account.peerId, network: account.network, postbox: account.postbox, auxiliaryMethods: account.auxiliaryMethods, @@ -181,94 +91,124 @@ func _internal_uploadStory(account: Account, media: EngineStoryInputMedia, text: text: "", media: [fileMedia] ) - let contentSignal: Signal - switch contentToUpload { - case let .immediate(result, _): - contentSignal = .single(result) - case let .signal(signal, _): - contentSignal = signal - } + } - return contentSignal - |> map(Optional.init) - |> `catch` { _ -> Signal in - return .single(nil) - } - |> mapToSignal { result -> Signal in - return account.postbox.transaction { transaction -> Signal in - var privacyRules: [Api.InputPrivacyRule] - switch privacy.base { - case .everyone: - privacyRules = [.inputPrivacyValueAllowAll] - case .contacts: - privacyRules = [.inputPrivacyValueAllowContacts] - case .closeFriends: - privacyRules = [.inputPrivacyValueAllowCloseFriends] - } - var privacyUsers: [Api.InputUser] = [] - var privacyChats: [Int64] = [] - for peerId in privacy.additionallyIncludePeers { - if let peer = transaction.getPeer(peerId) { - if let _ = peer as? TelegramUser { - if let inputUser = apiInputUser(peer) { - privacyUsers.append(inputUser) - } - } else if peer is TelegramGroup || peer is TelegramChannel { - privacyChats.append(peer.id.id._internalGetInt64Value()) + let contentSignal: Signal + switch contentToUpload { + case let .immediate(result, _): + contentSignal = .single(result) + case let .signal(signal, _): + contentSignal = signal + } + + return contentSignal + |> map(Optional.init) + |> `catch` { _ -> Signal in + return .single(nil) + } + |> mapToSignal { result -> Signal in + return account.postbox.transaction { transaction -> Signal in + var privacyRules: [Api.InputPrivacyRule] + switch privacy.base { + case .everyone: + privacyRules = [.inputPrivacyValueAllowAll] + case .contacts: + privacyRules = [.inputPrivacyValueAllowContacts] + case .closeFriends: + privacyRules = [.inputPrivacyValueAllowCloseFriends] + } + var privacyUsers: [Api.InputUser] = [] + var privacyChats: [Int64] = [] + for peerId in privacy.additionallyIncludePeers { + if let peer = transaction.getPeer(peerId) { + if let _ = peer as? TelegramUser { + if let inputUser = apiInputUser(peer) { + privacyUsers.append(inputUser) } + } else if peer is TelegramGroup || peer is TelegramChannel { + privacyChats.append(peer.id.id._internalGetInt64Value()) } } - if !privacyUsers.isEmpty { - privacyRules.append(.inputPrivacyValueAllowUsers(users: privacyUsers)) - } - if !privacyChats.isEmpty { - privacyRules.append(.inputPrivacyValueAllowChatParticipants(chats: privacyChats)) - } - - switch result { - case let .content(content): - switch content.content { - case let .media(inputMedia, _): - return account.network.request(Api.functions.stories.sendStory(flags: 0, media: inputMedia, caption: nil, entities: nil, privacyRules: privacyRules)) - |> map(Optional.init) - |> `catch` { _ -> Signal in - return .single(nil) + } + if !privacyUsers.isEmpty { + privacyRules.append(.inputPrivacyValueAllowUsers(users: privacyUsers)) + } + if !privacyChats.isEmpty { + privacyRules.append(.inputPrivacyValueAllowChatParticipants(chats: privacyChats)) + } + + switch result { + case let .content(content): + switch content.content { + case let .media(inputMedia, _): + var flags: Int32 = 0 + var apiCaption: String? + var apiEntities: [Api.MessageEntity]? + + if !text.isEmpty { + flags |= 1 << 0 + apiCaption = text + + if !entities.isEmpty { + flags |= 1 << 1 + + var associatedPeers: [PeerId: Peer] = [:] + for entity in entities { + for entityPeerId in entity.associatedPeerIds { + if let peer = transaction.getPeer(entityPeerId) { + associatedPeers[peer.id] = peer + } + } + } + apiEntities = apiEntitiesFromMessageTextEntities(entities, associatedPeers: SimpleDictionary(associatedPeers)) } - |> mapToSignal { updates -> Signal in - if let updates = updates { - for update in updates.allUpdates { - if case let .updateStories(stories) = update { - switch stories { - case .userStories(let userId, let apiStories), .userStoriesSlice(_, let userId, let apiStories): - if PeerId(namespace: Namespaces.Peer.CloudUser, id: PeerId.Id._internalFromInt64Value(userId)) == account.peerId, apiStories.count == 1 { - switch apiStories[0] { - case let .storyItem(_, _, _, _, _, media, _, _, _): - let (parsedMedia, _, _, _) = textMediaAndExpirationTimerFromApiMedia(media, account.peerId) - if let parsedMedia = parsedMedia { - applyMediaResourceChanges(from: fileMedia, to: parsedMedia, postbox: account.postbox, force: true) - } - default: - break + } + + return account.network.request(Api.functions.stories.sendStory( + flags: flags, + media: inputMedia, + caption: apiCaption, + entities: apiEntities, + privacyRules: privacyRules + )) + |> map(Optional.init) + |> `catch` { _ -> Signal in + return .single(nil) + } + |> mapToSignal { updates -> Signal in + if let updates = updates { + for update in updates.allUpdates { + if case let .updateStories(stories) = update { + switch stories { + case .userStories(let userId, let apiStories), .userStoriesSlice(_, let userId, let apiStories): + if PeerId(namespace: Namespaces.Peer.CloudUser, id: PeerId.Id._internalFromInt64Value(userId)) == account.peerId, apiStories.count == 1 { + switch apiStories[0] { + case let .storyItem(_, _, _, _, _, media, _, _): + let (parsedMedia, _, _, _) = textMediaAndExpirationTimerFromApiMedia(media, account.peerId) + if let parsedMedia = parsedMedia { + applyMediaResourceChanges(from: originalMedia, to: parsedMedia, postbox: account.postbox, force: false) } + default: + break } } } } - - account.stateManager.addUpdates(updates) } - return .complete() + account.stateManager.addUpdates(updates) } - default: + return .complete() } default: return .complete() } + default: + return .complete() } - |> switchToLatest } + |> switchToLatest } } @@ -300,3 +240,217 @@ func _internal_markStoryAsSeen(account: Account, peerId: PeerId, id: Int32) -> S |> ignoreValues } } + +extension Api.StoryItem { + var id: Int32 { + switch self { + case let .storyItem(_, id, _, _, _, _, _, _): + return id + case let .storyItemDeleted(id): + return id + } + } +} + +func _internal_parseApiStoryItem(transaction: Transaction, peerId: PeerId, apiStory: Api.StoryItem) -> StoryListContext.Item? { + switch apiStory { + case let .storyItem(flags, id, date, caption, entities, media, privacy, views): + let _ = flags + let (parsedMedia, _, _, _) = textMediaAndExpirationTimerFromApiMedia(media, peerId) + if let parsedMedia = parsedMedia { + var parsedPrivacy: EngineStoryPrivacy? + if let privacy = privacy { + var base: EngineStoryPrivacy.Base = .everyone + var additionalPeerIds: [EnginePeer.Id] = [] + for rule in privacy { + switch rule { + case .privacyValueAllowAll: + base = .everyone + case .privacyValueAllowContacts: + base = .contacts + case .privacyValueAllowCloseFriends: + base = .closeFriends + case let .privacyValueAllowUsers(users): + for id in users { + additionalPeerIds.append(EnginePeer.Id(namespace: Namespaces.Peer.CloudUser, id: EnginePeer.Id.Id._internalFromInt64Value(id))) + } + case let .privacyValueAllowChatParticipants(chats): + for id in chats { + if let peer = transaction.getPeer(EnginePeer.Id(namespace: Namespaces.Peer.CloudGroup, id: EnginePeer.Id.Id._internalFromInt64Value(id))) { + additionalPeerIds.append(peer.id) + } else if let peer = transaction.getPeer(EnginePeer.Id(namespace: Namespaces.Peer.CloudChannel, id: EnginePeer.Id.Id._internalFromInt64Value(id))) { + additionalPeerIds.append(peer.id) + } + } + default: + break + } + } + parsedPrivacy = EngineStoryPrivacy(base: base, additionallyIncludePeers: additionalPeerIds) + } + + let item = StoryListContext.Item( + id: id, + timestamp: date, + media: EngineMedia(parsedMedia), + text: caption ?? "", + entities: entities.flatMap { entities in return messageTextEntitiesFromApiEntities(entities) } ?? [], + views: views.flatMap { _internal_parseApiStoryViews(transaction: transaction, views: $0) }, + privacy: parsedPrivacy + ) + return item + } else { + return nil + } + case .storyItemDeleted: + return nil + } +} + +func _internal_parseApiStoryViews(transaction: Transaction, views: Api.StoryViews) -> StoryListContext.Views { + switch views { + case let .storyViews(recentViewers, viewsCount): + return StoryListContext.Views(seenCount: Int(viewsCount), seenPeers: recentViewers.compactMap { id -> EnginePeer? in + return transaction.getPeer(PeerId(namespace: Namespaces.Peer.CloudUser, id: PeerId.Id._internalFromInt64Value(id))).flatMap(EnginePeer.init) + }) + } +} + +func _internal_getStoryById(accountPeerId: PeerId, postbox: Postbox, network: Network, peer: PeerReference, id: Int32) -> Signal { + guard let inputUser = peer.inputUser else { + return .single(nil) + } + return network.request(Api.functions.stories.getStoriesByID(userId: inputUser, id: [id])) + |> map(Optional.init) + |> `catch` { _ -> Signal in + return .single(nil) + } + |> mapToSignal { result -> Signal in + guard let result else { + return .single(nil) + } + return postbox.transaction { transaction -> StoryListContext.Item? in + switch result { + case let .stories(_, stories, users): + var peers: [Peer] = [] + var peerPresences: [PeerId: Api.User] = [:] + + for user in users { + let telegramUser = TelegramUser(user: user) + peers.append(telegramUser) + peerPresences[telegramUser.id] = user + } + + updatePeers(transaction: transaction, peers: peers, update: { _, updated -> Peer in + return updated + }) + updatePeerPresences(transaction: transaction, accountPeerId: accountPeerId, peerPresences: peerPresences) + + return stories.first.flatMap { _internal_parseApiStoryItem(transaction: transaction, peerId: peer.id, apiStory: $0) } + } + } + } +} + +public final class StoryViewList { + public final class Item { + public let peer: EnginePeer + public let timestamp: Int32 + + public init(peer: EnginePeer, timestamp: Int32) { + self.peer = peer + self.timestamp = timestamp + } + } + + public let items: [Item] + public let totalCount: Int + + public init(items: [Item], totalCount: Int) { + self.items = items + self.totalCount = totalCount + } +} + +func _internal_getStoryViewList(account: Account, id: Int32, offsetTimestamp: Int32?, offsetPeerId: PeerId?, limit: Int) -> Signal { + return account.network.request(Api.functions.stories.getStoryViewsList(id: id, offsetDate: offsetTimestamp ?? 0, offsetId: offsetPeerId?.id._internalGetInt64Value() ?? 0, limit: Int32(limit))) + |> map(Optional.init) + |> `catch` { _ -> Signal in + return .single(nil) + } + |> mapToSignal { result -> Signal in + guard let result else { + return .single(nil) + } + return account.postbox.transaction { transaction -> StoryViewList? in + switch result { + case let .storyViewsList(count, views, users): + var peers: [Peer] = [] + var peerPresences: [PeerId: Api.User] = [:] + + for user in users { + let telegramUser = TelegramUser(user: user) + peers.append(telegramUser) + peerPresences[telegramUser.id] = user + } + + updatePeers(transaction: transaction, peers: peers, update: { _, updated -> Peer in + return updated + }) + updatePeerPresences(transaction: transaction, accountPeerId: account.peerId, peerPresences: peerPresences) + + var items: [StoryViewList.Item] = [] + for view in views { + switch view { + case let .storyView(userId, date): + if let peer = transaction.getPeer(PeerId(namespace: Namespaces.Peer.CloudUser, id: PeerId.Id._internalFromInt64Value(userId))) { + items.append(StoryViewList.Item(peer: EnginePeer(peer), timestamp: date)) + } + } + } + + return StoryViewList(items: items, totalCount: Int(count)) + } + } + } +} + +func _internal_getStoryViews(account: Account, ids: [Int32]) -> Signal<[Int32: StoryListContext.Views], NoError> { + return account.network.request(Api.functions.stories.getStoriesViews(id: ids)) + |> map(Optional.init) + |> `catch` { _ -> Signal in + return .single(nil) + } + |> mapToSignal { result -> Signal<[Int32: StoryListContext.Views], NoError> in + guard let result else { + return .single([:]) + } + return account.postbox.transaction { transaction -> [Int32: StoryListContext.Views] in + var parsedViews: [Int32: StoryListContext.Views] = [:] + switch result { + case let .storyViews(views, users): + var peers: [Peer] = [] + var peerPresences: [PeerId: Api.User] = [:] + + for user in users { + let telegramUser = TelegramUser(user: user) + peers.append(telegramUser) + peerPresences[telegramUser.id] = user + } + + updatePeers(transaction: transaction, peers: peers, update: { _, updated -> Peer in + return updated + }) + updatePeerPresences(transaction: transaction, accountPeerId: account.peerId, peerPresences: peerPresences) + + for i in 0 ..< views.count { + if i < ids.count { + parsedViews[ids[i]] = _internal_parseApiStoryViews(transaction: transaction, views: views[i]) + } + } + } + + return parsedViews + } + } +} diff --git a/submodules/TelegramCore/Sources/TelegramEngine/Messages/StoryListContext.swift b/submodules/TelegramCore/Sources/TelegramEngine/Messages/StoryListContext.swift index 544990ccd8..113e0c3f53 100644 --- a/submodules/TelegramCore/Sources/TelegramEngine/Messages/StoryListContext.swift +++ b/submodules/TelegramCore/Sources/TelegramEngine/Messages/StoryListContext.swift @@ -4,7 +4,7 @@ import TelegramApi import SwiftSignalKit enum InternalStoryUpdate { - case deleted(Int32) + case deleted(peerId: PeerId, id: Int32) case added(peerId: PeerId, item: StoryListContext.Item) case read(peerId: PeerId, maxId: Int32) } @@ -15,20 +15,32 @@ public final class StoryListContext { case peer(EnginePeer.Id) } + public struct Views: Equatable { + public var seenCount: Int + public var seenPeers: [EnginePeer] + + public init(seenCount: Int, seenPeers: [EnginePeer]) { + self.seenCount = seenCount + self.seenPeers = seenPeers + } + } + public final class Item: Equatable { public let id: Int32 public let timestamp: Int32 public let media: EngineMedia - public let seenCount: Int - public let seenPeers: [EnginePeer] + public let text: String + public let entities: [MessageTextEntity] + public let views: Views? public let privacy: EngineStoryPrivacy? - public init(id: Int32, timestamp: Int32, media: EngineMedia, seenCount: Int, seenPeers: [EnginePeer], privacy: EngineStoryPrivacy?) { + public init(id: Int32, timestamp: Int32, media: EngineMedia, text: String, entities: [MessageTextEntity], views: Views?, privacy: EngineStoryPrivacy?) { self.id = id self.timestamp = timestamp self.media = media - self.seenCount = seenCount - self.seenPeers = seenPeers + self.text = text + self.entities = entities + self.views = views self.privacy = privacy } @@ -42,10 +54,13 @@ public final class StoryListContext { if lhs.media != rhs.media { return false } - if lhs.seenCount != rhs.seenCount { + if lhs.text != rhs.text { return false } - if lhs.seenPeers != rhs.seenPeers { + if lhs.entities != rhs.entities { + return false + } + if lhs.views != rhs.views { return false } if lhs.privacy != rhs.privacy { @@ -207,18 +222,20 @@ public final class StoryListContext { for update in updates { switch update { - case let .deleted(id): + case let .deleted(peerId, id): for i in 0 ..< itemSets.count { - if let index = itemSets[i].items.firstIndex(where: { $0.id == id }) { - var items = itemSets[i].items - items.remove(at: index) - itemSets[i] = PeerItemSet( - peerId: itemSets[i].peerId, - peer: itemSets[i].peer, - maxReadId: itemSets[i].maxReadId, - items: items, - totalCount: items.count - ) + if itemSets[i].peerId == peerId { + if let index = itemSets[i].items.firstIndex(where: { $0.id == id }) { + var items = itemSets[i].items + items.remove(at: index) + itemSets[i] = PeerItemSet( + peerId: itemSets[i].peerId, + peer: itemSets[i].peer, + maxReadId: itemSets[i].maxReadId, + items: items, + totalCount: items.count + ) + } } } case let .added(peerId, item): @@ -232,18 +249,7 @@ public final class StoryListContext { items.remove(at: index) } - if peerId == self.account.peerId { - items.append(Item( - id: item.id, - timestamp: item.timestamp, - media: item.media, - seenCount: item.seenCount, - seenPeers: item.seenPeers, - privacy: item.privacy - )) - } else { - items.append(item) - } + items.append(item) items.sort(by: { lhsItem, rhsItem in if lhsItem.timestamp != rhsItem.timestamp { @@ -367,68 +373,13 @@ public final class StoryListContext { let peerId = id for apiStory in apiStories { - switch apiStory { - case let .storyItem(flags, id, date, _, _, media, privacy, recentViewers, viewCount): - let _ = flags - let (parsedMedia, _, _, _) = textMediaAndExpirationTimerFromApiMedia(media, peerId) - if let parsedMedia = parsedMedia { - var seenPeers: [EnginePeer] = [] - if let recentViewers = recentViewers { - for id in recentViewers { - if let peer = transaction.getPeer(PeerId(namespace: Namespaces.Peer.CloudUser, id: PeerId.Id._internalFromInt64Value(id))) { - seenPeers.append(EnginePeer(peer)) - } - } - } - - var parsedPrivacy: EngineStoryPrivacy? - if let privacy = privacy { - var base: EngineStoryPrivacy.Base = .everyone - var additionalPeerIds: [EnginePeer.Id] = [] - for rule in privacy { - switch rule { - case .privacyValueAllowAll: - base = .everyone - case .privacyValueAllowContacts: - base = .contacts - case .privacyValueAllowCloseFriends: - base = .closeFriends - case let .privacyValueAllowUsers(users): - for id in users { - additionalPeerIds.append(EnginePeer.Id(namespace: Namespaces.Peer.CloudUser, id: EnginePeer.Id.Id._internalFromInt64Value(id))) - } - case let .privacyValueAllowChatParticipants(chats): - for id in chats { - if let peer = transaction.getPeer(EnginePeer.Id(namespace: Namespaces.Peer.CloudGroup, id: EnginePeer.Id.Id._internalFromInt64Value(id))) { - additionalPeerIds.append(peer.id) - } else if let peer = transaction.getPeer(EnginePeer.Id(namespace: Namespaces.Peer.CloudChannel, id: EnginePeer.Id.Id._internalFromInt64Value(id))) { - additionalPeerIds.append(peer.id) - } - } - default: - break - } - } - parsedPrivacy = EngineStoryPrivacy(base: base, additionallyIncludePeers: additionalPeerIds) - } - - let item = StoryListContext.Item( - id: id, - timestamp: date, - media: EngineMedia(parsedMedia), - seenCount: viewCount.flatMap(Int.init) ?? 0, - seenPeers: seenPeers, - privacy: parsedPrivacy - ) - if !parsedItemSets.isEmpty && parsedItemSets[parsedItemSets.count - 1].peerId == peerId { - parsedItemSets[parsedItemSets.count - 1].items.append(item) - parsedItemSets[parsedItemSets.count - 1].totalCount = parsedItemSets[parsedItemSets.count - 1].items.count - } else { - parsedItemSets.append(StoryListContext.PeerItemSet(peerId: peerId, peer: transaction.getPeer(peerId).flatMap(EnginePeer.init), maxReadId: 0, items: [item], totalCount: 1)) - } + if let item = _internal_parseApiStoryItem(transaction: transaction, peerId: peerId, apiStory: apiStory) { + if !parsedItemSets.isEmpty && parsedItemSets[parsedItemSets.count - 1].peerId == peerId { + parsedItemSets[parsedItemSets.count - 1].items.append(item) + parsedItemSets[parsedItemSets.count - 1].totalCount = parsedItemSets[parsedItemSets.count - 1].items.count + } else { + parsedItemSets.append(StoryListContext.PeerItemSet(peerId: peerId, peer: transaction.getPeer(peerId).flatMap(EnginePeer.init), maxReadId: 0, items: [item], totalCount: 1)) } - case .storyItemDeleted: - break } } @@ -450,7 +401,7 @@ public final class StoryListContext { } } - func upload(media: EngineStoryInputMedia, text: String?, entities: [MessageTextEntity]?, privacy: EngineStoryPrivacy) { + func upload(media: EngineStoryInputMedia, text: String, entities: [MessageTextEntity], privacy: EngineStoryPrivacy) { let uploadContext = UploadContext() self.uploadContexts.append(uploadContext) uploadContext.disposable.set((_internal_uploadStory(account: self.account, media: media, text: text, entities: entities, privacy: privacy) @@ -530,73 +481,18 @@ public final class StoryListContext { let peerId = PeerId(namespace: Namespaces.Peer.CloudUser, id: PeerId.Id._internalFromInt64Value(apiUserId)) for apiStory in apiStories { - switch apiStory { - case let .storyItem(flags, id, date, _, _, media, privacy, recentViewers, viewCount): - let _ = flags - let (parsedMedia, _, _, _) = textMediaAndExpirationTimerFromApiMedia(media, peerId) - if let parsedMedia = parsedMedia { - var seenPeers: [EnginePeer] = [] - if let recentViewers = recentViewers { - for id in recentViewers { - if let peer = transaction.getPeer(PeerId(namespace: Namespaces.Peer.CloudUser, id: PeerId.Id._internalFromInt64Value(id))) { - seenPeers.append(EnginePeer(peer)) - } - } - } - - var parsedPrivacy: EngineStoryPrivacy? - if let privacy = privacy { - var base: EngineStoryPrivacy.Base = .everyone - var additionalPeerIds: [EnginePeer.Id] = [] - for rule in privacy { - switch rule { - case .privacyValueAllowAll: - base = .everyone - case .privacyValueAllowContacts: - base = .contacts - case .privacyValueAllowCloseFriends: - base = .closeFriends - case let .privacyValueAllowUsers(users): - for id in users { - additionalPeerIds.append(EnginePeer.Id(namespace: Namespaces.Peer.CloudUser, id: EnginePeer.Id.Id._internalFromInt64Value(id))) - } - case let .privacyValueAllowChatParticipants(chats): - for id in chats { - if let peer = transaction.getPeer(EnginePeer.Id(namespace: Namespaces.Peer.CloudGroup, id: EnginePeer.Id.Id._internalFromInt64Value(id))) { - additionalPeerIds.append(peer.id) - } else if let peer = transaction.getPeer(EnginePeer.Id(namespace: Namespaces.Peer.CloudChannel, id: EnginePeer.Id.Id._internalFromInt64Value(id))) { - additionalPeerIds.append(peer.id) - } - } - default: - break - } - } - parsedPrivacy = EngineStoryPrivacy(base: base, additionallyIncludePeers: additionalPeerIds) - } - - let item = StoryListContext.Item( - id: id, - timestamp: date, - media: EngineMedia(parsedMedia), - seenCount: viewCount.flatMap(Int.init) ?? 0, - seenPeers: seenPeers, - privacy: parsedPrivacy - ) - if !parsedItemSets.isEmpty && parsedItemSets[parsedItemSets.count - 1].peerId == peerId { - parsedItemSets[parsedItemSets.count - 1].items.append(item) - } else { - parsedItemSets.append(StoryListContext.PeerItemSet( - peerId: peerId, - peer: transaction.getPeer(peerId).flatMap(EnginePeer.init), - maxReadId: 0, - items: [item], - totalCount: apiTotalCount.flatMap(Int.init) - )) - } + if let item = _internal_parseApiStoryItem(transaction: transaction, peerId: peerId, apiStory: apiStory) { + if !parsedItemSets.isEmpty && parsedItemSets[parsedItemSets.count - 1].peerId == peerId { + parsedItemSets[parsedItemSets.count - 1].items.append(item) + } else { + parsedItemSets.append(StoryListContext.PeerItemSet( + peerId: peerId, + peer: transaction.getPeer(peerId).flatMap(EnginePeer.init), + maxReadId: 0, + items: [item], + totalCount: apiTotalCount.flatMap(Int.init) + )) } - case .storyItemDeleted: - break } } } @@ -721,7 +617,7 @@ public final class StoryListContext { } } - public func upload(media: EngineStoryInputMedia, text: String?, entities: [MessageTextEntity]?, privacy: EngineStoryPrivacy) { + public func upload(media: EngineStoryInputMedia, text: String, entities: [MessageTextEntity], privacy: EngineStoryPrivacy) { self.impl.with { impl in impl.upload(media: media, text: text, entities: entities, privacy: privacy) } diff --git a/submodules/TelegramCore/Sources/TelegramEngine/Messages/TelegramEngineMessages.swift b/submodules/TelegramCore/Sources/TelegramEngine/Messages/TelegramEngineMessages.swift index ccb004edea..8073859ad6 100644 --- a/submodules/TelegramCore/Sources/TelegramEngine/Messages/TelegramEngineMessages.swift +++ b/submodules/TelegramCore/Sources/TelegramEngine/Messages/TelegramEngineMessages.swift @@ -577,7 +577,7 @@ public extension TelegramEngine { return StoryListContext(account: self.account, scope: .peer(id)) } - public func uploadStory(media: EngineStoryInputMedia, text: String?, entities: [MessageTextEntity]?, privacy: EngineStoryPrivacy) -> Signal { + public func uploadStory(media: EngineStoryInputMedia, text: String, entities: [MessageTextEntity], privacy: EngineStoryPrivacy) -> Signal { return _internal_uploadStory(account: self.account, media: media, text: text, entities: entities, privacy: privacy) } @@ -588,5 +588,9 @@ public extension TelegramEngine { public func markStoryAsSeen(peerId: EnginePeer.Id, id: Int32) -> Signal { return _internal_markStoryAsSeen(account: self.account, peerId: peerId, id: id) } + + public func getStoryViewList(account: Account, id: Int32, offsetTimestamp: Int32?, offsetPeerId: PeerId?, limit: Int) -> Signal { + return _internal_getStoryViewList(account: account, id: id, offsetTimestamp: offsetTimestamp, offsetPeerId: offsetPeerId, limit: limit) + } } } diff --git a/submodules/TelegramCore/Sources/TelegramEngine/Peers/NotificationSoundList.swift b/submodules/TelegramCore/Sources/TelegramEngine/Peers/NotificationSoundList.swift index 77238d619d..ce0e9ea56c 100644 --- a/submodules/TelegramCore/Sources/TelegramEngine/Peers/NotificationSoundList.swift +++ b/submodules/TelegramCore/Sources/TelegramEngine/Peers/NotificationSoundList.swift @@ -268,10 +268,11 @@ func _internal_saveNotificationSound(account: Account, file: FileMediaReference, guard let resource = file.media.resource as? CloudDocumentMediaResource else { return .fail(.generic) } + let accountPeerId = account.peerId return account.network.request(Api.functions.account.saveRingtone(id: .inputDocument(id: resource.fileId, accessHash: resource.accessHash, fileReference: Buffer(data: resource.fileReference)), unsave: unsave ? .boolTrue : .boolFalse)) |> `catch` { error -> Signal in if error.errorDescription == "FILE_REFERENCE_EXPIRED" { - return revalidateMediaResourceReference(postbox: account.postbox, network: account.network, revalidationContext: account.mediaReferenceRevalidationContext, info: TelegramCloudMediaResourceFetchInfo(reference: file.abstract.resourceReference(file.media.resource), preferBackgroundReferenceRevalidation: false, continueInBackground: false), resource: file.media.resource) + return revalidateMediaResourceReference(accountPeerId: accountPeerId, postbox: account.postbox, network: account.network, revalidationContext: account.mediaReferenceRevalidationContext, info: TelegramCloudMediaResourceFetchInfo(reference: file.abstract.resourceReference(file.media.resource), preferBackgroundReferenceRevalidation: false, continueInBackground: false), resource: file.media.resource) |> mapError { _ -> MTRpcError in return MTRpcError(errorCode: 500, errorDescription: "Internal") } diff --git a/submodules/TelegramCore/Sources/TelegramEngine/Resources/TelegramEngineResources.swift b/submodules/TelegramCore/Sources/TelegramEngine/Resources/TelegramEngineResources.swift index b47f405aa9..946e6c83a6 100644 --- a/submodules/TelegramCore/Sources/TelegramEngine/Resources/TelegramEngineResources.swift +++ b/submodules/TelegramCore/Sources/TelegramEngine/Resources/TelegramEngineResources.swift @@ -353,7 +353,7 @@ public extension TelegramEngine { |> mapToSignal { datacenterId -> Signal in let resource = AlbumCoverResource(datacenterId: Int(datacenterId), file: file, title: title, performer: performer, isThumbnail: isThumbnail) - return multipartFetch(postbox: self.account.postbox, network: self.account.network, mediaReferenceRevalidationContext: self.account.mediaReferenceRevalidationContext, networkStatsContext: self.account.networkStatsContext, resource: resource, datacenterId: Int(datacenterId), size: nil, intervals: .single([(0 ..< Int64.max, .default)]), parameters: MediaResourceFetchParameters( + return multipartFetch(accountPeerId: self.account.peerId, postbox: self.account.postbox, network: self.account.network, mediaReferenceRevalidationContext: self.account.mediaReferenceRevalidationContext, networkStatsContext: self.account.networkStatsContext, resource: resource, datacenterId: Int(datacenterId), size: nil, intervals: .single([(0 ..< Int64.max, .default)]), parameters: MediaResourceFetchParameters( tag: nil, info: TelegramCloudMediaResourceFetchInfo( reference: MediaResourceReference.standalone(resource: resource), diff --git a/submodules/TelegramCore/Sources/TelegramEngine/Stickers/StickerPack.swift b/submodules/TelegramCore/Sources/TelegramEngine/Stickers/StickerPack.swift index a630f1d10d..0f5ea32a5a 100644 --- a/submodules/TelegramCore/Sources/TelegramEngine/Stickers/StickerPack.swift +++ b/submodules/TelegramCore/Sources/TelegramEngine/Stickers/StickerPack.swift @@ -75,9 +75,10 @@ func _internal_stickerPacksAttachedToMedia(account: Account, media: AnyMediaRefe } else { return .single([]) } + let accountPeerId = account.peerId return account.network.request(Api.functions.messages.getAttachedStickers(media: inputMedia)) |> `catch` { _ -> Signal<[Api.StickerSetCovered], MTRpcError> in - return revalidateMediaResourceReference(postbox: account.postbox, network: account.network, revalidationContext: account.mediaReferenceRevalidationContext, info: TelegramCloudMediaResourceFetchInfo(reference: resourceReference, preferBackgroundReferenceRevalidation: false, continueInBackground: false), resource: resourceReference.resource) + return revalidateMediaResourceReference(accountPeerId: accountPeerId, postbox: account.postbox, network: account.network, revalidationContext: account.mediaReferenceRevalidationContext, info: TelegramCloudMediaResourceFetchInfo(reference: resourceReference, preferBackgroundReferenceRevalidation: false, continueInBackground: false), resource: resourceReference.resource) |> mapError { _ -> MTRpcError in return MTRpcError(errorCode: 500, errorDescription: "Internal") } diff --git a/submodules/TelegramUI/Components/FullScreenEffectView/MetalResources/RippleEffect.metal b/submodules/TelegramUI/Components/FullScreenEffectView/MetalResources/RippleEffect.metal index 625566a593..5f1c50fb96 100644 --- a/submodules/TelegramUI/Components/FullScreenEffectView/MetalResources/RippleEffect.metal +++ b/submodules/TelegramUI/Components/FullScreenEffectView/MetalResources/RippleEffect.metal @@ -25,11 +25,11 @@ float doubleStep(float value, float lowerBound, float upperBound) { return step(lowerBound, value) * (1.0 - step(upperBound, value)); } -float fieldFunction(float2 center, float2 position, float2 dimensions, float time) { +float fieldFunction(float2 center, float contentScale, float2 position, float2 dimensions, float time) { float maxDimension = max(dimensions.x, dimensions.y); float currentDistance = time * maxDimension; - float waveWidth = 100.0f * 3.0f; + float waveWidth = 100.0f * contentScale; float d = distance(center, position); @@ -50,7 +50,8 @@ vertex RasterizerData rippleVertex device const uint2 ¢er [[buffer(0)]], device const uint2 &gridResolution [[buffer(1)]], device const uint2 &resolution [[buffer(2)]], - device const float &time [[buffer(3)]] + device const float &time [[buffer(3)]], + device const float &contentScale [[buffer(4)]] ) { uint triangleIndex = vid / 6; uint vertexIndex = vid % 6; @@ -69,7 +70,7 @@ vertex RasterizerData rippleVertex ); float2 texCoord = float2(position.x, 1.0 - position.y); - float zPosition = fieldFunction(float2(center), float2(position.x * dimensions.x, (1.0 - position.y) * dimensions.y), dimensions, time); + float zPosition = fieldFunction(float2(center), contentScale, float2(position.x * dimensions.x, (1.0 - position.y) * dimensions.y), dimensions, time); zPosition *= 0.5f; float leftEdgeDistance = abs(position.x); @@ -84,9 +85,6 @@ vertex RasterizerData rippleVertex zPosition *= edgeDistance; zPosition *= max(0.0, min(1.0, linearDecay(time, 0.7))); - if (zPosition <= 0.1) { - //zPosition = 0.0; - } float3 camPosition = float3(0.0, 0.0f, 1.0f); float3 camTarget = float3(0.0, 0.0, 0.0); @@ -147,6 +145,9 @@ fragment half4 rippleFragment( float4 rgb = float4(texture.sample(textureSampler, texCoord)); float4 out = float4(rgb.xyz, 1.0); + /*out.r = 0.0; + out.g = 0.0; + out.b = 1.0;*/ out.a = 1.0 - step(in.visibilityFraction, 0.5); diff --git a/submodules/TelegramUI/Components/FullScreenEffectView/Sources/RippleEffectView.swift b/submodules/TelegramUI/Components/FullScreenEffectView/Sources/RippleEffectView.swift index 10d867aed9..2bf06f470c 100644 --- a/submodules/TelegramUI/Components/FullScreenEffectView/Sources/RippleEffectView.swift +++ b/submodules/TelegramUI/Components/FullScreenEffectView/Sources/RippleEffectView.swift @@ -4,6 +4,9 @@ import MetalKit import simd public final class RippleEffectView: MTKView { + private let centerLocation: CGPoint + private let completion: () -> Void + private let textureLoader: MTKTextureLoader private let commandQueue: MTLCommandQueue private let drawPassthroughPipelineState: MTLRenderPipelineState @@ -11,7 +14,7 @@ public final class RippleEffectView: MTKView { private var viewportDimensions = CGSize(width: 1, height: 1) - private var time: Float = 0.0 + private var startTime: Double? private var lastUpdateTimestamp: Double? @@ -21,7 +24,10 @@ public final class RippleEffectView: MTKView { } } - public init?(test: Bool) { + public init?(centerLocation: CGPoint, completion: @escaping () -> Void) { + self.centerLocation = centerLocation + self.completion = completion + let mainBundle = Bundle(for: RippleEffectView.self) guard let path = mainBundle.path(forResource: "FullScreenEffectViewBundle", ofType: "bundle") else { @@ -135,12 +141,21 @@ public final class RippleEffectView: MTKView { } private func redraw(drawable: MTLDrawable) { - if let lastUpdateTimestamp = self.lastUpdateTimestamp { + /*if let lastUpdateTimestamp = self.lastUpdateTimestamp { if lastUpdateTimestamp + 1.0 < CACurrentMediaTime() { self.updateImageFromSourceView() } } else { self.updateImageFromSourceView() + }*/ + + let relativeTime: Double + let timestamp = CACurrentMediaTime() + if let startTime = self.startTime { + relativeTime = timestamp - startTime + } else { + self.startTime = timestamp + relativeTime = 0.0 } guard let commandBuffer = self.commandQueue.makeCommandBuffer() else { @@ -160,20 +175,20 @@ public final class RippleEffectView: MTKView { renderEncoder.setRenderPipelineState(self.drawPassthroughPipelineState) let gridSize = 1000 - var time = self.time.truncatingRemainder(dividingBy: 0.7) - //time = 0.6 - self.time += (1.0 / 60.0) * 0.1 + var time: Float = Float(min(relativeTime, 0.7)) var gridResolution = simd_uint2(UInt32(gridSize), UInt32(gridSize)) var resolution = simd_uint2(UInt32(viewportDimensions.width), UInt32(viewportDimensions.height)) - var center = simd_uint2(200, 200); + var center = simd_uint2(UInt32(self.centerLocation.x * self.contentScaleFactor), UInt32(self.centerLocation.y * self.contentScaleFactor)); if let texture = self.texture { + var contentScale: Float = Float(self.contentScaleFactor) renderEncoder.setVertexBytes(¢er, length: MemoryLayout.size, index: 0) renderEncoder.setVertexBytes(&gridResolution, length: MemoryLayout.size, index: 1) renderEncoder.setVertexBytes(&resolution, length: MemoryLayout.size, index: 2) renderEncoder.setVertexBytes(&time, length: MemoryLayout.size, index: 3) + renderEncoder.setVertexBytes(&contentScale, length: MemoryLayout.size, index: 4) renderEncoder.setFragmentTexture(texture, index: 0) @@ -184,5 +199,11 @@ public final class RippleEffectView: MTKView { commandBuffer.present(drawable) commandBuffer.commit() + + if relativeTime >= 0.7 { + //self.startTime = nil + self.isPaused = true + self.completion() + } } } diff --git a/submodules/TelegramUI/Components/Stories/StoryContentComponent/Sources/StoryChatContent.swift b/submodules/TelegramUI/Components/Stories/StoryContentComponent/Sources/StoryChatContent.swift index 596e8ff7d0..3cd6399661 100644 --- a/submodules/TelegramUI/Components/Stories/StoryContentComponent/Sources/StoryChatContent.swift +++ b/submodules/TelegramUI/Components/Stories/StoryContentComponent/Sources/StoryChatContent.swift @@ -16,6 +16,9 @@ public enum StoryChatContent { for itemSet in state.itemSets { var items: [StoryContentItem] = [] + guard let peer = itemSet.peer else { + continue + } let peerId = itemSet.peerId for item in itemSet.items { @@ -24,7 +27,7 @@ public enum StoryChatContent { position: items.count, component: AnyComponent(StoryItemContentComponent( context: context, - peerId: peerId, + peer: peer, item: item )), centerInfoComponent: AnyComponent(StoryAuthorInfoComponent( diff --git a/submodules/TelegramUI/Components/Stories/StoryContentComponent/Sources/StoryItemContentComponent.swift b/submodules/TelegramUI/Components/Stories/StoryContentComponent/Sources/StoryItemContentComponent.swift index 3302cc94ff..3fb49ee36a 100644 --- a/submodules/TelegramUI/Components/Stories/StoryContentComponent/Sources/StoryItemContentComponent.swift +++ b/submodules/TelegramUI/Components/Stories/StoryContentComponent/Sources/StoryItemContentComponent.swift @@ -16,12 +16,12 @@ final class StoryItemContentComponent: Component { typealias EnvironmentType = StoryContentItem.Environment let context: AccountContext - let peerId: EnginePeer.Id + let peer: EnginePeer let item: StoryListContext.Item - init(context: AccountContext, peerId: EnginePeer.Id, item: StoryListContext.Item) { + init(context: AccountContext, peer: EnginePeer, item: StoryListContext.Item) { self.context = context - self.peerId = peerId + self.peer = peer self.item = item } @@ -29,7 +29,7 @@ final class StoryItemContentComponent: Component { if lhs.context !== rhs.context { return false } - if lhs.peerId != rhs.peerId { + if lhs.peer != rhs.peer { return false } if lhs.item != rhs.item { @@ -144,7 +144,7 @@ final class StoryItemContentComponent: Component { return } - if case let .file(file) = currentMessageMedia { + if case let .file(file) = currentMessageMedia, let peerReference = PeerReference(component.peer._asPeer()) { if self.videoNode == nil { let videoNode = UniversalVideoNode( postbox: component.context.account.postbox, @@ -154,7 +154,7 @@ final class StoryItemContentComponent: Component { content: NativeVideoContent( id: .message(0, file.fileId), userLocation: .other, - fileReference: .standalone(media: file), + fileReference: .story(peer: peerReference, id: component.item.id, media: file), imageReference: nil, loopVideo: true, enableSound: true, @@ -224,7 +224,7 @@ final class StoryItemContentComponent: Component { if !self.markedAsSeen { self.markedAsSeen = true if let component = self.component { - let _ = component.context.engine.messages.markStoryAsSeen(peerId: component.peerId, id: component.item.id).start() + let _ = component.context.engine.messages.markStoryAsSeen(peerId: component.peer.id, id: component.item.id).start() } } @@ -293,7 +293,7 @@ final class StoryItemContentComponent: Component { if !self.markedAsSeen { self.markedAsSeen = true if let component = self.component { - let _ = component.context.engine.messages.markStoryAsSeen(peerId: component.peerId, id: component.item.id).start() + let _ = component.context.engine.messages.markStoryAsSeen(peerId: component.peer.id, id: component.item.id).start() } } } @@ -308,6 +308,8 @@ final class StoryItemContentComponent: Component { self.state = state self.environment = environment[StoryContentItem.Environment.self].value + let peerReference = PeerReference(component.peer._asPeer()) + var messageMedia: EngineMedia? switch component.item.media { case let .image(image): @@ -324,7 +326,7 @@ final class StoryItemContentComponent: Component { reloadMedia = true } - if reloadMedia, let messageMedia { + if reloadMedia, let messageMedia, let peerReference { var signal: Signal<(TransformImageArguments) -> DrawingContext?, NoError>? var fetchSignal: Signal? switch messageMedia { @@ -332,7 +334,7 @@ final class StoryItemContentComponent: Component { signal = chatMessagePhoto( postbox: component.context.account.postbox, userLocation: .other, - photoReference: .standalone(media: image), + photoReference: .story(peer: peerReference, id: component.item.id, media: image), synchronousLoad: true, highQuality: true ) @@ -341,7 +343,7 @@ final class StoryItemContentComponent: Component { mediaBox: component.context.account.postbox.mediaBox, userLocation: .other, userContentType: .image, - reference: ImageMediaReference.standalone(media: image).resourceReference(representation.resource) + reference: ImageMediaReference.story(peer: peerReference, id: component.item.id, media: image).resourceReference(representation.resource) ) |> ignoreValues |> `catch` { _ -> Signal in @@ -354,14 +356,14 @@ final class StoryItemContentComponent: Component { signal = chatMessageVideo( postbox: component.context.account.postbox, userLocation: .other, - videoReference: .standalone(media: file), + videoReference: .story(peer: peerReference, id: component.item.id, media: file), synchronousLoad: true ) fetchSignal = fetchedMediaResource( mediaBox: component.context.account.postbox.mediaBox, userLocation: .other, userContentType: .image, - reference: FileMediaReference.standalone(media: file).resourceReference(file.resource) + reference: FileMediaReference.story(peer: peerReference, id: component.item.id, media: file).resourceReference(file.resource) ) |> ignoreValues |> `catch` { _ -> Signal in diff --git a/submodules/TelegramUI/Components/Stories/StoryFooterPanelComponent/Sources/StoryFooterPanelComponent.swift b/submodules/TelegramUI/Components/Stories/StoryFooterPanelComponent/Sources/StoryFooterPanelComponent.swift index eb267263d5..948f98aafb 100644 --- a/submodules/TelegramUI/Components/Stories/StoryFooterPanelComponent/Sources/StoryFooterPanelComponent.swift +++ b/submodules/TelegramUI/Components/Stories/StoryFooterPanelComponent/Sources/StoryFooterPanelComponent.swift @@ -73,7 +73,7 @@ public final class StoryFooterPanelComponent: Component { let avatarSpacing: CGFloat = 18.0 var peers: [EnginePeer] = [] - if let seenPeers = component.storyItem?.seenPeers { + if let seenPeers = component.storyItem?.views?.seenPeers { peers = Array(seenPeers.prefix(3)) } let avatarsContent = self.avatarsContext.update(peers: peers, animated: false) @@ -86,11 +86,11 @@ public final class StoryFooterPanelComponent: Component { } let viewsText: String - if let storyItem = component.storyItem, storyItem.seenCount != 0 { - if storyItem.seenCount == 1 { + if let views = component.storyItem?.views, views.seenCount != 0 { + if views.seenCount == 1 { viewsText = "1 view" } else { - viewsText = "\(storyItem.seenCount) views" + viewsText = "\(views.seenCount) views" } } else { viewsText = "No views yet" diff --git a/submodules/TelegramUI/Sources/TelegramRootController.swift b/submodules/TelegramUI/Sources/TelegramRootController.swift index 0da07105ab..feca1eb3cd 100644 --- a/submodules/TelegramUI/Sources/TelegramRootController.swift +++ b/submodules/TelegramUI/Sources/TelegramRootController.swift @@ -420,7 +420,10 @@ public final class TelegramRootController: NavigationController, TelegramRootCon switch mediaResult { case let .image(image, dimensions, _): if let data = image.jpegData(compressionQuality: 0.8) { - storyListContext.upload(media: .image(dimensions: dimensions, data: data), text: nil, entities: nil, privacy: privacy) + storyListContext.upload(media: .image(dimensions: dimensions, data: data), text: "", entities: [], privacy: privacy) + Queue.mainQueue().after(0.3, { [weak chatListController] in + chatListController?.animateStoryUploadRipple() + }) } case let .video(content, _, values, duration, dimensions, _): let adjustments: VideoMediaResourceAdjustments @@ -438,7 +441,10 @@ public final class TelegramRootController: NavigationController, TelegramRootCon case let .asset(localIdentifier): resource = VideoLibraryMediaResource(localIdentifier: localIdentifier, conversion: .compress(adjustments)) } - storyListContext.upload(media: .video(dimensions: dimensions, duration: Int(duration), resource: resource), text: nil, entities: nil, privacy: privacy) + storyListContext.upload(media: .video(dimensions: dimensions, duration: Int(duration), resource: resource), text: "", entities: [], privacy: privacy) + Queue.mainQueue().after(0.3, { [weak chatListController] in + chatListController?.animateStoryUploadRipple() + }) } } }