Update API

This commit is contained in:
Ilya Laktyushin 2023-12-14 06:56:25 +04:00
parent 072a923df4
commit ed8b17d325
12 changed files with 192 additions and 125 deletions

View File

@ -215,16 +215,14 @@ private enum StatsEntry: ItemListNodeEntry {
} }
} }
private func messageStatsControllerEntries(data: PostStats?, storyViews: EngineStoryItem.Views?, messages: SearchMessagesResult?, forwards: StoryStatsPublicForwardsContext.State?, presentationData: PresentationData) -> [StatsEntry] { private func messageStatsControllerEntries(data: PostStats?, storyViews: EngineStoryItem.Views?, forwards: StoryStatsPublicForwardsContext.State?, presentationData: PresentationData) -> [StatsEntry] {
var entries: [StatsEntry] = [] var entries: [StatsEntry] = []
if let data = data { if let data = data {
entries.append(.overviewTitle(presentationData.theme, presentationData.strings.Stats_MessageOverview.uppercased())) entries.append(.overviewTitle(presentationData.theme, presentationData.strings.Stats_MessageOverview.uppercased()))
var publicShares: Int32? var publicShares: Int32?
if let messages { if let forwards {
publicShares = messages.totalCount
} else if let forwards {
publicShares = forwards.count publicShares = forwards.count
} }
entries.append(.overview(presentationData.theme, data, storyViews, publicShares)) entries.append(.overview(presentationData.theme, data, storyViews, publicShares))
@ -254,15 +252,6 @@ private func messageStatsControllerEntries(data: PostStats?, storyViews: EngineS
entries.append(.reactionsGraph(presentationData.theme, presentationData.strings, presentationData.dateTimeFormat, data.reactionsGraph, .bars, isStories)) entries.append(.reactionsGraph(presentationData.theme, presentationData.strings, presentationData.dateTimeFormat, data.reactionsGraph, .bars, isStories))
} }
if let messages, !messages.messages.isEmpty {
entries.append(.publicForwardsTitle(presentationData.theme, presentationData.strings.Stats_MessagePublicForwardsTitle.uppercased()))
var index: Int32 = 0
for message in messages.messages {
entries.append(.publicForward(index, presentationData.theme, presentationData.strings, presentationData.dateTimeFormat, .message(message)))
index += 1
}
}
if let forwards, !forwards.forwards.isEmpty { if let forwards, !forwards.forwards.isEmpty {
entries.append(.publicForwardsTitle(presentationData.theme, presentationData.strings.Stats_MessagePublicForwardsTitle.uppercased())) entries.append(.publicForwardsTitle(presentationData.theme, presentationData.strings.Stats_MessagePublicForwardsTitle.uppercased()))
var index: Int32 = 0 var index: Int32 = 0
@ -305,7 +294,6 @@ public func messageStatsController(context: AccountContext, updatedPresentationD
let actionsDisposable = DisposableSet() let actionsDisposable = DisposableSet()
let dataPromise = Promise<PostStats?>(nil) let dataPromise = Promise<PostStats?>(nil)
let messagesPromise = Promise<(SearchMessagesResult, SearchMessagesState)?>(nil)
let forwardsPromise = Promise<StoryStatsPublicForwardsContext.State?>(nil) let forwardsPromise = Promise<StoryStatsPublicForwardsContext.State?>(nil)
let anyStatsContext: Any let anyStatsContext: Any
@ -314,7 +302,7 @@ public func messageStatsController(context: AccountContext, updatedPresentationD
var openStoryImpl: ((EnginePeer.Id, EngineStoryItem, UIView) -> Void)? var openStoryImpl: ((EnginePeer.Id, EngineStoryItem, UIView) -> Void)?
var storyContextActionImpl: ((EnginePeer.Id, ASDisplayNode, ContextGesture?, Bool) -> Void)? var storyContextActionImpl: ((EnginePeer.Id, ASDisplayNode, ContextGesture?, Bool) -> Void)?
var forwardsContext: StoryStatsPublicForwardsContext? let forwardsContext: StoryStatsPublicForwardsContext
let peerId: EnginePeer.Id let peerId: EnginePeer.Id
var storyItem: EngineStoryItem? var storyItem: EngineStoryItem?
switch subject { switch subject {
@ -331,19 +319,7 @@ public func messageStatsController(context: AccountContext, updatedPresentationD
dataPromise.set(.single(nil) |> then(dataSignal)) dataPromise.set(.single(nil) |> then(dataSignal))
anyStatsContext = statsContext anyStatsContext = statsContext
let searchSignal = context.engine.messages.searchMessages(location: .publicForwards(messageId: id), query: "", state: nil) forwardsContext = StoryStatsPublicForwardsContext(account: context.account, subject: .message(messageId: id))
|> map(Optional.init)
|> afterNext { result in
if let result = result {
for message in result.0.messages {
if let peer = message.peers[message.id.peerId], let peerReference = PeerReference(peer) {
let _ = context.engine.peers.updatedRemotePeer(peer: peerReference).start()
}
}
}
}
messagesPromise.set(.single(nil) |> then(searchSignal))
forwardsPromise.set(.single(nil))
case let .story(peerIdValue, id, item, _): case let .story(peerIdValue, id, item, _):
peerId = peerIdValue peerId = peerIdValue
storyItem = item storyItem = item
@ -358,23 +334,18 @@ public func messageStatsController(context: AccountContext, updatedPresentationD
} }
dataPromise.set(.single(nil) |> then(dataSignal)) dataPromise.set(.single(nil) |> then(dataSignal))
anyStatsContext = statsContext anyStatsContext = statsContext
messagesPromise.set(.single(nil)) forwardsContext = StoryStatsPublicForwardsContext(account: context.account, subject: .story(peerId: peerId, id: id))
forwardsContext = StoryStatsPublicForwardsContext(account: context.account, peerId: peerId, storyId: id)
if let forwardsContext {
forwardsPromise.set(
.single(nil)
|> then(
forwardsContext.state
|> map(Optional.init)
)
)
} else {
forwardsPromise.set(.single(nil))
}
} }
forwardsPromise.set(
.single(nil)
|> then(
forwardsContext.state
|> map(Optional.init)
)
)
let arguments = MessageStatsControllerArguments(context: context, loadDetailedGraph: { graph, x -> Signal<StatsGraph?, NoError> in let arguments = MessageStatsControllerArguments(context: context, loadDetailedGraph: { graph, x -> Signal<StatsGraph?, NoError> in
return loadDetailedGraphImpl?(graph, x) ?? .single(nil) return loadDetailedGraphImpl?(graph, x) ?? .single(nil)
}, openMessage: { messageId in }, openMessage: { messageId in
@ -412,14 +383,13 @@ public func messageStatsController(context: AccountContext, updatedPresentationD
let presentationData = updatedPresentationData?.signal ?? context.sharedContext.presentationData let presentationData = updatedPresentationData?.signal ?? context.sharedContext.presentationData
let signal = combineLatest( let signal = combineLatest(
presentationData, presentationData,
dataPromise.get(), dataPromise.get(),
messagesPromise.get(),
forwardsPromise.get(), forwardsPromise.get(),
longLoadingSignal, longLoadingSignal,
iconNodePromise.get() iconNodePromise.get()
) )
|> deliverOnMainQueue |> deliverOnMainQueue
|> map { presentationData, data, search, forwards, longLoading, iconNode -> (ItemListControllerState, (ItemListNodeState, Any)) in |> map { presentationData, data, forwards, longLoading, iconNode -> (ItemListControllerState, (ItemListNodeState, Any)) in
let previous = previousData.swap(data) let previous = previousData.swap(data)
var emptyStateItem: ItemListControllerEmptyStateItem? var emptyStateItem: ItemListControllerEmptyStateItem?
if data == nil { if data == nil {
@ -445,7 +415,7 @@ public func messageStatsController(context: AccountContext, updatedPresentationD
openStoryImpl?(peerId, storyItem, iconNode.view) openStoryImpl?(peerId, storyItem, iconNode.view)
} }
}) }, backNavigationButton: ItemListBackButton(title: presentationData.strings.Common_Back), animateChanges: true) }) }, backNavigationButton: ItemListBackButton(title: presentationData.strings.Common_Back), animateChanges: true)
let listState = ItemListNodeState(presentationData: ItemListPresentationData(presentationData), entries: messageStatsControllerEntries(data: data, storyViews: storyViews, messages: search?.0, forwards: forwards, presentationData: presentationData), style: .blocks, emptyStateItem: emptyStateItem, crossfadeState: previous == nil, animateChanges: false) let listState = ItemListNodeState(presentationData: ItemListPresentationData(presentationData), entries: messageStatsControllerEntries(data: data, storyViews: storyViews, forwards: forwards, presentationData: presentationData), style: .blocks, emptyStateItem: emptyStateItem, crossfadeState: previous == nil, animateChanges: false)
return (controllerState, (listState, arguments)) return (controllerState, (listState, arguments))
} }
@ -464,7 +434,7 @@ public func messageStatsController(context: AccountContext, updatedPresentationD
}) })
} }
controller.visibleBottomContentOffsetChanged = { [weak forwardsContext] offset in controller.visibleBottomContentOffsetChanged = { [weak forwardsContext] offset in
if case let .known(value) = offset, value < 100.0, case .story = subject { if case let .known(value) = offset, value < 100.0 {
forwardsContext?.loadMore() forwardsContext?.loadMore()
} }
} }

