diff --git a/TelegramCore.xcodeproj/project.pbxproj b/TelegramCore.xcodeproj/project.pbxproj index 742b57c67c..3d16816fd6 100644 --- a/TelegramCore.xcodeproj/project.pbxproj +++ b/TelegramCore.xcodeproj/project.pbxproj @@ -584,6 +584,10 @@ D0F7B1EA1E045C87007EB8A5 /* ChangePeerNotificationSettings.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0B843961DA7FBBC005F29E1 /* ChangePeerNotificationSettings.swift */; }; D0F7B1EB1E045C87007EB8A5 /* ResolvePeerByName.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0F3CC7C1DDE289E008148FA /* ResolvePeerByName.swift */; }; D0F7B1EC1E045C87007EB8A5 /* SearchPeers.swift in Sources */ = {isa = PBXBuildFile; fileRef = D07827BA1E00451F00071108 /* SearchPeers.swift */; }; + D0F8C39D20178B9B00236FC5 /* GroupFeedPeers.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0F8C39C20178B9B00236FC5 /* GroupFeedPeers.swift */; }; + D0F8C39E20178B9B00236FC5 /* GroupFeedPeers.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0F8C39C20178B9B00236FC5 /* GroupFeedPeers.swift */; }; + D0F8C3A02017AF2700236FC5 /* GlobalTelegramCoreConfiguration.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0F8C39F2017AF2700236FC5 /* GlobalTelegramCoreConfiguration.swift */; }; + D0F8C3A12017AF2700236FC5 /* GlobalTelegramCoreConfiguration.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0F8C39F2017AF2700236FC5 /* GlobalTelegramCoreConfiguration.swift */; }; D0FA0ABD1E76C908005BB9B7 /* TwoStepVerification.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0FA0ABC1E76C908005BB9B7 /* TwoStepVerification.swift */; }; D0FA35051EA6135D00E56FFA /* CacheStorageSettings.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0FA35041EA6135D00E56FFA /* CacheStorageSettings.swift */; }; D0FA35061EA6135D00E56FFA /* CacheStorageSettings.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0FA35041EA6135D00E56FFA /* CacheStorageSettings.swift */; }; @@ -939,6 +943,8 @@ D0F53BE81E784A4800117362 /* ChangeAccountPhoneNumber.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ChangeAccountPhoneNumber.swift; sourceTree = ""; }; D0F7AB2B1DCE889D009AD9A1 /* EditedMessageAttribute.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EditedMessageAttribute.swift; sourceTree = ""; }; D0F7AB2E1DCF507E009AD9A1 /* ReplyMarkupMessageAttribute.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ReplyMarkupMessageAttribute.swift; sourceTree = ""; }; + D0F8C39C20178B9B00236FC5 /* GroupFeedPeers.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GroupFeedPeers.swift; sourceTree = ""; }; + D0F8C39F2017AF2700236FC5 /* GlobalTelegramCoreConfiguration.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GlobalTelegramCoreConfiguration.swift; sourceTree = ""; }; D0FA0ABC1E76C908005BB9B7 /* TwoStepVerification.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TwoStepVerification.swift; sourceTree = ""; }; D0FA35041EA6135D00E56FFA /* CacheStorageSettings.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CacheStorageSettings.swift; sourceTree = ""; }; D0FA35071EA632E400E56FFA /* CollectCacheUsageStats.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CollectCacheUsageStats.swift; sourceTree = ""; }; @@ -1103,6 +1109,7 @@ D01C7F031EFC1C49008305F1 /* DeviceContact.swift */, D053B3FD1F16534400E2D58A /* MonotonicTime.swift */, D01C06B61FBBA269001561AB /* CanSendMessagesToPeer.swift */, + D0F8C39F2017AF2700236FC5 /* GlobalTelegramCoreConfiguration.swift */, ); name = Utils; sourceTree = ""; @@ -1579,6 +1586,7 @@ D0DA1D311F7043D50034E892 /* ManagedPendingPeerNotificationSettings.swift */, D02395D51F8D09A50070F5C2 /* ChannelHistoryAvailabilitySettings.swift */, D0C44B601FC616E200227BE0 /* SearchGroupMembers.swift */, + D0F8C39C20178B9B00236FC5 /* GroupFeedPeers.swift */, ); name = Peers; sourceTree = ""; @@ -1930,6 +1938,7 @@ D0FA8BAD1E1FD6E2001E855B /* MemoryBufferExtensions.swift in Sources */, D03B0CBF1D62234A00955575 /* Log.swift in Sources */, C2FD33E41E687BF1008D13D4 /* PeerPhotoUpdater.swift in Sources */, + D0F8C3A02017AF2700236FC5 /* GlobalTelegramCoreConfiguration.swift in Sources */, D01C06B71FBBA269001561AB /* CanSendMessagesToPeer.swift in Sources */, D0B843B51DA7FF30005F29E1 /* NBMetadataCore.m in Sources */, D0C26D691FE02402004ABF18 /* ManagedSynchronizeGroupedPeersOperations.swift in Sources */, @@ -2046,6 +2055,7 @@ D0B85AC51F6B2B9400B8B5CE /* RecentlyUsedHashtags.swift in Sources */, D0B843C31DA7FF30005F29E1 /* NBPhoneMetaDataGenerator.m in Sources */, C2366C861E4F403C0097CCFF /* AddressNames.swift in Sources */, + D0F8C39D20178B9B00236FC5 /* GroupFeedPeers.swift in Sources */, D0B843C11DA7FF30005F29E1 /* NBPhoneMetaData.m in Sources */, D0528E601E65B94E00E2FEF5 /* SingleMessageView.swift in Sources */, D08CAA841ED8164B0000FDA8 /* Localization.swift in Sources */, @@ -2246,6 +2256,7 @@ D001F3E91E128A1C007A8C60 /* SecretChatState.swift in Sources */, D08F4A6A1E79CECB00A2AA15 /* ManagedSynchronizeInstalledStickerPacksOperations.swift in Sources */, D0B8444B1DAB91FD005F29E1 /* ManagedSynchronizePeerReadStates.swift in Sources */, + D0F8C39E20178B9B00236FC5 /* GroupFeedPeers.swift in Sources */, D073CE6C1DCBCF17007511FD /* TextEntitiesMessageAttribute.swift in Sources */, D03C53751DAD5CA9004C17B3 /* TelegramUserPresence.swift in Sources */, D05452081E7B5093006EEF19 /* LoadedStickerPack.swift in Sources */, @@ -2318,6 +2329,7 @@ D03E5E0D1E55E02D0029569A /* LoggedOutAccountAttribute.swift in Sources */, D0B418AD1D7E0597004562A4 /* Serialization.swift in Sources */, C28725431EF967E700613564 /* NotificationInfoMessageAttribute.swift in Sources */, + D0F8C3A12017AF2700236FC5 /* GlobalTelegramCoreConfiguration.swift in Sources */, D099D7471EEF0C2700A3128C /* ChannelMessageStateVersionAttribute.swift in Sources */, D058E0D21E8AD65C00A442DE /* StandaloneSendMessage.swift in Sources */, D03C536F1DAD5CA9004C17B3 /* BotInfo.swift in Sources */, diff --git a/TelegramCore/AccountIntermediateState.swift b/TelegramCore/AccountIntermediateState.swift index cdcaa6b0d8..2ab7916da9 100644 --- a/TelegramCore/AccountIntermediateState.swift +++ b/TelegramCore/AccountIntermediateState.swift @@ -69,7 +69,6 @@ enum AccountStateMutationOperation { case UpdateChannelState(PeerId, ChannelState) case UpdateNotificationSettings(AccountStateNotificationSettingsSubject, PeerNotificationSettings) case UpdateGlobalNotificationSettings(AccountStateGlobalNotificationSettingsSubject, MessageNotificationSettings) - case AddHole(MessageId) case MergeApiChats([Api.Chat]) case UpdatePeer(PeerId, (Peer?) -> Peer?) case UpdateCachedPeerData(PeerId, (CachedPeerData?) -> CachedPeerData?) @@ -102,6 +101,7 @@ struct AccountMutableState { var peerNotificationSettings: [PeerId: PeerNotificationSettings] var storedMessages: Set var readInboxMaxIds: [PeerId: MessageId] + var namespacesWithHolesFromPreviousState: [PeerId: Set] var storedMessagesByPeerIdAndTimestamp: [PeerId: Set] @@ -119,9 +119,10 @@ struct AccountMutableState { self.peerNotificationSettings = initialState.peerNotificationSettings self.storedMessagesByPeerIdAndTimestamp = storedMessagesByPeerIdAndTimestamp self.branchOperationIndex = 0 + self.namespacesWithHolesFromPreviousState = [:] } - init(initialState: AccountInitialState, operations: [AccountStateMutationOperation], state: AuthorizedAccountState.State, peers: [PeerId: Peer], chatStates: [PeerId: PeerChatState], peerNotificationSettings: [PeerId: PeerNotificationSettings], storedMessages: Set, readInboxMaxIds: [PeerId: MessageId], storedMessagesByPeerIdAndTimestamp: [PeerId: Set], branchOperationIndex: Int) { + init(initialState: AccountInitialState, operations: [AccountStateMutationOperation], state: AuthorizedAccountState.State, peers: [PeerId: Peer], chatStates: [PeerId: PeerChatState], peerNotificationSettings: [PeerId: PeerNotificationSettings], storedMessages: Set, readInboxMaxIds: [PeerId: MessageId], storedMessagesByPeerIdAndTimestamp: [PeerId: Set], namespacesWithHolesFromPreviousState: [PeerId: Set], branchOperationIndex: Int) { self.initialState = initialState self.operations = operations self.state = state @@ -131,11 +132,12 @@ struct AccountMutableState { self.peerNotificationSettings = peerNotificationSettings self.readInboxMaxIds = readInboxMaxIds self.storedMessagesByPeerIdAndTimestamp = storedMessagesByPeerIdAndTimestamp + self.namespacesWithHolesFromPreviousState = namespacesWithHolesFromPreviousState self.branchOperationIndex = branchOperationIndex } func branch() -> AccountMutableState { - return AccountMutableState(initialState: self.initialState, operations: self.operations, state: self.state, peers: self.peers, chatStates: self.chatStates, peerNotificationSettings: self.peerNotificationSettings, storedMessages: self.storedMessages, readInboxMaxIds: self.readInboxMaxIds, storedMessagesByPeerIdAndTimestamp: self.storedMessagesByPeerIdAndTimestamp, branchOperationIndex: self.operations.count) + return AccountMutableState(initialState: self.initialState, operations: self.operations, state: self.state, peers: self.peers, chatStates: self.chatStates, peerNotificationSettings: self.peerNotificationSettings, storedMessages: self.storedMessages, readInboxMaxIds: self.readInboxMaxIds, storedMessagesByPeerIdAndTimestamp: self.storedMessagesByPeerIdAndTimestamp, namespacesWithHolesFromPreviousState: self.namespacesWithHolesFromPreviousState, branchOperationIndex: self.operations.count) } mutating func merge(_ other: AccountMutableState) { @@ -146,6 +148,14 @@ struct AccountMutableState { self.peers[peer.id] = peer } self.preCachedResources.append(contentsOf: other.preCachedResources) + for (peerId, namespaces) in other.namespacesWithHolesFromPreviousState { + if self.namespacesWithHolesFromPreviousState[peerId] == nil { + self.self.namespacesWithHolesFromPreviousState[peerId] = Set() + } + for namespace in namespaces { + self.namespacesWithHolesFromPreviousState[peerId]!.insert(namespace) + } + } } mutating func addPreCachedResource(_ resource: MediaResource, data: Data) { @@ -208,8 +218,11 @@ struct AccountMutableState { self.addOperation(.UpdateGlobalNotificationSettings(subject, notificationSettings)) } - mutating func addHole(_ messageId: MessageId) { - self.addOperation(.AddHole(messageId)) + mutating func setNeedsHoleFromPreviousState(peerId: PeerId, namespace: MessageId.Namespace) { + if self.namespacesWithHolesFromPreviousState[peerId] == nil { + self.namespacesWithHolesFromPreviousState[peerId] = Set() + } + self.namespacesWithHolesFromPreviousState[peerId]!.insert(namespace) } mutating func mergeChats(_ chats: [Api.Chat]) { @@ -302,7 +315,7 @@ struct AccountMutableState { mutating func addOperation(_ operation: AccountStateMutationOperation) { switch operation { - case .AddHole, .DeleteMessages, .DeleteMessagesWithGlobalIds, .EditMessage, .UpdateMedia, .ReadOutbox, .ReadGroupFeedInbox, .MergePeerPresences, .UpdateSecretChat, .AddSecretMessages, .ReadSecretOutbox, .AddPeerInputActivity, .UpdateCachedPeerData, .UpdatePinnedItemIds, .ReadMessageContents, .UpdateMessageImpressionCount, .UpdateInstalledStickerPacks, .UpdateRecentGifs, .UpdateChatInputState, .UpdateCall, .UpdateLangPack, .UpdateMinAvailableMessage: + case .DeleteMessages, .DeleteMessagesWithGlobalIds, .EditMessage, .UpdateMedia, .ReadOutbox, .ReadGroupFeedInbox, .MergePeerPresences, .UpdateSecretChat, .AddSecretMessages, .ReadSecretOutbox, .AddPeerInputActivity, .UpdateCachedPeerData, .UpdatePinnedItemIds, .ReadMessageContents, .UpdateMessageImpressionCount, .UpdateInstalledStickerPacks, .UpdateRecentGifs, .UpdateChatInputState, .UpdateCall, .UpdateLangPack, .UpdateMinAvailableMessage: break case let .AddMessages(messages, _): for message in messages { diff --git a/TelegramCore/AccountStateManagementUtils.swift b/TelegramCore/AccountStateManagementUtils.swift index fc01e1f9d2..da126c83d3 100644 --- a/TelegramCore/AccountStateManagementUtils.swift +++ b/TelegramCore/AccountStateManagementUtils.swift @@ -1413,8 +1413,8 @@ private func resetChannels(_ account: Account, peers: [Peer], state: AccountMuta updatedState.mergeUsers(dialogsUsers) for message in storeMessages { - if case let .Id(id) = message.id { - updatedState.addHole(MessageId(peerId: id.peerId, namespace: Namespaces.Message.Cloud, id: Int32.max)) + if case let .Id(id) = message.id, id.namespace == Namespaces.Message.Cloud { + updatedState.setNeedsHoleFromPreviousState(peerId: id.peerId, namespace: id.namespace) } } @@ -1576,7 +1576,7 @@ private func pollChannel(_ account: Account, peer: Peer, state: AccountMutableSt updatedState.mergeChats(chats) updatedState.mergeUsers(users) - updatedState.addHole(MessageId(peerId: peer.id, namespace: Namespaces.Message.Cloud, id: Int32.max)) + updatedState.setNeedsHoleFromPreviousState(peerId: peer.id, namespace: Namespaces.Message.Cloud) for apiMessage in messages { if let message = StoreMessage(apiMessage: apiMessage) { @@ -1703,7 +1703,7 @@ private func optimizedOperations(_ operations: [AccountStateMutationOperation]) var currentAddMessages: OptimizeAddMessagesState? for operation in operations { switch operation { - case .AddHole, .DeleteMessages, .DeleteMessagesWithGlobalIds, .EditMessage, .UpdateMedia, .MergeApiChats, .MergeApiUsers, .MergePeerPresences, .UpdatePeer, .ReadInbox, .ReadOutbox, .ReadGroupFeedInbox, .ResetReadState, .ResetMessageTagSummary, .UpdateNotificationSettings, .UpdateGlobalNotificationSettings, .UpdateSecretChat, .AddSecretMessages, .ReadSecretOutbox, .AddPeerInputActivity, .UpdateCachedPeerData, .UpdatePinnedItemIds, .ReadMessageContents, .UpdateMessageImpressionCount, .UpdateInstalledStickerPacks, .UpdateRecentGifs, .UpdateChatInputState, .UpdateCall, .UpdateLangPack, .UpdateMinAvailableMessage: + case .DeleteMessages, .DeleteMessagesWithGlobalIds, .EditMessage, .UpdateMedia, .MergeApiChats, .MergeApiUsers, .MergePeerPresences, .UpdatePeer, .ReadInbox, .ReadOutbox, .ReadGroupFeedInbox, .ResetReadState, .ResetMessageTagSummary, .UpdateNotificationSettings, .UpdateGlobalNotificationSettings, .UpdateSecretChat, .AddSecretMessages, .ReadSecretOutbox, .AddPeerInputActivity, .UpdateCachedPeerData, .UpdatePinnedItemIds, .ReadMessageContents, .UpdateMessageImpressionCount, .UpdateInstalledStickerPacks, .UpdateRecentGifs, .UpdateChatInputState, .UpdateCall, .UpdateLangPack, .UpdateMinAvailableMessage: if let currentAddMessages = currentAddMessages, !currentAddMessages.messages.isEmpty { result.append(.AddMessages(currentAddMessages.messages, currentAddMessages.location)) } @@ -1757,6 +1757,36 @@ func replayFinalState(accountPeerId: PeerId, mediaBox: MediaBox, modifier: Modif var langPackDifferences: [Api.LangPackDifference] = [] var pollLangPack = false + var addHolesToGroupFeedIds = Set() + + for (peerId, namespaces) in finalState.state.namespacesWithHolesFromPreviousState { + for namespace in namespaces { + modifier.addHole(MessageId(peerId: peerId, namespace: namespace, id: Int32.max)) + + if namespace == Namespaces.Message.Cloud { + let peer: Peer? = finalState.state.peers[peerId] ?? modifier.getPeer(peerId) + if let peer = peer { + var groupId: PeerGroupId? + if let channel = peer as? TelegramChannel { + groupId = channel.peerGroupId + } + if groupId == nil { + groupId = modifier.getPeerGroupId(peerId) + } + if let groupId = groupId { + addHolesToGroupFeedIds.insert(groupId) + } + } else { + assertionFailure() + } + } + } + } + + for groupId in addHolesToGroupFeedIds { + modifier.addFeedHoleFromLatestEntries(groupId: groupId) + } + for operation in optimizedOperations(finalState.state.operations) { switch operation { case let .AddMessages(messages, location): @@ -1847,8 +1877,6 @@ func replayFinalState(accountPeerId: PeerId, mediaBox: MediaBox, modifier: Modif }) }) } - case let .AddHole(messageId): - modifier.addHole(messageId) case let .MergeApiChats(chats): var peers: [Peer] = [] for chat in chats { diff --git a/TelegramCore/ChannelAdminEventLogContext.swift b/TelegramCore/ChannelAdminEventLogContext.swift index f2422db064..b4dbaf8d75 100644 --- a/TelegramCore/ChannelAdminEventLogContext.swift +++ b/TelegramCore/ChannelAdminEventLogContext.swift @@ -7,6 +7,7 @@ #endif public struct ChannelAdminEventLogEntry: Comparable { + public let stableId: UInt32 public let event: AdminLogEvent public let peers: [PeerId: Peer] @@ -25,6 +26,60 @@ public enum ChannelAdminEventLogUpdateType { case load } +public struct ChannelAdminEventLogFilter: Equatable { + public let query: String? + public let events: AdminLogEventsFlags + public let adminPeerIds: [PeerId]? + + public init(query: String? = nil, events: AdminLogEventsFlags = .all, adminPeerIds: [PeerId]? = nil) { + self.query = query + self.events = events + self.adminPeerIds = adminPeerIds + } + + public static func ==(lhs: ChannelAdminEventLogFilter, rhs: ChannelAdminEventLogFilter) -> Bool { + if lhs.query != rhs.query { + return false + } + if lhs.events != rhs.events { + return false + } + if let lhsAdminPeerIds = lhs.adminPeerIds, let rhsAdminPeerIds = rhs.adminPeerIds { + if lhsAdminPeerIds != rhsAdminPeerIds { + return false + } + } else if (lhs.adminPeerIds != nil) != (rhs.adminPeerIds != nil) { + return false + } + return true + } + + public var isEmpty: Bool { + if self.query != nil { + return false + } + if self.events != .all { + return false + } + if self.adminPeerIds != nil { + return false + } + return true + } + + public func withQuery(_ query: String?) -> ChannelAdminEventLogFilter { + return ChannelAdminEventLogFilter(query: query, events: self.events, adminPeerIds: self.adminPeerIds) + } + + public func withEvents(_ events: AdminLogEventsFlags) -> ChannelAdminEventLogFilter { + return ChannelAdminEventLogFilter(query: self.query, events: events, adminPeerIds: self.adminPeerIds) + } + + public func withAdminPeerIds(_ adminPeerIds: [PeerId]?) -> ChannelAdminEventLogFilter { + return ChannelAdminEventLogFilter(query: self.query, events: self.events, adminPeerIds: adminPeerIds) + } +} + public final class ChannelAdminEventLogContext { private let queue: Queue = Queue.mainQueue() @@ -32,7 +87,12 @@ public final class ChannelAdminEventLogContext { private let network: Network private let peerId: PeerId - private var entries: [ChannelAdminEventLogEntry] = [] + private var filter: ChannelAdminEventLogFilter = ChannelAdminEventLogFilter() + + private var nextStableId: UInt32 = 1 + private var stableIds: [AdminLogEventId: UInt32] = [:] + + private var entries: ([ChannelAdminEventLogEntry], ChannelAdminEventLogFilter) = ([], ChannelAdminEventLogFilter()) private var hasEarlier: Bool = true private var loadingMoreEarlier: Bool = false @@ -54,10 +114,10 @@ public final class ChannelAdminEventLogContext { let queue = self.queue return Signal { [weak self] subscriber in if let strongSelf = self { - subscriber.putNext((strongSelf.entries, strongSelf.hasEarlier, .initial)) + subscriber.putNext((strongSelf.entries.0, strongSelf.hasEarlier, .initial)) let index = strongSelf.subscribers.add({ entries, hasEarlier, type in - subscriber.putNext((strongSelf.entries, strongSelf.hasEarlier, type)) + subscriber.putNext((strongSelf.entries.0, strongSelf.hasEarlier, type)) }) return ActionDisposable { @@ -73,6 +133,20 @@ public final class ChannelAdminEventLogContext { } |> runOn(queue) } + public func setFilter(_ filter: ChannelAdminEventLogFilter) { + if self.filter != filter { + self.filter = filter + self.loadingMoreEarlier = false + self.hasEarlier = false + + for subscriber in self.subscribers.copyItems() { + subscriber(self.entries.0, self.hasEarlier, .load) + } + + self.loadMoreEntries() + } + } + public func loadMoreEntries() { assert(self.queue.isCurrent()) @@ -81,44 +155,60 @@ public final class ChannelAdminEventLogContext { } let maxId: AdminLogEventId - if let last = self.entries.last { - maxId = last.event.id + if self.entries.1 == self.filter, let first = self.entries.0.first { + maxId = first.event.id } else { maxId = AdminLogEventId.max } self.loadingMoreEarlier = true - self.loadMoreDisposable.set((channelAdminLogEvents(postbox: self.postbox, network: self.network, peerId: self.peerId, maxId: maxId, minId: AdminLogEventId.min, limit: 10, query: nil, filter: nil, admins: nil) + self.loadMoreDisposable.set((channelAdminLogEvents(postbox: self.postbox, network: self.network, peerId: self.peerId, maxId: maxId, minId: AdminLogEventId.min, limit: 100, query: self.filter.query, filter: self.filter.events, admins: self.filter.adminPeerIds) |> deliverOn(self.queue)).start(next: { [weak self] result in if let strongSelf = self { var events = result.events.sorted() - if let first = strongSelf.entries.first { - var clipIndex = events.count - for i in (0 ..< events.count).reversed() { - if events[i] >= first.event { - clipIndex = i - 1 + if strongSelf.entries.1 == strongSelf.filter { + if let first = strongSelf.entries.0.first { + var clipIndex = events.count + for i in (0 ..< events.count).reversed() { + if events[i] >= first.event { + clipIndex = i - 1 + } + } + if clipIndex < events.count { + events.removeSubrange(clipIndex ..< events.count) } } - if clipIndex < events.count { - events.removeSubrange(clipIndex ..< events.count) + + var entries: [ChannelAdminEventLogEntry] = events.map { event in + return ChannelAdminEventLogEntry(stableId: strongSelf.stableIdForEventId(event.id), event: event, peers: result.peers) } + entries.append(contentsOf: strongSelf.entries.0) + strongSelf.entries = (entries, strongSelf.filter) + } else { + let entries: [ChannelAdminEventLogEntry] = events.map { event in + return ChannelAdminEventLogEntry(stableId: strongSelf.stableIdForEventId(event.id), event: event, peers: result.peers) + } + strongSelf.entries = (entries, strongSelf.filter) } strongSelf.hasEarlier = !events.isEmpty - - var entries: [ChannelAdminEventLogEntry] = events.map { event in - return ChannelAdminEventLogEntry(event: event, peers: result.peers) - - } - entries.append(contentsOf: strongSelf.entries) - strongSelf.entries = entries - strongSelf.loadingMoreEarlier = false for subscriber in strongSelf.subscribers.copyItems() { - subscriber(strongSelf.entries, strongSelf.hasEarlier, .load) + subscriber(strongSelf.entries.0, strongSelf.hasEarlier, .load) } } })) } + + private func stableIdForEventId(_ id: AdminLogEventId) -> UInt32 { + if let value = self.stableIds[id] { + return value + } else { + let value = self.nextStableId + self.nextStableId += 1 + self.stableIds[id] = value + return value + } + } } diff --git a/TelegramCore/ChannelAdminEventLogs.swift b/TelegramCore/ChannelAdminEventLogs.swift index 26c6662163..7cc6610fe1 100644 --- a/TelegramCore/ChannelAdminEventLogs.swift +++ b/TelegramCore/ChannelAdminEventLogs.swift @@ -81,7 +81,7 @@ public struct AdminLogEventsFlags : OptionSet { public static let editMessages = AdminLogEventsFlags(rawValue: 1 << 12) public static let deleteMessages = AdminLogEventsFlags(rawValue: 1 << 13) - public static var all: [AdminLogEventsFlags] { + public static var all: AdminLogEventsFlags { return [.join, .leave, .invite, .ban, .unban, .kick, .unkick, .promote, .demote, .info, .settings, .pinnedMessages, .editMessages, .deleteMessages] } public static var flags: AdminLogEventsFlags { diff --git a/TelegramCore/GlobalTelegramCoreConfiguration.swift b/TelegramCore/GlobalTelegramCoreConfiguration.swift new file mode 100644 index 0000000000..7cf05d8aa9 --- /dev/null +++ b/TelegramCore/GlobalTelegramCoreConfiguration.swift @@ -0,0 +1,5 @@ +import Foundation + +public final class GlobalTelegramCoreConfiguration { + public static var readMessages: Bool = true +} diff --git a/TelegramCore/GroupFeedPeers.swift b/TelegramCore/GroupFeedPeers.swift new file mode 100644 index 0000000000..34760222e2 --- /dev/null +++ b/TelegramCore/GroupFeedPeers.swift @@ -0,0 +1,50 @@ +import Foundation +#if os(macOS) + import PostboxMac + import SwiftSignalKitMac +#else + import Postbox + import SwiftSignalKit +#endif + +public func availableGroupFeedPeers(postbox: Postbox, network: Network, groupId: PeerGroupId) -> Signal<[(Peer, Bool)], NoError> { + return network.request(Api.functions.channels.getFeedSources(flags: 0, feedId: groupId.rawValue, hash: 0)) + |> retryRequest + |> mapToSignal { result -> Signal<[(Peer, Bool)], NoError> in + return postbox.modify { modifier -> [(Peer, Bool)] in + switch result { + case .feedSourcesNotModified: + return [] + case let .feedSources(_, newlyJoinedFeed, feeds, chats, users): + var includedPeerIds = Set() + var excludedPeerIds = Set() + for feedsInfo in feeds { + switch feedsInfo { + case let .feedBroadcasts(feedId, channels): + if feedId == groupId.rawValue { + for id in channels { + includedPeerIds.insert(PeerId(namespace: Namespaces.Peer.CloudChannel, id: id)) + } + } + case let .feedBroadcastsUngrouped(channels): + for id in channels { + excludedPeerIds.insert(PeerId(namespace: Namespaces.Peer.CloudChannel, id: id)) + } + } + } + var peers: [(Peer, Bool)] = [] + for peerId in includedPeerIds { + if let peer = modifier.getPeer(peerId) { + peers.append((peer, true)) + } + } + for peerId in excludedPeerIds { + if let peer = modifier.getPeer(peerId) { + peers.append((peer, false)) + } + } + return peers + } + } + } +} diff --git a/TelegramCore/ManagedGroupFeedReadStateSyncOperations.swift b/TelegramCore/ManagedGroupFeedReadStateSyncOperations.swift index 44f41caab7..1143dc9882 100644 --- a/TelegramCore/ManagedGroupFeedReadStateSyncOperations.swift +++ b/TelegramCore/ManagedGroupFeedReadStateSyncOperations.swift @@ -171,9 +171,13 @@ private func groupBoundaryPeer(_ peerId: PeerId, accountPeerId: PeerId) -> Api.P private func pushReadState(network: Network, accountPeerId: PeerId, groupId: PeerGroupId, state: GroupFeedReadState) -> Signal { let position: Api.FeedPosition = .feedPosition(date: state.maxReadIndex.timestamp, peer: groupBoundaryPeer(state.maxReadIndex.id.peerId, accountPeerId: accountPeerId), id: state.maxReadIndex.id.id) - return network.request(Api.functions.channels.readFeed(feedId: groupId.rawValue, maxPosition: position)) - |> retryRequest - |> map(Optional.init) + if GlobalTelegramCoreConfiguration.readMessages { + return network.request(Api.functions.channels.readFeed(feedId: groupId.rawValue, maxPosition: position)) + |> retryRequest + |> map(Optional.init) + } else { + return .single(nil) + } } private func performSyncOperation(postbox: Postbox, network: Network, accountPeerId: PeerId, stateManager: AccountStateManager, groupId: PeerGroupId, operation: GroupFeedReadStateSyncOperation) -> Signal { diff --git a/TelegramCore/PeerAdmins.swift b/TelegramCore/PeerAdmins.swift index 89c1085a85..8294c3045d 100644 --- a/TelegramCore/PeerAdmins.swift +++ b/TelegramCore/PeerAdmins.swift @@ -202,7 +202,7 @@ public enum UpdatePeerAdminRightsError { case addMemberError(AddPeerMemberError) } -func fetchChannelParticipant(account: Account, peerId: PeerId, participantId: PeerId) -> Signal { +public func fetchChannelParticipant(account: Account, peerId: PeerId, participantId: PeerId) -> Signal { return account.postbox.modify { modifier -> Signal in if let peer = modifier.getPeer(peerId), let adminPeer = modifier.getPeer(participantId), let inputUser = apiInputUser(adminPeer) { if let channel = peer as? TelegramChannel, let inputChannel = apiInputChannel(channel) { diff --git a/TelegramCore/ResolvePeerByName.swift b/TelegramCore/ResolvePeerByName.swift index 8ef15584d5..b822561217 100644 --- a/TelegramCore/ResolvePeerByName.swift +++ b/TelegramCore/ResolvePeerByName.swift @@ -64,7 +64,7 @@ public enum ResolvePeerByNameOptionRemote { public func resolvePeerByName(account: Account, name: String, ageLimit: Int32 = 2 * 60 * 60 * 24) -> Signal { var normalizedName = name if normalizedName.hasPrefix("@") { - normalizedName = normalizedName.substring(from: name.index(after: name.startIndex)) + normalizedName = String(normalizedName[name.index(after: name.startIndex)...]) } return account.postbox.modify { modifier -> CachedResolvedByNamePeer? in @@ -82,7 +82,6 @@ public func resolvePeerByName(account: Account, name: String, ageLimit: Int32 = return account.postbox.modify { modifier -> PeerId? in var peerId: PeerId? = nil - //contacts.resolvedPeer peer:Peer chats:Vector users:Vector = contacts.ResolvedPeer; switch result { case let .resolvedPeer(apiPeer, chats, users): var peers: [PeerId: Peer] = [:] diff --git a/TelegramCore/SynchronizeGroupedPeersOperation.swift b/TelegramCore/SynchronizeGroupedPeersOperation.swift index 1b742db15f..e9190df359 100644 --- a/TelegramCore/SynchronizeGroupedPeersOperation.swift +++ b/TelegramCore/SynchronizeGroupedPeersOperation.swift @@ -55,6 +55,18 @@ public func updatePeerGroupIdInteractively(postbox: Postbox, peerId: PeerId, gro } } +public func clearPeerGroupInteractively(postbox: Postbox, groupId: PeerGroupId) -> Signal { + return postbox.modify { modifier -> Void in + var previousGroupPeerIds = Set() + previousGroupPeerIds = modifier.getPeerIdsInGroup(groupId) + + for peerId in modifier.getPeerIdsInGroup(groupId) { + modifier.updatePeerGroupId(peerId, groupId: nil) + } + addSynchronizeGroupedPeersOperation(modifier: modifier, groupId: groupId, initialPeerIds: previousGroupPeerIds) + } +} + private func addSynchronizeGroupedPeersOperation(modifier: Modifier, groupId: PeerGroupId, initialPeerIds: Set) { let tag: PeerOperationLogTag = OperationLogTags.SynchronizeGroupedPeers let peerId = PeerId(namespace: 0, id: groupId.rawValue) diff --git a/TelegramCore/SynchronizePeerReadState.swift b/TelegramCore/SynchronizePeerReadState.swift index 1f858f1ff0..bf6657f340 100644 --- a/TelegramCore/SynchronizePeerReadState.swift +++ b/TelegramCore/SynchronizePeerReadState.swift @@ -235,9 +235,9 @@ private func validatePeerReadState(network: Network, postbox: Postbox, stateMana } private func pushPeerReadState(network: Network, postbox: Postbox, stateManager: AccountStateManager, peerId: PeerId, readState: PeerReadState) -> Signal { - #if (arch(i386) || arch(x86_64)) && os(iOS) - //return .single(readState) - #endif + if !GlobalTelegramCoreConfiguration.readMessages { + return .single(readState) + } if peerId.namespace == Namespaces.Peer.SecretChat { return inputSecretChat(postbox: postbox, peerId: peerId) diff --git a/TelegramCore/TelegramChannel.swift b/TelegramCore/TelegramChannel.swift index f6f1d4e3bb..d939195dfb 100644 --- a/TelegramCore/TelegramChannel.swift +++ b/TelegramCore/TelegramChannel.swift @@ -77,6 +77,10 @@ public struct TelegramChannelGroupFlags: OptionSet { public struct TelegramChannelGroupInfo: Equatable { public let flags: TelegramChannelGroupFlags + + public init(flags: TelegramChannelGroupFlags) { + self.flags = flags + } public static func ==(lhs: TelegramChannelGroupInfo, rhs: TelegramChannelGroupInfo) -> Bool { return lhs.flags == rhs.flags diff --git a/TelegramCore/TelegramMediaAction.swift b/TelegramCore/TelegramMediaAction.swift index 3f2e8c498f..8303c93081 100644 --- a/TelegramCore/TelegramMediaAction.swift +++ b/TelegramCore/TelegramMediaAction.swift @@ -29,7 +29,7 @@ public enum TelegramMediaActionType: PostboxCoding, Equatable { case gameScore(gameId: Int64, score: Int32) case phoneCall(callId: Int64, discardReason: PhoneCallDiscardReason?, duration: Int32?) case paymentSent(currency: String, totalAmount: Int64) - case customText(text: String) + case customText(text: String, entities: [MessageTextEntity]) public init(decoder: PostboxDecoder) { let rawValue: Int32 = decoder.decodeInt32ForKey("_rawValue", orElse: 0) @@ -69,7 +69,7 @@ public enum TelegramMediaActionType: PostboxCoding, Equatable { case 15: self = .paymentSent(currency: decoder.decodeStringForKey("currency", orElse: ""), totalAmount: decoder.decodeInt64ForKey("ta", orElse: 0)) case 16: - self = .customText(text: decoder.decodeStringForKey("text", orElse: "")) + self = .customText(text: decoder.decodeStringForKey("text", orElse: ""), entities: decoder.decodeObjectArrayWithDecoderForKey("ent")) default: self = .unknown } @@ -140,9 +140,10 @@ public enum TelegramMediaActionType: PostboxCoding, Equatable { } else { encoder.encodeNil(forKey: "d") } - case let .customText(text): + case let .customText(text, entities): encoder.encodeInt32(16, forKey: "_rawValue") encoder.encodeString(text, forKey: "text") + encoder.encodeObjectArray(entities, forKey: "ent") } } @@ -262,8 +263,8 @@ public func ==(lhs: TelegramMediaActionType, rhs: TelegramMediaActionType) -> Bo } else { return false } - case let .customText(text): - if case .customText(text) = rhs { + case let .customText(lhsText, lhsEntities): + if case let .customText(rhsText, rhsEntities) = rhs, lhsText == rhsText, lhsEntities == rhsEntities { return true } else { return false @@ -343,7 +344,7 @@ func telegramMediaActionFromApiAction(_ action: Api.MessageAction) -> TelegramMe case .messageActionScreenshotTaken: return TelegramMediaAction(action: .historyScreenshot) case let .messageActionCustomAction(message): - return TelegramMediaAction(action: .customText(text: message)) + return TelegramMediaAction(action: .customText(text: message, entities: [])) } }