mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-06-16 05:55:20 +00:00
Update API
This commit is contained in:
parent
a4175c44ca
commit
8477cf454c
@ -1214,6 +1214,7 @@ private final class NotificationServiceHandler {
|
||||
let collectedData = Atomic<DataValue>(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<Data>(value: Data())
|
||||
return standaloneMultipartFetch(
|
||||
accountPeerId: stateManager.accountPeerId,
|
||||
postbox: stateManager.postbox,
|
||||
network: stateManager.network,
|
||||
resource: resource,
|
||||
|
@ -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) {
|
||||
@ -2501,25 +2506,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) {
|
||||
|
@ -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:
|
||||
|
@ -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])
|
||||
|
@ -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])
|
||||
|
@ -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<Api.stories.StoryViewsList>) {
|
||||
static func getStoriesByID(userId: Api.InputUser, id: [Int32]) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.stories.Stories>) {
|
||||
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<Api.stories.StoryViews>) {
|
||||
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<Api.stories.StoryViewsList>) {
|
||||
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() {
|
||||
|
@ -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<MediaResourceDataFetchResult, MediaResourceDataFetchError> {
|
||||
return Signal { subscriber in
|
||||
let impl = FetchImpl(
|
||||
accountPeerId: accountPeerId,
|
||||
postbox: postbox,
|
||||
network: network,
|
||||
mediaReferenceRevalidationContext: mediaReferenceRevalidationContext,
|
||||
|
@ -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<StoryListContext.Item, RevalidateMediaReferenceError> {
|
||||
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<StoryListContext.Item, RevalidateMediaReferenceError> 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<StoryListContext.Item, RevalidateMediaReferenceError> 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<RevalidatedMediaResource, RevalidateMediaReferenceError> {
|
||||
func revalidateMediaResourceReference(accountPeerId: PeerId, postbox: Postbox, network: Network, revalidationContext: MediaReferenceRevalidationContext, info: TelegramCloudMediaResourceFetchInfo, resource: MediaResource) -> Signal<RevalidatedMediaResource, RevalidateMediaReferenceError> {
|
||||
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<RevalidatedMediaResource, RevalidateMediaReferenceError> 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 {
|
||||
|
@ -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<Int64>, 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<Int64>, 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<Int64>, MediaBoxFetchPriority)], NoError>, parameters: MediaResourceFetchParameters?, encryptionKey: SecretFileEncryptionKey? = nil, decryptedSize: Int32? = nil, continueInBackground: Bool = false, useMainConnection: Bool = false) -> Signal<MediaResourceDataFetchResult, MediaResourceDataFetchError> {
|
||||
public func standaloneMultipartFetch(accountPeerId: PeerId, postbox: Postbox, network: Network, resource: TelegramMediaResource, datacenterId: Int, size: Int64?, intervals: Signal<[(Range<Int64>, MediaBoxFetchPriority)], NoError>, parameters: MediaResourceFetchParameters?, encryptionKey: SecretFileEncryptionKey? = nil, decryptedSize: Int32? = nil, continueInBackground: Bool = false, useMainConnection: Bool = false) -> Signal<MediaResourceDataFetchResult, MediaResourceDataFetchError> {
|
||||
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<MediaResourceDataFetchResult, MediaResourceDataFetchError> {
|
||||
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,
|
||||
|
@ -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<PendingMessageUploadedContentResult, PendingMessageUploadError>? {
|
||||
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<PendingMessageUploadedContentResult, PendingMessageUploadError>? {
|
||||
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
|
||||
}
|
||||
|
@ -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 {
|
||||
|
@ -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<RequestEditMessageResult, RequestEditMessageError> {
|
||||
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<RequestEditMessageResult, RequestEditMessageError> {
|
||||
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<RequestEditMessageResult, RequestEditMessageError> {
|
||||
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<RequestEditMessageResult, RequestEditMessageInternalError> 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<RequestEditMessageResult, RequestEditMessageInternalError> {
|
||||
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<RequestEditMessageResult, RequestEditMessageInternalError> {
|
||||
let uploadedMedia: Signal<PendingMessageUploadedContentResult?, NoError>
|
||||
switch media {
|
||||
case .keep:
|
||||
@ -59,7 +59,7 @@ private func requestEditMessageInternal(postbox: Postbox, network: Network, stat
|
||||
case let .update(media):
|
||||
let generateUploadSignal: (Bool) -> Signal<PendingMessageUploadedContentResult, PendingMessageUploadError>? = { 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))
|
||||
|
@ -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))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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<TelegramAccountManagerTypes>
|
||||
private let networkArguments: NetworkInitializationArguments
|
||||
@ -22,9 +23,10 @@ final class AccountTaskManager {
|
||||
|
||||
private var isUpdating: Bool = false
|
||||
|
||||
init(queue: Queue, stateManager: AccountStateManager, accountManager: AccountManager<TelegramAccountManagerTypes>,
|
||||
init(queue: Queue, accountPeerId: PeerId, stateManager: AccountStateManager, accountManager: AccountManager<TelegramAccountManagerTypes>,
|
||||
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)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -23,7 +23,7 @@ private final class MediaResourceDataCopyFile : MediaResourceDataFetchCopyLocalI
|
||||
}
|
||||
|
||||
public func fetchCloudMediaLocation(account: Account, resource: TelegramMediaResource, datacenterId: Int, size: Int64?, intervals: Signal<[(Range<Int64>, MediaBoxFetchPriority)], NoError>, parameters: MediaResourceFetchParameters?) -> Signal<MediaResourceDataFetchResult, MediaResourceDataFetchError> {
|
||||
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<MediaResourceDataFetchResult, NoError> {
|
||||
|
@ -5,5 +5,5 @@ import MtProtoKit
|
||||
|
||||
|
||||
func fetchSecretFileResource(account: Account, resource: SecretFileMediaResource, intervals: Signal<[(Range<Int64>, MediaBoxFetchPriority)], NoError>, parameters: MediaResourceFetchParameters?) -> Signal<MediaResourceDataFetchResult, MediaResourceDataFetchError> {
|
||||
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)
|
||||
}
|
||||
|
@ -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<Void, NoError> {
|
||||
func managedSynchronizeRecentlyUsedMediaOperations(accountPeerId: PeerId, postbox: Postbox, network: Network, category: RecentlyUsedMediaCategory, revalidationContext: MediaReferenceRevalidationContext) -> Signal<Void, NoError> {
|
||||
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<Void, NoError> 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<Void, NoError> {
|
||||
private func synchronizeRecentlyUsedMedia(transaction: Transaction, accountPeerId: PeerId, postbox: Postbox, network: Network, revalidationContext: MediaReferenceRevalidationContext, operation: SynchronizeRecentlyUsedMediaOperation) -> Signal<Void, NoError> {
|
||||
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
|
||||
}
|
||||
|
@ -49,7 +49,7 @@ private final class ManagedSynchronizeSavedGifsOperationsHelper {
|
||||
}
|
||||
}
|
||||
|
||||
private func withTakenOperation(postbox: Postbox, peerId: PeerId, tag: PeerOperationLogTag, tagLocalIndex: Int32, _ f: @escaping (Transaction, PeerMergedOperationLogEntry?) -> Signal<Void, NoError>) -> Signal<Void, NoError> {
|
||||
private func withTakenOperation(accountPeerId: PeerId, postbox: Postbox, peerId: PeerId, tag: PeerOperationLogTag, tagLocalIndex: Int32, _ f: @escaping (Transaction, PeerMergedOperationLogEntry?) -> Signal<Void, NoError>) -> Signal<Void, NoError> {
|
||||
return postbox.transaction { transaction -> Signal<Void, NoError> 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<Void, NoError> {
|
||||
func managedSynchronizeSavedGifsOperations(accountPeerId: PeerId, postbox: Postbox, network: Network, revalidationContext: MediaReferenceRevalidationContext) -> Signal<Void, NoError> {
|
||||
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<Void, NoError> in
|
||||
let signal = withTakenOperation(accountPeerId: accountPeerId, postbox: postbox, peerId: entry.peerId, tag: tag, tagLocalIndex: entry.tagLocalIndex, { transaction, entry -> Signal<Void, NoError> 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<Void, NoError> {
|
||||
private func synchronizeSavedGifs(transaction: Transaction, accountPeerId: PeerId, postbox: Postbox, network: Network, revalidationContext: MediaReferenceRevalidationContext, operation: SynchronizeSavedGifsOperation) -> Signal<Void, NoError> {
|
||||
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
|
||||
}
|
||||
|
@ -65,7 +65,7 @@ private func withTakenOperation(postbox: Postbox, peerId: PeerId, tag: PeerOpera
|
||||
} |> switchToLatest
|
||||
}
|
||||
|
||||
func managedSynchronizeSavedStickersOperations(postbox: Postbox, network: Network, revalidationContext: MediaReferenceRevalidationContext) -> Signal<Void, NoError> {
|
||||
func managedSynchronizeSavedStickersOperations(accountPeerId: PeerId, postbox: Postbox, network: Network, revalidationContext: MediaReferenceRevalidationContext) -> Signal<Void, NoError> {
|
||||
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<Void, NoError> 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<Void, NoError> {
|
||||
private func synchronizeSavedStickers(transaction: Transaction, accountPeerId: PeerId, postbox: Postbox, network: Network, revalidationContext: MediaReferenceRevalidationContext, operation: SynchronizeSavedStickersOperation) -> Signal<Void, NoError> {
|
||||
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
|
||||
}
|
||||
|
@ -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):
|
||||
|
@ -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<T: Media> {
|
||||
case avatarList
|
||||
case attachBot
|
||||
case customEmoji
|
||||
case story
|
||||
}
|
||||
|
||||
case standalone(media: T)
|
||||
@ -472,6 +488,7 @@ public enum MediaReference<T: Media> {
|
||||
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<T: Media> {
|
||||
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<T: Media> {
|
||||
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<T: Media> {
|
||||
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<T: Media> {
|
||||
return media
|
||||
case let .customEmoji(media):
|
||||
return media
|
||||
case let .story(_, _, media):
|
||||
return media
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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]
|
||||
|
||||
|
@ -24,7 +24,10 @@ public struct EngineStoryPrivacy: Equatable {
|
||||
}
|
||||
}
|
||||
|
||||
func _internal_uploadStory(account: Account, media: EngineStoryInputMedia, privacy: EngineStoryPrivacy) -> Signal<Never, NoError> {
|
||||
func _internal_uploadStory(account: Account, media: EngineStoryInputMedia, text: String, entities: [MessageTextEntity], privacy: EngineStoryPrivacy) -> Signal<Never, NoError> {
|
||||
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, priva
|
||||
partialReference: nil,
|
||||
flags: []
|
||||
)
|
||||
originalMedia = imageMedia
|
||||
|
||||
let contentToUpload = messageContentToUpload(
|
||||
contentToUpload = messageContentToUpload(
|
||||
accountPeerId: account.peerId,
|
||||
network: account.network,
|
||||
postbox: account.postbox,
|
||||
auxiliaryMethods: account.auxiliaryMethods,
|
||||
@ -54,94 +59,6 @@ func _internal_uploadStory(account: Account, media: EngineStoryInputMedia, priva
|
||||
text: "",
|
||||
media: [imageMedia]
|
||||
)
|
||||
let contentSignal: Signal<PendingMessageUploadedContentResult, PendingMessageUploadError>
|
||||
switch contentToUpload {
|
||||
case let .immediate(result, _):
|
||||
contentSignal = .single(result)
|
||||
case let .signal(signal, _):
|
||||
contentSignal = signal
|
||||
}
|
||||
|
||||
return contentSignal
|
||||
|> map(Optional.init)
|
||||
|> `catch` { _ -> Signal<PendingMessageUploadedContentResult?, NoError> in
|
||||
return .single(nil)
|
||||
}
|
||||
|> mapToSignal { result -> Signal<Never, NoError> in
|
||||
return account.postbox.transaction { transaction -> Signal<Never, NoError> 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<Api.Updates?, NoError> in
|
||||
return .single(nil)
|
||||
}
|
||||
|> mapToSignal { updates -> Signal<Never, NoError> 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)),
|
||||
@ -156,8 +73,10 @@ func _internal_uploadStory(account: Account, media: EngineStoryInputMedia, priva
|
||||
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,
|
||||
@ -172,94 +91,124 @@ func _internal_uploadStory(account: Account, media: EngineStoryInputMedia, priva
|
||||
text: "",
|
||||
media: [fileMedia]
|
||||
)
|
||||
let contentSignal: Signal<PendingMessageUploadedContentResult, PendingMessageUploadError>
|
||||
switch contentToUpload {
|
||||
case let .immediate(result, _):
|
||||
contentSignal = .single(result)
|
||||
case let .signal(signal, _):
|
||||
contentSignal = signal
|
||||
}
|
||||
}
|
||||
|
||||
return contentSignal
|
||||
|> map(Optional.init)
|
||||
|> `catch` { _ -> Signal<PendingMessageUploadedContentResult?, NoError> in
|
||||
return .single(nil)
|
||||
}
|
||||
|> mapToSignal { result -> Signal<Never, NoError> in
|
||||
return account.postbox.transaction { transaction -> Signal<Never, NoError> 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<PendingMessageUploadedContentResult, PendingMessageUploadError>
|
||||
switch contentToUpload {
|
||||
case let .immediate(result, _):
|
||||
contentSignal = .single(result)
|
||||
case let .signal(signal, _):
|
||||
contentSignal = signal
|
||||
}
|
||||
|
||||
return contentSignal
|
||||
|> map(Optional.init)
|
||||
|> `catch` { _ -> Signal<PendingMessageUploadedContentResult?, NoError> in
|
||||
return .single(nil)
|
||||
}
|
||||
|> mapToSignal { result -> Signal<Never, NoError> in
|
||||
return account.postbox.transaction { transaction -> Signal<Never, NoError> 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<Api.Updates?, NoError> 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<Never, NoError> 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<Api.Updates?, NoError> in
|
||||
return .single(nil)
|
||||
}
|
||||
|> mapToSignal { updates -> Signal<Never, NoError> 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
|
||||
}
|
||||
}
|
||||
|
||||
@ -291,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<StoryListContext.Item?, NoError> {
|
||||
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<Api.stories.Stories?, NoError> in
|
||||
return .single(nil)
|
||||
}
|
||||
|> mapToSignal { result -> Signal<StoryListContext.Item?, NoError> 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<StoryViewList?, NoError> {
|
||||
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<Api.stories.StoryViewsList?, NoError> in
|
||||
return .single(nil)
|
||||
}
|
||||
|> mapToSignal { result -> Signal<StoryViewList?, NoError> 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<Api.stories.StoryViews?, NoError> 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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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,10 +401,10 @@ public final class StoryListContext {
|
||||
}
|
||||
}
|
||||
|
||||
func upload(media: EngineStoryInputMedia, 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, privacy: privacy)
|
||||
uploadContext.disposable.set((_internal_uploadStory(account: self.account, media: media, text: text, entities: entities, privacy: privacy)
|
||||
|> deliverOn(self.queue)).start(next: { _ in
|
||||
}, completed: { [weak self, weak uploadContext] in
|
||||
guard let `self` = self, let uploadContext = uploadContext else {
|
||||
@ -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,9 +617,9 @@ public final class StoryListContext {
|
||||
}
|
||||
}
|
||||
|
||||
public func upload(media: EngineStoryInputMedia, privacy: EngineStoryPrivacy) {
|
||||
public func upload(media: EngineStoryInputMedia, text: String, entities: [MessageTextEntity], privacy: EngineStoryPrivacy) {
|
||||
self.impl.with { impl in
|
||||
impl.upload(media: media, privacy: privacy)
|
||||
impl.upload(media: media, text: text, entities: entities, privacy: privacy)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -577,8 +577,8 @@ public extension TelegramEngine {
|
||||
return StoryListContext(account: self.account, scope: .peer(id))
|
||||
}
|
||||
|
||||
public func uploadStory(media: EngineStoryInputMedia, privacy: EngineStoryPrivacy) -> Signal<Never, NoError> {
|
||||
return _internal_uploadStory(account: self.account, media: media, privacy: privacy)
|
||||
public func uploadStory(media: EngineStoryInputMedia, text: String, entities: [MessageTextEntity], privacy: EngineStoryPrivacy) -> Signal<Never, NoError> {
|
||||
return _internal_uploadStory(account: self.account, media: media, text: text, entities: entities, privacy: privacy)
|
||||
}
|
||||
|
||||
public func deleteStory(id: Int32) -> Signal<Never, NoError> {
|
||||
@ -588,5 +588,9 @@ public extension TelegramEngine {
|
||||
public func markStoryAsSeen(peerId: EnginePeer.Id, id: Int32) -> Signal<Never, NoError> {
|
||||
return _internal_markStoryAsSeen(account: self.account, peerId: peerId, id: id)
|
||||
}
|
||||
|
||||
public func getStoryViewList(account: Account, id: Int32, offsetTimestamp: Int32?, offsetPeerId: PeerId?, limit: Int) -> Signal<StoryViewList?, NoError> {
|
||||
return _internal_getStoryViewList(account: account, id: id, offsetTimestamp: offsetTimestamp, offsetPeerId: offsetPeerId, limit: limit)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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<Api.account.SavedRingtone, MTRpcError> 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")
|
||||
}
|
||||
|
@ -353,7 +353,7 @@ public extension TelegramEngine {
|
||||
|> mapToSignal { datacenterId -> Signal<EngineMediaResource.Fetch.Result, EngineMediaResource.Fetch.Error> 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),
|
||||
|
@ -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")
|
||||
}
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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<simd_uint2>.size, index: 0)
|
||||
renderEncoder.setVertexBytes(&gridResolution, length: MemoryLayout<simd_uint2>.size, index: 1)
|
||||
renderEncoder.setVertexBytes(&resolution, length: MemoryLayout<simd_uint2>.size, index: 2)
|
||||
renderEncoder.setVertexBytes(&time, length: MemoryLayout<Float>.size, index: 3)
|
||||
renderEncoder.setVertexBytes(&contentScale, length: MemoryLayout<Float>.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()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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(
|
||||
|
@ -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<Never, NoError>?
|
||||
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<Never, NoError> 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<Never, NoError> in
|
||||
|
@ -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"
|
||||
|
@ -372,18 +372,12 @@ public final class TelegramRootController: NavigationController, TelegramRootCon
|
||||
return
|
||||
}
|
||||
if let chatListController = self.chatListController as? ChatListControllerImpl, let storyListContext = chatListController.storyListContext {
|
||||
storyListContext.upload(media: .image(dimensions: PixelDimensions(image.size), data: data), privacy: privacy)
|
||||
storyListContext.upload(media: .image(dimensions: PixelDimensions(image.size), data: data), text: "", entities: [], privacy: privacy)
|
||||
Queue.mainQueue().after(0.3, { [weak chatListController] in
|
||||
chatListController?.animateStoryUploadRipple()
|
||||
})
|
||||
}
|
||||
selectionController?.dismiss()
|
||||
|
||||
/*let _ = (context.engine.messages.uploadStory(media: )
|
||||
|> deliverOnMainQueue).start(completed: {
|
||||
guard let self else {
|
||||
return
|
||||
}
|
||||
let _ = self
|
||||
selectionController?.dismiss()
|
||||
})*/
|
||||
}
|
||||
}
|
||||
})
|
||||
@ -391,18 +385,12 @@ public final class TelegramRootController: NavigationController, TelegramRootCon
|
||||
let resource = VideoLibraryMediaResource(localIdentifier: asset.localIdentifier, conversion: VideoLibraryMediaResourceConversion.passthrough)
|
||||
|
||||
if let chatListController = self.chatListController as? ChatListControllerImpl, let storyListContext = chatListController.storyListContext {
|
||||
storyListContext.upload(media: .video(dimensions: PixelDimensions(width: Int32(asset.pixelWidth), height: Int32(asset.pixelHeight)), duration: Int(asset.duration), resource: resource), privacy: privacy)
|
||||
storyListContext.upload(media: .video(dimensions: PixelDimensions(width: Int32(asset.pixelWidth), height: Int32(asset.pixelHeight)), duration: Int(asset.duration), resource: resource), text: "", entities: [], privacy: privacy)
|
||||
Queue.mainQueue().after(0.3, { [weak chatListController] in
|
||||
chatListController?.animateStoryUploadRipple()
|
||||
})
|
||||
}
|
||||
selectionController?.dismiss()
|
||||
|
||||
/*let _ = (context.engine.messages.uploadStory(media: .video(dimensions: PixelDimensions(width: Int32(asset.pixelWidth), height: Int32(asset.pixelHeight)), duration: Int(asset.duration), resource: resource), privacy: privacy)
|
||||
|> deliverOnMainQueue).start(completed: { [weak self] in
|
||||
guard let self else {
|
||||
return
|
||||
}
|
||||
let _ = self
|
||||
selectionController?.dismiss()
|
||||
})*/
|
||||
default:
|
||||
selectionController?.dismiss()
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user