mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-08-28 08:30:11 +00:00
Shared media improvements
This commit is contained in:
parent
426c2f7e79
commit
7871cd8f43
File diff suppressed because it is too large
Load Diff
@ -2,12 +2,19 @@ import Foundation
|
|||||||
import UIKit
|
import UIKit
|
||||||
|
|
||||||
public struct ToolbarAction: Equatable {
|
public struct ToolbarAction: Equatable {
|
||||||
|
public enum Color: Equatable {
|
||||||
|
case accent
|
||||||
|
case custom(UIColor)
|
||||||
|
}
|
||||||
|
|
||||||
public let title: String
|
public let title: String
|
||||||
public let isEnabled: Bool
|
public let isEnabled: Bool
|
||||||
|
public let color: Color
|
||||||
|
|
||||||
public init(title: String, isEnabled: Bool) {
|
public init(title: String, isEnabled: Bool, color: Color = .accent) {
|
||||||
self.title = title
|
self.title = title
|
||||||
self.isEnabled = isEnabled
|
self.isEnabled = isEnabled
|
||||||
|
self.color = color
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -117,8 +117,23 @@ public final class ToolbarNode: ASDisplayNode {
|
|||||||
|
|
||||||
self.rightTitle.attributedText = NSAttributedString(string: toolbar.rightAction?.title ?? "", font: Font.regular(17.0), textColor: (toolbar.rightAction?.isEnabled ?? false) ? self.theme.tabBarSelectedTextColor : self.theme.tabBarTextColor)
|
self.rightTitle.attributedText = NSAttributedString(string: toolbar.rightAction?.title ?? "", font: Font.regular(17.0), textColor: (toolbar.rightAction?.isEnabled ?? false) ? self.theme.tabBarSelectedTextColor : self.theme.tabBarTextColor)
|
||||||
self.rightButton.accessibilityLabel = toolbar.rightAction?.title
|
self.rightButton.accessibilityLabel = toolbar.rightAction?.title
|
||||||
|
|
||||||
self.middleTitle.attributedText = NSAttributedString(string: toolbar.middleAction?.title ?? "", font: Font.regular(17.0), textColor: (toolbar.middleAction?.isEnabled ?? false) ? self.theme.tabBarSelectedTextColor : self.theme.tabBarTextColor)
|
let middleColor: UIColor
|
||||||
|
if let middleAction = toolbar.middleAction {
|
||||||
|
if middleAction.isEnabled {
|
||||||
|
switch middleAction.color {
|
||||||
|
case .accent:
|
||||||
|
middleColor = self.theme.tabBarSelectedTextColor
|
||||||
|
case let .custom(color):
|
||||||
|
middleColor = color
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
middleColor = self.theme.tabBarTextColor
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
middleColor = self.theme.tabBarTextColor
|
||||||
|
}
|
||||||
|
self.middleTitle.attributedText = NSAttributedString(string: toolbar.middleAction?.title ?? "", font: Font.regular(17.0), textColor: middleColor)
|
||||||
self.middleButton.accessibilityLabel = toolbar.middleAction?.title
|
self.middleButton.accessibilityLabel = toolbar.middleAction?.title
|
||||||
|
|
||||||
var size = size
|
var size = size
|
||||||
|
@ -469,6 +469,14 @@ final class MessageHistoryTable: Table {
|
|||||||
|
|
||||||
self.processIndexOperations(peerId, operations: operations, processedOperationsByPeerId: &operationsByPeerId, updatedMedia: &updatedMedia, unsentMessageOperations: &unsentMessageOperations, updatedPeerReadStateOperations: &updatedPeerReadStateOperations, globalTagsOperations: &globalTagsOperations, pendingActionsOperations: &pendingActionsOperations, updatedMessageActionsSummaries: &updatedMessageActionsSummaries, updatedMessageTagSummaries: &updatedMessageTagSummaries, invalidateMessageTagSummaries: &invalidateMessageTagSummaries, localTagsOperations: &localTagsOperations, timestampBasedMessageAttributesOperations: ×tampBasedMessageAttributesOperations)
|
self.processIndexOperations(peerId, operations: operations, processedOperationsByPeerId: &operationsByPeerId, updatedMedia: &updatedMedia, unsentMessageOperations: &unsentMessageOperations, updatedPeerReadStateOperations: &updatedPeerReadStateOperations, globalTagsOperations: &globalTagsOperations, pendingActionsOperations: &pendingActionsOperations, updatedMessageActionsSummaries: &updatedMessageActionsSummaries, updatedMessageTagSummaries: &updatedMessageTagSummaries, invalidateMessageTagSummaries: &invalidateMessageTagSummaries, localTagsOperations: &localTagsOperations, timestampBasedMessageAttributesOperations: ×tampBasedMessageAttributesOperations)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func clearHistoryInRange(peerId: PeerId, minTimestamp: Int32, maxTimestamp: Int32, namespaces: MessageIdNamespaces, operationsByPeerId: inout [PeerId: [MessageHistoryOperation]], updatedMedia: inout [MediaId: Media?], unsentMessageOperations: inout [IntermediateMessageHistoryUnsentOperation], updatedPeerReadStateOperations: inout [PeerId: PeerReadStateSynchronizationOperation?], globalTagsOperations: inout [GlobalMessageHistoryTagsOperation], pendingActionsOperations: inout [PendingMessageActionsOperation], updatedMessageActionsSummaries: inout [PendingMessageActionsSummaryKey: Int32], updatedMessageTagSummaries: inout [MessageHistoryTagsSummaryKey: MessageHistoryTagNamespaceSummary], invalidateMessageTagSummaries: inout [InvalidatedMessageHistoryTagsSummaryEntryOperation], localTagsOperations: inout [IntermediateMessageHistoryLocalTagsOperation], timestampBasedMessageAttributesOperations: inout [TimestampBasedMessageAttributesOperation], forEachMedia: (Media) -> Void) {
|
||||||
|
var indices = self.allMessageIndices(peerId: peerId).filter { namespaces.contains($0.id.namespace) }
|
||||||
|
indices = indices.filter { index in
|
||||||
|
return index.timestamp >= minTimestamp && index.timestamp <= maxTimestamp
|
||||||
|
}
|
||||||
|
self.removeMessages(indices.map { $0.id }, operationsByPeerId: &operationsByPeerId, updatedMedia: &updatedMedia, unsentMessageOperations: &unsentMessageOperations, updatedPeerReadStateOperations: &updatedPeerReadStateOperations, globalTagsOperations: &globalTagsOperations, pendingActionsOperations: &pendingActionsOperations, updatedMessageActionsSummaries: &updatedMessageActionsSummaries, updatedMessageTagSummaries: &updatedMessageTagSummaries, invalidateMessageTagSummaries: &invalidateMessageTagSummaries, localTagsOperations: &localTagsOperations, timestampBasedMessageAttributesOperations: ×tampBasedMessageAttributesOperations, forEachMedia: forEachMedia)
|
||||||
|
}
|
||||||
|
|
||||||
func clearHistory(peerId: PeerId, namespaces: MessageIdNamespaces, operationsByPeerId: inout [PeerId: [MessageHistoryOperation]], updatedMedia: inout [MediaId: Media?], unsentMessageOperations: inout [IntermediateMessageHistoryUnsentOperation], updatedPeerReadStateOperations: inout [PeerId: PeerReadStateSynchronizationOperation?], globalTagsOperations: inout [GlobalMessageHistoryTagsOperation], pendingActionsOperations: inout [PendingMessageActionsOperation], updatedMessageActionsSummaries: inout [PendingMessageActionsSummaryKey: Int32], updatedMessageTagSummaries: inout [MessageHistoryTagsSummaryKey: MessageHistoryTagNamespaceSummary], invalidateMessageTagSummaries: inout [InvalidatedMessageHistoryTagsSummaryEntryOperation], localTagsOperations: inout [IntermediateMessageHistoryLocalTagsOperation], timestampBasedMessageAttributesOperations: inout [TimestampBasedMessageAttributesOperation], forEachMedia: (Media) -> Void) {
|
func clearHistory(peerId: PeerId, namespaces: MessageIdNamespaces, operationsByPeerId: inout [PeerId: [MessageHistoryOperation]], updatedMedia: inout [MediaId: Media?], unsentMessageOperations: inout [IntermediateMessageHistoryUnsentOperation], updatedPeerReadStateOperations: inout [PeerId: PeerReadStateSynchronizationOperation?], globalTagsOperations: inout [GlobalMessageHistoryTagsOperation], pendingActionsOperations: inout [PendingMessageActionsOperation], updatedMessageActionsSummaries: inout [PendingMessageActionsSummaryKey: Int32], updatedMessageTagSummaries: inout [MessageHistoryTagsSummaryKey: MessageHistoryTagNamespaceSummary], invalidateMessageTagSummaries: inout [InvalidatedMessageHistoryTagsSummaryEntryOperation], localTagsOperations: inout [IntermediateMessageHistoryLocalTagsOperation], timestampBasedMessageAttributesOperations: inout [TimestampBasedMessageAttributesOperation], forEachMedia: (Media) -> Void) {
|
||||||
let indices = self.allMessageIndices(peerId: peerId).filter { namespaces.contains($0.id.namespace) }
|
let indices = self.allMessageIndices(peerId: peerId).filter { namespaces.contains($0.id.namespace) }
|
||||||
|
@ -147,9 +147,9 @@ public final class Transaction {
|
|||||||
self.postbox?.withAllMessages(peerId: peerId, namespace: namespace, f)
|
self.postbox?.withAllMessages(peerId: peerId, namespace: namespace, f)
|
||||||
}
|
}
|
||||||
|
|
||||||
public func clearHistory(_ peerId: PeerId, namespaces: MessageIdNamespaces, forEachMedia: (Media) -> Void) {
|
public func clearHistory(_ peerId: PeerId, minTimestamp: Int32?, maxTimestamp: Int32?, namespaces: MessageIdNamespaces, forEachMedia: (Media) -> Void) {
|
||||||
assert(!self.disposed)
|
assert(!self.disposed)
|
||||||
self.postbox?.clearHistory(peerId, namespaces: namespaces, forEachMedia: forEachMedia)
|
self.postbox?.clearHistory(peerId, minTimestamp: minTimestamp, maxTimestamp: maxTimestamp, namespaces: namespaces, forEachMedia: forEachMedia)
|
||||||
}
|
}
|
||||||
|
|
||||||
public func removeAllMessagesWithAuthor(_ peerId: PeerId, authorId: PeerId, namespace: MessageId.Namespace, forEachMedia: (Media) -> Void) {
|
public func removeAllMessagesWithAuthor(_ peerId: PeerId, authorId: PeerId, namespace: MessageId.Namespace, forEachMedia: (Media) -> Void) {
|
||||||
@ -1806,10 +1806,14 @@ final class PostboxImpl {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fileprivate func clearHistory(_ peerId: PeerId, namespaces: MessageIdNamespaces, forEachMedia: (Media) -> Void) {
|
fileprivate func clearHistory(_ peerId: PeerId, minTimestamp: Int32?, maxTimestamp: Int32?, namespaces: MessageIdNamespaces, forEachMedia: (Media) -> Void) {
|
||||||
self.messageHistoryTable.clearHistory(peerId: peerId, namespaces: namespaces, operationsByPeerId: &self.currentOperationsByPeerId, updatedMedia: &self.currentUpdatedMedia, unsentMessageOperations: ¤tUnsentOperations, updatedPeerReadStateOperations: &self.currentUpdatedSynchronizeReadStateOperations, globalTagsOperations: &self.currentGlobalTagsOperations, pendingActionsOperations: &self.currentPendingMessageActionsOperations, updatedMessageActionsSummaries: &self.currentUpdatedMessageActionsSummaries, updatedMessageTagSummaries: &self.currentUpdatedMessageTagSummaries, invalidateMessageTagSummaries: &self.currentInvalidateMessageTagSummaries, localTagsOperations: &self.currentLocalTagsOperations, timestampBasedMessageAttributesOperations: &self.currentTimestampBasedMessageAttributesOperations, forEachMedia: forEachMedia)
|
if let minTimestamp = minTimestamp, let maxTimestamp = maxTimestamp {
|
||||||
for namespace in self.messageHistoryHoleIndexTable.existingNamespaces(peerId: peerId, holeSpace: .everywhere) where namespaces.contains(namespace) {
|
self.messageHistoryTable.clearHistoryInRange(peerId: peerId, minTimestamp: minTimestamp, maxTimestamp: maxTimestamp, namespaces: namespaces, operationsByPeerId: &self.currentOperationsByPeerId, updatedMedia: &self.currentUpdatedMedia, unsentMessageOperations: ¤tUnsentOperations, updatedPeerReadStateOperations: &self.currentUpdatedSynchronizeReadStateOperations, globalTagsOperations: &self.currentGlobalTagsOperations, pendingActionsOperations: &self.currentPendingMessageActionsOperations, updatedMessageActionsSummaries: &self.currentUpdatedMessageActionsSummaries, updatedMessageTagSummaries: &self.currentUpdatedMessageTagSummaries, invalidateMessageTagSummaries: &self.currentInvalidateMessageTagSummaries, localTagsOperations: &self.currentLocalTagsOperations, timestampBasedMessageAttributesOperations: &self.currentTimestampBasedMessageAttributesOperations, forEachMedia: forEachMedia)
|
||||||
self.messageHistoryHoleIndexTable.remove(peerId: peerId, namespace: namespace, space: .everywhere, range: 1 ... Int32.max - 1, operations: &self.currentPeerHoleOperations)
|
} else {
|
||||||
|
self.messageHistoryTable.clearHistory(peerId: peerId, namespaces: namespaces, operationsByPeerId: &self.currentOperationsByPeerId, updatedMedia: &self.currentUpdatedMedia, unsentMessageOperations: ¤tUnsentOperations, updatedPeerReadStateOperations: &self.currentUpdatedSynchronizeReadStateOperations, globalTagsOperations: &self.currentGlobalTagsOperations, pendingActionsOperations: &self.currentPendingMessageActionsOperations, updatedMessageActionsSummaries: &self.currentUpdatedMessageActionsSummaries, updatedMessageTagSummaries: &self.currentUpdatedMessageTagSummaries, invalidateMessageTagSummaries: &self.currentInvalidateMessageTagSummaries, localTagsOperations: &self.currentLocalTagsOperations, timestampBasedMessageAttributesOperations: &self.currentTimestampBasedMessageAttributesOperations, forEachMedia: forEachMedia)
|
||||||
|
for namespace in self.messageHistoryHoleIndexTable.existingNamespaces(peerId: peerId, holeSpace: .everywhere) where namespaces.contains(namespace) {
|
||||||
|
self.messageHistoryHoleIndexTable.remove(peerId: peerId, namespace: namespace, space: .everywhere, range: 1 ... Int32.max - 1, operations: &self.currentPeerHoleOperations)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4,10 +4,12 @@ import Postbox
|
|||||||
public final class AdMessageAttribute: MessageAttribute {
|
public final class AdMessageAttribute: MessageAttribute {
|
||||||
public let opaqueId: Data
|
public let opaqueId: Data
|
||||||
public let startParam: String?
|
public let startParam: String?
|
||||||
|
public let messageId: MessageId?
|
||||||
|
|
||||||
public init(opaqueId: Data, startParam: String?) {
|
public init(opaqueId: Data, startParam: String?, messageId: MessageId?) {
|
||||||
self.opaqueId = opaqueId
|
self.opaqueId = opaqueId
|
||||||
self.startParam = startParam
|
self.startParam = startParam
|
||||||
|
self.messageId = messageId
|
||||||
}
|
}
|
||||||
|
|
||||||
public init(decoder: PostboxDecoder) {
|
public init(decoder: PostboxDecoder) {
|
||||||
|
@ -8,7 +8,7 @@ func cloudChatAddRemoveChatOperation(transaction: Transaction, peerId: PeerId, r
|
|||||||
transaction.operationLogAddEntry(peerId: peerId, tag: OperationLogTags.CloudChatRemoveMessages, tagLocalIndex: .automatic, tagMergedIndex: .automatic, contents: CloudChatRemoveChatOperation(peerId: peerId, reportChatSpam: reportChatSpam, deleteGloballyIfPossible: deleteGloballyIfPossible, topMessageId: transaction.getTopPeerMessageId(peerId: peerId, namespace: Namespaces.Message.Cloud)))
|
transaction.operationLogAddEntry(peerId: peerId, tag: OperationLogTags.CloudChatRemoveMessages, tagLocalIndex: .automatic, tagMergedIndex: .automatic, contents: CloudChatRemoveChatOperation(peerId: peerId, reportChatSpam: reportChatSpam, deleteGloballyIfPossible: deleteGloballyIfPossible, topMessageId: transaction.getTopPeerMessageId(peerId: peerId, namespace: Namespaces.Message.Cloud)))
|
||||||
}
|
}
|
||||||
|
|
||||||
func cloudChatAddClearHistoryOperation(transaction: Transaction, peerId: PeerId, explicitTopMessageId: MessageId?, type: CloudChatClearHistoryType) {
|
func cloudChatAddClearHistoryOperation(transaction: Transaction, peerId: PeerId, explicitTopMessageId: MessageId?, minTimestamp: Int32?, maxTimestamp: Int32?, type: CloudChatClearHistoryType) {
|
||||||
if type == .scheduledMessages {
|
if type == .scheduledMessages {
|
||||||
var messageIds: [MessageId] = []
|
var messageIds: [MessageId] = []
|
||||||
transaction.withAllMessages(peerId: peerId, namespace: Namespaces.Message.ScheduledCloud) { message -> Bool in
|
transaction.withAllMessages(peerId: peerId, namespace: Namespaces.Message.ScheduledCloud) { message -> Bool in
|
||||||
@ -24,7 +24,7 @@ func cloudChatAddClearHistoryOperation(transaction: Transaction, peerId: PeerId,
|
|||||||
topMessageId = transaction.getTopPeerMessageId(peerId: peerId, namespace: Namespaces.Message.Cloud)
|
topMessageId = transaction.getTopPeerMessageId(peerId: peerId, namespace: Namespaces.Message.Cloud)
|
||||||
}
|
}
|
||||||
if let topMessageId = topMessageId {
|
if let topMessageId = topMessageId {
|
||||||
transaction.operationLogAddEntry(peerId: peerId, tag: OperationLogTags.CloudChatRemoveMessages, tagLocalIndex: .automatic, tagMergedIndex: .automatic, contents: CloudChatClearHistoryOperation(peerId: peerId, topMessageId: topMessageId, type: type))
|
transaction.operationLogAddEntry(peerId: peerId, tag: OperationLogTags.CloudChatRemoveMessages, tagLocalIndex: .automatic, tagMergedIndex: .automatic, contents: CloudChatClearHistoryOperation(peerId: peerId, topMessageId: topMessageId, minTimestamp: minTimestamp, maxTimestamp: maxTimestamp, type: type))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -302,7 +302,7 @@ private func removeChat(transaction: Transaction, postbox: Postbox, network: Net
|
|||||||
}
|
}
|
||||||
let deleteMessages: Signal<Void, NoError>
|
let deleteMessages: Signal<Void, NoError>
|
||||||
if let inputPeer = apiInputPeer(peer), let topMessageId = operation.topMessageId ?? transaction.getTopPeerMessageId(peerId: peer.id, namespace: Namespaces.Message.Cloud) {
|
if let inputPeer = apiInputPeer(peer), let topMessageId = operation.topMessageId ?? transaction.getTopPeerMessageId(peerId: peer.id, namespace: Namespaces.Message.Cloud) {
|
||||||
deleteMessages = requestClearHistory(postbox: postbox, network: network, stateManager: stateManager, inputPeer: inputPeer, maxId: topMessageId.id, justClear: false, type: operation.deleteGloballyIfPossible ? .forEveryone : .forLocalPeer)
|
deleteMessages = requestClearHistory(postbox: postbox, network: network, stateManager: stateManager, inputPeer: inputPeer, maxId: topMessageId.id, justClear: false, minTimestamp: nil, maxTimestamp: nil, type: operation.deleteGloballyIfPossible ? .forEveryone : .forLocalPeer)
|
||||||
} else {
|
} else {
|
||||||
deleteMessages = .complete()
|
deleteMessages = .complete()
|
||||||
}
|
}
|
||||||
@ -326,7 +326,7 @@ private func removeChat(transaction: Transaction, postbox: Postbox, network: Net
|
|||||||
} else {
|
} else {
|
||||||
reportSignal = .complete()
|
reportSignal = .complete()
|
||||||
}
|
}
|
||||||
return requestClearHistory(postbox: postbox, network: network, stateManager: stateManager, inputPeer: inputPeer, maxId: operation.topMessageId?.id ?? Int32.max - 1, justClear: false, type: operation.deleteGloballyIfPossible ? .forEveryone : .forLocalPeer)
|
return requestClearHistory(postbox: postbox, network: network, stateManager: stateManager, inputPeer: inputPeer, maxId: operation.topMessageId?.id ?? Int32.max - 1, justClear: false, minTimestamp: nil, maxTimestamp: nil, type: operation.deleteGloballyIfPossible ? .forEveryone : .forLocalPeer)
|
||||||
|> then(reportSignal)
|
|> then(reportSignal)
|
||||||
|> then(postbox.transaction { transaction -> Void in
|
|> then(postbox.transaction { transaction -> Void in
|
||||||
_internal_clearHistory(transaction: transaction, mediaBox: postbox.mediaBox, peerId: peer.id, namespaces: .not(Namespaces.Message.allScheduled))
|
_internal_clearHistory(transaction: transaction, mediaBox: postbox.mediaBox, peerId: peer.id, namespaces: .not(Namespaces.Message.allScheduled))
|
||||||
@ -339,7 +339,7 @@ private func removeChat(transaction: Transaction, postbox: Postbox, network: Net
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private func requestClearHistory(postbox: Postbox, network: Network, stateManager: AccountStateManager, inputPeer: Api.InputPeer, maxId: Int32, justClear: Bool, type: CloudChatClearHistoryType) -> Signal<Void, NoError> {
|
private func requestClearHistory(postbox: Postbox, network: Network, stateManager: AccountStateManager, inputPeer: Api.InputPeer, maxId: Int32, justClear: Bool, minTimestamp: Int32?, maxTimestamp: Int32?, type: CloudChatClearHistoryType) -> Signal<Void, NoError> {
|
||||||
var flags: Int32 = 0
|
var flags: Int32 = 0
|
||||||
if justClear {
|
if justClear {
|
||||||
flags |= 1 << 0
|
flags |= 1 << 0
|
||||||
@ -347,7 +347,16 @@ private func requestClearHistory(postbox: Postbox, network: Network, stateManage
|
|||||||
if case .forEveryone = type {
|
if case .forEveryone = type {
|
||||||
flags |= 1 << 1
|
flags |= 1 << 1
|
||||||
}
|
}
|
||||||
let signal = network.request(Api.functions.messages.deleteHistory(flags: flags, peer: inputPeer, maxId: maxId, minDate: nil, maxDate: nil))
|
var updatedMaxId = maxId
|
||||||
|
if minTimestamp != nil {
|
||||||
|
flags |= 1 << 2
|
||||||
|
updatedMaxId = 0
|
||||||
|
}
|
||||||
|
if maxTimestamp != nil {
|
||||||
|
flags |= 1 << 3
|
||||||
|
updatedMaxId = 0
|
||||||
|
}
|
||||||
|
let signal = network.request(Api.functions.messages.deleteHistory(flags: flags, peer: inputPeer, maxId: updatedMaxId, minDate: minTimestamp, maxDate: maxTimestamp))
|
||||||
|> map { result -> Api.messages.AffectedHistory? in
|
|> map { result -> Api.messages.AffectedHistory? in
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
@ -378,17 +387,21 @@ private func requestClearHistory(postbox: Postbox, network: Network, stateManage
|
|||||||
private func _internal_clearHistory(transaction: Transaction, postbox: Postbox, network: Network, stateManager: AccountStateManager, peer: Peer, operation: CloudChatClearHistoryOperation) -> Signal<Void, NoError> {
|
private func _internal_clearHistory(transaction: Transaction, postbox: Postbox, network: Network, stateManager: AccountStateManager, peer: Peer, operation: CloudChatClearHistoryOperation) -> Signal<Void, NoError> {
|
||||||
if peer.id.namespace == Namespaces.Peer.CloudGroup || peer.id.namespace == Namespaces.Peer.CloudUser {
|
if peer.id.namespace == Namespaces.Peer.CloudGroup || peer.id.namespace == Namespaces.Peer.CloudUser {
|
||||||
if let inputPeer = apiInputPeer(peer) {
|
if let inputPeer = apiInputPeer(peer) {
|
||||||
return requestClearHistory(postbox: postbox, network: network, stateManager: stateManager, inputPeer: inputPeer, maxId: operation.topMessageId.id, justClear: true, type: operation.type)
|
return requestClearHistory(postbox: postbox, network: network, stateManager: stateManager, inputPeer: inputPeer, maxId: operation.topMessageId.id, justClear: true, minTimestamp: operation.minTimestamp, maxTimestamp: operation.maxTimestamp, type: operation.type)
|
||||||
} else {
|
} else {
|
||||||
return .complete()
|
return .complete()
|
||||||
}
|
}
|
||||||
} else if peer.id.namespace == Namespaces.Peer.CloudChannel, let inputChannel = apiInputChannel(peer) {
|
} else if peer.id.namespace == Namespaces.Peer.CloudChannel, let inputChannel = apiInputChannel(peer) {
|
||||||
return network.request(Api.functions.channels.deleteHistory(channel: inputChannel, maxId: operation.topMessageId.id))
|
if operation.minTimestamp != nil {
|
||||||
|> `catch` { _ -> Signal<Api.Bool, NoError> in
|
|
||||||
return .single(.boolFalse)
|
|
||||||
}
|
|
||||||
|> mapToSignal { _ -> Signal<Void, NoError> in
|
|
||||||
return .complete()
|
return .complete()
|
||||||
|
} else {
|
||||||
|
return network.request(Api.functions.channels.deleteHistory(channel: inputChannel, maxId: operation.topMessageId.id))
|
||||||
|
|> `catch` { _ -> Signal<Api.Bool, NoError> in
|
||||||
|
return .single(.boolFalse)
|
||||||
|
}
|
||||||
|
|> mapToSignal { _ -> Signal<Void, NoError> in
|
||||||
|
return .complete()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
assertionFailure()
|
assertionFailure()
|
||||||
|
@ -112,17 +112,23 @@ public extension CloudChatClearHistoryType {
|
|||||||
public final class CloudChatClearHistoryOperation: PostboxCoding {
|
public final class CloudChatClearHistoryOperation: PostboxCoding {
|
||||||
public let peerId: PeerId
|
public let peerId: PeerId
|
||||||
public let topMessageId: MessageId
|
public let topMessageId: MessageId
|
||||||
|
public let minTimestamp: Int32?
|
||||||
|
public let maxTimestamp: Int32?
|
||||||
public let type: CloudChatClearHistoryType
|
public let type: CloudChatClearHistoryType
|
||||||
|
|
||||||
public init(peerId: PeerId, topMessageId: MessageId, type: CloudChatClearHistoryType) {
|
public init(peerId: PeerId, topMessageId: MessageId, minTimestamp: Int32?, maxTimestamp: Int32?, type: CloudChatClearHistoryType) {
|
||||||
self.peerId = peerId
|
self.peerId = peerId
|
||||||
self.topMessageId = topMessageId
|
self.topMessageId = topMessageId
|
||||||
|
self.minTimestamp = minTimestamp
|
||||||
|
self.maxTimestamp = maxTimestamp
|
||||||
self.type = type
|
self.type = type
|
||||||
}
|
}
|
||||||
|
|
||||||
public init(decoder: PostboxDecoder) {
|
public init(decoder: PostboxDecoder) {
|
||||||
self.peerId = PeerId(decoder.decodeInt64ForKey("p", orElse: 0))
|
self.peerId = PeerId(decoder.decodeInt64ForKey("p", orElse: 0))
|
||||||
self.topMessageId = MessageId(peerId: PeerId(decoder.decodeInt64ForKey("m.p", orElse: 0)), namespace: decoder.decodeInt32ForKey("m.n", orElse: 0), id: decoder.decodeInt32ForKey("m.i", orElse: 0))
|
self.topMessageId = MessageId(peerId: PeerId(decoder.decodeInt64ForKey("m.p", orElse: 0)), namespace: decoder.decodeInt32ForKey("m.n", orElse: 0), id: decoder.decodeInt32ForKey("m.i", orElse: 0))
|
||||||
|
self.minTimestamp = decoder.decodeOptionalInt32ForKey("minTimestamp")
|
||||||
|
self.maxTimestamp = decoder.decodeOptionalInt32ForKey("maxTimestamp")
|
||||||
self.type = CloudChatClearHistoryType(rawValue: decoder.decodeInt32ForKey("type", orElse: 0)) ?? .forLocalPeer
|
self.type = CloudChatClearHistoryType(rawValue: decoder.decodeInt32ForKey("type", orElse: 0)) ?? .forLocalPeer
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -131,6 +137,16 @@ public final class CloudChatClearHistoryOperation: PostboxCoding {
|
|||||||
encoder.encodeInt64(self.topMessageId.peerId.toInt64(), forKey: "m.p")
|
encoder.encodeInt64(self.topMessageId.peerId.toInt64(), forKey: "m.p")
|
||||||
encoder.encodeInt32(self.topMessageId.namespace, forKey: "m.n")
|
encoder.encodeInt32(self.topMessageId.namespace, forKey: "m.n")
|
||||||
encoder.encodeInt32(self.topMessageId.id, forKey: "m.i")
|
encoder.encodeInt32(self.topMessageId.id, forKey: "m.i")
|
||||||
|
if let minTimestamp = self.minTimestamp {
|
||||||
|
encoder.encodeInt32(minTimestamp, forKey: "minTimestamp")
|
||||||
|
} else {
|
||||||
|
encoder.encodeNil(forKey: "minTimestamp")
|
||||||
|
}
|
||||||
|
if let maxTimestamp = self.maxTimestamp {
|
||||||
|
encoder.encodeInt32(maxTimestamp, forKey: "maxTimestamp")
|
||||||
|
} else {
|
||||||
|
encoder.encodeNil(forKey: "maxTimestamp")
|
||||||
|
}
|
||||||
encoder.encodeInt32(self.type.rawValue, forKey: "type")
|
encoder.encodeInt32(self.type.rawValue, forKey: "type")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -111,7 +111,7 @@ private class AdMessagesHistoryContextImpl {
|
|||||||
func toMessage(peerId: PeerId, transaction: Transaction) -> Message {
|
func toMessage(peerId: PeerId, transaction: Transaction) -> Message {
|
||||||
var attributes: [MessageAttribute] = []
|
var attributes: [MessageAttribute] = []
|
||||||
|
|
||||||
attributes.append(AdMessageAttribute(opaqueId: self.opaqueId, startParam: self.startParam))
|
attributes.append(AdMessageAttribute(opaqueId: self.opaqueId, startParam: self.startParam, messageId: self.messageId))
|
||||||
if !self.textEntities.isEmpty {
|
if !self.textEntities.isEmpty {
|
||||||
let attribute = TextEntitiesMessageAttribute(entities: self.textEntities)
|
let attribute = TextEntitiesMessageAttribute(entities: self.textEntities)
|
||||||
attributes.append(attribute)
|
attributes.append(attribute)
|
||||||
|
@ -87,7 +87,24 @@ func _internal_clearHistory(transaction: Transaction, mediaBox: MediaBox, peerId
|
|||||||
let _ = mediaBox.removeCachedResources(Set(resourceIds), force: true).start()
|
let _ = mediaBox.removeCachedResources(Set(resourceIds), force: true).start()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
transaction.clearHistory(peerId, namespaces: namespaces, forEachMedia: { _ in
|
transaction.clearHistory(peerId, minTimestamp: nil, maxTimestamp: nil, namespaces: namespaces, forEachMedia: { _ in
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func _internal_clearHistoryInRange(transaction: Transaction, mediaBox: MediaBox, peerId: PeerId, minTimestamp: Int32, maxTimestamp: Int32, namespaces: MessageIdNamespaces) {
|
||||||
|
if peerId.namespace == Namespaces.Peer.SecretChat {
|
||||||
|
var resourceIds: [MediaResourceId] = []
|
||||||
|
transaction.withAllMessages(peerId: peerId, { message in
|
||||||
|
if message.timestamp >= minTimestamp && message.timestamp <= maxTimestamp {
|
||||||
|
addMessageMediaResourceIdsToRemove(message: message, resourceIds: &resourceIds)
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
})
|
||||||
|
if !resourceIds.isEmpty {
|
||||||
|
let _ = mediaBox.removeCachedResources(Set(resourceIds), force: true).start()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
transaction.clearHistory(peerId, minTimestamp: minTimestamp, maxTimestamp: maxTimestamp, namespaces: namespaces, forEachMedia: { _ in
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -96,10 +96,43 @@ func deleteMessagesInteractively(transaction: Transaction, stateManager: Account
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func _internal_clearHistoryInRangeInteractively(postbox: Postbox, peerId: PeerId, minTimestamp: Int32, maxTimestamp: Int32, type: InteractiveHistoryClearingType) -> Signal<Void, NoError> {
|
||||||
|
return postbox.transaction { transaction -> Void in
|
||||||
|
if peerId.namespace == Namespaces.Peer.CloudUser || peerId.namespace == Namespaces.Peer.CloudGroup || peerId.namespace == Namespaces.Peer.CloudChannel {
|
||||||
|
cloudChatAddClearHistoryOperation(transaction: transaction, peerId: peerId, explicitTopMessageId: nil, minTimestamp: minTimestamp, maxTimestamp: maxTimestamp, type: CloudChatClearHistoryType(type))
|
||||||
|
if type == .scheduledMessages {
|
||||||
|
} else {
|
||||||
|
_internal_clearHistoryInRange(transaction: transaction, mediaBox: postbox.mediaBox, peerId: peerId, minTimestamp: minTimestamp, maxTimestamp: maxTimestamp, namespaces: .not(Namespaces.Message.allScheduled))
|
||||||
|
}
|
||||||
|
} else if peerId.namespace == Namespaces.Peer.SecretChat {
|
||||||
|
/*_internal_clearHistory(transaction: transaction, mediaBox: postbox.mediaBox, peerId: peerId, namespaces: .all)
|
||||||
|
|
||||||
|
if let state = transaction.getPeerChatState(peerId) as? SecretChatState {
|
||||||
|
var layer: SecretChatLayer?
|
||||||
|
switch state.embeddedState {
|
||||||
|
case .terminated, .handshake:
|
||||||
|
break
|
||||||
|
case .basicLayer:
|
||||||
|
layer = .layer8
|
||||||
|
case let .sequenceBasedLayer(sequenceState):
|
||||||
|
layer = sequenceState.layerNegotiationState.activeLayer.secretChatLayer
|
||||||
|
}
|
||||||
|
|
||||||
|
if let layer = layer {
|
||||||
|
let updatedState = addSecretChatOutgoingOperation(transaction: transaction, peerId: peerId, operation: SecretChatOutgoingOperationContents.clearHistory(layer: layer, actionGloballyUniqueId: Int64.random(in: Int64.min ... Int64.max)), state: state)
|
||||||
|
if updatedState != state {
|
||||||
|
transaction.setPeerChatState(peerId, state: updatedState)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}*/
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func _internal_clearHistoryInteractively(postbox: Postbox, peerId: PeerId, type: InteractiveHistoryClearingType) -> Signal<Void, NoError> {
|
func _internal_clearHistoryInteractively(postbox: Postbox, peerId: PeerId, type: InteractiveHistoryClearingType) -> Signal<Void, NoError> {
|
||||||
return postbox.transaction { transaction -> Void in
|
return postbox.transaction { transaction -> Void in
|
||||||
if peerId.namespace == Namespaces.Peer.CloudUser || peerId.namespace == Namespaces.Peer.CloudGroup || peerId.namespace == Namespaces.Peer.CloudChannel {
|
if peerId.namespace == Namespaces.Peer.CloudUser || peerId.namespace == Namespaces.Peer.CloudGroup || peerId.namespace == Namespaces.Peer.CloudChannel {
|
||||||
cloudChatAddClearHistoryOperation(transaction: transaction, peerId: peerId, explicitTopMessageId: nil, type: CloudChatClearHistoryType(type))
|
cloudChatAddClearHistoryOperation(transaction: transaction, peerId: peerId, explicitTopMessageId: nil, minTimestamp: nil, maxTimestamp: nil, type: CloudChatClearHistoryType(type))
|
||||||
if type == .scheduledMessages {
|
if type == .scheduledMessages {
|
||||||
_internal_clearHistory(transaction: transaction, mediaBox: postbox.mediaBox, peerId: peerId, namespaces: .just(Namespaces.Message.allScheduled))
|
_internal_clearHistory(transaction: transaction, mediaBox: postbox.mediaBox, peerId: peerId, namespaces: .just(Namespaces.Message.allScheduled))
|
||||||
} else {
|
} else {
|
||||||
@ -110,7 +143,7 @@ func _internal_clearHistoryInteractively(postbox: Postbox, peerId: PeerId, type:
|
|||||||
|
|
||||||
_internal_clearHistory(transaction: transaction, mediaBox: postbox.mediaBox, peerId: peerId, namespaces: .not(Namespaces.Message.allScheduled))
|
_internal_clearHistory(transaction: transaction, mediaBox: postbox.mediaBox, peerId: peerId, namespaces: .not(Namespaces.Message.allScheduled))
|
||||||
if let cachedData = transaction.getPeerCachedData(peerId: peerId) as? CachedChannelData, let migrationReference = cachedData.migrationReference {
|
if let cachedData = transaction.getPeerCachedData(peerId: peerId) as? CachedChannelData, let migrationReference = cachedData.migrationReference {
|
||||||
cloudChatAddClearHistoryOperation(transaction: transaction, peerId: migrationReference.maxMessageId.peerId, explicitTopMessageId: MessageId(peerId: migrationReference.maxMessageId.peerId, namespace: migrationReference.maxMessageId.namespace, id: migrationReference.maxMessageId.id + 1), type: CloudChatClearHistoryType(type))
|
cloudChatAddClearHistoryOperation(transaction: transaction, peerId: migrationReference.maxMessageId.peerId, explicitTopMessageId: MessageId(peerId: migrationReference.maxMessageId.peerId, namespace: migrationReference.maxMessageId.namespace, id: migrationReference.maxMessageId.id + 1), minTimestamp: nil, maxTimestamp: nil, type: CloudChatClearHistoryType(type))
|
||||||
_internal_clearHistory(transaction: transaction, mediaBox: postbox.mediaBox, peerId: migrationReference.maxMessageId.peerId, namespaces: .all)
|
_internal_clearHistory(transaction: transaction, mediaBox: postbox.mediaBox, peerId: migrationReference.maxMessageId.peerId, namespaces: .all)
|
||||||
}
|
}
|
||||||
if let topIndex = topIndex {
|
if let topIndex = topIndex {
|
||||||
|
@ -581,6 +581,24 @@ public final class SparseMessageCalendar {
|
|||||||
self.loadMore()
|
self.loadMore()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func removeMessagesInRange(minTimestamp: Int32, maxTimestamp: Int32, type: InteractiveHistoryClearingType, completion: @escaping () -> Void) -> Disposable {
|
||||||
|
var removeKeys: [Int32] = []
|
||||||
|
for (id, message) in self.state.messagesByDay {
|
||||||
|
if message.timestamp >= minTimestamp && message.timestamp <= maxTimestamp {
|
||||||
|
removeKeys.append(id)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for id in removeKeys {
|
||||||
|
self.state.messagesByDay.removeValue(forKey: id)
|
||||||
|
}
|
||||||
|
|
||||||
|
self.statePromise.set(.single(self.state))
|
||||||
|
|
||||||
|
return _internal_clearHistoryInRangeInteractively(postbox: self.account.postbox, peerId: self.peerId, minTimestamp: minTimestamp, maxTimestamp: maxTimestamp, type: type).start(completed: {
|
||||||
|
completion()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
private func loadMore() {
|
private func loadMore() {
|
||||||
guard let nextRequestOffset = self.state.nextRequestOffset else {
|
guard let nextRequestOffset = self.state.nextRequestOffset else {
|
||||||
return
|
return
|
||||||
@ -754,4 +772,14 @@ public final class SparseMessageCalendar {
|
|||||||
impl.maybeLoadMore()
|
impl.maybeLoadMore()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public func removeMessagesInRange(minTimestamp: Int32, maxTimestamp: Int32, type: InteractiveHistoryClearingType, completion: @escaping () -> Void) -> Disposable {
|
||||||
|
let disposable = MetaDisposable()
|
||||||
|
|
||||||
|
self.impl.with { impl in
|
||||||
|
disposable.set(impl.removeMessagesInRange(minTimestamp: minTimestamp, maxTimestamp: maxTimestamp, type: type, completion: completion))
|
||||||
|
}
|
||||||
|
|
||||||
|
return disposable
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -68,7 +68,11 @@ final class ChatMessageWebpageBubbleContentNode: ChatMessageBubbleContentNode {
|
|||||||
if let bot = author as? TelegramUser, bot.botInfo != nil, let startParam = adAttribute.startParam {
|
if let bot = author as? TelegramUser, bot.botInfo != nil, let startParam = adAttribute.startParam {
|
||||||
navigationData = .withBotStartPayload(ChatControllerInitialBotStart(payload: startParam, behavior: .interactive))
|
navigationData = .withBotStartPayload(ChatControllerInitialBotStart(payload: startParam, behavior: .interactive))
|
||||||
} else {
|
} else {
|
||||||
navigationData = .chat(textInputState: nil, subject: nil, peekData: nil)
|
var subject: ChatControllerSubject?
|
||||||
|
if let messageId = adAttribute.messageId {
|
||||||
|
subject = .message(id: messageId, highlight: true, timecode: nil)
|
||||||
|
}
|
||||||
|
navigationData = .chat(textInputState: nil, subject: subject, peekData: nil)
|
||||||
}
|
}
|
||||||
item.controllerInteraction.openPeer(author.id, navigationData, nil)
|
item.controllerInteraction.openPeer(author.id, navigationData, nil)
|
||||||
} else {
|
} else {
|
||||||
|
@ -1172,6 +1172,7 @@ private final class SparseItemGridBindingImpl: SparseItemGridBinding, ListShimme
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if let loadSignal = result.loadSignal {
|
if let loadSignal = result.loadSignal {
|
||||||
|
layer.disposable?.dispose()
|
||||||
layer.disposable = (loadSignal
|
layer.disposable = (loadSignal
|
||||||
|> deliverOnMainQueue).start(next: { [weak self, weak layer, weak displayItem] image in
|
|> deliverOnMainQueue).start(next: { [weak self, weak layer, weak displayItem] image in
|
||||||
guard let layer = layer else {
|
guard let layer = layer else {
|
||||||
@ -2167,9 +2168,6 @@ final class PeerInfoVisualMediaPaneNode: ASDisplayNode, PeerInfoPaneNode, UIScro
|
|||||||
func currentTopTimestamp() -> Int32? {
|
func currentTopTimestamp() -> Int32? {
|
||||||
var timestamp: Int32?
|
var timestamp: Int32?
|
||||||
self.itemGrid.forEachVisibleItem { item in
|
self.itemGrid.forEachVisibleItem { item in
|
||||||
if timestamp != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
guard let itemLayer = item.layer as? ItemLayer else {
|
guard let itemLayer = item.layer as? ItemLayer else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user