mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-12-24 07:05:35 +00:00
Merge branch 'master' of gitlab.com:peter-iakovlev/telegram-ios
This commit is contained in:
@@ -41,14 +41,17 @@ public enum Stories {
|
||||
public struct Views: Codable, Equatable {
|
||||
private enum CodingKeys: String, CodingKey {
|
||||
case seenCount = "seenCount"
|
||||
case reactedCount = "reactedCount"
|
||||
case seenPeerIds = "seenPeerIds"
|
||||
}
|
||||
|
||||
public var seenCount: Int
|
||||
public var reactedCount: Int
|
||||
public var seenPeerIds: [PeerId]
|
||||
|
||||
public init(seenCount: Int, seenPeerIds: [PeerId]) {
|
||||
public init(seenCount: Int, reactedCount: Int, seenPeerIds: [PeerId]) {
|
||||
self.seenCount = seenCount
|
||||
self.reactedCount = reactedCount
|
||||
self.seenPeerIds = seenPeerIds
|
||||
}
|
||||
|
||||
@@ -56,6 +59,7 @@ public enum Stories {
|
||||
let container = try decoder.container(keyedBy: CodingKeys.self)
|
||||
|
||||
self.seenCount = Int(try container.decode(Int32.self, forKey: .seenCount))
|
||||
self.reactedCount = Int(try container.decodeIfPresent(Int32.self, forKey: .reactedCount) ?? 0)
|
||||
self.seenPeerIds = try container.decode([Int64].self, forKey: .seenPeerIds).map(PeerId.init)
|
||||
}
|
||||
|
||||
@@ -63,6 +67,7 @@ public enum Stories {
|
||||
var container = encoder.container(keyedBy: CodingKeys.self)
|
||||
|
||||
try container.encode(Int32(clamping: self.seenCount), forKey: .seenCount)
|
||||
try container.encode(Int32(clamping: self.reactedCount), forKey: .reactedCount)
|
||||
try container.encode(self.seenPeerIds.map { $0.toInt64() }, forKey: .seenPeerIds)
|
||||
}
|
||||
}
|
||||
@@ -137,7 +142,7 @@ public enum Stories {
|
||||
case isSelectedContacts
|
||||
case isForwardingDisabled
|
||||
case isEdited
|
||||
case hasLike
|
||||
case myReaction
|
||||
}
|
||||
|
||||
public let id: Int32
|
||||
@@ -157,7 +162,7 @@ public enum Stories {
|
||||
public let isSelectedContacts: Bool
|
||||
public let isForwardingDisabled: Bool
|
||||
public let isEdited: Bool
|
||||
public let hasLike: Bool
|
||||
public let myReaction: MessageReaction.Reaction?
|
||||
|
||||
public init(
|
||||
id: Int32,
|
||||
@@ -177,7 +182,7 @@ public enum Stories {
|
||||
isSelectedContacts: Bool,
|
||||
isForwardingDisabled: Bool,
|
||||
isEdited: Bool,
|
||||
hasLike: Bool
|
||||
myReaction: MessageReaction.Reaction?
|
||||
) {
|
||||
self.id = id
|
||||
self.timestamp = timestamp
|
||||
@@ -196,7 +201,7 @@ public enum Stories {
|
||||
self.isSelectedContacts = isSelectedContacts
|
||||
self.isForwardingDisabled = isForwardingDisabled
|
||||
self.isEdited = isEdited
|
||||
self.hasLike = hasLike
|
||||
self.myReaction = myReaction
|
||||
}
|
||||
|
||||
public init(from decoder: Decoder) throws {
|
||||
@@ -225,7 +230,7 @@ public enum Stories {
|
||||
self.isSelectedContacts = try container.decodeIfPresent(Bool.self, forKey: .isSelectedContacts) ?? false
|
||||
self.isForwardingDisabled = try container.decodeIfPresent(Bool.self, forKey: .isForwardingDisabled) ?? false
|
||||
self.isEdited = try container.decodeIfPresent(Bool.self, forKey: .isEdited) ?? false
|
||||
self.hasLike = try container.decodeIfPresent(Bool.self, forKey: .hasLike) ?? false
|
||||
self.myReaction = try container.decodeIfPresent(MessageReaction.Reaction.self, forKey: .myReaction)
|
||||
}
|
||||
|
||||
public func encode(to encoder: Encoder) throws {
|
||||
@@ -255,7 +260,7 @@ public enum Stories {
|
||||
try container.encode(self.isSelectedContacts, forKey: .isSelectedContacts)
|
||||
try container.encode(self.isForwardingDisabled, forKey: .isForwardingDisabled)
|
||||
try container.encode(self.isEdited, forKey: .isEdited)
|
||||
try container.encode(self.hasLike, forKey: .hasLike)
|
||||
try container.encodeIfPresent(self.myReaction, forKey: .myReaction)
|
||||
}
|
||||
|
||||
public static func ==(lhs: Item, rhs: Item) -> Bool {
|
||||
@@ -317,7 +322,7 @@ public enum Stories {
|
||||
if lhs.isEdited != rhs.isEdited {
|
||||
return false
|
||||
}
|
||||
if lhs.hasLike != rhs.hasLike {
|
||||
if lhs.myReaction != rhs.myReaction {
|
||||
return false
|
||||
}
|
||||
|
||||
@@ -949,7 +954,7 @@ func _internal_uploadStoryImpl(postbox: Postbox, network: Network, accountPeerId
|
||||
for update in updates.allUpdates {
|
||||
if case let .updateStory(_, story) = update {
|
||||
switch story {
|
||||
case let .storyItem(_, idValue, _, _, _, _, media, _, _, _):
|
||||
case let .storyItem(_, idValue, _, _, _, _, media, _, _, _, _):
|
||||
if let parsedStory = Stories.StoredItem(apiStoryItem: story, peerId: accountPeerId, transaction: transaction) {
|
||||
var items = transaction.getStoryItems(peerId: accountPeerId)
|
||||
var updatedItems: [Stories.Item] = []
|
||||
@@ -972,7 +977,7 @@ func _internal_uploadStoryImpl(postbox: Postbox, network: Network, accountPeerId
|
||||
isSelectedContacts: item.isSelectedContacts,
|
||||
isForwardingDisabled: item.isForwardingDisabled,
|
||||
isEdited: item.isEdited,
|
||||
hasLike: item.hasLike
|
||||
myReaction: item.myReaction
|
||||
)
|
||||
if let entry = CodableEntry(Stories.StoredItem.item(updatedItem)) {
|
||||
items.append(StoryItemsTableEntry(value: entry, id: item.id, expirationTimestamp: updatedItem.expirationTimestamp, isCloseFriends: updatedItem.isCloseFriends))
|
||||
@@ -1094,7 +1099,7 @@ func _internal_editStory(account: Account, id: Int32, media: EngineStoryInputMed
|
||||
for update in updates.allUpdates {
|
||||
if case let .updateStory(_, story) = update {
|
||||
switch story {
|
||||
case let .storyItem(_, _, _, _, _, _, media, _, _, _):
|
||||
case let .storyItem(_, _, _, _, _, _, media, _, _, _, _):
|
||||
let (parsedMedia, _, _, _) = textMediaAndExpirationTimerFromApiMedia(media, account.peerId)
|
||||
if let parsedMedia = parsedMedia, let originalMedia = originalMedia {
|
||||
applyMediaResourceChanges(from: originalMedia, to: parsedMedia, postbox: account.postbox, force: false)
|
||||
@@ -1136,7 +1141,7 @@ func _internal_editStoryPrivacy(account: Account, id: Int32, privacy: EngineStor
|
||||
isSelectedContacts: item.isSelectedContacts,
|
||||
isForwardingDisabled: item.isForwardingDisabled,
|
||||
isEdited: item.isEdited,
|
||||
hasLike: item.hasLike
|
||||
myReaction: item.myReaction
|
||||
)
|
||||
if let entry = CodableEntry(Stories.StoredItem.item(updatedItem)) {
|
||||
transaction.setStory(id: storyId, value: entry)
|
||||
@@ -1164,7 +1169,7 @@ func _internal_editStoryPrivacy(account: Account, id: Int32, privacy: EngineStor
|
||||
isSelectedContacts: item.isSelectedContacts,
|
||||
isForwardingDisabled: item.isForwardingDisabled,
|
||||
isEdited: item.isEdited,
|
||||
hasLike: item.hasLike
|
||||
myReaction: item.myReaction
|
||||
)
|
||||
if let entry = CodableEntry(Stories.StoredItem.item(updatedItem)) {
|
||||
items[index] = StoryItemsTableEntry(value: entry, id: item.id, expirationTimestamp: updatedItem.expirationTimestamp, isCloseFriends: updatedItem.isCloseFriends)
|
||||
@@ -1292,7 +1297,7 @@ func _internal_updateStoriesArePinned(account: Account, ids: [Int32: EngineStory
|
||||
isSelectedContacts: item.isSelectedContacts,
|
||||
isForwardingDisabled: item.isForwardingDisabled,
|
||||
isEdited: item.isEdited,
|
||||
hasLike: item.hasLike
|
||||
myReaction: item.myReaction
|
||||
)
|
||||
if let entry = CodableEntry(Stories.StoredItem.item(updatedItem)) {
|
||||
items[index] = StoryItemsTableEntry(value: entry, id: item.id, expirationTimestamp: updatedItem.expirationTimestamp, isCloseFriends: updatedItem.isCloseFriends)
|
||||
@@ -1319,7 +1324,7 @@ func _internal_updateStoriesArePinned(account: Account, ids: [Int32: EngineStory
|
||||
isSelectedContacts: item.isSelectedContacts,
|
||||
isForwardingDisabled: item.isForwardingDisabled,
|
||||
isEdited: item.isEdited,
|
||||
hasLike: item.hasLike
|
||||
myReaction: item.myReaction
|
||||
)
|
||||
updatedItems.append(updatedItem)
|
||||
}
|
||||
@@ -1345,7 +1350,7 @@ func _internal_updateStoriesArePinned(account: Account, ids: [Int32: EngineStory
|
||||
extension Api.StoryItem {
|
||||
var id: Int32 {
|
||||
switch self {
|
||||
case let .storyItem(_, id, _, _, _, _, _, _, _, _):
|
||||
case let .storyItem(_, id, _, _, _, _, _, _, _, _, _):
|
||||
return id
|
||||
case let .storyItemDeleted(id):
|
||||
return id
|
||||
@@ -1358,12 +1363,12 @@ extension Api.StoryItem {
|
||||
extension Stories.Item.Views {
|
||||
init(apiViews: Api.StoryViews) {
|
||||
switch apiViews {
|
||||
case let .storyViews(_, viewsCount, recentViewers):
|
||||
case let .storyViews(_, viewsCount, reactionsCount, 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)
|
||||
self.init(seenCount: Int(viewsCount), reactedCount: Int(reactionsCount), seenPeerIds: seenPeerIds)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1371,7 +1376,7 @@ extension Stories.Item.Views {
|
||||
extension Stories.StoredItem {
|
||||
init?(apiStoryItem: Api.StoryItem, existingItem: Stories.Item? = nil, peerId: PeerId, transaction: Transaction) {
|
||||
switch apiStoryItem {
|
||||
case let .storyItem(flags, id, date, expireDate, caption, entities, media, mediaAreas, privacy, views):
|
||||
case let .storyItem(flags, id, date, expireDate, caption, entities, media, mediaAreas, privacy, views, sentReaction):
|
||||
let (parsedMedia, _, _, _) = textMediaAndExpirationTimerFromApiMedia(media, peerId)
|
||||
if let parsedMedia = parsedMedia {
|
||||
var parsedPrivacy: Stories.Item.Privacy?
|
||||
@@ -1428,6 +1433,13 @@ extension Stories.StoredItem {
|
||||
mergedViews = views.flatMap(Stories.Item.Views.init(apiViews:))
|
||||
}
|
||||
|
||||
var mergedMyReaction: MessageReaction.Reaction?
|
||||
if isMin, let existingItem = existingItem {
|
||||
mergedMyReaction = existingItem.myReaction
|
||||
} else {
|
||||
mergedMyReaction = sentReaction.flatMap(MessageReaction.Reaction.init(apiReaction:))
|
||||
}
|
||||
|
||||
let item = Stories.Item(
|
||||
id: id,
|
||||
timestamp: date,
|
||||
@@ -1446,7 +1458,7 @@ extension Stories.StoredItem {
|
||||
isSelectedContacts: isSelectedContacts,
|
||||
isForwardingDisabled: isForwardingDisabled,
|
||||
isEdited: isEdited,
|
||||
hasLike: false
|
||||
myReaction: mergedMyReaction
|
||||
)
|
||||
self = .item(item)
|
||||
} else {
|
||||
@@ -1533,42 +1545,12 @@ public final class StoryViewList {
|
||||
|
||||
public let items: [Item]
|
||||
public let totalCount: Int
|
||||
public let totalReactedCount: Int
|
||||
|
||||
public init(items: [Item], totalCount: Int) {
|
||||
public init(items: [Item], totalCount: Int, totalReactedCount: Int) {
|
||||
self.items = items
|
||||
self.totalCount = totalCount
|
||||
}
|
||||
}
|
||||
|
||||
func _internal_getStoryViewList(account: Account, id: Int32, offsetTimestamp: Int32?, offsetPeerId: PeerId?, limit: Int) -> Signal<StoryViewList?, NoError> {
|
||||
let accountPeerId = account.peerId
|
||||
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 = result else {
|
||||
return .single(nil)
|
||||
}
|
||||
return account.postbox.transaction { transaction -> StoryViewList? in
|
||||
switch result {
|
||||
case let .storyViewsList(count, views, users):
|
||||
updatePeers(transaction: transaction, accountPeerId: accountPeerId, peers: AccumulatedPeers(users: users))
|
||||
|
||||
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))
|
||||
}
|
||||
}
|
||||
self.totalReactedCount = totalReactedCount
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1603,26 +1585,28 @@ func _internal_getStoryViews(account: Account, ids: [Int32]) -> Signal<[Int32: S
|
||||
|
||||
public final class EngineStoryViewListContext {
|
||||
public struct LoadMoreToken: Equatable {
|
||||
var id: Int64
|
||||
var timestamp: Int32
|
||||
var value: String
|
||||
}
|
||||
|
||||
public final class Item: Equatable {
|
||||
public let peer: EnginePeer
|
||||
public let timestamp: Int32
|
||||
public let storyStats: PeerStoryStats?
|
||||
public let isLike: Bool
|
||||
public let reaction: MessageReaction.Reaction?
|
||||
public let reactionFile: TelegramMediaFile?
|
||||
|
||||
public init(
|
||||
peer: EnginePeer,
|
||||
timestamp: Int32,
|
||||
storyStats: PeerStoryStats?,
|
||||
isLike: Bool
|
||||
reaction: MessageReaction.Reaction?,
|
||||
reactionFile: TelegramMediaFile?
|
||||
) {
|
||||
self.peer = peer
|
||||
self.timestamp = timestamp
|
||||
self.storyStats = storyStats
|
||||
self.isLike = isLike
|
||||
self.reaction = reaction
|
||||
self.reactionFile = reactionFile
|
||||
}
|
||||
|
||||
public static func ==(lhs: Item, rhs: Item) -> Bool {
|
||||
@@ -1635,7 +1619,10 @@ public final class EngineStoryViewListContext {
|
||||
if lhs.storyStats != rhs.storyStats {
|
||||
return false
|
||||
}
|
||||
if lhs.isLike != rhs.isLike {
|
||||
if lhs.reaction != rhs.reaction {
|
||||
return false
|
||||
}
|
||||
if lhs.reactionFile?.fileId != rhs.reactionFile?.fileId {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
@@ -1644,15 +1631,18 @@ public final class EngineStoryViewListContext {
|
||||
|
||||
public struct State: Equatable {
|
||||
public var totalCount: Int
|
||||
public var totalReactedCount: Int
|
||||
public var items: [Item]
|
||||
public var loadMoreToken: LoadMoreToken?
|
||||
|
||||
public init(
|
||||
totalCount: Int,
|
||||
totalReactedCount: Int,
|
||||
items: [Item],
|
||||
loadMoreToken: LoadMoreToken?
|
||||
) {
|
||||
self.totalCount = totalCount
|
||||
self.totalReactedCount = totalReactedCount
|
||||
self.items = items
|
||||
self.loadMoreToken = loadMoreToken
|
||||
}
|
||||
@@ -1660,12 +1650,12 @@ public final class EngineStoryViewListContext {
|
||||
|
||||
private final class Impl {
|
||||
struct NextOffset: Equatable {
|
||||
var id: Int64
|
||||
var timestamp: Int32
|
||||
var value: String
|
||||
}
|
||||
|
||||
struct InternalState: Equatable {
|
||||
var totalCount: Int
|
||||
var totalReactedCount: Int
|
||||
var items: [Item]
|
||||
var canLoadMore: Bool
|
||||
var nextOffset: NextOffset?
|
||||
@@ -1689,8 +1679,8 @@ public final class EngineStoryViewListContext {
|
||||
self.account = account
|
||||
self.storyId = storyId
|
||||
|
||||
let initialState = State(totalCount: views.seenCount, items: [], loadMoreToken: LoadMoreToken(id: 0, timestamp: 0))
|
||||
self.state = InternalState(totalCount: initialState.totalCount, items: initialState.items, canLoadMore: initialState.loadMoreToken != nil, nextOffset: nil)
|
||||
let initialState = State(totalCount: views.seenCount, totalReactedCount: views.reactedCount, items: [], loadMoreToken: LoadMoreToken(value: ""))
|
||||
self.state = InternalState(totalCount: initialState.totalCount, totalReactedCount: initialState.totalReactedCount, items: initialState.items, canLoadMore: initialState.loadMoreToken != nil, nextOffset: nil)
|
||||
self.statePromise.set(.single(self.state))
|
||||
|
||||
if initialState.loadMoreToken != nil {
|
||||
@@ -1722,7 +1712,7 @@ public final class EngineStoryViewListContext {
|
||||
let signal: Signal<InternalState, NoError> = self.account.postbox.transaction { transaction -> Void in
|
||||
}
|
||||
|> mapToSignal { _ -> Signal<InternalState, NoError> in
|
||||
return account.network.request(Api.functions.stories.getStoryViewsList(id: storyId, offsetDate: currentOffset?.timestamp ?? 0, offsetId: currentOffset?.id ?? 0, limit: Int32(limit)))
|
||||
return account.network.request(Api.functions.stories.getStoryViewsList(flags: 0, q: nil, id: storyId, offset: currentOffset?.value ?? "", limit: Int32(limit)))
|
||||
|> map(Optional.init)
|
||||
|> `catch` { _ -> Signal<Api.stories.StoryViewsList?, NoError> in
|
||||
return .single(nil)
|
||||
@@ -1730,14 +1720,13 @@ public final class EngineStoryViewListContext {
|
||||
|> mapToSignal { result -> Signal<InternalState, NoError> in
|
||||
return account.postbox.transaction { transaction -> InternalState in
|
||||
switch result {
|
||||
case let .storyViewsList(count, views, users):
|
||||
case let .storyViewsList(_, count, reactionsCount, views, users, nextOffset):
|
||||
updatePeers(transaction: transaction, accountPeerId: accountPeerId, peers: AccumulatedPeers(users: users))
|
||||
|
||||
var items: [Item] = []
|
||||
var nextOffset: NextOffset?
|
||||
for view in views {
|
||||
switch view {
|
||||
case let .storyView(flags, userId, date):
|
||||
case let .storyView(flags, userId, date, reaction):
|
||||
let isBlocked = (flags & (1 << 0)) != 0
|
||||
let isBlockedFromStories = (flags & (1 << 1)) != 0
|
||||
|
||||
@@ -1758,9 +1747,21 @@ public final class EngineStoryViewListContext {
|
||||
return previousData.withUpdatedIsBlocked(isBlocked).withUpdatedFlags(updatedFlags)
|
||||
})
|
||||
if let peer = transaction.getPeer(peerId) {
|
||||
items.append(Item(peer: EnginePeer(peer), timestamp: date, storyStats: transaction.getPeerStoryStats(peerId: peerId), isLike: false))
|
||||
|
||||
nextOffset = NextOffset(id: userId, timestamp: date)
|
||||
let parsedReaction = reaction.flatMap(MessageReaction.Reaction.init(apiReaction:))
|
||||
items.append(Item(
|
||||
peer: EnginePeer(peer),
|
||||
timestamp: date,
|
||||
storyStats: transaction.getPeerStoryStats(peerId: peerId),
|
||||
reaction: parsedReaction,
|
||||
reactionFile: parsedReaction.flatMap { reaction -> TelegramMediaFile? in
|
||||
switch reaction {
|
||||
case .builtin:
|
||||
return nil
|
||||
case let .custom(fileId):
|
||||
return transaction.getMedia(MediaId(namespace: Namespaces.Media.CloudFile, id: fileId)) as? TelegramMediaFile
|
||||
}
|
||||
}
|
||||
))
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1774,7 +1775,7 @@ public final class EngineStoryViewListContext {
|
||||
mediaAreas: item.mediaAreas,
|
||||
text: item.text,
|
||||
entities: item.entities,
|
||||
views: Stories.Item.Views(seenCount: Int(count), seenPeerIds: currentViews.seenPeerIds),
|
||||
views: Stories.Item.Views(seenCount: Int(count), reactedCount: Int(reactionsCount), seenPeerIds: currentViews.seenPeerIds),
|
||||
privacy: item.privacy,
|
||||
isPinned: item.isPinned,
|
||||
isExpired: item.isExpired,
|
||||
@@ -1784,7 +1785,7 @@ public final class EngineStoryViewListContext {
|
||||
isSelectedContacts: item.isSelectedContacts,
|
||||
isForwardingDisabled: item.isForwardingDisabled,
|
||||
isEdited: item.isEdited,
|
||||
hasLike: item.hasLike
|
||||
myReaction: item.myReaction
|
||||
))
|
||||
if let entry = CodableEntry(updatedItem) {
|
||||
transaction.setStory(id: StoryId(peerId: account.peerId, id: storyId), value: entry)
|
||||
@@ -1803,7 +1804,7 @@ public final class EngineStoryViewListContext {
|
||||
mediaAreas: item.mediaAreas,
|
||||
text: item.text,
|
||||
entities: item.entities,
|
||||
views: Stories.Item.Views(seenCount: Int(count), seenPeerIds: currentViews.seenPeerIds),
|
||||
views: Stories.Item.Views(seenCount: Int(count), reactedCount: Int(reactionsCount), seenPeerIds: currentViews.seenPeerIds),
|
||||
privacy: item.privacy,
|
||||
isPinned: item.isPinned,
|
||||
isExpired: item.isExpired,
|
||||
@@ -1813,7 +1814,7 @@ public final class EngineStoryViewListContext {
|
||||
isSelectedContacts: item.isSelectedContacts,
|
||||
isForwardingDisabled: item.isForwardingDisabled,
|
||||
isEdited: item.isEdited,
|
||||
hasLike: item.hasLike
|
||||
myReaction: item.myReaction
|
||||
))
|
||||
if let entry = CodableEntry(updatedItem) {
|
||||
currentItems[i] = StoryItemsTableEntry(value: entry, id: updatedItem.id, expirationTimestamp: updatedItem.expirationTimestamp, isCloseFriends: updatedItem.isCloseFriends)
|
||||
@@ -1823,9 +1824,9 @@ public final class EngineStoryViewListContext {
|
||||
}
|
||||
transaction.setStoryItems(peerId: account.peerId, items: currentItems)
|
||||
|
||||
return InternalState(totalCount: Int(count), items: items, canLoadMore: nextOffset != nil, nextOffset: nextOffset)
|
||||
return InternalState(totalCount: Int(count), totalReactedCount: Int(reactionsCount), items: items, canLoadMore: nextOffset != nil, nextOffset: nextOffset.flatMap { NextOffset(value: $0) })
|
||||
case .none:
|
||||
return InternalState(totalCount: 0, items: [], canLoadMore: false, nextOffset: nil)
|
||||
return InternalState(totalCount: 0, totalReactedCount: 0, items: [], canLoadMore: false, nextOffset: nil)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1853,10 +1854,22 @@ public final class EngineStoryViewListContext {
|
||||
existingItems.insert(itemHash)
|
||||
strongSelf.state.items.append(item)
|
||||
}
|
||||
|
||||
var allReactedCount = 0
|
||||
for item in strongSelf.state.items {
|
||||
if item.reaction != nil {
|
||||
allReactedCount += 1
|
||||
} else {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if state.canLoadMore {
|
||||
strongSelf.state.totalCount = max(state.totalCount, strongSelf.state.items.count)
|
||||
strongSelf.state.totalReactedCount = max(state.totalReactedCount, allReactedCount)
|
||||
} else {
|
||||
strongSelf.state.totalCount = strongSelf.state.items.count
|
||||
strongSelf.state.totalReactedCount = allReactedCount
|
||||
}
|
||||
strongSelf.state.canLoadMore = state.canLoadMore
|
||||
strongSelf.state.nextOffset = state.nextOffset
|
||||
@@ -1884,7 +1897,8 @@ public final class EngineStoryViewListContext {
|
||||
peer: item.peer,
|
||||
timestamp: item.timestamp,
|
||||
storyStats: value,
|
||||
isLike: false
|
||||
reaction: item.reaction,
|
||||
reactionFile: item.reactionFile
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -1907,10 +1921,11 @@ public final class EngineStoryViewListContext {
|
||||
disposable.set(impl.statePromise.get().start(next: { state in
|
||||
var loadMoreToken: LoadMoreToken?
|
||||
if let nextOffset = state.nextOffset {
|
||||
loadMoreToken = LoadMoreToken(id: nextOffset.id, timestamp: nextOffset.timestamp)
|
||||
loadMoreToken = LoadMoreToken(value: nextOffset.value)
|
||||
}
|
||||
subscriber.putNext(State(
|
||||
totalCount: state.totalCount,
|
||||
totalReactedCount: state.totalReactedCount,
|
||||
items: state.items,
|
||||
loadMoreToken: loadMoreToken
|
||||
))
|
||||
@@ -2113,10 +2128,15 @@ func _internal_enableStoryStealthMode(account: Account) -> Signal<Never, NoError
|
||||
flags |= 1 << 0
|
||||
flags |= 1 << 1
|
||||
return account.network.request(Api.functions.stories.activateStealthMode(flags: flags))
|
||||
|> `catch` { _ -> Signal<Api.Bool, NoError> in
|
||||
return .single(.boolFalse)
|
||||
|> map(Optional.init)
|
||||
|> `catch` { _ -> Signal<Api.Updates?, NoError> in
|
||||
return .single(nil)
|
||||
}
|
||||
|> mapToSignal { result -> Signal<Never, NoError> in
|
||||
if let result = result {
|
||||
account.stateManager.addUpdates(result)
|
||||
}
|
||||
|
||||
return account.postbox.transaction { transaction in
|
||||
let appConfig = transaction.getPreferencesEntry(key: PreferencesKeys.appConfiguration)?.get(AppConfiguration.self) ?? .defaultValue
|
||||
|
||||
@@ -2158,8 +2178,15 @@ public func _internal_setStoryNotificationWasDisplayed(transaction: Transaction,
|
||||
transaction.putItemCacheEntry(id: ItemCacheEntryId(collectionId: Namespaces.CachedItemCollection.displayedStoryNotifications, key: key), entry: CodableEntry(data: Data()))
|
||||
}
|
||||
|
||||
func _internal_setStoryLike(account: Account, peerId: EnginePeer.Id, id: Int32, hasLike: Bool) -> Signal<Never, NoError> {
|
||||
return account.postbox.transaction { transaction -> Void in
|
||||
func _internal_setStoryReaction(account: Account, peerId: EnginePeer.Id, id: Int32, reaction: MessageReaction.Reaction?) -> Signal<Never, NoError> {
|
||||
return account.postbox.transaction { transaction -> Api.InputUser? in
|
||||
guard let peer = transaction.getPeer(peerId) else {
|
||||
return nil
|
||||
}
|
||||
guard let inputUser = apiInputUser(peer) else {
|
||||
return nil
|
||||
}
|
||||
|
||||
var currentItems = transaction.getStoryItems(peerId: peerId)
|
||||
for i in 0 ..< currentItems.count {
|
||||
if currentItems[i].id == id {
|
||||
@@ -2182,7 +2209,7 @@ func _internal_setStoryLike(account: Account, peerId: EnginePeer.Id, id: Int32,
|
||||
isSelectedContacts: item.isSelectedContacts,
|
||||
isForwardingDisabled: item.isForwardingDisabled,
|
||||
isEdited: item.isEdited,
|
||||
hasLike: hasLike
|
||||
myReaction: reaction
|
||||
))
|
||||
if let entry = CodableEntry(updatedItem) {
|
||||
currentItems[i] = StoryItemsTableEntry(value: entry, id: updatedItem.id, expirationTimestamp: updatedItem.expirationTimestamp, isCloseFriends: updatedItem.isCloseFriends)
|
||||
@@ -2211,12 +2238,30 @@ func _internal_setStoryLike(account: Account, peerId: EnginePeer.Id, id: Int32,
|
||||
isSelectedContacts: item.isSelectedContacts,
|
||||
isForwardingDisabled: item.isForwardingDisabled,
|
||||
isEdited: item.isEdited,
|
||||
hasLike: hasLike
|
||||
myReaction: reaction
|
||||
))
|
||||
if let entry = CodableEntry(updatedItem) {
|
||||
transaction.setStory(id: StoryId(peerId: peerId, id: id), value: entry)
|
||||
}
|
||||
}
|
||||
|
||||
return inputUser
|
||||
}
|
||||
|> mapToSignal { inputUser -> Signal<Never, NoError> in
|
||||
guard let inputUser = inputUser else {
|
||||
return .complete()
|
||||
}
|
||||
return account.network.request(Api.functions.stories.sendReaction(flags: 0, userId: inputUser, storyId: id, reaction: reaction?.apiReaction ?? .reactionEmpty))
|
||||
|> map(Optional.init)
|
||||
|> `catch` { _ -> Signal<Api.Updates?, NoError> in
|
||||
return .single(nil)
|
||||
}
|
||||
|> mapToSignal { updates -> Signal<Never, NoError> in
|
||||
if let updates = updates {
|
||||
account.stateManager.addUpdates(updates)
|
||||
}
|
||||
|
||||
return .complete()
|
||||
}
|
||||
}
|
||||
|> ignoreValues
|
||||
}
|
||||
|
||||
@@ -13,10 +13,12 @@ enum InternalStoryUpdate {
|
||||
public final class EngineStoryItem: Equatable {
|
||||
public final class Views: Equatable {
|
||||
public let seenCount: Int
|
||||
public let reactedCount: Int
|
||||
public let seenPeers: [EnginePeer]
|
||||
|
||||
public init(seenCount: Int, seenPeers: [EnginePeer]) {
|
||||
public init(seenCount: Int, reactedCount: Int, seenPeers: [EnginePeer]) {
|
||||
self.seenCount = seenCount
|
||||
self.reactedCount = reactedCount
|
||||
self.seenPeers = seenPeers
|
||||
}
|
||||
|
||||
@@ -24,6 +26,9 @@ public final class EngineStoryItem: Equatable {
|
||||
if lhs.seenCount != rhs.seenCount {
|
||||
return false
|
||||
}
|
||||
if lhs.reactedCount != rhs.reactedCount {
|
||||
return false
|
||||
}
|
||||
if lhs.seenPeers != rhs.seenPeers {
|
||||
return false
|
||||
}
|
||||
@@ -49,9 +54,9 @@ public final class EngineStoryItem: Equatable {
|
||||
public let isSelectedContacts: Bool
|
||||
public let isForwardingDisabled: Bool
|
||||
public let isEdited: Bool
|
||||
public let hasLike: Bool
|
||||
public let myReaction: MessageReaction.Reaction?
|
||||
|
||||
public init(id: Int32, timestamp: Int32, expirationTimestamp: Int32, media: EngineMedia, mediaAreas: [MediaArea], text: String, entities: [MessageTextEntity], views: Views?, privacy: EngineStoryPrivacy?, isPinned: Bool, isExpired: Bool, isPublic: Bool, isPending: Bool, isCloseFriends: Bool, isContacts: Bool, isSelectedContacts: Bool, isForwardingDisabled: Bool, isEdited: Bool, hasLike: Bool) {
|
||||
public init(id: Int32, timestamp: Int32, expirationTimestamp: Int32, media: EngineMedia, mediaAreas: [MediaArea], text: String, entities: [MessageTextEntity], views: Views?, privacy: EngineStoryPrivacy?, isPinned: Bool, isExpired: Bool, isPublic: Bool, isPending: Bool, isCloseFriends: Bool, isContacts: Bool, isSelectedContacts: Bool, isForwardingDisabled: Bool, isEdited: Bool, myReaction: MessageReaction.Reaction?) {
|
||||
self.id = id
|
||||
self.timestamp = timestamp
|
||||
self.expirationTimestamp = expirationTimestamp
|
||||
@@ -70,7 +75,7 @@ public final class EngineStoryItem: Equatable {
|
||||
self.isSelectedContacts = isSelectedContacts
|
||||
self.isForwardingDisabled = isForwardingDisabled
|
||||
self.isEdited = isEdited
|
||||
self.hasLike = hasLike
|
||||
self.myReaction = myReaction
|
||||
}
|
||||
|
||||
public static func ==(lhs: EngineStoryItem, rhs: EngineStoryItem) -> Bool {
|
||||
@@ -128,7 +133,7 @@ public final class EngineStoryItem: Equatable {
|
||||
if lhs.isEdited != rhs.isEdited {
|
||||
return false
|
||||
}
|
||||
if lhs.hasLike != rhs.hasLike {
|
||||
if lhs.myReaction != rhs.myReaction {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
@@ -148,6 +153,7 @@ extension EngineStoryItem {
|
||||
views: self.views.flatMap { views in
|
||||
return Stories.Item.Views(
|
||||
seenCount: views.seenCount,
|
||||
reactedCount: views.reactedCount,
|
||||
seenPeerIds: views.seenPeers.map(\.id)
|
||||
)
|
||||
},
|
||||
@@ -165,7 +171,7 @@ extension EngineStoryItem {
|
||||
isSelectedContacts: self.isSelectedContacts,
|
||||
isForwardingDisabled: self.isForwardingDisabled,
|
||||
isEdited: self.isEdited,
|
||||
hasLike: self.hasLike
|
||||
myReaction: self.myReaction
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -520,6 +526,7 @@ public final class PeerStoryListContext {
|
||||
views: item.views.flatMap { views in
|
||||
return EngineStoryItem.Views(
|
||||
seenCount: views.seenCount,
|
||||
reactedCount: views.reactedCount,
|
||||
seenPeers: views.seenPeerIds.compactMap { id -> EnginePeer? in
|
||||
return transaction.getPeer(id).flatMap(EnginePeer.init)
|
||||
}
|
||||
@@ -535,7 +542,7 @@ public final class PeerStoryListContext {
|
||||
isSelectedContacts: item.isSelectedContacts,
|
||||
isForwardingDisabled: item.isForwardingDisabled,
|
||||
isEdited: item.isEdited,
|
||||
hasLike: item.hasLike
|
||||
myReaction: item.myReaction
|
||||
)
|
||||
items.append(mappedItem)
|
||||
|
||||
@@ -646,6 +653,7 @@ public final class PeerStoryListContext {
|
||||
views: item.views.flatMap { views in
|
||||
return EngineStoryItem.Views(
|
||||
seenCount: views.seenCount,
|
||||
reactedCount: views.reactedCount,
|
||||
seenPeers: views.seenPeerIds.compactMap { id -> EnginePeer? in
|
||||
return transaction.getPeer(id).flatMap(EnginePeer.init)
|
||||
}
|
||||
@@ -661,7 +669,7 @@ public final class PeerStoryListContext {
|
||||
isSelectedContacts: item.isSelectedContacts,
|
||||
isForwardingDisabled: item.isForwardingDisabled,
|
||||
isEdited: item.isEdited,
|
||||
hasLike: item.hasLike
|
||||
myReaction: item.myReaction
|
||||
)
|
||||
storyItems.append(mappedItem)
|
||||
}
|
||||
@@ -796,6 +804,7 @@ public final class PeerStoryListContext {
|
||||
views: item.views.flatMap { views in
|
||||
return EngineStoryItem.Views(
|
||||
seenCount: views.seenCount,
|
||||
reactedCount: views.reactedCount,
|
||||
seenPeers: views.seenPeerIds.compactMap { id -> EnginePeer? in
|
||||
return peers[id].flatMap(EnginePeer.init)
|
||||
}
|
||||
@@ -811,7 +820,7 @@ public final class PeerStoryListContext {
|
||||
isSelectedContacts: item.isSelectedContacts,
|
||||
isForwardingDisabled: item.isForwardingDisabled,
|
||||
isEdited: item.isEdited,
|
||||
hasLike: item.hasLike
|
||||
myReaction: item.myReaction
|
||||
)
|
||||
finalUpdatedState = updatedState
|
||||
}
|
||||
@@ -837,6 +846,7 @@ public final class PeerStoryListContext {
|
||||
views: item.views.flatMap { views in
|
||||
return EngineStoryItem.Views(
|
||||
seenCount: views.seenCount,
|
||||
reactedCount: views.reactedCount,
|
||||
seenPeers: views.seenPeerIds.compactMap { id -> EnginePeer? in
|
||||
return peers[id].flatMap(EnginePeer.init)
|
||||
}
|
||||
@@ -852,7 +862,7 @@ public final class PeerStoryListContext {
|
||||
isSelectedContacts: item.isSelectedContacts,
|
||||
isForwardingDisabled: item.isForwardingDisabled,
|
||||
isEdited: item.isEdited,
|
||||
hasLike: item.hasLike
|
||||
myReaction: item.myReaction
|
||||
)
|
||||
finalUpdatedState = updatedState
|
||||
} else {
|
||||
@@ -880,6 +890,7 @@ public final class PeerStoryListContext {
|
||||
views: item.views.flatMap { views in
|
||||
return EngineStoryItem.Views(
|
||||
seenCount: views.seenCount,
|
||||
reactedCount: views.reactedCount,
|
||||
seenPeers: views.seenPeerIds.compactMap { id -> EnginePeer? in
|
||||
return peers[id].flatMap(EnginePeer.init)
|
||||
}
|
||||
@@ -895,7 +906,7 @@ public final class PeerStoryListContext {
|
||||
isSelectedContacts: item.isSelectedContacts,
|
||||
isForwardingDisabled: item.isForwardingDisabled,
|
||||
isEdited: item.isEdited,
|
||||
hasLike: item.hasLike
|
||||
myReaction: item.myReaction
|
||||
))
|
||||
updatedState.items.sort(by: { lhs, rhs in
|
||||
return lhs.timestamp > rhs.timestamp
|
||||
@@ -919,6 +930,7 @@ public final class PeerStoryListContext {
|
||||
views: item.views.flatMap { views in
|
||||
return EngineStoryItem.Views(
|
||||
seenCount: views.seenCount,
|
||||
reactedCount: views.reactedCount,
|
||||
seenPeers: views.seenPeerIds.compactMap { id -> EnginePeer? in
|
||||
return peers[id].flatMap(EnginePeer.init)
|
||||
}
|
||||
@@ -934,7 +946,7 @@ public final class PeerStoryListContext {
|
||||
isSelectedContacts: item.isSelectedContacts,
|
||||
isForwardingDisabled: item.isForwardingDisabled,
|
||||
isEdited: item.isEdited,
|
||||
hasLike: item.hasLike
|
||||
myReaction: item.myReaction
|
||||
))
|
||||
updatedState.items.sort(by: { lhs, rhs in
|
||||
return lhs.timestamp > rhs.timestamp
|
||||
@@ -1082,6 +1094,7 @@ public final class PeerExpiringStoryListContext {
|
||||
views: item.views.flatMap { views in
|
||||
return EngineStoryItem.Views(
|
||||
seenCount: views.seenCount,
|
||||
reactedCount: views.reactedCount,
|
||||
seenPeers: views.seenPeerIds.compactMap { id -> EnginePeer? in
|
||||
return transaction.getPeer(id).flatMap(EnginePeer.init)
|
||||
}
|
||||
@@ -1097,7 +1110,7 @@ public final class PeerExpiringStoryListContext {
|
||||
isSelectedContacts: item.isSelectedContacts,
|
||||
isForwardingDisabled: item.isForwardingDisabled,
|
||||
isEdited: item.isEdited,
|
||||
hasLike: item.hasLike
|
||||
myReaction: item.myReaction
|
||||
)
|
||||
items.append(.item(mappedItem))
|
||||
}
|
||||
|
||||
@@ -1035,7 +1035,7 @@ public extension TelegramEngine {
|
||||
isSelectedContacts: item.isSelectedContacts,
|
||||
isForwardingDisabled: item.isForwardingDisabled,
|
||||
isEdited: item.isEdited,
|
||||
hasLike: item.hasLike
|
||||
myReaction: item.myReaction
|
||||
))
|
||||
if let entry = CodableEntry(updatedItem) {
|
||||
currentItems[i] = StoryItemsTableEntry(value: entry, id: updatedItem.id, expirationTimestamp: updatedItem.expirationTimestamp, isCloseFriends: updatedItem.isCloseFriends)
|
||||
@@ -1102,10 +1102,6 @@ public extension TelegramEngine {
|
||||
return _internal_updateStoriesArePinned(account: self.account, ids: ids, isPinned: isPinned)
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
public func storyViewList(id: Int32, views: EngineStoryItem.Views) -> EngineStoryViewListContext {
|
||||
return EngineStoryViewListContext(account: self.account, storyId: id, views: views)
|
||||
}
|
||||
@@ -1118,8 +1114,8 @@ public extension TelegramEngine {
|
||||
return _internal_enableStoryStealthMode(account: self.account)
|
||||
}
|
||||
|
||||
public func setStoryLike(peerId: EnginePeer.Id, id: Int32, hasLike: Bool) -> Signal<Never, NoError> {
|
||||
return _internal_setStoryLike(account: self.account, peerId: peerId, id: id, hasLike: hasLike)
|
||||
public func setStoryReaction(peerId: EnginePeer.Id, id: Int32, reaction: MessageReaction.Reaction?) -> Signal<Never, NoError> {
|
||||
return _internal_setStoryReaction(account: self.account, peerId: peerId, id: id, reaction: reaction)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user