mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-11-07 17:30:12 +00:00
Various Improvements
This commit is contained in:
parent
a76672896e
commit
45018fdd27
@ -147,11 +147,13 @@ public struct ChatAvailableMessageActions {
|
|||||||
public var options: ChatAvailableMessageActionOptions
|
public var options: ChatAvailableMessageActionOptions
|
||||||
public var banAuthor: Peer?
|
public var banAuthor: Peer?
|
||||||
public var disableDelete: Bool
|
public var disableDelete: Bool
|
||||||
|
public var isCopyProtected: Bool
|
||||||
|
|
||||||
public init(options: ChatAvailableMessageActionOptions, banAuthor: Peer?, disableDelete: Bool) {
|
public init(options: ChatAvailableMessageActionOptions, banAuthor: Peer?, disableDelete: Bool, isCopyProtected: Bool) {
|
||||||
self.options = options
|
self.options = options
|
||||||
self.banAuthor = banAuthor
|
self.banAuthor = banAuthor
|
||||||
self.disableDelete = disableDelete
|
self.disableDelete = disableDelete
|
||||||
|
self.isCopyProtected = isCopyProtected
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -115,6 +115,8 @@ public final class ChatListSearchContainerNode: SearchDisplayControllerContentNo
|
|||||||
private var selectedFilterKeyPromise = Promise<ChatListSearchFilterEntryId?>()
|
private var selectedFilterKeyPromise = Promise<ChatListSearchFilterEntryId?>()
|
||||||
private var transitionFraction: CGFloat = 0.0
|
private var transitionFraction: CGFloat = 0.0
|
||||||
|
|
||||||
|
private weak var copyProtectionTooltipController: TooltipController?
|
||||||
|
|
||||||
private var didSetReady: Bool = false
|
private var didSetReady: Bool = false
|
||||||
private let _ready = Promise<Void>()
|
private let _ready = Promise<Void>()
|
||||||
public override func ready() -> Signal<Void, NoError> {
|
public override func ready() -> Signal<Void, NoError> {
|
||||||
@ -417,6 +419,8 @@ public final class ChatListSearchContainerNode: SearchDisplayControllerContentNo
|
|||||||
self.presentationDataDisposable?.dispose()
|
self.presentationDataDisposable?.dispose()
|
||||||
self.suggestedFiltersDisposable.dispose()
|
self.suggestedFiltersDisposable.dispose()
|
||||||
self.shareStatusDisposable?.dispose()
|
self.shareStatusDisposable?.dispose()
|
||||||
|
|
||||||
|
self.copyProtectionTooltipController?.dismiss()
|
||||||
}
|
}
|
||||||
|
|
||||||
private func updateState(_ f: (ChatListSearchContainerNodeSearchState) -> ChatListSearchContainerNodeSearchState) {
|
private func updateState(_ f: (ChatListSearchContainerNodeSearchState) -> ChatListSearchContainerNodeSearchState) {
|
||||||
@ -588,6 +592,53 @@ public final class ChatListSearchContainerNode: SearchDisplayControllerContentNo
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
strongSelf.forwardMessages(messageIds: nil)
|
strongSelf.forwardMessages(messageIds: nil)
|
||||||
|
}, displayCopyProtectionTip: { [weak self] node, save in
|
||||||
|
guard let strongSelf = self, let messageIds = strongSelf.stateValue.selectedMessageIds, !messageIds.isEmpty else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
let _ = (strongSelf.context.account.postbox.transaction { transaction -> [EngineMessage] in
|
||||||
|
var messages: [EngineMessage] = []
|
||||||
|
for id in messageIds {
|
||||||
|
if let message = transaction.getMessage(id) {
|
||||||
|
messages.append(EngineMessage(message))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return messages
|
||||||
|
}
|
||||||
|
|> deliverOnMainQueue).start(next: { messages in
|
||||||
|
if let strongSelf = self, !messages.isEmpty {
|
||||||
|
var isChannel = false
|
||||||
|
for message in messages {
|
||||||
|
if let channel = message.peers[message.id.peerId] as? TelegramChannel, case .broadcast = channel.info {
|
||||||
|
isChannel = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let text: String
|
||||||
|
if save {
|
||||||
|
text = isChannel ? strongSelf.presentationData.strings.Conversation_CopyProtectionSavingDisabledChannel : strongSelf.presentationData.strings.Conversation_CopyProtectionSavingDisabledGroup
|
||||||
|
} else {
|
||||||
|
text = isChannel ? strongSelf.presentationData.strings.Conversation_CopyProtectionForwardingDisabledChannel : strongSelf.presentationData.strings.Conversation_CopyProtectionForwardingDisabledGroup
|
||||||
|
}
|
||||||
|
|
||||||
|
strongSelf.copyProtectionTooltipController?.dismiss()
|
||||||
|
let tooltipController = TooltipController(content: .text(text), baseFontSize: strongSelf.presentationData.listsFontSize.baseDisplaySize, dismissByTapOutside: true, dismissImmediatelyOnLayoutUpdate: true)
|
||||||
|
strongSelf.copyProtectionTooltipController = tooltipController
|
||||||
|
tooltipController.dismissed = { [weak tooltipController] _ in
|
||||||
|
if let strongSelf = self, let tooltipController = tooltipController, strongSelf.copyProtectionTooltipController === tooltipController {
|
||||||
|
strongSelf.copyProtectionTooltipController = nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
strongSelf.present?(tooltipController, TooltipControllerPresentationArguments(sourceNodeAndRect: {
|
||||||
|
if let strongSelf = self {
|
||||||
|
let rect = node.view.convert(node.view.bounds, to: strongSelf.view).offsetBy(dx: 0.0, dy: 3.0)
|
||||||
|
return (strongSelf, rect)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
})
|
||||||
})
|
})
|
||||||
selectionPanelNode.chatAvailableMessageActions = { [weak self] messageIds -> Signal<ChatAvailableMessageActions, NoError> in
|
selectionPanelNode.chatAvailableMessageActions = { [weak self] messageIds -> Signal<ChatAvailableMessageActions, NoError> in
|
||||||
guard let strongSelf = self else {
|
guard let strongSelf = self else {
|
||||||
|
|||||||
@ -17,6 +17,7 @@ final class ChatListSearchMessageSelectionPanelNode: ASDisplayNode {
|
|||||||
private let deleteMessages: () -> Void
|
private let deleteMessages: () -> Void
|
||||||
private let shareMessages: () -> Void
|
private let shareMessages: () -> Void
|
||||||
private let forwardMessages: () -> Void
|
private let forwardMessages: () -> Void
|
||||||
|
private let displayCopyProtectionTip: (ASDisplayNode, Bool) -> Void
|
||||||
|
|
||||||
private let separatorNode: ASDisplayNode
|
private let separatorNode: ASDisplayNode
|
||||||
private let backgroundNode: NavigationBackgroundNode
|
private let backgroundNode: NavigationBackgroundNode
|
||||||
@ -60,11 +61,12 @@ final class ChatListSearchMessageSelectionPanelNode: ASDisplayNode {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
init(context: AccountContext, deleteMessages: @escaping () -> Void, shareMessages: @escaping () -> Void, forwardMessages: @escaping () -> Void) {
|
init(context: AccountContext, deleteMessages: @escaping () -> Void, shareMessages: @escaping () -> Void, forwardMessages: @escaping () -> Void, displayCopyProtectionTip: @escaping (ASDisplayNode, Bool) -> Void) {
|
||||||
self.context = context
|
self.context = context
|
||||||
self.deleteMessages = deleteMessages
|
self.deleteMessages = deleteMessages
|
||||||
self.shareMessages = shareMessages
|
self.shareMessages = shareMessages
|
||||||
self.forwardMessages = forwardMessages
|
self.forwardMessages = forwardMessages
|
||||||
|
self.displayCopyProtectionTip = displayCopyProtectionTip
|
||||||
|
|
||||||
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
||||||
self.theme = presentationData.theme
|
self.theme = presentationData.theme
|
||||||
@ -102,8 +104,8 @@ final class ChatListSearchMessageSelectionPanelNode: ASDisplayNode {
|
|||||||
self.addSubnode(self.separatorNode)
|
self.addSubnode(self.separatorNode)
|
||||||
|
|
||||||
self.deleteButton.isEnabled = false
|
self.deleteButton.isEnabled = false
|
||||||
self.forwardButton.isEnabled = false
|
self.forwardButton.isImplicitlyDisabled = true
|
||||||
self.shareButton.isEnabled = false
|
self.shareButton.isImplicitlyDisabled = true
|
||||||
|
|
||||||
self.deleteButton.addTarget(self, action: #selector(self.deleteButtonPressed), forControlEvents: .touchUpInside)
|
self.deleteButton.addTarget(self, action: #selector(self.deleteButtonPressed), forControlEvents: .touchUpInside)
|
||||||
self.forwardButton.addTarget(self, action: #selector(self.forwardButtonPressed), forControlEvents: .touchUpInside)
|
self.forwardButton.addTarget(self, action: #selector(self.forwardButtonPressed), forControlEvents: .touchUpInside)
|
||||||
@ -144,15 +146,15 @@ final class ChatListSearchMessageSelectionPanelNode: ASDisplayNode {
|
|||||||
|
|
||||||
if let actions = self.actions {
|
if let actions = self.actions {
|
||||||
self.deleteButton.isEnabled = false
|
self.deleteButton.isEnabled = false
|
||||||
self.forwardButton.isEnabled = actions.options.contains(.forward)
|
self.forwardButton.isImplicitlyDisabled = !actions.options.contains(.forward)
|
||||||
self.shareButton.isEnabled = false
|
|
||||||
|
|
||||||
self.deleteButton.isEnabled = !actions.options.intersection([.deleteLocally, .deleteGlobally]).isEmpty
|
self.deleteButton.isEnabled = !actions.options.intersection([.deleteLocally, .deleteGlobally]).isEmpty
|
||||||
self.shareButton.isEnabled = !actions.options.intersection([.forward]).isEmpty
|
self.shareButton.isImplicitlyDisabled = actions.options.intersection([.forward]).isEmpty
|
||||||
} else {
|
} else {
|
||||||
self.deleteButton.isEnabled = false
|
self.deleteButton.isEnabled = false
|
||||||
self.forwardButton.isEnabled = false
|
self.forwardButton.isImplicitlyDisabled = true
|
||||||
self.shareButton.isEnabled = false
|
self.shareButton.isImplicitlyDisabled = true
|
||||||
}
|
}
|
||||||
|
|
||||||
self.deleteButton.frame = CGRect(origin: CGPoint(x: leftInset, y: 0.0), size: CGSize(width: 57.0, height: panelHeight))
|
self.deleteButton.frame = CGRect(origin: CGPoint(x: leftInset, y: 0.0), size: CGSize(width: 57.0, height: panelHeight))
|
||||||
@ -173,10 +175,18 @@ final class ChatListSearchMessageSelectionPanelNode: ASDisplayNode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@objc func forwardButtonPressed() {
|
@objc func forwardButtonPressed() {
|
||||||
|
if let actions = self.actions, actions.isCopyProtected {
|
||||||
|
self.displayCopyProtectionTip(self.forwardButton, false)
|
||||||
|
} else {
|
||||||
self.forwardMessages()
|
self.forwardMessages()
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@objc func shareButtonPressed() {
|
@objc func shareButtonPressed() {
|
||||||
|
if let actions = self.actions, actions.isCopyProtected {
|
||||||
|
self.displayCopyProtectionTip(self.shareButton, true)
|
||||||
|
} else {
|
||||||
self.shareMessages()
|
self.shareMessages()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|||||||
@ -89,7 +89,7 @@ open class HighlightableButtonNode: HighlightTrackingButtonNode {
|
|||||||
super.init(pointerStyle: pointerStyle)
|
super.init(pointerStyle: pointerStyle)
|
||||||
|
|
||||||
self.highligthedChanged = { [weak self] highlighted in
|
self.highligthedChanged = { [weak self] highlighted in
|
||||||
if let strongSelf = self {
|
if let strongSelf = self, !strongSelf.isImplicitlyDisabled {
|
||||||
if highlighted {
|
if highlighted {
|
||||||
strongSelf.layer.removeAnimation(forKey: "opacity")
|
strongSelf.layer.removeAnimation(forKey: "opacity")
|
||||||
strongSelf.alpha = 0.4
|
strongSelf.alpha = 0.4
|
||||||
|
|||||||
@ -298,8 +298,9 @@ open class ASButtonNode: ASControlNode {
|
|||||||
|
|
||||||
override open var isHighlighted: Bool {
|
override open var isHighlighted: Bool {
|
||||||
didSet {
|
didSet {
|
||||||
if self.isHighlighted != oldValue {
|
if self.isHighlighted != oldValue && !self.isImplicitlyDisabled {
|
||||||
if self.isHighlighted {
|
let isHighlighted = self.isHighlighted
|
||||||
|
if isHighlighted {
|
||||||
if self.highlightedTitleNode.attributedText != nil {
|
if self.highlightedTitleNode.attributedText != nil {
|
||||||
self.highlightedTitleNode.isHidden = false
|
self.highlightedTitleNode.isHidden = false
|
||||||
self.titleNode.isHidden = true
|
self.titleNode.isHidden = true
|
||||||
@ -349,10 +350,26 @@ open class ASButtonNode: ASControlNode {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
open var isImplicitlyDisabled: Bool = false {
|
||||||
|
didSet {
|
||||||
|
if self.isImplicitlyDisabled != oldValue {
|
||||||
|
self.updateIsEnabled()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
override open var isEnabled: Bool {
|
override open var isEnabled: Bool {
|
||||||
didSet {
|
didSet {
|
||||||
if self.isEnabled != oldValue {
|
if self.isEnabled != oldValue {
|
||||||
if self.isEnabled || self.disabledTitleNode.attributedText == nil {
|
self.updateIsEnabled()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private func updateIsEnabled() {
|
||||||
|
let isEnabled = self.isEnabled && !self.isImplicitlyDisabled
|
||||||
|
|
||||||
|
if isEnabled || self.disabledTitleNode.attributedText == nil {
|
||||||
self.titleNode.isHidden = false
|
self.titleNode.isHidden = false
|
||||||
self.disabledTitleNode.isHidden = true
|
self.disabledTitleNode.isHidden = true
|
||||||
} else {
|
} else {
|
||||||
@ -360,7 +377,7 @@ open class ASButtonNode: ASControlNode {
|
|||||||
self.disabledTitleNode.isHidden = false
|
self.disabledTitleNode.isHidden = false
|
||||||
}
|
}
|
||||||
|
|
||||||
if self.isEnabled || self.disabledImageNode.image == nil {
|
if isEnabled || self.disabledImageNode.image == nil {
|
||||||
self.imageNode.isHidden = false
|
self.imageNode.isHidden = false
|
||||||
self.disabledImageNode.isHidden = true
|
self.disabledImageNode.isHidden = true
|
||||||
} else {
|
} else {
|
||||||
@ -368,8 +385,6 @@ open class ASButtonNode: ASControlNode {
|
|||||||
self.disabledImageNode.isHidden = false
|
self.disabledImageNode.isHidden = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override open func layout() {
|
override open func layout() {
|
||||||
let size = self.bounds.size
|
let size = self.bounds.size
|
||||||
|
|||||||
@ -411,6 +411,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
|||||||
private weak var mediaRestrictedTooltipController: TooltipController?
|
private weak var mediaRestrictedTooltipController: TooltipController?
|
||||||
private var mediaRestrictedTooltipControllerMode = true
|
private var mediaRestrictedTooltipControllerMode = true
|
||||||
private weak var checksTooltipController: TooltipController?
|
private weak var checksTooltipController: TooltipController?
|
||||||
|
private weak var copyProtectionTooltipController: TooltipController?
|
||||||
|
|
||||||
private var currentMessageTooltipScreens: [(TooltipScreen, ListViewItemNode)] = []
|
private var currentMessageTooltipScreens: [(TooltipScreen, ListViewItemNode)] = []
|
||||||
|
|
||||||
@ -7685,6 +7686,37 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
|||||||
})
|
})
|
||||||
}, presentChatRequestAdminInfo: { [weak self] in
|
}, presentChatRequestAdminInfo: { [weak self] in
|
||||||
self?.presentChatRequestAdminInfo()
|
self?.presentChatRequestAdminInfo()
|
||||||
|
}, displayCopyProtectionTip: { [weak self] node, save in
|
||||||
|
if let strongSelf = self, let peer = strongSelf.presentationInterfaceState.renderedPeer?.peer {
|
||||||
|
let isChannel: Bool
|
||||||
|
if let channel = peer as? TelegramChannel, case .broadcast = channel.info {
|
||||||
|
isChannel = true
|
||||||
|
} else {
|
||||||
|
isChannel = false
|
||||||
|
}
|
||||||
|
let text: String
|
||||||
|
if save {
|
||||||
|
text = isChannel ? strongSelf.presentationInterfaceState.strings.Conversation_CopyProtectionSavingDisabledChannel : strongSelf.presentationInterfaceState.strings.Conversation_CopyProtectionSavingDisabledGroup
|
||||||
|
} else {
|
||||||
|
text = isChannel ? strongSelf.presentationInterfaceState.strings.Conversation_CopyProtectionForwardingDisabledChannel : strongSelf.presentationInterfaceState.strings.Conversation_CopyProtectionForwardingDisabledGroup
|
||||||
|
}
|
||||||
|
|
||||||
|
strongSelf.copyProtectionTooltipController?.dismiss()
|
||||||
|
let tooltipController = TooltipController(content: .text(text), baseFontSize: strongSelf.presentationData.listsFontSize.baseDisplaySize, dismissByTapOutside: true, dismissImmediatelyOnLayoutUpdate: true)
|
||||||
|
strongSelf.copyProtectionTooltipController = tooltipController
|
||||||
|
tooltipController.dismissed = { [weak tooltipController] _ in
|
||||||
|
if let strongSelf = self, let tooltipController = tooltipController, strongSelf.copyProtectionTooltipController === tooltipController {
|
||||||
|
strongSelf.copyProtectionTooltipController = nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
strongSelf.present(tooltipController, in: .window(.root), with: TooltipControllerPresentationArguments(sourceNodeAndRect: {
|
||||||
|
if let strongSelf = self {
|
||||||
|
let rect = node.view.convert(node.view.bounds, to: strongSelf.chatDisplayNode.view).offsetBy(dx: 0.0, dy: 3.0)
|
||||||
|
return (strongSelf.chatDisplayNode, rect)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}))
|
||||||
|
}
|
||||||
}, statuses: ChatPanelInterfaceInteractionStatuses(editingMessage: self.editingMessage.get(), startingBot: self.startingBot.get(), unblockingPeer: self.unblockingPeer.get(), searching: self.searching.get(), loadingMessage: self.loadingMessage.get(), inlineSearch: self.performingInlineSearch.get()))
|
}, statuses: ChatPanelInterfaceInteractionStatuses(editingMessage: self.editingMessage.get(), startingBot: self.startingBot.get(), unblockingPeer: self.unblockingPeer.get(), searching: self.searching.get(), loadingMessage: self.loadingMessage.get(), inlineSearch: self.performingInlineSearch.get()))
|
||||||
|
|
||||||
do {
|
do {
|
||||||
@ -13548,6 +13580,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
|||||||
self.mediaRecordingModeTooltipController?.dismiss()
|
self.mediaRecordingModeTooltipController?.dismiss()
|
||||||
self.mediaRestrictedTooltipController?.dismiss()
|
self.mediaRestrictedTooltipController?.dismiss()
|
||||||
self.checksTooltipController?.dismiss()
|
self.checksTooltipController?.dismiss()
|
||||||
|
self.copyProtectionTooltipController?.dismiss()
|
||||||
|
|
||||||
self.window?.forEachController({ controller in
|
self.window?.forEachController({ controller in
|
||||||
if let controller = controller as? UndoOverlayController {
|
if let controller = controller as? UndoOverlayController {
|
||||||
|
|||||||
@ -1285,6 +1285,7 @@ func chatAvailableMessageActionsImpl(postbox: Postbox, accountPeerId: PeerId, me
|
|||||||
var hadPersonalIncoming = false
|
var hadPersonalIncoming = false
|
||||||
var hadBanPeerId = false
|
var hadBanPeerId = false
|
||||||
var disableDelete = false
|
var disableDelete = false
|
||||||
|
var isCopyProtected = false
|
||||||
|
|
||||||
func getPeer(_ peerId: PeerId) -> Peer? {
|
func getPeer(_ peerId: PeerId) -> Peer? {
|
||||||
if let peer = transaction.getPeer(peerId) {
|
if let peer = transaction.getPeer(peerId) {
|
||||||
@ -1306,12 +1307,16 @@ func chatAvailableMessageActionsImpl(postbox: Postbox, accountPeerId: PeerId, me
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
for id in messageIds {
|
for id in messageIds {
|
||||||
let isScheduled = id.namespace == Namespaces.Message.ScheduledCloud
|
let isScheduled = id.namespace == Namespaces.Message.ScheduledCloud
|
||||||
if optionsMap[id] == nil {
|
if optionsMap[id] == nil {
|
||||||
optionsMap[id] = []
|
optionsMap[id] = []
|
||||||
}
|
}
|
||||||
if let message = getMessage(id) {
|
if let message = getMessage(id) {
|
||||||
|
if message.isCopyProtected() {
|
||||||
|
isCopyProtected = true
|
||||||
|
}
|
||||||
for media in message.media {
|
for media in message.media {
|
||||||
if let file = media as? TelegramMediaFile, file.isSticker {
|
if let file = media as? TelegramMediaFile, file.isSticker {
|
||||||
for case let .Sticker(_, packReference, _) in file.attributes {
|
for case let .Sticker(_, packReference, _) in file.attributes {
|
||||||
@ -1501,9 +1506,9 @@ func chatAvailableMessageActionsImpl(postbox: Postbox, accountPeerId: PeerId, me
|
|||||||
if hadPersonalIncoming && optionsMap.values.contains(where: { $0.contains(.deleteGlobally) }) && !reducedOptions.contains(.deleteGlobally) {
|
if hadPersonalIncoming && optionsMap.values.contains(where: { $0.contains(.deleteGlobally) }) && !reducedOptions.contains(.deleteGlobally) {
|
||||||
reducedOptions.insert(.unsendPersonal)
|
reducedOptions.insert(.unsendPersonal)
|
||||||
}
|
}
|
||||||
return ChatAvailableMessageActions(options: reducedOptions, banAuthor: banPeer, disableDelete: disableDelete)
|
return ChatAvailableMessageActions(options: reducedOptions, banAuthor: banPeer, disableDelete: disableDelete, isCopyProtected: isCopyProtected)
|
||||||
} else {
|
} else {
|
||||||
return ChatAvailableMessageActions(options: [], banAuthor: nil, disableDelete: false)
|
return ChatAvailableMessageActions(options: [], banAuthor: nil, disableDelete: false, isCopyProtected: isCopyProtected)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -93,8 +93,8 @@ final class ChatMessageSelectionInputPanelNode: ChatInputPanelNode {
|
|||||||
self.addSubnode(self.shareButton)
|
self.addSubnode(self.shareButton)
|
||||||
self.addSubnode(self.separatorNode)
|
self.addSubnode(self.separatorNode)
|
||||||
|
|
||||||
self.forwardButton.isEnabled = false
|
self.forwardButton.isImplicitlyDisabled = true
|
||||||
self.shareButton.isEnabled = false
|
self.shareButton.isImplicitlyDisabled = true
|
||||||
|
|
||||||
self.deleteButton.addTarget(self, action: #selector(self.deleteButtonPressed), forControlEvents: .touchUpInside)
|
self.deleteButton.addTarget(self, action: #selector(self.deleteButtonPressed), forControlEvents: .touchUpInside)
|
||||||
self.reportButton.addTarget(self, action: #selector(self.reportButtonPressed), forControlEvents: .touchUpInside)
|
self.reportButton.addTarget(self, action: #selector(self.reportButtonPressed), forControlEvents: .touchUpInside)
|
||||||
@ -132,12 +132,20 @@ final class ChatMessageSelectionInputPanelNode: ChatInputPanelNode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@objc func forwardButtonPressed() {
|
@objc func forwardButtonPressed() {
|
||||||
|
if let actions = self.actions, actions.isCopyProtected {
|
||||||
|
self.interfaceInteraction?.displayCopyProtectionTip(self.forwardButton, false)
|
||||||
|
} else {
|
||||||
self.interfaceInteraction?.forwardSelectedMessages()
|
self.interfaceInteraction?.forwardSelectedMessages()
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@objc func shareButtonPressed() {
|
@objc func shareButtonPressed() {
|
||||||
|
if let actions = self.actions, actions.isCopyProtected {
|
||||||
|
self.interfaceInteraction?.displayCopyProtectionTip(self.shareButton, true)
|
||||||
|
} else {
|
||||||
self.interfaceInteraction?.shareSelectedMessages()
|
self.interfaceInteraction?.shareSelectedMessages()
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
override func updateLayout(width: CGFloat, leftInset: CGFloat, rightInset: CGFloat, additionalSideInsets: UIEdgeInsets, maxHeight: CGFloat, isSecondary: Bool, transition: ContainedViewLayoutTransition, interfaceState: ChatPresentationInterfaceState, metrics: LayoutMetrics) -> CGFloat {
|
override func updateLayout(width: CGFloat, leftInset: CGFloat, rightInset: CGFloat, additionalSideInsets: UIEdgeInsets, maxHeight: CGFloat, isSecondary: Bool, transition: ContainedViewLayoutTransition, interfaceState: ChatPresentationInterfaceState, metrics: LayoutMetrics) -> CGFloat {
|
||||||
self.validLayout = (width, leftInset, rightInset, additionalSideInsets, maxHeight, metrics, isSecondary)
|
self.validLayout = (width, leftInset, rightInset, additionalSideInsets, maxHeight, metrics, isSecondary)
|
||||||
@ -150,14 +158,14 @@ final class ChatMessageSelectionInputPanelNode: ChatInputPanelNode {
|
|||||||
if let actions = self.actions {
|
if let actions = self.actions {
|
||||||
self.deleteButton.isEnabled = false
|
self.deleteButton.isEnabled = false
|
||||||
self.reportButton.isEnabled = false
|
self.reportButton.isEnabled = false
|
||||||
self.forwardButton.isEnabled = actions.options.contains(.forward)
|
self.forwardButton.isImplicitlyDisabled = !actions.options.contains(.forward)
|
||||||
|
|
||||||
if self.peerMedia {
|
if self.peerMedia {
|
||||||
self.deleteButton.isEnabled = !actions.options.intersection([.deleteLocally, .deleteGlobally]).isEmpty
|
self.deleteButton.isEnabled = !actions.options.intersection([.deleteLocally, .deleteGlobally]).isEmpty
|
||||||
} else {
|
} else {
|
||||||
self.deleteButton.isEnabled = !actions.disableDelete
|
self.deleteButton.isEnabled = !actions.disableDelete
|
||||||
}
|
}
|
||||||
self.shareButton.isEnabled = !actions.options.intersection([.forward]).isEmpty
|
self.shareButton.isImplicitlyDisabled = actions.options.intersection([.forward]).isEmpty
|
||||||
self.reportButton.isEnabled = !actions.options.intersection([.report]).isEmpty
|
self.reportButton.isEnabled = !actions.options.intersection([.report]).isEmpty
|
||||||
|
|
||||||
if self.peerMedia {
|
if self.peerMedia {
|
||||||
@ -171,8 +179,8 @@ final class ChatMessageSelectionInputPanelNode: ChatInputPanelNode {
|
|||||||
self.deleteButton.isHidden = self.peerMedia
|
self.deleteButton.isHidden = self.peerMedia
|
||||||
self.reportButton.isEnabled = false
|
self.reportButton.isEnabled = false
|
||||||
self.reportButton.isHidden = true
|
self.reportButton.isHidden = true
|
||||||
self.forwardButton.isEnabled = false
|
self.forwardButton.isImplicitlyDisabled = true
|
||||||
self.shareButton.isEnabled = false
|
self.shareButton.isImplicitlyDisabled = true
|
||||||
}
|
}
|
||||||
|
|
||||||
if self.reportButton.isHidden || (self.peerMedia && self.deleteButton.isHidden && self.reportButton.isHidden) {
|
if self.reportButton.isHidden || (self.peerMedia && self.deleteButton.isHidden && self.reportButton.isHidden) {
|
||||||
|
|||||||
@ -136,6 +136,7 @@ final class ChatPanelInterfaceInteraction {
|
|||||||
let openInviteRequests: () -> Void
|
let openInviteRequests: () -> Void
|
||||||
let openSendAsPeer: (ASDisplayNode, ContextGesture?) -> Void
|
let openSendAsPeer: (ASDisplayNode, ContextGesture?) -> Void
|
||||||
let presentChatRequestAdminInfo: () -> Void
|
let presentChatRequestAdminInfo: () -> Void
|
||||||
|
let displayCopyProtectionTip: (ASDisplayNode, Bool) -> Void
|
||||||
let statuses: ChatPanelInterfaceInteractionStatuses?
|
let statuses: ChatPanelInterfaceInteractionStatuses?
|
||||||
|
|
||||||
init(
|
init(
|
||||||
@ -226,6 +227,7 @@ final class ChatPanelInterfaceInteraction {
|
|||||||
openInviteRequests: @escaping () -> Void,
|
openInviteRequests: @escaping () -> Void,
|
||||||
openSendAsPeer: @escaping (ASDisplayNode, ContextGesture?) -> Void,
|
openSendAsPeer: @escaping (ASDisplayNode, ContextGesture?) -> Void,
|
||||||
presentChatRequestAdminInfo: @escaping () -> Void,
|
presentChatRequestAdminInfo: @escaping () -> Void,
|
||||||
|
displayCopyProtectionTip: @escaping (ASDisplayNode, Bool) -> Void,
|
||||||
statuses: ChatPanelInterfaceInteractionStatuses?
|
statuses: ChatPanelInterfaceInteractionStatuses?
|
||||||
) {
|
) {
|
||||||
self.setupReplyMessage = setupReplyMessage
|
self.setupReplyMessage = setupReplyMessage
|
||||||
@ -315,6 +317,7 @@ final class ChatPanelInterfaceInteraction {
|
|||||||
self.openInviteRequests = openInviteRequests
|
self.openInviteRequests = openInviteRequests
|
||||||
self.openSendAsPeer = openSendAsPeer
|
self.openSendAsPeer = openSendAsPeer
|
||||||
self.presentChatRequestAdminInfo = presentChatRequestAdminInfo
|
self.presentChatRequestAdminInfo = presentChatRequestAdminInfo
|
||||||
|
self.displayCopyProtectionTip = displayCopyProtectionTip
|
||||||
self.statuses = statuses
|
self.statuses = statuses
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -411,6 +414,7 @@ final class ChatPanelInterfaceInteraction {
|
|||||||
}, openInviteRequests: {
|
}, openInviteRequests: {
|
||||||
}, openSendAsPeer: { _, _ in
|
}, openSendAsPeer: { _, _ in
|
||||||
}, presentChatRequestAdminInfo: {
|
}, presentChatRequestAdminInfo: {
|
||||||
|
}, displayCopyProtectionTip: { _, _ in
|
||||||
}, statuses: nil)
|
}, statuses: nil)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -148,7 +148,9 @@ final class ChatRecentActionsController: TelegramBaseController {
|
|||||||
}, updateShowSendAsPeers: { _ in
|
}, updateShowSendAsPeers: { _ in
|
||||||
}, openInviteRequests: {
|
}, openInviteRequests: {
|
||||||
}, openSendAsPeer: { _, _ in
|
}, openSendAsPeer: { _, _ in
|
||||||
}, presentChatRequestAdminInfo: {}, statuses: nil)
|
}, presentChatRequestAdminInfo: {
|
||||||
|
}, displayCopyProtectionTip: { _, _ in
|
||||||
|
}, statuses: nil)
|
||||||
|
|
||||||
self.navigationItem.titleView = self.titleView
|
self.navigationItem.titleView = self.titleView
|
||||||
|
|
||||||
|
|||||||
@ -222,18 +222,20 @@ final class PeerInfoSelectionPanelNode: ASDisplayNode {
|
|||||||
private let shareMessages: () -> Void
|
private let shareMessages: () -> Void
|
||||||
private let forwardMessages: () -> Void
|
private let forwardMessages: () -> Void
|
||||||
private let reportMessages: () -> Void
|
private let reportMessages: () -> Void
|
||||||
|
private let displayCopyProtectionTip: (ASDisplayNode, Bool) -> Void
|
||||||
|
|
||||||
let selectionPanel: ChatMessageSelectionInputPanelNode
|
let selectionPanel: ChatMessageSelectionInputPanelNode
|
||||||
let separatorNode: ASDisplayNode
|
let separatorNode: ASDisplayNode
|
||||||
let backgroundNode: NavigationBackgroundNode
|
let backgroundNode: NavigationBackgroundNode
|
||||||
|
|
||||||
init(context: AccountContext, presentationData: PresentationData, peerId: PeerId, deleteMessages: @escaping () -> Void, shareMessages: @escaping () -> Void, forwardMessages: @escaping () -> Void, reportMessages: @escaping () -> Void) {
|
init(context: AccountContext, presentationData: PresentationData, peerId: PeerId, deleteMessages: @escaping () -> Void, shareMessages: @escaping () -> Void, forwardMessages: @escaping () -> Void, reportMessages: @escaping () -> Void, displayCopyProtectionTip: @escaping (ASDisplayNode, Bool) -> Void) {
|
||||||
self.context = context
|
self.context = context
|
||||||
self.peerId = peerId
|
self.peerId = peerId
|
||||||
self.deleteMessages = deleteMessages
|
self.deleteMessages = deleteMessages
|
||||||
self.shareMessages = shareMessages
|
self.shareMessages = shareMessages
|
||||||
self.forwardMessages = forwardMessages
|
self.forwardMessages = forwardMessages
|
||||||
self.reportMessages = reportMessages
|
self.reportMessages = reportMessages
|
||||||
|
self.displayCopyProtectionTip = displayCopyProtectionTip
|
||||||
|
|
||||||
let presentationData = presentationData
|
let presentationData = presentationData
|
||||||
|
|
||||||
@ -337,7 +339,10 @@ final class PeerInfoSelectionPanelNode: ASDisplayNode {
|
|||||||
}, updateShowSendAsPeers: { _ in
|
}, updateShowSendAsPeers: { _ in
|
||||||
}, openInviteRequests: {
|
}, openInviteRequests: {
|
||||||
}, openSendAsPeer: { _, _ in
|
}, openSendAsPeer: { _, _ in
|
||||||
}, presentChatRequestAdminInfo: {}, statuses: nil)
|
}, presentChatRequestAdminInfo: {
|
||||||
|
}, displayCopyProtectionTip: { node, save in
|
||||||
|
displayCopyProtectionTip(node, save)
|
||||||
|
}, statuses: nil)
|
||||||
|
|
||||||
self.selectionPanel.interfaceInteraction = interfaceInteraction
|
self.selectionPanel.interfaceInteraction = interfaceInteraction
|
||||||
|
|
||||||
@ -1507,6 +1512,8 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate
|
|||||||
private let tipsPeerDisposable = MetaDisposable()
|
private let tipsPeerDisposable = MetaDisposable()
|
||||||
private let cachedFaq = Promise<ResolvedUrl?>(nil)
|
private let cachedFaq = Promise<ResolvedUrl?>(nil)
|
||||||
|
|
||||||
|
private weak var copyProtectionTooltipController: TooltipController?
|
||||||
|
|
||||||
private let _ready = Promise<Bool>()
|
private let _ready = Promise<Bool>()
|
||||||
var ready: Promise<Bool> {
|
var ready: Promise<Bool> {
|
||||||
return self._ready
|
return self._ready
|
||||||
@ -2877,6 +2884,8 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate
|
|||||||
self.shareStatusDisposable?.dispose()
|
self.shareStatusDisposable?.dispose()
|
||||||
self.customStatusDisposable?.dispose()
|
self.customStatusDisposable?.dispose()
|
||||||
self.refreshMessageTagStatsDisposable?.dispose()
|
self.refreshMessageTagStatsDisposable?.dispose()
|
||||||
|
|
||||||
|
self.copyProtectionTooltipController?.dismiss()
|
||||||
}
|
}
|
||||||
|
|
||||||
override func didLoad() {
|
override func didLoad() {
|
||||||
@ -6477,6 +6486,37 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate
|
|||||||
}, push: { c in
|
}, push: { c in
|
||||||
self?.controller?.push(c)
|
self?.controller?.push(c)
|
||||||
}, completion: { _, _ in }), in: .window(.root))
|
}, completion: { _, _ in }), in: .window(.root))
|
||||||
|
}, displayCopyProtectionTip: { [weak self] node, save in
|
||||||
|
if let strongSelf = self, let peer = strongSelf.data?.peer {
|
||||||
|
let isChannel: Bool
|
||||||
|
if let channel = peer as? TelegramChannel, case .broadcast = channel.info {
|
||||||
|
isChannel = true
|
||||||
|
} else {
|
||||||
|
isChannel = false
|
||||||
|
}
|
||||||
|
let text: String
|
||||||
|
if save {
|
||||||
|
text = isChannel ? strongSelf.presentationData.strings.Conversation_CopyProtectionSavingDisabledChannel : strongSelf.presentationData.strings.Conversation_CopyProtectionSavingDisabledGroup
|
||||||
|
} else {
|
||||||
|
text = isChannel ? strongSelf.presentationData.strings.Conversation_CopyProtectionForwardingDisabledChannel : strongSelf.presentationData.strings.Conversation_CopyProtectionForwardingDisabledGroup
|
||||||
|
}
|
||||||
|
|
||||||
|
strongSelf.copyProtectionTooltipController?.dismiss()
|
||||||
|
let tooltipController = TooltipController(content: .text(text), baseFontSize: strongSelf.presentationData.listsFontSize.baseDisplaySize, dismissByTapOutside: true, dismissImmediatelyOnLayoutUpdate: true)
|
||||||
|
strongSelf.copyProtectionTooltipController = tooltipController
|
||||||
|
tooltipController.dismissed = { [weak tooltipController] _ in
|
||||||
|
if let strongSelf = self, let tooltipController = tooltipController, strongSelf.copyProtectionTooltipController === tooltipController {
|
||||||
|
strongSelf.copyProtectionTooltipController = nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
strongSelf.controller?.present(tooltipController, in: .window(.root), with: TooltipControllerPresentationArguments(sourceNodeAndRect: {
|
||||||
|
if let strongSelf = self {
|
||||||
|
let rect = node.view.convert(node.view.bounds, to: strongSelf.view).offsetBy(dx: 0.0, dy: 3.0)
|
||||||
|
return (strongSelf, rect)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}))
|
||||||
|
}
|
||||||
})
|
})
|
||||||
self.paneContainerNode.selectionPanelNode = selectionPanelNode
|
self.paneContainerNode.selectionPanelNode = selectionPanelNode
|
||||||
self.paneContainerNode.addSubnode(selectionPanelNode)
|
self.paneContainerNode.addSubnode(selectionPanelNode)
|
||||||
|
|||||||
@ -304,7 +304,9 @@ final class PeerSelectionControllerNode: ASDisplayNode {
|
|||||||
}, updateShowSendAsPeers: { _ in
|
}, updateShowSendAsPeers: { _ in
|
||||||
}, openInviteRequests: {
|
}, openInviteRequests: {
|
||||||
}, openSendAsPeer: { _, _ in
|
}, openSendAsPeer: { _, _ in
|
||||||
}, presentChatRequestAdminInfo: {}, statuses: nil)
|
}, presentChatRequestAdminInfo: {
|
||||||
|
}, displayCopyProtectionTip: { _, _ in
|
||||||
|
}, statuses: nil)
|
||||||
|
|
||||||
self.readyValue.set(self.chatListNode.ready)
|
self.readyValue.set(self.chatListNode.ready)
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user