View File

@ -463,7 +463,9 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = {
dict[695856818] = { return Api.LangPackString.parse_langPackStringDeleted($0) } dict[695856818] = { return Api.LangPackString.parse_langPackStringDeleted($0) }
dict[1816636575] = { return Api.LangPackString.parse_langPackStringPluralized($0) } dict[1816636575] = { return Api.LangPackString.parse_langPackStringPluralized($0) }
dict[-1361650766] = { return Api.MaskCoords.parse_maskCoords($0) } dict[-1361650766] = { return Api.MaskCoords.parse_maskCoords($0) }
dict[577893055] = { return Api.MediaArea.parse_inputMediaAreaChannelPost($0) }
dict[-1300094593] = { return Api.MediaArea.parse_inputMediaAreaVenue($0) } dict[-1300094593] = { return Api.MediaArea.parse_inputMediaAreaVenue($0) }
dict[1996756655] = { return Api.MediaArea.parse_mediaAreaChannelPost($0) }
dict[-544523486] = { return Api.MediaArea.parse_mediaAreaGeoPoint($0) } dict[-544523486] = { return Api.MediaArea.parse_mediaAreaGeoPoint($0) }
dict[340088945] = { return Api.MediaArea.parse_mediaAreaSuggestedReaction($0) } dict[340088945] = { return Api.MediaArea.parse_mediaAreaSuggestedReaction($0) }
dict[-1098720356] = { return Api.MediaArea.parse_mediaAreaVenue($0) } dict[-1098720356] = { return Api.MediaArea.parse_mediaAreaVenue($0) }

View File

@ -155,14 +155,24 @@ public extension Api {
} }
} }
public extension Api { public extension Api {
enum MediaArea: TypeConstructorDescription { indirect enum MediaArea: TypeConstructorDescription {
case inputMediaAreaChannelPost(coordinates: Api.MediaAreaCoordinates, channel: Api.InputChannel, msgId: Int32)
case inputMediaAreaVenue(coordinates: Api.MediaAreaCoordinates, queryId: Int64, resultId: String) case inputMediaAreaVenue(coordinates: Api.MediaAreaCoordinates, queryId: Int64, resultId: String)
case mediaAreaChannelPost(coordinates: Api.MediaAreaCoordinates, channelId: Int64, msgId: Int32)
case mediaAreaGeoPoint(coordinates: Api.MediaAreaCoordinates, geo: Api.GeoPoint) case mediaAreaGeoPoint(coordinates: Api.MediaAreaCoordinates, geo: Api.GeoPoint)
case mediaAreaSuggestedReaction(flags: Int32, coordinates: Api.MediaAreaCoordinates, reaction: Api.Reaction) case mediaAreaSuggestedReaction(flags: Int32, coordinates: Api.MediaAreaCoordinates, reaction: Api.Reaction)
case mediaAreaVenue(coordinates: Api.MediaAreaCoordinates, geo: Api.GeoPoint, title: String, address: String, provider: String, venueId: String, venueType: String) case mediaAreaVenue(coordinates: Api.MediaAreaCoordinates, geo: Api.GeoPoint, title: String, address: String, provider: String, venueId: String, venueType: String)
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
switch self { switch self {
case .inputMediaAreaChannelPost(let coordinates, let channel, let msgId):
if boxed {
buffer.appendInt32(577893055)
}
coordinates.serialize(buffer, true)
channel.serialize(buffer, true)
serializeInt32(msgId, buffer: buffer, boxed: false)
break
case .inputMediaAreaVenue(let coordinates, let queryId, let resultId): case .inputMediaAreaVenue(let coordinates, let queryId, let resultId):
if boxed { if boxed {
buffer.appendInt32(-1300094593) buffer.appendInt32(-1300094593)
@ -171,6 +181,14 @@ public extension Api {
serializeInt64(queryId, buffer: buffer, boxed: false) serializeInt64(queryId, buffer: buffer, boxed: false)
serializeString(resultId, buffer: buffer, boxed: false) serializeString(resultId, buffer: buffer, boxed: false)
break break
case .mediaAreaChannelPost(let coordinates, let channelId, let msgId):
if boxed {
buffer.appendInt32(1996756655)
}
coordinates.serialize(buffer, true)
serializeInt64(channelId, buffer: buffer, boxed: false)
serializeInt32(msgId, buffer: buffer, boxed: false)
break
case .mediaAreaGeoPoint(let coordinates, let geo): case .mediaAreaGeoPoint(let coordinates, let geo):
if boxed { if boxed {
buffer.appendInt32(-544523486) buffer.appendInt32(-544523486)
@ -203,8 +221,12 @@ public extension Api {
public func descriptionFields() -> (String, [(String, Any)]) { public func descriptionFields() -> (String, [(String, Any)]) {
switch self { switch self {
case .inputMediaAreaChannelPost(let coordinates, let channel, let msgId):
return ("inputMediaAreaChannelPost", [("coordinates", coordinates as Any), ("channel", channel as Any), ("msgId", msgId as Any)])
case .inputMediaAreaVenue(let coordinates, let queryId, let resultId): case .inputMediaAreaVenue(let coordinates, let queryId, let resultId):
return ("inputMediaAreaVenue", [("coordinates", coordinates as Any), ("queryId", queryId as Any), ("resultId", resultId as Any)]) return ("inputMediaAreaVenue", [("coordinates", coordinates as Any), ("queryId", queryId as Any), ("resultId", resultId as Any)])
case .mediaAreaChannelPost(let coordinates, let channelId, let msgId):
return ("mediaAreaChannelPost", [("coordinates", coordinates as Any), ("channelId", channelId as Any), ("msgId", msgId as Any)])
case .mediaAreaGeoPoint(let coordinates, let geo): case .mediaAreaGeoPoint(let coordinates, let geo):
return ("mediaAreaGeoPoint", [("coordinates", coordinates as Any), ("geo", geo as Any)]) return ("mediaAreaGeoPoint", [("coordinates", coordinates as Any), ("geo", geo as Any)])
case .mediaAreaSuggestedReaction(let flags, let coordinates, let reaction): case .mediaAreaSuggestedReaction(let flags, let coordinates, let reaction):
@ -214,6 +236,27 @@ public extension Api {
} }
} }
public static func parse_inputMediaAreaChannelPost(_ reader: BufferReader) -> MediaArea? {
var _1: Api.MediaAreaCoordinates?
if let signature = reader.readInt32() {
_1 = Api.parse(reader, signature: signature) as? Api.MediaAreaCoordinates
}
var _2: Api.InputChannel?
if let signature = reader.readInt32() {
_2 = Api.parse(reader, signature: signature) as? Api.InputChannel
}
var _3: Int32?
_3 = reader.readInt32()
let _c1 = _1 != nil
let _c2 = _2 != nil
let _c3 = _3 != nil
if _c1 && _c2 && _c3 {
return Api.MediaArea.inputMediaAreaChannelPost(coordinates: _1!, channel: _2!, msgId: _3!)
}
else {
return nil
}
}
public static func parse_inputMediaAreaVenue(_ reader: BufferReader) -> MediaArea? { public static func parse_inputMediaAreaVenue(_ reader: BufferReader) -> MediaArea? {
var _1: Api.MediaAreaCoordinates? var _1: Api.MediaAreaCoordinates?
if let signature = reader.readInt32() { if let signature = reader.readInt32() {
@ -233,6 +276,25 @@ public extension Api {
return nil return nil
} }
} }
public static func parse_mediaAreaChannelPost(_ reader: BufferReader) -> MediaArea? {
var _1: Api.MediaAreaCoordinates?
if let signature = reader.readInt32() {
_1 = Api.parse(reader, signature: signature) as? Api.MediaAreaCoordinates
}
var _2: Int64?
_2 = reader.readInt64()
var _3: Int32?
_3 = reader.readInt32()
let _c1 = _1 != nil
let _c2 = _2 != nil
let _c3 = _3 != nil
if _c1 && _c2 && _c3 {
return Api.MediaArea.mediaAreaChannelPost(coordinates: _1!, channelId: _2!, msgId: _3!)
}
else {
return nil
}
}
public static func parse_mediaAreaGeoPoint(_ reader: BufferReader) -> MediaArea? { public static func parse_mediaAreaGeoPoint(_ reader: BufferReader) -> MediaArea? {
var _1: Api.MediaAreaCoordinates? var _1: Api.MediaAreaCoordinates?
if let signature = reader.readInt32() { if let signature = reader.readInt32() {

View File

@ -8557,20 +8557,18 @@ public extension Api.functions.stats {
} }
} }
public extension Api.functions.stats { public extension Api.functions.stats {
static func getMessagePublicForwards(channel: Api.InputChannel, msgId: Int32, offsetRate: Int32, offsetPeer: Api.InputPeer, offsetId: Int32, limit: Int32) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.messages.Messages>) { static func getMessagePublicForwards(channel: Api.InputChannel, msgId: Int32, offset: String, limit: Int32) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.stats.PublicForwards>) {
let buffer = Buffer() let buffer = Buffer()
buffer.appendInt32(1445996571) buffer.appendInt32(1595212100)
channel.serialize(buffer, true) channel.serialize(buffer, true)
serializeInt32(msgId, buffer: buffer, boxed: false) serializeInt32(msgId, buffer: buffer, boxed: false)
serializeInt32(offsetRate, buffer: buffer, boxed: false) serializeString(offset, buffer: buffer, boxed: false)
offsetPeer.serialize(buffer, true)
serializeInt32(offsetId, buffer: buffer, boxed: false)
serializeInt32(limit, buffer: buffer, boxed: false) serializeInt32(limit, buffer: buffer, boxed: false)
return (FunctionDescription(name: "stats.getMessagePublicForwards", parameters: [("channel", String(describing: channel)), ("msgId", String(describing: msgId)), ("offsetRate", String(describing: offsetRate)), ("offsetPeer", String(describing: offsetPeer)), ("offsetId", String(describing: offsetId)), ("limit", String(describing: limit))]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.messages.Messages? in return (FunctionDescription(name: "stats.getMessagePublicForwards", parameters: [("channel", String(describing: channel)), ("msgId", String(describing: msgId)), ("offset", String(describing: offset)), ("limit", String(describing: limit))]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.stats.PublicForwards? in
let reader = BufferReader(buffer) let reader = BufferReader(buffer)
var result: Api.messages.Messages? var result: Api.stats.PublicForwards?
if let signature = reader.readInt32() { if let signature = reader.readInt32() {
result = Api.parse(reader, signature: signature) as? Api.messages.Messages result = Api.parse(reader, signature: signature) as? Api.stats.PublicForwards
} }
return result return result
}) })

View File

@ -451,6 +451,8 @@ func mediaAreaFromApiMediaArea(_ mediaArea: Api.MediaArea) -> MediaArea? {
} }
} }
switch mediaArea { switch mediaArea {
case .inputMediaAreaChannelPost:
return nil
case .inputMediaAreaVenue: case .inputMediaAreaVenue:
return nil return nil
case let .mediaAreaGeoPoint(coordinates, geo): case let .mediaAreaGeoPoint(coordinates, geo):
@ -490,10 +492,12 @@ func mediaAreaFromApiMediaArea(_ mediaArea: Api.MediaArea) -> MediaArea? {
} else { } else {
return nil return nil
} }
case let .mediaAreaChannelPost(coordinates, channelId, messageId):
return .channelMessage(coordinates: coodinatesFromApiMediaAreaCoordinates(coordinates), messageId: EngineMessage.Id(peerId: PeerId(namespace: Namespaces.Peer.CloudChannel, id: PeerId.Id._internalFromInt64Value(channelId)), namespace: Namespaces.Message.Cloud, id: messageId))
} }
} }
func apiMediaAreasFromMediaAreas(_ mediaAreas: [MediaArea]) -> [Api.MediaArea] { func apiMediaAreasFromMediaAreas(_ mediaAreas: [MediaArea], transaction: Transaction) -> [Api.MediaArea] {
var apiMediaAreas: [Api.MediaArea] = [] var apiMediaAreas: [Api.MediaArea] = []
for area in mediaAreas { for area in mediaAreas {
let coordinates = area.coordinates let coordinates = area.coordinates
@ -516,6 +520,10 @@ func apiMediaAreasFromMediaAreas(_ mediaAreas: [MediaArea]) -> [Api.MediaArea] {
apiFlags |= (1 << 1) apiFlags |= (1 << 1)
} }
apiMediaAreas.append(.mediaAreaSuggestedReaction(flags: apiFlags, coordinates: inputCoordinates, reaction: reaction.apiReaction)) apiMediaAreas.append(.mediaAreaSuggestedReaction(flags: apiFlags, coordinates: inputCoordinates, reaction: reaction.apiReaction))
case let .channelMessage(_, messageId):
if let peer = transaction.getPeer(messageId.peerId), let inputChannel = apiInputChannel(peer) {
apiMediaAreas.append(.inputMediaAreaChannelPost(coordinates: inputCoordinates, channel: inputChannel, msgId: messageId.id))
}
} }
} }
return apiMediaAreas return apiMediaAreas

View File

@ -201,8 +201,7 @@ public final class StoryStatsContext {
private final class StoryStatsPublicForwardsContextImpl { private final class StoryStatsPublicForwardsContextImpl {
private let queue: Queue private let queue: Queue
private let account: Account private let account: Account
private let peerId: EnginePeer.Id private let subject: StoryStatsPublicForwardsContext.Subject
private let storyId: Int32
private let disposable = MetaDisposable() private let disposable = MetaDisposable()
private var isLoadingMore: Bool = false private var isLoadingMore: Bool = false
private var hasLoadedOnce: Bool = false private var hasLoadedOnce: Bool = false
@ -213,11 +212,10 @@ private final class StoryStatsPublicForwardsContextImpl {
let state = Promise<StoryStatsPublicForwardsContext.State>() let state = Promise<StoryStatsPublicForwardsContext.State>()
init(queue: Queue, account: Account, peerId: EnginePeer.Id, storyId: Int32) { init(queue: Queue, account: Account, subject: StoryStatsPublicForwardsContext.Subject) {
self.queue = queue self.queue = queue
self.account = account self.account = account
self.peerId = peerId self.subject = subject
self.storyId = storyId
self.count = 0 self.count = 0
@ -239,22 +237,41 @@ private final class StoryStatsPublicForwardsContextImpl {
self.isLoadingMore = true self.isLoadingMore = true
let account = self.account let account = self.account
let accountPeerId = account.peerId let accountPeerId = account.peerId
let peerId = self.peerId let subject = self.subject
let storyId = self.storyId
let lastOffset = self.lastOffset let lastOffset = self.lastOffset
self.disposable.set((self.account.postbox.transaction { transaction -> (Api.InputPeer, Int32?)? in self.disposable.set((self.account.postbox.transaction { transaction -> (Peer, Int32?)? in
let peerId: PeerId
switch subject {
case let .story(peerIdValue, _):
peerId = peerIdValue
case let .message(messageId):
peerId = messageId.peerId
}
let statsDatacenterId = (transaction.getPeerCachedData(peerId: peerId) as? CachedChannelData)?.statsDatacenterId let statsDatacenterId = (transaction.getPeerCachedData(peerId: peerId) as? CachedChannelData)?.statsDatacenterId
guard let inputPeer = transaction.getPeer(peerId).flatMap(apiInputPeer) else { guard let peer = transaction.getPeer(peerId) else {
return nil return nil
} }
return (inputPeer, statsDatacenterId) return (peer, statsDatacenterId)
} }
|> mapToSignal { data -> Signal<([StoryStatsPublicForwardsContext.State.Forward], Int32, String?), NoError> in |> mapToSignal { data -> Signal<([StoryStatsPublicForwardsContext.State.Forward], Int32, String?), NoError> in
if let (inputPeer, statsDatacenterId) = data { if let (peer, statsDatacenterId) = data {
let offset = lastOffset ?? "" let offset = lastOffset ?? ""
let request = Api.functions.stats.getStoryPublicForwards(peer: inputPeer, id: storyId, offset: offset, limit: 50) let request: (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.stats.PublicForwards>)
switch subject {
case let .story(_, id):
guard let inputPeer = apiInputPeer(peer) else {
return .complete()
}
request = Api.functions.stats.getStoryPublicForwards(peer: inputPeer, id: id, offset: offset, limit: 50)
case let .message(messageId):
guard let inputChannel = apiInputChannel(peer) else {
return .complete()
}
request = Api.functions.stats.getMessagePublicForwards(channel: inputChannel, msgId: messageId.id, offset: offset, limit: 50)
}
let signal: Signal<Api.stats.PublicForwards, MTRpcError> let signal: Signal<Api.stats.PublicForwards, MTRpcError>
if let statsDatacenterId = statsDatacenterId, account.network.datacenterId != statsDatacenterId { if let statsDatacenterId = statsDatacenterId, account.network.datacenterId != statsDatacenterId {
signal = account.network.download(datacenterId: Int(statsDatacenterId), isMedia: false, tag: nil) signal = account.network.download(datacenterId: Int(statsDatacenterId), isMedia: false, tag: nil)
@ -298,7 +315,6 @@ private final class StoryStatsPublicForwardsContextImpl {
resultForwards.append(.message(EngineMessage(renderedMessage))) resultForwards.append(.message(EngineMessage(renderedMessage)))
} }
case let .publicForwardStory(apiPeer, apiStory): case let .publicForwardStory(apiPeer, apiStory):
if let storedItem = Stories.StoredItem(apiStoryItem: apiStory, peerId: apiPeer.peerId, transaction: transaction), case let .item(item) = storedItem, let media = item.media, let peer = peers[apiPeer.peerId] { if let storedItem = Stories.StoredItem(apiStoryItem: apiStory, peerId: apiPeer.peerId, transaction: transaction), case let .item(item) = storedItem, let media = item.media, let peer = peers[apiPeer.peerId] {
let mappedItem = EngineStoryItem( let mappedItem = EngineStoryItem(
id: item.id, id: item.id,
@ -404,10 +420,15 @@ public final class StoryStatsPublicForwardsContext {
} }
} }
public init(account: Account, peerId: EnginePeer.Id, storyId: Int32) { public enum Subject {
case story(peerId: EnginePeer.Id, id: Int32)
case message(messageId: EngineMessage.Id)
}
public init(account: Account, subject: Subject) {
let queue = self.queue let queue = self.queue
self.impl = QueueLocalObject(queue: queue, generate: { self.impl = QueueLocalObject(queue: queue, generate: {
return StoryStatsPublicForwardsContextImpl(queue: queue, account: account, peerId: peerId, storyId: storyId) return StoryStatsPublicForwardsContextImpl(queue: queue, account: account, subject: subject)
}) })
} }

View File

@ -124,6 +124,7 @@ public enum MediaArea: Codable, Equatable {
case venue(coordinates: Coordinates, venue: Venue) case venue(coordinates: Coordinates, venue: Venue)
case reaction(coordinates: Coordinates, reaction: MessageReaction.Reaction, flags: ReactionFlags) case reaction(coordinates: Coordinates, reaction: MessageReaction.Reaction, flags: ReactionFlags)
case channelMessage(coordinates: Coordinates, messageId: EngineMessage.Id)
public struct ReactionFlags: OptionSet { public struct ReactionFlags: OptionSet {
public var rawValue: Int32 public var rawValue: Int32
@ -144,6 +145,7 @@ public enum MediaArea: Codable, Equatable {
private enum MediaAreaType: Int32 { private enum MediaAreaType: Int32 {
case venue case venue
case reaction case reaction
case channelMessage
} }
public enum DecodingError: Error { public enum DecodingError: Error {
@ -166,6 +168,10 @@ public enum MediaArea: Codable, Equatable {
let reaction = try container.decode(MessageReaction.Reaction.self, forKey: .value) let reaction = try container.decode(MessageReaction.Reaction.self, forKey: .value)
let flags = ReactionFlags(rawValue: try container.decodeIfPresent(Int32.self, forKey: .flags) ?? 0) let flags = ReactionFlags(rawValue: try container.decodeIfPresent(Int32.self, forKey: .flags) ?? 0)
self = .reaction(coordinates: coordinates, reaction: reaction, flags: flags) self = .reaction(coordinates: coordinates, reaction: reaction, flags: flags)
case .channelMessage:
let coordinates = try container.decode(MediaArea.Coordinates.self, forKey: .coordinates)
let messageId = try container.decode(MessageId.self, forKey: .value)
self = .channelMessage(coordinates: coordinates, messageId: messageId)
} }
} }
@ -182,6 +188,10 @@ public enum MediaArea: Codable, Equatable {
try container.encode(coordinates, forKey: .coordinates) try container.encode(coordinates, forKey: .coordinates)
try container.encode(reaction, forKey: .value) try container.encode(reaction, forKey: .value)
try container.encode(flags.rawValue, forKey: .flags) try container.encode(flags.rawValue, forKey: .flags)
case let .channelMessage(coordinates, messageId):
try container.encode(MediaAreaType.channelMessage.rawValue, forKey: .type)
try container.encode(coordinates, forKey: .coordinates)
try container.encode(messageId, forKey: .value)
} }
} }
} }
@ -193,6 +203,8 @@ public extension MediaArea {
return coordinates return coordinates
case let .reaction(coordinates, _, _): case let .reaction(coordinates, _, _):
return coordinates return coordinates
case let .channelMessage(coordinates, _):
return coordinates
} }
} }
} }

View File

@ -9,7 +9,6 @@ public enum SearchMessagesLocation: Equatable {
case general(tags: MessageTags?, minDate: Int32?, maxDate: Int32?) case general(tags: MessageTags?, minDate: Int32?, maxDate: Int32?)
case group(groupId: PeerGroupId, tags: MessageTags?, minDate: Int32?, maxDate: Int32?) case group(groupId: PeerGroupId, tags: MessageTags?, minDate: Int32?, maxDate: Int32?)
case peer(peerId: PeerId, fromId: PeerId?, tags: MessageTags?, topMsgId: MessageId?, minDate: Int32?, maxDate: Int32?) case peer(peerId: PeerId, fromId: PeerId?, tags: MessageTags?, topMsgId: MessageId?, minDate: Int32?, maxDate: Int32?)
case publicForwards(messageId: MessageId)
case sentMedia(tags: MessageTags?) case sentMedia(tags: MessageTags?)
} }
@ -354,46 +353,6 @@ func _internal_searchMessages(account: Account, location: SearchMessagesLocation
return .single((nil, nil)) return .single((nil, nil))
} }
} }
case let .publicForwards(messageId):
remoteSearchResult = account.postbox.transaction { transaction -> (Api.InputChannel?, Int32, MessageIndex?, Api.InputPeer, Int32?) in
let sourcePeer = transaction.getPeer(messageId.peerId)
let inputChannel = sourcePeer.flatMap { apiInputChannel($0) }
let statsDatacenterId = (transaction.getPeerCachedData(peerId: messageId.peerId) as? CachedChannelData)?.statsDatacenterId
var lowerBound: MessageIndex?
if let state = state, let message = state.main.messages.last {
lowerBound = message.index
}
if let lowerBound = lowerBound, let peer = transaction.getPeer(lowerBound.id.peerId), let inputPeer = apiInputPeer(peer) {
return (inputChannel, state?.main.nextRate ?? 0, lowerBound, inputPeer, statsDatacenterId)
} else {
return (inputChannel, 0, lowerBound, .inputPeerEmpty, statsDatacenterId)
}
}
|> mapToSignal { (inputChannel, nextRate, lowerBound, inputPeer, statsDatacenterId) in
guard let inputChannel = inputChannel else {
return .complete()
}
let request = Api.functions.stats.getMessagePublicForwards(channel: inputChannel, msgId: messageId.id, offsetRate: nextRate, offsetPeer: inputPeer, offsetId: lowerBound?.id.id ?? 0, limit: limit)
let signal: Signal<Api.messages.Messages, MTRpcError>
if let statsDatacenterId = statsDatacenterId, account.network.datacenterId != statsDatacenterId {
signal = account.network.download(datacenterId: Int(statsDatacenterId), isMedia: false, tag: nil)
|> castError(MTRpcError.self)
|> mapToSignal { worker in
return worker.request(request)
}
} else {
signal = account.network.request(request, automaticFloodWait: false)
}
return signal
|> map { result -> (Api.messages.Messages?, Api.messages.Messages?) in
return (result, nil)
}
|> `catch` { _ -> Signal<(Api.messages.Messages?, Api.messages.Messages?), NoError> in
return .single((nil, nil))
}
}
case let .sentMedia(tags): case let .sentMedia(tags):
let filter: Api.MessagesFilter = tags.flatMap { messageFilterForTagMask($0) } ?? .inputMessagesFilterEmpty let filter: Api.MessagesFilter = tags.flatMap { messageFilterForTagMask($0) } ?? .inputMessagesFilterEmpty

View File

@ -1092,7 +1092,7 @@ func _internal_uploadStoryImpl(
flags |= 1 << 4 flags |= 1 << 4
} }
let inputMediaAreas: [Api.MediaArea] = apiMediaAreasFromMediaAreas(mediaAreas) let inputMediaAreas: [Api.MediaArea] = apiMediaAreasFromMediaAreas(mediaAreas, transaction: transaction)
if !inputMediaAreas.isEmpty { if !inputMediaAreas.isEmpty {
flags |= 1 << 5 flags |= 1 << 5
} }
@ -1281,7 +1281,7 @@ func _internal_editStory(account: Account, peerId: PeerId, id: Int32, media: Eng
flags |= 1 << 2 flags |= 1 << 2
} }
let inputMediaAreas: [Api.MediaArea]? = mediaAreas.flatMap(apiMediaAreasFromMediaAreas) let inputMediaAreas: [Api.MediaArea]? = mediaAreas.flatMap { apiMediaAreasFromMediaAreas($0, transaction: transaction) }
if let inputMediaAreas = inputMediaAreas, !inputMediaAreas.isEmpty { if let inputMediaAreas = inputMediaAreas, !inputMediaAreas.isEmpty {
flags |= 1 << 3 flags |= 1 << 3
} }

View File

@ -1,4 +1,5 @@
import Foundation import Foundation
import Postbox
import MtProtoKit import MtProtoKit
import SwiftSignalKit import SwiftSignalKit
import TelegramApi import TelegramApi
@ -138,13 +139,19 @@ func _internal_getPremiumGiveawayInfo(account: Account, peerId: EnginePeer.Id, m
} }
} }
func _internal_premiumGiftCodeOptions(account: Account, peerId: EnginePeer.Id) -> Signal<[PremiumGiftCodeOption], NoError> { func _internal_premiumGiftCodeOptions(account: Account, peerId: EnginePeer.Id?) -> Signal<[PremiumGiftCodeOption], NoError> {
let flags: Int32 = 1 << 0 var flags: Int32 = 0
return account.postbox.loadedPeerWithId(peerId) if let _ = peerId {
|> mapToSignal { peer in flags |= 1 << 0
guard let inputPeer = apiInputPeer(peer) else { }
return .complete() return account.postbox.transaction { transaction -> Peer? in
if let peerId = peerId {
return transaction.getPeer(peerId)
} }
return nil
}
|> mapToSignal { peer in
let inputPeer = peer.flatMap(apiInputPeer)
return account.network.request(Api.functions.payments.getPremiumGiftCodeOptions(flags: flags, boostPeer: inputPeer)) return account.network.request(Api.functions.payments.getPremiumGiftCodeOptions(flags: flags, boostPeer: inputPeer))
|> map(Optional.init) |> map(Optional.init)
|> `catch` { _ -> Signal<[Api.PremiumGiftCodeOption]?, NoError> in |> `catch` { _ -> Signal<[Api.PremiumGiftCodeOption]?, NoError> in

View File

@ -54,7 +54,7 @@ public extension TelegramEngine {
return _internal_applyPremiumGiftCode(account: self.account, slug: slug) return _internal_applyPremiumGiftCode(account: self.account, slug: slug)
} }
public func premiumGiftCodeOptions(peerId: EnginePeer.Id) -> Signal<[PremiumGiftCodeOption], NoError> { public func premiumGiftCodeOptions(peerId: EnginePeer.Id?) -> Signal<[PremiumGiftCodeOption], NoError> {
return _internal_premiumGiftCodeOptions(account: self.account, peerId: peerId) return _internal_premiumGiftCodeOptions(account: self.account, peerId: peerId)
} }

View File

@ -3273,12 +3273,12 @@ final class StoryItemSetContainerSendMessage {
let theme = defaultDarkColorPresentationTheme let theme = defaultDarkColorPresentationTheme
let updatedPresentationData: (initial: PresentationData, signal: Signal<PresentationData, NoError>) = (component.context.sharedContext.currentPresentationData.with({ $0 }).withUpdated(theme: theme), component.context.sharedContext.presentationData |> map { $0.withUpdated(theme: theme) }) let updatedPresentationData: (initial: PresentationData, signal: Signal<PresentationData, NoError>) = (component.context.sharedContext.currentPresentationData.with({ $0 }).withUpdated(theme: theme), component.context.sharedContext.presentationData |> map { $0.withUpdated(theme: theme) })
let context = component.context
var actions: [ContextMenuAction] = [] var actions: [ContextMenuAction] = []
switch mediaArea { switch mediaArea {
case let .venue(_, venue): case let .venue(_, venue):
let subject = EngineMessage(stableId: 0, stableVersion: 0, id: EngineMessage.Id(peerId: PeerId(0), namespace: 0, id: 0), globallyUniqueId: nil, groupingKey: nil, groupInfo: nil, threadId: nil, timestamp: 0, flags: [], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: nil, text: "", attributes: [], media: [.geo(TelegramMediaMap(latitude: venue.latitude, longitude: venue.longitude, heading: nil, accuracyRadius: nil, geoPlace: nil, venue: venue.venue, liveBroadcastingTimeout: nil, liveProximityNotificationRadius: nil))], peers: [:], associatedMessages: [:], associatedMessageIds: [], associatedMedia: [:], associatedThreadInfo: nil, associatedStories: [:]) let subject = EngineMessage(stableId: 0, stableVersion: 0, id: EngineMessage.Id(peerId: PeerId(0), namespace: 0, id: 0), globallyUniqueId: nil, groupingKey: nil, groupInfo: nil, threadId: nil, timestamp: 0, flags: [], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: nil, text: "", attributes: [], media: [.geo(TelegramMediaMap(latitude: venue.latitude, longitude: venue.longitude, heading: nil, accuracyRadius: nil, geoPlace: nil, venue: venue.venue, liveBroadcastingTimeout: nil, liveProximityNotificationRadius: nil))], peers: [:], associatedMessages: [:], associatedMessageIds: [], associatedMedia: [:], associatedThreadInfo: nil, associatedStories: [:])
let context = component.context
actions.append(ContextMenuAction(content: .textWithIcon(title: updatedPresentationData.initial.strings.Story_ViewLocation, icon: generateTintedImage(image: UIImage(bundleImageName: "Settings/TextArrowRight"), color: .white)), action: { [weak controller, weak view] in actions.append(ContextMenuAction(content: .textWithIcon(title: updatedPresentationData.initial.strings.Story_ViewLocation, icon: generateTintedImage(image: UIImage(bundleImageName: "Settings/TextArrowRight"), color: .white)), action: { [weak controller, weak view] in
let locationController = LocationViewController( let locationController = LocationViewController(
context: context, context: context,
@ -3303,6 +3303,34 @@ final class StoryItemSetContainerSendMessage {
} }
controller?.push(locationController) controller?.push(locationController)
})) }))
case let .channelMessage(_, messageId):
actions.append(ContextMenuAction(content: .textWithIcon(title: updatedPresentationData.initial.strings.Story_ViewMessage, icon: generateTintedImage(image: UIImage(bundleImageName: "Settings/TextArrowRight"), color: .white)), action: { [weak controller] in
let _ = ((context.engine.messages.getMessagesLoadIfNecessary([messageId], strategy: .local)
|> mapToSignal { result -> Signal<Message?, NoError> in
if case let .result(messages) = result {
return .single(messages.first)
}
return .single(nil)
})
|> deliverOnMainQueue).startStandalone(next: { [weak controller] message in
guard let controller, let message else {
return
}
let _ = context.sharedContext.openChatMessage(OpenChatMessageParams(context: context, chatLocation: .peer(id: message.id.peerId), chatLocationContextHolder: nil, message: message, standalone: false, reverseMessageGalleryOrder: false, navigationController: controller.navigationController as? NavigationController, dismissInput: {}, present: { [weak controller] c, a in
controller?.present(c, in: .window(.root))
}, transitionNode: { _, _, _ in
return nil
}, addToTransitionSurface: { _ in
}, openUrl: { _ in
}, openPeer: { _, _ in
}, callPeer: { _, _ in
}, enqueueMessage: { _ in
}, sendSticker: nil, sendEmoji: nil, setupTemporaryHiddenMedia: { _, _, _ in
}, chatAvatarHiddenMedia: { _, _ in
}))
})
}))
case .reaction: case .reaction:
return return
} }