mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2026-02-03 18:13:41 +00:00
Comment updates
This commit is contained in:
@@ -8346,6 +8346,11 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
strongSelf.loadingMessage.set(false)
|
||||
}
|
||||
}))
|
||||
} else {
|
||||
if let navigationController = self.effectiveNavigationController {
|
||||
self.context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: self.context, chatLocation: .peer(messageLocation.peerId), subject: messageLocation.messageId.flatMap { .message($0) }))
|
||||
}
|
||||
completion?()
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
||||
@@ -297,7 +297,7 @@ func contextMenuForChatPresentationIntefaceState(chatPresentationInterfaceState:
|
||||
|
||||
let message = messages[0]
|
||||
|
||||
if Namespaces.Message.allScheduled.contains(message.id.namespace) {
|
||||
if Namespaces.Message.allScheduled.contains(message.id.namespace) || message.id.peerId.isReplies {
|
||||
canReply = false
|
||||
canPin = false
|
||||
} else if messages[0].flags.intersection([.Failed, .Unsent]).isEmpty {
|
||||
@@ -758,7 +758,15 @@ func contextMenuForChatPresentationIntefaceState(chatPresentationInterfaceState:
|
||||
UIPasteboard.general.string = link
|
||||
|
||||
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
||||
if channel.addressName == nil {
|
||||
|
||||
var warnAboutPrivate = false
|
||||
if case let .peer = chatPresentationInterfaceState.chatLocation {
|
||||
if channel.addressName == nil {
|
||||
warnAboutPrivate = true
|
||||
}
|
||||
}
|
||||
|
||||
if warnAboutPrivate {
|
||||
controllerInteraction.presentGlobalOverlayController(OverlayStatusController(theme: presentationData.theme, type: .genericSuccess(presentationData.strings.Conversation_PrivateMessageLinkCopied, true)), nil)
|
||||
} else {
|
||||
controllerInteraction.presentGlobalOverlayController(OverlayStatusController(theme: presentationData.theme, type: .genericSuccess(presentationData.strings.GroupInfo_InviteLink_CopyAlert_Success, false)), nil)
|
||||
@@ -1050,7 +1058,7 @@ func chatAvailableMessageActionsImpl(postbox: Postbox, accountPeerId: PeerId, me
|
||||
}
|
||||
}
|
||||
} else if let user = peer as? TelegramUser {
|
||||
if !isScheduled && message.id.peerId.namespace != Namespaces.Peer.SecretChat && !message.containsSecretMedia && !isAction {
|
||||
if !isScheduled && message.id.peerId.namespace != Namespaces.Peer.SecretChat && !message.containsSecretMedia && !isAction && !message.id.peerId.isReplies {
|
||||
if !(message.flags.isSending || message.flags.contains(.Failed)) {
|
||||
optionsMap[id]!.insert(.forward)
|
||||
}
|
||||
@@ -1073,7 +1081,7 @@ func chatAvailableMessageActionsImpl(postbox: Postbox, accountPeerId: PeerId, me
|
||||
if canDeleteGlobally {
|
||||
optionsMap[id]!.insert(.deleteGlobally)
|
||||
}
|
||||
if user.botInfo != nil {
|
||||
if user.botInfo != nil && !user.id.isReplies {
|
||||
optionsMap[id]!.insert(.report)
|
||||
}
|
||||
} else if let _ = peer as? TelegramSecretChat {
|
||||
|
||||
@@ -27,6 +27,9 @@ struct ChatNavigationButton: Equatable {
|
||||
|
||||
func leftNavigationButtonForChatInterfaceState(_ presentationInterfaceState: ChatPresentationInterfaceState, subject: ChatControllerSubject?, strings: PresentationStrings, currentButton: ChatNavigationButton?, target: Any?, selector: Selector?) -> ChatNavigationButton? {
|
||||
if let _ = presentationInterfaceState.interfaceState.selectionState {
|
||||
if case .replyThread = presentationInterfaceState.chatLocation {
|
||||
return nil
|
||||
}
|
||||
if let currentButton = currentButton, currentButton.action == .clearHistory {
|
||||
return currentButton
|
||||
} else if let peer = presentationInterfaceState.renderedPeer?.peer {
|
||||
@@ -64,6 +67,14 @@ func leftNavigationButtonForChatInterfaceState(_ presentationInterfaceState: Cha
|
||||
}
|
||||
|
||||
func rightNavigationButtonForChatInterfaceState(_ presentationInterfaceState: ChatPresentationInterfaceState, strings: PresentationStrings, currentButton: ChatNavigationButton?, target: Any?, selector: Selector?, chatInfoNavigationButton: ChatNavigationButton?) -> ChatNavigationButton? {
|
||||
if let _ = presentationInterfaceState.interfaceState.selectionState {
|
||||
if let currentButton = currentButton, currentButton.action == .cancelMessageSelection {
|
||||
return currentButton
|
||||
} else {
|
||||
return ChatNavigationButton(action: .cancelMessageSelection, buttonItem: UIBarButtonItem(title: strings.Common_Cancel, style: .plain, target: target, action: selector))
|
||||
}
|
||||
}
|
||||
|
||||
if case .replyThread = presentationInterfaceState.chatLocation {
|
||||
if case .search = currentButton?.action {
|
||||
return currentButton
|
||||
@@ -84,13 +95,6 @@ func rightNavigationButtonForChatInterfaceState(_ presentationInterfaceState: Ch
|
||||
}
|
||||
}
|
||||
}
|
||||
if let _ = presentationInterfaceState.interfaceState.selectionState {
|
||||
if let currentButton = currentButton, currentButton.action == .cancelMessageSelection {
|
||||
return currentButton
|
||||
} else {
|
||||
return ChatNavigationButton(action: .cancelMessageSelection, buttonItem: UIBarButtonItem(title: strings.Common_Cancel, style: .plain, target: target, action: selector))
|
||||
}
|
||||
}
|
||||
|
||||
if presentationInterfaceState.isScheduledMessages {
|
||||
return chatInfoNavigationButton
|
||||
|
||||
@@ -531,7 +531,7 @@ final class ChatMessageAttachedContentNode: ASDisplayNode {
|
||||
var additionalImageBadgeContent: ChatMessageInteractiveMediaBadgeContent?
|
||||
|
||||
switch position {
|
||||
case .linear(_, .None):
|
||||
case .linear(_, .None), .linear(_, .Neighbour(true, _)):
|
||||
let imageMode = !((refineContentImageLayout == nil && refineContentFileLayout == nil && contentInstantVideoSizeAndApply == nil) || preferMediaBeforeText)
|
||||
statusInText = !imageMode
|
||||
|
||||
|
||||
@@ -29,8 +29,13 @@ enum InternalBubbleTapAction {
|
||||
case openContextMenu(tapMessage: Message, selectAll: Bool, subFrame: CGRect)
|
||||
}
|
||||
|
||||
private func contentNodeMessagesAndClassesForItem(_ item: ChatMessageItem) -> [(Message, AnyClass, ChatMessageEntryAttributes, Bool)] {
|
||||
var result: [(Message, AnyClass, ChatMessageEntryAttributes, Bool)] = []
|
||||
private struct BubbleItemAttributes {
|
||||
var isAttachment: Bool
|
||||
var neighborType: ChatMessageBubbleRelativePosition.NeighbourType
|
||||
}
|
||||
|
||||
private func contentNodeMessagesAndClassesForItem(_ item: ChatMessageItem) -> [(Message, AnyClass, ChatMessageEntryAttributes, BubbleItemAttributes)] {
|
||||
var result: [(Message, AnyClass, ChatMessageEntryAttributes, BubbleItemAttributes)] = []
|
||||
var skipText = false
|
||||
var messageWithCaptionToAdd: (Message, ChatMessageEntryAttributes)?
|
||||
var isUnsupportedMedia = false
|
||||
@@ -39,46 +44,46 @@ private func contentNodeMessagesAndClassesForItem(_ item: ChatMessageItem) -> [(
|
||||
outer: for (message, itemAttributes) in item.content {
|
||||
for attribute in message.attributes {
|
||||
if let attribute = attribute as? RestrictedContentMessageAttribute, attribute.platformText(platform: "ios", contentSettings: item.context.currentContentSettings.with { $0 }) != nil {
|
||||
result.append((message, ChatMessageRestrictedBubbleContentNode.self, itemAttributes, false))
|
||||
result.append((message, ChatMessageRestrictedBubbleContentNode.self, itemAttributes, BubbleItemAttributes(isAttachment: false, neighborType: .freeform)))
|
||||
break outer
|
||||
}
|
||||
}
|
||||
|
||||
inner: for media in message.media {
|
||||
if let _ = media as? TelegramMediaImage {
|
||||
result.append((message, ChatMessageMediaBubbleContentNode.self, itemAttributes, true))
|
||||
result.append((message, ChatMessageMediaBubbleContentNode.self, itemAttributes, BubbleItemAttributes(isAttachment: false, neighborType: .media)))
|
||||
} else if let file = media as? TelegramMediaFile {
|
||||
let isVideo = file.isVideo || (file.isAnimated && file.dimensions != nil)
|
||||
if isVideo {
|
||||
result.append((message, ChatMessageMediaBubbleContentNode.self, itemAttributes, true))
|
||||
result.append((message, ChatMessageMediaBubbleContentNode.self, itemAttributes, BubbleItemAttributes(isAttachment: false, neighborType: .media)))
|
||||
} else {
|
||||
result.append((message, ChatMessageFileBubbleContentNode.self, itemAttributes, false))
|
||||
result.append((message, ChatMessageFileBubbleContentNode.self, itemAttributes, BubbleItemAttributes(isAttachment: false, neighborType: .freeform)))
|
||||
}
|
||||
} else if let action = media as? TelegramMediaAction {
|
||||
isAction = true
|
||||
if case .phoneCall = action.action {
|
||||
result.append((message, ChatMessageCallBubbleContentNode.self, itemAttributes, false))
|
||||
result.append((message, ChatMessageCallBubbleContentNode.self, itemAttributes, BubbleItemAttributes(isAttachment: false, neighborType: .freeform)))
|
||||
} else {
|
||||
result.append((message, ChatMessageActionBubbleContentNode.self, itemAttributes, false))
|
||||
result.append((message, ChatMessageActionBubbleContentNode.self, itemAttributes, BubbleItemAttributes(isAttachment: false, neighborType: .freeform)))
|
||||
}
|
||||
} else if let _ = media as? TelegramMediaMap {
|
||||
result.append((message, ChatMessageMapBubbleContentNode.self, itemAttributes, true))
|
||||
result.append((message, ChatMessageMapBubbleContentNode.self, itemAttributes, BubbleItemAttributes(isAttachment: false, neighborType: .media)))
|
||||
} else if let _ = media as? TelegramMediaGame {
|
||||
skipText = true
|
||||
result.append((message, ChatMessageGameBubbleContentNode.self, itemAttributes, false))
|
||||
result.append((message, ChatMessageGameBubbleContentNode.self, itemAttributes, BubbleItemAttributes(isAttachment: false, neighborType: .freeform)))
|
||||
break inner
|
||||
} else if let _ = media as? TelegramMediaInvoice {
|
||||
skipText = true
|
||||
result.append((message, ChatMessageInvoiceBubbleContentNode.self, itemAttributes, false))
|
||||
result.append((message, ChatMessageInvoiceBubbleContentNode.self, itemAttributes, BubbleItemAttributes(isAttachment: false, neighborType: .freeform)))
|
||||
break inner
|
||||
} else if let _ = media as? TelegramMediaContact {
|
||||
result.append((message, ChatMessageContactBubbleContentNode.self, itemAttributes, false))
|
||||
result.append((message, ChatMessageContactBubbleContentNode.self, itemAttributes, BubbleItemAttributes(isAttachment: false, neighborType: .freeform)))
|
||||
} else if let _ = media as? TelegramMediaExpiredContent {
|
||||
result.removeAll()
|
||||
result.append((message, ChatMessageActionBubbleContentNode.self, itemAttributes, false))
|
||||
result.append((message, ChatMessageActionBubbleContentNode.self, itemAttributes, BubbleItemAttributes(isAttachment: false, neighborType: .freeform)))
|
||||
return result
|
||||
} else if let _ = media as? TelegramMediaPoll {
|
||||
result.append((message, ChatMessagePollBubbleContentNode.self, itemAttributes, false))
|
||||
result.append((message, ChatMessagePollBubbleContentNode.self, itemAttributes, BubbleItemAttributes(isAttachment: false, neighborType: .freeform)))
|
||||
} else if let _ = media as? TelegramMediaUnsupported {
|
||||
isUnsupportedMedia = true
|
||||
}
|
||||
@@ -95,7 +100,7 @@ private func contentNodeMessagesAndClassesForItem(_ item: ChatMessageItem) -> [(
|
||||
messageWithCaptionToAdd = (message, itemAttributes)
|
||||
skipText = true
|
||||
} else {
|
||||
result.append((message, ChatMessageTextBubbleContentNode.self, itemAttributes, false))
|
||||
result.append((message, ChatMessageTextBubbleContentNode.self, itemAttributes, BubbleItemAttributes(isAttachment: false, neighborType: .freeform)))
|
||||
}
|
||||
} else {
|
||||
if case .group = item.content {
|
||||
@@ -107,34 +112,34 @@ private func contentNodeMessagesAndClassesForItem(_ item: ChatMessageItem) -> [(
|
||||
inner: for media in message.media {
|
||||
if let webpage = media as? TelegramMediaWebpage {
|
||||
if case .Loaded = webpage.content {
|
||||
result.append((message, ChatMessageWebpageBubbleContentNode.self, itemAttributes, false))
|
||||
result.append((message, ChatMessageWebpageBubbleContentNode.self, itemAttributes, BubbleItemAttributes(isAttachment: false, neighborType: .freeform)))
|
||||
}
|
||||
break inner
|
||||
}
|
||||
}
|
||||
|
||||
if isUnsupportedMedia {
|
||||
result.append((message, ChatMessageUnsupportedBubbleContentNode.self, itemAttributes, false))
|
||||
result.append((message, ChatMessageUnsupportedBubbleContentNode.self, itemAttributes, BubbleItemAttributes(isAttachment: false, neighborType: .freeform)))
|
||||
}
|
||||
}
|
||||
|
||||
if let (messageWithCaptionToAdd, itemAttributes) = messageWithCaptionToAdd {
|
||||
result.append((messageWithCaptionToAdd, ChatMessageTextBubbleContentNode.self, itemAttributes, false))
|
||||
result.append((messageWithCaptionToAdd, ChatMessageTextBubbleContentNode.self, itemAttributes, BubbleItemAttributes(isAttachment: false, neighborType: .freeform)))
|
||||
}
|
||||
|
||||
if let additionalContent = item.additionalContent {
|
||||
switch additionalContent {
|
||||
case let .eventLogPreviousMessage(previousMessage):
|
||||
result.append((previousMessage, ChatMessageEventLogPreviousMessageContentNode.self, ChatMessageEntryAttributes(), false))
|
||||
result.append((previousMessage, ChatMessageEventLogPreviousMessageContentNode.self, ChatMessageEntryAttributes(), BubbleItemAttributes(isAttachment: false, neighborType: .freeform)))
|
||||
case let .eventLogPreviousDescription(previousMessage):
|
||||
result.append((previousMessage, ChatMessageEventLogPreviousDescriptionContentNode.self, ChatMessageEntryAttributes(), false))
|
||||
result.append((previousMessage, ChatMessageEventLogPreviousDescriptionContentNode.self, ChatMessageEntryAttributes(), BubbleItemAttributes(isAttachment: false, neighborType: .freeform)))
|
||||
case let .eventLogPreviousLink(previousMessage):
|
||||
result.append((previousMessage, ChatMessageEventLogPreviousLinkContentNode.self, ChatMessageEntryAttributes(), false))
|
||||
result.append((previousMessage, ChatMessageEventLogPreviousLinkContentNode.self, ChatMessageEntryAttributes(), BubbleItemAttributes(isAttachment: false, neighborType: .freeform)))
|
||||
}
|
||||
}
|
||||
|
||||
let firstMessage = item.content.firstMessage
|
||||
if !isAction {
|
||||
if !isAction && !Namespaces.Message.allScheduled.contains(firstMessage.id.namespace) {
|
||||
var hasDiscussion = false
|
||||
if let channel = firstMessage.peers[firstMessage.id.peerId] as? TelegramChannel, case let .broadcast(info) = channel.info, info.flags.contains(.hasDiscussionGroup) {
|
||||
hasDiscussion = true
|
||||
@@ -159,10 +164,10 @@ private func contentNodeMessagesAndClassesForItem(_ item: ChatMessageItem) -> [(
|
||||
}
|
||||
|
||||
if canComment {
|
||||
result.append((firstMessage, ChatMessageCommentFooterContentNode.self, ChatMessageEntryAttributes(), false))
|
||||
result.append((firstMessage, ChatMessageCommentFooterContentNode.self, ChatMessageEntryAttributes(), BubbleItemAttributes(isAttachment: true, neighborType: .freeform)))
|
||||
}
|
||||
} else if firstMessage.id.peerId.isReplies {
|
||||
result.append((firstMessage, ChatMessageCommentFooterContentNode.self, ChatMessageEntryAttributes(), false))
|
||||
result.append((firstMessage, ChatMessageCommentFooterContentNode.self, ChatMessageEntryAttributes(), BubbleItemAttributes(isAttachment: true, neighborType: .freeform)))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -981,22 +986,22 @@ class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePrevewItemNode
|
||||
|
||||
let maximumContentWidth = floor(tmpWidth - layoutConstants.bubble.edgeInset - layoutConstants.bubble.edgeInset - layoutConstants.bubble.contentInsets.left - layoutConstants.bubble.contentInsets.right - avatarInset)
|
||||
|
||||
var contentPropertiesAndPrepareLayouts: [(Message, Bool, ChatMessageEntryAttributes, Bool, (_ item: ChatMessageBubbleContentItem, _ layoutConstants: ChatMessageItemLayoutConstants, _ preparePosition: ChatMessageBubblePreparePosition, _ messageSelection: Bool?, _ constrainedSize: CGSize) -> (ChatMessageBubbleContentProperties, CGSize?, CGFloat, (CGSize, ChatMessageBubbleContentPosition) -> (CGFloat, (CGFloat) -> (CGSize, (ListViewItemUpdateAnimation, Bool) -> Void))))] = []
|
||||
var contentPropertiesAndPrepareLayouts: [(Message, Bool, ChatMessageEntryAttributes, BubbleItemAttributes, (_ item: ChatMessageBubbleContentItem, _ layoutConstants: ChatMessageItemLayoutConstants, _ preparePosition: ChatMessageBubblePreparePosition, _ messageSelection: Bool?, _ constrainedSize: CGSize) -> (ChatMessageBubbleContentProperties, CGSize?, CGFloat, (CGSize, ChatMessageBubbleContentPosition) -> (CGFloat, (CGFloat) -> (CGSize, (ListViewItemUpdateAnimation, Bool) -> Void))))] = []
|
||||
var addedContentNodes: [(Message, ChatMessageBubbleContentNode)]?
|
||||
|
||||
let contentNodeMessagesAndClasses = contentNodeMessagesAndClassesForItem(item)
|
||||
for (contentNodeMessage, contentNodeClass, attributes, isAttachment) in contentNodeMessagesAndClasses {
|
||||
for (contentNodeMessage, contentNodeClass, attributes, bubbleAttributes) in contentNodeMessagesAndClasses {
|
||||
var found = false
|
||||
for (currentMessage, currentClass, supportsMosaic, currentLayout) in currentContentClassesPropertiesAndLayouts {
|
||||
if currentClass == contentNodeClass && currentMessage.stableId == contentNodeMessage.stableId {
|
||||
contentPropertiesAndPrepareLayouts.append((contentNodeMessage, supportsMosaic, attributes, isAttachment, currentLayout))
|
||||
contentPropertiesAndPrepareLayouts.append((contentNodeMessage, supportsMosaic, attributes, bubbleAttributes, currentLayout))
|
||||
found = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !found {
|
||||
let contentNode = (contentNodeClass as! ChatMessageBubbleContentNode.Type).init()
|
||||
contentPropertiesAndPrepareLayouts.append((contentNodeMessage, contentNode.supportsMosaic, attributes, isAttachment, contentNode.asyncLayoutContent()))
|
||||
contentPropertiesAndPrepareLayouts.append((contentNodeMessage, contentNode.supportsMosaic, attributes, bubbleAttributes, contentNode.asyncLayoutContent()))
|
||||
if addedContentNodes == nil {
|
||||
addedContentNodes = []
|
||||
}
|
||||
@@ -1052,7 +1057,7 @@ class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePrevewItemNode
|
||||
inlineBotNameString = nil
|
||||
}
|
||||
|
||||
var contentPropertiesAndLayouts: [(CGSize?, ChatMessageBubbleContentProperties, ChatMessageBubblePreparePosition, Bool, (CGSize, ChatMessageBubbleContentPosition) -> (CGFloat, (CGFloat) -> (CGSize, (ListViewItemUpdateAnimation, Bool) -> Void)))] = []
|
||||
var contentPropertiesAndLayouts: [(CGSize?, ChatMessageBubbleContentProperties, ChatMessageBubblePreparePosition, BubbleItemAttributes, (CGSize, ChatMessageBubbleContentPosition) -> (CGFloat, (CGFloat) -> (CGSize, (ListViewItemUpdateAnimation, Bool) -> Void)))] = []
|
||||
|
||||
let topNodeMergeStatus: ChatMessageBubbleMergeStatus = mergedTop.merged ? (incoming ? .Left : .Right) : .None(incoming ? .Incoming : .Outgoing)
|
||||
let bottomNodeMergeStatus: ChatMessageBubbleMergeStatus = mergedBottom.merged ? (incoming ? .Left : .Right) : .None(incoming ? .Incoming : .Outgoing)
|
||||
@@ -1100,16 +1105,21 @@ class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePrevewItemNode
|
||||
}
|
||||
|
||||
var index = 0
|
||||
for (message, _, attributes, isAttachment, prepareLayout) in contentPropertiesAndPrepareLayouts {
|
||||
for (message, _, attributes, bubbleAttributes, prepareLayout) in contentPropertiesAndPrepareLayouts {
|
||||
let topPosition: ChatMessageBubbleRelativePosition
|
||||
let bottomPosition: ChatMessageBubbleRelativePosition
|
||||
|
||||
if index != 0 && contentPropertiesAndPrepareLayouts[index - 1].3 {
|
||||
topPosition = .Neighbour(true, .freeform)
|
||||
} else {
|
||||
topPosition = .Neighbour(false, .freeform)
|
||||
var topBubbleAttributes = BubbleItemAttributes(isAttachment: false, neighborType: .freeform)
|
||||
var bottomBubbleAttributes = BubbleItemAttributes(isAttachment: false, neighborType: .freeform)
|
||||
if index != 0 {
|
||||
topBubbleAttributes = contentPropertiesAndPrepareLayouts[index - 1].3
|
||||
}
|
||||
bottomPosition = .Neighbour(false, .freeform)
|
||||
if index != contentPropertiesAndPrepareLayouts.count - 1 {
|
||||
bottomBubbleAttributes = contentPropertiesAndPrepareLayouts[index + 1].3
|
||||
}
|
||||
|
||||
topPosition = .Neighbour(topBubbleAttributes.isAttachment, topBubbleAttributes.neighborType)
|
||||
bottomPosition = .Neighbour(bottomBubbleAttributes.isAttachment, bottomBubbleAttributes.neighborType)
|
||||
|
||||
let prepareContentPosition: ChatMessageBubblePreparePosition
|
||||
if let mosaicRange = mosaicRange, mosaicRange.contains(index) {
|
||||
@@ -1118,7 +1128,7 @@ class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePrevewItemNode
|
||||
let refinedBottomPosition: ChatMessageBubbleRelativePosition
|
||||
if index == contentPropertiesAndPrepareLayouts.count - 1 {
|
||||
refinedBottomPosition = .None(.Left)
|
||||
} else if index == contentPropertiesAndPrepareLayouts.count - 2 && contentPropertiesAndPrepareLayouts[contentPropertiesAndPrepareLayouts.count - 1].3 {
|
||||
} else if index == contentPropertiesAndPrepareLayouts.count - 2 && contentPropertiesAndPrepareLayouts[contentPropertiesAndPrepareLayouts.count - 1].3.isAttachment {
|
||||
refinedBottomPosition = .None(.Left)
|
||||
} else {
|
||||
refinedBottomPosition = bottomPosition
|
||||
@@ -1151,7 +1161,7 @@ class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePrevewItemNode
|
||||
let (properties, unboundSize, maxNodeWidth, nodeLayout) = prepareLayout(contentItem, layoutConstants, prepareContentPosition, itemSelection, CGSize(width: maximumContentWidth, height: CGFloat.greatestFiniteMagnitude))
|
||||
maximumNodeWidth = min(maximumNodeWidth, maxNodeWidth)
|
||||
|
||||
contentPropertiesAndLayouts.append((unboundSize, properties, prepareContentPosition, isAttachment, nodeLayout))
|
||||
contentPropertiesAndLayouts.append((unboundSize, properties, prepareContentPosition, bubbleAttributes, nodeLayout))
|
||||
|
||||
switch properties.hidesBackground {
|
||||
case .never:
|
||||
@@ -1266,7 +1276,7 @@ class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePrevewItemNode
|
||||
|
||||
maximumNodeWidth = size.width
|
||||
|
||||
if mosaicRange.upperBound == contentPropertiesAndLayouts.count {
|
||||
if mosaicRange.upperBound == contentPropertiesAndLayouts.count || contentPropertiesAndLayouts[contentPropertiesAndLayouts.count - 1].3.isAttachment {
|
||||
let message = item.content.firstMessage
|
||||
|
||||
var edited = false
|
||||
@@ -1601,19 +1611,26 @@ class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePrevewItemNode
|
||||
case .linear:
|
||||
let topPosition: ChatMessageBubbleRelativePosition
|
||||
let bottomPosition: ChatMessageBubbleRelativePosition
|
||||
|
||||
var topBubbleAttributes = BubbleItemAttributes(isAttachment: false, neighborType: .freeform)
|
||||
var bottomBubbleAttributes = BubbleItemAttributes(isAttachment: false, neighborType: .freeform)
|
||||
if i != 0 {
|
||||
topBubbleAttributes = contentPropertiesAndLayouts[i - 1].3
|
||||
}
|
||||
if i != contentPropertiesAndLayouts.count - 1 {
|
||||
bottomBubbleAttributes = contentPropertiesAndLayouts[i + 1].3
|
||||
}
|
||||
|
||||
if i == 0 {
|
||||
topPosition = firstNodeTopPosition
|
||||
} else if i == contentNodeCount - 1 && i != 0 && contentPropertiesAndLayouts[i - 1].3 {
|
||||
topPosition = .Neighbour(true, .freeform)
|
||||
} else {
|
||||
topPosition = .Neighbour(false, .freeform)
|
||||
topPosition = .Neighbour(topBubbleAttributes.isAttachment, topBubbleAttributes.neighborType)
|
||||
}
|
||||
|
||||
if i == contentNodeCount - 1 {
|
||||
bottomPosition = lastNodeTopPosition
|
||||
} else {
|
||||
bottomPosition = .Neighbour(false, .freeform)
|
||||
bottomPosition = .Neighbour(bottomBubbleAttributes.isAttachment, bottomBubbleAttributes.neighborType)
|
||||
}
|
||||
|
||||
contentPosition = .linear(top: topPosition, bottom: bottomPosition)
|
||||
@@ -1832,7 +1849,7 @@ class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePrevewItemNode
|
||||
replyInfoOriginY: CGFloat,
|
||||
removedContentNodeIndices: [Int]?,
|
||||
addedContentNodes: [(Message, ChatMessageBubbleContentNode)]?,
|
||||
contentNodeMessagesAndClasses: [(Message, AnyClass, ChatMessageEntryAttributes, Bool)],
|
||||
contentNodeMessagesAndClasses: [(Message, AnyClass, ChatMessageEntryAttributes, BubbleItemAttributes)],
|
||||
contentNodeFramesPropertiesAndApply: [(CGRect, ChatMessageBubbleContentProperties, (ListViewItemUpdateAnimation, Bool) -> Void)],
|
||||
mosaicStatusOrigin: CGPoint?,
|
||||
mosaicStatusSizeAndApply: (CGSize, (Bool) -> ChatMessageDateAndStatusNode)?,
|
||||
@@ -2475,8 +2492,10 @@ class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePrevewItemNode
|
||||
|
||||
if item.content.firstMessage.id.peerId.isRepliesOrSavedMessages(accountPeerId: item.context.account.peerId) {
|
||||
navigate = .chat(textInputState: nil, subject: nil, peekData: nil)
|
||||
} else {
|
||||
} else if openPeerId.namespace == Namespaces.Peer.CloudUser {
|
||||
navigate = .info
|
||||
} else {
|
||||
navigate = .chat(textInputState: nil, subject: nil, peekData: nil)
|
||||
}
|
||||
|
||||
for attribute in item.content.firstMessage.attributes {
|
||||
|
||||
@@ -100,10 +100,13 @@ final class ChatMessageCommentFooterContentNode: ChatMessageBubbleContentNode {
|
||||
let contentProperties = ChatMessageBubbleContentProperties(hidesSimpleAuthorHeader: false, headerSpacing: 0.0, hidesBackground: .never, forceFullCorners: false, forceAlignment: .none)
|
||||
|
||||
let displaySeparator: Bool
|
||||
if case let .linear(top, _) = preparePosition, case .Neighbour(true, _) = top {
|
||||
let topOffset: CGFloat
|
||||
if case let .linear(top, _) = preparePosition, case .Neighbour(_, .media) = top {
|
||||
displaySeparator = false
|
||||
topOffset = 2.0
|
||||
} else {
|
||||
displaySeparator = true
|
||||
topOffset = 0.0
|
||||
}
|
||||
|
||||
return (contentProperties, nil, CGFloat.greatestFiniteMagnitude, { constrainedSize, position in
|
||||
@@ -163,7 +166,7 @@ final class ChatMessageCommentFooterContentNode: ChatMessageBubbleContentNode {
|
||||
|
||||
let (textLayout, textApply) = textLayout(TextNodeLayoutArguments(attributedString: attributedText, backgroundColor: nil, maximumNumberOfLines: 0, truncationType: .end, constrainedSize: textConstrainedSize, alignment: .natural, cutout: nil, insets: textInsets, lineColor: messageTheme.accentControlColor))
|
||||
|
||||
var textFrame = CGRect(origin: CGPoint(x: -textInsets.left + textLeftInset, y: -textInsets.top + 5.0), size: textLayout.size)
|
||||
var textFrame = CGRect(origin: CGPoint(x: -textInsets.left + textLeftInset, y: -textInsets.top + 5.0 + topOffset), size: textLayout.size)
|
||||
var textFrameWithoutInsets = CGRect(origin: CGPoint(x: textFrame.origin.x + textInsets.left, y: textFrame.origin.y + textInsets.top), size: CGSize(width: textFrame.width - textInsets.left - textInsets.right, height: textFrame.height - textInsets.top - textInsets.bottom))
|
||||
|
||||
textFrame = textFrame.offsetBy(dx: layoutConstants.text.bubbleInsets.left, dy: layoutConstants.text.bubbleInsets.top - 5.0 + UIScreenPixel)
|
||||
@@ -189,7 +192,7 @@ final class ChatMessageCommentFooterContentNode: ChatMessageBubbleContentNode {
|
||||
|
||||
boundingSize = textFrameWithoutInsets.size
|
||||
boundingSize.width += layoutConstants.text.bubbleInsets.left + layoutConstants.text.bubbleInsets.right
|
||||
boundingSize.height = 40.0
|
||||
boundingSize.height = 40.0 + topOffset
|
||||
|
||||
return (boundingSize, { [weak self] animation, synchronousLoad in
|
||||
if let strongSelf = self {
|
||||
@@ -225,17 +228,17 @@ final class ChatMessageCommentFooterContentNode: ChatMessageBubbleContentNode {
|
||||
|
||||
if let iconImage = iconImage {
|
||||
strongSelf.iconNode.image = iconImage
|
||||
strongSelf.iconNode.frame = CGRect(origin: CGPoint(x: 15.0 + iconOffset.x, y: 6.0 + iconOffset.y), size: iconImage.size)
|
||||
strongSelf.iconNode.frame = CGRect(origin: CGPoint(x: 15.0 + iconOffset.x, y: 6.0 + iconOffset.y + topOffset), size: iconImage.size)
|
||||
}
|
||||
|
||||
if let arrowImage = arrowImage {
|
||||
strongSelf.arrowNode.image = arrowImage
|
||||
strongSelf.arrowNode.frame = CGRect(origin: CGPoint(x: boundingWidth - 33.0, y: 6.0), size: arrowImage.size)
|
||||
strongSelf.arrowNode.frame = CGRect(origin: CGPoint(x: boundingWidth - 33.0, y: 6.0 + topOffset), size: arrowImage.size)
|
||||
}
|
||||
|
||||
strongSelf.iconNode.isHidden = !replyPeers.isEmpty
|
||||
|
||||
let avatarsFrame = CGRect(origin: CGPoint(x: 13.0, y: 3.0), size: CGSize(width: imageSize * 3.0, height: imageSize))
|
||||
let avatarsFrame = CGRect(origin: CGPoint(x: 13.0, y: 3.0 + topOffset), size: CGSize(width: imageSize * 3.0, height: imageSize))
|
||||
strongSelf.avatarsNode.frame = avatarsFrame
|
||||
strongSelf.avatarsNode.updateLayout(size: avatarsFrame.size)
|
||||
strongSelf.avatarsNode.update(context: item.context, peers: replyPeers, synchronousLoad: synchronousLoad, imageSize: imageSize, imageSpacing: imageSpacing, borderWidth: 2.0 - UIScreenPixel)
|
||||
@@ -245,6 +248,8 @@ final class ChatMessageCommentFooterContentNode: ChatMessageBubbleContentNode {
|
||||
strongSelf.separatorNode.frame = CGRect(origin: CGPoint(x: layoutConstants.bubble.strokeInsets.left, y: -3.0), size: CGSize(width: boundingWidth - layoutConstants.bubble.strokeInsets.left - layoutConstants.bubble.strokeInsets.right, height: UIScreenPixel))
|
||||
|
||||
strongSelf.buttonNode.frame = CGRect(origin: CGPoint(x: 0.0, y: 0.0), size: CGSize(width: boundingWidth, height: boundingSize.height))
|
||||
|
||||
strongSelf.buttonNode.isUserInteractionEnabled = item.message.id.namespace == Namespaces.Message.Cloud
|
||||
}
|
||||
})
|
||||
})
|
||||
@@ -276,7 +281,7 @@ final class ChatMessageCommentFooterContentNode: ChatMessageBubbleContentNode {
|
||||
}
|
||||
|
||||
override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
|
||||
if self.buttonNode.frame.contains(point) {
|
||||
if self.buttonNode.isUserInteractionEnabled && self.buttonNode.frame.contains(point) {
|
||||
return self.buttonNode.view
|
||||
}
|
||||
return nil
|
||||
|
||||
@@ -176,7 +176,7 @@ class ChatMessageContactBubbleContentNode: ChatMessageBubbleContentNode {
|
||||
|
||||
let statusType: ChatMessageDateAndStatusType?
|
||||
switch position {
|
||||
case .linear(_, .None):
|
||||
case .linear(_, .None), .linear(_, .Neighbour(true, _)):
|
||||
if item.message.effectivelyIncoming(item.context.account.peerId) {
|
||||
statusType = .BubbleIncoming
|
||||
} else {
|
||||
|
||||
@@ -69,7 +69,7 @@ class ChatMessageFileBubbleContentNode: ChatMessageBubbleContentNode {
|
||||
let incoming = item.message.effectivelyIncoming(item.context.account.peerId)
|
||||
let statusType: ChatMessageDateAndStatusType?
|
||||
switch preparePosition {
|
||||
case .linear(_, .None):
|
||||
case .linear(_, .None), .linear(_, .Neighbour(true, _)):
|
||||
if incoming {
|
||||
statusType = .BubbleIncoming
|
||||
} else {
|
||||
|
||||
@@ -212,7 +212,7 @@ class ChatMessageMapBubbleContentNode: ChatMessageBubbleContentNode {
|
||||
|
||||
let statusType: ChatMessageDateAndStatusType?
|
||||
switch position {
|
||||
case .linear(_, .None):
|
||||
case .linear(_, .None), .linear(_, .Neighbour(true, _)):
|
||||
if selectedMedia?.venue != nil || activeLiveBroadcastingTimeout != nil {
|
||||
if item.message.effectivelyIncoming(item.context.account.peerId) {
|
||||
statusType = .BubbleIncoming
|
||||
|
||||
@@ -207,7 +207,7 @@ class ChatMessageMediaBubbleContentNode: ChatMessageBubbleContentNode {
|
||||
|
||||
let statusType: ChatMessageDateAndStatusType?
|
||||
switch position {
|
||||
case .linear(_, .None):
|
||||
case .linear(_, .None), .linear(_, .Neighbour(true, _)):
|
||||
if item.message.effectivelyIncoming(item.context.account.peerId) {
|
||||
statusType = .ImageIncoming
|
||||
} else {
|
||||
|
||||
@@ -1054,7 +1054,7 @@ class ChatMessagePollBubbleContentNode: ChatMessageBubbleContentNode {
|
||||
|
||||
let statusType: ChatMessageDateAndStatusType?
|
||||
switch position {
|
||||
case .linear(_, .None):
|
||||
case .linear(_, .None), .linear(_, .Neighbour(true, _)):
|
||||
if incoming {
|
||||
statusType = .BubbleIncoming
|
||||
} else {
|
||||
|
||||
@@ -85,7 +85,7 @@ class ChatMessageRestrictedBubbleContentNode: ChatMessageBubbleContentNode {
|
||||
|
||||
let statusType: ChatMessageDateAndStatusType?
|
||||
switch position {
|
||||
case .linear(_, .None):
|
||||
case .linear(_, .None), .linear(_, .Neighbour(true, _)):
|
||||
if incoming {
|
||||
statusType = .BubbleIncoming
|
||||
} else {
|
||||
|
||||
@@ -140,14 +140,14 @@ class ChatMessageTextBubbleContentNode: ChatMessageBubbleContentNode {
|
||||
let statusType: ChatMessageDateAndStatusType?
|
||||
var displayStatus = false
|
||||
switch position {
|
||||
case let .linear(_, neighbor):
|
||||
if case .None = neighbor {
|
||||
displayStatus = true
|
||||
} else if case .Neighbour(true, _) = neighbor {
|
||||
displayStatus = true
|
||||
}
|
||||
default:
|
||||
break
|
||||
case let .linear(_, neighbor):
|
||||
if case .None = neighbor {
|
||||
displayStatus = true
|
||||
} else if case .Neighbour(true, _) = neighbor {
|
||||
displayStatus = true
|
||||
}
|
||||
default:
|
||||
break
|
||||
}
|
||||
if displayStatus {
|
||||
if incoming {
|
||||
|
||||
@@ -203,6 +203,7 @@ final class ChatTitleView: UIView, NavigationBarTitleView {
|
||||
self.setNeedsLayout()
|
||||
}
|
||||
self.isUserInteractionEnabled = isEnabled
|
||||
self.button.isUserInteractionEnabled = isEnabled
|
||||
self.updateStatus()
|
||||
}
|
||||
}
|
||||
@@ -635,6 +636,9 @@ final class ChatTitleView: UIView, NavigationBarTitleView {
|
||||
}
|
||||
|
||||
override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
|
||||
if !self.isUserInteractionEnabled {
|
||||
return nil
|
||||
}
|
||||
if self.button.frame.contains(point) {
|
||||
return self.button.view
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user