mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-08-21 13:04:42 +00:00
Implement forward and copy restriction
This commit is contained in:
parent
7b3d1c6f59
commit
003d263ebd
@ -576,7 +576,7 @@ final class ChatItemGalleryFooterContentNode: GalleryFooterContentNode, UIScroll
|
||||
self.currentMessage = message
|
||||
|
||||
let canDelete: Bool
|
||||
var canShare = !message.containsSecretMedia
|
||||
var canShare = !message.containsSecretMedia && !message.isCopyProtected()
|
||||
|
||||
var canFullscreen = false
|
||||
|
||||
|
@ -238,6 +238,14 @@ public extension Message {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
func isCopyProtected() -> Bool {
|
||||
if let channel = self.peers[self.id.peerId] as? TelegramChannel, case let .broadcast(flags) = channel.info, flags.flags.contains(.copyProtectionEnabled) && channel.adminRights == nil {
|
||||
return true
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public extension Message {
|
||||
|
@ -376,36 +376,40 @@ func contextMenuForChatPresentationInterfaceState(chatPresentationInterfaceState
|
||||
|
||||
actions.append(.separator)
|
||||
|
||||
actions.append(.action(ContextMenuActionItem(text: chatPresentationInterfaceState.strings.Conversation_ContextMenuCopy, icon: { theme in
|
||||
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Copy"), color: theme.actionSheet.primaryTextColor)
|
||||
}, action: { _, f in
|
||||
let copyTextWithEntities = {
|
||||
var messageEntities: [MessageTextEntity]?
|
||||
var restrictedText: String?
|
||||
for attribute in message.attributes {
|
||||
if let attribute = attribute as? TextEntitiesMessageAttribute {
|
||||
messageEntities = attribute.entities
|
||||
if message.isCopyProtected() {
|
||||
|
||||
} else {
|
||||
actions.append(.action(ContextMenuActionItem(text: chatPresentationInterfaceState.strings.Conversation_ContextMenuCopy, icon: { theme in
|
||||
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Copy"), color: theme.actionSheet.primaryTextColor)
|
||||
}, action: { _, f in
|
||||
let copyTextWithEntities = {
|
||||
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 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: chatPresentationInterfaceState.strings.Conversation_MessageCopied)
|
||||
controllerInteraction.displayUndo(content)
|
||||
})
|
||||
}
|
||||
|
||||
if let restrictedText = restrictedText {
|
||||
storeMessageTextInPasteboard(restrictedText, entities: nil)
|
||||
} else {
|
||||
storeMessageTextInPasteboard(message.text, entities: messageEntities)
|
||||
}
|
||||
|
||||
Queue.mainQueue().after(0.2, {
|
||||
let content: UndoOverlayContent = .copy(text: chatPresentationInterfaceState.strings.Conversation_MessageCopied)
|
||||
controllerInteraction.displayUndo(content)
|
||||
})
|
||||
}
|
||||
|
||||
copyTextWithEntities()
|
||||
f(.default)
|
||||
})))
|
||||
copyTextWithEntities()
|
||||
f(.default)
|
||||
})))
|
||||
}
|
||||
|
||||
if let author = message.author, let addressName = author.addressName {
|
||||
let link = "https://t.me/\(addressName)"
|
||||
@ -682,7 +686,7 @@ func contextMenuForChatPresentationInterfaceState(chatPresentationInterfaceState
|
||||
resourceAvailable = false
|
||||
}
|
||||
|
||||
if !messages[0].text.isEmpty || resourceAvailable || diceEmoji != nil {
|
||||
if (!messages[0].text.isEmpty || resourceAvailable || diceEmoji != nil) && !messages[0].isCopyProtected() {
|
||||
let message = messages[0]
|
||||
var isExpired = false
|
||||
for media in message.media {
|
||||
@ -763,6 +767,7 @@ func contextMenuForChatPresentationInterfaceState(chatPresentationInterfaceState
|
||||
})))
|
||||
}
|
||||
}
|
||||
|
||||
if resourceAvailable, !message.containsSecretMedia {
|
||||
var mediaReference: AnyMediaReference?
|
||||
var isVideo = false
|
||||
@ -1036,12 +1041,16 @@ func contextMenuForChatPresentationInterfaceState(chatPresentationInterfaceState
|
||||
}
|
||||
|
||||
if data.messageActions.options.contains(.forward) {
|
||||
actions.append(.action(ContextMenuActionItem(text: chatPresentationInterfaceState.strings.Conversation_ContextMenuForward, icon: { theme in
|
||||
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Forward"), color: theme.actionSheet.primaryTextColor)
|
||||
}, action: { _, f in
|
||||
interfaceInteraction.forwardMessages(selectAll ? messages : [message])
|
||||
f(.dismissWithoutContent)
|
||||
})))
|
||||
if let channel = message.peers[message.id.peerId] as? TelegramChannel, case let .broadcast(flags) = channel.info, flags.flags.contains(.copyProtectionEnabled) && channel.adminRights == nil {
|
||||
|
||||
} else {
|
||||
actions.append(.action(ContextMenuActionItem(text: chatPresentationInterfaceState.strings.Conversation_ContextMenuForward, icon: { theme in
|
||||
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Forward"), color: theme.actionSheet.primaryTextColor)
|
||||
}, action: { _, f in
|
||||
interfaceInteraction.forwardMessages(selectAll ? messages : [message])
|
||||
f(.dismissWithoutContent)
|
||||
})))
|
||||
}
|
||||
}
|
||||
|
||||
if data.messageActions.options.contains(.report) {
|
||||
@ -1370,7 +1379,7 @@ func chatAvailableMessageActionsImpl(postbox: Postbox, accountPeerId: PeerId, me
|
||||
}
|
||||
}
|
||||
if !message.containsSecretMedia && !isAction {
|
||||
if message.id.peerId.namespace != Namespaces.Peer.SecretChat {
|
||||
if message.id.peerId.namespace != Namespaces.Peer.SecretChat && !message.isCopyProtected() {
|
||||
if !(message.flags.isSending || message.flags.contains(.Failed)) {
|
||||
optionsMap[id]!.insert(.forward)
|
||||
}
|
||||
|
@ -1037,87 +1037,91 @@ class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePreviewItemNode
|
||||
|
||||
let isFailed = item.content.firstMessage.effectivelyFailed(timestamp: item.context.account.network.getApproximateRemoteTimestamp())
|
||||
|
||||
var needShareButton = false
|
||||
var needsShareButton = false
|
||||
if case .pinnedMessages = item.associatedData.subject {
|
||||
needShareButton = true
|
||||
needsShareButton = true
|
||||
for media in item.message.media {
|
||||
if let _ = media as? TelegramMediaExpiredContent {
|
||||
needShareButton = false
|
||||
needsShareButton = false
|
||||
break
|
||||
}
|
||||
}
|
||||
} else if case let .replyThread(replyThreadMessage) = item.chatLocation, replyThreadMessage.effectiveTopId == item.message.id {
|
||||
needShareButton = false
|
||||
needsShareButton = false
|
||||
allowFullWidth = true
|
||||
} else if isFailed || Namespaces.Message.allScheduled.contains(item.message.id.namespace) {
|
||||
needShareButton = false
|
||||
needsShareButton = false
|
||||
} else if item.message.id.peerId == item.context.account.peerId {
|
||||
if let _ = sourceReference {
|
||||
needShareButton = true
|
||||
needsShareButton = true
|
||||
}
|
||||
} else if item.message.id.peerId.isReplies {
|
||||
needShareButton = false
|
||||
needsShareButton = false
|
||||
} else if item.message.effectivelyIncoming(item.context.account.peerId) {
|
||||
if let _ = sourceReference {
|
||||
needShareButton = true
|
||||
needsShareButton = true
|
||||
}
|
||||
|
||||
if let peer = item.message.peers[item.message.id.peerId] {
|
||||
if let channel = peer as? TelegramChannel {
|
||||
if case .broadcast = channel.info {
|
||||
needShareButton = true
|
||||
needsShareButton = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if let info = item.message.forwardInfo {
|
||||
if let author = info.author as? TelegramUser, let _ = author.botInfo, !item.message.media.isEmpty && !(item.message.media.first is TelegramMediaAction) {
|
||||
needShareButton = true
|
||||
needsShareButton = true
|
||||
} else if let author = info.author as? TelegramChannel, case .broadcast = author.info {
|
||||
needShareButton = true
|
||||
needsShareButton = true
|
||||
}
|
||||
}
|
||||
|
||||
if !needShareButton, let author = item.message.author as? TelegramUser, let _ = author.botInfo, !item.message.media.isEmpty && !(item.message.media.first is TelegramMediaAction) {
|
||||
needShareButton = true
|
||||
if !needsShareButton, let author = item.message.author as? TelegramUser, let _ = author.botInfo, !item.message.media.isEmpty && !(item.message.media.first is TelegramMediaAction) {
|
||||
needsShareButton = true
|
||||
}
|
||||
if !needShareButton {
|
||||
if !needsShareButton {
|
||||
loop: for media in item.message.media {
|
||||
if media is TelegramMediaGame || media is TelegramMediaInvoice {
|
||||
needShareButton = true
|
||||
needsShareButton = true
|
||||
break loop
|
||||
} else if let media = media as? TelegramMediaWebpage, case .Loaded = media.content {
|
||||
needShareButton = true
|
||||
needsShareButton = true
|
||||
break loop
|
||||
}
|
||||
}
|
||||
} else {
|
||||
loop: for media in item.message.media {
|
||||
if media is TelegramMediaAction {
|
||||
needShareButton = false
|
||||
needsShareButton = false
|
||||
break loop
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if item.message.isCopyProtected() {
|
||||
needsShareButton = false
|
||||
}
|
||||
}
|
||||
|
||||
if isPreview {
|
||||
needShareButton = false
|
||||
needsShareButton = false
|
||||
}
|
||||
let isAd = item.content.firstMessage.adAttribute != nil
|
||||
if isAd {
|
||||
needShareButton = false
|
||||
needsShareButton = false
|
||||
}
|
||||
|
||||
var tmpWidth: CGFloat
|
||||
if allowFullWidth {
|
||||
tmpWidth = baseWidth
|
||||
if needShareButton || isAd {
|
||||
if needsShareButton || isAd {
|
||||
tmpWidth -= 38.0
|
||||
}
|
||||
} else {
|
||||
tmpWidth = layoutConstants.bubble.maximumWidthFill.widthFor(baseWidth)
|
||||
if (needShareButton || isAd) && tmpWidth + 32.0 > baseWidth {
|
||||
if (needsShareButton || isAd) && tmpWidth + 32.0 > baseWidth {
|
||||
tmpWidth = baseWidth - 32.0
|
||||
}
|
||||
}
|
||||
@ -2031,7 +2035,7 @@ class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePreviewItemNode
|
||||
contentContainerNodeFrames: contentContainerNodeFrames,
|
||||
mosaicStatusOrigin: mosaicStatusOrigin,
|
||||
mosaicStatusSizeAndApply: mosaicStatusSizeAndApply,
|
||||
needsShareButton: needShareButton
|
||||
needsShareButton: needsShareButton
|
||||
)
|
||||
})
|
||||
}
|
||||
|
@ -70,7 +70,6 @@ final class ChatMessageSelectionInputPanelNode: ChatInputPanelNode {
|
||||
self.forwardButton.accessibilityLabel = strings.VoiceOver_MessageContextForward
|
||||
|
||||
self.shareButton = HighlightableButtonNode(pointerStyle: .default)
|
||||
self.shareButton.isEnabled = false
|
||||
self.shareButton.isAccessibilityElement = true
|
||||
self.shareButton.accessibilityLabel = strings.VoiceOver_MessageContextShare
|
||||
|
||||
@ -95,6 +94,7 @@ final class ChatMessageSelectionInputPanelNode: ChatInputPanelNode {
|
||||
self.addSubnode(self.separatorNode)
|
||||
|
||||
self.forwardButton.isEnabled = false
|
||||
self.shareButton.isEnabled = false
|
||||
|
||||
self.deleteButton.addTarget(self, action: #selector(self.deleteButtonPressed), forControlEvents: .touchUpInside)
|
||||
self.reportButton.addTarget(self, action: #selector(self.reportButtonPressed), forControlEvents: .touchUpInside)
|
||||
@ -116,6 +116,8 @@ final class ChatMessageSelectionInputPanelNode: ChatInputPanelNode {
|
||||
self.reportButton.setImage(generateTintedImage(image: UIImage(bundleImageName: "Chat/Input/Accessory Panels/MessageSelectionReport"), color: theme.chat.inputPanel.panelControlDisabledColor), for: [.disabled])
|
||||
self.forwardButton.setImage(generateTintedImage(image: UIImage(bundleImageName: "Chat/Input/Accessory Panels/MessageSelectionForward"), color: theme.chat.inputPanel.panelControlAccentColor), for: [.normal])
|
||||
self.forwardButton.setImage(generateTintedImage(image: UIImage(bundleImageName: "Chat/Input/Accessory Panels/MessageSelectionForward"), color: theme.chat.inputPanel.panelControlDisabledColor), for: [.disabled])
|
||||
self.shareButton.setImage(generateTintedImage(image: UIImage(bundleImageName: "Chat/Input/Accessory Panels/MessageSelectionAction"), color: theme.chat.inputPanel.panelControlAccentColor), for: [.normal])
|
||||
self.shareButton.setImage(generateTintedImage(image: UIImage(bundleImageName: "Chat/Input/Accessory Panels/MessageSelectionAction"), color: theme.chat.inputPanel.panelControlDisabledColor), for: [.disabled])
|
||||
|
||||
self.separatorNode.backgroundColor = theme.chat.inputPanel.panelSeparatorColor
|
||||
}
|
||||
@ -149,7 +151,6 @@ final class ChatMessageSelectionInputPanelNode: ChatInputPanelNode {
|
||||
self.deleteButton.isEnabled = false
|
||||
self.reportButton.isEnabled = false
|
||||
self.forwardButton.isEnabled = actions.options.contains(.forward)
|
||||
self.shareButton.isEnabled = false
|
||||
|
||||
if self.peerMedia {
|
||||
self.deleteButton.isEnabled = !actions.options.intersection([.deleteLocally, .deleteGlobally]).isEmpty
|
||||
|
@ -1191,6 +1191,7 @@ private func editingItems(data: PeerInfoScreenData?, context: AccountContext, pr
|
||||
case groupLocation
|
||||
case peerPublicSettings
|
||||
case peerSettings
|
||||
case peerAdditionalSettings
|
||||
case peerActions
|
||||
}
|
||||
|
||||
@ -1278,7 +1279,7 @@ private func editingItems(data: PeerInfoScreenData?, context: AccountContext, pr
|
||||
}))
|
||||
items[.peerSettings]!.append(PeerInfoScreenCommentItem(id: ItemSignMessagesHelp, text: presentationData.strings.Channel_SignMessages_Help))
|
||||
|
||||
items[.peerSettings]!.append(PeerInfoScreenSwitchItem(id: ItemCopyProtection, text: "Disable Forwards", value: messagesCopyProtection, icon: UIImage(bundleImageName: "Chat/Info/GroupSignIcon"), toggled: { value in
|
||||
items[.peerAdditionalSettings]!.append(PeerInfoScreenSwitchItem(id: ItemCopyProtection, text: "Disable Forwards", value: messagesCopyProtection, icon: UIImage(bundleImageName: "Chat/Info/GroupSignIcon"), toggled: { value in
|
||||
interaction.editingToggleChannelMessageCopyProtection(value)
|
||||
}))
|
||||
}
|
||||
@ -1851,7 +1852,9 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate
|
||||
})))
|
||||
}
|
||||
|
||||
if message.id.peerId.namespace != Namespaces.Peer.SecretChat {
|
||||
if let channel = message.peers[message.id.peerId] as? TelegramChannel, case let .broadcast(flags) = channel.info, flags.flags.contains(.copyProtectionEnabled) && channel.adminRights == nil {
|
||||
|
||||
} else if message.id.peerId.namespace != Namespaces.Peer.SecretChat {
|
||||
items.append(.action(ContextMenuActionItem(text: strongSelf.presentationData.strings.Conversation_ContextMenuForward, icon: { theme in generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Forward"), color: theme.contextMenu.primaryColor) }, action: { c, _ in
|
||||
c.dismiss(completion: {
|
||||
if let strongSelf = self {
|
||||
@ -1987,7 +1990,9 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate
|
||||
})
|
||||
})))
|
||||
|
||||
if message.id.peerId.namespace != Namespaces.Peer.SecretChat {
|
||||
if message.isCopyProtected() {
|
||||
|
||||
} else if message.id.peerId.namespace != Namespaces.Peer.SecretChat {
|
||||
items.append(.action(ContextMenuActionItem(text: strings.Conversation_ContextMenuForward, icon: { theme in generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Forward"), color: theme.contextMenu.primaryColor) }, action: { c, f in
|
||||
c.dismiss(completion: {
|
||||
if let strongSelf = self {
|
||||
|
Loading…
x
Reference in New Issue
Block a user