mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-11-07 01:10:09 +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())
|
let collectedData = Atomic<DataValue>(value: DataValue())
|
||||||
|
|
||||||
return standaloneMultipartFetch(
|
return standaloneMultipartFetch(
|
||||||
|
accountPeerId: stateManager.accountPeerId,
|
||||||
postbox: stateManager.postbox,
|
postbox: stateManager.postbox,
|
||||||
network: stateManager.network,
|
network: stateManager.network,
|
||||||
resource: resource,
|
resource: resource,
|
||||||
@ -1304,6 +1305,7 @@ private final class NotificationServiceHandler {
|
|||||||
fetchNotificationSoundSignal = Signal { subscriber in
|
fetchNotificationSoundSignal = Signal { subscriber in
|
||||||
let collectedData = Atomic<Data>(value: Data())
|
let collectedData = Atomic<Data>(value: Data())
|
||||||
return standaloneMultipartFetch(
|
return standaloneMultipartFetch(
|
||||||
|
accountPeerId: stateManager.accountPeerId,
|
||||||
postbox: stateManager.postbox,
|
postbox: stateManager.postbox,
|
||||||
network: stateManager.network,
|
network: stateManager.network,
|
||||||
resource: resource,
|
resource: resource,
|
||||||
|
|||||||
@ -2304,6 +2304,11 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
|
|||||||
}
|
}
|
||||||
|
|
||||||
self.chatListDisplayNode.clearHighlightAnimated(true)
|
self.chatListDisplayNode.clearHighlightAnimated(true)
|
||||||
|
|
||||||
|
if let fullScreenEffectView = self.fullScreenEffectView {
|
||||||
|
self.fullScreenEffectView = nil
|
||||||
|
fullScreenEffectView.removeFromSuperview()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func requestUpdateHeaderContent(transition: ContainedViewLayoutTransition) {
|
func requestUpdateHeaderContent(transition: ContainedViewLayoutTransition) {
|
||||||
@ -2501,25 +2506,37 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
|
|||||||
searchContentNode.updateListVisibleContentOffset(.known(0.0))
|
searchContentNode.updateListVisibleContentOffset(.known(0.0))
|
||||||
self.chatListDisplayNode.scrollToTop()
|
self.chatListDisplayNode.scrollToTop()
|
||||||
}
|
}
|
||||||
|
}
|
||||||
#if DEBUG && false
|
|
||||||
var fullScreenEffectView: RippleEffectView?
|
public func animateStoryUploadRipple() {
|
||||||
if let current = self.fullScreenEffectView {
|
if let componentView = self.headerContentView.view as? ChatListHeaderComponent.View {
|
||||||
fullScreenEffectView = current
|
if let transitionView = componentView.storyPeerListView()?.transitionViewForItem(peerId: self.context.account.peerId) {
|
||||||
self.view.window?.addSubview(current)
|
let localRect = transitionView.convert(transitionView.bounds, to: self.view)
|
||||||
current.sourceView = self.view
|
self.animateRipple(centerLocation: localRect.center)
|
||||||
} else {
|
|
||||||
if let value = RippleEffectView(test: false) {
|
|
||||||
fullScreenEffectView = value
|
|
||||||
self.fullScreenEffectView = value
|
|
||||||
self.view.window?.addSubview(value)
|
|
||||||
value.sourceView = self.view
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
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) {
|
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[1087454222] = { return Api.StickerSetCovered.parse_stickerSetFullCovered($0) }
|
||||||
dict[872932635] = { return Api.StickerSetCovered.parse_stickerSetMultiCovered($0) }
|
dict[872932635] = { return Api.StickerSetCovered.parse_stickerSetMultiCovered($0) }
|
||||||
dict[2008112412] = { return Api.StickerSetCovered.parse_stickerSetNoCovered($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[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[1964978502] = { return Api.TextWithEntities.parse_textWithEntities($0) }
|
||||||
dict[-1609668650] = { return Api.Theme.parse_theme($0) }
|
dict[-1609668650] = { return Api.Theme.parse_theme($0) }
|
||||||
dict[-94849324] = { return Api.ThemeSettings.parse_themeSettings($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[276907596] = { return Api.storage.FileType.parse_fileWebp($0) }
|
||||||
dict[1214632796] = { return Api.stories.AllStories.parse_allStories($0) }
|
dict[1214632796] = { return Api.stories.AllStories.parse_allStories($0) }
|
||||||
dict[1340440049] = { return Api.stories.Stories.parse_stories($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[-79726676] = { return Api.stories.StoryViewsList.parse_storyViewsList($0) }
|
||||||
dict[543450958] = { return Api.updates.ChannelDifference.parse_channelDifference($0) }
|
dict[543450958] = { return Api.updates.ChannelDifference.parse_channelDifference($0) }
|
||||||
dict[1041346555] = { return Api.updates.ChannelDifference.parse_channelDifferenceEmpty($0) }
|
dict[1041346555] = { return Api.updates.ChannelDifference.parse_channelDifferenceEmpty($0) }
|
||||||
@ -1712,6 +1714,8 @@ public extension Api {
|
|||||||
_1.serialize(buffer, boxed)
|
_1.serialize(buffer, boxed)
|
||||||
case let _1 as Api.StoryView:
|
case let _1 as Api.StoryView:
|
||||||
_1.serialize(buffer, boxed)
|
_1.serialize(buffer, boxed)
|
||||||
|
case let _1 as Api.StoryViews:
|
||||||
|
_1.serialize(buffer, boxed)
|
||||||
case let _1 as Api.TextWithEntities:
|
case let _1 as Api.TextWithEntities:
|
||||||
_1.serialize(buffer, boxed)
|
_1.serialize(buffer, boxed)
|
||||||
case let _1 as Api.Theme:
|
case let _1 as Api.Theme:
|
||||||
@ -2020,6 +2024,8 @@ public extension Api {
|
|||||||
_1.serialize(buffer, boxed)
|
_1.serialize(buffer, boxed)
|
||||||
case let _1 as Api.stories.Stories:
|
case let _1 as Api.stories.Stories:
|
||||||
_1.serialize(buffer, boxed)
|
_1.serialize(buffer, boxed)
|
||||||
|
case let _1 as Api.stories.StoryViews:
|
||||||
|
_1.serialize(buffer, boxed)
|
||||||
case let _1 as Api.stories.StoryViewsList:
|
case let _1 as Api.stories.StoryViewsList:
|
||||||
_1.serialize(buffer, boxed)
|
_1.serialize(buffer, boxed)
|
||||||
case let _1 as Api.updates.ChannelDifference:
|
case let _1 as Api.updates.ChannelDifference:
|
||||||
|
|||||||
@ -328,14 +328,14 @@ public extension Api {
|
|||||||
}
|
}
|
||||||
public extension Api {
|
public extension Api {
|
||||||
indirect enum StoryItem: TypeConstructorDescription {
|
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)
|
case storyItemDeleted(id: Int32)
|
||||||
|
|
||||||
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
|
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
|
||||||
switch self {
|
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 {
|
if boxed {
|
||||||
buffer.appendInt32(-1526488475)
|
buffer.appendInt32(-1882351956)
|
||||||
}
|
}
|
||||||
serializeInt32(flags, buffer: buffer, boxed: false)
|
serializeInt32(flags, buffer: buffer, boxed: false)
|
||||||
serializeInt32(id, buffer: buffer, boxed: false)
|
serializeInt32(id, buffer: buffer, boxed: false)
|
||||||
@ -352,12 +352,7 @@ public extension Api {
|
|||||||
for item in privacy! {
|
for item in privacy! {
|
||||||
item.serialize(buffer, true)
|
item.serialize(buffer, true)
|
||||||
}}
|
}}
|
||||||
if Int(flags) & Int(1 << 3) != 0 {buffer.appendInt32(481674261)
|
if Int(flags) & Int(1 << 3) != 0 {views!.serialize(buffer, true)}
|
||||||
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)}
|
|
||||||
break
|
break
|
||||||
case .storyItemDeleted(let id):
|
case .storyItemDeleted(let id):
|
||||||
if boxed {
|
if boxed {
|
||||||
@ -370,8 +365,8 @@ public extension Api {
|
|||||||
|
|
||||||
public func descriptionFields() -> (String, [(String, Any)]) {
|
public func descriptionFields() -> (String, [(String, Any)]) {
|
||||||
switch self {
|
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):
|
||||||
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)])
|
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):
|
case .storyItemDeleted(let id):
|
||||||
return ("storyItemDeleted", [("id", id as Any)])
|
return ("storyItemDeleted", [("id", id as Any)])
|
||||||
}
|
}
|
||||||
@ -398,12 +393,10 @@ public extension Api {
|
|||||||
if Int(_1!) & Int(1 << 2) != 0 {if let _ = reader.readInt32() {
|
if Int(_1!) & Int(1 << 2) != 0 {if let _ = reader.readInt32() {
|
||||||
_7 = Api.parseVector(reader, elementSignature: 0, elementType: Api.PrivacyRule.self)
|
_7 = Api.parseVector(reader, elementSignature: 0, elementType: Api.PrivacyRule.self)
|
||||||
} }
|
} }
|
||||||
var _8: [Int64]?
|
var _8: Api.StoryViews?
|
||||||
if Int(_1!) & Int(1 << 3) != 0 {if let _ = reader.readInt32() {
|
if Int(_1!) & Int(1 << 3) != 0 {if let signature = reader.readInt32() {
|
||||||
_8 = Api.parseVector(reader, elementSignature: 570911930, elementType: Int64.self)
|
_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 _c1 = _1 != nil
|
||||||
let _c2 = _2 != nil
|
let _c2 = _2 != nil
|
||||||
let _c3 = _3 != nil
|
let _c3 = _3 != nil
|
||||||
@ -412,9 +405,8 @@ public extension Api {
|
|||||||
let _c6 = _6 != nil
|
let _c6 = _6 != nil
|
||||||
let _c7 = (Int(_1!) & Int(1 << 2) == 0) || _7 != nil
|
let _c7 = (Int(_1!) & Int(1 << 2) == 0) || _7 != nil
|
||||||
let _c8 = (Int(_1!) & Int(1 << 3) == 0) || _8 != 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 {
|
||||||
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, views: _8)
|
||||||
return Api.StoryItem.storyItem(flags: _1!, id: _2!, date: _3!, caption: _4, entities: _5, media: _6!, privacy: _7, recentViewers: _8, viewsCount: _9)
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
return nil
|
return nil
|
||||||
@ -436,16 +428,16 @@ public extension Api {
|
|||||||
}
|
}
|
||||||
public extension Api {
|
public extension Api {
|
||||||
enum StoryView: TypeConstructorDescription {
|
enum StoryView: TypeConstructorDescription {
|
||||||
case storyView(userId: Int64, date: Int64)
|
case storyView(userId: Int64, date: Int32)
|
||||||
|
|
||||||
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
|
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
|
||||||
switch self {
|
switch self {
|
||||||
case .storyView(let userId, let date):
|
case .storyView(let userId, let date):
|
||||||
if boxed {
|
if boxed {
|
||||||
buffer.appendInt32(90474706)
|
buffer.appendInt32(-1491424062)
|
||||||
}
|
}
|
||||||
serializeInt64(userId, buffer: buffer, boxed: false)
|
serializeInt64(userId, buffer: buffer, boxed: false)
|
||||||
serializeInt64(date, buffer: buffer, boxed: false)
|
serializeInt32(date, buffer: buffer, boxed: false)
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -460,8 +452,8 @@ public extension Api {
|
|||||||
public static func parse_storyView(_ reader: BufferReader) -> StoryView? {
|
public static func parse_storyView(_ reader: BufferReader) -> StoryView? {
|
||||||
var _1: Int64?
|
var _1: Int64?
|
||||||
_1 = reader.readInt64()
|
_1 = reader.readInt64()
|
||||||
var _2: Int64?
|
var _2: Int32?
|
||||||
_2 = reader.readInt64()
|
_2 = reader.readInt32()
|
||||||
let _c1 = _1 != nil
|
let _c1 = _1 != nil
|
||||||
let _c2 = _2 != nil
|
let _c2 = _2 != nil
|
||||||
if _c1 && _c2 {
|
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 {
|
public extension Api {
|
||||||
enum TextWithEntities: TypeConstructorDescription {
|
enum TextWithEntities: TypeConstructorDescription {
|
||||||
case textWithEntities(text: String, entities: [Api.MessageEntity])
|
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 {
|
public extension Api.stories {
|
||||||
enum StoryViewsList: TypeConstructorDescription {
|
enum StoryViewsList: TypeConstructorDescription {
|
||||||
case storyViewsList(count: Int32, views: [Api.StoryView], users: [Api.User])
|
case storyViewsList(count: Int32, views: [Api.StoryView], users: [Api.User])
|
||||||
|
|||||||
@ -8508,14 +8508,53 @@ public extension Api.functions.stories {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
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()
|
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(id, buffer: buffer, boxed: false)
|
||||||
serializeInt32(offsetDate, 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)
|
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)
|
let reader = BufferReader(buffer)
|
||||||
var result: Api.stories.StoryViewsList?
|
var result: Api.stories.StoryViewsList?
|
||||||
if let signature = reader.readInt32() {
|
if let signature = reader.readInt32() {
|
||||||
|
|||||||
@ -191,6 +191,7 @@ private final class FetchImpl {
|
|||||||
private final class Impl {
|
private final class Impl {
|
||||||
private let queue: Queue
|
private let queue: Queue
|
||||||
|
|
||||||
|
private let accountPeerId: PeerId
|
||||||
private let postbox: Postbox
|
private let postbox: Postbox
|
||||||
private let network: Network
|
private let network: Network
|
||||||
private let mediaReferenceRevalidationContext: MediaReferenceRevalidationContext?
|
private let mediaReferenceRevalidationContext: MediaReferenceRevalidationContext?
|
||||||
@ -220,6 +221,7 @@ private final class FetchImpl {
|
|||||||
|
|
||||||
init(
|
init(
|
||||||
queue: Queue,
|
queue: Queue,
|
||||||
|
accountPeerId: PeerId,
|
||||||
postbox: Postbox,
|
postbox: Postbox,
|
||||||
network: Network,
|
network: Network,
|
||||||
mediaReferenceRevalidationContext: MediaReferenceRevalidationContext?,
|
mediaReferenceRevalidationContext: MediaReferenceRevalidationContext?,
|
||||||
@ -237,6 +239,7 @@ private final class FetchImpl {
|
|||||||
) {
|
) {
|
||||||
self.queue = queue
|
self.queue = queue
|
||||||
|
|
||||||
|
self.accountPeerId = accountPeerId
|
||||||
self.postbox = postbox
|
self.postbox = postbox
|
||||||
self.network = network
|
self.network = network
|
||||||
self.mediaReferenceRevalidationContext = mediaReferenceRevalidationContext
|
self.mediaReferenceRevalidationContext = mediaReferenceRevalidationContext
|
||||||
@ -471,6 +474,7 @@ private final class FetchImpl {
|
|||||||
let fetchLocation = state.fetchLocation
|
let fetchLocation = state.fetchLocation
|
||||||
|
|
||||||
state.disposable = (revalidateMediaResourceReference(
|
state.disposable = (revalidateMediaResourceReference(
|
||||||
|
accountPeerId: self.accountPeerId,
|
||||||
postbox: self.postbox,
|
postbox: self.postbox,
|
||||||
network: self.network,
|
network: self.network,
|
||||||
revalidationContext: mediaReferenceRevalidationContext,
|
revalidationContext: mediaReferenceRevalidationContext,
|
||||||
@ -716,6 +720,7 @@ private final class FetchImpl {
|
|||||||
|
|
||||||
|
|
||||||
init(
|
init(
|
||||||
|
accountPeerId: PeerId,
|
||||||
postbox: Postbox,
|
postbox: Postbox,
|
||||||
network: Network,
|
network: Network,
|
||||||
mediaReferenceRevalidationContext: MediaReferenceRevalidationContext?,
|
mediaReferenceRevalidationContext: MediaReferenceRevalidationContext?,
|
||||||
@ -736,6 +741,7 @@ private final class FetchImpl {
|
|||||||
self.impl = QueueLocalObject(queue: queue, generate: {
|
self.impl = QueueLocalObject(queue: queue, generate: {
|
||||||
return Impl(
|
return Impl(
|
||||||
queue: queue,
|
queue: queue,
|
||||||
|
accountPeerId: accountPeerId,
|
||||||
postbox: postbox,
|
postbox: postbox,
|
||||||
network: network,
|
network: network,
|
||||||
mediaReferenceRevalidationContext: mediaReferenceRevalidationContext,
|
mediaReferenceRevalidationContext: mediaReferenceRevalidationContext,
|
||||||
@ -756,6 +762,7 @@ private final class FetchImpl {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func multipartFetchV2(
|
func multipartFetchV2(
|
||||||
|
accountPeerId: PeerId,
|
||||||
postbox: Postbox,
|
postbox: Postbox,
|
||||||
network: Network,
|
network: Network,
|
||||||
mediaReferenceRevalidationContext: MediaReferenceRevalidationContext?,
|
mediaReferenceRevalidationContext: MediaReferenceRevalidationContext?,
|
||||||
@ -771,6 +778,7 @@ func multipartFetchV2(
|
|||||||
) -> Signal<MediaResourceDataFetchResult, MediaResourceDataFetchError> {
|
) -> Signal<MediaResourceDataFetchResult, MediaResourceDataFetchError> {
|
||||||
return Signal { subscriber in
|
return Signal { subscriber in
|
||||||
let impl = FetchImpl(
|
let impl = FetchImpl(
|
||||||
|
accountPeerId: accountPeerId,
|
||||||
postbox: postbox,
|
postbox: postbox,
|
||||||
network: network,
|
network: network,
|
||||||
mediaReferenceRevalidationContext: mediaReferenceRevalidationContext,
|
mediaReferenceRevalidationContext: mediaReferenceRevalidationContext,
|
||||||
|
|||||||
@ -307,6 +307,7 @@ private enum MediaReferenceRevalidationKey: Hashable {
|
|||||||
case attachBot(peer: PeerReference)
|
case attachBot(peer: PeerReference)
|
||||||
case notificationSoundList
|
case notificationSoundList
|
||||||
case customEmoji(fileId: Int64)
|
case customEmoji(fileId: Int64)
|
||||||
|
case story(peer: PeerReference, id: Int32)
|
||||||
}
|
}
|
||||||
|
|
||||||
private final class MediaReferenceRevalidationItemContext {
|
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> {
|
func notificationSoundList(postbox: Postbox, network: Network, background: Bool) -> Signal<[TelegramMediaFile], RevalidateMediaReferenceError> {
|
||||||
return self.genericItem(key: .notificationSoundList, background: background, request: { next, error in
|
return self.genericItem(key: .notificationSoundList, background: background, request: { next, error in
|
||||||
return (requestNotificationSoundList(network: network, hash: 0)
|
return (requestNotificationSoundList(network: network, hash: 0)
|
||||||
@ -682,7 +708,7 @@ struct RevalidatedMediaResource {
|
|||||||
let updatedReference: MediaResourceReference?
|
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
|
var updatedReference = info.reference
|
||||||
if case let .media(media, resource) = updatedReference {
|
if case let .media(media, resource) = updatedReference {
|
||||||
if case let .message(messageReference, mediaValue) = media {
|
if case let .message(messageReference, mediaValue) = media {
|
||||||
@ -805,6 +831,14 @@ func revalidateMediaResourceReference(postbox: Postbox, network: Network, revali
|
|||||||
}
|
}
|
||||||
return .fail(.generic)
|
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):
|
case let .standalone(media):
|
||||||
if let file = media as? TelegramMediaFile {
|
if let file = media as? TelegramMediaFile {
|
||||||
for attribute in file.attributes {
|
for attribute in file.attributes {
|
||||||
|
|||||||
@ -473,6 +473,7 @@ private final class MultipartFetchManager {
|
|||||||
var completeSize: Int64?
|
var completeSize: Int64?
|
||||||
var completeSizeReported = false
|
var completeSizeReported = false
|
||||||
|
|
||||||
|
let accountPeerId: PeerId
|
||||||
let postbox: Postbox
|
let postbox: Postbox
|
||||||
let network: Network
|
let network: Network
|
||||||
let networkStatsContext: NetworkStatsContext?
|
let networkStatsContext: NetworkStatsContext?
|
||||||
@ -505,7 +506,7 @@ private final class MultipartFetchManager {
|
|||||||
private var fetchSpeedRecords: [FetchSpeedRecord] = []
|
private var fetchSpeedRecords: [FetchSpeedRecord] = []
|
||||||
private var totalFetchedByteCount: Int = 0
|
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.resource = resource
|
||||||
self.parameters = parameters
|
self.parameters = parameters
|
||||||
self.consumerId = Int64.random(in: Int64.min ... Int64.max)
|
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.state = MultipartDownloadState(encryptionKey: encryptionKey, decryptedSize: decryptedSize)
|
||||||
|
self.accountPeerId = accountPeerId
|
||||||
self.postbox = postbox
|
self.postbox = postbox
|
||||||
self.network = network
|
self.network = network
|
||||||
self.networkStatsContext = networkStatsContext
|
self.networkStatsContext = networkStatsContext
|
||||||
@ -836,7 +838,7 @@ private final class MultipartFetchManager {
|
|||||||
strongSelf.fetchingParts.removeAll()
|
strongSelf.fetchingParts.removeAll()
|
||||||
|
|
||||||
if let info = strongSelf.parameters?.info as? TelegramCloudMediaResourceFetchInfo, let revalidationContext = strongSelf.revalidationContext {
|
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
|
|> deliverOn(strongSelf.queue)).start(next: { validationResult in
|
||||||
if let strongSelf = self {
|
if let strongSelf = self {
|
||||||
strongSelf.revalidatingMediaReference = false
|
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(
|
return multipartFetch(
|
||||||
|
accountPeerId: accountPeerId,
|
||||||
postbox: postbox,
|
postbox: postbox,
|
||||||
network: network,
|
network: network,
|
||||||
mediaReferenceRevalidationContext: nil,
|
mediaReferenceRevalidationContext: nil,
|
||||||
@ -921,6 +924,7 @@ public func resourceFetchInfo(resource: TelegramMediaResource) -> MediaResourceF
|
|||||||
}
|
}
|
||||||
|
|
||||||
private func multipartFetchV1(
|
private func multipartFetchV1(
|
||||||
|
accountPeerId: PeerId,
|
||||||
postbox: Postbox,
|
postbox: Postbox,
|
||||||
network: Network,
|
network: Network,
|
||||||
mediaReferenceRevalidationContext: MediaReferenceRevalidationContext?,
|
mediaReferenceRevalidationContext: MediaReferenceRevalidationContext?,
|
||||||
@ -992,7 +996,7 @@ private func multipartFetchV1(
|
|||||||
subscriber.putNext(.reset)
|
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))
|
subscriber.putNext(.dataPart(resourceOffset: dataOffset, data: data, range: 0 ..< Int64(data.count), complete: false))
|
||||||
}, reportCompleteSize: { size in
|
}, reportCompleteSize: { size in
|
||||||
subscriber.putNext(.resourceSizeUpdated(size))
|
subscriber.putNext(.resourceSizeUpdated(size))
|
||||||
@ -1013,6 +1017,7 @@ private func multipartFetchV1(
|
|||||||
}
|
}
|
||||||
|
|
||||||
func multipartFetch(
|
func multipartFetch(
|
||||||
|
accountPeerId: PeerId,
|
||||||
postbox: Postbox,
|
postbox: Postbox,
|
||||||
network: Network,
|
network: Network,
|
||||||
mediaReferenceRevalidationContext: MediaReferenceRevalidationContext?,
|
mediaReferenceRevalidationContext: MediaReferenceRevalidationContext?,
|
||||||
@ -1029,6 +1034,7 @@ func multipartFetch(
|
|||||||
) -> Signal<MediaResourceDataFetchResult, MediaResourceDataFetchError> {
|
) -> Signal<MediaResourceDataFetchResult, MediaResourceDataFetchError> {
|
||||||
if network.useExperimentalFeatures, let _ = resource as? TelegramCloudMediaResource, !(resource is SecretFileMediaResource) {
|
if network.useExperimentalFeatures, let _ = resource as? TelegramCloudMediaResource, !(resource is SecretFileMediaResource) {
|
||||||
return multipartFetchV2(
|
return multipartFetchV2(
|
||||||
|
accountPeerId: accountPeerId,
|
||||||
postbox: postbox,
|
postbox: postbox,
|
||||||
network: network,
|
network: network,
|
||||||
mediaReferenceRevalidationContext: mediaReferenceRevalidationContext,
|
mediaReferenceRevalidationContext: mediaReferenceRevalidationContext,
|
||||||
@ -1044,6 +1050,7 @@ func multipartFetch(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
return multipartFetchV1(
|
return multipartFetchV1(
|
||||||
|
accountPeerId: accountPeerId,
|
||||||
postbox: postbox,
|
postbox: postbox,
|
||||||
network: network,
|
network: network,
|
||||||
mediaReferenceRevalidationContext: mediaReferenceRevalidationContext,
|
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 {
|
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(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)
|
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 contextResult: OutgoingChatContextResultMessageAttribute?
|
||||||
var autoremoveMessageAttribute: AutoremoveTimeoutMessageAttribute?
|
var autoremoveMessageAttribute: AutoremoveTimeoutMessageAttribute?
|
||||||
var autoclearMessageAttribute: AutoclearTimeoutMessageAttribute?
|
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)
|
return .immediate(.content(PendingMessageUploadedContentAndReuploadInfo(content: .forward(forwardInfo), reuploadInfo: nil, cacheReferenceKey: nil)), .text)
|
||||||
} else if let contextResult = contextResult {
|
} else if let contextResult = contextResult {
|
||||||
return .immediate(.content(PendingMessageUploadedContentAndReuploadInfo(content: .chatContextResult(contextResult), reuploadInfo: nil, cacheReferenceKey: nil)), .text)
|
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)
|
return .signal(mediaResult, .media)
|
||||||
} else {
|
} else {
|
||||||
return .signal(.single(.content(PendingMessageUploadedContentAndReuploadInfo(content: .text(text), reuploadInfo: nil, cacheReferenceKey: nil))), .text)
|
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 let image = media as? TelegramMediaImage, let largest = largestImageRepresentation(image.representations) {
|
||||||
if peerId.namespace == Namespaces.Peer.SecretChat, let resource = largest.resource as? SecretFileMediaResource {
|
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)))
|
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 {
|
} else {
|
||||||
mediaReference = .savedGif(media: file)
|
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
|
|> mapError { _ -> PendingMessageUploadError in
|
||||||
return .generic
|
return .generic
|
||||||
}
|
}
|
||||||
|
|||||||
@ -75,7 +75,7 @@ private final class PendingUpdateMessageManagerImpl {
|
|||||||
self.contexts[messageId] = context
|
self.contexts[messageId] = context
|
||||||
|
|
||||||
let queue = self.queue
|
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
|
|> deliverOn(self.queue)).start(next: { [weak self, weak context] value in
|
||||||
queue.async {
|
queue.async {
|
||||||
guard let strongSelf = self, let initialContext = context else {
|
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> {
|
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> {
|
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(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)
|
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
|
|> `catch` { error -> Signal<RequestEditMessageResult, RequestEditMessageInternalError> in
|
||||||
if case .invalidReference = error {
|
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 {
|
} else {
|
||||||
return .fail(error)
|
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>
|
let uploadedMedia: Signal<PendingMessageUploadedContentResult?, NoError>
|
||||||
switch media {
|
switch media {
|
||||||
case .keep:
|
case .keep:
|
||||||
@ -59,7 +59,7 @@ private func requestEditMessageInternal(postbox: Postbox, network: Network, stat
|
|||||||
case let .update(media):
|
case let .update(media):
|
||||||
let generateUploadSignal: (Bool) -> Signal<PendingMessageUploadedContentResult, PendingMessageUploadError>? = { forceReupload in
|
let generateUploadSignal: (Bool) -> Signal<PendingMessageUploadedContentResult, PendingMessageUploadError>? = { forceReupload in
|
||||||
let augmentedMedia = augmentMediaWithReference(media)
|
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) {
|
if let uploadSignal = generateUploadSignal(forceReupload) {
|
||||||
uploadedMedia = .single(.progress(0.027))
|
uploadedMedia = .single(.progress(0.027))
|
||||||
|
|||||||
@ -4333,62 +4333,10 @@ func replayFinalState(
|
|||||||
case .userStories(let userId, let stories), .userStoriesSlice(_, let userId, let stories):
|
case .userStories(let userId, let stories), .userStoriesSlice(_, let userId, let stories):
|
||||||
let peerId = PeerId(namespace: Namespaces.Peer.CloudUser, id: PeerId.Id._internalFromInt64Value(userId))
|
let peerId = PeerId(namespace: Namespaces.Peer.CloudUser, id: PeerId.Id._internalFromInt64Value(userId))
|
||||||
for storyItem in stories {
|
for storyItem in stories {
|
||||||
switch storyItem {
|
if let parsedItem = _internal_parseApiStoryItem(transaction: transaction, peerId: peerId, apiStory: storyItem) {
|
||||||
case let .storyItemDeleted(id):
|
storyUpdates.append(InternalStoryUpdate.added(peerId: peerId, item: parsedItem))
|
||||||
storyUpdates.append(InternalStoryUpdate.deleted(id))
|
} else {
|
||||||
case let .storyItem(flags, id, date, _, _, media, privacy, recentViewers, viewCount):
|
storyUpdates.append(InternalStoryUpdate.deleted(peerId: peerId, id: storyItem.id))
|
||||||
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
|
|
||||||
)))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -7,6 +7,7 @@ import TelegramApi
|
|||||||
final class AccountTaskManager {
|
final class AccountTaskManager {
|
||||||
private final class Impl {
|
private final class Impl {
|
||||||
private let queue: Queue
|
private let queue: Queue
|
||||||
|
private let accountPeerId: PeerId
|
||||||
private let stateManager: AccountStateManager
|
private let stateManager: AccountStateManager
|
||||||
private let accountManager: AccountManager<TelegramAccountManagerTypes>
|
private let accountManager: AccountManager<TelegramAccountManagerTypes>
|
||||||
private let networkArguments: NetworkInitializationArguments
|
private let networkArguments: NetworkInitializationArguments
|
||||||
@ -22,9 +23,10 @@ final class AccountTaskManager {
|
|||||||
|
|
||||||
private var isUpdating: Bool = false
|
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) {
|
networkArguments: NetworkInitializationArguments, viewTracker: AccountViewTracker, mediaReferenceRevalidationContext: MediaReferenceRevalidationContext, isMainApp: Bool, testingEnvironment: Bool) {
|
||||||
self.queue = queue
|
self.queue = queue
|
||||||
|
self.accountPeerId = accountPeerId
|
||||||
self.stateManager = stateManager
|
self.stateManager = stateManager
|
||||||
self.accountManager = accountManager
|
self.accountManager = accountManager
|
||||||
self.networkArguments = networkArguments
|
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: .masks).start())
|
||||||
tasks.add(managedSynchronizeInstalledStickerPacksOperations(postbox: self.stateManager.postbox, network: self.stateManager.network, stateManager: self.stateManager, namespace: .emoji).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(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(managedSynchronizeRecentlyUsedMediaOperations(accountPeerId: self.accountPeerId, 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(managedSynchronizeSavedGifsOperations(accountPeerId: self.accountPeerId, 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(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(_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(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())
|
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
|
let queue = Account.sharedQueue
|
||||||
self.queue = queue
|
self.queue = queue
|
||||||
self.impl = QueueLocalObject(queue: queue, generate: {
|
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> {
|
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> {
|
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> {
|
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
|
} |> 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
|
return Signal { _ in
|
||||||
let tag: PeerOperationLogTag
|
let tag: PeerOperationLogTag
|
||||||
switch category {
|
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
|
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 entry = entry {
|
||||||
if let operation = entry.contents as? SynchronizeRecentlyUsedMediaOperation {
|
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 {
|
} else {
|
||||||
assertionFailure()
|
assertionFailure()
|
||||||
}
|
}
|
||||||
@ -120,7 +120,7 @@ private enum SaveRecentlyUsedMediaError {
|
|||||||
case invalidReference
|
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 {
|
switch operation.content {
|
||||||
case let .add(id, accessHash, fileReference):
|
case let .add(id, accessHash, fileReference):
|
||||||
guard let fileReference = fileReference else {
|
guard let fileReference = fileReference else {
|
||||||
@ -150,7 +150,7 @@ private func synchronizeRecentlyUsedMedia(transaction: Transaction, postbox: Pos
|
|||||||
case .generic:
|
case .generic:
|
||||||
return .fail(.generic)
|
return .fail(.generic)
|
||||||
case .invalidReference:
|
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
|
|> mapError { _ -> SaveRecentlyUsedMediaError in
|
||||||
return .generic
|
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
|
return postbox.transaction { transaction -> Signal<Void, NoError> in
|
||||||
var result: PeerMergedOperationLogEntry?
|
var result: PeerMergedOperationLogEntry?
|
||||||
transaction.operationLogUpdateEntry(peerId: peerId, tag: tag, tagLocalIndex: tagLocalIndex, { entry in
|
transaction.operationLogUpdateEntry(peerId: peerId, tag: tag, tagLocalIndex: tagLocalIndex, { entry in
|
||||||
@ -65,7 +65,7 @@ private func withTakenOperation(postbox: Postbox, peerId: PeerId, tag: PeerOpera
|
|||||||
} |> switchToLatest
|
} |> 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
|
return Signal { _ in
|
||||||
let tag: PeerOperationLogTag = OperationLogTags.SynchronizeSavedGifs
|
let tag: PeerOperationLogTag = OperationLogTags.SynchronizeSavedGifs
|
||||||
|
|
||||||
@ -81,10 +81,10 @@ func managedSynchronizeSavedGifsOperations(postbox: Postbox, network: Network, r
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (entry, disposable) in beginOperations {
|
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 entry = entry {
|
||||||
if let operation = entry.contents as? SynchronizeSavedGifsOperation {
|
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 {
|
} else {
|
||||||
assertionFailure()
|
assertionFailure()
|
||||||
}
|
}
|
||||||
@ -116,7 +116,7 @@ private enum SaveGifError {
|
|||||||
case invalidReference
|
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 {
|
switch operation.content {
|
||||||
case let .add(id, accessHash, fileReference):
|
case let .add(id, accessHash, fileReference):
|
||||||
guard let fileReference = fileReference else {
|
guard let fileReference = fileReference else {
|
||||||
@ -146,7 +146,7 @@ private func synchronizeSavedGifs(transaction: Transaction, postbox: Postbox, ne
|
|||||||
case .generic:
|
case .generic:
|
||||||
return .fail(.generic)
|
return .fail(.generic)
|
||||||
case .invalidReference:
|
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
|
|> mapError { _ -> SaveGifError in
|
||||||
return .generic
|
return .generic
|
||||||
}
|
}
|
||||||
|
|||||||
@ -65,7 +65,7 @@ private func withTakenOperation(postbox: Postbox, peerId: PeerId, tag: PeerOpera
|
|||||||
} |> switchToLatest
|
} |> 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
|
return Signal { _ in
|
||||||
let tag: PeerOperationLogTag = OperationLogTags.SynchronizeSavedStickers
|
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
|
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 entry = entry {
|
||||||
if let operation = entry.contents as? SynchronizeSavedStickersOperation {
|
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 {
|
} else {
|
||||||
assertionFailure()
|
assertionFailure()
|
||||||
}
|
}
|
||||||
@ -116,7 +116,7 @@ private enum SaveStickerError {
|
|||||||
case invalidReference
|
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 {
|
switch operation.content {
|
||||||
case let .add(id, accessHash, fileReference):
|
case let .add(id, accessHash, fileReference):
|
||||||
guard let fileReference = fileReference else {
|
guard let fileReference = fileReference else {
|
||||||
@ -146,7 +146,7 @@ private func synchronizeSavedStickers(transaction: Transaction, postbox: Postbox
|
|||||||
case .generic:
|
case .generic:
|
||||||
return .fail(.generic)
|
return .fail(.generic)
|
||||||
case .invalidReference:
|
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
|
|> mapError { _ -> SaveStickerError in
|
||||||
return .generic
|
return .generic
|
||||||
}
|
}
|
||||||
|
|||||||
@ -403,7 +403,7 @@ public final class PendingMessageManager {
|
|||||||
return lhs.1.index < rhs.1.index
|
return lhs.1.index < rhs.1.index
|
||||||
}) {
|
}) {
|
||||||
if case let .collectingInfo(message) = messageContext.state {
|
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
|
messageContext.contentType = contentToUpload.type
|
||||||
switch contentToUpload {
|
switch contentToUpload {
|
||||||
case let .immediate(result, type):
|
case let .immediate(result, type):
|
||||||
|
|||||||
@ -251,6 +251,7 @@ public enum AnyMediaReference: Equatable {
|
|||||||
case avatarList(peer: PeerReference, media: Media)
|
case avatarList(peer: PeerReference, media: Media)
|
||||||
case attachBot(peer: PeerReference, media: Media)
|
case attachBot(peer: PeerReference, media: Media)
|
||||||
case customEmoji(media: Media)
|
case customEmoji(media: Media)
|
||||||
|
case story(peer: PeerReference, id: Int32, media: Media)
|
||||||
|
|
||||||
public static func ==(lhs: AnyMediaReference, rhs: AnyMediaReference) -> Bool {
|
public static func ==(lhs: AnyMediaReference, rhs: AnyMediaReference) -> Bool {
|
||||||
switch lhs {
|
switch lhs {
|
||||||
@ -302,6 +303,12 @@ public enum AnyMediaReference: Equatable {
|
|||||||
} else {
|
} else {
|
||||||
return false
|
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
|
return nil
|
||||||
case .customEmoji:
|
case .customEmoji:
|
||||||
return nil
|
return nil
|
||||||
|
case .story:
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -360,6 +369,10 @@ public enum AnyMediaReference: Equatable {
|
|||||||
if let media = media as? T {
|
if let media = media as? T {
|
||||||
return .customEmoji(media: media)
|
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
|
return nil
|
||||||
}
|
}
|
||||||
@ -382,6 +395,8 @@ public enum AnyMediaReference: Equatable {
|
|||||||
return media
|
return media
|
||||||
case let .customEmoji(media):
|
case let .customEmoji(media):
|
||||||
return media
|
return media
|
||||||
|
case let .story(_, _, media):
|
||||||
|
return media
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -462,6 +477,7 @@ public enum MediaReference<T: Media> {
|
|||||||
case avatarList
|
case avatarList
|
||||||
case attachBot
|
case attachBot
|
||||||
case customEmoji
|
case customEmoji
|
||||||
|
case story
|
||||||
}
|
}
|
||||||
|
|
||||||
case standalone(media: T)
|
case standalone(media: T)
|
||||||
@ -472,6 +488,7 @@ public enum MediaReference<T: Media> {
|
|||||||
case avatarList(peer: PeerReference, media: T)
|
case avatarList(peer: PeerReference, media: T)
|
||||||
case attachBot(peer: PeerReference, media: T)
|
case attachBot(peer: PeerReference, media: T)
|
||||||
case customEmoji(media: T)
|
case customEmoji(media: T)
|
||||||
|
case story(peer: PeerReference, id: Int32, media: T)
|
||||||
|
|
||||||
public init?(decoder: PostboxDecoder) {
|
public init?(decoder: PostboxDecoder) {
|
||||||
guard let caseIdValue = decoder.decodeOptionalInt32ForKey("_r"), let caseId = CodingCase(rawValue: caseIdValue) else {
|
guard let caseIdValue = decoder.decodeOptionalInt32ForKey("_r"), let caseId = CodingCase(rawValue: caseIdValue) else {
|
||||||
@ -523,6 +540,13 @@ public enum MediaReference<T: Media> {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
self = .customEmoji(media: media)
|
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):
|
case let .customEmoji(media):
|
||||||
encoder.encodeInt32(CodingCase.customEmoji.rawValue, forKey: "_r")
|
encoder.encodeInt32(CodingCase.customEmoji.rawValue, forKey: "_r")
|
||||||
encoder.encodeObject(media, forKey: "m")
|
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)
|
return .attachBot(peer: peer, media: media)
|
||||||
case let .customEmoji(media):
|
case let .customEmoji(media):
|
||||||
return .customEmoji(media: 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
|
return media
|
||||||
case let .customEmoji(media):
|
case let .customEmoji(media):
|
||||||
return 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 class TextEntitiesMessageAttribute: MessageAttribute, Equatable {
|
||||||
public let entities: [MessageTextEntity]
|
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 {
|
switch media {
|
||||||
case let .image(dimensions, data):
|
case let .image(dimensions, data):
|
||||||
let resource = LocalFileMediaResource(fileId: Int64.random(in: Int64.min ... Int64.max))
|
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,
|
partialReference: nil,
|
||||||
flags: []
|
flags: []
|
||||||
)
|
)
|
||||||
|
originalMedia = imageMedia
|
||||||
|
|
||||||
let contentToUpload = messageContentToUpload(
|
contentToUpload = messageContentToUpload(
|
||||||
|
accountPeerId: account.peerId,
|
||||||
network: account.network,
|
network: account.network,
|
||||||
postbox: account.postbox,
|
postbox: account.postbox,
|
||||||
auxiliaryMethods: account.auxiliaryMethods,
|
auxiliaryMethods: account.auxiliaryMethods,
|
||||||
@ -54,94 +59,6 @@ func _internal_uploadStory(account: Account, media: EngineStoryInputMedia, priva
|
|||||||
text: "",
|
text: "",
|
||||||
media: [imageMedia]
|
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):
|
case let .video(dimensions, duration, resource):
|
||||||
let fileMedia = TelegramMediaFile(
|
let fileMedia = TelegramMediaFile(
|
||||||
fileId: MediaId(namespace: Namespaces.Media.LocalFile, id: MediaId.Id.random(in: MediaId.Id.min ... MediaId.Id.max)),
|
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)
|
TelegramMediaFileAttribute.Video(duration: duration, size: dimensions, flags: .supportsStreaming)
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
|
originalMedia = fileMedia
|
||||||
|
|
||||||
let contentToUpload = messageContentToUpload(
|
contentToUpload = messageContentToUpload(
|
||||||
|
accountPeerId: account.peerId,
|
||||||
network: account.network,
|
network: account.network,
|
||||||
postbox: account.postbox,
|
postbox: account.postbox,
|
||||||
auxiliaryMethods: account.auxiliaryMethods,
|
auxiliaryMethods: account.auxiliaryMethods,
|
||||||
@ -172,94 +91,124 @@ func _internal_uploadStory(account: Account, media: EngineStoryInputMedia, priva
|
|||||||
text: "",
|
text: "",
|
||||||
media: [fileMedia]
|
media: [fileMedia]
|
||||||
)
|
)
|
||||||
let contentSignal: Signal<PendingMessageUploadedContentResult, PendingMessageUploadError>
|
}
|
||||||
switch contentToUpload {
|
|
||||||
case let .immediate(result, _):
|
|
||||||
contentSignal = .single(result)
|
|
||||||
case let .signal(signal, _):
|
|
||||||
contentSignal = signal
|
|
||||||
}
|
|
||||||
|
|
||||||
return contentSignal
|
let contentSignal: Signal<PendingMessageUploadedContentResult, PendingMessageUploadError>
|
||||||
|> map(Optional.init)
|
switch contentToUpload {
|
||||||
|> `catch` { _ -> Signal<PendingMessageUploadedContentResult?, NoError> in
|
case let .immediate(result, _):
|
||||||
return .single(nil)
|
contentSignal = .single(result)
|
||||||
}
|
case let .signal(signal, _):
|
||||||
|> mapToSignal { result -> Signal<Never, NoError> in
|
contentSignal = signal
|
||||||
return account.postbox.transaction { transaction -> Signal<Never, NoError> in
|
}
|
||||||
var privacyRules: [Api.InputPrivacyRule]
|
|
||||||
switch privacy.base {
|
return contentSignal
|
||||||
case .everyone:
|
|> map(Optional.init)
|
||||||
privacyRules = [.inputPrivacyValueAllowAll]
|
|> `catch` { _ -> Signal<PendingMessageUploadedContentResult?, NoError> in
|
||||||
case .contacts:
|
return .single(nil)
|
||||||
privacyRules = [.inputPrivacyValueAllowContacts]
|
}
|
||||||
case .closeFriends:
|
|> mapToSignal { result -> Signal<Never, NoError> in
|
||||||
privacyRules = [.inputPrivacyValueAllowCloseFriends]
|
return account.postbox.transaction { transaction -> Signal<Never, NoError> in
|
||||||
}
|
var privacyRules: [Api.InputPrivacyRule]
|
||||||
var privacyUsers: [Api.InputUser] = []
|
switch privacy.base {
|
||||||
var privacyChats: [Int64] = []
|
case .everyone:
|
||||||
for peerId in privacy.additionallyIncludePeers {
|
privacyRules = [.inputPrivacyValueAllowAll]
|
||||||
if let peer = transaction.getPeer(peerId) {
|
case .contacts:
|
||||||
if let _ = peer as? TelegramUser {
|
privacyRules = [.inputPrivacyValueAllowContacts]
|
||||||
if let inputUser = apiInputUser(peer) {
|
case .closeFriends:
|
||||||
privacyUsers.append(inputUser)
|
privacyRules = [.inputPrivacyValueAllowCloseFriends]
|
||||||
}
|
}
|
||||||
} else if peer is TelegramGroup || peer is TelegramChannel {
|
var privacyUsers: [Api.InputUser] = []
|
||||||
privacyChats.append(peer.id.id._internalGetInt64Value())
|
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 !privacyUsers.isEmpty {
|
||||||
}
|
privacyRules.append(.inputPrivacyValueAllowUsers(users: privacyUsers))
|
||||||
if !privacyChats.isEmpty {
|
}
|
||||||
privacyRules.append(.inputPrivacyValueAllowChatParticipants(chats: privacyChats))
|
if !privacyChats.isEmpty {
|
||||||
}
|
privacyRules.append(.inputPrivacyValueAllowChatParticipants(chats: privacyChats))
|
||||||
|
}
|
||||||
switch result {
|
|
||||||
case let .content(content):
|
switch result {
|
||||||
switch content.content {
|
case let .content(content):
|
||||||
case let .media(inputMedia, _):
|
switch content.content {
|
||||||
return account.network.request(Api.functions.stories.sendStory(flags: 0, media: inputMedia, caption: nil, entities: nil, privacyRules: privacyRules))
|
case let .media(inputMedia, _):
|
||||||
|> map(Optional.init)
|
var flags: Int32 = 0
|
||||||
|> `catch` { _ -> Signal<Api.Updates?, NoError> in
|
var apiCaption: String?
|
||||||
return .single(nil)
|
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 {
|
return account.network.request(Api.functions.stories.sendStory(
|
||||||
if case let .updateStories(stories) = update {
|
flags: flags,
|
||||||
switch stories {
|
media: inputMedia,
|
||||||
case .userStories(let userId, let apiStories), .userStoriesSlice(_, let userId, let apiStories):
|
caption: apiCaption,
|
||||||
if PeerId(namespace: Namespaces.Peer.CloudUser, id: PeerId.Id._internalFromInt64Value(userId)) == account.peerId, apiStories.count == 1 {
|
entities: apiEntities,
|
||||||
switch apiStories[0] {
|
privacyRules: privacyRules
|
||||||
case let .storyItem(_, _, _, _, _, media, _, _, _):
|
))
|
||||||
let (parsedMedia, _, _, _) = textMediaAndExpirationTimerFromApiMedia(media, account.peerId)
|
|> map(Optional.init)
|
||||||
if let parsedMedia = parsedMedia {
|
|> `catch` { _ -> Signal<Api.Updates?, NoError> in
|
||||||
applyMediaResourceChanges(from: fileMedia, to: parsedMedia, postbox: account.postbox, force: true)
|
return .single(nil)
|
||||||
}
|
}
|
||||||
default:
|
|> mapToSignal { updates -> Signal<Never, NoError> in
|
||||||
break
|
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()
|
return .complete()
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
return .complete()
|
return .complete()
|
||||||
}
|
}
|
||||||
|
default:
|
||||||
|
return .complete()
|
||||||
}
|
}
|
||||||
|> switchToLatest
|
|
||||||
}
|
}
|
||||||
|
|> switchToLatest
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -291,3 +240,217 @@ func _internal_markStoryAsSeen(account: Account, peerId: PeerId, id: Int32) -> S
|
|||||||
|> ignoreValues
|
|> 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
|
import SwiftSignalKit
|
||||||
|
|
||||||
enum InternalStoryUpdate {
|
enum InternalStoryUpdate {
|
||||||
case deleted(Int32)
|
case deleted(peerId: PeerId, id: Int32)
|
||||||
case added(peerId: PeerId, item: StoryListContext.Item)
|
case added(peerId: PeerId, item: StoryListContext.Item)
|
||||||
case read(peerId: PeerId, maxId: Int32)
|
case read(peerId: PeerId, maxId: Int32)
|
||||||
}
|
}
|
||||||
@ -15,20 +15,32 @@ public final class StoryListContext {
|
|||||||
case peer(EnginePeer.Id)
|
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 final class Item: Equatable {
|
||||||
public let id: Int32
|
public let id: Int32
|
||||||
public let timestamp: Int32
|
public let timestamp: Int32
|
||||||
public let media: EngineMedia
|
public let media: EngineMedia
|
||||||
public let seenCount: Int
|
public let text: String
|
||||||
public let seenPeers: [EnginePeer]
|
public let entities: [MessageTextEntity]
|
||||||
|
public let views: Views?
|
||||||
public let privacy: EngineStoryPrivacy?
|
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.id = id
|
||||||
self.timestamp = timestamp
|
self.timestamp = timestamp
|
||||||
self.media = media
|
self.media = media
|
||||||
self.seenCount = seenCount
|
self.text = text
|
||||||
self.seenPeers = seenPeers
|
self.entities = entities
|
||||||
|
self.views = views
|
||||||
self.privacy = privacy
|
self.privacy = privacy
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -42,10 +54,13 @@ public final class StoryListContext {
|
|||||||
if lhs.media != rhs.media {
|
if lhs.media != rhs.media {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
if lhs.seenCount != rhs.seenCount {
|
if lhs.text != rhs.text {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
if lhs.seenPeers != rhs.seenPeers {
|
if lhs.entities != rhs.entities {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if lhs.views != rhs.views {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
if lhs.privacy != rhs.privacy {
|
if lhs.privacy != rhs.privacy {
|
||||||
@ -207,18 +222,20 @@ public final class StoryListContext {
|
|||||||
|
|
||||||
for update in updates {
|
for update in updates {
|
||||||
switch update {
|
switch update {
|
||||||
case let .deleted(id):
|
case let .deleted(peerId, id):
|
||||||
for i in 0 ..< itemSets.count {
|
for i in 0 ..< itemSets.count {
|
||||||
if let index = itemSets[i].items.firstIndex(where: { $0.id == id }) {
|
if itemSets[i].peerId == peerId {
|
||||||
var items = itemSets[i].items
|
if let index = itemSets[i].items.firstIndex(where: { $0.id == id }) {
|
||||||
items.remove(at: index)
|
var items = itemSets[i].items
|
||||||
itemSets[i] = PeerItemSet(
|
items.remove(at: index)
|
||||||
peerId: itemSets[i].peerId,
|
itemSets[i] = PeerItemSet(
|
||||||
peer: itemSets[i].peer,
|
peerId: itemSets[i].peerId,
|
||||||
maxReadId: itemSets[i].maxReadId,
|
peer: itemSets[i].peer,
|
||||||
items: items,
|
maxReadId: itemSets[i].maxReadId,
|
||||||
totalCount: items.count
|
items: items,
|
||||||
)
|
totalCount: items.count
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
case let .added(peerId, item):
|
case let .added(peerId, item):
|
||||||
@ -232,18 +249,7 @@ public final class StoryListContext {
|
|||||||
items.remove(at: index)
|
items.remove(at: index)
|
||||||
}
|
}
|
||||||
|
|
||||||
if peerId == self.account.peerId {
|
items.append(item)
|
||||||
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.sort(by: { lhsItem, rhsItem in
|
items.sort(by: { lhsItem, rhsItem in
|
||||||
if lhsItem.timestamp != rhsItem.timestamp {
|
if lhsItem.timestamp != rhsItem.timestamp {
|
||||||
@ -367,68 +373,13 @@ public final class StoryListContext {
|
|||||||
let peerId = id
|
let peerId = id
|
||||||
|
|
||||||
for apiStory in apiStories {
|
for apiStory in apiStories {
|
||||||
switch apiStory {
|
if let item = _internal_parseApiStoryItem(transaction: transaction, peerId: peerId, apiStory: apiStory) {
|
||||||
case let .storyItem(flags, id, date, _, _, media, privacy, recentViewers, viewCount):
|
if !parsedItemSets.isEmpty && parsedItemSets[parsedItemSets.count - 1].peerId == peerId {
|
||||||
let _ = flags
|
parsedItemSets[parsedItemSets.count - 1].items.append(item)
|
||||||
let (parsedMedia, _, _, _) = textMediaAndExpirationTimerFromApiMedia(media, peerId)
|
parsedItemSets[parsedItemSets.count - 1].totalCount = parsedItemSets[parsedItemSets.count - 1].items.count
|
||||||
if let parsedMedia = parsedMedia {
|
} else {
|
||||||
var seenPeers: [EnginePeer] = []
|
parsedItemSets.append(StoryListContext.PeerItemSet(peerId: peerId, peer: transaction.getPeer(peerId).flatMap(EnginePeer.init), maxReadId: 0, items: [item], totalCount: 1))
|
||||||
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))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
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()
|
let uploadContext = UploadContext()
|
||||||
self.uploadContexts.append(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
|
|> deliverOn(self.queue)).start(next: { _ in
|
||||||
}, completed: { [weak self, weak uploadContext] in
|
}, completed: { [weak self, weak uploadContext] in
|
||||||
guard let `self` = self, let uploadContext = uploadContext else {
|
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))
|
let peerId = PeerId(namespace: Namespaces.Peer.CloudUser, id: PeerId.Id._internalFromInt64Value(apiUserId))
|
||||||
for apiStory in apiStories {
|
for apiStory in apiStories {
|
||||||
switch apiStory {
|
if let item = _internal_parseApiStoryItem(transaction: transaction, peerId: peerId, apiStory: apiStory) {
|
||||||
case let .storyItem(flags, id, date, _, _, media, privacy, recentViewers, viewCount):
|
if !parsedItemSets.isEmpty && parsedItemSets[parsedItemSets.count - 1].peerId == peerId {
|
||||||
let _ = flags
|
parsedItemSets[parsedItemSets.count - 1].items.append(item)
|
||||||
let (parsedMedia, _, _, _) = textMediaAndExpirationTimerFromApiMedia(media, peerId)
|
} else {
|
||||||
if let parsedMedia = parsedMedia {
|
parsedItemSets.append(StoryListContext.PeerItemSet(
|
||||||
var seenPeers: [EnginePeer] = []
|
peerId: peerId,
|
||||||
if let recentViewers = recentViewers {
|
peer: transaction.getPeer(peerId).flatMap(EnginePeer.init),
|
||||||
for id in recentViewers {
|
maxReadId: 0,
|
||||||
if let peer = transaction.getPeer(PeerId(namespace: Namespaces.Peer.CloudUser, id: PeerId.Id._internalFromInt64Value(id))) {
|
items: [item],
|
||||||
seenPeers.append(EnginePeer(peer))
|
totalCount: apiTotalCount.flatMap(Int.init)
|
||||||
}
|
))
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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)
|
|
||||||
))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
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
|
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))
|
return StoryListContext(account: self.account, scope: .peer(id))
|
||||||
}
|
}
|
||||||
|
|
||||||
public func uploadStory(media: EngineStoryInputMedia, privacy: EngineStoryPrivacy) -> Signal<Never, NoError> {
|
public func uploadStory(media: EngineStoryInputMedia, text: String, entities: [MessageTextEntity], privacy: EngineStoryPrivacy) -> Signal<Never, NoError> {
|
||||||
return _internal_uploadStory(account: self.account, media: media, privacy: privacy)
|
return _internal_uploadStory(account: self.account, media: media, text: text, entities: entities, privacy: privacy)
|
||||||
}
|
}
|
||||||
|
|
||||||
public func deleteStory(id: Int32) -> Signal<Never, NoError> {
|
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> {
|
public func markStoryAsSeen(peerId: EnginePeer.Id, id: Int32) -> Signal<Never, NoError> {
|
||||||
return _internal_markStoryAsSeen(account: self.account, peerId: peerId, id: id)
|
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 {
|
guard let resource = file.media.resource as? CloudDocumentMediaResource else {
|
||||||
return .fail(.generic)
|
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))
|
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
|
|> `catch` { error -> Signal<Api.account.SavedRingtone, MTRpcError> in
|
||||||
if error.errorDescription == "FILE_REFERENCE_EXPIRED" {
|
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
|
|> mapError { _ -> MTRpcError in
|
||||||
return MTRpcError(errorCode: 500, errorDescription: "Internal")
|
return MTRpcError(errorCode: 500, errorDescription: "Internal")
|
||||||
}
|
}
|
||||||
|
|||||||
@ -353,7 +353,7 @@ public extension TelegramEngine {
|
|||||||
|> mapToSignal { datacenterId -> Signal<EngineMediaResource.Fetch.Result, EngineMediaResource.Fetch.Error> in
|
|> mapToSignal { datacenterId -> Signal<EngineMediaResource.Fetch.Result, EngineMediaResource.Fetch.Error> in
|
||||||
let resource = AlbumCoverResource(datacenterId: Int(datacenterId), file: file, title: title, performer: performer, isThumbnail: isThumbnail)
|
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,
|
tag: nil,
|
||||||
info: TelegramCloudMediaResourceFetchInfo(
|
info: TelegramCloudMediaResourceFetchInfo(
|
||||||
reference: MediaResourceReference.standalone(resource: resource),
|
reference: MediaResourceReference.standalone(resource: resource),
|
||||||
|
|||||||
@ -75,9 +75,10 @@ func _internal_stickerPacksAttachedToMedia(account: Account, media: AnyMediaRefe
|
|||||||
} else {
|
} else {
|
||||||
return .single([])
|
return .single([])
|
||||||
}
|
}
|
||||||
|
let accountPeerId = account.peerId
|
||||||
return account.network.request(Api.functions.messages.getAttachedStickers(media: inputMedia))
|
return account.network.request(Api.functions.messages.getAttachedStickers(media: inputMedia))
|
||||||
|> `catch` { _ -> Signal<[Api.StickerSetCovered], MTRpcError> in
|
|> `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
|
|> mapError { _ -> MTRpcError in
|
||||||
return MTRpcError(errorCode: 500, errorDescription: "Internal")
|
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));
|
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 maxDimension = max(dimensions.x, dimensions.y);
|
||||||
|
|
||||||
float currentDistance = time * maxDimension;
|
float currentDistance = time * maxDimension;
|
||||||
float waveWidth = 100.0f * 3.0f;
|
float waveWidth = 100.0f * contentScale;
|
||||||
|
|
||||||
float d = distance(center, position);
|
float d = distance(center, position);
|
||||||
|
|
||||||
@ -50,7 +50,8 @@ vertex RasterizerData rippleVertex
|
|||||||
device const uint2 ¢er [[buffer(0)]],
|
device const uint2 ¢er [[buffer(0)]],
|
||||||
device const uint2 &gridResolution [[buffer(1)]],
|
device const uint2 &gridResolution [[buffer(1)]],
|
||||||
device const uint2 &resolution [[buffer(2)]],
|
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 triangleIndex = vid / 6;
|
||||||
uint vertexIndex = vid % 6;
|
uint vertexIndex = vid % 6;
|
||||||
@ -69,7 +70,7 @@ vertex RasterizerData rippleVertex
|
|||||||
);
|
);
|
||||||
float2 texCoord = float2(position.x, 1.0 - position.y);
|
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;
|
zPosition *= 0.5f;
|
||||||
|
|
||||||
float leftEdgeDistance = abs(position.x);
|
float leftEdgeDistance = abs(position.x);
|
||||||
@ -84,9 +85,6 @@ vertex RasterizerData rippleVertex
|
|||||||
zPosition *= edgeDistance;
|
zPosition *= edgeDistance;
|
||||||
|
|
||||||
zPosition *= max(0.0, min(1.0, linearDecay(time, 0.7)));
|
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 camPosition = float3(0.0, 0.0f, 1.0f);
|
||||||
float3 camTarget = float3(0.0, 0.0, 0.0);
|
float3 camTarget = float3(0.0, 0.0, 0.0);
|
||||||
@ -147,6 +145,9 @@ fragment half4 rippleFragment(
|
|||||||
float4 rgb = float4(texture.sample(textureSampler, texCoord));
|
float4 rgb = float4(texture.sample(textureSampler, texCoord));
|
||||||
|
|
||||||
float4 out = float4(rgb.xyz, 1.0);
|
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);
|
out.a = 1.0 - step(in.visibilityFraction, 0.5);
|
||||||
|
|
||||||
|
|||||||
@ -4,6 +4,9 @@ import MetalKit
|
|||||||
import simd
|
import simd
|
||||||
|
|
||||||
public final class RippleEffectView: MTKView {
|
public final class RippleEffectView: MTKView {
|
||||||
|
private let centerLocation: CGPoint
|
||||||
|
private let completion: () -> Void
|
||||||
|
|
||||||
private let textureLoader: MTKTextureLoader
|
private let textureLoader: MTKTextureLoader
|
||||||
private let commandQueue: MTLCommandQueue
|
private let commandQueue: MTLCommandQueue
|
||||||
private let drawPassthroughPipelineState: MTLRenderPipelineState
|
private let drawPassthroughPipelineState: MTLRenderPipelineState
|
||||||
@ -11,7 +14,7 @@ public final class RippleEffectView: MTKView {
|
|||||||
|
|
||||||
private var viewportDimensions = CGSize(width: 1, height: 1)
|
private var viewportDimensions = CGSize(width: 1, height: 1)
|
||||||
|
|
||||||
private var time: Float = 0.0
|
private var startTime: Double?
|
||||||
|
|
||||||
private var lastUpdateTimestamp: 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)
|
let mainBundle = Bundle(for: RippleEffectView.self)
|
||||||
|
|
||||||
guard let path = mainBundle.path(forResource: "FullScreenEffectViewBundle", ofType: "bundle") else {
|
guard let path = mainBundle.path(forResource: "FullScreenEffectViewBundle", ofType: "bundle") else {
|
||||||
@ -135,12 +141,21 @@ public final class RippleEffectView: MTKView {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private func redraw(drawable: MTLDrawable) {
|
private func redraw(drawable: MTLDrawable) {
|
||||||
if let lastUpdateTimestamp = self.lastUpdateTimestamp {
|
/*if let lastUpdateTimestamp = self.lastUpdateTimestamp {
|
||||||
if lastUpdateTimestamp + 1.0 < CACurrentMediaTime() {
|
if lastUpdateTimestamp + 1.0 < CACurrentMediaTime() {
|
||||||
self.updateImageFromSourceView()
|
self.updateImageFromSourceView()
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
self.updateImageFromSourceView()
|
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 {
|
guard let commandBuffer = self.commandQueue.makeCommandBuffer() else {
|
||||||
@ -160,20 +175,20 @@ public final class RippleEffectView: MTKView {
|
|||||||
renderEncoder.setRenderPipelineState(self.drawPassthroughPipelineState)
|
renderEncoder.setRenderPipelineState(self.drawPassthroughPipelineState)
|
||||||
|
|
||||||
let gridSize = 1000
|
let gridSize = 1000
|
||||||
var time = self.time.truncatingRemainder(dividingBy: 0.7)
|
var time: Float = Float(min(relativeTime, 0.7))
|
||||||
//time = 0.6
|
|
||||||
self.time += (1.0 / 60.0) * 0.1
|
|
||||||
|
|
||||||
var gridResolution = simd_uint2(UInt32(gridSize), UInt32(gridSize))
|
var gridResolution = simd_uint2(UInt32(gridSize), UInt32(gridSize))
|
||||||
var resolution = simd_uint2(UInt32(viewportDimensions.width), UInt32(viewportDimensions.height))
|
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 {
|
if let texture = self.texture {
|
||||||
|
var contentScale: Float = Float(self.contentScaleFactor)
|
||||||
renderEncoder.setVertexBytes(¢er, length: MemoryLayout<simd_uint2>.size, index: 0)
|
renderEncoder.setVertexBytes(¢er, length: MemoryLayout<simd_uint2>.size, index: 0)
|
||||||
renderEncoder.setVertexBytes(&gridResolution, length: MemoryLayout<simd_uint2>.size, index: 1)
|
renderEncoder.setVertexBytes(&gridResolution, length: MemoryLayout<simd_uint2>.size, index: 1)
|
||||||
renderEncoder.setVertexBytes(&resolution, length: MemoryLayout<simd_uint2>.size, index: 2)
|
renderEncoder.setVertexBytes(&resolution, length: MemoryLayout<simd_uint2>.size, index: 2)
|
||||||
renderEncoder.setVertexBytes(&time, length: MemoryLayout<Float>.size, index: 3)
|
renderEncoder.setVertexBytes(&time, length: MemoryLayout<Float>.size, index: 3)
|
||||||
|
renderEncoder.setVertexBytes(&contentScale, length: MemoryLayout<Float>.size, index: 4)
|
||||||
|
|
||||||
renderEncoder.setFragmentTexture(texture, index: 0)
|
renderEncoder.setFragmentTexture(texture, index: 0)
|
||||||
|
|
||||||
@ -184,5 +199,11 @@ public final class RippleEffectView: MTKView {
|
|||||||
|
|
||||||
commandBuffer.present(drawable)
|
commandBuffer.present(drawable)
|
||||||
commandBuffer.commit()
|
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 {
|
for itemSet in state.itemSets {
|
||||||
var items: [StoryContentItem] = []
|
var items: [StoryContentItem] = []
|
||||||
|
|
||||||
|
guard let peer = itemSet.peer else {
|
||||||
|
continue
|
||||||
|
}
|
||||||
let peerId = itemSet.peerId
|
let peerId = itemSet.peerId
|
||||||
|
|
||||||
for item in itemSet.items {
|
for item in itemSet.items {
|
||||||
@ -24,7 +27,7 @@ public enum StoryChatContent {
|
|||||||
position: items.count,
|
position: items.count,
|
||||||
component: AnyComponent(StoryItemContentComponent(
|
component: AnyComponent(StoryItemContentComponent(
|
||||||
context: context,
|
context: context,
|
||||||
peerId: peerId,
|
peer: peer,
|
||||||
item: item
|
item: item
|
||||||
)),
|
)),
|
||||||
centerInfoComponent: AnyComponent(StoryAuthorInfoComponent(
|
centerInfoComponent: AnyComponent(StoryAuthorInfoComponent(
|
||||||
|
|||||||
@ -16,12 +16,12 @@ final class StoryItemContentComponent: Component {
|
|||||||
typealias EnvironmentType = StoryContentItem.Environment
|
typealias EnvironmentType = StoryContentItem.Environment
|
||||||
|
|
||||||
let context: AccountContext
|
let context: AccountContext
|
||||||
let peerId: EnginePeer.Id
|
let peer: EnginePeer
|
||||||
let item: StoryListContext.Item
|
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.context = context
|
||||||
self.peerId = peerId
|
self.peer = peer
|
||||||
self.item = item
|
self.item = item
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -29,7 +29,7 @@ final class StoryItemContentComponent: Component {
|
|||||||
if lhs.context !== rhs.context {
|
if lhs.context !== rhs.context {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
if lhs.peerId != rhs.peerId {
|
if lhs.peer != rhs.peer {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
if lhs.item != rhs.item {
|
if lhs.item != rhs.item {
|
||||||
@ -144,7 +144,7 @@ final class StoryItemContentComponent: Component {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if case let .file(file) = currentMessageMedia {
|
if case let .file(file) = currentMessageMedia, let peerReference = PeerReference(component.peer._asPeer()) {
|
||||||
if self.videoNode == nil {
|
if self.videoNode == nil {
|
||||||
let videoNode = UniversalVideoNode(
|
let videoNode = UniversalVideoNode(
|
||||||
postbox: component.context.account.postbox,
|
postbox: component.context.account.postbox,
|
||||||
@ -154,7 +154,7 @@ final class StoryItemContentComponent: Component {
|
|||||||
content: NativeVideoContent(
|
content: NativeVideoContent(
|
||||||
id: .message(0, file.fileId),
|
id: .message(0, file.fileId),
|
||||||
userLocation: .other,
|
userLocation: .other,
|
||||||
fileReference: .standalone(media: file),
|
fileReference: .story(peer: peerReference, id: component.item.id, media: file),
|
||||||
imageReference: nil,
|
imageReference: nil,
|
||||||
loopVideo: true,
|
loopVideo: true,
|
||||||
enableSound: true,
|
enableSound: true,
|
||||||
@ -224,7 +224,7 @@ final class StoryItemContentComponent: Component {
|
|||||||
if !self.markedAsSeen {
|
if !self.markedAsSeen {
|
||||||
self.markedAsSeen = true
|
self.markedAsSeen = true
|
||||||
if let component = self.component {
|
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 {
|
if !self.markedAsSeen {
|
||||||
self.markedAsSeen = true
|
self.markedAsSeen = true
|
||||||
if let component = self.component {
|
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.state = state
|
||||||
self.environment = environment[StoryContentItem.Environment.self].value
|
self.environment = environment[StoryContentItem.Environment.self].value
|
||||||
|
|
||||||
|
let peerReference = PeerReference(component.peer._asPeer())
|
||||||
|
|
||||||
var messageMedia: EngineMedia?
|
var messageMedia: EngineMedia?
|
||||||
switch component.item.media {
|
switch component.item.media {
|
||||||
case let .image(image):
|
case let .image(image):
|
||||||
@ -324,7 +326,7 @@ final class StoryItemContentComponent: Component {
|
|||||||
reloadMedia = true
|
reloadMedia = true
|
||||||
}
|
}
|
||||||
|
|
||||||
if reloadMedia, let messageMedia {
|
if reloadMedia, let messageMedia, let peerReference {
|
||||||
var signal: Signal<(TransformImageArguments) -> DrawingContext?, NoError>?
|
var signal: Signal<(TransformImageArguments) -> DrawingContext?, NoError>?
|
||||||
var fetchSignal: Signal<Never, NoError>?
|
var fetchSignal: Signal<Never, NoError>?
|
||||||
switch messageMedia {
|
switch messageMedia {
|
||||||
@ -332,7 +334,7 @@ final class StoryItemContentComponent: Component {
|
|||||||
signal = chatMessagePhoto(
|
signal = chatMessagePhoto(
|
||||||
postbox: component.context.account.postbox,
|
postbox: component.context.account.postbox,
|
||||||
userLocation: .other,
|
userLocation: .other,
|
||||||
photoReference: .standalone(media: image),
|
photoReference: .story(peer: peerReference, id: component.item.id, media: image),
|
||||||
synchronousLoad: true,
|
synchronousLoad: true,
|
||||||
highQuality: true
|
highQuality: true
|
||||||
)
|
)
|
||||||
@ -341,7 +343,7 @@ final class StoryItemContentComponent: Component {
|
|||||||
mediaBox: component.context.account.postbox.mediaBox,
|
mediaBox: component.context.account.postbox.mediaBox,
|
||||||
userLocation: .other,
|
userLocation: .other,
|
||||||
userContentType: .image,
|
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
|
|> ignoreValues
|
||||||
|> `catch` { _ -> Signal<Never, NoError> in
|
|> `catch` { _ -> Signal<Never, NoError> in
|
||||||
@ -354,14 +356,14 @@ final class StoryItemContentComponent: Component {
|
|||||||
signal = chatMessageVideo(
|
signal = chatMessageVideo(
|
||||||
postbox: component.context.account.postbox,
|
postbox: component.context.account.postbox,
|
||||||
userLocation: .other,
|
userLocation: .other,
|
||||||
videoReference: .standalone(media: file),
|
videoReference: .story(peer: peerReference, id: component.item.id, media: file),
|
||||||
synchronousLoad: true
|
synchronousLoad: true
|
||||||
)
|
)
|
||||||
fetchSignal = fetchedMediaResource(
|
fetchSignal = fetchedMediaResource(
|
||||||
mediaBox: component.context.account.postbox.mediaBox,
|
mediaBox: component.context.account.postbox.mediaBox,
|
||||||
userLocation: .other,
|
userLocation: .other,
|
||||||
userContentType: .image,
|
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
|
|> ignoreValues
|
||||||
|> `catch` { _ -> Signal<Never, NoError> in
|
|> `catch` { _ -> Signal<Never, NoError> in
|
||||||
|
|||||||
@ -73,7 +73,7 @@ public final class StoryFooterPanelComponent: Component {
|
|||||||
let avatarSpacing: CGFloat = 18.0
|
let avatarSpacing: CGFloat = 18.0
|
||||||
|
|
||||||
var peers: [EnginePeer] = []
|
var peers: [EnginePeer] = []
|
||||||
if let seenPeers = component.storyItem?.seenPeers {
|
if let seenPeers = component.storyItem?.views?.seenPeers {
|
||||||
peers = Array(seenPeers.prefix(3))
|
peers = Array(seenPeers.prefix(3))
|
||||||
}
|
}
|
||||||
let avatarsContent = self.avatarsContext.update(peers: peers, animated: false)
|
let avatarsContent = self.avatarsContext.update(peers: peers, animated: false)
|
||||||
@ -86,11 +86,11 @@ public final class StoryFooterPanelComponent: Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let viewsText: String
|
let viewsText: String
|
||||||
if let storyItem = component.storyItem, storyItem.seenCount != 0 {
|
if let views = component.storyItem?.views, views.seenCount != 0 {
|
||||||
if storyItem.seenCount == 1 {
|
if views.seenCount == 1 {
|
||||||
viewsText = "1 view"
|
viewsText = "1 view"
|
||||||
} else {
|
} else {
|
||||||
viewsText = "\(storyItem.seenCount) views"
|
viewsText = "\(views.seenCount) views"
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
viewsText = "No views yet"
|
viewsText = "No views yet"
|
||||||
|
|||||||
@ -372,18 +372,12 @@ public final class TelegramRootController: NavigationController, TelegramRootCon
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
if let chatListController = self.chatListController as? ChatListControllerImpl, let storyListContext = chatListController.storyListContext {
|
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()
|
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)
|
let resource = VideoLibraryMediaResource(localIdentifier: asset.localIdentifier, conversion: VideoLibraryMediaResourceConversion.passthrough)
|
||||||
|
|
||||||
if let chatListController = self.chatListController as? ChatListControllerImpl, let storyListContext = chatListController.storyListContext {
|
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()
|
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:
|
default:
|
||||||
selectionController?.dismiss()
|
selectionController?.dismiss()
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user