mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-08-29 00:50:40 +00:00
Add antispam false positive reporting
This commit is contained in:
parent
1750bc5a73
commit
3895daa974
@ -8302,3 +8302,6 @@ Sorry for the inconvenience.";
|
|||||||
|
|
||||||
"CreateTopic.ShowGeneral" = "Show in Topics";
|
"CreateTopic.ShowGeneral" = "Show in Topics";
|
||||||
"CreateTopic.ShowGeneralInfo" = "If the 'General' topic is hidden, group members can pull down in the topic list to view it.";
|
"CreateTopic.ShowGeneralInfo" = "If the 'General' topic is hidden, group members can pull down in the topic list to view it.";
|
||||||
|
|
||||||
|
"Conversation.ContextMenuReportFalsePositive" = "Report False Positive";
|
||||||
|
"Group.AdminLog.AntiSpamFalsePositiveReportedText" = "Telegram moderators will review your report. Thank you!";
|
||||||
|
@ -925,18 +925,20 @@ public struct PremiumConfiguration {
|
|||||||
|
|
||||||
public struct AntiSpamBotConfiguration {
|
public struct AntiSpamBotConfiguration {
|
||||||
public static var defaultValue: AntiSpamBotConfiguration {
|
public static var defaultValue: AntiSpamBotConfiguration {
|
||||||
return AntiSpamBotConfiguration(antiSpamBotId: nil)
|
return AntiSpamBotConfiguration(antiSpamBotId: nil, minimumGroupParticipants: 100)
|
||||||
}
|
}
|
||||||
|
|
||||||
public let antiSpamBotId: EnginePeer.Id?
|
public let antiSpamBotId: EnginePeer.Id?
|
||||||
|
public let minimumGroupParticipants: Int32
|
||||||
|
|
||||||
fileprivate init(antiSpamBotId: EnginePeer.Id?) {
|
fileprivate init(antiSpamBotId: EnginePeer.Id?, minimumGroupParticipants: Int32) {
|
||||||
self.antiSpamBotId = antiSpamBotId
|
self.antiSpamBotId = antiSpamBotId
|
||||||
|
self.minimumGroupParticipants = minimumGroupParticipants
|
||||||
}
|
}
|
||||||
|
|
||||||
public static func with(appConfiguration: AppConfiguration) -> AntiSpamBotConfiguration {
|
public static func with(appConfiguration: AppConfiguration) -> AntiSpamBotConfiguration {
|
||||||
if let data = appConfiguration.data, let string = data["telegram_antispam_user_id"] as? String, let value = Int64(string) {
|
if let data = appConfiguration.data, let botIdString = data["telegram_antispam_user_id"] as? String, let botIdValue = Int64(botIdString), let groupSize = data["telegram_antispam_group_size_min"] as? Double {
|
||||||
return AntiSpamBotConfiguration(antiSpamBotId: EnginePeer.Id(namespace: Namespaces.Peer.CloudUser, id: EnginePeer.Id.Id._internalFromInt64Value(value)))
|
return AntiSpamBotConfiguration(antiSpamBotId: EnginePeer.Id(namespace: Namespaces.Peer.CloudUser, id: EnginePeer.Id.Id._internalFromInt64Value(botIdValue)), minimumGroupParticipants: Int32(groupSize))
|
||||||
} else {
|
} else {
|
||||||
return .defaultValue
|
return .defaultValue
|
||||||
}
|
}
|
||||||
|
@ -3,6 +3,7 @@ import SwiftSignalKit
|
|||||||
|
|
||||||
public struct ChannelAdminEventLogEntry: Comparable {
|
public struct ChannelAdminEventLogEntry: Comparable {
|
||||||
public let stableId: UInt32
|
public let stableId: UInt32
|
||||||
|
public let headerStableId: UInt32
|
||||||
public let event: AdminLogEvent
|
public let event: AdminLogEvent
|
||||||
public let peers: [PeerId: Peer]
|
public let peers: [PeerId: Peer]
|
||||||
|
|
||||||
@ -85,6 +86,7 @@ public final class ChannelAdminEventLogContext {
|
|||||||
private var filter: ChannelAdminEventLogFilter = ChannelAdminEventLogFilter()
|
private var filter: ChannelAdminEventLogFilter = ChannelAdminEventLogFilter()
|
||||||
|
|
||||||
private var nextStableId: UInt32 = 1
|
private var nextStableId: UInt32 = 1
|
||||||
|
private var headerStableIds: [AdminLogEventId: UInt32] = [:]
|
||||||
private var stableIds: [AdminLogEventId: UInt32] = [:]
|
private var stableIds: [AdminLogEventId: UInt32] = [:]
|
||||||
|
|
||||||
private var entries: ([ChannelAdminEventLogEntry], ChannelAdminEventLogFilter) = ([], ChannelAdminEventLogFilter())
|
private var entries: ([ChannelAdminEventLogEntry], ChannelAdminEventLogFilter) = ([], ChannelAdminEventLogFilter())
|
||||||
@ -182,13 +184,13 @@ public final class ChannelAdminEventLogContext {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var entries: [ChannelAdminEventLogEntry] = events.map { event in
|
var entries: [ChannelAdminEventLogEntry] = events.map { event in
|
||||||
return ChannelAdminEventLogEntry(stableId: strongSelf.stableIdForEventId(event.id), event: event, peers: result.peers)
|
return ChannelAdminEventLogEntry(stableId: strongSelf.stableIdForEventId(event.id), headerStableId: strongSelf.headerStableIdForEventId(event.id), event: event, peers: result.peers)
|
||||||
}
|
}
|
||||||
entries.append(contentsOf: strongSelf.entries.0)
|
entries.append(contentsOf: strongSelf.entries.0)
|
||||||
strongSelf.entries = (entries, strongSelf.filter)
|
strongSelf.entries = (entries, strongSelf.filter)
|
||||||
} else {
|
} else {
|
||||||
let entries: [ChannelAdminEventLogEntry] = events.map { event in
|
let entries: [ChannelAdminEventLogEntry] = events.map { event in
|
||||||
return ChannelAdminEventLogEntry(stableId: strongSelf.stableIdForEventId(event.id), event: event, peers: result.peers)
|
return ChannelAdminEventLogEntry(stableId: strongSelf.stableIdForEventId(event.id), headerStableId: strongSelf.headerStableIdForEventId(event.id), event: event, peers: result.peers)
|
||||||
}
|
}
|
||||||
strongSelf.entries = (entries, strongSelf.filter)
|
strongSelf.entries = (entries, strongSelf.filter)
|
||||||
}
|
}
|
||||||
@ -214,4 +216,15 @@ public final class ChannelAdminEventLogContext {
|
|||||||
return value
|
return value
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private func headerStableIdForEventId(_ id: AdminLogEventId) -> UInt32 {
|
||||||
|
if let value = self.headerStableIds[id] {
|
||||||
|
return value
|
||||||
|
} else {
|
||||||
|
let value = self.nextStableId
|
||||||
|
self.nextStableId += 1
|
||||||
|
self.headerStableIds[id] = value
|
||||||
|
return value
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -292,6 +292,10 @@ public extension TelegramEngine {
|
|||||||
return _internal_toggleAntiSpamProtection(account: self.account, peerId: peerId, enabled: enabled)
|
return _internal_toggleAntiSpamProtection(account: self.account, peerId: peerId, enabled: enabled)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public func reportAntiSpamFalsePositive(peerId: PeerId, messageId: MessageId) -> Signal<Bool, NoError> {
|
||||||
|
return _internal_reportAntiSpamFalsePositive(account: self.account, peerId: peerId, messageId: messageId)
|
||||||
|
}
|
||||||
|
|
||||||
public func requestPeerPhotos(peerId: PeerId) -> Signal<[TelegramPeerPhoto], NoError> {
|
public func requestPeerPhotos(peerId: PeerId) -> Signal<[TelegramPeerPhoto], NoError> {
|
||||||
return _internal_requestPeerPhotos(postbox: self.account.postbox, network: self.account.network, peerId: peerId)
|
return _internal_requestPeerPhotos(postbox: self.account.postbox, network: self.account.network, peerId: peerId)
|
||||||
}
|
}
|
||||||
|
12
submodules/TelegramUI/Images.xcassets/Chat/Context Menu/AntiSpam.imageset/Contents.json
vendored
Normal file
12
submodules/TelegramUI/Images.xcassets/Chat/Context Menu/AntiSpam.imageset/Contents.json
vendored
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
{
|
||||||
|
"images" : [
|
||||||
|
{
|
||||||
|
"filename" : "reportfalse_24.pdf",
|
||||||
|
"idiom" : "universal"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"info" : {
|
||||||
|
"author" : "xcode",
|
||||||
|
"version" : 1
|
||||||
|
}
|
||||||
|
}
|
135
submodules/TelegramUI/Images.xcassets/Chat/Context Menu/AntiSpam.imageset/reportfalse_24.pdf
vendored
Normal file
135
submodules/TelegramUI/Images.xcassets/Chat/Context Menu/AntiSpam.imageset/reportfalse_24.pdf
vendored
Normal file
@ -0,0 +1,135 @@
|
|||||||
|
%PDF-1.7
|
||||||
|
|
||||||
|
1 0 obj
|
||||||
|
<< >>
|
||||||
|
endobj
|
||||||
|
|
||||||
|
2 0 obj
|
||||||
|
<< /Length 3 0 R >>
|
||||||
|
stream
|
||||||
|
/DeviceRGB CS
|
||||||
|
/DeviceRGB cs
|
||||||
|
q
|
||||||
|
1.000000 0.000000 -0.000000 1.000000 4.834961 3.335003 cm
|
||||||
|
0.000000 0.000000 0.000000 scn
|
||||||
|
5.861066 15.587957 m
|
||||||
|
6.196899 15.711591 6.498980 15.822798 6.742460 15.912901 c
|
||||||
|
6.938185 15.972766 7.061687 15.999998 7.169050 15.999998 c
|
||||||
|
7.276096 15.999998 7.389237 15.973757 7.604651 15.910002 c
|
||||||
|
8.743544 15.512181 11.235205 14.579237 12.364463 14.129102 c
|
||||||
|
12.722498 13.984460 12.842218 13.892902 12.896966 13.823884 c
|
||||||
|
12.934976 13.775966 13.000000 13.665576 13.000000 13.307275 c
|
||||||
|
13.000000 7.185324 l
|
||||||
|
13.000000 6.553703 12.915850 6.062992 12.747086 5.640941 c
|
||||||
|
12.579326 5.221397 12.313388 4.833261 11.900326 4.426327 c
|
||||||
|
11.044427 3.583125 9.640606 2.731597 7.372818 1.412622 c
|
||||||
|
7.318006 1.381764 7.263755 1.358576 7.218547 1.344114 c
|
||||||
|
7.193927 1.336239 7.177481 1.332685 7.169050 1.331110 c
|
||||||
|
7.160619 1.332685 7.144172 1.336239 7.119552 1.344114 c
|
||||||
|
7.074736 1.358451 7.021033 1.381364 6.966707 1.411822 c
|
||||||
|
4.705894 2.743835 3.299533 3.594983 2.437976 4.437263 c
|
||||||
|
2.022268 4.843668 1.754397 5.229964 1.585310 5.647222 c
|
||||||
|
1.415345 6.066645 1.330000 6.554857 1.330000 7.185324 c
|
||||||
|
1.330000 13.307275 l
|
||||||
|
1.330000 13.662965 1.395993 13.779277 1.436774 13.830870 c
|
||||||
|
1.491529 13.900139 1.610740 13.992070 1.957460 14.125925 c
|
||||||
|
1.957469 14.125902 l
|
||||||
|
1.962718 14.127980 l
|
||||||
|
2.859330 14.482901 4.598611 15.123198 5.860996 15.587932 c
|
||||||
|
5.861066 15.587957 l
|
||||||
|
h
|
||||||
|
7.169050 17.329998 m
|
||||||
|
6.842114 17.329998 6.548457 17.244995 6.332937 17.178432 c
|
||||||
|
6.321291 17.174837 6.309747 17.170919 6.298316 17.166689 c
|
||||||
|
6.058186 17.077799 5.755209 16.966265 5.415772 16.841309 c
|
||||||
|
5.415587 16.841240 l
|
||||||
|
4.154459 16.376986 2.390144 15.727495 1.475762 15.365632 c
|
||||||
|
1.086233 15.215069 0.680177 15.018452 0.393381 14.655631 c
|
||||||
|
0.091951 14.274296 0.000000 13.813374 0.000000 13.307275 c
|
||||||
|
0.000000 7.185324 l
|
||||||
|
0.000000 6.433676 0.101960 5.766401 0.352673 5.147715 c
|
||||||
|
0.604264 4.526862 0.990442 3.992426 1.508224 3.486230 c
|
||||||
|
2.512969 2.503967 4.089810 1.563107 6.296909 0.262775 c
|
||||||
|
6.296864 0.262699 l
|
||||||
|
6.306323 0.257332 l
|
||||||
|
6.547542 0.120480 6.865578 0.000000 7.169050 0.000000 c
|
||||||
|
7.472521 0.000000 7.790557 0.120480 8.031776 0.257332 c
|
||||||
|
8.031796 0.257298 l
|
||||||
|
8.037958 0.260883 l
|
||||||
|
10.255331 1.550500 11.831186 2.491209 12.833723 3.478873 c
|
||||||
|
13.350101 3.987590 13.733150 4.524757 13.982018 5.147135 c
|
||||||
|
14.229882 5.767005 14.330000 6.434830 14.330000 7.185324 c
|
||||||
|
14.330000 13.307275 l
|
||||||
|
14.330000 13.810762 14.241129 14.269478 13.938952 14.650421 c
|
||||||
|
13.653583 15.010178 13.247056 15.207094 12.860974 15.362955 c
|
||||||
|
12.858298 15.364022 l
|
||||||
|
11.707717 15.822705 9.179629 16.769213 8.027948 17.170942 c
|
||||||
|
8.018206 17.174341 8.008386 17.177513 7.998495 17.180454 c
|
||||||
|
7.995981 17.181202 l
|
||||||
|
7.783853 17.244291 7.495684 17.329998 7.169050 17.329998 c
|
||||||
|
h
|
||||||
|
7.165000 12.829998 m
|
||||||
|
7.532269 12.829998 7.830000 12.532268 7.830000 12.164998 c
|
||||||
|
7.830000 7.664998 l
|
||||||
|
7.830000 7.297729 7.532269 6.999998 7.165000 6.999998 c
|
||||||
|
6.797730 6.999998 6.500000 7.297729 6.500000 7.664998 c
|
||||||
|
6.500000 12.164998 l
|
||||||
|
6.500000 12.532268 6.797730 12.829998 7.165000 12.829998 c
|
||||||
|
h
|
||||||
|
8.165000 5.164998 m
|
||||||
|
8.165000 4.612713 7.717285 4.164998 7.165000 4.164998 c
|
||||||
|
6.612715 4.164998 6.165000 4.612713 6.165000 5.164998 c
|
||||||
|
6.165000 5.717283 6.612715 6.164998 7.165000 6.164998 c
|
||||||
|
7.717285 6.164998 8.165000 5.717283 8.165000 5.164998 c
|
||||||
|
h
|
||||||
|
f*
|
||||||
|
n
|
||||||
|
Q
|
||||||
|
|
||||||
|
endstream
|
||||||
|
endobj
|
||||||
|
|
||||||
|
3 0 obj
|
||||||
|
3222
|
||||||
|
endobj
|
||||||
|
|
||||||
|
4 0 obj
|
||||||
|
<< /Annots []
|
||||||
|
/Type /Page
|
||||||
|
/MediaBox [ 0.000000 0.000000 24.000000 24.000000 ]
|
||||||
|
/Resources 1 0 R
|
||||||
|
/Contents 2 0 R
|
||||||
|
/Parent 5 0 R
|
||||||
|
>>
|
||||||
|
endobj
|
||||||
|
|
||||||
|
5 0 obj
|
||||||
|
<< /Kids [ 4 0 R ]
|
||||||
|
/Count 1
|
||||||
|
/Type /Pages
|
||||||
|
>>
|
||||||
|
endobj
|
||||||
|
|
||||||
|
6 0 obj
|
||||||
|
<< /Pages 5 0 R
|
||||||
|
/Type /Catalog
|
||||||
|
>>
|
||||||
|
endobj
|
||||||
|
|
||||||
|
xref
|
||||||
|
0 7
|
||||||
|
0000000000 65535 f
|
||||||
|
0000000010 00000 n
|
||||||
|
0000000034 00000 n
|
||||||
|
0000003312 00000 n
|
||||||
|
0000003335 00000 n
|
||||||
|
0000003508 00000 n
|
||||||
|
0000003582 00000 n
|
||||||
|
trailer
|
||||||
|
<< /ID [ (some) (id) ]
|
||||||
|
/Root 6 0 R
|
||||||
|
/Size 7
|
||||||
|
>>
|
||||||
|
startxref
|
||||||
|
3641
|
||||||
|
%%EOF
|
@ -24,6 +24,8 @@ import UndoUI
|
|||||||
import TelegramCallsUI
|
import TelegramCallsUI
|
||||||
import WallpaperBackgroundNode
|
import WallpaperBackgroundNode
|
||||||
import BotPaymentsUI
|
import BotPaymentsUI
|
||||||
|
import ContextUI
|
||||||
|
import Pasteboard
|
||||||
|
|
||||||
private final class ChatRecentActionsListOpaqueState {
|
private final class ChatRecentActionsListOpaqueState {
|
||||||
let entries: [ChatRecentActionsEntry]
|
let entries: [ChatRecentActionsEntry]
|
||||||
@ -56,13 +58,14 @@ final class ChatRecentActionsControllerNode: ViewControllerTracingNode {
|
|||||||
private var automaticMediaDownloadSettings: MediaAutoDownloadSettings
|
private var automaticMediaDownloadSettings: MediaAutoDownloadSettings
|
||||||
|
|
||||||
private var containerLayout: (ContainerViewLayout, CGFloat)?
|
private var containerLayout: (ContainerViewLayout, CGFloat)?
|
||||||
|
private var visibleAreaInset = UIEdgeInsets()
|
||||||
|
|
||||||
private let backgroundNode: WallpaperBackgroundNode
|
private let backgroundNode: WallpaperBackgroundNode
|
||||||
private let panelBackgroundNode: NavigationBackgroundNode
|
private let panelBackgroundNode: NavigationBackgroundNode
|
||||||
private let panelSeparatorNode: ASDisplayNode
|
private let panelSeparatorNode: ASDisplayNode
|
||||||
private let panelButtonNode: HighlightableButtonNode
|
private let panelButtonNode: HighlightableButtonNode
|
||||||
|
|
||||||
private let listNode: ListView
|
fileprivate let listNode: ListView
|
||||||
private let loadingNode: ChatLoadingNode
|
private let loadingNode: ChatLoadingNode
|
||||||
private let emptyNode: ChatRecentActionsEmptyNode
|
private let emptyNode: ChatRecentActionsEmptyNode
|
||||||
|
|
||||||
@ -86,6 +89,7 @@ final class ChatRecentActionsControllerNode: ViewControllerTracingNode {
|
|||||||
private var adminsDisposable: Disposable?
|
private var adminsDisposable: Disposable?
|
||||||
private var adminsState: ChannelMemberListState?
|
private var adminsState: ChannelMemberListState?
|
||||||
private let banDisposables = DisposableDict<PeerId>()
|
private let banDisposables = DisposableDict<PeerId>()
|
||||||
|
private let reportFalsePositiveDisposables = DisposableDict<MessageId>()
|
||||||
|
|
||||||
private weak var antiSpamTooltipController: UndoOverlayController?
|
private weak var antiSpamTooltipController: UndoOverlayController?
|
||||||
|
|
||||||
@ -258,8 +262,10 @@ final class ChatRecentActionsControllerNode: ViewControllerTracingNode {
|
|||||||
}
|
}
|
||||||
}, openPeerMention: { [weak self] name in
|
}, openPeerMention: { [weak self] name in
|
||||||
self?.openPeerMention(name)
|
self?.openPeerMention(name)
|
||||||
}, openMessageContextMenu: { [weak self] message, selectAll, node, frame, _, location in
|
}, openMessageContextMenu: { [weak self] message, selectAll, node, frame, anyRecognizer, location in
|
||||||
self?.openMessageContextMenu(message: message, selectAll: selectAll, node: node, frame: frame, location: location)
|
let recognizer: TapLongTapOrDoubleTapGestureRecognizer? = anyRecognizer as? TapLongTapOrDoubleTapGestureRecognizer
|
||||||
|
let gesture: ContextGesture? = anyRecognizer as? ContextGesture
|
||||||
|
self?.openMessageContextMenu(message: message, selectAll: selectAll, node: node, frame: frame, recognizer: recognizer, gesture: gesture, location: location)
|
||||||
}, openMessageReactionContextMenu: { _, _, _, _ in
|
}, openMessageReactionContextMenu: { _, _, _, _ in
|
||||||
}, updateMessageReaction: { _, _ in
|
}, updateMessageReaction: { _, _ in
|
||||||
}, activateMessagePinch: { _ in
|
}, activateMessagePinch: { _ in
|
||||||
@ -628,6 +634,7 @@ final class ChatRecentActionsControllerNode: ViewControllerTracingNode {
|
|||||||
self.resolvePeerByNameDisposable.dispose()
|
self.resolvePeerByNameDisposable.dispose()
|
||||||
self.adminsDisposable?.dispose()
|
self.adminsDisposable?.dispose()
|
||||||
self.banDisposables.dispose()
|
self.banDisposables.dispose()
|
||||||
|
self.reportFalsePositiveDisposables.dispose()
|
||||||
}
|
}
|
||||||
|
|
||||||
func updatePresentationData(_ presentationData: PresentationData) {
|
func updatePresentationData(_ presentationData: PresentationData) {
|
||||||
@ -664,6 +671,8 @@ final class ChatRecentActionsControllerNode: ViewControllerTracingNode {
|
|||||||
transition.updateFrame(node: self.panelSeparatorNode, frame: CGRect(origin: CGPoint(x: 0.0, y: layout.size.height - panelHeight), size: CGSize(width: layout.size.width, height: UIScreenPixel)))
|
transition.updateFrame(node: self.panelSeparatorNode, frame: CGRect(origin: CGPoint(x: 0.0, y: layout.size.height - panelHeight), size: CGSize(width: layout.size.width, height: UIScreenPixel)))
|
||||||
transition.updateFrame(node: self.panelButtonNode, frame: CGRect(origin: CGPoint(x: 0.0, y: layout.size.height - panelHeight), size: CGSize(width: layout.size.width, height: intrinsicPanelHeight)))
|
transition.updateFrame(node: self.panelButtonNode, frame: CGRect(origin: CGPoint(x: 0.0, y: layout.size.height - panelHeight), size: CGSize(width: layout.size.width, height: intrinsicPanelHeight)))
|
||||||
|
|
||||||
|
self.visibleAreaInset = UIEdgeInsets(top: 0.0, left: 0.0, bottom: panelHeight, right: 0.0)
|
||||||
|
|
||||||
transition.updateBounds(node: self.listNode, bounds: CGRect(origin: CGPoint(), size: layout.size))
|
transition.updateBounds(node: self.listNode, bounds: CGRect(origin: CGPoint(), size: layout.size))
|
||||||
transition.updatePosition(node: self.listNode, position: CGRect(origin: CGPoint(), size: layout.size).center)
|
transition.updatePosition(node: self.listNode, position: CGRect(origin: CGPoint(), size: layout.size).center)
|
||||||
|
|
||||||
@ -819,15 +828,51 @@ final class ChatRecentActionsControllerNode: ViewControllerTracingNode {
|
|||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
private func openMessageContextMenu(message: Message, selectAll: Bool, node: ASDisplayNode, frame: CGRect, location: CGPoint?) {
|
private func openMessageContextMenu(message: Message, selectAll: Bool, node: ASDisplayNode, frame: CGRect, recognizer: TapLongTapOrDoubleTapGestureRecognizer? = nil, gesture: ContextGesture? = nil, location: CGPoint? = nil) {
|
||||||
var actions: [ContextMenuAction] = []
|
guard let controller = self.controller else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
self.dismissAllTooltips()
|
||||||
|
|
||||||
|
let context = self.context
|
||||||
|
let source: ContextContentSource
|
||||||
|
if let location = location {
|
||||||
|
source = .location(ChatMessageContextLocationContentSource(controller: controller, location: node.view.convert(node.bounds, to: nil).origin.offsetBy(dx: location.x, dy: location.y)))
|
||||||
|
} else {
|
||||||
|
source = .extracted(ChatRecentActionsMessageContextExtractedContentSource(controllerNode: self, message: message, selectAll: selectAll))
|
||||||
|
}
|
||||||
|
|
||||||
|
var actions: [ContextMenuItem] = []
|
||||||
if !message.text.isEmpty {
|
if !message.text.isEmpty {
|
||||||
actions.append(ContextMenuAction(content: .text(title: self.presentationData.strings.Conversation_ContextMenuCopy, accessibilityLabel: self.presentationData.strings.Conversation_ContextMenuCopy), action: {
|
actions.append(
|
||||||
UIPasteboard.general.string = message.text
|
.action(ContextMenuActionItem(text: self.presentationData.strings.Conversation_ContextMenuCopy, icon: { theme in return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Copy"), color: theme.contextMenu.primaryColor) }, action: { [weak self] _, f in
|
||||||
|
f(.default)
|
||||||
let content: UndoOverlayContent = .copy(text: self.presentationData.strings.Conversation_TextCopied)
|
|
||||||
self.presentController(UndoOverlayController(presentationData: self.presentationData, content: content, elevatedLayout: false, animateInAsReplacement: false, action: { _ in return false }), .current, nil)
|
if let strongSelf = self {
|
||||||
}))
|
var messageEntities: [MessageTextEntity]?
|
||||||
|
var restrictedText: String?
|
||||||
|
for attribute in message.attributes {
|
||||||
|
if let attribute = attribute as? TextEntitiesMessageAttribute {
|
||||||
|
messageEntities = attribute.entities
|
||||||
|
}
|
||||||
|
if let attribute = attribute as? RestrictedContentMessageAttribute {
|
||||||
|
restrictedText = attribute.platformText(platform: "ios", contentSettings: context.currentContentSettings.with { $0 }) ?? ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if let restrictedText = restrictedText {
|
||||||
|
storeMessageTextInPasteboard(restrictedText, entities: nil)
|
||||||
|
} else {
|
||||||
|
storeMessageTextInPasteboard(message.text, entities: messageEntities)
|
||||||
|
}
|
||||||
|
|
||||||
|
Queue.mainQueue().after(0.2, {
|
||||||
|
let content: UndoOverlayContent = .copy(text: strongSelf.presentationData.strings.Conversation_TextCopied)
|
||||||
|
strongSelf.presentController(UndoOverlayController(presentationData: strongSelf.presentationData, content: content, elevatedLayout: false, animateInAsReplacement: false, action: { _ in return false }), .current, nil)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}))
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
if let author = message.author, let adminsState = self.adminsState {
|
if let author = message.author, let adminsState = self.adminsState {
|
||||||
@ -847,42 +892,54 @@ final class ChatRecentActionsControllerNode: ViewControllerTracingNode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if canBan {
|
if canBan {
|
||||||
actions.append(ContextMenuAction(content: .text(title: self.presentationData.strings.Conversation_ContextMenuBan, accessibilityLabel: self.presentationData.strings.Conversation_ContextMenuBan), action: { [weak self] in
|
actions.append(
|
||||||
if let strongSelf = self {
|
.action(ContextMenuActionItem(text: self.presentationData.strings.Conversation_ContextMenuBan, icon: { theme in return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Restrict"), color: theme.contextMenu.primaryColor) }, action: { [weak self] _, f in
|
||||||
strongSelf.banDisposables.set((strongSelf.context.engine.peers.fetchChannelParticipant(peerId: strongSelf.peer.id, participantId: author.id)
|
if let strongSelf = self {
|
||||||
|> deliverOnMainQueue).start(next: { participant in
|
f(.default)
|
||||||
if let strongSelf = self {
|
strongSelf.banDisposables.set((strongSelf.context.engine.peers.fetchChannelParticipant(peerId: strongSelf.peer.id, participantId: author.id)
|
||||||
strongSelf.presentController(channelBannedMemberController(context: strongSelf.context, peerId: strongSelf.peer.id, memberId: author.id, initialParticipant: participant, updated: { _ in }, upgradedToSupergroup: { _, f in f() }), .window(.root), ViewControllerPresentationArguments(presentationAnimation: .modalSheet))
|
|> deliverOnMainQueue).start(next: { participant in
|
||||||
}
|
if let strongSelf = self {
|
||||||
}), forKey: author.id)
|
strongSelf.presentController(channelBannedMemberController(context: strongSelf.context, peerId: strongSelf.peer.id, memberId: author.id, initialParticipant: participant, updated: { _ in }, upgradedToSupergroup: { _, f in f() }), .window(.root), ViewControllerPresentationArguments(presentationAnimation: .modalSheet))
|
||||||
}
|
}
|
||||||
}))
|
}), forKey: author.id)
|
||||||
|
}
|
||||||
|
}))
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if !actions.isEmpty {
|
let configuration = AntiSpamBotConfiguration.with(appConfiguration: context.currentAppConfiguration.with { $0 })
|
||||||
let contextMenuController = ContextMenuController(actions: actions)
|
for peer in message.peers {
|
||||||
|
if peer.0 == configuration.antiSpamBotId {
|
||||||
self.controllerInteraction.highlightedState = ChatInterfaceHighlightedState(messageStableId: message.stableId)
|
if !actions.isEmpty {
|
||||||
self.updateItemNodesHighlightedStates(animated: true)
|
actions.insert(.separator, at: 0)
|
||||||
|
|
||||||
contextMenuController.dismissed = { [weak self] in
|
|
||||||
if let strongSelf = self {
|
|
||||||
if strongSelf.controllerInteraction.highlightedState?.messageStableId == message.stableId {
|
|
||||||
strongSelf.controllerInteraction.highlightedState = nil
|
|
||||||
strongSelf.updateItemNodesHighlightedStates(animated: true)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
actions.insert(
|
||||||
|
.action(ContextMenuActionItem(text: self.presentationData.strings.Conversation_ContextMenuReportFalsePositive, icon: { theme in return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/AntiSpam"), color: theme.contextMenu.primaryColor) }, action: { [weak self] _, f in
|
||||||
|
f(.default)
|
||||||
|
|
||||||
|
if let strongSelf = self {
|
||||||
|
strongSelf.reportFalsePositiveDisposables.set((strongSelf.context.engine.peers.reportAntiSpamFalsePositive(peerId: message.id.peerId, messageId: message.id)
|
||||||
|
|> deliverOnMainQueue).start(), forKey: message.id)
|
||||||
|
|
||||||
|
Queue.mainQueue().after(0.2, {
|
||||||
|
let content: UndoOverlayContent = .image(image: UIImage(bundleImageName: "Chat/AntiSpamTooltipIcon")!, title: nil, text: strongSelf.presentationData.strings.Group_AdminLog_AntiSpamFalsePositiveReportedText, undo: false)
|
||||||
|
strongSelf.presentController(UndoOverlayController(presentationData: strongSelf.presentationData, content: content, elevatedLayout: false, animateInAsReplacement: false, action: { _ in return false }), .current, nil)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})), at: 0
|
||||||
|
)
|
||||||
|
|
||||||
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
self.presentController(contextMenuController, .window(.root), ContextMenuControllerPresentationArguments(sourceNodeAndRect: { [weak self, weak node] in
|
|
||||||
if let strongSelf = self, let node = node {
|
|
||||||
return (node, frame, strongSelf, strongSelf.bounds)
|
|
||||||
} else {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
guard !actions.isEmpty else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
let contextController = ContextController(account: self.context.account, presentationData: self.presentationData, source: source, items: .single(ContextController.Items(content: .list(actions))), recognizer: recognizer, gesture: gesture)
|
||||||
|
controller.window?.presentInGlobalOverlay(contextController)
|
||||||
}
|
}
|
||||||
|
|
||||||
private func updateItemNodesHighlightedStates(animated: Bool) {
|
private func updateItemNodesHighlightedStates(animated: Bool) {
|
||||||
@ -1043,4 +1100,70 @@ final class ChatRecentActionsControllerNode: ViewControllerTracingNode {
|
|||||||
return true
|
return true
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func frameForVisibleArea() -> CGRect {
|
||||||
|
let rect = CGRect(origin: CGPoint(x: self.visibleAreaInset.left, y: self.visibleAreaInset.top), size: CGSize(width: self.bounds.size.width - self.visibleAreaInset.left - self.visibleAreaInset.right, height: self.bounds.size.height - self.visibleAreaInset.top - self.visibleAreaInset.bottom))
|
||||||
|
|
||||||
|
return rect
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
final class ChatRecentActionsMessageContextExtractedContentSource: ContextExtractedContentSource {
|
||||||
|
let keepInPlace: Bool = false
|
||||||
|
let ignoreContentTouches: Bool = false
|
||||||
|
let blurBackground: Bool = true
|
||||||
|
|
||||||
|
private weak var controllerNode: ChatRecentActionsControllerNode?
|
||||||
|
private let message: Message
|
||||||
|
private let selectAll: Bool
|
||||||
|
|
||||||
|
var shouldBeDismissed: Signal<Bool, NoError> {
|
||||||
|
return .single(false)
|
||||||
|
}
|
||||||
|
|
||||||
|
init(controllerNode: ChatRecentActionsControllerNode, message: Message, selectAll: Bool) {
|
||||||
|
self.controllerNode = controllerNode
|
||||||
|
self.message = message
|
||||||
|
self.selectAll = selectAll
|
||||||
|
}
|
||||||
|
|
||||||
|
func takeView() -> ContextControllerTakeViewInfo? {
|
||||||
|
guard let controllerNode = self.controllerNode else {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
var result: ContextControllerTakeViewInfo?
|
||||||
|
controllerNode.listNode.forEachItemNode { itemNode in
|
||||||
|
guard let itemNode = itemNode as? ChatMessageItemView else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
guard let item = itemNode.item else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if item.content.contains(where: { $0.0.stableId == self.message.stableId }), let contentNode = itemNode.getMessageContextSourceNode(stableId: self.selectAll ? nil : self.message.stableId) {
|
||||||
|
result = ContextControllerTakeViewInfo(containingItem: .node(contentNode), contentAreaInScreenSpace: controllerNode.convert(controllerNode.frameForVisibleArea(), to: nil))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
func putBack() -> ContextControllerPutBackViewInfo? {
|
||||||
|
guard let controllerNode = self.controllerNode else {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
var result: ContextControllerPutBackViewInfo?
|
||||||
|
controllerNode.listNode.forEachItemNode { itemNode in
|
||||||
|
guard let itemNode = itemNode as? ChatMessageItemView else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
guard let item = itemNode.item else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if item.content.contains(where: { $0.0.stableId == self.message.stableId }) {
|
||||||
|
result = ContextControllerPutBackViewInfo(contentAreaInScreenSpace: controllerNode.convert(controllerNode.frameForVisibleArea(), to: nil))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -144,7 +144,7 @@ struct ChatRecentActionsEntry: Comparable, Identifiable {
|
|||||||
}, to: &text, entities: &entities)
|
}, to: &text, entities: &entities)
|
||||||
}
|
}
|
||||||
let action = TelegramMediaActionType.customText(text: text, entities: entities)
|
let action = TelegramMediaActionType.customText(text: text, entities: entities)
|
||||||
let message = Message(stableId: 0, stableVersion: 0, id: MessageId(peerId: peer.id, namespace: Namespaces.Message.Cloud, id: 1), globallyUniqueId: self.entry.event.id, groupingKey: nil, groupInfo: nil, threadId: nil, timestamp: self.entry.event.date, flags: [.Incoming], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: author, text: "", attributes: [], media: [TelegramMediaAction(action: action)], peers: peers, associatedMessages: SimpleDictionary(), associatedMessageIds: [], associatedMedia: [:], associatedThreadInfo: nil)
|
let message = Message(stableId: self.entry.headerStableId, stableVersion: 0, id: MessageId(peerId: peer.id, namespace: Namespaces.Message.Cloud, id: 1), globallyUniqueId: self.entry.event.id, groupingKey: nil, groupInfo: nil, threadId: nil, timestamp: self.entry.event.date, flags: [.Incoming], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: author, text: "", attributes: [], media: [TelegramMediaAction(action: action)], peers: peers, associatedMessages: SimpleDictionary(), associatedMessageIds: [], associatedMedia: [:], associatedThreadInfo: nil)
|
||||||
return ChatMessageItem(presentationData: self.presentationData, context: context, chatLocation: .peer(id: peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadNetworkType: .cellular, isRecentActions: true, availableReactions: nil, defaultReaction: nil, isPremium: false, accountPeer: nil), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, attributes: ChatMessageEntryAttributes(), location: nil))
|
return ChatMessageItem(presentationData: self.presentationData, context: context, chatLocation: .peer(id: peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadNetworkType: .cellular, isRecentActions: true, availableReactions: nil, defaultReaction: nil, isPremium: false, accountPeer: nil), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, attributes: ChatMessageEntryAttributes(), location: nil))
|
||||||
case .content:
|
case .content:
|
||||||
let peers = SimpleDictionary<PeerId, Peer>()
|
let peers = SimpleDictionary<PeerId, Peer>()
|
||||||
@ -182,7 +182,7 @@ struct ChatRecentActionsEntry: Comparable, Identifiable {
|
|||||||
}, to: &text, entities: &entities)
|
}, to: &text, entities: &entities)
|
||||||
}
|
}
|
||||||
let action: TelegramMediaActionType = TelegramMediaActionType.customText(text: text, entities: entities)
|
let action: TelegramMediaActionType = TelegramMediaActionType.customText(text: text, entities: entities)
|
||||||
let message = Message(stableId: 0, stableVersion: 0, id: MessageId(peerId: peer.id, namespace: Namespaces.Message.Cloud, id: 1), globallyUniqueId: self.entry.event.id, groupingKey: nil, groupInfo: nil, threadId: nil, timestamp: self.entry.event.date, flags: [.Incoming], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: author, text: "", attributes: [], media: [TelegramMediaAction(action: action)], peers: peers, associatedMessages: SimpleDictionary(), associatedMessageIds: [], associatedMedia: [:], associatedThreadInfo: nil)
|
let message = Message(stableId: self.entry.headerStableId, stableVersion: 0, id: MessageId(peerId: peer.id, namespace: Namespaces.Message.Cloud, id: 1), globallyUniqueId: self.entry.event.id, groupingKey: nil, groupInfo: nil, threadId: nil, timestamp: self.entry.event.date, flags: [.Incoming], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: author, text: "", attributes: [], media: [TelegramMediaAction(action: action)], peers: peers, associatedMessages: SimpleDictionary(), associatedMessageIds: [], associatedMedia: [:], associatedThreadInfo: nil)
|
||||||
return ChatMessageItem(presentationData: self.presentationData, context: context, chatLocation: .peer(id: peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadNetworkType: .cellular, isRecentActions: true, availableReactions: nil, defaultReaction: nil, isPremium: false, accountPeer: nil), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, attributes: ChatMessageEntryAttributes(), location: nil))
|
return ChatMessageItem(presentationData: self.presentationData, context: context, chatLocation: .peer(id: peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadNetworkType: .cellular, isRecentActions: true, availableReactions: nil, defaultReaction: nil, isPremium: false, accountPeer: nil), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, attributes: ChatMessageEntryAttributes(), location: nil))
|
||||||
case .content:
|
case .content:
|
||||||
var previousAttributes: [MessageAttribute] = []
|
var previousAttributes: [MessageAttribute] = []
|
||||||
@ -232,7 +232,7 @@ struct ChatRecentActionsEntry: Comparable, Identifiable {
|
|||||||
}, to: &text, entities: &entities)
|
}, to: &text, entities: &entities)
|
||||||
}
|
}
|
||||||
let action: TelegramMediaActionType = TelegramMediaActionType.customText(text: text, entities: entities)
|
let action: TelegramMediaActionType = TelegramMediaActionType.customText(text: text, entities: entities)
|
||||||
let message = Message(stableId: 0, stableVersion: 0, id: MessageId(peerId: peer.id, namespace: Namespaces.Message.Cloud, id: 1), globallyUniqueId: self.entry.event.id, groupingKey: nil, groupInfo: nil, threadId: nil, timestamp: self.entry.event.date, flags: [.Incoming], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: author, text: "", attributes: [], media: [TelegramMediaAction(action: action)], peers: peers, associatedMessages: SimpleDictionary(), associatedMessageIds: [], associatedMedia: [:], associatedThreadInfo: nil)
|
let message = Message(stableId: self.entry.headerStableId, stableVersion: 0, id: MessageId(peerId: peer.id, namespace: Namespaces.Message.Cloud, id: 1), globallyUniqueId: self.entry.event.id, groupingKey: nil, groupInfo: nil, threadId: nil, timestamp: self.entry.event.date, flags: [.Incoming], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: author, text: "", attributes: [], media: [TelegramMediaAction(action: action)], peers: peers, associatedMessages: SimpleDictionary(), associatedMessageIds: [], associatedMedia: [:], associatedThreadInfo: nil)
|
||||||
return ChatMessageItem(presentationData: self.presentationData, context: context, chatLocation: .peer(id: peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadNetworkType: .cellular, isRecentActions: true, availableReactions: nil, defaultReaction: nil, isPremium: false, accountPeer: nil), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, attributes: ChatMessageEntryAttributes(), location: nil))
|
return ChatMessageItem(presentationData: self.presentationData, context: context, chatLocation: .peer(id: peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadNetworkType: .cellular, isRecentActions: true, availableReactions: nil, defaultReaction: nil, isPremium: false, accountPeer: nil), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, attributes: ChatMessageEntryAttributes(), location: nil))
|
||||||
case .content:
|
case .content:
|
||||||
var previousAttributes: [MessageAttribute] = []
|
var previousAttributes: [MessageAttribute] = []
|
||||||
@ -374,7 +374,7 @@ struct ChatRecentActionsEntry: Comparable, Identifiable {
|
|||||||
}, to: &text, entities: &entities)
|
}, to: &text, entities: &entities)
|
||||||
|
|
||||||
let action = TelegramMediaActionType.customText(text: text, entities: entities)
|
let action = TelegramMediaActionType.customText(text: text, entities: entities)
|
||||||
let message = Message(stableId: 0, stableVersion: 0, id: MessageId(peerId: peer.id, namespace: Namespaces.Message.Cloud, id: 1), globallyUniqueId: self.entry.event.id, groupingKey: nil, groupInfo: nil, threadId: nil, timestamp: self.entry.event.date, flags: [.Incoming], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: author, text: "", attributes: [], media: [TelegramMediaAction(action: action)], peers: peers, associatedMessages: SimpleDictionary(), associatedMessageIds: [], associatedMedia: [:], associatedThreadInfo: nil)
|
let message = Message(stableId: self.entry.headerStableId, stableVersion: 0, id: MessageId(peerId: peer.id, namespace: Namespaces.Message.Cloud, id: 1), globallyUniqueId: self.entry.event.id, groupingKey: nil, groupInfo: nil, threadId: nil, timestamp: self.entry.event.date, flags: [.Incoming], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: author, text: "", attributes: [], media: [TelegramMediaAction(action: action)], peers: peers, associatedMessages: SimpleDictionary(), associatedMessageIds: [], associatedMedia: [:], associatedThreadInfo: nil)
|
||||||
return ChatMessageItem(presentationData: self.presentationData, context: context, chatLocation: .peer(id: peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadNetworkType: .cellular, isRecentActions: true, availableReactions: nil, defaultReaction: nil, isPremium: false, accountPeer: nil), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, attributes: ChatMessageEntryAttributes(), location: nil))
|
return ChatMessageItem(presentationData: self.presentationData, context: context, chatLocation: .peer(id: peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadNetworkType: .cellular, isRecentActions: true, availableReactions: nil, defaultReaction: nil, isPremium: false, accountPeer: nil), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, attributes: ChatMessageEntryAttributes(), location: nil))
|
||||||
case .content:
|
case .content:
|
||||||
if let message = message {
|
if let message = message {
|
||||||
@ -459,7 +459,7 @@ struct ChatRecentActionsEntry: Comparable, Identifiable {
|
|||||||
|
|
||||||
let action = TelegramMediaActionType.customText(text: text, entities: entities)
|
let action = TelegramMediaActionType.customText(text: text, entities: entities)
|
||||||
|
|
||||||
let message = Message(stableId: 0, stableVersion: 0, id: MessageId(peerId: peer.id, namespace: Namespaces.Message.Cloud, id: 1), globallyUniqueId: self.entry.event.id, groupingKey: nil, groupInfo: nil, threadId: nil, timestamp: self.entry.event.date, flags: [.Incoming], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: author, text: "", attributes: [], media: [TelegramMediaAction(action: action)], peers: peers, associatedMessages: SimpleDictionary(), associatedMessageIds: [], associatedMedia: [:], associatedThreadInfo: nil)
|
let message = Message(stableId: self.entry.headerStableId, stableVersion: 0, id: MessageId(peerId: peer.id, namespace: Namespaces.Message.Cloud, id: 1), globallyUniqueId: self.entry.event.id, groupingKey: nil, groupInfo: nil, threadId: nil, timestamp: self.entry.event.date, flags: [.Incoming], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: author, text: "", attributes: [], media: [TelegramMediaAction(action: action)], peers: peers, associatedMessages: SimpleDictionary(), associatedMessageIds: [], associatedMedia: [:], associatedThreadInfo: nil)
|
||||||
return ChatMessageItem(presentationData: self.presentationData, context: context, chatLocation: .peer(id: peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadNetworkType: .cellular, isRecentActions: true, availableReactions: nil, defaultReaction: nil, isPremium: false, accountPeer: nil), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, attributes: ChatMessageEntryAttributes(), location: nil))
|
return ChatMessageItem(presentationData: self.presentationData, context: context, chatLocation: .peer(id: peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadNetworkType: .cellular, isRecentActions: true, availableReactions: nil, defaultReaction: nil, isPremium: false, accountPeer: nil), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, attributes: ChatMessageEntryAttributes(), location: nil))
|
||||||
case .content:
|
case .content:
|
||||||
var peers = SimpleDictionary<PeerId, Peer>()
|
var peers = SimpleDictionary<PeerId, Peer>()
|
||||||
@ -502,7 +502,7 @@ struct ChatRecentActionsEntry: Comparable, Identifiable {
|
|||||||
|
|
||||||
let action = TelegramMediaActionType.customText(text: text, entities: entities)
|
let action = TelegramMediaActionType.customText(text: text, entities: entities)
|
||||||
|
|
||||||
let message = Message(stableId: 0, stableVersion: 0, id: MessageId(peerId: peer.id, namespace: Namespaces.Message.Cloud, id: 1), globallyUniqueId: self.entry.event.id, groupingKey: nil, groupInfo: nil, threadId: nil, timestamp: self.entry.event.date, flags: [.Incoming], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: author, text: "", attributes: [], media: [TelegramMediaAction(action: action)], peers: peers, associatedMessages: SimpleDictionary(), associatedMessageIds: [], associatedMedia: [:], associatedThreadInfo: nil)
|
let message = Message(stableId: self.entry.headerStableId, stableVersion: 0, id: MessageId(peerId: peer.id, namespace: Namespaces.Message.Cloud, id: 1), globallyUniqueId: self.entry.event.id, groupingKey: nil, groupInfo: nil, threadId: nil, timestamp: self.entry.event.date, flags: [.Incoming], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: author, text: "", attributes: [], media: [TelegramMediaAction(action: action)], peers: peers, associatedMessages: SimpleDictionary(), associatedMessageIds: [], associatedMedia: [:], associatedThreadInfo: nil)
|
||||||
return ChatMessageItem(presentationData: self.presentationData, context: context, chatLocation: .peer(id: peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadNetworkType: .cellular, isRecentActions: true, availableReactions: nil, defaultReaction: nil, isPremium: false, accountPeer: nil), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, attributes: ChatMessageEntryAttributes(), location: nil))
|
return ChatMessageItem(presentationData: self.presentationData, context: context, chatLocation: .peer(id: peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadNetworkType: .cellular, isRecentActions: true, availableReactions: nil, defaultReaction: nil, isPremium: false, accountPeer: nil), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, attributes: ChatMessageEntryAttributes(), location: nil))
|
||||||
case .content:
|
case .content:
|
||||||
var peers = SimpleDictionary<PeerId, Peer>()
|
var peers = SimpleDictionary<PeerId, Peer>()
|
||||||
@ -526,6 +526,9 @@ struct ChatRecentActionsEntry: Comparable, Identifiable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if let peer = self.entry.peers[self.entry.event.peerId] {
|
||||||
|
peers[peer.id] = peer
|
||||||
|
}
|
||||||
let message = Message(stableId: self.entry.stableId, stableVersion: 0, id: MessageId(peerId: peer.id, namespace: Namespaces.Message.Cloud, id: Int32(bitPattern: self.entry.stableId)), globallyUniqueId: self.entry.event.id, groupingKey: nil, groupInfo: nil, threadId: nil, timestamp: self.entry.event.date, flags: [.Incoming], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: message.effectiveAuthor, text: message.text, attributes: attributes, media: message.media, peers: peers, associatedMessages: SimpleDictionary(), associatedMessageIds: [], associatedMedia: [:], associatedThreadInfo: nil)
|
let message = Message(stableId: self.entry.stableId, stableVersion: 0, id: MessageId(peerId: peer.id, namespace: Namespaces.Message.Cloud, id: Int32(bitPattern: self.entry.stableId)), globallyUniqueId: self.entry.event.id, groupingKey: nil, groupInfo: nil, threadId: nil, timestamp: self.entry.event.date, flags: [.Incoming], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: message.effectiveAuthor, text: message.text, attributes: attributes, media: message.media, peers: peers, associatedMessages: SimpleDictionary(), associatedMessageIds: [], associatedMedia: [:], associatedThreadInfo: nil)
|
||||||
return ChatMessageItem(presentationData: self.presentationData, context: context, chatLocation: .peer(id: peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadNetworkType: .cellular, isRecentActions: true, availableReactions: nil, defaultReaction: nil, isPremium: false, accountPeer: nil), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, attributes: ChatMessageEntryAttributes(), location: nil))
|
return ChatMessageItem(presentationData: self.presentationData, context: context, chatLocation: .peer(id: peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadNetworkType: .cellular, isRecentActions: true, availableReactions: nil, defaultReaction: nil, isPremium: false, accountPeer: nil), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, attributes: ChatMessageEntryAttributes(), location: nil))
|
||||||
}
|
}
|
||||||
@ -1072,7 +1075,7 @@ struct ChatRecentActionsEntry: Comparable, Identifiable {
|
|||||||
|
|
||||||
let action = TelegramMediaActionType.customText(text: text, entities: entities)
|
let action = TelegramMediaActionType.customText(text: text, entities: entities)
|
||||||
|
|
||||||
let message = Message(stableId: 0, stableVersion: 0, id: MessageId(peerId: peer.id, namespace: Namespaces.Message.Cloud, id: 1), globallyUniqueId: self.entry.event.id, groupingKey: nil, groupInfo: nil, threadId: nil, timestamp: self.entry.event.date, flags: [.Incoming], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: author, text: "", attributes: [], media: [TelegramMediaAction(action: action)], peers: peers, associatedMessages: SimpleDictionary(), associatedMessageIds: [], associatedMedia: [:], associatedThreadInfo: nil)
|
let message = Message(stableId: self.entry.headerStableId, stableVersion: 0, id: MessageId(peerId: peer.id, namespace: Namespaces.Message.Cloud, id: 1), globallyUniqueId: self.entry.event.id, groupingKey: nil, groupInfo: nil, threadId: nil, timestamp: self.entry.event.date, flags: [.Incoming], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: author, text: "", attributes: [], media: [TelegramMediaAction(action: action)], peers: peers, associatedMessages: SimpleDictionary(), associatedMessageIds: [], associatedMedia: [:], associatedThreadInfo: nil)
|
||||||
return ChatMessageItem(presentationData: self.presentationData, context: context, chatLocation: .peer(id: peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadNetworkType: .cellular, isRecentActions: true, availableReactions: nil, defaultReaction: nil, isPremium: false, accountPeer: nil), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, attributes: ChatMessageEntryAttributes(), location: nil))
|
return ChatMessageItem(presentationData: self.presentationData, context: context, chatLocation: .peer(id: peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadNetworkType: .cellular, isRecentActions: true, availableReactions: nil, defaultReaction: nil, isPremium: false, accountPeer: nil), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, attributes: ChatMessageEntryAttributes(), location: nil))
|
||||||
case .content:
|
case .content:
|
||||||
var peers = SimpleDictionary<PeerId, Peer>()
|
var peers = SimpleDictionary<PeerId, Peer>()
|
||||||
@ -1634,7 +1637,7 @@ struct ChatRecentActionsEntry: Comparable, Identifiable {
|
|||||||
}, to: &text, entities: &entities)
|
}, to: &text, entities: &entities)
|
||||||
|
|
||||||
let action = TelegramMediaActionType.customText(text: text, entities: entities)
|
let action = TelegramMediaActionType.customText(text: text, entities: entities)
|
||||||
let message = Message(stableId: 0, stableVersion: 0, id: MessageId(peerId: peer.id, namespace: Namespaces.Message.Cloud, id: 1), globallyUniqueId: self.entry.event.id, groupingKey: nil, groupInfo: nil, threadId: nil, timestamp: self.entry.event.date, flags: [.Incoming], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: author, text: "", attributes: [], media: [TelegramMediaAction(action: action)], peers: peers, associatedMessages: SimpleDictionary(), associatedMessageIds: [], associatedMedia: [:], associatedThreadInfo: nil)
|
let message = Message(stableId: self.entry.headerStableId, stableVersion: 0, id: MessageId(peerId: peer.id, namespace: Namespaces.Message.Cloud, id: 1), globallyUniqueId: self.entry.event.id, groupingKey: nil, groupInfo: nil, threadId: nil, timestamp: self.entry.event.date, flags: [.Incoming], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: author, text: "", attributes: [], media: [TelegramMediaAction(action: action)], peers: peers, associatedMessages: SimpleDictionary(), associatedMessageIds: [], associatedMedia: [:], associatedThreadInfo: nil)
|
||||||
return ChatMessageItem(presentationData: self.presentationData, context: context, chatLocation: .peer(id: peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadNetworkType: .cellular, isRecentActions: true, availableReactions: nil, defaultReaction: nil, isPremium: false, accountPeer: nil), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, attributes: ChatMessageEntryAttributes(), location: nil))
|
return ChatMessageItem(presentationData: self.presentationData, context: context, chatLocation: .peer(id: peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadNetworkType: .cellular, isRecentActions: true, availableReactions: nil, defaultReaction: nil, isPremium: false, accountPeer: nil), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, attributes: ChatMessageEntryAttributes(), location: nil))
|
||||||
case .content:
|
case .content:
|
||||||
var peers = SimpleDictionary<PeerId, Peer>()
|
var peers = SimpleDictionary<PeerId, Peer>()
|
||||||
|
Loading…
x
Reference in New Issue
Block a user