Merge commit 'f17a6f95fa4f31e943da4e7f31ab4500bd72aab3'

This commit is contained in:
Ali 2020-04-17 22:23:04 +04:00
commit 8845e78fba
14 changed files with 4273 additions and 4187 deletions

View File

@ -5475,7 +5475,10 @@ Any member of this group will be able to see messages in the channel.";
"MuteFor.Forever" = "Mute Forever";
"Conversation.Dice" = "Send a 🎲 emoji to any chat to get a random number from Telegram.";
"Conversation.Darts" = "Send a single dart 🎯 emoji to try your luck.";
"Conversation.Dice.🎲" = "Send a dice emoji to any chat to roll a die.";
"Conversation.Dice.🎯" = "Send a dart emoji to try your luck.";
"Conversation.SendDice" = "Send";
"ForwardedDices_1" = "Forwarded dice";
"ForwardedDices_2" = "2 forwarded dices";

View File

@ -1969,6 +1969,8 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
strongSelf.presentPollCreation(isQuiz: isQuiz)
}, displayPollSolution: { [weak self] solution, sourceNode in
self?.displayPollSolution(solution: solution, sourceNode: sourceNode, isAutomatic: false)
}, displayDiceTooltip: { [weak self] dice in
self?.displayDiceTooltip(dice: dice)
}, requestMessageUpdate: { [weak self] id in
if let strongSelf = self {
strongSelf.chatDisplayNode.historyNode.requestMessageUpdate(id)
@ -6516,7 +6518,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
self.present(tooltipScreen, in: .current)
}
private func presentPollCreation(isQuiz: Bool? = nil) {
if case .peer = self.chatLocation, let peer = self.presentationInterfaceState.renderedPeer?.peer {
self.effectiveNavigationController?.pushViewController(createPollController(context: self.context, peer: peer, isQuiz: isQuiz, completion: { [weak self] message in
@ -6541,6 +6543,40 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
return transformEnqueueMessages(messages, silentPosting: silentPosting)
}
private func displayDiceTooltip(dice: TelegramMediaDice) {
guard let _ = dice.value else {
return
}
self.window?.forEachController({ controller in
if let controller = controller as? UndoOverlayController {
controller.dismissWithCommitAction()
}
})
let value: String?
if dice.emoji == "🎲" {
value = self.presentationData.strings.Conversation_Dice_🎲
} else if dice.emoji == "🎯" {
value = self.presentationData.strings.Conversation_Dice_🎯
} else {
let key = "Conversation.Dice.\(dice.emoji)"
if let string = self.presentationData.strings.primaryComponent.dict[key] {
value = string
} else if let string = self.presentationData.strings.secondaryComponent?.dict[key] {
value = string
} else {
value = nil
}
}
if let value = value {
self.present(UndoOverlayController(presentationData: self.presentationData, content: .dice(dice: dice, account: self.context.account, text: value, action: self.presentationData.strings.Conversation_SendDice), elevatedLayout: true, action: { [weak self] action in
if let strongSelf = self, action == .undo {
strongSelf.sendMessages([.message(text: "", attributes: [], mediaReference: AnyMediaReference.standalone(media: TelegramMediaDice(emoji: dice.emoji)), replyToMessageId: nil, localGroupingKey: nil)])
}
return false
}), in: .window(.root))
}
}
private func transformEnqueueMessages(_ messages: [EnqueueMessage], silentPosting: Bool, scheduleTime: Int32? = nil) -> [EnqueueMessage] {
return messages.map { message in
if silentPosting || scheduleTime != nil {

View File

@ -108,6 +108,7 @@ public final class ChatControllerInteraction {
let openMessagePollResults: (MessageId, Data) -> Void
let openPollCreation: (Bool?) -> Void
let displayPollSolution: (TelegramMediaPollResults.Solution, ASDisplayNode) -> Void
let displayDiceTooltip: (TelegramMediaDice) -> Void
let requestMessageUpdate: (MessageId) -> Void
let cancelInteractiveKeyboardGestures: () -> Void
@ -124,7 +125,7 @@ public final class ChatControllerInteraction {
var searchTextHighightState: (String, [MessageIndex])?
var seenOneTimeAnimatedMedia = Set<MessageId>()
init(openMessage: @escaping (Message, ChatControllerInteractionOpenMessageMode) -> Bool, openPeer: @escaping (PeerId?, ChatControllerInteractionNavigateToPeer, Message?) -> Void, openPeerMention: @escaping (String) -> Void, openMessageContextMenu: @escaping (Message, Bool, ASDisplayNode, CGRect, UIGestureRecognizer?) -> Void, openMessageContextActions: @escaping (Message, ASDisplayNode, CGRect, ContextGesture?) -> Void, navigateToMessage: @escaping (MessageId, MessageId) -> Void, tapMessage: ((Message) -> Void)?, clickThroughMessage: @escaping () -> Void, toggleMessagesSelection: @escaping ([MessageId], Bool) -> Void, sendCurrentMessage: @escaping (Bool) -> Void, sendMessage: @escaping (String) -> Void, sendSticker: @escaping (FileMediaReference, Bool, ASDisplayNode, CGRect) -> Bool, sendGif: @escaping (FileMediaReference, ASDisplayNode, CGRect) -> Bool, requestMessageActionCallback: @escaping (MessageId, MemoryBuffer?, Bool) -> Void, requestMessageActionUrlAuth: @escaping (String, MessageId, Int32) -> Void, activateSwitchInline: @escaping (PeerId?, String) -> Void, openUrl: @escaping (String, Bool, Bool?, Message?) -> Void, shareCurrentLocation: @escaping () -> Void, shareAccountContact: @escaping () -> Void, sendBotCommand: @escaping (MessageId?, String) -> Void, openInstantPage: @escaping (Message, ChatMessageItemAssociatedData?) -> Void, openWallpaper: @escaping (Message) -> Void, openTheme: @escaping (Message) -> Void, openHashtag: @escaping (String?, String) -> Void, updateInputState: @escaping ((ChatTextInputState) -> ChatTextInputState) -> Void, updateInputMode: @escaping ((ChatInputMode) -> ChatInputMode) -> Void, openMessageShareMenu: @escaping (MessageId) -> Void, presentController: @escaping (ViewController, Any?) -> Void, navigationController: @escaping () -> NavigationController?, chatControllerNode: @escaping () -> ASDisplayNode?, reactionContainerNode: @escaping () -> ReactionSelectionParentNode?, presentGlobalOverlayController: @escaping (ViewController, Any?) -> Void, callPeer: @escaping (PeerId) -> Void, longTap: @escaping (ChatControllerInteractionLongTapAction, Message?) -> Void, openCheckoutOrReceipt: @escaping (MessageId) -> Void, openSearch: @escaping () -> Void, setupReply: @escaping (MessageId) -> Void, canSetupReply: @escaping (Message) -> Bool, navigateToFirstDateMessage: @escaping(Int32) ->Void, requestRedeliveryOfFailedMessages: @escaping (MessageId) -> Void, addContact: @escaping (String) -> Void, rateCall: @escaping (Message, CallId) -> Void, requestSelectMessagePollOptions: @escaping (MessageId, [Data]) -> Void, requestOpenMessagePollResults: @escaping (MessageId, MediaId) -> Void, openAppStorePage: @escaping () -> Void, displayMessageTooltip: @escaping (MessageId, String, ASDisplayNode?, CGRect?) -> Void, seekToTimecode: @escaping (Message, Double, Bool) -> Void, scheduleCurrentMessage: @escaping () -> Void, sendScheduledMessagesNow: @escaping ([MessageId]) -> Void, editScheduledMessagesTime: @escaping ([MessageId]) -> Void, performTextSelectionAction: @escaping (UInt32, String, TextSelectionAction) -> Void, updateMessageReaction: @escaping (MessageId, String?) -> Void, openMessageReactions: @escaping (MessageId) -> Void, displaySwipeToReplyHint: @escaping () -> Void, dismissReplyMarkupMessage: @escaping (Message) -> Void, openMessagePollResults: @escaping (MessageId, Data) -> Void, openPollCreation: @escaping (Bool?) -> Void, displayPollSolution: @escaping (TelegramMediaPollResults.Solution, ASDisplayNode) -> Void, requestMessageUpdate: @escaping (MessageId) -> Void, cancelInteractiveKeyboardGestures: @escaping () -> Void, automaticMediaDownloadSettings: MediaAutoDownloadSettings, pollActionState: ChatInterfacePollActionState, stickerSettings: ChatInterfaceStickerSettings) {
init(openMessage: @escaping (Message, ChatControllerInteractionOpenMessageMode) -> Bool, openPeer: @escaping (PeerId?, ChatControllerInteractionNavigateToPeer, Message?) -> Void, openPeerMention: @escaping (String) -> Void, openMessageContextMenu: @escaping (Message, Bool, ASDisplayNode, CGRect, UIGestureRecognizer?) -> Void, openMessageContextActions: @escaping (Message, ASDisplayNode, CGRect, ContextGesture?) -> Void, navigateToMessage: @escaping (MessageId, MessageId) -> Void, tapMessage: ((Message) -> Void)?, clickThroughMessage: @escaping () -> Void, toggleMessagesSelection: @escaping ([MessageId], Bool) -> Void, sendCurrentMessage: @escaping (Bool) -> Void, sendMessage: @escaping (String) -> Void, sendSticker: @escaping (FileMediaReference, Bool, ASDisplayNode, CGRect) -> Bool, sendGif: @escaping (FileMediaReference, ASDisplayNode, CGRect) -> Bool, requestMessageActionCallback: @escaping (MessageId, MemoryBuffer?, Bool) -> Void, requestMessageActionUrlAuth: @escaping (String, MessageId, Int32) -> Void, activateSwitchInline: @escaping (PeerId?, String) -> Void, openUrl: @escaping (String, Bool, Bool?, Message?) -> Void, shareCurrentLocation: @escaping () -> Void, shareAccountContact: @escaping () -> Void, sendBotCommand: @escaping (MessageId?, String) -> Void, openInstantPage: @escaping (Message, ChatMessageItemAssociatedData?) -> Void, openWallpaper: @escaping (Message) -> Void, openTheme: @escaping (Message) -> Void, openHashtag: @escaping (String?, String) -> Void, updateInputState: @escaping ((ChatTextInputState) -> ChatTextInputState) -> Void, updateInputMode: @escaping ((ChatInputMode) -> ChatInputMode) -> Void, openMessageShareMenu: @escaping (MessageId) -> Void, presentController: @escaping (ViewController, Any?) -> Void, navigationController: @escaping () -> NavigationController?, chatControllerNode: @escaping () -> ASDisplayNode?, reactionContainerNode: @escaping () -> ReactionSelectionParentNode?, presentGlobalOverlayController: @escaping (ViewController, Any?) -> Void, callPeer: @escaping (PeerId) -> Void, longTap: @escaping (ChatControllerInteractionLongTapAction, Message?) -> Void, openCheckoutOrReceipt: @escaping (MessageId) -> Void, openSearch: @escaping () -> Void, setupReply: @escaping (MessageId) -> Void, canSetupReply: @escaping (Message) -> Bool, navigateToFirstDateMessage: @escaping(Int32) ->Void, requestRedeliveryOfFailedMessages: @escaping (MessageId) -> Void, addContact: @escaping (String) -> Void, rateCall: @escaping (Message, CallId) -> Void, requestSelectMessagePollOptions: @escaping (MessageId, [Data]) -> Void, requestOpenMessagePollResults: @escaping (MessageId, MediaId) -> Void, openAppStorePage: @escaping () -> Void, displayMessageTooltip: @escaping (MessageId, String, ASDisplayNode?, CGRect?) -> Void, seekToTimecode: @escaping (Message, Double, Bool) -> Void, scheduleCurrentMessage: @escaping () -> Void, sendScheduledMessagesNow: @escaping ([MessageId]) -> Void, editScheduledMessagesTime: @escaping ([MessageId]) -> Void, performTextSelectionAction: @escaping (UInt32, String, TextSelectionAction) -> Void, updateMessageReaction: @escaping (MessageId, String?) -> Void, openMessageReactions: @escaping (MessageId) -> Void, displaySwipeToReplyHint: @escaping () -> Void, dismissReplyMarkupMessage: @escaping (Message) -> Void, openMessagePollResults: @escaping (MessageId, Data) -> Void, openPollCreation: @escaping (Bool?) -> Void, displayPollSolution: @escaping (TelegramMediaPollResults.Solution, ASDisplayNode) -> Void, displayDiceTooltip: @escaping (TelegramMediaDice) -> Void, requestMessageUpdate: @escaping (MessageId) -> Void, cancelInteractiveKeyboardGestures: @escaping () -> Void, automaticMediaDownloadSettings: MediaAutoDownloadSettings, pollActionState: ChatInterfacePollActionState, stickerSettings: ChatInterfaceStickerSettings) {
self.openMessage = openMessage
self.openPeer = openPeer
self.openPeerMention = openPeerMention
@ -183,6 +184,7 @@ public final class ChatControllerInteraction {
self.displaySwipeToReplyHint = displaySwipeToReplyHint
self.dismissReplyMarkupMessage = dismissReplyMarkupMessage
self.openMessagePollResults = openMessagePollResults
self.displayDiceTooltip = displayDiceTooltip
self.requestMessageUpdate = requestMessageUpdate
self.cancelInteractiveKeyboardGestures = cancelInteractiveKeyboardGestures
@ -225,6 +227,7 @@ public final class ChatControllerInteraction {
}, openMessagePollResults: { _, _ in
}, openPollCreation: { _ in
}, displayPollSolution: { _, _ in
}, displayDiceTooltip: { _ in
}, requestMessageUpdate: { _ in
}, cancelInteractiveKeyboardGestures: {
}, automaticMediaDownloadSettings: MediaAutoDownloadSettings.defaultSettings,

View File

@ -1010,18 +1010,7 @@ class ChatMessageAnimatedStickerItemNode: ChatMessageItemView {
})
} else if let dice = self.telegramDice {
return .optionalAction({
var text: String?
switch dice.emoji {
case "🎲":
text = item.presentationData.strings.Conversation_Dice
case "🎯":
text = item.presentationData.strings.Conversation_Darts
default:
break
}
if let text = text {
item.controllerInteraction.displayMessageTooltip(item.content.firstMessage.id, text, self, self.imageNode.frame.offsetBy(dx: 0.0, dy: self.imageNode.frame.height / 3.0))
}
item.controllerInteraction.displayDiceTooltip(dice)
})
} else if let _ = self.emojiFile {
if let animationNode = self.animationNode as? AnimatedStickerNode {

View File

@ -424,6 +424,7 @@ final class ChatRecentActionsControllerNode: ViewControllerTracingNode {
}, openMessagePollResults: { _, _ in
}, openPollCreation: { _ in
}, displayPollSolution: { _, _ in
}, displayDiceTooltip: { _ in
}, requestMessageUpdate: { _ in
}, cancelInteractiveKeyboardGestures: {
}, automaticMediaDownloadSettings: self.automaticMediaDownloadSettings,

View File

@ -86,7 +86,7 @@ final class ManagedDiceAnimationNode: ManagedAnimationNode, GenericAnimatedStick
case let .value(value, _):
let animationItem: Signal<ManagedAnimationItem, NoError> = self.emojis.get()
|> mapToSignal { emojis -> Signal<ManagedAnimationItem, NoError> in
guard emojis.count > value else {
guard emojis.count >= value else {
return .complete()
}
let file = emojis[Int(value) - 1]
@ -134,7 +134,7 @@ final class ManagedDiceAnimationNode: ManagedAnimationNode, GenericAnimatedStick
case let .value(value, immediate):
let animationItem: Signal<ManagedAnimationItem, NoError> = self.emojis.get()
|> mapToSignal { emojis -> Signal<ManagedAnimationItem, NoError> in
guard emojis.count > value else {
guard emojis.count >= value else {
return .complete()
}
let file = emojis[Int(value) - 1]

View File

@ -123,6 +123,7 @@ final class OverlayAudioPlayerControllerNode: ViewControllerTracingNode, UIGestu
}, openMessagePollResults: { _, _ in
}, openPollCreation: { _ in
}, displayPollSolution: { _, _ in
}, displayDiceTooltip: { _ in
}, requestMessageUpdate: { _ in
}, cancelInteractiveKeyboardGestures: {
}, automaticMediaDownloadSettings: MediaAutoDownloadSettings.defaultSettings, pollActionState: ChatInterfacePollActionState(), stickerSettings: ChatInterfaceStickerSettings(loopAnimatedStickers: false))

View File

@ -1528,6 +1528,7 @@ private final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewD
}, openMessagePollResults: { _, _ in
}, openPollCreation: { _ in
}, displayPollSolution: { _, _ in
}, displayDiceTooltip: { _ in
}, requestMessageUpdate: { _ in
}, cancelInteractiveKeyboardGestures: {
}, automaticMediaDownloadSettings: MediaAutoDownloadSettings.defaultSettings,

View File

@ -428,6 +428,7 @@ public class PeerMediaCollectionController: TelegramBaseController {
}, openMessagePollResults: { _, _ in
}, openPollCreation: { _ in
}, displayPollSolution: { _, _ in
}, displayDiceTooltip: { _ in
}, requestMessageUpdate: { _ in
}, cancelInteractiveKeyboardGestures: {
}, automaticMediaDownloadSettings: MediaAutoDownloadSettings.defaultSettings,

View File

@ -1136,6 +1136,7 @@ public final class SharedAccountContextImpl: SharedAccountContext {
}, openMessagePollResults: { _, _ in
}, openPollCreation: { _ in
}, displayPollSolution: { _, _ in
}, displayDiceTooltip: { _ in
}, requestMessageUpdate: { _ in
}, cancelInteractiveKeyboardGestures: {
}, automaticMediaDownloadSettings: MediaAutoDownloadSettings.defaultSettings,

View File

@ -17,6 +17,7 @@ public enum UndoOverlayContent {
case swipeToReply(title: String, text: String)
case actionSucceeded(title: String, text: String, cancel: String)
case stickersModified(title: String, text: String, undo: Bool, info: StickerPackCollectionInfo, topItem: ItemCollectionItem?, account: Account)
case dice(dice: TelegramMediaDice, account: Account, text: String, action: String)
}
public enum UndoOverlayAction {
@ -61,12 +62,12 @@ public final class UndoOverlayController: ViewController {
}
public func dismissWithCommitAction() {
self.action(.commit)
let _ = self.action(.commit)
self.dismiss()
}
public func dismissWithCommitActionAndReplacementAnimation() {
self.action(.commit)
let _ = self.action(.commit)
(self.displayNode as! UndoOverlayControllerNode).animateOutWithReplacement(completion: { [weak self] in
self?.presentingViewController?.dismiss(animated: false, completion: nil)
})

View File

@ -26,6 +26,7 @@ final class UndoOverlayControllerNode: ViewControllerTracingNode {
private var animatedStickerNode: AnimatedStickerNode?
private var stillStickerNode: TransformImageNode?
private var stickerImageSize: CGSize?
private var stickerOffset: CGPoint?
private let titleNode: ImmediateTextNode
private let textNode: ImmediateTextNode
private let buttonNode: HighlightTrackingButtonNode
@ -279,6 +280,46 @@ final class UndoOverlayControllerNode: ViewControllerTracingNode {
animatedStickerNode.setup(source: AnimatedStickerResourceSource(account: account, resource: resource), width: 80, height: 80, mode: .cached)
}
}
case let .dice(dice, account, text, action):
self.iconNode = nil
self.iconCheckNode = nil
self.animationNode = nil
let body = MarkdownAttributeSet(font: Font.regular(14.0), textColor: .white)
let bold = MarkdownAttributeSet(font: Font.semibold(14.0), textColor: .white)
let link = MarkdownAttributeSet(font: Font.regular(14.0), textColor: undoTextColor)
let attributedText = parseMarkdownIntoAttributedString(text, attributes: MarkdownAttributes(body: body, bold: bold, link: link, linkAttribute: { _ in return nil }), textAlignment: .natural)
self.textNode.attributedText = attributedText
displayUndo = true
undoText = action
self.originalRemainingSeconds = 5
self.stickerImageSize = CGSize(width: 42.0, height: 42.0)
switch dice.emoji {
case "🎲":
self.stickerOffset = CGPoint(x: 0.0, y: -8.0)
default:
break
}
let animatedStickerNode = AnimatedStickerNode()
self.animatedStickerNode = animatedStickerNode
let _ = (loadedStickerPack(postbox: account.postbox, network: account.network, reference: .dice(dice.emoji), forceActualized: false)
|> deliverOnMainQueue).start(next: { stickerPack in
if let value = dice.value {
switch stickerPack {
case let .result(_, items, _):
let item = items[Int(value) - 1]
if let item = item as? StickerPackItem {
animatedStickerNode.setup(source: AnimatedStickerResourceSource(account: account, resource: item.file.resource), width: 120, height: 120, playbackMode: .once, mode: .direct)
}
default:
break
}
}
})
}
self.remainingSeconds = self.originalRemainingSeconds
@ -309,6 +350,8 @@ final class UndoOverlayControllerNode: ViewControllerTracingNode {
self.panelWrapperNode.addSubnode(self.timerTextNode)
case .archivedChat, .hidArchive, .revealedArchive, .succeed, .emoji, .swipeToReply, .actionSucceeded, .stickersModified:
break
case .dice:
self.panelWrapperNode.clipsToBounds = true
case .info:
self.isUserInteractionEnabled = false
}
@ -419,7 +462,7 @@ final class UndoOverlayControllerNode: ViewControllerTracingNode {
let rightInset: CGFloat = 16.0
var contentHeight: CGFloat = 20.0
let margin: CGFloat = 16.0
let margin: CGFloat = 12.0
let buttonTextSize = self.undoButtonTextNode.updateLayout(CGSize(width: 200.0, height: .greatestFiniteMagnitude))
let buttonMinX: CGFloat
@ -492,7 +535,11 @@ final class UndoOverlayControllerNode: ViewControllerTracingNode {
if let stickerImageSize = self.stickerImageSize {
let iconSize = stickerImageSize
let iconFrame = CGRect(origin: CGPoint(x: floor((leftInset - iconSize.width) / 2.0), y: floor((contentHeight - iconSize.height) / 2.0)), size: iconSize)
var iconFrame = CGRect(origin: CGPoint(x: floor((leftInset - iconSize.width) / 2.0), y: floor((contentHeight - iconSize.height) / 2.0)), size: iconSize)
if let stickerOffset = self.stickerOffset {
iconFrame = iconFrame.offsetBy(dx: stickerOffset.x, dy: stickerOffset.y)
}
if let stillStickerNode = self.stillStickerNode {
let makeImageLayout = stillStickerNode.asyncLayout()