From cf3dbeee29ab89484d8714fe478cf90aeb18e9f1 Mon Sep 17 00:00:00 2001 From: Isaac <> Date: Tue, 22 Jul 2025 00:13:32 +0200 Subject: [PATCH] Update --- MODULE.bazel.lock | 11 +- .../Sources/AccountContext.swift | 2 +- submodules/TelegramApi/Sources/Api0.swift | 9 +- submodules/TelegramApi/Sources/Api26.swift | 80 ++- submodules/TelegramApi/Sources/Api37.swift | 110 ++-- submodules/TelegramApi/Sources/Api38.swift | 52 ++ submodules/TelegramApi/Sources/Api39.swift | 135 ++++- .../Sources/State/Serialization.swift | 2 +- .../Messages/PendingStoryManager.swift | 12 +- .../TelegramEngine/Messages/Stories.swift | 22 +- .../Messages/StoryListContext.swift | 491 +++++++++++------- .../Messages/TelegramEngineMessages.swift | 4 +- .../Sources/EditStories.swift | 2 +- .../Sources/PeerInfoScreen.swift | 2 +- .../Sources/PeerInfoStoryPaneNode.swift | 18 +- .../Sources/ShareWithPeersScreen.swift | 17 +- .../Sources/StoryContainerScreen.swift | 8 +- .../TelegramUI/Sources/OpenResolvedUrl.swift | 2 +- .../Sources/SharedAccountContext.swift | 2 +- .../Sources/TelegramRootController.swift | 7 +- .../WebUI/Sources/WebAppController.swift | 2 +- 21 files changed, 703 insertions(+), 287 deletions(-) diff --git a/MODULE.bazel.lock b/MODULE.bazel.lock index b361f3adef..ed86535e8b 100644 --- a/MODULE.bazel.lock +++ b/MODULE.bazel.lock @@ -312,7 +312,7 @@ }, "@@rules_xcodeproj+//xcodeproj:extensions.bzl%non_module_deps": { "general": { - "bzlTransitiveDigest": "/r7IWMTdpceHqqiSh7G9bQLHvIkfqE/cesswbkTSJZw=", + "bzlTransitiveDigest": "6MYik+6MZUO7rOzaI0dUJYVD8dJrR1Q2rT+5vo1j73U=", "usagesDigest": "jzxYhnOC9BE0dJ0biFLfxWXi/+R19uAAZkJ0p9CY0JI=", "recordedFileInputs": {}, "recordedDirentsInputs": {}, @@ -345,6 +345,15 @@ "url": "https://github.com/apple/swift-argument-parser/archive/refs/tags/1.2.3.tar.gz" } }, + "com_github_tadija_aexml": { + "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", + "attributes": { + "build_file_content": "load(\"@build_bazel_rules_swift//swift:swift.bzl\", \"swift_library\")\n\nswift_library(\n name = \"AEXML\",\n srcs = glob([\"Sources/AEXML/**/*.swift\"]),\n visibility = [\"//visibility:public\"],\n)\n", + "sha256": "5a76c28e4fa9dcc1cbfb87a8518652628e990e522ecfbc98bdad17eabf4631d5", + "strip_prefix": "AEXML-4.6.1", + "url": "https://github.com/tadija/AEXML/archive/refs/tags/4.6.1.tar.gz" + } + }, "com_github_michaeleisel_jjliso8601dateformatter": { "repoRuleId": "@@bazel_tools//tools/build_defs/repo:http.bzl%http_archive", "attributes": { diff --git a/submodules/AccountContext/Sources/AccountContext.swift b/submodules/AccountContext/Sources/AccountContext.swift index 7b0b0d692f..fde006cf19 100644 --- a/submodules/AccountContext/Sources/AccountContext.swift +++ b/submodules/AccountContext/Sources/AccountContext.swift @@ -884,7 +884,7 @@ public protocol MediaEditorScreenResult { public protocol TelegramRootControllerInterface: NavigationController { @discardableResult func openStoryCamera(customTarget: Stories.PendingTarget?, transitionIn: StoryCameraTransitionIn?, transitionedIn: @escaping () -> Void, transitionOut: @escaping (Stories.PendingTarget?, Bool) -> StoryCameraTransitionOut?) -> StoryCameraTransitionInCoordinator? - func proceedWithStoryUpload(target: Stories.PendingTarget, results: [MediaEditorScreenResult], existingMedia: EngineMedia?, forwardInfo: Stories.PendingForwardInfo?, externalState: MediaEditorTransitionOutExternalState, commit: @escaping (@escaping () -> Void) -> Void) + func proceedWithStoryUpload(target: Stories.PendingTarget, results: [MediaEditorScreenResult], existingMedia: EngineMedia?, forwardInfo: Stories.PendingForwardInfo?, folders: [Int64], externalState: MediaEditorTransitionOutExternalState, commit: @escaping (@escaping () -> Void) -> Void) func getContactsController() -> ViewController? func getChatsController() -> ViewController? diff --git a/submodules/TelegramApi/Sources/Api0.swift b/submodules/TelegramApi/Sources/Api0.swift index 0bf257604c..d42bc0ead8 100644 --- a/submodules/TelegramApi/Sources/Api0.swift +++ b/submodules/TelegramApi/Sources/Api0.swift @@ -992,8 +992,9 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = { dict[872932635] = { return Api.StickerSetCovered.parse_stickerSetMultiCovered($0) } dict[2008112412] = { return Api.StickerSetCovered.parse_stickerSetNoCovered($0) } dict[1898850301] = { return Api.StoriesStealthMode.parse_storiesStealthMode($0) } + dict[-1826262950] = { return Api.StoryAlbum.parse_storyAlbum($0) } dict[-1205411504] = { return Api.StoryFwdHeader.parse_storyFwdHeader($0) } - dict[2041735716] = { return Api.StoryItem.parse_storyItem($0) } + dict[-302947087] = { return Api.StoryItem.parse_storyItem($0) } dict[1374088783] = { return Api.StoryItem.parse_storyItemDeleted($0) } dict[-5388013] = { return Api.StoryItem.parse_storyItemSkipped($0) } dict[1620104917] = { return Api.StoryReaction.parse_storyReaction($0) } @@ -1476,6 +1477,8 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = { dict[172975040] = { return Api.storage.FileType.parse_filePng($0) } dict[-1432995067] = { return Api.storage.FileType.parse_fileUnknown($0) } dict[276907596] = { return Api.storage.FileType.parse_fileWebp($0) } + dict[-1013417414] = { return Api.stories.Albums.parse_albums($0) } + dict[1448008427] = { return Api.stories.Albums.parse_albumsNotModified($0) } dict[1862033025] = { return Api.stories.AllStories.parse_allStories($0) } dict[291044926] = { return Api.stories.AllStories.parse_allStoriesNotModified($0) } dict[-1014513586] = { return Api.stories.CanSendStoryCount.parse_canSendStoryCount($0) } @@ -2196,6 +2199,8 @@ public extension Api { _1.serialize(buffer, boxed) case let _1 as Api.StoriesStealthMode: _1.serialize(buffer, boxed) + case let _1 as Api.StoryAlbum: + _1.serialize(buffer, boxed) case let _1 as Api.StoryFwdHeader: _1.serialize(buffer, boxed) case let _1 as Api.StoryItem: @@ -2614,6 +2619,8 @@ public extension Api { _1.serialize(buffer, boxed) case let _1 as Api.storage.FileType: _1.serialize(buffer, boxed) + case let _1 as Api.stories.Albums: + _1.serialize(buffer, boxed) case let _1 as Api.stories.AllStories: _1.serialize(buffer, boxed) case let _1 as Api.stories.CanSendStoryCount: diff --git a/submodules/TelegramApi/Sources/Api26.swift b/submodules/TelegramApi/Sources/Api26.swift index dff9d15574..c2d30c953f 100644 --- a/submodules/TelegramApi/Sources/Api26.swift +++ b/submodules/TelegramApi/Sources/Api26.swift @@ -324,6 +324,62 @@ public extension Api { } } +public extension Api { + enum StoryAlbum: TypeConstructorDescription { + case storyAlbum(flags: Int32, albumId: Int32, title: String, iconPhoto: Api.Photo?, iconVideo: Api.Document?) + + public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .storyAlbum(let flags, let albumId, let title, let iconPhoto, let iconVideo): + if boxed { + buffer.appendInt32(-1826262950) + } + serializeInt32(flags, buffer: buffer, boxed: false) + serializeInt32(albumId, buffer: buffer, boxed: false) + serializeString(title, buffer: buffer, boxed: false) + if Int(flags) & Int(1 << 0) != 0 {iconPhoto!.serialize(buffer, true)} + if Int(flags) & Int(1 << 1) != 0 {iconVideo!.serialize(buffer, true)} + break + } + } + + public func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .storyAlbum(let flags, let albumId, let title, let iconPhoto, let iconVideo): + return ("storyAlbum", [("flags", flags as Any), ("albumId", albumId as Any), ("title", title as Any), ("iconPhoto", iconPhoto as Any), ("iconVideo", iconVideo as Any)]) + } + } + + public static func parse_storyAlbum(_ reader: BufferReader) -> StoryAlbum? { + var _1: Int32? + _1 = reader.readInt32() + var _2: Int32? + _2 = reader.readInt32() + var _3: String? + _3 = parseString(reader) + var _4: Api.Photo? + if Int(_1!) & Int(1 << 0) != 0 {if let signature = reader.readInt32() { + _4 = Api.parse(reader, signature: signature) as? Api.Photo + } } + var _5: Api.Document? + if Int(_1!) & Int(1 << 1) != 0 {if let signature = reader.readInt32() { + _5 = Api.parse(reader, signature: signature) as? Api.Document + } } + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = _3 != nil + let _c4 = (Int(_1!) & Int(1 << 0) == 0) || _4 != nil + let _c5 = (Int(_1!) & Int(1 << 1) == 0) || _5 != nil + if _c1 && _c2 && _c3 && _c4 && _c5 { + return Api.StoryAlbum.storyAlbum(flags: _1!, albumId: _2!, title: _3!, iconPhoto: _4, iconVideo: _5) + } + else { + return nil + } + } + + } +} public extension Api { enum StoryFwdHeader: TypeConstructorDescription { case storyFwdHeader(flags: Int32, from: Api.Peer?, fromName: String?, storyId: Int32?) @@ -376,15 +432,15 @@ public extension Api { } public extension Api { indirect enum StoryItem: TypeConstructorDescription { - case storyItem(flags: Int32, id: Int32, date: Int32, fromId: Api.Peer?, fwdFrom: Api.StoryFwdHeader?, expireDate: Int32, caption: String?, entities: [Api.MessageEntity]?, media: Api.MessageMedia, mediaAreas: [Api.MediaArea]?, privacy: [Api.PrivacyRule]?, views: Api.StoryViews?, sentReaction: Api.Reaction?) + case storyItem(flags: Int32, id: Int32, date: Int32, fromId: Api.Peer?, fwdFrom: Api.StoryFwdHeader?, expireDate: Int32, caption: String?, entities: [Api.MessageEntity]?, media: Api.MessageMedia, mediaAreas: [Api.MediaArea]?, privacy: [Api.PrivacyRule]?, views: Api.StoryViews?, sentReaction: Api.Reaction?, albums: [Int32]?) case storyItemDeleted(id: Int32) case storyItemSkipped(flags: Int32, id: Int32, date: Int32, expireDate: Int32) public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { switch self { - case .storyItem(let flags, let id, let date, let fromId, let fwdFrom, let expireDate, let caption, let entities, let media, let mediaAreas, let privacy, let views, let sentReaction): + case .storyItem(let flags, let id, let date, let fromId, let fwdFrom, let expireDate, let caption, let entities, let media, let mediaAreas, let privacy, let views, let sentReaction, let albums): if boxed { - buffer.appendInt32(2041735716) + buffer.appendInt32(-302947087) } serializeInt32(flags, buffer: buffer, boxed: false) serializeInt32(id, buffer: buffer, boxed: false) @@ -411,6 +467,11 @@ public extension Api { }} if Int(flags) & Int(1 << 3) != 0 {views!.serialize(buffer, true)} if Int(flags) & Int(1 << 15) != 0 {sentReaction!.serialize(buffer, true)} + if Int(flags) & Int(1 << 19) != 0 {buffer.appendInt32(481674261) + buffer.appendInt32(Int32(albums!.count)) + for item in albums! { + serializeInt32(item, buffer: buffer, boxed: false) + }} break case .storyItemDeleted(let id): if boxed { @@ -432,8 +493,8 @@ public extension Api { public func descriptionFields() -> (String, [(String, Any)]) { switch self { - case .storyItem(let flags, let id, let date, let fromId, let fwdFrom, let expireDate, let caption, let entities, let media, let mediaAreas, let privacy, let views, let sentReaction): - return ("storyItem", [("flags", flags as Any), ("id", id as Any), ("date", date as Any), ("fromId", fromId as Any), ("fwdFrom", fwdFrom as Any), ("expireDate", expireDate as Any), ("caption", caption as Any), ("entities", entities as Any), ("media", media as Any), ("mediaAreas", mediaAreas as Any), ("privacy", privacy as Any), ("views", views as Any), ("sentReaction", sentReaction as Any)]) + case .storyItem(let flags, let id, let date, let fromId, let fwdFrom, let expireDate, let caption, let entities, let media, let mediaAreas, let privacy, let views, let sentReaction, let albums): + return ("storyItem", [("flags", flags as Any), ("id", id as Any), ("date", date as Any), ("fromId", fromId as Any), ("fwdFrom", fwdFrom as Any), ("expireDate", expireDate as Any), ("caption", caption as Any), ("entities", entities as Any), ("media", media as Any), ("mediaAreas", mediaAreas as Any), ("privacy", privacy as Any), ("views", views as Any), ("sentReaction", sentReaction as Any), ("albums", albums as Any)]) case .storyItemDeleted(let id): return ("storyItemDeleted", [("id", id as Any)]) case .storyItemSkipped(let flags, let id, let date, let expireDate): @@ -484,6 +545,10 @@ public extension Api { if Int(_1!) & Int(1 << 15) != 0 {if let signature = reader.readInt32() { _13 = Api.parse(reader, signature: signature) as? Api.Reaction } } + var _14: [Int32]? + if Int(_1!) & Int(1 << 19) != 0 {if let _ = reader.readInt32() { + _14 = Api.parseVector(reader, elementSignature: -1471112230, elementType: Int32.self) + } } let _c1 = _1 != nil let _c2 = _2 != nil let _c3 = _3 != nil @@ -497,8 +562,9 @@ public extension Api { let _c11 = (Int(_1!) & Int(1 << 2) == 0) || _11 != nil let _c12 = (Int(_1!) & Int(1 << 3) == 0) || _12 != nil let _c13 = (Int(_1!) & Int(1 << 15) == 0) || _13 != nil - if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 && _c8 && _c9 && _c10 && _c11 && _c12 && _c13 { - return Api.StoryItem.storyItem(flags: _1!, id: _2!, date: _3!, fromId: _4, fwdFrom: _5, expireDate: _6!, caption: _7, entities: _8, media: _9!, mediaAreas: _10, privacy: _11, views: _12, sentReaction: _13) + let _c14 = (Int(_1!) & Int(1 << 19) == 0) || _14 != nil + if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 && _c8 && _c9 && _c10 && _c11 && _c12 && _c13 && _c14 { + return Api.StoryItem.storyItem(flags: _1!, id: _2!, date: _3!, fromId: _4, fwdFrom: _5, expireDate: _6!, caption: _7, entities: _8, media: _9!, mediaAreas: _10, privacy: _11, views: _12, sentReaction: _13, albums: _14) } else { return nil diff --git a/submodules/TelegramApi/Sources/Api37.swift b/submodules/TelegramApi/Sources/Api37.swift index 62bcb3429a..cbba07a113 100644 --- a/submodules/TelegramApi/Sources/Api37.swift +++ b/submodules/TelegramApi/Sources/Api37.swift @@ -482,6 +482,64 @@ public extension Api.storage { } } +public extension Api.stories { + enum Albums: TypeConstructorDescription { + case albums(hash: Int64, albums: [Api.StoryAlbum]) + case albumsNotModified + + public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .albums(let hash, let albums): + if boxed { + buffer.appendInt32(-1013417414) + } + serializeInt64(hash, buffer: buffer, boxed: false) + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(albums.count)) + for item in albums { + item.serialize(buffer, true) + } + break + case .albumsNotModified: + if boxed { + buffer.appendInt32(1448008427) + } + + break + } + } + + public func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .albums(let hash, let albums): + return ("albums", [("hash", hash as Any), ("albums", albums as Any)]) + case .albumsNotModified: + return ("albumsNotModified", []) + } + } + + public static func parse_albums(_ reader: BufferReader) -> Albums? { + var _1: Int64? + _1 = reader.readInt64() + var _2: [Api.StoryAlbum]? + if let _ = reader.readInt32() { + _2 = Api.parseVector(reader, elementSignature: 0, elementType: Api.StoryAlbum.self) + } + let _c1 = _1 != nil + let _c2 = _2 != nil + if _c1 && _c2 { + return Api.stories.Albums.albums(hash: _1!, albums: _2!) + } + else { + return nil + } + } + public static func parse_albumsNotModified(_ reader: BufferReader) -> Albums? { + return Api.stories.Albums.albumsNotModified + } + + } +} public extension Api.stories { enum AllStories: TypeConstructorDescription { case allStories(flags: Int32, count: Int32, state: String, peerStories: [Api.PeerStories], chats: [Api.Chat], users: [Api.User], stealthMode: Api.StoriesStealthMode) @@ -1428,55 +1486,3 @@ public extension Api.updates { } } -public extension Api.updates { - enum State: TypeConstructorDescription { - case state(pts: Int32, qts: Int32, date: Int32, seq: Int32, unreadCount: Int32) - - public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { - switch self { - case .state(let pts, let qts, let date, let seq, let unreadCount): - if boxed { - buffer.appendInt32(-1519637954) - } - serializeInt32(pts, buffer: buffer, boxed: false) - serializeInt32(qts, buffer: buffer, boxed: false) - serializeInt32(date, buffer: buffer, boxed: false) - serializeInt32(seq, buffer: buffer, boxed: false) - serializeInt32(unreadCount, buffer: buffer, boxed: false) - break - } - } - - public func descriptionFields() -> (String, [(String, Any)]) { - switch self { - case .state(let pts, let qts, let date, let seq, let unreadCount): - return ("state", [("pts", pts as Any), ("qts", qts as Any), ("date", date as Any), ("seq", seq as Any), ("unreadCount", unreadCount as Any)]) - } - } - - public static func parse_state(_ reader: BufferReader) -> State? { - var _1: Int32? - _1 = reader.readInt32() - var _2: Int32? - _2 = reader.readInt32() - var _3: Int32? - _3 = reader.readInt32() - var _4: Int32? - _4 = reader.readInt32() - var _5: Int32? - _5 = reader.readInt32() - let _c1 = _1 != nil - let _c2 = _2 != nil - let _c3 = _3 != nil - let _c4 = _4 != nil - let _c5 = _5 != nil - if _c1 && _c2 && _c3 && _c4 && _c5 { - return Api.updates.State.state(pts: _1!, qts: _2!, date: _3!, seq: _4!, unreadCount: _5!) - } - else { - return nil - } - } - - } -} diff --git a/submodules/TelegramApi/Sources/Api38.swift b/submodules/TelegramApi/Sources/Api38.swift index e76c07649a..281a495dbf 100644 --- a/submodules/TelegramApi/Sources/Api38.swift +++ b/submodules/TelegramApi/Sources/Api38.swift @@ -1,3 +1,55 @@ +public extension Api.updates { + enum State: TypeConstructorDescription { + case state(pts: Int32, qts: Int32, date: Int32, seq: Int32, unreadCount: Int32) + + public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { + switch self { + case .state(let pts, let qts, let date, let seq, let unreadCount): + if boxed { + buffer.appendInt32(-1519637954) + } + serializeInt32(pts, buffer: buffer, boxed: false) + serializeInt32(qts, buffer: buffer, boxed: false) + serializeInt32(date, buffer: buffer, boxed: false) + serializeInt32(seq, buffer: buffer, boxed: false) + serializeInt32(unreadCount, buffer: buffer, boxed: false) + break + } + } + + public func descriptionFields() -> (String, [(String, Any)]) { + switch self { + case .state(let pts, let qts, let date, let seq, let unreadCount): + return ("state", [("pts", pts as Any), ("qts", qts as Any), ("date", date as Any), ("seq", seq as Any), ("unreadCount", unreadCount as Any)]) + } + } + + public static func parse_state(_ reader: BufferReader) -> State? { + var _1: Int32? + _1 = reader.readInt32() + var _2: Int32? + _2 = reader.readInt32() + var _3: Int32? + _3 = reader.readInt32() + var _4: Int32? + _4 = reader.readInt32() + var _5: Int32? + _5 = reader.readInt32() + let _c1 = _1 != nil + let _c2 = _2 != nil + let _c3 = _3 != nil + let _c4 = _4 != nil + let _c5 = _5 != nil + if _c1 && _c2 && _c3 && _c4 && _c5 { + return Api.updates.State.state(pts: _1!, qts: _2!, date: _3!, seq: _4!, unreadCount: _5!) + } + else { + return nil + } + } + + } +} public extension Api.upload { enum CdnFile: TypeConstructorDescription { case cdnFile(bytes: Buffer) diff --git a/submodules/TelegramApi/Sources/Api39.swift b/submodules/TelegramApi/Sources/Api39.swift index 43e04f36f2..5567cfe4d7 100644 --- a/submodules/TelegramApi/Sources/Api39.swift +++ b/submodules/TelegramApi/Sources/Api39.swift @@ -11371,6 +11371,43 @@ public extension Api.functions.stories { }) } } +public extension Api.functions.stories { + static func createAlbum(peer: Api.InputPeer, title: String, stories: [Int32]) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(-1553754395) + peer.serialize(buffer, true) + serializeString(title, buffer: buffer, boxed: false) + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(stories.count)) + for item in stories { + serializeInt32(item, buffer: buffer, boxed: false) + } + return (FunctionDescription(name: "stories.createAlbum", parameters: [("peer", String(describing: peer)), ("title", String(describing: title)), ("stories", String(describing: stories))]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.StoryAlbum? in + let reader = BufferReader(buffer) + var result: Api.StoryAlbum? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.StoryAlbum + } + return result + }) + } +} +public extension Api.functions.stories { + static func deleteAlbum(peer: Api.InputPeer, albumId: Int32) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(-1925949744) + peer.serialize(buffer, true) + serializeInt32(albumId, buffer: buffer, boxed: false) + return (FunctionDescription(name: "stories.deleteAlbum", parameters: [("peer", String(describing: peer)), ("albumId", String(describing: albumId))]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.Bool? in + let reader = BufferReader(buffer) + var result: Api.Bool? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.Bool + } + return result + }) + } +} public extension Api.functions.stories { static func deleteStories(peer: Api.InputPeer, id: [Int32]) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<[Int32]>) { let buffer = Buffer() @@ -11441,6 +11478,40 @@ public extension Api.functions.stories { }) } } +public extension Api.functions.stories { + static func getAlbumStories(peer: Api.InputPeer, albumId: Int32, offset: Int32, limit: Int32) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(-1400869535) + peer.serialize(buffer, true) + serializeInt32(albumId, buffer: buffer, boxed: false) + serializeInt32(offset, buffer: buffer, boxed: false) + serializeInt32(limit, buffer: buffer, boxed: false) + return (FunctionDescription(name: "stories.getAlbumStories", parameters: [("peer", String(describing: peer)), ("albumId", String(describing: albumId)), ("offset", String(describing: offset)), ("limit", String(describing: limit))]), 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 getAlbums(peer: Api.InputPeer, hash: Int64) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(632548039) + peer.serialize(buffer, true) + serializeInt64(hash, buffer: buffer, boxed: false) + return (FunctionDescription(name: "stories.getAlbums", parameters: [("peer", String(describing: peer)), ("hash", String(describing: hash))]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.stories.Albums? in + let reader = BufferReader(buffer) + var result: Api.stories.Albums? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.stories.Albums + } + return result + }) + } +} public extension Api.functions.stories { static func getAllReadPeerStories() -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { let buffer = Buffer() @@ -11671,6 +11742,26 @@ public extension Api.functions.stories { }) } } +public extension Api.functions.stories { + static func reorderAlbums(peer: Api.InputPeer, order: [Int32]) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(-2060059687) + peer.serialize(buffer, true) + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(order.count)) + for item in order { + serializeInt32(item, buffer: buffer, boxed: false) + } + return (FunctionDescription(name: "stories.reorderAlbums", parameters: [("peer", String(describing: peer)), ("order", String(describing: order))]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.Bool? in + let reader = BufferReader(buffer) + var result: Api.Bool? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.Bool + } + return result + }) + } +} public extension Api.functions.stories { static func report(peer: Api.InputPeer, id: [Int32], option: Buffer, message: String) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { let buffer = Buffer() @@ -11732,9 +11823,9 @@ public extension Api.functions.stories { } } public extension Api.functions.stories { - static func sendStory(flags: Int32, peer: Api.InputPeer, media: Api.InputMedia, mediaAreas: [Api.MediaArea]?, caption: String?, entities: [Api.MessageEntity]?, privacyRules: [Api.InputPrivacyRule], randomId: Int64, period: Int32?, fwdFromId: Api.InputPeer?, fwdFromStory: Int32?) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + static func sendStory(flags: Int32, peer: Api.InputPeer, media: Api.InputMedia, mediaAreas: [Api.MediaArea]?, caption: String?, entities: [Api.MessageEntity]?, privacyRules: [Api.InputPrivacyRule], randomId: Int64, period: Int32?, fwdFromId: Api.InputPeer?, fwdFromStory: Int32?, albums: [Int32]?) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { let buffer = Buffer() - buffer.appendInt32(-454661813) + buffer.appendInt32(1937752812) serializeInt32(flags, buffer: buffer, boxed: false) peer.serialize(buffer, true) media.serialize(buffer, true) @@ -11758,7 +11849,12 @@ public extension Api.functions.stories { if Int(flags) & Int(1 << 3) != 0 {serializeInt32(period!, buffer: buffer, boxed: false)} if Int(flags) & Int(1 << 6) != 0 {fwdFromId!.serialize(buffer, true)} if Int(flags) & Int(1 << 6) != 0 {serializeInt32(fwdFromStory!, buffer: buffer, boxed: false)} - return (FunctionDescription(name: "stories.sendStory", parameters: [("flags", String(describing: flags)), ("peer", String(describing: peer)), ("media", String(describing: media)), ("mediaAreas", String(describing: mediaAreas)), ("caption", String(describing: caption)), ("entities", String(describing: entities)), ("privacyRules", String(describing: privacyRules)), ("randomId", String(describing: randomId)), ("period", String(describing: period)), ("fwdFromId", String(describing: fwdFromId)), ("fwdFromStory", String(describing: fwdFromStory))]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.Updates? in + if Int(flags) & Int(1 << 8) != 0 {buffer.appendInt32(481674261) + buffer.appendInt32(Int32(albums!.count)) + for item in albums! { + serializeInt32(item, buffer: buffer, boxed: false) + }} + return (FunctionDescription(name: "stories.sendStory", parameters: [("flags", String(describing: flags)), ("peer", String(describing: peer)), ("media", String(describing: media)), ("mediaAreas", String(describing: mediaAreas)), ("caption", String(describing: caption)), ("entities", String(describing: entities)), ("privacyRules", String(describing: privacyRules)), ("randomId", String(describing: randomId)), ("period", String(describing: period)), ("fwdFromId", String(describing: fwdFromId)), ("fwdFromStory", String(describing: fwdFromStory)), ("albums", String(describing: albums))]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.Updates? in let reader = BufferReader(buffer) var result: Api.Updates? if let signature = reader.readInt32() { @@ -11840,6 +11936,39 @@ public extension Api.functions.stories { }) } } +public extension Api.functions.stories { + static func updateAlbum(flags: Int32, peer: Api.InputPeer, albumId: Int32, title: String?, deleteStories: [Int32]?, addStories: [Int32]?, order: [Int32]?) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(1582455222) + serializeInt32(flags, buffer: buffer, boxed: false) + peer.serialize(buffer, true) + serializeInt32(albumId, buffer: buffer, boxed: false) + if Int(flags) & Int(1 << 0) != 0 {serializeString(title!, buffer: buffer, boxed: false)} + if Int(flags) & Int(1 << 1) != 0 {buffer.appendInt32(481674261) + buffer.appendInt32(Int32(deleteStories!.count)) + for item in deleteStories! { + serializeInt32(item, buffer: buffer, boxed: false) + }} + if Int(flags) & Int(1 << 2) != 0 {buffer.appendInt32(481674261) + buffer.appendInt32(Int32(addStories!.count)) + for item in addStories! { + serializeInt32(item, buffer: buffer, boxed: false) + }} + if Int(flags) & Int(1 << 3) != 0 {buffer.appendInt32(481674261) + buffer.appendInt32(Int32(order!.count)) + for item in order! { + serializeInt32(item, buffer: buffer, boxed: false) + }} + return (FunctionDescription(name: "stories.updateAlbum", parameters: [("flags", String(describing: flags)), ("peer", String(describing: peer)), ("albumId", String(describing: albumId)), ("title", String(describing: title)), ("deleteStories", String(describing: deleteStories)), ("addStories", String(describing: addStories)), ("order", String(describing: order))]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.StoryAlbum? in + let reader = BufferReader(buffer) + var result: Api.StoryAlbum? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.StoryAlbum + } + return result + }) + } +} public extension Api.functions.updates { static func getChannelDifference(flags: Int32, channel: Api.InputChannel, filter: Api.ChannelMessagesFilter, pts: Int32, limit: Int32) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { let buffer = Buffer() diff --git a/submodules/TelegramCore/Sources/State/Serialization.swift b/submodules/TelegramCore/Sources/State/Serialization.swift index ddd61c801e..1cda543eba 100644 --- a/submodules/TelegramCore/Sources/State/Serialization.swift +++ b/submodules/TelegramCore/Sources/State/Serialization.swift @@ -210,7 +210,7 @@ public class BoxedMessage: NSObject { public class Serialization: NSObject, MTSerialization { public func currentLayer() -> UInt { - return 210 + return 211 } public func parseMessage(_ data: Data!) -> Any! { diff --git a/submodules/TelegramCore/Sources/TelegramEngine/Messages/PendingStoryManager.swift b/submodules/TelegramCore/Sources/TelegramEngine/Messages/PendingStoryManager.swift index 0fa08c6ef1..b350443e9b 100644 --- a/submodules/TelegramCore/Sources/TelegramEngine/Messages/PendingStoryManager.swift +++ b/submodules/TelegramCore/Sources/TelegramEngine/Messages/PendingStoryManager.swift @@ -98,6 +98,7 @@ public extension Stories { case randomId case forwardInfo case uploadInfo + case folders } public let target: PendingTarget @@ -114,6 +115,7 @@ public extension Stories { public let period: Int32 public let randomId: Int64 public let forwardInfo: PendingForwardInfo? + public let folders: [Int64] public let uploadInfo: StoryUploadInfo? public init( @@ -131,6 +133,7 @@ public extension Stories { period: Int32, randomId: Int64, forwardInfo: PendingForwardInfo?, + folders: [Int64], uploadInfo: StoryUploadInfo? ) { self.target = target @@ -147,6 +150,7 @@ public extension Stories { self.period = period self.randomId = randomId self.forwardInfo = forwardInfo + self.folders = folders self.uploadInfo = uploadInfo } @@ -176,6 +180,8 @@ public extension Stories { self.forwardInfo = try container.decodeIfPresent(PendingForwardInfo.self, forKey: .forwardInfo) + self.folders = try container.decodeIfPresent([Int64].self, forKey: .folders) ?? [] + self.uploadInfo = try container.decodeIfPresent(StoryUploadInfo.self, forKey: .uploadInfo) } @@ -205,6 +211,7 @@ public extension Stories { try container.encode(self.period, forKey: .period) try container.encode(self.randomId, forKey: .randomId) try container.encodeIfPresent(self.forwardInfo, forKey: .forwardInfo) + try container.encode(self.folders, forKey: .folders) try container.encodeIfPresent(self.uploadInfo, forKey: .uploadInfo) } @@ -245,6 +252,9 @@ public extension Stories { if lhs.forwardInfo != rhs.forwardInfo { return false } + if lhs.folders != rhs.folders { + return false + } if lhs.uploadInfo != rhs.uploadInfo { return false } @@ -473,7 +483,7 @@ final class PendingStoryManager { let partTotalProgress = 1.0 / Float(uploadInfo.total) pendingItemContext.progress = Float(uploadInfo.index) * partTotalProgress } - pendingItemContext.disposable = (_internal_uploadStoryImpl(postbox: self.postbox, network: self.network, accountPeerId: self.accountPeerId, stateManager: self.stateManager, messageMediaPreuploadManager: self.messageMediaPreuploadManager, revalidationContext: self.revalidationContext, auxiliaryMethods: self.auxiliaryMethods, toPeerId: toPeerId, stableId: stableId, media: firstItem.media, mediaAreas: firstItem.mediaAreas, text: firstItem.text, entities: firstItem.entities, embeddedStickers: firstItem.embeddedStickers, pin: firstItem.pin, privacy: firstItem.privacy, isForwardingDisabled: firstItem.isForwardingDisabled, period: Int(firstItem.period), randomId: firstItem.randomId, forwardInfo: firstItem.forwardInfo) + pendingItemContext.disposable = (_internal_uploadStoryImpl(postbox: self.postbox, network: self.network, accountPeerId: self.accountPeerId, stateManager: self.stateManager, messageMediaPreuploadManager: self.messageMediaPreuploadManager, revalidationContext: self.revalidationContext, auxiliaryMethods: self.auxiliaryMethods, toPeerId: toPeerId, stableId: stableId, media: firstItem.media, mediaAreas: firstItem.mediaAreas, text: firstItem.text, entities: firstItem.entities, embeddedStickers: firstItem.embeddedStickers, pin: firstItem.pin, privacy: firstItem.privacy, isForwardingDisabled: firstItem.isForwardingDisabled, period: Int(firstItem.period), folders: firstItem.folders, randomId: firstItem.randomId, forwardInfo: firstItem.forwardInfo) |> deliverOn(self.queue)).start(next: { [weak self] event in guard let `self` = self else { return diff --git a/submodules/TelegramCore/Sources/TelegramEngine/Messages/Stories.swift b/submodules/TelegramCore/Sources/TelegramEngine/Messages/Stories.swift index 59e1183adb..55d981e40b 100644 --- a/submodules/TelegramCore/Sources/TelegramEngine/Messages/Stories.swift +++ b/submodules/TelegramCore/Sources/TelegramEngine/Messages/Stories.swift @@ -988,7 +988,7 @@ public struct StoryUploadInfo: Codable, Equatable { } } -func _internal_uploadStory(account: Account, target: Stories.PendingTarget, media: EngineStoryInputMedia, mediaAreas: [MediaArea], text: String, entities: [MessageTextEntity], pin: Bool, privacy: EngineStoryPrivacy, isForwardingDisabled: Bool, period: Int, randomId: Int64, forwardInfo: Stories.PendingForwardInfo?, uploadInfo: StoryUploadInfo? = nil) -> Signal { +func _internal_uploadStory(account: Account, target: Stories.PendingTarget, media: EngineStoryInputMedia, mediaAreas: [MediaArea], text: String, entities: [MessageTextEntity], pin: Bool, privacy: EngineStoryPrivacy, isForwardingDisabled: Bool, period: Int, randomId: Int64, forwardInfo: Stories.PendingForwardInfo?, folders: [Int64], uploadInfo: StoryUploadInfo? = nil) -> Signal { let inputMedia = prepareUploadStoryContent(account: account, media: media) return (account.postbox.transaction { transaction in @@ -1017,6 +1017,7 @@ func _internal_uploadStory(account: Account, target: Stories.PendingTarget, medi period: Int32(period), randomId: randomId, forwardInfo: forwardInfo, + folders: folders, uploadInfo: uploadInfo )) transaction.setLocalStoryState(state: CodableEntry(currentState)) @@ -1064,6 +1065,7 @@ func _internal_cancelStoryUpload(account: Account, stableId: Int32) { period: currentState.items[i].period, randomId: currentState.items[i].randomId, forwardInfo: currentState.items[i].forwardInfo, + folders: currentState.items[i].folders, uploadInfo: StoryUploadInfo( groupingId: groupingId, index: newIndex, @@ -1141,6 +1143,7 @@ func _internal_uploadStoryImpl( privacy: EngineStoryPrivacy, isForwardingDisabled: Bool, period: Int, + folders: [Int64], randomId: Int64, forwardInfo: Stories.PendingForwardInfo? ) -> Signal { @@ -1224,6 +1227,10 @@ func _internal_uploadStoryImpl( fwdFromStory = forwardInfo.storyId } + if !folders.isEmpty { + flags |= 1 << 8 + } + return network.request(Api.functions.stories.sendStory( flags: flags, peer: inputPeer, @@ -1235,7 +1242,8 @@ func _internal_uploadStoryImpl( randomId: randomId, period: Int32(period), fwdFromId: fwdFromId, - fwdFromStory: fwdFromStory + fwdFromStory: fwdFromStory, + albums: folders.isEmpty ? nil : folders.map(Int32.init(clamping:)) )) |> map(Optional.init) |> `catch` { _ -> Signal in @@ -1259,7 +1267,7 @@ func _internal_uploadStoryImpl( for update in updates.allUpdates { if case let .updateStory(_, story) = update { switch story { - case let .storyItem(_, idValue, _, fromId, _, _, _, _, media, _, _, _, _): + case let .storyItem(_, idValue, _, fromId, _, _, _, _, media, _, _, _, _, _): if let parsedStory = Stories.StoredItem(apiStoryItem: story, peerId: toPeerId, transaction: transaction) { var items = transaction.getStoryItems(peerId: toPeerId) var updatedItems: [Stories.Item] = [] @@ -1648,7 +1656,7 @@ func _internal_editStory(account: Account, peerId: PeerId, id: Int32, media: Eng for update in updates.allUpdates { if case let .updateStory(_, story) = update { switch story { - case let .storyItem(_, _, _, _, _, _, _, _, media, _, _, _, _): + case let .storyItem(_, _, _, _, _, _, _, _, media, _, _, _, _, _): let parsedMedia = textMediaAndExpirationTimerFromApiMedia(media, account.peerId).media if let parsedMedia = parsedMedia, let originalMedia = originalMedia { applyMediaResourceChanges(from: originalMedia, to: parsedMedia, postbox: account.postbox, force: false, skipPreviews: updatingCoverTime) @@ -2009,7 +2017,7 @@ func _internal_updatePinnedToTopStories(account: Account, peerId: PeerId, ids: [ extension Api.StoryItem { var id: Int32 { switch self { - case let .storyItem(_, id, _, _, _, _, _, _, _, _, _, _, _): + case let .storyItem(_, id, _, _, _, _, _, _, _, _, _, _, _, _): return id case let .storyItemDeleted(id): return id @@ -2072,7 +2080,9 @@ extension Stories.Item.ForwardInfo { extension Stories.StoredItem { init?(apiStoryItem: Api.StoryItem, existingItem: Stories.Item? = nil, peerId: PeerId, transaction: Transaction) { switch apiStoryItem { - case let .storyItem(flags, id, date, fromId, forwardFrom, expireDate, caption, entities, media, mediaAreas, privacy, views, sentReaction): + case let .storyItem(flags, id, date, fromId, forwardFrom, expireDate, caption, entities, media, mediaAreas, privacy, views, sentReaction, albums): + let _ = albums + let parsedMedia = textMediaAndExpirationTimerFromApiMedia(media, peerId).media if let parsedMedia = parsedMedia { var parsedPrivacy: Stories.Item.Privacy? diff --git a/submodules/TelegramCore/Sources/TelegramEngine/Messages/StoryListContext.swift b/submodules/TelegramCore/Sources/TelegramEngine/Messages/StoryListContext.swift index c0c957fe6d..320bebaedd 100644 --- a/submodules/TelegramCore/Sources/TelegramEngine/Messages/StoryListContext.swift +++ b/submodules/TelegramCore/Sources/TelegramEngine/Messages/StoryListContext.swift @@ -679,6 +679,8 @@ public final class PeerStoryListContext: StoryListContext { return (nil, [], [], 0, [:], [], false) } + let mainFolders: [State.Folder] = cachedMain.folders + let cached: CachedPeerStoryListHead if let folderId { let key = ValueBoxKey(length: 8 + 1 + 8) @@ -768,7 +770,7 @@ public final class PeerStoryListContext: StoryListContext { let peerReference = transaction.getPeer(peerId).flatMap(PeerReference.init) - return (peerReference, items, cached.pinnedIds, Int(cached.totalCount), allEntityFiles, cached.folders, true) + return (peerReference, items, cached.pinnedIds, Int(cached.totalCount), allEntityFiles, mainFolders, true) } |> deliverOn(self.queue)).start(next: { [weak self] peerReference, items, pinnedIds, totalCount, allEntityFiles, folders, hasCache in guard let self else { @@ -828,103 +830,73 @@ public final class PeerStoryListContext: StoryListContext { let accountPeerId = account.peerId let isArchived = self.isArchived let folderId = self.folderId - let folders = self.stateValue.availableFolders self.requestDisposable = (self.account.postbox.transaction { transaction -> Api.InputPeer? in return transaction.getPeer(peerId).flatMap(apiInputPeer) } - |> mapToSignal { inputPeer -> Signal<([State.Item], Int, PeerReference?, Bool), NoError> in - guard let inputPeer = inputPeer else { - return .single(([], 0, nil, false)) + |> mapToSignal { inputPeer -> Signal<([State.Item], Int, PeerReference?, [State.Folder], Bool), NoError> in + guard let inputPeer else { + return .single(([], 0, nil, [], false)) } - let signal: Signal - if isArchived { - signal = account.network.request(Api.functions.stories.getStoriesArchive(peer: inputPeer, offsetId: Int32(loadMoreToken), limit: Int32(limit))) + let signal: Signal + var additionalFolders: Signal = .single(nil) + if let folderId { + signal = account.network.request(Api.functions.stories.getAlbumStories(peer: inputPeer, albumId: Int32(clamping: folderId), offset: Int32(loadMoreToken), limit: Int32(limit))) |> map(Optional.init) } else { - signal = account.network.request(Api.functions.stories.getPinnedStories(peer: inputPeer, offsetId: Int32(loadMoreToken), limit: Int32(limit))) + if isArchived { + signal = account.network.request(Api.functions.stories.getStoriesArchive(peer: inputPeer, offsetId: Int32(loadMoreToken), limit: Int32(limit))) |> map(Optional.init) + } else { + signal = account.network.request(Api.functions.stories.getPinnedStories(peer: inputPeer, offsetId: Int32(loadMoreToken), limit: Int32(limit))) |> map(Optional.init) + additionalFolders = account.network.request(Api.functions.stories.getAlbums(peer: inputPeer, hash: 0)) + |> map(Optional.init) + } } - return signal - |> map { result -> Api.stories.Stories? in - return result - } - |> `catch` { _ -> Signal in - return .single(nil) - } - |> mapToSignal { result -> Signal<([State.Item], Int, PeerReference?, Bool), NoError> in - guard let result = result else { - return .single(([], 0, nil, false)) + return combineLatest( + signal + |> `catch` { _ -> Signal in + return .single(nil) + }, + additionalFolders + |> `catch` { _ -> Signal in + return .single(nil) + } + ) + |> mapToSignal { result, updatedFolders -> Signal<([State.Item], Int, PeerReference?, [State.Folder], Bool), NoError> in + guard let result else { + return .single(([], 0, nil, [], false)) } - return account.postbox.transaction { transaction -> ([State.Item], Int, PeerReference?, Bool) in + return account.postbox.transaction { transaction -> ([State.Item], Int, PeerReference?, [State.Folder], Bool) in var storyItems: [State.Item] = [] var totalCount: Int = 0 var hasMore: Bool = false + var folderItems: [State.Folder] = [] - if let folderId { - let key = ValueBoxKey(length: 8 + 1 + 8) - key.setInt64(0, value: peerId.toInt64()) - key.setInt8(8, value: isArchived ? 1 : 0) - key.setInt64(8 + 1, value: folderId) - - var updatedItems: [Stories.StoredItem] = [] - if let currentEntry = transaction.retrieveItemCacheEntry(id: ItemCacheEntryId(collectionId: Namespaces.CachedItemCollection.cachedPeerStoryListHeads, key: key))?.get(CachedPeerStoryListHead.self) { - updatedItems = currentEntry.items - } - - if let entry = CodableEntry(CachedPeerStoryListHead(items: updatedItems, pinnedIds: [], totalCount: Int32(updatedItems.count), folders: [])) { - transaction.putItemCacheEntry(id: ItemCacheEntryId(collectionId: Namespaces.CachedItemCollection.cachedPeerStoryListHeads, key: key), entry: entry) - } - - for item in updatedItems { - if case let .item(item) = item, let media = item.media { - let mappedItem = EngineStoryItem( - id: item.id, - timestamp: item.timestamp, - expirationTimestamp: item.expirationTimestamp, - media: EngineMedia(media), - alternativeMediaList: item.alternativeMediaList.map(EngineMedia.init), - mediaAreas: item.mediaAreas, - text: item.text, - entities: item.entities, - views: item.views.flatMap { views in - return EngineStoryItem.Views( - seenCount: views.seenCount, - reactedCount: views.reactedCount, - forwardCount: views.forwardCount, - seenPeers: views.seenPeerIds.compactMap { id -> EnginePeer? in - return transaction.getPeer(id).flatMap(EnginePeer.init) - }, - reactions: views.reactions, - hasList: views.hasList - ) - }, - privacy: item.privacy.flatMap(EngineStoryPrivacy.init), - isPinned: item.isPinned, - isExpired: item.isExpired, - isPublic: item.isPublic, - isPending: false, - isCloseFriends: item.isCloseFriends, - isContacts: item.isContacts, - isSelectedContacts: item.isSelectedContacts, - isForwardingDisabled: item.isForwardingDisabled, - isEdited: item.isEdited, - isMy: item.isMy, - myReaction: item.myReaction, - forwardInfo: item.forwardInfo.flatMap { EngineStoryItem.ForwardInfo($0, transaction: transaction) }, - author: item.authorId.flatMap { transaction.getPeer($0).flatMap(EnginePeer.init) } - ) - storyItems.append(State.Item( - id: StoryId(peerId: peerId, id: mappedItem.id), - storyItem: mappedItem, - peer: nil - )) + if let updatedFolders { + switch updatedFolders { + case let .albums(_, albums): + for album in albums { + switch album { + case let .storyAlbum(_, albumId, title, iconPhoto, iconVideo): + let _ = iconPhoto + let _ = iconVideo + folderItems.append(State.Folder( + id: Int64(albumId), + title: title + )) + } } + case .albumsNotModified: + break } + } else { + let key = ValueBoxKey(length: 8 + 1) + key.setInt64(0, value: peerId.toInt64()) + key.setInt8(8, value: 0) - totalCount = storyItems.count - hasMore = false - - return (storyItems, totalCount, transaction.getPeer(peerId).flatMap(PeerReference.init), hasMore) + if let cached = transaction.retrieveItemCacheEntry(id: ItemCacheEntryId(collectionId: Namespaces.CachedItemCollection.cachedPeerStoryListHeads, key: key))?.get(CachedPeerStoryListHead.self) { + folderItems = cached.folders + } } switch result { @@ -985,20 +957,38 @@ public final class PeerStoryListContext: StoryListContext { } if loadMoreToken == 0 { + let key: ValueBoxKey + if let folderId { + key = ValueBoxKey(length: 8 + 1 + 8) + key.setInt64(0, value: peerId.toInt64()) + key.setInt8(8, value: isArchived ? 1 : 0) + key.setInt64(8 + 1, value: folderId) + } else { + key = ValueBoxKey(length: 8 + 1) + key.setInt64(0, value: peerId.toInt64()) + key.setInt8(8, value: isArchived ? 1 : 0) + } + if let entry = CodableEntry(CachedPeerStoryListHead(items: storyItems.prefix(100).map { .item($0.storyItem.asStoryItem()) }, pinnedIds: pinnedIds, totalCount: count, folders: folderId == nil ? folderItems : [])) { + transaction.putItemCacheEntry(id: ItemCacheEntryId(collectionId: Namespaces.CachedItemCollection.cachedPeerStoryListHeads, key: key), entry: entry) + } + } else if folderId == nil && updatedFolders != nil { let key = ValueBoxKey(length: 8 + 1) key.setInt64(0, value: peerId.toInt64()) - key.setInt8(8, value: isArchived ? 1 : 0) - if let entry = CodableEntry(CachedPeerStoryListHead(items: storyItems.prefix(100).map { .item($0.storyItem.asStoryItem()) }, pinnedIds: pinnedIds, totalCount: count, folders: folders)) { - transaction.putItemCacheEntry(id: ItemCacheEntryId(collectionId: Namespaces.CachedItemCollection.cachedPeerStoryListHeads, key: key), entry: entry) + key.setInt8(8, value: 0) + + if let cached = transaction.retrieveItemCacheEntry(id: ItemCacheEntryId(collectionId: Namespaces.CachedItemCollection.cachedPeerStoryListHeads, key: key))?.get(CachedPeerStoryListHead.self) { + if let entry = CodableEntry(CachedPeerStoryListHead(items: cached.items, pinnedIds: cached.pinnedIds, totalCount: cached.totalCount, folders: folderItems)) { + transaction.putItemCacheEntry(id: ItemCacheEntryId(collectionId: Namespaces.CachedItemCollection.cachedPeerStoryListHeads, key: key), entry: entry) + } } } } - return (storyItems, totalCount, transaction.getPeer(peerId).flatMap(PeerReference.init), hasMore) + return (storyItems, totalCount, transaction.getPeer(peerId).flatMap(PeerReference.init), folderItems, hasMore) } } } - |> deliverOn(self.queue)).start(next: { [weak self] storyItems, totalCount, peerReference, hasMore in + |> deliverOn(self.queue)).start(next: { [weak self] storyItems, totalCount, peerReference, folderItems, hasMore in guard let self else { return } @@ -1022,6 +1012,8 @@ public final class PeerStoryListContext: StoryListContext { updatedState.items.append(item) } + updatedState.availableFolders = folderItems + if updatedState.peerReference == nil { updatedState.peerReference = peerReference } @@ -1376,55 +1368,93 @@ public final class PeerStoryListContext: StoryListContext { }) } - func addFolder(title: String) -> Int64 { - let id = Int64.random(in: Int64.min ... Int64.max) - - var state = self.stateValue - state.availableFolders.append(StoryListContextState.Folder(id: id, title: title)) - self.stateValue = state - + func addFolder(title: String, completion: @escaping (Int64?) -> Void) -> Disposable { let peerId = self.peerId - let isArchived = self.isArchived - let items = state.items - let pinnedIds = state.pinnedIds - let totalCount = state.totalCount - let folders = state.availableFolders - let _ = (self.account.postbox.transaction { transaction -> Void in - let key = ValueBoxKey(length: 8 + 1) - key.setInt64(0, value: peerId.toInt64()) - key.setInt8(8, value: isArchived ? 1 : 0) - if let entry = CodableEntry(CachedPeerStoryListHead(items: items.prefix(100).map { .item($0.storyItem.asStoryItem()) }, pinnedIds: pinnedIds, totalCount: Int32(totalCount), folders: folders)) { - transaction.putItemCacheEntry(id: ItemCacheEntryId(collectionId: Namespaces.CachedItemCollection.cachedPeerStoryListHeads, key: key), entry: entry) + return (self.account.postbox.transaction { transaction -> Api.InputPeer? in + return transaction.getPeer(peerId).flatMap(apiInputPeer) + } + |> mapToSignal { inputPeer -> Signal in + guard let inputPeer else { + return .single(nil) } - }).start() - - return id + return self.account.network.request(Api.functions.stories.createAlbum( + peer: inputPeer, title: title, stories: [])) + |> map(Optional.init) + |> `catch` { _ -> Signal in + return .single(nil) + } + } + |> deliverOn(self.queue)).start(next: { [weak self] result in + guard let self else { + return + } + if let result { + switch result { + case let .storyAlbum(_, albumId, _, _, _): + var state = self.stateValue + state.availableFolders.insert(StoryListContextState.Folder(id: Int64(albumId), title: title), at: 0) + self.stateValue = state + + let peerId = self.peerId + let isArchived = self.isArchived + let items = state.items + let pinnedIds = state.pinnedIds + let totalCount = state.totalCount + let folders = state.availableFolders + let _ = (self.account.postbox.transaction { transaction -> Void in + let key = ValueBoxKey(length: 8 + 1) + key.setInt64(0, value: peerId.toInt64()) + key.setInt8(8, value: isArchived ? 1 : 0) + if let entry = CodableEntry(CachedPeerStoryListHead(items: items.prefix(100).map { .item($0.storyItem.asStoryItem()) }, pinnedIds: pinnedIds, totalCount: Int32(totalCount), folders: folders)) { + transaction.putItemCacheEntry(id: ItemCacheEntryId(collectionId: Namespaces.CachedItemCollection.cachedPeerStoryListHeads, key: key), entry: entry) + } + } |> deliverOn(self.queue)).start(completed: { + completion(Int64(albumId)) + }) + } + } else { + completion(nil) + } + }) } - func removeFolder(id: Int64) { + func removeFolder(id: Int64) -> Disposable { var state = self.stateValue if let index = state.availableFolders.firstIndex(where: { $0.id == id }) { state.availableFolders.remove(at: index) } self.stateValue = state + let account = self.account let peerId = self.peerId let isArchived = self.isArchived let items = state.items let pinnedIds = state.pinnedIds let totalCount = state.totalCount let folders = state.availableFolders - let _ = (self.account.postbox.transaction { transaction -> Void in + return (account.postbox.transaction { transaction -> Api.InputPeer? in let key = ValueBoxKey(length: 8 + 1) key.setInt64(0, value: peerId.toInt64()) key.setInt8(8, value: isArchived ? 1 : 0) if let entry = CodableEntry(CachedPeerStoryListHead(items: items.prefix(100).map { .item($0.storyItem.asStoryItem()) }, pinnedIds: pinnedIds, totalCount: Int32(totalCount), folders: folders)) { transaction.putItemCacheEntry(id: ItemCacheEntryId(collectionId: Namespaces.CachedItemCollection.cachedPeerStoryListHeads, key: key), entry: entry) } + + return transaction.getPeer(peerId).flatMap(apiInputPeer) + } + |> mapToSignal { inputPeer -> Signal in + guard let inputPeer else { + return .complete() + } + return account.network.request(Api.functions.stories.deleteAlbum(peer: inputPeer, albumId: Int32(clamping: id))) + |> `catch` { _ -> Signal in + return .single(.boolFalse) + } + |> ignoreValues }).start() } - func reorderFolders(ids: [Int64]) { + func reorderFolders(ids: [Int64]) -> Disposable { var state = self.stateValue var folders: [State.Folder] = [] for id in ids { @@ -1440,24 +1470,51 @@ public final class PeerStoryListContext: StoryListContext { state.availableFolders = folders self.stateValue = state + let account = self.account let peerId = self.peerId let isArchived = self.isArchived let items = state.items let pinnedIds = state.pinnedIds let totalCount = state.totalCount - let _ = (self.account.postbox.transaction { transaction -> Void in + return (account.postbox.transaction { transaction -> Api.InputPeer? in let key = ValueBoxKey(length: 8 + 1) key.setInt64(0, value: peerId.toInt64()) key.setInt8(8, value: isArchived ? 1 : 0) if let entry = CodableEntry(CachedPeerStoryListHead(items: items.prefix(100).map { .item($0.storyItem.asStoryItem()) }, pinnedIds: pinnedIds, totalCount: Int32(totalCount), folders: folders)) { transaction.putItemCacheEntry(id: ItemCacheEntryId(collectionId: Namespaces.CachedItemCollection.cachedPeerStoryListHeads, key: key), entry: entry) } + return transaction.getPeer(peerId).flatMap(apiInputPeer) + } + |> mapToSignal { inputPeer -> Signal in + guard let inputPeer else { + return .complete() + } + return account.network.request(Api.functions.stories.reorderAlbums(peer: inputPeer, order: ids.map(Int32.init(clamping:)))) + |> `catch` { _ -> Signal in + return .single(.boolFalse) + } + |> ignoreValues }).start() } - func addToFolder(id: Int64, items: [EngineStoryItem]) { + func addToFolder(id: Int64, items: [EngineStoryItem]) -> Disposable { + if self.folderId == id { + var state = self.stateValue + for item in items { + state.items.removeAll(where: { $0.id.id == item.id }) + state.items.insert(StoryListContextState.Item( + id: StoryId(peerId: self.peerId, id: item.id), + storyItem: item, + peer: nil + ), at: 0) + } + state.totalCount = state.items.count + self.stateValue = state + } + + let account = self.account let peerId = self.peerId - let _ = (self.account.postbox.transaction { transaction -> Void in + return (account.postbox.transaction { transaction -> Api.InputPeer? in let key = ValueBoxKey(length: 8 + 1 + 8) key.setInt64(0, value: peerId.toInt64()) key.setInt8(8, value: 0) @@ -1528,26 +1585,35 @@ public final class PeerStoryListContext: StoryListContext { if let entry = CodableEntry(CachedPeerStoryListHead(items: updatedItems.map { .item($0) }, pinnedIds: [], totalCount: Int32(updatedItems.count), folders: [])) { transaction.putItemCacheEntry(id: ItemCacheEntryId(collectionId: Namespaces.CachedItemCollection.cachedPeerStoryListHeads, key: key), entry: entry) } + + return transaction.getPeer(peerId).flatMap(apiInputPeer) + } + |> mapToSignal { inputPeer -> Signal in + guard let inputPeer else { + return .complete() + } + var flags: Int32 = 0 + flags |= 1 << 2 + return account.network.request(Api.functions.stories.updateAlbum(flags: flags, peer: inputPeer, albumId: Int32(clamping: id), title: nil, deleteStories: nil, addStories: items.map(\.id), order: nil)) + |> map(Optional.init) + |> `catch` { _ -> Signal in + return .single(nil) + } + |> ignoreValues }).start() - + } + + func removeFromFolder(id: Int64, itemIds: [Int32]) -> Disposable { if self.folderId == id { var state = self.stateValue - for item in items { - state.items.removeAll(where: { $0.id.id == item.id }) - state.items.insert(StoryListContextState.Item( - id: StoryId(peerId: self.peerId, id: item.id), - storyItem: item, - peer: nil - ), at: 0) - } + state.items.removeAll(where: { itemIds.contains($0.id.id) }) state.totalCount = state.items.count self.stateValue = state } - } - - func removeFromFolder(id: Int64, itemIds: [Int32]) { + + let account = self.account let peerId = self.peerId - let _ = (self.account.postbox.transaction { transaction -> Void in + return (account.postbox.transaction { transaction -> Api.InputPeer? in let key = ValueBoxKey(length: 8 + 1 + 8) key.setInt64(0, value: peerId.toInt64()) key.setInt8(8, value: 0) @@ -1573,23 +1639,52 @@ public final class PeerStoryListContext: StoryListContext { if let entry = CodableEntry(CachedPeerStoryListHead(items: updatedItems.map { .item($0) }, pinnedIds: [], totalCount: Int32(updatedItems.count), folders: [])) { transaction.putItemCacheEntry(id: ItemCacheEntryId(collectionId: Namespaces.CachedItemCollection.cachedPeerStoryListHeads, key: key), entry: entry) } + + return transaction.getPeer(peerId).flatMap(apiInputPeer) + } + |> mapToSignal { inputPeer -> Signal in + guard let inputPeer else { + return .complete() + } + var flags: Int32 = 0 + flags |= 1 << 1 + return account.network.request(Api.functions.stories.updateAlbum(flags: flags, peer: inputPeer, albumId: Int32(clamping: id), title: nil, deleteStories: itemIds, addStories: nil, order: nil)) + |> map(Optional.init) + |> `catch` { _ -> Signal in + return .single(nil) + } + |> ignoreValues }).start() + } + + func reorderItemsInFolder(itemIds: [Int32]) -> Disposable { + guard let id = self.folderId else { + return EmptyDisposable + } if self.folderId == id { var state = self.stateValue - state.items.removeAll(where: { itemIds.contains($0.id.id) }) - state.totalCount = state.items.count + + let previousItems = state.items + var updatedItems: [State.Item] = [] + for itemId in itemIds { + if let index = previousItems.firstIndex(where: { $0.id.id == itemId }) { + updatedItems.append(previousItems[index]) + } + } + for item in previousItems { + if !updatedItems.contains(where: { $0.id == item.id }) { + updatedItems.append(item) + } + } + + state.items = updatedItems self.stateValue = state } - } - - func reorderItemsInFolder(itemIds: [Int32]) { - guard let id = self.folderId else { - return - } + let account = self.account let peerId = self.peerId - let _ = (self.account.postbox.transaction { transaction -> Void in + return (account.postbox.transaction { transaction -> Api.InputPeer? in let key = ValueBoxKey(length: 8 + 1 + 8) key.setInt64(0, value: peerId.toInt64()) key.setInt8(8, value: 0) @@ -1622,27 +1717,22 @@ public final class PeerStoryListContext: StoryListContext { if let entry = CodableEntry(CachedPeerStoryListHead(items: updatedItems.map { .item($0) }, pinnedIds: [], totalCount: Int32(updatedItems.count), folders: [])) { transaction.putItemCacheEntry(id: ItemCacheEntryId(collectionId: Namespaces.CachedItemCollection.cachedPeerStoryListHeads, key: key), entry: entry) } - }).start() - - if self.folderId == id { - var state = self.stateValue - let previousItems = state.items - var updatedItems: [State.Item] = [] - for itemId in itemIds { - if let index = previousItems.firstIndex(where: { $0.id.id == itemId }) { - updatedItems.append(previousItems[index]) - } - } - for item in previousItems { - if !updatedItems.contains(where: { $0.id == item.id }) { - updatedItems.append(item) - } - } - - state.items = updatedItems - self.stateValue = state + return transaction.getPeer(peerId).flatMap(apiInputPeer) } + |> mapToSignal { inputPeer -> Signal in + guard let inputPeer else { + return .complete() + } + var flags: Int32 = 0 + flags |= 1 << 3 + return account.network.request(Api.functions.stories.updateAlbum(flags: flags, peer: inputPeer, albumId: Int32(clamping: id), title: nil, deleteStories: nil, addStories: nil, order: itemIds)) + |> map(Optional.init) + |> `catch` { _ -> Signal in + return .single(nil) + } + |> ignoreValues + }).start() } } @@ -1676,61 +1766,92 @@ public final class PeerStoryListContext: StoryListContext { } } - public func addFolder(title: String, completion: @escaping (Int64) -> Void) { + public func addFolder(title: String, completion: @escaping (Int64?) -> Void) -> Disposable { + let disposable = MetaDisposable() self.impl.with { impl in - completion(impl.addFolder(title: title)) + disposable.set(impl.addFolder(title: title, completion: completion)) } + return disposable } - public func removeFolder(id: Int64) { + public func removeFolder(id: Int64) -> Disposable { + let disposable = MetaDisposable() self.impl.with { impl in - impl.removeFolder(id: id) + disposable.set(impl.removeFolder(id: id)) } + return disposable } - public func reorderFolders(ids: [Int64]) { + public func reorderFolders(ids: [Int64]) -> Disposable { + let disposable = MetaDisposable() self.impl.with { impl in - impl.reorderFolders(ids: ids) + disposable.set(impl.reorderFolders(ids: ids)) } + return disposable } - public func addToFolder(id: Int64, items: [EngineStoryItem]) { + public func addToFolder(id: Int64, items: [EngineStoryItem]) -> Disposable { + let disposable = MetaDisposable() self.impl.with { impl in - impl.addToFolder(id: id, items: items) + disposable.set(impl.addToFolder(id: id, items: items)) } + return disposable } - public func removeFromFolder(id: Int64, itemIds: [Int32]) { + public func removeFromFolder(id: Int64, itemIds: [Int32]) -> Disposable { + let disposable = MetaDisposable() self.impl.with { impl in - impl.removeFromFolder(id: id, itemIds: itemIds) + disposable.set(impl.removeFromFolder(id: id, itemIds: itemIds)) } + return disposable } - public func reorderItemsInFolder(itemIds: [Int32]) { + public func reorderItemsInFolder(itemIds: [Int32]) -> Disposable { + let disposable = MetaDisposable() self.impl.with { impl in - impl.reorderItemsInFolder(itemIds: itemIds) + disposable.set(impl.reorderItemsInFolder(itemIds: itemIds)) } + return disposable } - public static func addFolderExternal(account: Account, peerId: PeerId, title: String) -> Int64 { - let id = Int64.random(in: Int64.min ... Int64.max) - - let _ = (account.postbox.transaction { transaction -> Void in - let key = ValueBoxKey(length: 8 + 1) - key.setInt64(0, value: peerId.toInt64()) - key.setInt8(8, value: 0) - - - let cached = transaction.retrieveItemCacheEntry(id: ItemCacheEntryId(collectionId: Namespaces.CachedItemCollection.cachedPeerStoryListHeads, key: key))?.get(CachedPeerStoryListHead.self) - var folders = cached?.folders ?? [] - folders.append(StoryListContextState.Folder(id: id, title: title)) - - if let entry = CodableEntry(CachedPeerStoryListHead(items: cached?.items ?? [], pinnedIds: cached?.pinnedIds ?? [], totalCount: cached?.totalCount ?? 0, folders: folders)) { - transaction.putItemCacheEntry(id: ItemCacheEntryId(collectionId: Namespaces.CachedItemCollection.cachedPeerStoryListHeads, key: key), entry: entry) + public static func addFolderExternal(account: Account, peerId: PeerId, title: String, completion: @escaping (Int64?) -> Void) -> Disposable { + return (account.postbox.transaction { transaction -> Api.InputPeer? in + return transaction.getPeer(peerId).flatMap(apiInputPeer) + } + |> mapToSignal { inputPeer -> Signal in + guard let inputPeer else { + return .single(nil) } - }).start() - - return id + return account.network.request(Api.functions.stories.createAlbum( + peer: inputPeer, title: title, stories: [])) + |> map(Optional.init) + |> `catch` { _ -> Signal in + return .single(nil) + } + }).start(next: { result in + if let result { + switch result { + case let .storyAlbum(_, albumId, _, _, _): + let _ = (account.postbox.transaction { transaction -> Void in + let key = ValueBoxKey(length: 8 + 1) + key.setInt64(0, value: peerId.toInt64()) + key.setInt8(8, value: 0) + + let cached = transaction.retrieveItemCacheEntry(id: ItemCacheEntryId(collectionId: Namespaces.CachedItemCollection.cachedPeerStoryListHeads, key: key))?.get(CachedPeerStoryListHead.self) + var folders = cached?.folders ?? [] + folders.append(StoryListContextState.Folder(id: Int64(albumId), title: title)) + + if let entry = CodableEntry(CachedPeerStoryListHead(items: cached?.items ?? [], pinnedIds: cached?.pinnedIds ?? [], totalCount: cached?.totalCount ?? 0, folders: folders)) { + transaction.putItemCacheEntry(id: ItemCacheEntryId(collectionId: Namespaces.CachedItemCollection.cachedPeerStoryListHeads, key: key), entry: entry) + } + }).start(completed: { + completion(Int64(albumId)) + }) + } + } else { + completion(nil) + } + }) } public static func folderPreviews(peerId: EnginePeer.Id, account: Account) -> Signal<(peer: PeerReference, [(folder: StoryListContext.State.Folder, item: EngineStoryItem?)]), NoError> { diff --git a/submodules/TelegramCore/Sources/TelegramEngine/Messages/TelegramEngineMessages.swift b/submodules/TelegramCore/Sources/TelegramEngine/Messages/TelegramEngineMessages.swift index ae90822692..0ed3892780 100644 --- a/submodules/TelegramCore/Sources/TelegramEngine/Messages/TelegramEngineMessages.swift +++ b/submodules/TelegramCore/Sources/TelegramEngine/Messages/TelegramEngineMessages.swift @@ -1367,8 +1367,8 @@ public extension TelegramEngine { } } - public func uploadStory(target: Stories.PendingTarget, media: EngineStoryInputMedia, mediaAreas: [MediaArea], text: String, entities: [MessageTextEntity], pin: Bool, privacy: EngineStoryPrivacy, isForwardingDisabled: Bool, period: Int, randomId: Int64, forwardInfo: Stories.PendingForwardInfo?, uploadInfo: StoryUploadInfo? = nil) -> Signal { - return _internal_uploadStory(account: self.account, target: target, media: media, mediaAreas: mediaAreas, text: text, entities: entities, pin: pin, privacy: privacy, isForwardingDisabled: isForwardingDisabled, period: period, randomId: randomId, forwardInfo: forwardInfo, uploadInfo: uploadInfo) + public func uploadStory(target: Stories.PendingTarget, media: EngineStoryInputMedia, mediaAreas: [MediaArea], text: String, entities: [MessageTextEntity], pin: Bool, privacy: EngineStoryPrivacy, isForwardingDisabled: Bool, period: Int, randomId: Int64, forwardInfo: Stories.PendingForwardInfo?, folders: [Int64], uploadInfo: StoryUploadInfo? = nil) -> Signal { + return _internal_uploadStory(account: self.account, target: target, media: media, mediaAreas: mediaAreas, text: text, entities: entities, pin: pin, privacy: privacy, isForwardingDisabled: isForwardingDisabled, period: period, randomId: randomId, forwardInfo: forwardInfo, folders: folders, uploadInfo: uploadInfo) } public func allStoriesUploadEvents() -> Signal<(Int32, Int32), NoError> { diff --git a/submodules/TelegramUI/Components/MediaEditorScreen/Sources/EditStories.swift b/submodules/TelegramUI/Components/MediaEditorScreen/Sources/EditStories.swift index e8cc73e516..3359bf0c1d 100644 --- a/submodules/TelegramUI/Components/MediaEditorScreen/Sources/EditStories.swift +++ b/submodules/TelegramUI/Components/MediaEditorScreen/Sources/EditStories.swift @@ -163,7 +163,7 @@ public extension MediaEditorScreenImpl { } else { existingMedia = storyItem.media } - rootController.proceedWithStoryUpload(target: target, results: [result as! MediaEditorScreenResult], existingMedia: existingMedia, forwardInfo: forwardInfo, externalState: externalState, commit: commit) + rootController.proceedWithStoryUpload(target: target, results: [result as! MediaEditorScreenResult], existingMedia: existingMedia, forwardInfo: forwardInfo, folders: [], externalState: externalState, commit: commit) } }) } else { diff --git a/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/PeerInfoScreen.swift b/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/PeerInfoScreen.swift index 400e9140a8..06d2feb66b 100644 --- a/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/PeerInfoScreen.swift +++ b/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/PeerInfoScreen.swift @@ -10258,7 +10258,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, PeerInfoScreenNodePro viewControllers = viewControllers.filter { !($0 is AttachmentController)} rootController.setViewControllers(viewControllers, animated: false) - rootController.proceedWithStoryUpload(target: target, results: [result], existingMedia: nil, forwardInfo: nil, externalState: externalState, commit: commit) + rootController.proceedWithStoryUpload(target: target, results: [result], existingMedia: nil, forwardInfo: nil, folders: [], externalState: externalState, commit: commit) } }, cancelled: {} diff --git a/submodules/TelegramUI/Components/PeerInfo/PeerInfoVisualMediaPaneNode/Sources/PeerInfoStoryPaneNode.swift b/submodules/TelegramUI/Components/PeerInfo/PeerInfoVisualMediaPaneNode/Sources/PeerInfoStoryPaneNode.swift index 6814d08189..7f1cdd3f54 100644 --- a/submodules/TelegramUI/Components/PeerInfo/PeerInfoVisualMediaPaneNode/Sources/PeerInfoStoryPaneNode.swift +++ b/submodules/TelegramUI/Components/PeerInfo/PeerInfoVisualMediaPaneNode/Sources/PeerInfoStoryPaneNode.swift @@ -2481,7 +2481,7 @@ public final class PeerInfoStoryPaneNode: ASDisplayNode, PeerInfoPaneNode, ASScr } if let listSource = self.listSource as? PeerStoryListContext { - listSource.removeFromFolder(id: folder.id, itemIds: [item.id]) + let _ = listSource.removeFromFolder(id: folder.id, itemIds: [item.id]) } f(.dismissWithoutContent) @@ -2575,7 +2575,7 @@ public final class PeerInfoStoryPaneNode: ASDisplayNode, PeerInfoPaneNode, ASScr c?.dismiss(completion: {}) if let listSource = self.listSource as? PeerStoryListContext { - listSource.addToFolder(id: folderPreview.folder.id, items: [item]) + let _ = listSource.addToFolder(id: folderPreview.folder.id, items: [item]) } }))) } @@ -4900,13 +4900,13 @@ public final class PeerInfoStoryPaneNode: ASDisplayNode, PeerInfoPaneNode, ASScr } if let value { if let listSource = self.listSource as? PeerStoryListContext { - listSource.addFolder(title: value, completion: { [weak self] id in + let _ = listSource.addFolder(title: value, completion: { [weak self] id in Queue.mainQueue().async { - guard let self, let listSource = self.listSource as? PeerStoryListContext else { + guard let self, let id, let listSource = self.listSource as? PeerStoryListContext else { return } if !addItems.isEmpty { - listSource.addToFolder(id: id, items: addItems) + let _ = listSource.addToFolder(id: id, items: addItems) } self.setStoryFolder(id: id, assumeEmpty: addItems.isEmpty) } @@ -4931,7 +4931,7 @@ public final class PeerInfoStoryPaneNode: ASDisplayNode, PeerInfoPaneNode, ASScr return } if let listSource = self.listSource as? PeerStoryListContext { - listSource.addToFolder(id: folder.id, items: items) + let _ = listSource.addToFolder(id: folder.id, items: items) } }) controller.navigationPresentation = .modal @@ -4958,7 +4958,7 @@ public final class PeerInfoStoryPaneNode: ASDisplayNode, PeerInfoPaneNode, ASScr self.removedStoryFolders.insert(id) if let listContext = self.listSource as? PeerStoryListContext { - listContext.removeFolder(id: id) + let _ = listContext.removeFolder(id: id) } if let (size, topInset, sideInset, bottomInset, deviceMetrics, visibleHeight, isScrollingLockedAtTop, expandProgress, navigationHeight, presentationData) = self.currentParams { @@ -5111,7 +5111,7 @@ public final class PeerInfoStoryPaneNode: ASDisplayNode, PeerInfoPaneNode, ASScr if !isReordering && !self.currentStoryFolders.isEmpty && self.canManageStories { if let listSource = self.listSource as? PeerStoryListContext { - listSource.reorderFolders(ids: self.currentStoryFolders.map(\.id)) + let _ = listSource.reorderFolders(ids: self.currentStoryFolders.map(\.id)) } } @@ -5132,7 +5132,7 @@ public final class PeerInfoStoryPaneNode: ASDisplayNode, PeerInfoPaneNode, ASScr } else if case let .peer(id, _, _) = self.scope, id == self.context.account.peerId, let items = self.items { if let _ = self.currentStoryFolder { if let listSource = self.listSource as? PeerStoryListContext { - listSource.reorderItemsInFolder(itemIds: reorderedIds.map { $0.id }) + let _ = listSource.reorderItemsInFolder(itemIds: reorderedIds.map { $0.id }) } } else { var updatedPinnedIds: [Int32] = [] diff --git a/submodules/TelegramUI/Components/ShareWithPeersScreen/Sources/ShareWithPeersScreen.swift b/submodules/TelegramUI/Components/ShareWithPeersScreen/Sources/ShareWithPeersScreen.swift index cf04937b71..5cb946e270 100644 --- a/submodules/TelegramUI/Components/ShareWithPeersScreen/Sources/ShareWithPeersScreen.swift +++ b/submodules/TelegramUI/Components/ShareWithPeersScreen/Sources/ShareWithPeersScreen.swift @@ -1005,12 +1005,17 @@ final class ShareWithPeersScreenComponent: Component { return } if let value, !value.isEmpty { - let id = PeerStoryListContext.addFolderExternal(account: component.context.account, peerId: component.context.account.peerId, title: value) - self.shareToFolders.append(StoryListContext.State.Folder( - id: id, - title: value - )) - self.state?.updated(transition: .immediate) + let _ = PeerStoryListContext.addFolderExternal(account: component.context.account, peerId: component.context.account.peerId, title: value, completion: { [weak self] id in + guard let self, let id else { + return + } + + self.shareToFolders.append(StoryListContext.State.Folder( + id: id, + title: value + )) + self.state?.updated(transition: .immediate) + }) } } ) diff --git a/submodules/TelegramUI/Components/Stories/StoryContainerScreen/Sources/StoryContainerScreen.swift b/submodules/TelegramUI/Components/Stories/StoryContainerScreen/Sources/StoryContainerScreen.swift index b22b6aefb3..df2e7e0a69 100644 --- a/submodules/TelegramUI/Components/Stories/StoryContainerScreen/Sources/StoryContainerScreen.swift +++ b/submodules/TelegramUI/Components/Stories/StoryContainerScreen/Sources/StoryContainerScreen.swift @@ -1695,13 +1695,13 @@ private final class StoryContainerScreenComponent: Component { if let content = component.content as? PeerStoryListContentContextImpl { if let listSource = content.listContext as? PeerStoryListContext { - listSource.addFolder(title: title, completion: { [weak listSource] id in + let _ = listSource.addFolder(title: title, completion: { [weak listSource] id in Queue.mainQueue().async { - guard let listSource else { + guard let listSource, let id else { return } if !items.isEmpty { - listSource.addToFolder(id: id, items: items) + let _ = listSource.addToFolder(id: id, items: items) } } }) @@ -1717,7 +1717,7 @@ private final class StoryContainerScreenComponent: Component { } if let content = component.content as? PeerStoryListContentContextImpl { if let listSource = content.listContext as? PeerStoryListContext { - listSource.addToFolder(id: folderId, items: [slice.item.storyItem]) + let _ = listSource.addToFolder(id: folderId, items: [slice.item.storyItem]) } } }, diff --git a/submodules/TelegramUI/Sources/OpenResolvedUrl.swift b/submodules/TelegramUI/Sources/OpenResolvedUrl.swift index f24d0624f1..6d1ece1b61 100644 --- a/submodules/TelegramUI/Sources/OpenResolvedUrl.swift +++ b/submodules/TelegramUI/Sources/OpenResolvedUrl.swift @@ -992,7 +992,7 @@ func openResolvedUrlImpl( if let rootController = context.sharedContext.mainWindow?.viewController as? TelegramRootControllerInterface { rootController.popToRoot(animated: false) - rootController.proceedWithStoryUpload(target: target, results: results, existingMedia: nil, forwardInfo: nil, externalState: externalState, commit: commit) + rootController.proceedWithStoryUpload(target: target, results: results, existingMedia: nil, forwardInfo: nil, folders: [], externalState: externalState, commit: commit) } }) if let navigationController { diff --git a/submodules/TelegramUI/Sources/SharedAccountContext.swift b/submodules/TelegramUI/Sources/SharedAccountContext.swift index 48ad0ae251..b8eb922eb4 100644 --- a/submodules/TelegramUI/Sources/SharedAccountContext.swift +++ b/submodules/TelegramUI/Sources/SharedAccountContext.swift @@ -3821,7 +3821,7 @@ public final class SharedAccountContextImpl: SharedAccountContext { externalState.storyTarget = target if let rootController = context.sharedContext.mainWindow?.viewController as? TelegramRootControllerInterface { - rootController.proceedWithStoryUpload(target: target, results: [result], existingMedia: nil, forwardInfo: nil, externalState: externalState, commit: commit) + rootController.proceedWithStoryUpload(target: target, results: [result], existingMedia: nil, forwardInfo: nil, folders: [], externalState: externalState, commit: commit) } let _ = (context.engine.data.get(TelegramEngine.EngineData.Item.Peer.Peer(id: targetPeerId)) diff --git a/submodules/TelegramUI/Sources/TelegramRootController.swift b/submodules/TelegramUI/Sources/TelegramRootController.swift index 683e3bb911..0f743f7c67 100644 --- a/submodules/TelegramUI/Sources/TelegramRootController.swift +++ b/submodules/TelegramUI/Sources/TelegramRootController.swift @@ -471,7 +471,7 @@ public final class TelegramRootController: NavigationController, TelegramRootCon if let customTarget, case .botPreview = customTarget { externalState.storyTarget = customTarget - self.proceedWithStoryUpload(target: customTarget, results: results, existingMedia: nil, forwardInfo: nil, externalState: externalState, commit: commit) + self.proceedWithStoryUpload(target: customTarget, results: results, existingMedia: nil, forwardInfo: nil, folders: [], externalState: externalState, commit: commit) dismissCameraImpl?() return @@ -504,7 +504,7 @@ public final class TelegramRootController: NavigationController, TelegramRootCon externalState.isPeerArchived = channel.storiesHidden ?? false } - self.proceedWithStoryUpload(target: target, results: results, existingMedia: nil, forwardInfo: nil, externalState: externalState, commit: commit) + self.proceedWithStoryUpload(target: target, results: results, existingMedia: nil, forwardInfo: nil, folders: [], externalState: externalState, commit: commit) dismissCameraImpl?() }) @@ -568,7 +568,7 @@ public final class TelegramRootController: NavigationController, TelegramRootCon }) } - public func proceedWithStoryUpload(target: Stories.PendingTarget, results: [MediaEditorScreenResult], existingMedia: EngineMedia?, forwardInfo: Stories.PendingForwardInfo?, externalState: MediaEditorTransitionOutExternalState, commit: @escaping (@escaping () -> Void) -> Void) { + public func proceedWithStoryUpload(target: Stories.PendingTarget, results: [MediaEditorScreenResult], existingMedia: EngineMedia?, forwardInfo: Stories.PendingForwardInfo?, folders: [Int64], externalState: MediaEditorTransitionOutExternalState, commit: @escaping (@escaping () -> Void) -> Void) { guard let results = results as? [MediaEditorScreenImpl.Result] else { return } @@ -753,6 +753,7 @@ public final class TelegramRootController: NavigationController, TelegramRootCon period: result.options.timeout, randomId: result.randomId, forwardInfo: forwardInfo, + folders: folders, uploadInfo: results.count > 1 ? StoryUploadInfo(groupingId: groupingId, index: index, total: Int32(results.count)) : nil ) |> deliverOnMainQueue).startStandalone(next: { stableId in diff --git a/submodules/WebUI/Sources/WebAppController.swift b/submodules/WebUI/Sources/WebAppController.swift index 3445a10613..aaa520fd2d 100644 --- a/submodules/WebUI/Sources/WebAppController.swift +++ b/submodules/WebUI/Sources/WebAppController.swift @@ -1494,7 +1494,7 @@ public final class WebAppController: ViewController, AttachmentContainable { externalState.storyTarget = target if let rootController = self.context.sharedContext.mainWindow?.viewController as? TelegramRootControllerInterface { - rootController.proceedWithStoryUpload(target: target, results: results, existingMedia: nil, forwardInfo: nil, externalState: externalState, commit: commit) + rootController.proceedWithStoryUpload(target: target, results: results, existingMedia: nil, forwardInfo: nil, folders: [], externalState: externalState, commit: commit) } }) if let navigationController = self.controller?.getNavigationController() {