Display error when sharing to a slowmode-restricted group

This commit is contained in:
Peter 2019-07-29 19:07:45 +03:00
parent bda8c53d41
commit 53de2b9dc0
8 changed files with 168 additions and 108 deletions

View File

@ -3749,20 +3749,21 @@ public final class ChatController: TelegramController, GalleryHiddenMediaTarget,
self.failedMessageEventsDisposable.set((self.context.account.pendingMessageManager.failedMessageEvents(peerId: peerId)
|> deliverOnMainQueue).start(next: { [weak self] reason in
if let strongSelf = self {
let subjectFlags: TelegramChatBannedRightsFlags = .banSendMedia
let text: String
let moreInfo: Bool
switch reason {
case .flood:
text = strongSelf.presentationData.strings.Conversation_SendMessageErrorFlood
moreInfo = true
case .publicBan:
text = strongSelf.presentationData.strings.Conversation_SendMessageErrorGroupRestricted
moreInfo = true
case .mediaRestricted:
strongSelf.interfaceInteraction?.displayRestrictedInfo(.mediaRecording, .alert)
return
case .flood:
text = strongSelf.presentationData.strings.Conversation_SendMessageErrorFlood
moreInfo = true
case .publicBan:
text = strongSelf.presentationData.strings.Conversation_SendMessageErrorGroupRestricted
moreInfo = true
case .mediaRestricted:
strongSelf.interfaceInteraction?.displayRestrictedInfo(.mediaRecording, .alert)
return
case .slowmodeActive:
text = strongSelf.presentationData.strings.Chat_SlowmodeSendError
moreInfo = false
}
let actions: [TextAlertAction]
if moreInfo {
@ -5826,7 +5827,7 @@ public final class ChatController: TelegramController, GalleryHiddenMediaTarget,
return nil
}
return strongSelf.context.account.pendingMessageManager.pendingMessageStatus(id)
|> mapToSignal { status -> Signal<Bool, NoError> in
|> mapToSignal { status, _ -> Signal<Bool, NoError> in
if status != nil {
return .never()
} else {

View File

@ -195,7 +195,7 @@ class ChatMessageInteractiveInstantVideoNode: ASDisplayNode {
var updatedPlaybackStatus: Signal<FileMediaResourceStatus, NoError>?
if let updatedFile = updatedFile, updatedMedia || updatedMessageId {
updatedPlaybackStatus = combineLatest(messageFileMediaResourceStatus(context: item.context, file: updatedFile, message: item.message, isRecentActions: item.associatedData.isRecentActions), item.context.account.pendingMessageManager.pendingMessageStatus(item.message.id))
updatedPlaybackStatus = combineLatest(messageFileMediaResourceStatus(context: item.context, file: updatedFile, message: item.message, isRecentActions: item.associatedData.isRecentActions), item.context.account.pendingMessageManager.pendingMessageStatus(item.message.id) |> map { $0.0 })
|> map { resourceStatus, pendingStatus -> FileMediaResourceStatus in
if let pendingStatus = pendingStatus {
var progress = pendingStatus.progress

View File

@ -555,7 +555,7 @@ final class ChatMessageInteractiveMediaNode: ASDisplayNode {
if statusUpdated {
if let image = media as? TelegramMediaImage {
if message.flags.isSending {
updatedStatusSignal = combineLatest(chatMessagePhotoStatus(context: context, messageId: message.id, photoReference: .message(message: MessageReference(message), media: image)), context.account.pendingMessageManager.pendingMessageStatus(message.id))
updatedStatusSignal = combineLatest(chatMessagePhotoStatus(context: context, messageId: message.id, photoReference: .message(message: MessageReference(message), media: image)), context.account.pendingMessageManager.pendingMessageStatus(message.id) |> map { $0.0 })
|> map { resourceStatus, pendingStatus -> (MediaResourceStatus, MediaResourceStatus?) in
if let pendingStatus = pendingStatus {
let adjustedProgress = max(pendingStatus.progress, 0.027)
@ -571,7 +571,7 @@ final class ChatMessageInteractiveMediaNode: ASDisplayNode {
}
}
} else if let file = media as? TelegramMediaFile {
updatedStatusSignal = combineLatest(messageMediaFileStatus(context: context, messageId: message.id, file: file), context.account.pendingMessageManager.pendingMessageStatus(message.id))
updatedStatusSignal = combineLatest(messageMediaFileStatus(context: context, messageId: message.id, file: file), context.account.pendingMessageManager.pendingMessageStatus(message.id) |> map { $0.0 })
|> map { resourceStatus, pendingStatus -> (MediaResourceStatus, MediaResourceStatus?) in
if let pendingStatus = pendingStatus {
let adjustedProgress = max(pendingStatus.progress, 0.027)

View File

@ -52,7 +52,7 @@ func messageFileMediaResourceStatus(context: AccountContext, file: TelegramMedia
}
if message.flags.isSending {
return combineLatest(messageMediaFileStatus(context: context, messageId: message.id, file: file), context.account.pendingMessageManager.pendingMessageStatus(message.id), playbackStatus)
return combineLatest(messageMediaFileStatus(context: context, messageId: message.id, file: file), context.account.pendingMessageManager.pendingMessageStatus(message.id) |> map { $0.0 }, playbackStatus)
|> map { resourceStatus, pendingStatus, playbackStatus -> FileMediaResourceStatus in
let mediaStatus: FileMediaResourceMediaStatus
if let playbackStatus = playbackStatus {

View File

@ -663,7 +663,7 @@ public class PeerMediaCollectionController: TelegramController {
return nil
}
return strongSelf.context.account.pendingMessageManager.pendingMessageStatus(id)
|> mapToSignal { status -> Signal<Bool, NoError> in
|> mapToSignal { status, _ -> Signal<Bool, NoError> in
if status != nil {
return .never()
} else {

View File

@ -340,6 +340,11 @@ public final class ShareController: ViewController {
override public func loadDisplayNode() {
self.displayNode = ShareControllerNode(sharedContext: self.sharedContext, defaultAction: self.defaultAction, requestLayout: { [weak self] transition in
self?.requestLayout(transition: transition)
}, presentError: { [weak self] title, text in
guard let strongSelf = self else {
return
}
strongSelf.present(standardTextAlertController(theme: AlertControllerTheme(presentationTheme: strongSelf.presentationData.theme), title: title, text: text, actions: [TextAlertAction(type: .defaultAction, title: strongSelf.presentationData.strings.Common_OK, action: {})]), in: .window(.root))
}, externalShare: self.externalShare, immediateExternalShare: self.immediateExternalShare)
self.controllerNode.dismiss = { [weak self] shared in
self?.presentingViewController?.dismiss(animated: false, completion: nil)
@ -353,98 +358,141 @@ public final class ShareController: ViewController {
})
}
self.controllerNode.share = { [weak self] text, peerIds in
if let strongSelf = self {
switch strongSelf.subject {
case let .url(url):
for peerId in peerIds {
var messages: [EnqueueMessage] = []
if !text.isEmpty {
messages.append(.message(text: text, attributes: [], mediaReference: nil, replyToMessageId: nil, localGroupingKey: nil))
}
messages.append(.message(text: url, attributes: [], mediaReference: nil, replyToMessageId: nil, localGroupingKey: nil))
let _ = enqueueMessages(account: strongSelf.currentAccount, peerId: peerId, messages: messages).start()
}
return .complete()
case let .text(string):
for peerId in peerIds {
var messages: [EnqueueMessage] = []
if !text.isEmpty {
messages.append(.message(text: text, attributes: [], mediaReference: nil, replyToMessageId: nil, localGroupingKey: nil))
}
messages.append(.message(text: string, attributes: [], mediaReference: nil, replyToMessageId: nil, localGroupingKey: nil))
let _ = enqueueMessages(account: strongSelf.currentAccount, peerId: peerId, messages: messages).start()
}
return .complete()
case let .quote(string, url):
for peerId in peerIds {
var messages: [EnqueueMessage] = []
if !text.isEmpty {
messages.append(.message(text: text, attributes: [], mediaReference: nil, replyToMessageId: nil, localGroupingKey: nil))
}
let attributedText = NSMutableAttributedString(string: string, attributes: [ChatTextInputAttributes.italic: true as NSNumber])
attributedText.append(NSAttributedString(string: "\n\n\(url)"))
let entities = generateChatInputTextEntities(attributedText)
messages.append(.message(text: attributedText.string, attributes: [TextEntitiesMessageAttribute(entities: entities)], mediaReference: nil, replyToMessageId: nil, localGroupingKey: nil))
let _ = enqueueMessages(account: strongSelf.currentAccount, peerId: peerId, messages: messages).start()
}
return .complete()
case let .image(representations):
for peerId in peerIds {
var messages: [EnqueueMessage] = []
if !text.isEmpty {
messages.append(.message(text: text, attributes: [], mediaReference: nil, replyToMessageId: nil, localGroupingKey: nil))
}
messages.append(.message(text: "", attributes: [], mediaReference: .standalone(media: TelegramMediaImage(imageId: MediaId(namespace: Namespaces.Media.LocalImage, id: arc4random64()), representations: representations.map({ $0.representation }), immediateThumbnailData: nil, reference: nil, partialReference: nil)), replyToMessageId: nil, localGroupingKey: nil))
let _ = enqueueMessages(account: strongSelf.currentAccount, peerId: peerId, messages: messages).start()
}
return .complete()
case let .media(mediaReference):
for peerId in peerIds {
var messages: [EnqueueMessage] = []
if !text.isEmpty {
messages.append(.message(text: text, attributes: [], mediaReference: nil, replyToMessageId: nil, localGroupingKey: nil))
}
messages.append(.message(text: "", attributes: [], mediaReference: mediaReference, replyToMessageId: nil, localGroupingKey: nil))
let _ = enqueueMessages(account: strongSelf.currentAccount, peerId: peerId, messages: messages).start()
}
return .complete()
case let .mapMedia(media):
for peerId in peerIds {
var messages: [EnqueueMessage] = []
if !text.isEmpty {
messages.append(.message(text: text, attributes: [], mediaReference: nil, replyToMessageId: nil, localGroupingKey: nil))
}
messages.append(.message(text: "", attributes: [], mediaReference: .standalone(media: media), replyToMessageId: nil, localGroupingKey: nil))
let _ = enqueueMessages(account: strongSelf.currentAccount, peerId: peerId, messages: messages).start()
}
return .complete()
case let .messages(messages):
for peerId in peerIds {
var messagesToEnqueue: [EnqueueMessage] = []
if !text.isEmpty {
messagesToEnqueue.append(.message(text: text, attributes: [], mediaReference: nil, replyToMessageId: nil, localGroupingKey: nil))
}
for message in messages {
messagesToEnqueue.append(.forward(source: message.id, grouping: .auto))
}
let _ = enqueueMessages(account: strongSelf.currentAccount, peerId: peerId, messages: messagesToEnqueue).start()
}
return .single(.done)
case let .fromExternal(f):
return f(peerIds, text, strongSelf.currentAccount)
|> map { state -> ShareState in
switch state {
case .preparing:
return .preparing
case let .progress(value):
return .progress(value)
case .done:
return .done
}
}
guard let strongSelf = self else {
return .complete()
}
var shareSignals: [Signal<[MessageId?], NoError>] = []
switch strongSelf.subject {
case let .url(url):
for peerId in peerIds {
var messages: [EnqueueMessage] = []
if !text.isEmpty {
messages.append(.message(text: text, attributes: [], mediaReference: nil, replyToMessageId: nil, localGroupingKey: nil))
}
messages.append(.message(text: url, attributes: [], mediaReference: nil, replyToMessageId: nil, localGroupingKey: nil))
shareSignals.append(enqueueMessages(account: strongSelf.currentAccount, peerId: peerId, messages: messages))
}
case let .text(string):
for peerId in peerIds {
var messages: [EnqueueMessage] = []
if !text.isEmpty {
messages.append(.message(text: text, attributes: [], mediaReference: nil, replyToMessageId: nil, localGroupingKey: nil))
}
messages.append(.message(text: string, attributes: [], mediaReference: nil, replyToMessageId: nil, localGroupingKey: nil))
shareSignals.append(enqueueMessages(account: strongSelf.currentAccount, peerId: peerId, messages: messages))
}
case let .quote(string, url):
for peerId in peerIds {
var messages: [EnqueueMessage] = []
if !text.isEmpty {
messages.append(.message(text: text, attributes: [], mediaReference: nil, replyToMessageId: nil, localGroupingKey: nil))
}
let attributedText = NSMutableAttributedString(string: string, attributes: [ChatTextInputAttributes.italic: true as NSNumber])
attributedText.append(NSAttributedString(string: "\n\n\(url)"))
let entities = generateChatInputTextEntities(attributedText)
messages.append(.message(text: attributedText.string, attributes: [TextEntitiesMessageAttribute(entities: entities)], mediaReference: nil, replyToMessageId: nil, localGroupingKey: nil))
shareSignals.append(enqueueMessages(account: strongSelf.currentAccount, peerId: peerId, messages: messages))
}
case let .image(representations):
for peerId in peerIds {
var messages: [EnqueueMessage] = []
if !text.isEmpty {
messages.append(.message(text: text, attributes: [], mediaReference: nil, replyToMessageId: nil, localGroupingKey: nil))
}
messages.append(.message(text: "", attributes: [], mediaReference: .standalone(media: TelegramMediaImage(imageId: MediaId(namespace: Namespaces.Media.LocalImage, id: arc4random64()), representations: representations.map({ $0.representation }), immediateThumbnailData: nil, reference: nil, partialReference: nil)), replyToMessageId: nil, localGroupingKey: nil))
shareSignals.append(enqueueMessages(account: strongSelf.currentAccount, peerId: peerId, messages: messages))
}
case let .media(mediaReference):
for peerId in peerIds {
var messages: [EnqueueMessage] = []
if !text.isEmpty {
messages.append(.message(text: text, attributes: [], mediaReference: nil, replyToMessageId: nil, localGroupingKey: nil))
}
messages.append(.message(text: "", attributes: [], mediaReference: mediaReference, replyToMessageId: nil, localGroupingKey: nil))
shareSignals.append(enqueueMessages(account: strongSelf.currentAccount, peerId: peerId, messages: messages))
}
case let .mapMedia(media):
for peerId in peerIds {
var messages: [EnqueueMessage] = []
if !text.isEmpty {
messages.append(.message(text: text, attributes: [], mediaReference: nil, replyToMessageId: nil, localGroupingKey: nil))
}
messages.append(.message(text: "", attributes: [], mediaReference: .standalone(media: media), replyToMessageId: nil, localGroupingKey: nil))
shareSignals.append(enqueueMessages(account: strongSelf.currentAccount, peerId: peerId, messages: messages))
}
case let .messages(messages):
for peerId in peerIds {
var messagesToEnqueue: [EnqueueMessage] = []
if !text.isEmpty {
messagesToEnqueue.append(.message(text: text, attributes: [], mediaReference: nil, replyToMessageId: nil, localGroupingKey: nil))
}
for message in messages {
messagesToEnqueue.append(.forward(source: message.id, grouping: .auto))
}
shareSignals.append(enqueueMessages(account: strongSelf.currentAccount, peerId: peerId, messages: messagesToEnqueue))
}
case let .fromExternal(f):
return f(peerIds, text, strongSelf.currentAccount)
|> map { state -> ShareState in
switch state {
case .preparing:
return .preparing
case let .progress(value):
return .progress(value)
case .done:
return .done
}
}
}
return .complete()
let account = strongSelf.currentAccount
let queue = Queue.mainQueue()
var displayedError = false
return combineLatest(queue: queue, shareSignals)
|> mapToSignal { messageIdSets -> Signal<ShareState, NoError> in
var statuses: [Signal<(MessageId, PendingMessageStatus?, PendingMessageFailureReason?), NoError>] = []
for messageIds in messageIdSets {
for case let id? in messageIds {
statuses.append(account.pendingMessageManager.pendingMessageStatus(id)
|> map { status, error -> (MessageId, PendingMessageStatus?, PendingMessageFailureReason?) in
return (id, status, error)
})
}
}
return combineLatest(queue: queue, statuses)
|> mapToSignal { statuses -> Signal<ShareState, NoError> in
var hasStatuses = false
for (id, status, error) in statuses {
if let error = error {
Queue.mainQueue().async {
let _ = (account.postbox.transaction { transaction -> Peer? in
transaction.deleteMessages([id])
return transaction.getPeer(id.peerId)
}
|> deliverOnMainQueue).start(next: { peer in
guard let strongSelf = self, let peer = peer else {
return
}
if !displayedError, case .slowmodeActive = error {
displayedError = true
strongSelf.present(standardTextAlertController(theme: AlertControllerTheme(presentationTheme: strongSelf.presentationData.theme), title: peer.displayTitle, text: strongSelf.presentationData.strings.Chat_SlowmodeSendError, actions: [TextAlertAction(type: .defaultAction, title: strongSelf.presentationData.strings.Common_OK, action: {})]), in: .window(.root))
}
})
}
}
let _ = account.postbox.transaction({ transaction in
}).start()
if status != nil {
hasStatuses = true
}
}
if !hasStatuses {
return .single(.done)
}
return .complete()
}
|> take(1)
}
}
self.controllerNode.shareExternal = { [weak self] in
if let strongSelf = self {

View File

@ -30,6 +30,7 @@ final class ShareControllerNode: ViewControllerTracingNode, UIScrollViewDelegate
private let defaultAction: ShareControllerAction?
private let requestLayout: (ContainedViewLayoutTransition) -> Void
private let presentError: (String?, String) -> Void
private var containerLayout: (ContainerViewLayout, CGFloat, CGFloat)?
@ -70,11 +71,12 @@ final class ShareControllerNode: ViewControllerTracingNode, UIScrollViewDelegate
private var hapticFeedback: HapticFeedback?
init(sharedContext: SharedAccountContext, defaultAction: ShareControllerAction?, requestLayout: @escaping (ContainedViewLayoutTransition) -> Void, externalShare: Bool, immediateExternalShare: Bool) {
init(sharedContext: SharedAccountContext, defaultAction: ShareControllerAction?, requestLayout: @escaping (ContainedViewLayoutTransition) -> Void, presentError: @escaping (String?, String) -> Void, externalShare: Bool, immediateExternalShare: Bool) {
self.sharedContext = sharedContext
self.presentationData = sharedContext.currentPresentationData.with { $0 }
self.externalShare = externalShare
self.immediateExternalShare = immediateExternalShare
self.presentError = presentError
self.defaultAction = defaultAction
self.requestLayout = requestLayout
@ -500,6 +502,15 @@ final class ShareControllerNode: ViewControllerTracingNode, UIScrollViewDelegate
defaultAction.action()
}
} else {
if !self.inputFieldNode.text.isEmpty {
for peer in self.controllerInteraction!.selectedPeers {
if let channel = peer.peer as? TelegramChannel, channel.isRestrictedBySlowmode {
self.presentError(channel.title, self.presentationData.strings.Share_MultipleMessagesDisabled)
return
}
}
}
self.inputFieldNode.deactivateInput()
let transition = ContainedViewLayoutTransition.animated(duration: 0.12, curve: .easeInOut)
transition.updateAlpha(node: self.actionButtonNode, alpha: 0.0)