[WIP] Stories

This commit is contained in:
Ali
2023-05-25 13:55:29 +04:00
parent 39963f3a6c
commit 00b62b3e58
33 changed files with 990 additions and 2095 deletions

View File

@@ -63,7 +63,15 @@ public enum RequestWebViewError {
private func keepWebViewSignal(network: Network, stateManager: AccountStateManager, flags: Int32, peer: Api.InputPeer, bot: Api.InputUser, queryId: Int64, replyToMessageId: MessageId?, threadId: Int64?, sendAs: Api.InputPeer?) -> Signal<Never, KeepWebViewError> {
let signal = Signal<Never, KeepWebViewError> { subscriber in
let poll = Signal<Never, KeepWebViewError> { subscriber in
let signal: Signal<Never, KeepWebViewError> = network.request(Api.functions.messages.prolongWebView(flags: flags, peer: peer, bot: bot, queryId: queryId, replyToMsgId: replyToMessageId?.id, topMsgId: threadId.flatMap(Int32.init(clamping:)), sendAs: sendAs))
var replyTo: Api.InputReplyTo?
if let replyToMessageId = replyToMessageId {
var replyFlags: Int32 = 0
if threadId != nil {
replyFlags |= 1 << 0
}
replyTo = .inputReplyToMessage(flags: replyFlags, replyToMsgId: replyToMessageId.id, topMsgId: threadId.flatMap(Int32.init(clamping:)))
}
let signal: Signal<Never, KeepWebViewError> = network.request(Api.functions.messages.prolongWebView(flags: flags, peer: peer, bot: bot, queryId: queryId, replyTo: replyTo, sendAs: sendAs))
|> mapError { _ -> KeepWebViewError in
return .generic
}
@@ -120,22 +128,25 @@ func _internal_requestWebView(postbox: Postbox, network: Network, stateManager:
if let _ = serializedThemeParams {
flags |= (1 << 2)
}
var replyToMsgId: Int32?
if let replyToMessageId = replyToMessageId {
flags |= (1 << 0)
replyToMsgId = replyToMessageId.id
}
if let _ = payload {
flags |= (1 << 3)
}
if fromMenu {
flags |= (1 << 4)
}
if threadId != nil {
flags |= (1 << 9)
var replyTo: Api.InputReplyTo?
if let replyToMessageId = replyToMessageId {
flags |= (1 << 0)
var replyFlags: Int32 = 0
if threadId != nil {
replyFlags |= 1 << 0
}
replyTo = .inputReplyToMessage(flags: replyFlags, replyToMsgId: replyToMessageId.id, topMsgId: threadId.flatMap(Int32.init(clamping:)))
}
return network.request(Api.functions.messages.requestWebView(flags: flags, peer: inputPeer, bot: inputBot, url: url, startParam: payload, themeParams: serializedThemeParams, platform: botWebViewPlatform, replyToMsgId: replyToMsgId, topMsgId: threadId.flatMap(Int32.init(clamping:)), sendAs: nil))
return network.request(Api.functions.messages.requestWebView(flags: flags, peer: inputPeer, bot: inputBot, url: url, startParam: payload, themeParams: serializedThemeParams, platform: botWebViewPlatform, replyTo: replyTo, sendAs: nil))
|> mapError { _ -> RequestWebViewError in
return .generic
}

View File

@@ -704,8 +704,12 @@ extension Api.StoryItem {
extension Stories.Item.Views {
init(apiViews: Api.StoryViews) {
switch apiViews {
case let .storyViews(recentViewers, viewsCount):
self.init(seenCount: Int(viewsCount), seenPeerIds: recentViewers.map { PeerId(namespace: Namespaces.Peer.CloudUser, id: PeerId.Id._internalFromInt64Value($0)) })
case let .storyViews(_, viewsCount, recentViewers):
var seenPeerIds: [PeerId] = []
if let recentViewers = recentViewers {
seenPeerIds = recentViewers.map { PeerId(namespace: Namespaces.Peer.CloudUser, id: PeerId.Id._internalFromInt64Value($0)) }
}
self.init(seenCount: Int(viewsCount), seenPeerIds: seenPeerIds)
}
}
}
@@ -769,69 +773,42 @@ extension Stories.StoredItem {
}
}
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 .storyItemSkipped:
return nil
case .storyItemDeleted:
return nil
func _internal_getStoriesById(accountPeerId: PeerId, postbox: Postbox, network: Network, peer: PeerReference, ids: [Int32]) -> Signal<[Stories.StoredItem], NoError> {
guard let inputUser = peer.inputUser else {
return .single([])
}
}
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)
})
return network.request(Api.functions.stories.getStoriesByID(userId: inputUser, id: ids))
|> map(Optional.init)
|> `catch` { _ -> Signal<Api.stories.Stories?, NoError> in
return .single(nil)
}
|> mapToSignal { result -> Signal<[Stories.StoredItem], NoError> in
guard let result = result else {
return .single([])
}
return postbox.transaction { transaction -> [Stories.StoredItem] 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.compactMap { apiStoryItem -> Stories.StoredItem? in
return Stories.StoredItem(apiStoryItem: apiStoryItem, peerId: peer.id, transaction: transaction)
}
}
}
}
}
@@ -879,42 +856,6 @@ func _internal_getStoriesById(accountPeerId: PeerId, postbox: Postbox, network:
}
}
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 = 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
@@ -978,18 +919,18 @@ func _internal_getStoryViewList(account: Account, id: Int32, offsetTimestamp: In
}
}
func _internal_getStoryViews(account: Account, ids: [Int32]) -> Signal<[Int32: StoryListContext.Views], NoError> {
func _internal_getStoryViews(account: Account, ids: [Int32]) -> Signal<[Int32: Stories.Item.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
|> mapToSignal { result -> Signal<[Int32: Stories.Item.Views], NoError> in
guard let result = result else {
return .single([:])
}
return account.postbox.transaction { transaction -> [Int32: StoryListContext.Views] in
var parsedViews: [Int32: StoryListContext.Views] = [:]
return account.postbox.transaction { transaction -> [Int32: Stories.Item.Views] in
var parsedViews: [Int32: Stories.Item.Views] = [:]
switch result {
case let .storyViews(views, users):
var peers: [Peer] = []
@@ -1008,7 +949,7 @@ func _internal_getStoryViews(account: Account, ids: [Int32]) -> Signal<[Int32: S
for i in 0 ..< views.count {
if i < ids.count {
parsedViews[ids[i]] = _internal_parseApiStoryViews(transaction: transaction, views: views[i])
parsedViews[ids[i]] = Stories.Item.Views(apiViews: views[i])
}
}
}

View File

@@ -774,7 +774,7 @@ public extension TelegramEngine {
let resource = MediaResourceReference.media(media: .story(peer: peerReference, id: item.id, media: file), resource: file.resource)
resultResources[EngineMediaResource.Id(resource.resource.id)] = StoryPreloadInfo(
resource: resource,
size: nil,
size: file.preloadSize,
priority: .top(position: nextPriority)
)
nextPriority += 1
@@ -788,10 +788,6 @@ public extension TelegramEngine {
}
}
public func peerStoryFocusContext(id: EnginePeer.Id, focusItemId: Int32?) -> PeerStoryFocusContext {
return PeerStoryFocusContext(account: self.account, peerId: id, focusItemId: focusItemId)
}
public func refreshStories(peerId: EnginePeer.Id, ids: [Int32]) -> Signal<Never, NoError> {
return _internal_getStoriesById(accountPeerId: self.account.peerId, postbox: self.account.postbox, network: self.account.network, peerId: peerId, ids: ids)
|> mapToSignal { result -> Signal<Never, NoError> in
@@ -812,10 +808,6 @@ public extension TelegramEngine {
}
}
public func peerStories(id: EnginePeer.Id) -> StoryListContext {
return StoryListContext(account: self.account, scope: .peer(id))
}
public func uploadStory(media: EngineStoryInputMedia, text: String, entities: [MessageTextEntity], privacy: EngineStoryPrivacy) -> Signal<Never, NoError> {
return _internal_uploadStory(account: self.account, media: media, text: text, entities: entities, privacy: privacy)
}