diff --git a/TelegramCore.xcodeproj/project.pbxproj b/TelegramCore.xcodeproj/project.pbxproj index fb3cc499eb..742b57c67c 100644 --- a/TelegramCore.xcodeproj/project.pbxproj +++ b/TelegramCore.xcodeproj/project.pbxproj @@ -151,7 +151,6 @@ D033FEB61E61F3F900644997 /* BlockedPeers.swift in Sources */ = {isa = PBXBuildFile; fileRef = D033FEB51E61F3F900644997 /* BlockedPeers.swift */; }; D033FEB71E61F3F900644997 /* BlockedPeers.swift in Sources */ = {isa = PBXBuildFile; fileRef = D033FEB51E61F3F900644997 /* BlockedPeers.swift */; }; D03B0CB91D62233400955575 /* Either.swift in Sources */ = {isa = PBXBuildFile; fileRef = D03B0CB81D62233400955575 /* Either.swift */; }; - D03B0CBB1D62233C00955575 /* MergeLists.swift in Sources */ = {isa = PBXBuildFile; fileRef = D03B0CBA1D62233C00955575 /* MergeLists.swift */; }; D03B0CBD1D62234300955575 /* Regex.swift in Sources */ = {isa = PBXBuildFile; fileRef = D03B0CBC1D62234300955575 /* Regex.swift */; }; D03B0CBF1D62234A00955575 /* Log.swift in Sources */ = {isa = PBXBuildFile; fileRef = D03B0CBE1D62234A00955575 /* Log.swift */; }; D03B0CC11D62235000955575 /* StringFormat.swift in Sources */ = {isa = PBXBuildFile; fileRef = D03B0CC01D62235000955575 /* StringFormat.swift */; }; @@ -454,7 +453,6 @@ D0B8440D1DAB91CD005F29E1 /* ImageRepresentationsUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0DF0C901D81A857008AEB01 /* ImageRepresentationsUtils.swift */; }; D0B8440E1DAB91CD005F29E1 /* MessageUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0DF0C921D81AD09008AEB01 /* MessageUtils.swift */; }; D0B8440F1DAB91CD005F29E1 /* Either.swift in Sources */ = {isa = PBXBuildFile; fileRef = D03B0CB81D62233400955575 /* Either.swift */; }; - D0B844101DAB91CD005F29E1 /* MergeLists.swift in Sources */ = {isa = PBXBuildFile; fileRef = D03B0CBA1D62233C00955575 /* MergeLists.swift */; }; D0B844111DAB91CD005F29E1 /* Regex.swift in Sources */ = {isa = PBXBuildFile; fileRef = D03B0CBC1D62234300955575 /* Regex.swift */; }; D0B844121DAB91CD005F29E1 /* Log.swift in Sources */ = {isa = PBXBuildFile; fileRef = D03B0CBE1D62234A00955575 /* Log.swift */; }; D0B844131DAB91CD005F29E1 /* StringFormat.swift in Sources */ = {isa = PBXBuildFile; fileRef = D03B0CC01D62235000955575 /* StringFormat.swift */; }; @@ -556,6 +554,8 @@ D0E35A151DE4C6A200BC6096 /* OutgoingMessageWithChatContextResult.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0E35A0F1DE49E1C00BC6096 /* OutgoingMessageWithChatContextResult.swift */; }; D0E6521F1E3A364A004EEA91 /* UpdateAccountPeerName.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0E6521E1E3A364A004EEA91 /* UpdateAccountPeerName.swift */; }; D0E652201E3A364A004EEA91 /* UpdateAccountPeerName.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0E6521E1E3A364A004EEA91 /* UpdateAccountPeerName.swift */; }; + D0E817492010E7E300B82BBB /* ChannelAdminEventLogContext.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0E817482010E7E300B82BBB /* ChannelAdminEventLogContext.swift */; }; + D0E8174A2010E7E300B82BBB /* ChannelAdminEventLogContext.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0E817482010E7E300B82BBB /* ChannelAdminEventLogContext.swift */; }; D0F02CE51E9926C40065DEE2 /* ManagedConfigurationUpdates.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0F02CE41E9926C40065DEE2 /* ManagedConfigurationUpdates.swift */; }; D0F02CE61E9926C50065DEE2 /* ManagedConfigurationUpdates.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0F02CE41E9926C40065DEE2 /* ManagedConfigurationUpdates.swift */; }; D0F3A89F1E82C65400B4C64C /* SynchronizeChatInputStateOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0F3A89E1E82C65400B4C64C /* SynchronizeChatInputStateOperation.swift */; }; @@ -694,7 +694,6 @@ D033FEB21E61F3C000644997 /* ReportPeer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ReportPeer.swift; sourceTree = ""; }; D033FEB51E61F3F900644997 /* BlockedPeers.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BlockedPeers.swift; sourceTree = ""; }; D03B0CB81D62233400955575 /* Either.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Either.swift; sourceTree = ""; }; - D03B0CBA1D62233C00955575 /* MergeLists.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MergeLists.swift; sourceTree = ""; }; D03B0CBC1D62234300955575 /* Regex.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Regex.swift; sourceTree = ""; }; D03B0CBE1D62234A00955575 /* Log.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Log.swift; sourceTree = ""; }; D03B0CC01D62235000955575 /* StringFormat.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StringFormat.swift; sourceTree = ""; }; @@ -930,6 +929,7 @@ D0E35A0F1DE49E1C00BC6096 /* OutgoingMessageWithChatContextResult.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OutgoingMessageWithChatContextResult.swift; sourceTree = ""; }; D0E35A111DE4A25E00BC6096 /* OutgoingChatContextResultMessageAttribute.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OutgoingChatContextResultMessageAttribute.swift; sourceTree = ""; }; D0E6521E1E3A364A004EEA91 /* UpdateAccountPeerName.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UpdateAccountPeerName.swift; sourceTree = ""; }; + D0E817482010E7E300B82BBB /* ChannelAdminEventLogContext.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChannelAdminEventLogContext.swift; sourceTree = ""; }; D0F02CE41E9926C40065DEE2 /* ManagedConfigurationUpdates.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ManagedConfigurationUpdates.swift; sourceTree = ""; }; D0F3A89E1E82C65400B4C64C /* SynchronizeChatInputStateOperation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SynchronizeChatInputStateOperation.swift; sourceTree = ""; }; D0F3A8A11E82C65E00B4C64C /* ManagedSynchronizeChatInputStateOperations.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ManagedSynchronizeChatInputStateOperations.swift; sourceTree = ""; }; @@ -1090,7 +1090,6 @@ D0DF0C901D81A857008AEB01 /* ImageRepresentationsUtils.swift */, D0DF0C921D81AD09008AEB01 /* MessageUtils.swift */, D03B0CB81D62233400955575 /* Either.swift */, - D03B0CBA1D62233C00955575 /* MergeLists.swift */, D03B0CBC1D62234300955575 /* Regex.swift */, D03B0CBE1D62234A00955575 /* Log.swift */, D03B0CC01D62235000955575 /* StringFormat.swift */, @@ -1575,6 +1574,7 @@ C23BC3861E9BE3CA00D79F92 /* ImportContact.swift */, C205FEA71EB3B75900455808 /* ExportMessageLink.swift */, C230BEB51EE9A3760029586C /* ChannelAdminEventLogs.swift */, + D0E817482010E7E300B82BBB /* ChannelAdminEventLogContext.swift */, D0A472B51F4CBE8B00E0EEDA /* LoadedPeer.swift */, D0DA1D311F7043D50034E892 /* ManagedPendingPeerNotificationSettings.swift */, D02395D51F8D09A50070F5C2 /* ChannelHistoryAvailabilitySettings.swift */, @@ -1950,6 +1950,7 @@ D0561DE31E5737FC00E6B9E9 /* UpdatePeerInfo.swift in Sources */, D0DF0C8A1D819C7E008AEB01 /* JoinChannel.swift in Sources */, D04CAA5A1E83310D0047E51F /* MD5.swift in Sources */, + D0E817492010E7E300B82BBB /* ChannelAdminEventLogContext.swift in Sources */, D05452071E7B5093006EEF19 /* LoadedStickerPack.swift in Sources */, D01C7F041EFC1C49008305F1 /* DeviceContact.swift in Sources */, D0F7AB2F1DCF507E009AD9A1 /* ReplyMarkupMessageAttribute.swift in Sources */, @@ -2040,7 +2041,6 @@ D0528E651E65C82400E2FEF5 /* UpdateContactName.swift in Sources */, D03121021DA57E93006A2A60 /* TelegramPeerNotificationSettings.swift in Sources */, D0C48F391E8138DF0075317D /* ArchivedStickerPacksInfo.swift in Sources */, - D03B0CBB1D62233C00955575 /* MergeLists.swift in Sources */, C239BE971E62EE1E00C2C453 /* LoadMessagesIfNecessary.swift in Sources */, D03B0CC11D62235000955575 /* StringFormat.swift in Sources */, D0B85AC51F6B2B9400B8B5CE /* RecentlyUsedHashtags.swift in Sources */, @@ -2289,6 +2289,7 @@ D050F2621E4A5AE700988324 /* GlobalNotificationSettings.swift in Sources */, D0DFD5E01FCDBCFD0039B3B1 /* CachedSentMediaReferences.swift in Sources */, D0B418991D7E0580004562A4 /* TelegramMediaMap.swift in Sources */, + D0E8174A2010E7E300B82BBB /* ChannelAdminEventLogContext.swift in Sources */, D0561DEB1E5754FA00E6B9E9 /* ChannelAdmins.swift in Sources */, D0AD02E41FFFA14800C1DCFF /* PeerLiveLocationsContext.swift in Sources */, D0613FCB1E60440600202CDB /* InvitationLinks.swift in Sources */, @@ -2324,7 +2325,6 @@ D033FEB41E61F3C000644997 /* ReportPeer.swift in Sources */, D0FA8BAE1E1FD6E2001E855B /* MemoryBufferExtensions.swift in Sources */, D0FA8BB41E201B02001E855B /* ProcessSecretChatIncomingEncryptedOperations.swift in Sources */, - D0B844101DAB91CD005F29E1 /* MergeLists.swift in Sources */, D0F3A8A31E82C65E00B4C64C /* ManagedSynchronizeChatInputStateOperations.swift in Sources */, D0448CA61E29215A005A61A7 /* MediaResourceApiUtils.swift in Sources */, D001F3F11E128A1C007A8C60 /* SynchronizePeerReadState.swift in Sources */, diff --git a/TelegramCore/ChannelAdminEventLogContext.swift b/TelegramCore/ChannelAdminEventLogContext.swift new file mode 100644 index 0000000000..f2422db064 --- /dev/null +++ b/TelegramCore/ChannelAdminEventLogContext.swift @@ -0,0 +1,124 @@ +#if os(macOS) + import PostboxMac + import SwiftSignalKitMac +#else + import Postbox + import SwiftSignalKit +#endif + +public struct ChannelAdminEventLogEntry: Comparable { + public let event: AdminLogEvent + public let peers: [PeerId: Peer] + + public static func ==(lhs: ChannelAdminEventLogEntry, rhs: ChannelAdminEventLogEntry) -> Bool { + return lhs.event == rhs.event + } + + public static func <(lhs: ChannelAdminEventLogEntry, rhs: ChannelAdminEventLogEntry) -> Bool { + return lhs.event < rhs.event + } +} + +public enum ChannelAdminEventLogUpdateType { + case initial + case generic + case load +} + +public final class ChannelAdminEventLogContext { + private let queue: Queue = Queue.mainQueue() + + private let postbox: Postbox + private let network: Network + private let peerId: PeerId + + private var entries: [ChannelAdminEventLogEntry] = [] + private var hasEarlier: Bool = true + private var loadingMoreEarlier: Bool = false + + private var subscribers = Bag<([ChannelAdminEventLogEntry], Bool, ChannelAdminEventLogUpdateType) -> Void>() + + private let loadMoreDisposable = MetaDisposable() + + public init(postbox: Postbox, network: Network, peerId: PeerId) { + self.postbox = postbox + self.network = network + self.peerId = peerId + } + + deinit { + self.loadMoreDisposable.dispose() + } + + public func get() -> Signal<([ChannelAdminEventLogEntry], Bool, ChannelAdminEventLogUpdateType), NoError> { + let queue = self.queue + return Signal { [weak self] subscriber in + if let strongSelf = self { + subscriber.putNext((strongSelf.entries, strongSelf.hasEarlier, .initial)) + + let index = strongSelf.subscribers.add({ entries, hasEarlier, type in + subscriber.putNext((strongSelf.entries, strongSelf.hasEarlier, type)) + }) + + return ActionDisposable { + queue.async { + if let strongSelf = self { + strongSelf.subscribers.remove(index) + } + } + } + } else { + return EmptyDisposable + } + } |> runOn(queue) + } + + public func loadMoreEntries() { + assert(self.queue.isCurrent()) + + if self.loadingMoreEarlier { + return + } + + let maxId: AdminLogEventId + if let last = self.entries.last { + maxId = last.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) + |> 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 clipIndex < events.count { + events.removeSubrange(clipIndex ..< events.count) + } + } + + 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) + } + } + })) + } +} diff --git a/TelegramCore/ChannelAdminEventLogs.swift b/TelegramCore/ChannelAdminEventLogs.swift index 7877236a3c..26c6662163 100644 --- a/TelegramCore/ChannelAdminEventLogs.swift +++ b/TelegramCore/ChannelAdminEventLogs.swift @@ -8,11 +8,23 @@ public typealias AdminLogEventId = Int64 -public struct AdminLogEvent { +public struct AdminLogEvent: Comparable { public let id: AdminLogEventId public let peerId: PeerId public let date: Int32 public let action: AdminLogEventAction + + public static func ==(lhs: AdminLogEvent, rhs: AdminLogEvent) -> Bool { + return lhs.id == rhs.id + } + + public static func <(lhs: AdminLogEvent, rhs: AdminLogEvent) -> Bool { + if lhs.date != rhs.date { + return lhs.date < rhs.date + } else { + return lhs.id < rhs.id + } + } } public struct AdminLogEventsResult { @@ -86,112 +98,112 @@ private func boolFromApiValue(_ value: Api.Bool) -> Bool { } } -public func channelAdminLogEvents(_ account:Account, peerId:PeerId, maxId: AdminLogEventId, minId: AdminLogEventId, limit: Int32 = 100, query: String? = nil, filter: AdminLogEventsFlags? = nil, admins: [PeerId]? = nil) -> Signal { - - return account.postbox.modify { modifier -> (Peer?, [Peer]?) in - return (modifier.getPeer(peerId), admins?.flatMap {modifier.getPeer($0)}) - } |> mapError {return .generic} |> mapToSignal { (peer, admins) -> Signal in +public func channelAdminLogEvents(postbox: Postbox, network: Network, peerId: PeerId, maxId: AdminLogEventId, minId: AdminLogEventId, limit: Int32 = 100, query: String? = nil, filter: AdminLogEventsFlags? = nil, admins: [PeerId]? = nil) -> Signal { + return postbox.modify { modifier -> (Peer?, [Peer]?) in + return (modifier.getPeer(peerId), admins?.flatMap { modifier.getPeer($0) }) + } + |> mapError { return .generic } + |> mapToSignal { (peer, admins) -> Signal in + if let peer = peer, let inputChannel = apiInputChannel(peer) { + let inputAdmins = admins?.flatMap {apiInputUser($0)} - if let peer = peer, let inputChannel = apiInputChannel(peer) { - let inputAdmins = admins?.flatMap {apiInputUser($0)} - - var flags:Int32 = 0 - var eventsFilter:Api.ChannelAdminLogEventsFilter? = nil - if let filter = filter { - flags += Int32(1 << 0) - eventsFilter = Api.ChannelAdminLogEventsFilter.channelAdminLogEventsFilter(flags: Int32(filter.rawValue)) - } - if let _ = inputAdmins { - flags += Int32(1 << 1) - } - return account.network.request(Api.functions.channels.getAdminLog(flags: flags, channel: inputChannel, q: query ?? "", eventsFilter: eventsFilter, admins: inputAdmins, maxId: maxId, minId: minId, limit: limit)) |> map { result in - - switch result { - case let .adminLogResults(apiEvents, apiChats, apiUsers): - let peers = (apiChats.flatMap {parseTelegramGroupOrChannel(chat: $0)} + apiUsers.flatMap { TelegramUser(user: $0) } + Array(arrayLiteral: peer)).reduce([:], { current, peer -> [PeerId : Peer] in - var current = current - current[peer.id] = peer - return current - }) - - var events: [AdminLogEvent] = [] - - for event in apiEvents { - switch event { - case let .channelAdminLogEvent(id, date, userId, apiAction): - var action: AdminLogEventAction? - switch apiAction { - case let .channelAdminLogEventActionChangeTitle(prev, new): - action = .changeTitle(prev: prev, new: new) - case let .channelAdminLogEventActionChangeAbout(prev, new): - action = .changeAbout(prev: prev, new: new) - case let .channelAdminLogEventActionChangeUsername(prev, new): - action = .changeUsername(prev: prev, new: new) - case let .channelAdminLogEventActionChangePhoto(prev, new): - action = .changePhoto(prev: imageRepresentationsForApiChatPhoto(prev), new: imageRepresentationsForApiChatPhoto(new)) - case let .channelAdminLogEventActionToggleInvites(new): - action = .toggleInvites(boolFromApiValue(new)) - case let .channelAdminLogEventActionToggleSignatures(new): - action = .toggleSignatures(boolFromApiValue(new)) - case let .channelAdminLogEventActionUpdatePinned(new): - switch new { - case .messageEmpty: - action = .updatePinned(nil) - default: - if let message = StoreMessage(apiMessage: new), let rendered = locallyRenderedMessage(message: message, peers: peers) { - action = .updatePinned(rendered) - } - } - - case let .channelAdminLogEventActionEditMessage(prev, new): - if let prev = StoreMessage(apiMessage: prev), let prevRendered = locallyRenderedMessage(message: prev, peers: peers), let new = StoreMessage(apiMessage: new), let newRendered = locallyRenderedMessage(message: new, peers: peers) { - action = .editMessage(prev: prevRendered, new: newRendered) - } - case let .channelAdminLogEventActionDeleteMessage(message): - if let message = StoreMessage(apiMessage: message), let rendered = locallyRenderedMessage(message: message, peers: peers) { - action = .deleteMessage(rendered) - } - case .channelAdminLogEventActionParticipantJoin: - action = .participantJoin - case .channelAdminLogEventActionParticipantLeave: - action = .participantLeave - case let .channelAdminLogEventActionParticipantInvite(participant): - let participant = ChannelParticipant(apiParticipant: participant) - - if let peer = peers[participant.peerId] { - action = .participantInvite(RenderedChannelParticipant(participant: participant, peer: peer)) - } - case let .channelAdminLogEventActionParticipantToggleBan(prev, new): - let prevParticipant = ChannelParticipant(apiParticipant: prev) - let newParticipant = ChannelParticipant(apiParticipant: new) - - if let prevPeer = peers[prevParticipant.peerId], let newPeer = peers[newParticipant.peerId] { - action = .participantToggleBan(prev: RenderedChannelParticipant(participant: prevParticipant, peer: prevPeer), new: RenderedChannelParticipant(participant: newParticipant, peer: newPeer)) - } - case let .channelAdminLogEventActionParticipantToggleAdmin(prev, new): - let prevParticipant = ChannelParticipant(apiParticipant: prev) - let newParticipant = ChannelParticipant(apiParticipant: new) - - if let prevPeer = peers[prevParticipant.peerId], let newPeer = peers[newParticipant.peerId] { - action = .participantToggleAdmin(prev: RenderedChannelParticipant(participant: prevParticipant, peer: prevPeer), new: RenderedChannelParticipant(participant: newParticipant, peer: newPeer)) - } - case let .channelAdminLogEventActionChangeStickerSet(prevStickerset, newStickerset): - action = .changeStickerPack(prev: StickerPackReference(apiInputSet: prevStickerset), new: StickerPackReference(apiInputSet: newStickerset)) - case let .channelAdminLogEventActionTogglePreHistoryHidden(value): - action = .togglePreHistoryHidden(value == .boolTrue) - } - let peerId = PeerId(namespace: Namespaces.Peer.CloudUser, id: userId) - if let action = action { - events.append(AdminLogEvent(id: id, peerId: peerId, date: date, action: action)) - } - } - } - return AdminLogEventsResult(peerId: peerId, peers: peers, events: events) - } - - } |> mapError {_ in return .generic} + var flags: Int32 = 0 + var eventsFilter: Api.ChannelAdminLogEventsFilter? = nil + if let filter = filter { + flags += Int32(1 << 0) + eventsFilter = Api.ChannelAdminLogEventsFilter.channelAdminLogEventsFilter(flags: Int32(filter.rawValue)) } - - return .complete() + if let _ = inputAdmins { + flags += Int32(1 << 1) + } + return network.request(Api.functions.channels.getAdminLog(flags: flags, channel: inputChannel, q: query ?? "", eventsFilter: eventsFilter, admins: inputAdmins, maxId: maxId, minId: minId, limit: limit)) |> map { result in + + switch result { + case let .adminLogResults(apiEvents, apiChats, apiUsers): + let peers = (apiChats.flatMap {parseTelegramGroupOrChannel(chat: $0)} + apiUsers.flatMap { TelegramUser(user: $0) } + Array(arrayLiteral: peer)).reduce([:], { current, peer -> [PeerId : Peer] in + var current = current + current[peer.id] = peer + return current + }) + + var events: [AdminLogEvent] = [] + + for event in apiEvents { + switch event { + case let .channelAdminLogEvent(id, date, userId, apiAction): + var action: AdminLogEventAction? + switch apiAction { + case let .channelAdminLogEventActionChangeTitle(prev, new): + action = .changeTitle(prev: prev, new: new) + case let .channelAdminLogEventActionChangeAbout(prev, new): + action = .changeAbout(prev: prev, new: new) + case let .channelAdminLogEventActionChangeUsername(prev, new): + action = .changeUsername(prev: prev, new: new) + case let .channelAdminLogEventActionChangePhoto(prev, new): + action = .changePhoto(prev: imageRepresentationsForApiChatPhoto(prev), new: imageRepresentationsForApiChatPhoto(new)) + case let .channelAdminLogEventActionToggleInvites(new): + action = .toggleInvites(boolFromApiValue(new)) + case let .channelAdminLogEventActionToggleSignatures(new): + action = .toggleSignatures(boolFromApiValue(new)) + case let .channelAdminLogEventActionUpdatePinned(new): + switch new { + case .messageEmpty: + action = .updatePinned(nil) + default: + if let message = StoreMessage(apiMessage: new), let rendered = locallyRenderedMessage(message: message, peers: peers) { + action = .updatePinned(rendered) + } + } + + case let .channelAdminLogEventActionEditMessage(prev, new): + if let prev = StoreMessage(apiMessage: prev), let prevRendered = locallyRenderedMessage(message: prev, peers: peers), let new = StoreMessage(apiMessage: new), let newRendered = locallyRenderedMessage(message: new, peers: peers) { + action = .editMessage(prev: prevRendered, new: newRendered) + } + case let .channelAdminLogEventActionDeleteMessage(message): + if let message = StoreMessage(apiMessage: message), let rendered = locallyRenderedMessage(message: message, peers: peers) { + action = .deleteMessage(rendered) + } + case .channelAdminLogEventActionParticipantJoin: + action = .participantJoin + case .channelAdminLogEventActionParticipantLeave: + action = .participantLeave + case let .channelAdminLogEventActionParticipantInvite(participant): + let participant = ChannelParticipant(apiParticipant: participant) + + if let peer = peers[participant.peerId] { + action = .participantInvite(RenderedChannelParticipant(participant: participant, peer: peer)) + } + case let .channelAdminLogEventActionParticipantToggleBan(prev, new): + let prevParticipant = ChannelParticipant(apiParticipant: prev) + let newParticipant = ChannelParticipant(apiParticipant: new) + + if let prevPeer = peers[prevParticipant.peerId], let newPeer = peers[newParticipant.peerId] { + action = .participantToggleBan(prev: RenderedChannelParticipant(participant: prevParticipant, peer: prevPeer), new: RenderedChannelParticipant(participant: newParticipant, peer: newPeer)) + } + case let .channelAdminLogEventActionParticipantToggleAdmin(prev, new): + let prevParticipant = ChannelParticipant(apiParticipant: prev) + let newParticipant = ChannelParticipant(apiParticipant: new) + + if let prevPeer = peers[prevParticipant.peerId], let newPeer = peers[newParticipant.peerId] { + action = .participantToggleAdmin(prev: RenderedChannelParticipant(participant: prevParticipant, peer: prevPeer), new: RenderedChannelParticipant(participant: newParticipant, peer: newPeer)) + } + case let .channelAdminLogEventActionChangeStickerSet(prevStickerset, newStickerset): + action = .changeStickerPack(prev: StickerPackReference(apiInputSet: prevStickerset), new: StickerPackReference(apiInputSet: newStickerset)) + case let .channelAdminLogEventActionTogglePreHistoryHidden(value): + action = .togglePreHistoryHidden(value == .boolTrue) + } + let peerId = PeerId(namespace: Namespaces.Peer.CloudUser, id: userId) + if let action = action { + events.append(AdminLogEvent(id: id, peerId: peerId, date: date, action: action)) + } + } + } + return AdminLogEventsResult(peerId: peerId, peers: peers, events: events) + } + + } |> mapError {_ in return .generic} + } + + return .complete() } } diff --git a/TelegramCore/MergeLists.swift b/TelegramCore/MergeLists.swift deleted file mode 100644 index fe83f021d7..0000000000 --- a/TelegramCore/MergeLists.swift +++ /dev/null @@ -1,413 +0,0 @@ -import Foundation - -public protocol Identifiable { - associatedtype T: Hashable - var stableId: T { get } -} - -public func mergeListsStable(leftList: [T], rightList: [T]) -> ([Int], [(Int, T, Int?)]) where T: Comparable, T: Identifiable { - var removeIndices: [Int] = [] - var insertItems: [(Int, T, Int?)] = [] - - var currentList = leftList - - var i = 0 - var j = 0 - while true { - let left: T? = i < currentList.count ? currentList[i] : nil - let right: T? = j < rightList.count ? rightList[j] : nil - - if let left = left, let right = right { - if left == right { - i += 1 - j += 1 - } else if left < right { - removeIndices.append(i) - i += 1 - } else { - j += 1 - } - } else if let _ = left { - removeIndices.append(i) - i += 1 - } else if let _ = right { - j += 1 - } else { - break - } - } - - for index in removeIndices.reversed() { - currentList.remove(at: index) - } - - var previousIndices: [T.T: Int] = [:] - i = 0 - for left in leftList { - previousIndices[left.stableId] = i - i += 1 - } - - i = 0 - j = 0 - while true { - let left: T? = i < currentList.count ? currentList[i] : nil - let right: T? = j < rightList.count ? rightList[j] : nil - - if let left = left, let right = right { - if left == right { - i += 1 - j += 1 - } else if left > right { - let previousIndex = previousIndices[right.stableId] - insertItems.append((i, right, previousIndex)) - currentList.insert(right, at: i) - i += 1 - j += 1 - } else { - i += 1 - } - } else if let _ = left { - i += 1 - } else if let right = right { - let previousIndex = previousIndices[right.stableId] - insertItems.append((i, right, previousIndex)) - currentList.insert(right, at: i) - i += 1 - j += 1 - } else { - break - } - } - - assert(currentList == rightList, "currentList == rightList") - - return (removeIndices, insertItems) -} - -public func mergeListsStableWithUpdates(leftList: [T], rightList: [T]) -> ([Int], [(Int, T, Int?)], [(Int, T, Int)]) where T: Comparable, T: Identifiable { - var removeIndices: [Int] = [] - var insertItems: [(Int, T, Int?)] = [] - var updatedIndices: [(Int, T, Int)] = [] - - #if (arch(i386) || arch(x86_64)) && os(iOS) - var existingStableIds: [T.T: T] = [:] - for item in leftList { - if let _ = existingStableIds[item.stableId] { - assertionFailure() - } else { - existingStableIds[item.stableId] = item - } - } - existingStableIds.removeAll() - for item in rightList { - if let other = existingStableIds[item.stableId] { - print("\(other) has the same stableId as \(item): \(item.stableId)") - assertionFailure() - } else { - existingStableIds[item.stableId] = item - } - } - #endif - - var currentList = leftList - - var i = 0 - var previousIndices: [T.T: Int] = [:] - for left in leftList { - previousIndices[left.stableId] = i - i += 1 - } - - i = 0 - var j = 0 - while true { - let left: T? = i < currentList.count ? currentList[i] : nil - let right: T? = j < rightList.count ? rightList[j] : nil - - if let left = left, let right = right { - if left.stableId == right.stableId && left != right { - updatedIndices.append((i, right, previousIndices[left.stableId]!)) - i += 1 - j += 1 - } else { - if left == right { - i += 1 - j += 1 - } else if left < right { - removeIndices.append(i) - i += 1 - } else if !(left > right) { - removeIndices.append(i) - i += 1 - } else { - j += 1 - } - } - } else if let _ = left { - removeIndices.append(i) - i += 1 - } else if let _ = right { - j += 1 - } else { - break - } - } - - //print("remove:\n\(removeIndices)") - - for index in removeIndices.reversed() { - currentList.remove(at: index) - for i in 0 ..< updatedIndices.count { - if updatedIndices[i].0 >= index { - updatedIndices[i].0 -= 1 - } - } - } - - /*print("\n current after removes:\n") - m = 0 - for right in currentList { - print("\(m): \(right.stableId)") - m += 1 - } - - print("update:\n\(updatedIndices.map({ "\($0.0), \($0.1.stableId) (was \($0.2)))" }))")*/ - - i = 0 - j = 0 - var k = 0 - while true { - let left: T? - - //print("i=\(i), j=\(j), k=\(k)") - - if k < updatedIndices.count && updatedIndices[k].0 < i { - //print("updated[k=\(k)]=\(updatedIndices[k].0) right { - //print("\(left.stableId)>\(right.stableId)") - //print("insert \(right.stableId) at \(i)") - //print("i++, j++") - let previousIndex = previousIndices[right.stableId] - insertItems.append((i, right, previousIndex)) - currentList.insert(right, at: i) - if k < updatedIndices.count { - for l in k ..< updatedIndices.count { - updatedIndices[l] = (updatedIndices[l].0 + 1, updatedIndices[l].1, updatedIndices[l].2) - } - } - - i += 1 - j += 1 - } else { - //print("\(left.stableId)<\(right.stableId)") - //print("i++") - i += 1 - } - } else if let _ = left { - //print("\(left!.stableId)>nil") - //print("i++") - i += 1 - } else if let right = right { - //print("nil<\(right.stableId)") - //print("insert \(right.stableId) at \(i)") - //print("i++") - //print("j++") - let previousIndex = previousIndices[right.stableId] - insertItems.append((i, right, previousIndex)) - currentList.insert(right, at: i) - - if k < updatedIndices.count { - for l in k ..< updatedIndices.count { - updatedIndices[l] = (updatedIndices[l].0 + 1, updatedIndices[l].1, updatedIndices[l].2) - } - } - - i += 1 - j += 1 - } else { - break - } - } - - for (index, item, _) in updatedIndices { - currentList[index] = item - } - - assert(currentList == rightList, "currentList == rightList") - - return (removeIndices, insertItems, updatedIndices) -} - -public func mergeListsStableWithUpdatesReversed(leftList: [T], rightList: [T]) -> ([Int], [(Int, T, Int?)], [(Int, T, Int)]) where T: Comparable, T: Identifiable { - var removeIndices: [Int] = [] - var insertItems: [(Int, T, Int?)] = [] - var updatedIndices: [(Int, T, Int)] = [] - - #if (arch(i386) || arch(x86_64)) && os(iOS) - var existingStableIds: [T.T: T] = [:] - for item in leftList { - if let _ = existingStableIds[item.stableId] { - assertionFailure() - } else { - existingStableIds[item.stableId] = item - } - } - existingStableIds.removeAll() - for item in rightList { - if let other = existingStableIds[item.stableId] { - print("\(other) has the same stableId as \(item): \(item.stableId)") - assertionFailure() - } else { - existingStableIds[item.stableId] = item - } - } - #endif - - var currentList = leftList - - var i = 0 - var previousIndices: [T.T: Int] = [:] - for left in leftList { - previousIndices[left.stableId] = i - i += 1 - } - - i = 0 - var j = 0 - while true { - let left: T? = i < currentList.count ? currentList[i] : nil - let right: T? = j < rightList.count ? rightList[j] : nil - - if let left = left, let right = right { - if left.stableId == right.stableId && left != right { - updatedIndices.append((i, right, previousIndices[left.stableId]!)) - i += 1 - j += 1 - } else { - if left == right { - i += 1 - j += 1 - } else if left > right { - removeIndices.append(i) - i += 1 - } else if !(left < right) { - removeIndices.append(i) - i += 1 - } else { - j += 1 - } - } - } else if let _ = left { - removeIndices.append(i) - i += 1 - } else if let _ = right { - j += 1 - } else { - break - } - } - - //print("remove:\n\(removeIndices)") - - for index in removeIndices.reversed() { - currentList.remove(at: index) - for i in 0 ..< updatedIndices.count { - if updatedIndices[i].0 >= index { - updatedIndices[i].0 -= 1 - } - } - } - - i = 0 - j = 0 - var k = 0 - while true { - let left: T? - - if k < updatedIndices.count && updatedIndices[k].0 < i { - k += 1 - } - - if k < updatedIndices.count { - if updatedIndices[k].0 == i { - left = updatedIndices[k].1 - } else { - left = i < currentList.count ? currentList[i] : nil - } - } else { - left = i < currentList.count ? currentList[i] : nil - } - - let right: T? = j < rightList.count ? rightList[j] : nil - - if let left = left, let right = right { - if left == right { - i += 1 - j += 1 - } else if left < right { - let previousIndex = previousIndices[right.stableId] - insertItems.append((i, right, previousIndex)) - currentList.insert(right, at: i) - if k < updatedIndices.count { - for l in k ..< updatedIndices.count { - updatedIndices[l] = (updatedIndices[l].0 + 1, updatedIndices[l].1, updatedIndices[l].2) - } - } - - i += 1 - j += 1 - } else { - i += 1 - } - } else if let _ = left { - i += 1 - } else if let right = right { - let previousIndex = previousIndices[right.stableId] - insertItems.append((i, right, previousIndex)) - currentList.insert(right, at: i) - - if k < updatedIndices.count { - for l in k ..< updatedIndices.count { - updatedIndices[l] = (updatedIndices[l].0 + 1, updatedIndices[l].1, updatedIndices[l].2) - } - } - - i += 1 - j += 1 - } else { - break - } - } - - for (index, item, _) in updatedIndices { - currentList[index] = item - } - - assert(currentList == rightList, "currentList == rightList") - - return (removeIndices, insertItems, updatedIndices) -} - diff --git a/TelegramCore/Serialization.swift b/TelegramCore/Serialization.swift index ce0ac83adc..35146f1eb5 100644 --- a/TelegramCore/Serialization.swift +++ b/TelegramCore/Serialization.swift @@ -20,7 +20,7 @@ public class BoxedMessage: NSObject { public class Serialization: NSObject, MTSerialization { public func currentLayer() -> UInt { - return 75 + return 76 } public func parseMessage(_ data: Data!) -> Any! {