mirror of
https://github.com/TelegramMessenger/Telegram-iOS.git
synced 2026-07-06 03:33:41 +02:00
Refactoring
This commit is contained in:
parent
8b7ca5f4f7
commit
3f6d4678f5
61 changed files with 785 additions and 516 deletions
|
|
@ -341,6 +341,11 @@ swift_library(
|
|||
"//submodules/TelegramUI/Components/Chat/ForwardAccessoryPanelNode",
|
||||
"//submodules/TelegramUI/Components/LegacyMessageInputPanel",
|
||||
"//submodules/TelegramUI/Components/Chat/ChatMessageDateAndStatusNode",
|
||||
"//submodules/TelegramUI/Components/Chat/ChatMessageBubbleContentNode",
|
||||
"//submodules/TelegramUI/Components/Chat/ChatHistoryEntry",
|
||||
"//submodules/TelegramUI/Components/Chat/ChatMessageItemCommon",
|
||||
"//submodules/TelegramUI/Components/Chat/ChatMessageTextBubbleContentNode",
|
||||
"//submodules/TelegramUI/Components/Chat/EditableTokenListNode",
|
||||
] + select({
|
||||
"@build_bazel_rules_apple//apple:ios_arm64": appcenter_targets,
|
||||
"//build-system:ios_sim_arm64": [],
|
||||
|
|
|
|||
23
submodules/TelegramUI/Components/Chat/ChatHistoryEntry/BUILD
Normal file
23
submodules/TelegramUI/Components/Chat/ChatHistoryEntry/BUILD
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
load("@build_bazel_rules_swift//swift:swift.bzl", "swift_library")
|
||||
|
||||
swift_library(
|
||||
name = "ChatHistoryEntry",
|
||||
module_name = "ChatHistoryEntry",
|
||||
srcs = glob([
|
||||
"Sources/**/*.swift",
|
||||
]),
|
||||
copts = [
|
||||
"-warnings-as-errors",
|
||||
],
|
||||
deps = [
|
||||
"//submodules/Postbox",
|
||||
"//submodules/TelegramCore",
|
||||
"//submodules/TelegramPresentationData",
|
||||
"//submodules/MergeLists",
|
||||
"//submodules/TemporaryCachedPeerDataManager",
|
||||
"//submodules/AccountContext",
|
||||
],
|
||||
visibility = [
|
||||
"//visibility:public",
|
||||
],
|
||||
)
|
||||
|
|
@ -12,15 +12,15 @@ public enum ChatMessageEntryContentType {
|
|||
}
|
||||
|
||||
public struct ChatMessageEntryAttributes: Equatable {
|
||||
var rank: CachedChannelAdminRank?
|
||||
var isContact: Bool
|
||||
var contentTypeHint: ChatMessageEntryContentType
|
||||
var updatingMedia: ChatUpdatingMessageMedia?
|
||||
var isPlaying: Bool
|
||||
var isCentered: Bool
|
||||
var authorStoryStats: PeerStoryStats?
|
||||
public var rank: CachedChannelAdminRank?
|
||||
public var isContact: Bool
|
||||
public var contentTypeHint: ChatMessageEntryContentType
|
||||
public var updatingMedia: ChatUpdatingMessageMedia?
|
||||
public var isPlaying: Bool
|
||||
public var isCentered: Bool
|
||||
public var authorStoryStats: PeerStoryStats?
|
||||
|
||||
init(rank: CachedChannelAdminRank?, isContact: Bool, contentTypeHint: ChatMessageEntryContentType, updatingMedia: ChatUpdatingMessageMedia?, isPlaying: Bool, isCentered: Bool, authorStoryStats: PeerStoryStats?) {
|
||||
public init(rank: CachedChannelAdminRank?, isContact: Bool, contentTypeHint: ChatMessageEntryContentType, updatingMedia: ChatUpdatingMessageMedia?, isPlaying: Bool, isCentered: Bool, authorStoryStats: PeerStoryStats?) {
|
||||
self.rank = rank
|
||||
self.isContact = isContact
|
||||
self.contentTypeHint = contentTypeHint
|
||||
|
|
@ -41,7 +41,7 @@ public struct ChatMessageEntryAttributes: Equatable {
|
|||
}
|
||||
}
|
||||
|
||||
enum ChatHistoryEntry: Identifiable, Comparable {
|
||||
public enum ChatHistoryEntry: Identifiable, Comparable {
|
||||
case MessageEntry(Message, ChatPresentationData, Bool, MessageHistoryEntryLocation?, ChatHistoryMessageSelection, ChatMessageEntryAttributes)
|
||||
case MessageGroupEntry(MessageGroupInfo, [(Message, Bool, ChatHistoryMessageSelection, ChatMessageEntryAttributes, MessageHistoryEntryLocation?)], ChatPresentationData)
|
||||
case UnreadEntry(MessageIndex, ChatPresentationData)
|
||||
|
|
@ -49,7 +49,7 @@ enum ChatHistoryEntry: Identifiable, Comparable {
|
|||
case ChatInfoEntry(String, String, TelegramMediaImage?, TelegramMediaFile?, ChatPresentationData)
|
||||
case SearchEntry(PresentationTheme, PresentationStrings)
|
||||
|
||||
var stableId: UInt64 {
|
||||
public var stableId: UInt64 {
|
||||
switch self {
|
||||
case let .MessageEntry(message, _, _, _, _, attributes):
|
||||
let type: UInt64
|
||||
|
|
@ -75,7 +75,7 @@ enum ChatHistoryEntry: Identifiable, Comparable {
|
|||
}
|
||||
}
|
||||
|
||||
var index: MessageIndex {
|
||||
public var index: MessageIndex {
|
||||
switch self {
|
||||
case let .MessageEntry(message, _, _, _, _, _):
|
||||
return message.index
|
||||
|
|
@ -92,7 +92,7 @@ enum ChatHistoryEntry: Identifiable, Comparable {
|
|||
}
|
||||
}
|
||||
|
||||
var firstIndex: MessageIndex {
|
||||
public var firstIndex: MessageIndex {
|
||||
switch self {
|
||||
case let .MessageEntry(message, _, _, _, _, _):
|
||||
return message.index
|
||||
|
|
@ -109,7 +109,7 @@ enum ChatHistoryEntry: Identifiable, Comparable {
|
|||
}
|
||||
}
|
||||
|
||||
static func ==(lhs: ChatHistoryEntry, rhs: ChatHistoryEntry) -> Bool {
|
||||
public static func ==(lhs: ChatHistoryEntry, rhs: ChatHistoryEntry) -> Bool {
|
||||
switch lhs {
|
||||
case let .MessageEntry(lhsMessage, lhsPresentationData, lhsRead, _, lhsSelection, lhsAttributes):
|
||||
switch rhs {
|
||||
|
|
@ -264,7 +264,7 @@ enum ChatHistoryEntry: Identifiable, Comparable {
|
|||
}
|
||||
}
|
||||
|
||||
static func <(lhs: ChatHistoryEntry, rhs: ChatHistoryEntry) -> Bool {
|
||||
public static func <(lhs: ChatHistoryEntry, rhs: ChatHistoryEntry) -> Bool {
|
||||
let lhsIndex = lhs.index
|
||||
let rhsIndex = rhs.index
|
||||
if lhsIndex == rhsIndex {
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
load("@build_bazel_rules_swift//swift:swift.bzl", "swift_library")
|
||||
|
||||
swift_library(
|
||||
name = "ChatMessageBubbleContentNode",
|
||||
module_name = "ChatMessageBubbleContentNode",
|
||||
srcs = glob([
|
||||
"Sources/**/*.swift",
|
||||
]),
|
||||
copts = [
|
||||
"-warnings-as-errors",
|
||||
],
|
||||
deps = [
|
||||
"//submodules/AsyncDisplayKit",
|
||||
"//submodules/Display",
|
||||
"//submodules/Postbox",
|
||||
"//submodules/TelegramCore",
|
||||
"//submodules/TelegramUIPreferences",
|
||||
"//submodules/TelegramPresentationData",
|
||||
"//submodules/AccountContext",
|
||||
"//submodules/ChatMessageBackground",
|
||||
"//submodules/TelegramUI/Components/ChatControllerInteraction",
|
||||
"//submodules/TelegramUI/Components/Chat/ChatHistoryEntry",
|
||||
"//submodules/TelegramUI/Components/Chat/ChatMessageItemCommon",
|
||||
],
|
||||
visibility = [
|
||||
"//visibility:public",
|
||||
],
|
||||
)
|
||||
|
|
@ -0,0 +1,269 @@
|
|||
import Foundation
|
||||
import UIKit
|
||||
import AsyncDisplayKit
|
||||
import Display
|
||||
import Postbox
|
||||
import TelegramCore
|
||||
import TelegramUIPreferences
|
||||
import TelegramPresentationData
|
||||
import AccountContext
|
||||
import ChatMessageBackground
|
||||
import ChatControllerInteraction
|
||||
import ChatHistoryEntry
|
||||
import ChatMessageItemCommon
|
||||
|
||||
public enum ChatMessageBubbleContentBackgroundHiding {
|
||||
case never
|
||||
case emptyWallpaper
|
||||
case always
|
||||
}
|
||||
|
||||
public enum ChatMessageBubbleContentAlignment {
|
||||
case none
|
||||
case center
|
||||
}
|
||||
|
||||
public struct ChatMessageBubbleContentProperties {
|
||||
public let hidesSimpleAuthorHeader: Bool
|
||||
public let headerSpacing: CGFloat
|
||||
public let hidesBackground: ChatMessageBubbleContentBackgroundHiding
|
||||
public let forceFullCorners: Bool
|
||||
public let forceAlignment: ChatMessageBubbleContentAlignment
|
||||
public let shareButtonOffset: CGPoint?
|
||||
public let hidesHeaders: Bool
|
||||
public let avatarOffset: CGFloat?
|
||||
|
||||
public init(
|
||||
hidesSimpleAuthorHeader: Bool,
|
||||
headerSpacing: CGFloat,
|
||||
hidesBackground: ChatMessageBubbleContentBackgroundHiding,
|
||||
forceFullCorners: Bool,
|
||||
forceAlignment: ChatMessageBubbleContentAlignment,
|
||||
shareButtonOffset: CGPoint? = nil,
|
||||
hidesHeaders: Bool = false,
|
||||
avatarOffset: CGFloat? = nil
|
||||
) {
|
||||
self.hidesSimpleAuthorHeader = hidesSimpleAuthorHeader
|
||||
self.headerSpacing = headerSpacing
|
||||
self.hidesBackground = hidesBackground
|
||||
self.forceFullCorners = forceFullCorners
|
||||
self.forceAlignment = forceAlignment
|
||||
self.shareButtonOffset = shareButtonOffset
|
||||
self.hidesHeaders = hidesHeaders
|
||||
self.avatarOffset = avatarOffset
|
||||
}
|
||||
}
|
||||
|
||||
public enum ChatMessageBubbleNoneMergeStatus {
|
||||
case Incoming
|
||||
case Outgoing
|
||||
case None
|
||||
}
|
||||
|
||||
public enum ChatMessageBubbleMergeStatus {
|
||||
case None(ChatMessageBubbleNoneMergeStatus)
|
||||
case Left
|
||||
case Right
|
||||
case Both
|
||||
}
|
||||
|
||||
public enum ChatMessageBubbleRelativePosition {
|
||||
public enum NeighbourType {
|
||||
case media
|
||||
case freeform
|
||||
}
|
||||
|
||||
public enum NeighbourSpacing {
|
||||
case `default`
|
||||
case condensed
|
||||
case overlap(CGFloat)
|
||||
}
|
||||
|
||||
case None(ChatMessageBubbleMergeStatus)
|
||||
case BubbleNeighbour
|
||||
case Neighbour(Bool, NeighbourType, NeighbourSpacing)
|
||||
}
|
||||
|
||||
public enum ChatMessageBubbleContentMosaicNeighbor {
|
||||
case merged
|
||||
case mergedBubble
|
||||
case none(tail: Bool)
|
||||
}
|
||||
|
||||
public struct ChatMessageBubbleContentMosaicPosition {
|
||||
public let topLeft: ChatMessageBubbleContentMosaicNeighbor
|
||||
public let topRight: ChatMessageBubbleContentMosaicNeighbor
|
||||
public let bottomLeft: ChatMessageBubbleContentMosaicNeighbor
|
||||
public let bottomRight: ChatMessageBubbleContentMosaicNeighbor
|
||||
|
||||
public init(topLeft: ChatMessageBubbleContentMosaicNeighbor, topRight: ChatMessageBubbleContentMosaicNeighbor, bottomLeft: ChatMessageBubbleContentMosaicNeighbor, bottomRight: ChatMessageBubbleContentMosaicNeighbor) {
|
||||
self.topLeft = topLeft
|
||||
self.topRight = topRight
|
||||
self.bottomLeft = bottomLeft
|
||||
self.bottomRight = bottomRight
|
||||
}
|
||||
}
|
||||
|
||||
public enum ChatMessageBubbleContentPosition {
|
||||
case linear(top: ChatMessageBubbleRelativePosition, bottom: ChatMessageBubbleRelativePosition)
|
||||
case mosaic(position: ChatMessageBubbleContentMosaicPosition, wide: Bool)
|
||||
}
|
||||
|
||||
public enum ChatMessageBubblePreparePosition {
|
||||
case linear(top: ChatMessageBubbleRelativePosition, bottom: ChatMessageBubbleRelativePosition)
|
||||
case mosaic(top: ChatMessageBubbleRelativePosition, bottom: ChatMessageBubbleRelativePosition)
|
||||
}
|
||||
|
||||
public enum ChatMessageBubbleContentTapAction {
|
||||
case none
|
||||
case url(url: String, concealed: Bool)
|
||||
case textMention(String)
|
||||
case peerMention(peerId: PeerId, mention: String, openProfile: Bool)
|
||||
case botCommand(String)
|
||||
case hashtag(String?, String)
|
||||
case instantPage
|
||||
case wallpaper
|
||||
case theme
|
||||
case call(peerId: PeerId, isVideo: Bool)
|
||||
case openMessage
|
||||
case timecode(Double, String)
|
||||
case tooltip(String, ASDisplayNode?, CGRect?)
|
||||
case bankCard(String)
|
||||
case ignore
|
||||
case openPollResults(Data)
|
||||
case copy(String)
|
||||
case largeEmoji(String, String?, TelegramMediaFile)
|
||||
case customEmoji(TelegramMediaFile)
|
||||
}
|
||||
|
||||
public final class ChatMessageBubbleContentItem {
|
||||
public let context: AccountContext
|
||||
public let controllerInteraction: ChatControllerInteraction
|
||||
public let message: Message
|
||||
public let topMessage: Message
|
||||
public let read: Bool
|
||||
public let chatLocation: ChatLocation
|
||||
public let presentationData: ChatPresentationData
|
||||
public let associatedData: ChatMessageItemAssociatedData
|
||||
public let attributes: ChatMessageEntryAttributes
|
||||
public let isItemPinned: Bool
|
||||
public let isItemEdited: Bool
|
||||
|
||||
public init(context: AccountContext, controllerInteraction: ChatControllerInteraction, message: Message, topMessage: Message, read: Bool, chatLocation: ChatLocation, presentationData: ChatPresentationData, associatedData: ChatMessageItemAssociatedData, attributes: ChatMessageEntryAttributes, isItemPinned: Bool, isItemEdited: Bool) {
|
||||
self.context = context
|
||||
self.controllerInteraction = controllerInteraction
|
||||
self.message = message
|
||||
self.topMessage = topMessage
|
||||
self.read = read
|
||||
self.chatLocation = chatLocation
|
||||
self.presentationData = presentationData
|
||||
self.associatedData = associatedData
|
||||
self.attributes = attributes
|
||||
self.isItemPinned = isItemPinned
|
||||
self.isItemEdited = isItemEdited
|
||||
}
|
||||
}
|
||||
|
||||
open class ChatMessageBubbleContentNode: ASDisplayNode {
|
||||
open var supportsMosaic: Bool {
|
||||
return false
|
||||
}
|
||||
|
||||
public weak var bubbleBackgroundNode: ChatMessageBackground?
|
||||
public weak var bubbleBackdropNode: ChatMessageBubbleBackdrop?
|
||||
|
||||
open var visibility: ListViewItemNodeVisibility = .none
|
||||
|
||||
public var item: ChatMessageBubbleContentItem?
|
||||
|
||||
public var updateIsTextSelectionActive: ((Bool) -> Void)?
|
||||
|
||||
open var disablesClipping: Bool {
|
||||
return false
|
||||
}
|
||||
|
||||
required public override init() {
|
||||
super.init()
|
||||
}
|
||||
|
||||
open func asyncLayoutContent() -> (_ item: ChatMessageBubbleContentItem, _ layoutConstants: ChatMessageItemLayoutConstants, _ preparePosition: ChatMessageBubblePreparePosition, _ messageSelection: Bool?, _ constrainedSize: CGSize, _ avatarInset: CGFloat) -> (ChatMessageBubbleContentProperties, unboundSize: CGSize?, maxWidth: CGFloat, layout: (CGSize, ChatMessageBubbleContentPosition) -> (CGFloat, (CGFloat) -> (CGSize, (ListViewItemUpdateAnimation, Bool, ListViewItemApply?) -> Void))) {
|
||||
preconditionFailure()
|
||||
}
|
||||
|
||||
open func animateInsertion(_ currentTimestamp: Double, duration: Double) {
|
||||
}
|
||||
|
||||
open func animateAdded(_ currentTimestamp: Double, duration: Double) {
|
||||
}
|
||||
|
||||
open func animateRemoved(_ currentTimestamp: Double, duration: Double) {
|
||||
}
|
||||
|
||||
open func animateInsertionIntoBubble(_ duration: Double) {
|
||||
}
|
||||
|
||||
open func animateRemovalFromBubble(_ duration: Double, completion: @escaping () -> Void) {
|
||||
self.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.25, removeOnCompletion: false, completion: { _ in
|
||||
completion()
|
||||
})
|
||||
}
|
||||
|
||||
open func transitionNode(messageId: MessageId, media: Media, adjustRect: Bool) -> (ASDisplayNode, CGRect, () -> (UIView?, UIView?))? {
|
||||
return nil
|
||||
}
|
||||
|
||||
open func updateHiddenMedia(_ media: [Media]?) -> Bool {
|
||||
return false
|
||||
}
|
||||
|
||||
open func updateSearchTextHighlightState(text: String?, messages: [MessageIndex]?) {
|
||||
}
|
||||
|
||||
open func updateAutomaticMediaDownloadSettings(_ settings: MediaAutoDownloadSettings) {
|
||||
}
|
||||
|
||||
open func playMediaWithSound() -> ((Double?) -> Void, Bool, Bool, Bool, ASDisplayNode?)? {
|
||||
return nil
|
||||
}
|
||||
|
||||
open func tapActionAtPoint(_ point: CGPoint, gesture: TapLongTapOrDoubleTapGesture, isEstimating: Bool) -> ChatMessageBubbleContentTapAction {
|
||||
return .none
|
||||
}
|
||||
|
||||
open func updateTouchesAtPoint(_ point: CGPoint?) {
|
||||
}
|
||||
|
||||
open func updateHighlightedState(animated: Bool) -> Bool {
|
||||
return false
|
||||
}
|
||||
|
||||
open func willUpdateIsExtractedToContextPreview(_ value: Bool) {
|
||||
}
|
||||
|
||||
open func updateIsExtractedToContextPreview(_ value: Bool) {
|
||||
}
|
||||
|
||||
open func updateAbsoluteRect(_ rect: CGRect, within containerSize: CGSize) {
|
||||
}
|
||||
|
||||
open func applyAbsoluteOffset(value: CGPoint, animationCurve: ContainedViewLayoutTransitionCurve, duration: Double) {
|
||||
}
|
||||
|
||||
open func applyAbsoluteOffsetSpring(value: CGFloat, duration: Double, damping: CGFloat) {
|
||||
}
|
||||
|
||||
open func unreadMessageRangeUpdated() {
|
||||
}
|
||||
|
||||
open func reactionTargetView(value: MessageReaction.Reaction) -> UIView? {
|
||||
return nil
|
||||
}
|
||||
|
||||
open func targetForStoryTransition(id: StoryId) -> UIView? {
|
||||
return nil
|
||||
}
|
||||
|
||||
open func getStatusNode() -> ASDisplayNode? {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
|
@ -15,9 +15,12 @@ swift_library(
|
|||
"//submodules/TelegramCore",
|
||||
"//submodules/Display",
|
||||
"//submodules/SSignalKit/SwiftSignalKit",
|
||||
"//submodules/TelegramUIPreferences",
|
||||
"//submodules/TelegramPresentationData",
|
||||
"//submodules/AccountContext",
|
||||
"//submodules/AppBundle",
|
||||
"//submodules/TelegramStringFormatting",
|
||||
"//submodules/LocalizedPeerData",
|
||||
"//submodules/Components/ReactionButtonListComponent",
|
||||
"//submodules/Components/ReactionImageComponent",
|
||||
"//submodules/TelegramUI/Components/AnimationCache",
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ import TelegramStringFormatting
|
|||
import LocalizedPeerData
|
||||
import AccountContext
|
||||
|
||||
enum MessageTimestampStatusFormat {
|
||||
public enum MessageTimestampStatusFormat {
|
||||
case regular
|
||||
case minimal
|
||||
}
|
||||
|
|
@ -29,7 +29,7 @@ private func dateStringForDay(strings: PresentationStrings, dateTimeFormat: Pres
|
|||
}
|
||||
}
|
||||
|
||||
func stringForMessageTimestampStatus(accountPeerId: PeerId, message: Message, dateTimeFormat: PresentationDateTimeFormat, nameDisplayOrder: PresentationPersonNameOrder, strings: PresentationStrings, format: MessageTimestampStatusFormat = .regular, associatedData: ChatMessageItemAssociatedData) -> String {
|
||||
public func stringForMessageTimestampStatus(accountPeerId: PeerId, message: Message, dateTimeFormat: PresentationDateTimeFormat, nameDisplayOrder: PresentationPersonNameOrder, strings: PresentationStrings, format: MessageTimestampStatusFormat = .regular, associatedData: ChatMessageItemAssociatedData) -> String {
|
||||
if let adAttribute = message.adAttribute {
|
||||
switch adAttribute.messageType {
|
||||
case .sponsored:
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
load("@build_bazel_rules_swift//swift:swift.bzl", "swift_library")
|
||||
|
||||
swift_library(
|
||||
name = "ChatMessageItemCommon",
|
||||
module_name = "ChatMessageItemCommon",
|
||||
srcs = glob([
|
||||
"Sources/**/*.swift",
|
||||
]),
|
||||
copts = [
|
||||
"-warnings-as-errors",
|
||||
],
|
||||
deps = [
|
||||
"//submodules/Display",
|
||||
"//submodules/Postbox",
|
||||
"//submodules/TelegramCore",
|
||||
],
|
||||
visibility = [
|
||||
"//visibility:public",
|
||||
],
|
||||
)
|
||||
|
||||
|
|
@ -0,0 +1,192 @@
|
|||
import Foundation
|
||||
import UIKit
|
||||
import Display
|
||||
import Postbox
|
||||
import TelegramCore
|
||||
|
||||
public struct ChatMessageItemWidthFill {
|
||||
public var compactInset: CGFloat
|
||||
public var compactWidthBoundary: CGFloat
|
||||
public var freeMaximumFillFactor: CGFloat
|
||||
|
||||
public func widthFor(_ width: CGFloat) -> CGFloat {
|
||||
if width <= self.compactWidthBoundary {
|
||||
return max(1.0, width - self.compactInset)
|
||||
} else {
|
||||
return max(1.0, floor(width * self.freeMaximumFillFactor))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public struct ChatMessageItemBubbleLayoutConstants {
|
||||
public var edgeInset: CGFloat
|
||||
public var defaultSpacing: CGFloat
|
||||
public var mergedSpacing: CGFloat
|
||||
public var maximumWidthFill: ChatMessageItemWidthFill
|
||||
public var minimumSize: CGSize
|
||||
public var contentInsets: UIEdgeInsets
|
||||
public var borderInset: CGFloat
|
||||
public var strokeInsets: UIEdgeInsets
|
||||
|
||||
public init(edgeInset: CGFloat, defaultSpacing: CGFloat, mergedSpacing: CGFloat, maximumWidthFill: ChatMessageItemWidthFill, minimumSize: CGSize, contentInsets: UIEdgeInsets, borderInset: CGFloat, strokeInsets: UIEdgeInsets) {
|
||||
self.edgeInset = edgeInset
|
||||
self.defaultSpacing = defaultSpacing
|
||||
self.mergedSpacing = mergedSpacing
|
||||
self.maximumWidthFill = maximumWidthFill
|
||||
self.minimumSize = minimumSize
|
||||
self.contentInsets = contentInsets
|
||||
self.borderInset = borderInset
|
||||
self.strokeInsets = strokeInsets
|
||||
}
|
||||
}
|
||||
|
||||
public struct ChatMessageItemTextLayoutConstants {
|
||||
public var bubbleInsets: UIEdgeInsets
|
||||
|
||||
public init(bubbleInsets: UIEdgeInsets) {
|
||||
self.bubbleInsets = bubbleInsets
|
||||
}
|
||||
}
|
||||
|
||||
public struct ChatMessageItemImageLayoutConstants {
|
||||
public var bubbleInsets: UIEdgeInsets
|
||||
public var statusInsets: UIEdgeInsets
|
||||
public var defaultCornerRadius: CGFloat
|
||||
public var mergedCornerRadius: CGFloat
|
||||
public var contentMergedCornerRadius: CGFloat
|
||||
public var maxDimensions: CGSize
|
||||
public var minDimensions: CGSize
|
||||
|
||||
public init(bubbleInsets: UIEdgeInsets, statusInsets: UIEdgeInsets, defaultCornerRadius: CGFloat, mergedCornerRadius: CGFloat, contentMergedCornerRadius: CGFloat, maxDimensions: CGSize, minDimensions: CGSize) {
|
||||
self.bubbleInsets = bubbleInsets
|
||||
self.statusInsets = statusInsets
|
||||
self.defaultCornerRadius = defaultCornerRadius
|
||||
self.mergedCornerRadius = mergedCornerRadius
|
||||
self.contentMergedCornerRadius = contentMergedCornerRadius
|
||||
self.maxDimensions = maxDimensions
|
||||
self.minDimensions = minDimensions
|
||||
}
|
||||
}
|
||||
|
||||
public struct ChatMessageItemVideoLayoutConstants {
|
||||
public var maxHorizontalHeight: CGFloat
|
||||
public var maxVerticalHeight: CGFloat
|
||||
|
||||
public init(maxHorizontalHeight: CGFloat, maxVerticalHeight: CGFloat) {
|
||||
self.maxHorizontalHeight = maxHorizontalHeight
|
||||
self.maxVerticalHeight = maxVerticalHeight
|
||||
}
|
||||
}
|
||||
|
||||
public struct ChatMessageItemInstantVideoConstants {
|
||||
public var insets: UIEdgeInsets
|
||||
public var dimensions: CGSize
|
||||
|
||||
public init(insets: UIEdgeInsets, dimensions: CGSize) {
|
||||
self.insets = insets
|
||||
self.dimensions = dimensions
|
||||
}
|
||||
}
|
||||
|
||||
public struct ChatMessageItemFileLayoutConstants {
|
||||
public var bubbleInsets: UIEdgeInsets
|
||||
|
||||
public init(bubbleInsets: UIEdgeInsets) {
|
||||
self.bubbleInsets = bubbleInsets
|
||||
}
|
||||
}
|
||||
|
||||
public struct ChatMessageItemWallpaperLayoutConstants {
|
||||
public var maxTextWidth: CGFloat
|
||||
|
||||
public init(maxTextWidth: CGFloat) {
|
||||
self.maxTextWidth = maxTextWidth
|
||||
}
|
||||
}
|
||||
|
||||
public struct ChatMessageItemLayoutConstants {
|
||||
public var avatarDiameter: CGFloat
|
||||
public var timestampHeaderHeight: CGFloat
|
||||
|
||||
public var bubble: ChatMessageItemBubbleLayoutConstants
|
||||
public var image: ChatMessageItemImageLayoutConstants
|
||||
public var video: ChatMessageItemVideoLayoutConstants
|
||||
public var text: ChatMessageItemTextLayoutConstants
|
||||
public var file: ChatMessageItemFileLayoutConstants
|
||||
public var instantVideo: ChatMessageItemInstantVideoConstants
|
||||
public var wallpapers: ChatMessageItemWallpaperLayoutConstants
|
||||
|
||||
public init(avatarDiameter: CGFloat, timestampHeaderHeight: CGFloat, bubble: ChatMessageItemBubbleLayoutConstants, image: ChatMessageItemImageLayoutConstants, video: ChatMessageItemVideoLayoutConstants, text: ChatMessageItemTextLayoutConstants, file: ChatMessageItemFileLayoutConstants, instantVideo: ChatMessageItemInstantVideoConstants, wallpapers: ChatMessageItemWallpaperLayoutConstants) {
|
||||
self.avatarDiameter = avatarDiameter
|
||||
self.timestampHeaderHeight = timestampHeaderHeight
|
||||
self.bubble = bubble
|
||||
self.image = image
|
||||
self.video = video
|
||||
self.text = text
|
||||
self.file = file
|
||||
self.instantVideo = instantVideo
|
||||
self.wallpapers = wallpapers
|
||||
}
|
||||
|
||||
public static var `default`: ChatMessageItemLayoutConstants {
|
||||
return self.compact
|
||||
}
|
||||
|
||||
public static var compact: ChatMessageItemLayoutConstants {
|
||||
let bubble = ChatMessageItemBubbleLayoutConstants(edgeInset: 4.0, defaultSpacing: 2.0 + UIScreenPixel, mergedSpacing: 0.0, maximumWidthFill: ChatMessageItemWidthFill(compactInset: 36.0, compactWidthBoundary: 500.0, freeMaximumFillFactor: 0.85), minimumSize: CGSize(width: 40.0, height: 35.0), contentInsets: UIEdgeInsets(top: 0.0, left: 6.0, bottom: 0.0, right: 0.0), borderInset: UIScreenPixel, strokeInsets: UIEdgeInsets(top: 1.0, left: 1.0, bottom: 1.0, right: 1.0))
|
||||
let text = ChatMessageItemTextLayoutConstants(bubbleInsets: UIEdgeInsets(top: 6.0 + UIScreenPixel, left: 12.0, bottom: 6.0 - UIScreenPixel, right: 12.0))
|
||||
let image = ChatMessageItemImageLayoutConstants(bubbleInsets: UIEdgeInsets(top: 2.0, left: 2.0, bottom: 2.0, right: 2.0), statusInsets: UIEdgeInsets(top: 0.0, left: 0.0, bottom: 6.0, right: 6.0), defaultCornerRadius: 16.0, mergedCornerRadius: 8.0, contentMergedCornerRadius: 0.0, maxDimensions: CGSize(width: 300.0, height: 380.0), minDimensions: CGSize(width: 170.0, height: 74.0))
|
||||
let video = ChatMessageItemVideoLayoutConstants(maxHorizontalHeight: 250.0, maxVerticalHeight: 360.0)
|
||||
let file = ChatMessageItemFileLayoutConstants(bubbleInsets: UIEdgeInsets(top: 15.0, left: 9.0, bottom: 15.0, right: 12.0))
|
||||
let instantVideo = ChatMessageItemInstantVideoConstants(insets: UIEdgeInsets(top: 4.0, left: 0.0, bottom: 4.0, right: 0.0), dimensions: CGSize(width: 212.0, height: 212.0))
|
||||
let wallpapers = ChatMessageItemWallpaperLayoutConstants(maxTextWidth: 180.0)
|
||||
|
||||
return ChatMessageItemLayoutConstants(avatarDiameter: 37.0, timestampHeaderHeight: 34.0, bubble: bubble, image: image, video: video, text: text, file: file, instantVideo: instantVideo, wallpapers: wallpapers)
|
||||
}
|
||||
|
||||
public static var regular: ChatMessageItemLayoutConstants {
|
||||
let bubble = ChatMessageItemBubbleLayoutConstants(edgeInset: 4.0, defaultSpacing: 2.0 + UIScreenPixel, mergedSpacing: 0.0, maximumWidthFill: ChatMessageItemWidthFill(compactInset: 36.0, compactWidthBoundary: 500.0, freeMaximumFillFactor: 0.65), minimumSize: CGSize(width: 40.0, height: 35.0), contentInsets: UIEdgeInsets(top: 0.0, left: 6.0, bottom: 0.0, right: 0.0), borderInset: UIScreenPixel, strokeInsets: UIEdgeInsets(top: 1.0, left: 1.0, bottom: 1.0, right: 1.0))
|
||||
let text = ChatMessageItemTextLayoutConstants(bubbleInsets: UIEdgeInsets(top: 6.0 + UIScreenPixel, left: 12.0, bottom: 6.0 - UIScreenPixel, right: 12.0))
|
||||
let image = ChatMessageItemImageLayoutConstants(bubbleInsets: UIEdgeInsets(top: 2.0, left: 2.0, bottom: 2.0, right: 2.0), statusInsets: UIEdgeInsets(top: 0.0, left: 0.0, bottom: 6.0, right: 6.0), defaultCornerRadius: 16.0, mergedCornerRadius: 8.0, contentMergedCornerRadius: 5.0, maxDimensions: CGSize(width: 440.0, height: 440.0), minDimensions: CGSize(width: 170.0, height: 74.0))
|
||||
let video = ChatMessageItemVideoLayoutConstants(maxHorizontalHeight: 250.0, maxVerticalHeight: 360.0)
|
||||
let file = ChatMessageItemFileLayoutConstants(bubbleInsets: UIEdgeInsets(top: 15.0, left: 9.0, bottom: 15.0, right: 12.0))
|
||||
let instantVideo = ChatMessageItemInstantVideoConstants(insets: UIEdgeInsets(top: 4.0, left: 0.0, bottom: 4.0, right: 0.0), dimensions: CGSize(width: 240.0, height: 240.0))
|
||||
let wallpapers = ChatMessageItemWallpaperLayoutConstants(maxTextWidth: 180.0)
|
||||
|
||||
return ChatMessageItemLayoutConstants(avatarDiameter: 37.0, timestampHeaderHeight: 34.0, bubble: bubble, image: image, video: video, text: text, file: file, instantVideo: instantVideo, wallpapers: wallpapers)
|
||||
}
|
||||
}
|
||||
|
||||
public func canViewMessageReactionList(message: Message) -> Bool {
|
||||
var found = false
|
||||
var canViewList = false
|
||||
for attribute in message.attributes {
|
||||
if let attribute = attribute as? ReactionsMessageAttribute {
|
||||
canViewList = attribute.canViewList
|
||||
found = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if !found {
|
||||
return false
|
||||
}
|
||||
|
||||
if let peer = message.peers[message.id.peerId] {
|
||||
if let channel = peer as? TelegramChannel {
|
||||
if case .broadcast = channel.info {
|
||||
return false
|
||||
} else {
|
||||
return canViewList
|
||||
}
|
||||
} else if let _ = peer as? TelegramGroup {
|
||||
return canViewList
|
||||
} else if let _ = peer as? TelegramUser {
|
||||
return true
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,41 @@
|
|||
load("@build_bazel_rules_swift//swift:swift.bzl", "swift_library")
|
||||
|
||||
swift_library(
|
||||
name = "ChatMessageTextBubbleContentNode",
|
||||
module_name = "ChatMessageTextBubbleContentNode",
|
||||
srcs = glob([
|
||||
"Sources/**/*.swift",
|
||||
]),
|
||||
copts = [
|
||||
"-warnings-as-errors",
|
||||
],
|
||||
deps = [
|
||||
"//submodules/AsyncDisplayKit",
|
||||
"//submodules/Display",
|
||||
"//submodules/TelegramCore",
|
||||
"//submodules/Postbox",
|
||||
"//submodules/TextFormat",
|
||||
"//submodules/UrlEscaping",
|
||||
"//submodules/TelegramUniversalVideoContent",
|
||||
"//submodules/TextSelectionNode",
|
||||
"//submodules/InvisibleInkDustNode",
|
||||
"//submodules/Emoji",
|
||||
"//submodules/AnimatedStickerNode",
|
||||
"//submodules/TelegramAnimatedStickerNode",
|
||||
"//submodules/SSignalKit/SwiftSignalKit",
|
||||
"//submodules/AccountContext",
|
||||
"//submodules/YuvConversion",
|
||||
"//submodules/TelegramUI/Components/AnimationCache",
|
||||
"//submodules/TelegramUI/Components/LottieAnimationCache",
|
||||
"//submodules/TelegramUI/Components/MultiAnimationRenderer",
|
||||
"//submodules/TelegramUI/Components/EmojiTextAttachmentView",
|
||||
"//submodules/TelegramUI/Components/TextNodeWithEntities",
|
||||
"//submodules/TelegramUI/Components/Chat/ChatMessageDateAndStatusNode",
|
||||
"//submodules/TelegramUI/Components/Chat/ChatMessageBubbleContentNode",
|
||||
"//submodules/TelegramUI/Components/Chat/ShimmeringLinkNode",
|
||||
"//submodules/TelegramUI/Components/Chat/ChatMessageItemCommon",
|
||||
],
|
||||
visibility = [
|
||||
"//visibility:public",
|
||||
],
|
||||
)
|
||||
|
|
@ -21,6 +21,9 @@ import MultiAnimationRenderer
|
|||
import EmojiTextAttachmentView
|
||||
import TextNodeWithEntities
|
||||
import ChatMessageDateAndStatusNode
|
||||
import ChatMessageBubbleContentNode
|
||||
import ShimmeringLinkNode
|
||||
import ChatMessageItemCommon
|
||||
|
||||
private final class CachedChatMessageText {
|
||||
let text: String
|
||||
|
|
@ -48,7 +51,7 @@ private final class CachedChatMessageText {
|
|||
}
|
||||
}
|
||||
|
||||
class ChatMessageTextBubbleContentNode: ChatMessageBubbleContentNode {
|
||||
public class ChatMessageTextBubbleContentNode: ChatMessageBubbleContentNode {
|
||||
private let textNode: TextNodeWithEntities
|
||||
private var spoilerTextNode: TextNodeWithEntities?
|
||||
private var dustNode: InvisibleInkDustNode?
|
||||
|
|
@ -63,7 +66,7 @@ class ChatMessageTextBubbleContentNode: ChatMessageBubbleContentNode {
|
|||
|
||||
private var cachedChatMessageText: CachedChatMessageText?
|
||||
|
||||
override var visibility: ListViewItemNodeVisibility {
|
||||
override public var visibility: ListViewItemNodeVisibility {
|
||||
didSet {
|
||||
if oldValue != self.visibility {
|
||||
switch self.visibility {
|
||||
|
|
@ -81,7 +84,7 @@ class ChatMessageTextBubbleContentNode: ChatMessageBubbleContentNode {
|
|||
}
|
||||
}
|
||||
|
||||
required init() {
|
||||
required public init() {
|
||||
self.textNode = TextNodeWithEntities()
|
||||
|
||||
self.statusNode = ChatMessageDateAndStatusNode()
|
||||
|
|
@ -118,11 +121,11 @@ class ChatMessageTextBubbleContentNode: ChatMessageBubbleContentNode {
|
|||
}
|
||||
}
|
||||
|
||||
required init?(coder aDecoder: NSCoder) {
|
||||
required public init?(coder aDecoder: NSCoder) {
|
||||
fatalError("init(coder:) has not been implemented")
|
||||
}
|
||||
|
||||
override func asyncLayoutContent() -> (_ item: ChatMessageBubbleContentItem, _ layoutConstants: ChatMessageItemLayoutConstants, _ preparePosition: ChatMessageBubblePreparePosition, _ messageSelection: Bool?, _ constrainedSize: CGSize, _ avatarInset: CGFloat) -> (ChatMessageBubbleContentProperties, CGSize?, CGFloat, (CGSize, ChatMessageBubbleContentPosition) -> (CGFloat, (CGFloat) -> (CGSize, (ListViewItemUpdateAnimation, Bool, ListViewItemApply?) -> Void))) {
|
||||
override public func asyncLayoutContent() -> (_ item: ChatMessageBubbleContentItem, _ layoutConstants: ChatMessageItemLayoutConstants, _ preparePosition: ChatMessageBubblePreparePosition, _ messageSelection: Bool?, _ constrainedSize: CGSize, _ avatarInset: CGFloat) -> (ChatMessageBubbleContentProperties, CGSize?, CGFloat, (CGSize, ChatMessageBubbleContentPosition) -> (CGFloat, (CGFloat) -> (CGSize, (ListViewItemUpdateAnimation, Bool, ListViewItemApply?) -> Void))) {
|
||||
let textLayout = TextNodeWithEntities.asyncLayout(self.textNode)
|
||||
let spoilerTextLayout = TextNodeWithEntities.asyncLayout(self.spoilerTextNode)
|
||||
let statusLayout = self.statusNode.asyncLayout()
|
||||
|
|
@ -566,22 +569,22 @@ class ChatMessageTextBubbleContentNode: ChatMessageBubbleContentNode {
|
|||
}
|
||||
}
|
||||
|
||||
override func animateInsertion(_ currentTimestamp: Double, duration: Double) {
|
||||
override public func animateInsertion(_ currentTimestamp: Double, duration: Double) {
|
||||
self.textNode.textNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.2)
|
||||
self.statusNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.2)
|
||||
}
|
||||
|
||||
override func animateAdded(_ currentTimestamp: Double, duration: Double) {
|
||||
override public func animateAdded(_ currentTimestamp: Double, duration: Double) {
|
||||
self.textNode.textNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.2)
|
||||
self.statusNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.2)
|
||||
}
|
||||
|
||||
override func animateRemoved(_ currentTimestamp: Double, duration: Double) {
|
||||
override public func animateRemoved(_ currentTimestamp: Double, duration: Double) {
|
||||
self.textNode.textNode.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.2, removeOnCompletion: false)
|
||||
self.statusNode.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.2, removeOnCompletion: false)
|
||||
}
|
||||
|
||||
override func tapActionAtPoint(_ point: CGPoint, gesture: TapLongTapOrDoubleTapGesture, isEstimating: Bool) -> ChatMessageBubbleContentTapAction {
|
||||
override public func tapActionAtPoint(_ point: CGPoint, gesture: TapLongTapOrDoubleTapGesture, isEstimating: Bool) -> ChatMessageBubbleContentTapAction {
|
||||
let textNodeFrame = self.textNode.textNode.frame
|
||||
if let (index, attributes) = self.textNode.textNode.attributesAtPoint(CGPoint(x: point.x - textNodeFrame.minX, y: point.y - textNodeFrame.minY)) {
|
||||
if let _ = attributes[NSAttributedString.Key(rawValue: TelegramTextAttributes.Spoiler)], !(self.dustNode?.isRevealed ?? true) {
|
||||
|
|
@ -635,7 +638,7 @@ class ChatMessageTextBubbleContentNode: ChatMessageBubbleContentNode {
|
|||
}
|
||||
}
|
||||
|
||||
override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
|
||||
override public func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
|
||||
if self.statusNode.supernode != nil, let result = self.statusNode.hitTest(self.view.convert(point, to: self.statusNode.view), with: event) {
|
||||
return result
|
||||
}
|
||||
|
|
@ -668,7 +671,7 @@ class ChatMessageTextBubbleContentNode: ChatMessageBubbleContentNode {
|
|||
})
|
||||
}
|
||||
}
|
||||
override func updateTouchesAtPoint(_ point: CGPoint?) {
|
||||
override public func updateTouchesAtPoint(_ point: CGPoint?) {
|
||||
if let item = self.item {
|
||||
var rects: [CGRect]?
|
||||
var spoilerRects: [CGRect]?
|
||||
|
|
@ -718,29 +721,7 @@ class ChatMessageTextBubbleContentNode: ChatMessageBubbleContentNode {
|
|||
}
|
||||
}
|
||||
|
||||
override func peekPreviewContent(at point: CGPoint) -> (Message, ChatMessagePeekPreviewContent)? {
|
||||
if let item = self.item {
|
||||
let textNodeFrame = self.textNode.textNode.frame
|
||||
if let (index, attributes) = self.textNode.textNode.attributesAtPoint(CGPoint(x: point.x - textNodeFrame.minX, y: point.y - textNodeFrame.minY)) {
|
||||
if let value = attributes[NSAttributedString.Key(rawValue: TelegramTextAttributes.URL)] as? String {
|
||||
if let rects = self.textNode.textNode.attributeRects(name: TelegramTextAttributes.URL, at: index), !rects.isEmpty {
|
||||
var rect = rects[0]
|
||||
for i in 1 ..< rects.count {
|
||||
rect = rect.union(rects[i])
|
||||
}
|
||||
var concealed = true
|
||||
if let (attributeText, fullText) = self.textNode.textNode.attributeSubstring(name: TelegramTextAttributes.URL, index: index) {
|
||||
concealed = !doesUrlMatchText(url: value, text: attributeText, fullText: fullText)
|
||||
}
|
||||
return (item.message, .url(self, rect, value, concealed))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
override func updateSearchTextHighlightState(text: String?, messages: [MessageIndex]?) {
|
||||
override public func updateSearchTextHighlightState(text: String?, messages: [MessageIndex]?) {
|
||||
guard let item = self.item else {
|
||||
return
|
||||
}
|
||||
|
|
@ -769,7 +750,7 @@ class ChatMessageTextBubbleContentNode: ChatMessageBubbleContentNode {
|
|||
}
|
||||
}
|
||||
|
||||
override func willUpdateIsExtractedToContextPreview(_ value: Bool) {
|
||||
override public func willUpdateIsExtractedToContextPreview(_ value: Bool) {
|
||||
if !value {
|
||||
if let textSelectionNode = self.textSelectionNode {
|
||||
self.textSelectionNode = nil
|
||||
|
|
@ -782,7 +763,7 @@ class ChatMessageTextBubbleContentNode: ChatMessageBubbleContentNode {
|
|||
}
|
||||
}
|
||||
|
||||
override func updateIsExtractedToContextPreview(_ value: Bool) {
|
||||
override public func updateIsExtractedToContextPreview(_ value: Bool) {
|
||||
if value {
|
||||
if self.textSelectionNode == nil, let item = self.item, !item.associatedData.isCopyProtectionEnabled && !item.message.isCopyProtected(), let rootNode = item.controllerInteraction.chatControllerNode() {
|
||||
let selectionColor: UIColor
|
||||
|
|
@ -840,18 +821,18 @@ class ChatMessageTextBubbleContentNode: ChatMessageBubbleContentNode {
|
|||
}
|
||||
}
|
||||
|
||||
override func reactionTargetView(value: MessageReaction.Reaction) -> UIView? {
|
||||
override public func reactionTargetView(value: MessageReaction.Reaction) -> UIView? {
|
||||
if !self.statusNode.isHidden {
|
||||
return self.statusNode.reactionView(value: value)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
override func getStatusNode() -> ASDisplayNode? {
|
||||
override public func getStatusNode() -> ASDisplayNode? {
|
||||
return self.statusNode
|
||||
}
|
||||
|
||||
func animateFrom(sourceView: UIView, scrollOffset: CGFloat, widthDifference: CGFloat, transition: CombinedTransition) {
|
||||
public func animateFrom(sourceView: UIView, scrollOffset: CGFloat, widthDifference: CGFloat, transition: CombinedTransition) {
|
||||
self.view.addSubview(sourceView)
|
||||
|
||||
sourceView.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.1, removeOnCompletion: false, completion: { [weak sourceView] _ in
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
load("@build_bazel_rules_swift//swift:swift.bzl", "swift_library")
|
||||
|
||||
swift_library(
|
||||
name = "EditableTokenListNode",
|
||||
module_name = "EditableTokenListNode",
|
||||
srcs = glob([
|
||||
"Sources/**/*.swift",
|
||||
]),
|
||||
copts = [
|
||||
"-warnings-as-errors",
|
||||
],
|
||||
deps = [
|
||||
"//submodules/AsyncDisplayKit",
|
||||
"//submodules/Display",
|
||||
"//submodules/TelegramCore",
|
||||
"//submodules/TelegramPresentationData",
|
||||
"//submodules/AvatarNode",
|
||||
"//submodules/AccountContext",
|
||||
],
|
||||
visibility = [
|
||||
"//visibility:public",
|
||||
],
|
||||
)
|
||||
|
|
@ -7,16 +7,23 @@ import TelegramPresentationData
|
|||
import AvatarNode
|
||||
import AccountContext
|
||||
|
||||
struct EditableTokenListToken {
|
||||
enum Subject {
|
||||
public struct EditableTokenListToken {
|
||||
public enum Subject {
|
||||
case peer(EnginePeer)
|
||||
case category(UIImage?)
|
||||
}
|
||||
|
||||
let id: AnyHashable
|
||||
let title: String
|
||||
let fixedPosition: Int?
|
||||
let subject: Subject
|
||||
public let id: AnyHashable
|
||||
public let title: String
|
||||
public let fixedPosition: Int?
|
||||
public let subject: Subject
|
||||
|
||||
public init(id: AnyHashable, title: String, fixedPosition: Int?, subject: Subject) {
|
||||
self.id = id
|
||||
self.title = title
|
||||
self.fixedPosition = fixedPosition
|
||||
self.subject = subject
|
||||
}
|
||||
}
|
||||
|
||||
private let caretIndicatorImage = generateVerticallyStretchableFilledCircleImage(radius: 1.0, color: UIColor(rgb: 0x3350ee))
|
||||
|
|
@ -54,18 +61,18 @@ private func generateRemoveIcon(_ color: UIColor) -> UIImage? {
|
|||
})
|
||||
}
|
||||
|
||||
final class EditableTokenListNodeTheme {
|
||||
let backgroundColor: UIColor
|
||||
let separatorColor: UIColor
|
||||
let placeholderTextColor: UIColor
|
||||
let primaryTextColor: UIColor
|
||||
let tokenBackgroundColor: UIColor
|
||||
let selectedTextColor: UIColor
|
||||
let selectedBackgroundColor: UIColor
|
||||
let accentColor: UIColor
|
||||
let keyboardColor: PresentationThemeKeyboardColor
|
||||
public final class EditableTokenListNodeTheme {
|
||||
public let backgroundColor: UIColor
|
||||
public let separatorColor: UIColor
|
||||
public let placeholderTextColor: UIColor
|
||||
public let primaryTextColor: UIColor
|
||||
public let tokenBackgroundColor: UIColor
|
||||
public let selectedTextColor: UIColor
|
||||
public let selectedBackgroundColor: UIColor
|
||||
public let accentColor: UIColor
|
||||
public let keyboardColor: PresentationThemeKeyboardColor
|
||||
|
||||
init(backgroundColor: UIColor, separatorColor: UIColor, placeholderTextColor: UIColor, primaryTextColor: UIColor, tokenBackgroundColor: UIColor, selectedTextColor: UIColor, selectedBackgroundColor: UIColor, accentColor: UIColor, keyboardColor: PresentationThemeKeyboardColor) {
|
||||
public init(backgroundColor: UIColor, separatorColor: UIColor, placeholderTextColor: UIColor, primaryTextColor: UIColor, tokenBackgroundColor: UIColor, selectedTextColor: UIColor, selectedBackgroundColor: UIColor, accentColor: UIColor, keyboardColor: PresentationThemeKeyboardColor) {
|
||||
self.backgroundColor = backgroundColor
|
||||
self.separatorColor = separatorColor
|
||||
self.placeholderTextColor = placeholderTextColor
|
||||
|
|
@ -245,7 +252,7 @@ private final class CaretIndicatorNode: ASImageNode {
|
|||
}
|
||||
}
|
||||
|
||||
final class EditableTokenListNode: ASDisplayNode, UITextFieldDelegate {
|
||||
public final class EditableTokenListNode: ASDisplayNode, UITextFieldDelegate {
|
||||
private let context: AccountContext
|
||||
private let presentationTheme: PresentationTheme
|
||||
|
||||
|
|
@ -260,11 +267,11 @@ final class EditableTokenListNode: ASDisplayNode, UITextFieldDelegate {
|
|||
private let caretIndicatorNode: CaretIndicatorNode
|
||||
private var selectedTokenId: AnyHashable?
|
||||
|
||||
var textUpdated: ((String) -> Void)?
|
||||
var deleteToken: ((AnyHashable) -> Void)?
|
||||
var textReturned: (() -> Void)?
|
||||
public var textUpdated: ((String) -> Void)?
|
||||
public var deleteToken: ((AnyHashable) -> Void)?
|
||||
public var textReturned: (() -> Void)?
|
||||
|
||||
init(context: AccountContext, presentationTheme: PresentationTheme, theme: EditableTokenListNodeTheme, placeholder: String) {
|
||||
public init(context: AccountContext, presentationTheme: PresentationTheme, theme: EditableTokenListNodeTheme, placeholder: String) {
|
||||
self.context = context
|
||||
self.presentationTheme = presentationTheme
|
||||
self.theme = theme
|
||||
|
|
@ -326,7 +333,7 @@ final class EditableTokenListNode: ASDisplayNode, UITextFieldDelegate {
|
|||
self.view.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(self.tapGesture(_:))))
|
||||
}
|
||||
|
||||
func updateLayout(tokens: [EditableTokenListToken], width: CGFloat, leftInset: CGFloat, rightInset: CGFloat, transition: ContainedViewLayoutTransition) -> CGFloat {
|
||||
public func updateLayout(tokens: [EditableTokenListToken], width: CGFloat, leftInset: CGFloat, rightInset: CGFloat, transition: ContainedViewLayoutTransition) -> CGFloat {
|
||||
let validTokens = Set<AnyHashable>(tokens.map { $0.id })
|
||||
|
||||
for i in (0 ..< self.tokenNodes.count).reversed() {
|
||||
|
|
@ -466,7 +473,7 @@ final class EditableTokenListNode: ASDisplayNode, UITextFieldDelegate {
|
|||
return nodeHeight
|
||||
}
|
||||
|
||||
@objc func textFieldChanged(_ textField: UITextField) {
|
||||
@objc private func textFieldChanged(_ textField: UITextField) {
|
||||
let text = textField.text ?? ""
|
||||
self.placeholderNode.isHidden = !text.isEmpty
|
||||
self.updateSelectedTokenId(nil)
|
||||
|
|
@ -476,24 +483,24 @@ final class EditableTokenListNode: ASDisplayNode, UITextFieldDelegate {
|
|||
}
|
||||
}
|
||||
|
||||
func textFieldShouldReturn(_ textField: UITextField) -> Bool {
|
||||
public func textFieldShouldReturn(_ textField: UITextField) -> Bool {
|
||||
self.textReturned?()
|
||||
return false
|
||||
}
|
||||
|
||||
func textFieldDidBeginEditing(_ textField: UITextField) {
|
||||
public func textFieldDidBeginEditing(_ textField: UITextField) {
|
||||
/*if self.caretIndicatorNode.supernode == self {
|
||||
self.caretIndicatorNode.removeFromSupernode()
|
||||
}*/
|
||||
}
|
||||
|
||||
func textFieldDidEndEditing(_ textField: UITextField) {
|
||||
public func textFieldDidEndEditing(_ textField: UITextField) {
|
||||
/*if self.caretIndicatorNode.supernode != self.scrollNode {
|
||||
self.scrollNode.addSubnode(self.caretIndicatorNode)
|
||||
}*/
|
||||
}
|
||||
|
||||
func setText(_ text: String) {
|
||||
public func setText(_ text: String) {
|
||||
self.textFieldNode.textField.text = text
|
||||
self.textFieldChanged(self.textFieldNode.textField)
|
||||
}
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
load("@build_bazel_rules_swift//swift:swift.bzl", "swift_library")
|
||||
|
||||
swift_library(
|
||||
name = "ShimmeringLinkNode",
|
||||
module_name = "ShimmeringLinkNode",
|
||||
srcs = glob([
|
||||
"Sources/**/*.swift",
|
||||
]),
|
||||
copts = [
|
||||
"-warnings-as-errors",
|
||||
],
|
||||
deps = [
|
||||
"//submodules/AsyncDisplayKit",
|
||||
"//submodules/Display",
|
||||
"//submodules/ShimmerEffect",
|
||||
],
|
||||
visibility = [
|
||||
"//visibility:public",
|
||||
],
|
||||
)
|
||||
|
|
@ -4,7 +4,7 @@ import AsyncDisplayKit
|
|||
import Display
|
||||
import ShimmerEffect
|
||||
|
||||
final class ShimmeringLinkNode: ASDisplayNode {
|
||||
public final class ShimmeringLinkNode: ASDisplayNode {
|
||||
private let shimmerEffectNode: ShimmerEffectForegroundNode
|
||||
private let borderShimmerEffectNode: ShimmerEffectForegroundNode
|
||||
|
||||
|
|
@ -12,17 +12,17 @@ final class ShimmeringLinkNode: ASDisplayNode {
|
|||
private let borderMaskNode: ASImageNode
|
||||
|
||||
private(set) var rects: [CGRect] = []
|
||||
var color: UIColor {
|
||||
public var color: UIColor {
|
||||
didSet {
|
||||
self.backgroundColor = color
|
||||
}
|
||||
}
|
||||
|
||||
var innerRadius: CGFloat = 4.0
|
||||
var outerRadius: CGFloat = 4.0
|
||||
var inset: CGFloat = 2.0
|
||||
public var innerRadius: CGFloat = 4.0
|
||||
public var outerRadius: CGFloat = 4.0
|
||||
public var inset: CGFloat = 2.0
|
||||
|
||||
init(color: UIColor) {
|
||||
public init(color: UIColor) {
|
||||
self.color = color
|
||||
|
||||
self.shimmerEffectNode = ShimmerEffectForegroundNode()
|
||||
|
|
@ -46,14 +46,14 @@ final class ShimmeringLinkNode: ASDisplayNode {
|
|||
//self.addSubnode(self.borderShimmerEffectNode)
|
||||
}
|
||||
|
||||
override func didLoad() {
|
||||
override public func didLoad() {
|
||||
super.didLoad()
|
||||
|
||||
self.shimmerEffectNode.layer.mask = self.maskNode.layer
|
||||
self.borderShimmerEffectNode.layer.mask = self.borderMaskNode.layer
|
||||
}
|
||||
|
||||
func updateRects(_ rects: [CGRect], color: UIColor? = nil) {
|
||||
public func updateRects(_ rects: [CGRect], color: UIColor? = nil) {
|
||||
var updated = false
|
||||
if self.rects != rects {
|
||||
updated = true
|
||||
|
|
@ -86,7 +86,7 @@ final class ShimmeringLinkNode: ASDisplayNode {
|
|||
}
|
||||
}
|
||||
|
||||
func updateLayout(_ size: CGSize) {
|
||||
public func updateLayout(_ size: CGSize) {
|
||||
self.shimmerEffectNode.frame = CGRect(origin: .zero, size: size)
|
||||
self.borderShimmerEffectNode.frame = CGRect(origin: .zero, size: size)
|
||||
|
||||
|
|
@ -14,6 +14,7 @@ import UniversalMediaPlayer
|
|||
import TelegramUniversalVideoContent
|
||||
import WallpaperBackgroundNode
|
||||
import ChatControllerInteraction
|
||||
import ChatMessageBubbleContentNode
|
||||
|
||||
private let messageFont = Font.regular(17.0)
|
||||
private let messageBoldFont = Font.semibold(17.0)
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ import TemporaryCachedPeerDataManager
|
|||
import Emoji
|
||||
import AccountContext
|
||||
import TelegramPresentationData
|
||||
import ChatHistoryEntry
|
||||
|
||||
func chatHistoryEntriesForView(
|
||||
location: ChatLocation,
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@ import ChatPresentationInterfaceState
|
|||
import TelegramNotices
|
||||
import ChatControllerInteraction
|
||||
import TranslateUI
|
||||
import ChatHistoryEntry
|
||||
|
||||
extension ChatReplyThreadMessage {
|
||||
var effectiveTopId: MessageId {
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ import AsyncDisplayKit
|
|||
import Display
|
||||
import SwiftSignalKit
|
||||
import TelegramPresentationData
|
||||
import ChatMessageItemCommon
|
||||
|
||||
private let titleFont = UIFont.systemFont(ofSize: 13.0)
|
||||
|
||||
|
|
|
|||
|
|
@ -19,6 +19,8 @@ import GalleryUI
|
|||
import WallpaperBackgroundNode
|
||||
import InvisibleInkDustNode
|
||||
import TextNodeWithEntities
|
||||
import ChatMessageBubbleContentNode
|
||||
import ChatMessageItemCommon
|
||||
|
||||
private func attributedServiceMessageString(theme: ChatPresentationThemeData, strings: PresentationStrings, nameDisplayOrder: PresentationPersonNameOrder, dateTimeFormat: PresentationDateTimeFormat, message: Message, accountPeerId: PeerId, forForumOverview: Bool) -> NSAttributedString? {
|
||||
return universalServiceMessageString(presentationData: (theme.theme, theme.wallpaper), strings: strings, nameDisplayOrder: nameDisplayOrder, dateTimeFormat: dateTimeFormat, message: EngineMessage(message), accountPeerId: accountPeerId, forChatList: false, forForumOverview: forForumOverview)
|
||||
|
|
|
|||
|
|
@ -30,6 +30,8 @@ import TextNodeWithEntities
|
|||
import ChatControllerInteraction
|
||||
import ChatMessageForwardInfoNode
|
||||
import ChatMessageDateAndStatusNode
|
||||
import ChatMessageItemCommon
|
||||
import ChatMessageBubbleContentNode
|
||||
|
||||
private let nameFont = Font.medium(14.0)
|
||||
private let inlineBotPrefixFont = Font.regular(14.0)
|
||||
|
|
|
|||
|
|
@ -20,6 +20,9 @@ import MultiAnimationRenderer
|
|||
import ChatControllerInteraction
|
||||
import ShimmerEffect
|
||||
import ChatMessageDateAndStatusNode
|
||||
import ChatHistoryEntry
|
||||
import ChatMessageItemCommon
|
||||
import ChatMessageBubbleContentNode
|
||||
|
||||
private let buttonFont = Font.semibold(13.0)
|
||||
|
||||
|
|
|
|||
|
|
@ -2,6 +2,8 @@ import Foundation
|
|||
import UIKit
|
||||
import Display
|
||||
import TelegramPresentationData
|
||||
import ChatMessageBubbleContentNode
|
||||
import ChatMessageItemCommon
|
||||
|
||||
func chatMessageBubbleImageContentCorners(relativeContentPosition position: ChatMessageBubbleContentPosition, normalRadius: CGFloat, mergedRadius: CGFloat, mergedWithAnotherContentRadius: CGFloat, layoutConstants: ChatMessageItemLayoutConstants, chatPresentationData: ChatPresentationData) -> ImageCorners {
|
||||
let topLeftCorner: ImageCorner
|
||||
|
|
|
|||
|
|
@ -1,264 +0,0 @@
|
|||
import Foundation
|
||||
import UIKit
|
||||
import AsyncDisplayKit
|
||||
import Display
|
||||
import Postbox
|
||||
import TelegramCore
|
||||
import TelegramUIPreferences
|
||||
import TelegramPresentationData
|
||||
import AccountContext
|
||||
import ChatMessageBackground
|
||||
import ChatControllerInteraction
|
||||
|
||||
enum ChatMessageBubbleContentBackgroundHiding {
|
||||
case never
|
||||
case emptyWallpaper
|
||||
case always
|
||||
}
|
||||
|
||||
enum ChatMessageBubbleContentAlignment {
|
||||
case none
|
||||
case center
|
||||
}
|
||||
|
||||
struct ChatMessageBubbleContentProperties {
|
||||
let hidesSimpleAuthorHeader: Bool
|
||||
let headerSpacing: CGFloat
|
||||
let hidesBackground: ChatMessageBubbleContentBackgroundHiding
|
||||
let forceFullCorners: Bool
|
||||
let forceAlignment: ChatMessageBubbleContentAlignment
|
||||
let shareButtonOffset: CGPoint?
|
||||
let hidesHeaders: Bool
|
||||
let avatarOffset: CGFloat?
|
||||
|
||||
init(
|
||||
hidesSimpleAuthorHeader: Bool,
|
||||
headerSpacing: CGFloat,
|
||||
hidesBackground: ChatMessageBubbleContentBackgroundHiding,
|
||||
forceFullCorners: Bool,
|
||||
forceAlignment: ChatMessageBubbleContentAlignment,
|
||||
shareButtonOffset: CGPoint? = nil,
|
||||
hidesHeaders: Bool = false,
|
||||
avatarOffset: CGFloat? = nil
|
||||
) {
|
||||
self.hidesSimpleAuthorHeader = hidesSimpleAuthorHeader
|
||||
self.headerSpacing = headerSpacing
|
||||
self.hidesBackground = hidesBackground
|
||||
self.forceFullCorners = forceFullCorners
|
||||
self.forceAlignment = forceAlignment
|
||||
self.shareButtonOffset = shareButtonOffset
|
||||
self.hidesHeaders = hidesHeaders
|
||||
self.avatarOffset = avatarOffset
|
||||
}
|
||||
}
|
||||
|
||||
enum ChatMessageBubbleNoneMergeStatus {
|
||||
case Incoming
|
||||
case Outgoing
|
||||
case None
|
||||
}
|
||||
|
||||
enum ChatMessageBubbleMergeStatus {
|
||||
case None(ChatMessageBubbleNoneMergeStatus)
|
||||
case Left
|
||||
case Right
|
||||
case Both
|
||||
}
|
||||
|
||||
enum ChatMessageBubbleRelativePosition {
|
||||
enum NeighbourType {
|
||||
case media
|
||||
case freeform
|
||||
}
|
||||
|
||||
enum NeighbourSpacing {
|
||||
case `default`
|
||||
case condensed
|
||||
case overlap(CGFloat)
|
||||
}
|
||||
|
||||
case None(ChatMessageBubbleMergeStatus)
|
||||
case BubbleNeighbour
|
||||
case Neighbour(Bool, NeighbourType, NeighbourSpacing)
|
||||
}
|
||||
|
||||
enum ChatMessageBubbleContentMosaicNeighbor {
|
||||
case merged
|
||||
case mergedBubble
|
||||
case none(tail: Bool)
|
||||
}
|
||||
|
||||
struct ChatMessageBubbleContentMosaicPosition {
|
||||
let topLeft: ChatMessageBubbleContentMosaicNeighbor
|
||||
let topRight: ChatMessageBubbleContentMosaicNeighbor
|
||||
let bottomLeft: ChatMessageBubbleContentMosaicNeighbor
|
||||
let bottomRight: ChatMessageBubbleContentMosaicNeighbor
|
||||
}
|
||||
|
||||
enum ChatMessageBubbleContentPosition {
|
||||
case linear(top: ChatMessageBubbleRelativePosition, bottom: ChatMessageBubbleRelativePosition)
|
||||
case mosaic(position: ChatMessageBubbleContentMosaicPosition, wide: Bool)
|
||||
}
|
||||
|
||||
enum ChatMessageBubblePreparePosition {
|
||||
case linear(top: ChatMessageBubbleRelativePosition, bottom: ChatMessageBubbleRelativePosition)
|
||||
case mosaic(top: ChatMessageBubbleRelativePosition, bottom: ChatMessageBubbleRelativePosition)
|
||||
}
|
||||
|
||||
enum ChatMessageBubbleContentTapAction {
|
||||
case none
|
||||
case url(url: String, concealed: Bool)
|
||||
case textMention(String)
|
||||
case peerMention(peerId: PeerId, mention: String, openProfile: Bool)
|
||||
case botCommand(String)
|
||||
case hashtag(String?, String)
|
||||
case instantPage
|
||||
case wallpaper
|
||||
case theme
|
||||
case call(peerId: PeerId, isVideo: Bool)
|
||||
case openMessage
|
||||
case timecode(Double, String)
|
||||
case tooltip(String, ASDisplayNode?, CGRect?)
|
||||
case bankCard(String)
|
||||
case ignore
|
||||
case openPollResults(Data)
|
||||
case copy(String)
|
||||
case largeEmoji(String, String?, TelegramMediaFile)
|
||||
case customEmoji(TelegramMediaFile)
|
||||
}
|
||||
|
||||
final class ChatMessageBubbleContentItem {
|
||||
let context: AccountContext
|
||||
let controllerInteraction: ChatControllerInteraction
|
||||
let message: Message
|
||||
let topMessage: Message
|
||||
let read: Bool
|
||||
let chatLocation: ChatLocation
|
||||
let presentationData: ChatPresentationData
|
||||
let associatedData: ChatMessageItemAssociatedData
|
||||
let attributes: ChatMessageEntryAttributes
|
||||
let isItemPinned: Bool
|
||||
let isItemEdited: Bool
|
||||
|
||||
init(context: AccountContext, controllerInteraction: ChatControllerInteraction, message: Message, topMessage: Message, read: Bool, chatLocation: ChatLocation, presentationData: ChatPresentationData, associatedData: ChatMessageItemAssociatedData, attributes: ChatMessageEntryAttributes, isItemPinned: Bool, isItemEdited: Bool) {
|
||||
self.context = context
|
||||
self.controllerInteraction = controllerInteraction
|
||||
self.message = message
|
||||
self.topMessage = topMessage
|
||||
self.read = read
|
||||
self.chatLocation = chatLocation
|
||||
self.presentationData = presentationData
|
||||
self.associatedData = associatedData
|
||||
self.attributes = attributes
|
||||
self.isItemPinned = isItemPinned
|
||||
self.isItemEdited = isItemEdited
|
||||
}
|
||||
}
|
||||
|
||||
class ChatMessageBubbleContentNode: ASDisplayNode {
|
||||
var supportsMosaic: Bool {
|
||||
return false
|
||||
}
|
||||
|
||||
weak var bubbleBackgroundNode: ChatMessageBackground?
|
||||
weak var bubbleBackdropNode: ChatMessageBubbleBackdrop?
|
||||
|
||||
var visibility: ListViewItemNodeVisibility = .none
|
||||
|
||||
var item: ChatMessageBubbleContentItem?
|
||||
|
||||
var updateIsTextSelectionActive: ((Bool) -> Void)?
|
||||
|
||||
var disablesClipping: Bool {
|
||||
return false
|
||||
}
|
||||
|
||||
required override init() {
|
||||
super.init()
|
||||
}
|
||||
|
||||
func asyncLayoutContent() -> (_ item: ChatMessageBubbleContentItem, _ layoutConstants: ChatMessageItemLayoutConstants, _ preparePosition: ChatMessageBubblePreparePosition, _ messageSelection: Bool?, _ constrainedSize: CGSize, _ avatarInset: CGFloat) -> (ChatMessageBubbleContentProperties, unboundSize: CGSize?, maxWidth: CGFloat, layout: (CGSize, ChatMessageBubbleContentPosition) -> (CGFloat, (CGFloat) -> (CGSize, (ListViewItemUpdateAnimation, Bool, ListViewItemApply?) -> Void))) {
|
||||
preconditionFailure()
|
||||
}
|
||||
|
||||
func animateInsertion(_ currentTimestamp: Double, duration: Double) {
|
||||
}
|
||||
|
||||
func animateAdded(_ currentTimestamp: Double, duration: Double) {
|
||||
}
|
||||
|
||||
func animateRemoved(_ currentTimestamp: Double, duration: Double) {
|
||||
}
|
||||
|
||||
func animateInsertionIntoBubble(_ duration: Double) {
|
||||
}
|
||||
|
||||
func animateRemovalFromBubble(_ duration: Double, completion: @escaping () -> Void) {
|
||||
self.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.25, removeOnCompletion: false, completion: { _ in
|
||||
completion()
|
||||
})
|
||||
}
|
||||
|
||||
func transitionNode(messageId: MessageId, media: Media, adjustRect: Bool) -> (ASDisplayNode, CGRect, () -> (UIView?, UIView?))? {
|
||||
return nil
|
||||
}
|
||||
|
||||
func peekPreviewContent(at point: CGPoint) -> (Message, ChatMessagePeekPreviewContent)? {
|
||||
return nil
|
||||
}
|
||||
|
||||
func updateHiddenMedia(_ media: [Media]?) -> Bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func updateSearchTextHighlightState(text: String?, messages: [MessageIndex]?) {
|
||||
}
|
||||
|
||||
func updateAutomaticMediaDownloadSettings(_ settings: MediaAutoDownloadSettings) {
|
||||
}
|
||||
|
||||
func playMediaWithSound() -> ((Double?) -> Void, Bool, Bool, Bool, ASDisplayNode?)? {
|
||||
return nil
|
||||
}
|
||||
|
||||
func tapActionAtPoint(_ point: CGPoint, gesture: TapLongTapOrDoubleTapGesture, isEstimating: Bool) -> ChatMessageBubbleContentTapAction {
|
||||
return .none
|
||||
}
|
||||
|
||||
func updateTouchesAtPoint(_ point: CGPoint?) {
|
||||
}
|
||||
|
||||
func updateHighlightedState(animated: Bool) -> Bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func willUpdateIsExtractedToContextPreview(_ value: Bool) {
|
||||
}
|
||||
|
||||
func updateIsExtractedToContextPreview(_ value: Bool) {
|
||||
}
|
||||
|
||||
func updateAbsoluteRect(_ rect: CGRect, within containerSize: CGSize) {
|
||||
}
|
||||
|
||||
func applyAbsoluteOffset(value: CGPoint, animationCurve: ContainedViewLayoutTransitionCurve, duration: Double) {
|
||||
}
|
||||
|
||||
func applyAbsoluteOffsetSpring(value: CGFloat, duration: Double, damping: CGFloat) {
|
||||
}
|
||||
|
||||
func unreadMessageRangeUpdated() {
|
||||
}
|
||||
|
||||
func reactionTargetView(value: MessageReaction.Reaction) -> UIView? {
|
||||
return nil
|
||||
}
|
||||
|
||||
func targetForStoryTransition(id: StoryId) -> UIView? {
|
||||
return nil
|
||||
}
|
||||
|
||||
func getStatusNode() -> ASDisplayNode? {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
|
@ -31,6 +31,10 @@ import EmojiStatusComponent
|
|||
import ChatControllerInteraction
|
||||
import ChatMessageForwardInfoNode
|
||||
import ChatMessageDateAndStatusNode
|
||||
import ChatMessageBubbleContentNode
|
||||
import ChatHistoryEntry
|
||||
import ChatMessageTextBubbleContentNode
|
||||
import ChatMessageItemCommon
|
||||
|
||||
enum InternalBubbleTapAction {
|
||||
case action(() -> Void)
|
||||
|
|
@ -4157,16 +4161,6 @@ class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePreviewItemNode
|
|||
return nil
|
||||
}
|
||||
|
||||
override func peekPreviewContent(at point: CGPoint) -> (Message, ChatMessagePeekPreviewContent)? {
|
||||
for contentNode in self.contentNodes {
|
||||
let frame = contentNode.frame
|
||||
if let result = contentNode.peekPreviewContent(at: point.offsetBy(dx: -frame.minX, dy: -frame.minY)) {
|
||||
return result
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
override func updateHiddenMedia() {
|
||||
var hasHiddenMosaicStatus = false
|
||||
var hasHiddenBackground = false
|
||||
|
|
|
|||
|
|
@ -6,6 +6,9 @@ import TelegramCore
|
|||
import Postbox
|
||||
import TelegramPresentationData
|
||||
import AppBundle
|
||||
import ChatMessageBubbleContentNode
|
||||
import ChatMessageItemCommon
|
||||
import ChatMessageDateAndStatusNode
|
||||
|
||||
private let titleFont: UIFont = Font.medium(16.0)
|
||||
private let labelFont: UIFont = Font.regular(13.0)
|
||||
|
|
|
|||
|
|
@ -9,6 +9,8 @@ import TelegramPresentationData
|
|||
import RadialStatusNode
|
||||
import AnimatedCountLabelNode
|
||||
import AnimatedAvatarSetNode
|
||||
import ChatMessageBubbleContentNode
|
||||
import ChatMessageItemCommon
|
||||
|
||||
final class ChatMessageCommentFooterContentNode: ChatMessageBubbleContentNode {
|
||||
private let separatorNode: ASDisplayNode
|
||||
|
|
|
|||
|
|
@ -10,6 +10,8 @@ import AvatarNode
|
|||
import AccountContext
|
||||
import PhoneNumberFormat
|
||||
import ChatMessageDateAndStatusNode
|
||||
import ChatMessageBubbleContentNode
|
||||
import ChatMessageItemCommon
|
||||
|
||||
private let avatarFont = avatarPlaceholderFont(size: 16.0)
|
||||
|
||||
|
|
|
|||
|
|
@ -5,6 +5,8 @@ import Display
|
|||
import AsyncDisplayKit
|
||||
import SwiftSignalKit
|
||||
import TelegramCore
|
||||
import ChatMessageBubbleContentNode
|
||||
import ChatMessageItemCommon
|
||||
|
||||
final class ChatMessageEventLogPreviousDescriptionContentNode: ChatMessageBubbleContentNode {
|
||||
private let contentNode: ChatMessageAttachedContentNode
|
||||
|
|
|
|||
|
|
@ -5,6 +5,8 @@ import Display
|
|||
import AsyncDisplayKit
|
||||
import SwiftSignalKit
|
||||
import TelegramCore
|
||||
import ChatMessageBubbleContentNode
|
||||
import ChatMessageItemCommon
|
||||
|
||||
final class ChatMessageEventLogPreviousLinkContentNode: ChatMessageBubbleContentNode {
|
||||
private let contentNode: ChatMessageAttachedContentNode
|
||||
|
|
|
|||
|
|
@ -5,6 +5,8 @@ import Display
|
|||
import AsyncDisplayKit
|
||||
import SwiftSignalKit
|
||||
import TelegramCore
|
||||
import ChatMessageBubbleContentNode
|
||||
import ChatMessageItemCommon
|
||||
|
||||
final class ChatMessageEventLogPreviousMessageContentNode: ChatMessageBubbleContentNode {
|
||||
private let contentNode: ChatMessageAttachedContentNode
|
||||
|
|
|
|||
|
|
@ -9,6 +9,8 @@ import TelegramUIPreferences
|
|||
import ComponentFlow
|
||||
import AudioTranscriptionButtonComponent
|
||||
import ChatMessageDateAndStatusNode
|
||||
import ChatMessageBubbleContentNode
|
||||
import ChatMessageItemCommon
|
||||
|
||||
class ChatMessageFileBubbleContentNode: ChatMessageBubbleContentNode {
|
||||
let interactiveFileNode: ChatMessageInteractiveFileNode
|
||||
|
|
|
|||
|
|
@ -5,6 +5,8 @@ import Display
|
|||
import AsyncDisplayKit
|
||||
import SwiftSignalKit
|
||||
import TelegramCore
|
||||
import ChatMessageBubbleContentNode
|
||||
import ChatMessageItemCommon
|
||||
|
||||
final class ChatMessageGameBubbleContentNode: ChatMessageBubbleContentNode {
|
||||
private var game: TelegramMediaGame?
|
||||
|
|
|
|||
|
|
@ -18,6 +18,8 @@ import TelegramAnimatedStickerNode
|
|||
import ChatControllerInteraction
|
||||
import ShimmerEffect
|
||||
import Markdown
|
||||
import ChatMessageBubbleContentNode
|
||||
import ChatMessageItemCommon
|
||||
|
||||
private func attributedServiceMessageString(theme: ChatPresentationThemeData, strings: PresentationStrings, nameDisplayOrder: PresentationPersonNameOrder, dateTimeFormat: PresentationDateTimeFormat, message: EngineMessage, accountPeerId: EnginePeer.Id) -> NSAttributedString? {
|
||||
return universalServiceMessageString(presentationData: (theme.theme, theme.wallpaper), strings: strings, nameDisplayOrder: nameDisplayOrder, dateTimeFormat: dateTimeFormat, message: message, accountPeerId: accountPeerId, forChatList: false, forForumOverview: false)
|
||||
|
|
|
|||
|
|
@ -15,6 +15,8 @@ import ShimmerEffect
|
|||
import AnimatedStickerNode
|
||||
import TelegramAnimatedStickerNode
|
||||
import ChatMessageDateAndStatusNode
|
||||
import ChatMessageBubbleContentNode
|
||||
import ChatMessageItemCommon
|
||||
|
||||
private let titleFont = Font.medium(15.0)
|
||||
private let textFont = Font.regular(13.0)
|
||||
|
|
|
|||
|
|
@ -9,6 +9,8 @@ import TelegramUIPreferences
|
|||
import ComponentFlow
|
||||
import AudioTranscriptionButtonComponent
|
||||
import ChatMessageDateAndStatusNode
|
||||
import ChatMessageBubbleContentNode
|
||||
import ChatMessageItemCommon
|
||||
|
||||
class ChatMessageInstantVideoBubbleContentNode: ChatMessageBubbleContentNode {
|
||||
let interactiveFileNode: ChatMessageInteractiveFileNode
|
||||
|
|
|
|||
|
|
@ -15,6 +15,8 @@ import Markdown
|
|||
import ChatControllerInteraction
|
||||
import ChatMessageForwardInfoNode
|
||||
import ChatMessageDateAndStatusNode
|
||||
import ChatMessageItemCommon
|
||||
import ChatMessageBubbleContentNode
|
||||
|
||||
private let nameFont = Font.medium(14.0)
|
||||
|
||||
|
|
|
|||
|
|
@ -30,6 +30,8 @@ import UndoUI
|
|||
import TelegramNotices
|
||||
import ChatControllerInteraction
|
||||
import ChatMessageDateAndStatusNode
|
||||
import ChatHistoryEntry
|
||||
import ChatMessageItemCommon
|
||||
|
||||
private struct FetchControls {
|
||||
let fetch: (Bool) -> Void
|
||||
|
|
|
|||
|
|
@ -21,6 +21,8 @@ import Markdown
|
|||
import TextFormat
|
||||
import ChatMessageForwardInfoNode
|
||||
import ChatMessageDateAndStatusNode
|
||||
import ChatMessageItemCommon
|
||||
import ChatMessageBubbleContentNode
|
||||
|
||||
struct ChatMessageInstantVideoItemLayoutResult {
|
||||
let contentSize: CGSize
|
||||
|
|
|
|||
|
|
@ -26,6 +26,8 @@ import InvisibleInkDustNode
|
|||
import ChatControllerInteraction
|
||||
import StoryContainerScreen
|
||||
import ChatMessageDateAndStatusNode
|
||||
import ChatHistoryEntry
|
||||
import ChatMessageItemCommon
|
||||
|
||||
private struct FetchControls {
|
||||
let fetch: (Bool) -> Void
|
||||
|
|
|
|||
|
|
@ -7,6 +7,8 @@ import SwiftSignalKit
|
|||
import TelegramCore
|
||||
import TelegramUIPreferences
|
||||
import TelegramStringFormatting
|
||||
import ChatMessageBubbleContentNode
|
||||
import ChatMessageItemCommon
|
||||
|
||||
private let titleFont: UIFont = Font.semibold(15.0)
|
||||
private let textFont: UIFont = Font.regular(15.0)
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ import AccountContext
|
|||
import Emoji
|
||||
import PersistentStringHash
|
||||
import ChatControllerInteraction
|
||||
import ChatHistoryEntry
|
||||
|
||||
public enum ChatMessageItemContent: Sequence {
|
||||
case message(message: Message, read: Bool, selection: ChatHistoryMessageSelection, attributes: ChatMessageEntryAttributes, location: MessageHistoryEntryLocation?)
|
||||
|
|
|
|||
|
|
@ -11,104 +11,7 @@ import ChatListUI
|
|||
import TelegramPresentationData
|
||||
import SwiftSignalKit
|
||||
import ChatControllerInteraction
|
||||
|
||||
struct ChatMessageItemWidthFill {
|
||||
var compactInset: CGFloat
|
||||
var compactWidthBoundary: CGFloat
|
||||
var freeMaximumFillFactor: CGFloat
|
||||
|
||||
func widthFor(_ width: CGFloat) -> CGFloat {
|
||||
if width <= self.compactWidthBoundary {
|
||||
return max(1.0, width - self.compactInset)
|
||||
} else {
|
||||
return max(1.0, floor(width * self.freeMaximumFillFactor))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct ChatMessageItemBubbleLayoutConstants {
|
||||
var edgeInset: CGFloat
|
||||
var defaultSpacing: CGFloat
|
||||
var mergedSpacing: CGFloat
|
||||
var maximumWidthFill: ChatMessageItemWidthFill
|
||||
var minimumSize: CGSize
|
||||
var contentInsets: UIEdgeInsets
|
||||
var borderInset: CGFloat
|
||||
var strokeInsets: UIEdgeInsets
|
||||
}
|
||||
|
||||
struct ChatMessageItemTextLayoutConstants {
|
||||
var bubbleInsets: UIEdgeInsets
|
||||
}
|
||||
|
||||
struct ChatMessageItemImageLayoutConstants {
|
||||
var bubbleInsets: UIEdgeInsets
|
||||
var statusInsets: UIEdgeInsets
|
||||
var defaultCornerRadius: CGFloat
|
||||
var mergedCornerRadius: CGFloat
|
||||
var contentMergedCornerRadius: CGFloat
|
||||
var maxDimensions: CGSize
|
||||
var minDimensions: CGSize
|
||||
}
|
||||
|
||||
struct ChatMessageItemVideoLayoutConstants {
|
||||
var maxHorizontalHeight: CGFloat
|
||||
var maxVerticalHeight: CGFloat
|
||||
}
|
||||
|
||||
struct ChatMessageItemInstantVideoConstants {
|
||||
var insets: UIEdgeInsets
|
||||
var dimensions: CGSize
|
||||
}
|
||||
|
||||
struct ChatMessageItemFileLayoutConstants {
|
||||
var bubbleInsets: UIEdgeInsets
|
||||
}
|
||||
|
||||
struct ChatMessageItemWallpaperLayoutConstants {
|
||||
var maxTextWidth: CGFloat
|
||||
}
|
||||
|
||||
struct ChatMessageItemLayoutConstants {
|
||||
var avatarDiameter: CGFloat
|
||||
var timestampHeaderHeight: CGFloat
|
||||
|
||||
var bubble: ChatMessageItemBubbleLayoutConstants
|
||||
var image: ChatMessageItemImageLayoutConstants
|
||||
var video: ChatMessageItemVideoLayoutConstants
|
||||
var text: ChatMessageItemTextLayoutConstants
|
||||
var file: ChatMessageItemFileLayoutConstants
|
||||
var instantVideo: ChatMessageItemInstantVideoConstants
|
||||
var wallpapers: ChatMessageItemWallpaperLayoutConstants
|
||||
|
||||
static var `default`: ChatMessageItemLayoutConstants {
|
||||
return self.compact
|
||||
}
|
||||
|
||||
fileprivate static var compact: ChatMessageItemLayoutConstants {
|
||||
let bubble = ChatMessageItemBubbleLayoutConstants(edgeInset: 4.0, defaultSpacing: 2.0 + UIScreenPixel, mergedSpacing: 0.0, maximumWidthFill: ChatMessageItemWidthFill(compactInset: 36.0, compactWidthBoundary: 500.0, freeMaximumFillFactor: 0.85), minimumSize: CGSize(width: 40.0, height: 35.0), contentInsets: UIEdgeInsets(top: 0.0, left: 6.0, bottom: 0.0, right: 0.0), borderInset: UIScreenPixel, strokeInsets: UIEdgeInsets(top: 1.0, left: 1.0, bottom: 1.0, right: 1.0))
|
||||
let text = ChatMessageItemTextLayoutConstants(bubbleInsets: UIEdgeInsets(top: 6.0 + UIScreenPixel, left: 12.0, bottom: 6.0 - UIScreenPixel, right: 12.0))
|
||||
let image = ChatMessageItemImageLayoutConstants(bubbleInsets: UIEdgeInsets(top: 2.0, left: 2.0, bottom: 2.0, right: 2.0), statusInsets: UIEdgeInsets(top: 0.0, left: 0.0, bottom: 6.0, right: 6.0), defaultCornerRadius: 16.0, mergedCornerRadius: 8.0, contentMergedCornerRadius: 0.0, maxDimensions: CGSize(width: 300.0, height: 380.0), minDimensions: CGSize(width: 170.0, height: 74.0))
|
||||
let video = ChatMessageItemVideoLayoutConstants(maxHorizontalHeight: 250.0, maxVerticalHeight: 360.0)
|
||||
let file = ChatMessageItemFileLayoutConstants(bubbleInsets: UIEdgeInsets(top: 15.0, left: 9.0, bottom: 15.0, right: 12.0))
|
||||
let instantVideo = ChatMessageItemInstantVideoConstants(insets: UIEdgeInsets(top: 4.0, left: 0.0, bottom: 4.0, right: 0.0), dimensions: CGSize(width: 212.0, height: 212.0))
|
||||
let wallpapers = ChatMessageItemWallpaperLayoutConstants(maxTextWidth: 180.0)
|
||||
|
||||
return ChatMessageItemLayoutConstants(avatarDiameter: 37.0, timestampHeaderHeight: 34.0, bubble: bubble, image: image, video: video, text: text, file: file, instantVideo: instantVideo, wallpapers: wallpapers)
|
||||
}
|
||||
|
||||
fileprivate static var regular: ChatMessageItemLayoutConstants {
|
||||
let bubble = ChatMessageItemBubbleLayoutConstants(edgeInset: 4.0, defaultSpacing: 2.0 + UIScreenPixel, mergedSpacing: 0.0, maximumWidthFill: ChatMessageItemWidthFill(compactInset: 36.0, compactWidthBoundary: 500.0, freeMaximumFillFactor: 0.65), minimumSize: CGSize(width: 40.0, height: 35.0), contentInsets: UIEdgeInsets(top: 0.0, left: 6.0, bottom: 0.0, right: 0.0), borderInset: UIScreenPixel, strokeInsets: UIEdgeInsets(top: 1.0, left: 1.0, bottom: 1.0, right: 1.0))
|
||||
let text = ChatMessageItemTextLayoutConstants(bubbleInsets: UIEdgeInsets(top: 6.0 + UIScreenPixel, left: 12.0, bottom: 6.0 - UIScreenPixel, right: 12.0))
|
||||
let image = ChatMessageItemImageLayoutConstants(bubbleInsets: UIEdgeInsets(top: 2.0, left: 2.0, bottom: 2.0, right: 2.0), statusInsets: UIEdgeInsets(top: 0.0, left: 0.0, bottom: 6.0, right: 6.0), defaultCornerRadius: 16.0, mergedCornerRadius: 8.0, contentMergedCornerRadius: 5.0, maxDimensions: CGSize(width: 440.0, height: 440.0), minDimensions: CGSize(width: 170.0, height: 74.0))
|
||||
let video = ChatMessageItemVideoLayoutConstants(maxHorizontalHeight: 250.0, maxVerticalHeight: 360.0)
|
||||
let file = ChatMessageItemFileLayoutConstants(bubbleInsets: UIEdgeInsets(top: 15.0, left: 9.0, bottom: 15.0, right: 12.0))
|
||||
let instantVideo = ChatMessageItemInstantVideoConstants(insets: UIEdgeInsets(top: 4.0, left: 0.0, bottom: 4.0, right: 0.0), dimensions: CGSize(width: 240.0, height: 240.0))
|
||||
let wallpapers = ChatMessageItemWallpaperLayoutConstants(maxTextWidth: 180.0)
|
||||
|
||||
return ChatMessageItemLayoutConstants(avatarDiameter: 37.0, timestampHeaderHeight: 34.0, bubble: bubble, image: image, video: video, text: text, file: file, instantVideo: instantVideo, wallpapers: wallpapers)
|
||||
}
|
||||
}
|
||||
import ChatMessageItemCommon
|
||||
|
||||
func chatMessageItemLayoutConstants(_ constants: (ChatMessageItemLayoutConstants, ChatMessageItemLayoutConstants), params: ListViewItemLayoutParams, presentationData: ChatPresentationData) -> ChatMessageItemLayoutConstants {
|
||||
var result: ChatMessageItemLayoutConstants
|
||||
|
|
@ -136,11 +39,6 @@ enum ChatMessageItemBottomNeighbor {
|
|||
case merged(semi: Bool)
|
||||
}
|
||||
|
||||
enum ChatMessagePeekPreviewContent {
|
||||
case media(Media)
|
||||
case url(ASDisplayNode, CGRect, String, Bool)
|
||||
}
|
||||
|
||||
private let voiceMessageDurationFormatter: DateComponentsFormatter = {
|
||||
let formatter = DateComponentsFormatter()
|
||||
formatter.unitsStyle = .spellOut
|
||||
|
|
@ -790,10 +688,6 @@ public class ChatMessageItemView: ListViewItemNode, ChatMessageItemNodeProtocol
|
|||
return nil
|
||||
}
|
||||
|
||||
func peekPreviewContent(at point: CGPoint) -> (Message, ChatMessagePeekPreviewContent)? {
|
||||
return nil
|
||||
}
|
||||
|
||||
func updateHiddenMedia() {
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -11,6 +11,8 @@ import MediaResources
|
|||
import LocationResources
|
||||
import LiveLocationPositionNode
|
||||
import ChatMessageDateAndStatusNode
|
||||
import ChatMessageBubbleContentNode
|
||||
import ChatMessageItemCommon
|
||||
|
||||
private let titleFont = Font.medium(14.0)
|
||||
private let liveTitleFont = Font.medium(16.0)
|
||||
|
|
|
|||
|
|
@ -11,6 +11,8 @@ import AccountContext
|
|||
import GridMessageSelectionNode
|
||||
import ChatControllerInteraction
|
||||
import ChatMessageDateAndStatusNode
|
||||
import ChatMessageBubbleContentNode
|
||||
import ChatMessageItemCommon
|
||||
|
||||
class ChatMessageMediaBubbleContentNode: ChatMessageBubbleContentNode {
|
||||
override var supportsMosaic: Bool {
|
||||
|
|
@ -411,15 +413,6 @@ class ChatMessageMediaBubbleContentNode: ChatMessageBubbleContentNode {
|
|||
return nil
|
||||
}
|
||||
|
||||
override func peekPreviewContent(at point: CGPoint) -> (Message, ChatMessagePeekPreviewContent)? {
|
||||
if let message = self.item?.message, let currentMedia = self.media, !message.containsSecretMedia {
|
||||
if self.interactiveImageNode.frame.contains(point), self.interactiveImageNode.isReadyForInteractivePreview() {
|
||||
return (message, .media(currentMedia))
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
override func updateHiddenMedia(_ media: [Media]?) -> Bool {
|
||||
var mediaHidden = false
|
||||
|
||||
|
|
|
|||
|
|
@ -12,6 +12,8 @@ import AvatarNode
|
|||
import TelegramPresentationData
|
||||
import ChatMessageBackground
|
||||
import ChatMessageDateAndStatusNode
|
||||
import ChatMessageBubbleContentNode
|
||||
import ChatMessageItemCommon
|
||||
|
||||
func isPollEffectivelyClosed(message: Message, poll: TelegramMediaPoll) -> Bool {
|
||||
if poll.isClosed {
|
||||
|
|
|
|||
|
|
@ -18,6 +18,8 @@ import UniversalMediaPlayer
|
|||
import TelegramUniversalVideoContent
|
||||
import GalleryUI
|
||||
import Markdown
|
||||
import ChatMessageBubbleContentNode
|
||||
import ChatMessageItemCommon
|
||||
|
||||
class ChatMessageProfilePhotoSuggestionContentNode: ChatMessageBubbleContentNode {
|
||||
private var mediaBackgroundContent: WallpaperBubbleBackgroundNode?
|
||||
|
|
|
|||
|
|
@ -13,40 +13,8 @@ import ReactionButtonListComponent
|
|||
import AccountContext
|
||||
import WallpaperBackgroundNode
|
||||
import ChatControllerInteraction
|
||||
|
||||
func canViewMessageReactionList(message: Message) -> Bool {
|
||||
var found = false
|
||||
var canViewList = false
|
||||
for attribute in message.attributes {
|
||||
if let attribute = attribute as? ReactionsMessageAttribute {
|
||||
canViewList = attribute.canViewList
|
||||
found = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if !found {
|
||||
return false
|
||||
}
|
||||
|
||||
if let peer = message.peers[message.id.peerId] {
|
||||
if let channel = peer as? TelegramChannel {
|
||||
if case .broadcast = channel.info {
|
||||
return false
|
||||
} else {
|
||||
return canViewList
|
||||
}
|
||||
} else if let _ = peer as? TelegramGroup {
|
||||
return canViewList
|
||||
} else if let _ = peer as? TelegramUser {
|
||||
return true
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
}
|
||||
import ChatMessageBubbleContentNode
|
||||
import ChatMessageItemCommon
|
||||
|
||||
final class MessageReactionButtonsNode: ASDisplayNode {
|
||||
enum DisplayType {
|
||||
|
|
|
|||
|
|
@ -8,6 +8,8 @@ import TelegramCore
|
|||
import TelegramPresentationData
|
||||
import TextFormat
|
||||
import ChatMessageDateAndStatusNode
|
||||
import ChatMessageBubbleContentNode
|
||||
import ChatMessageItemCommon
|
||||
|
||||
class ChatMessageRestrictedBubbleContentNode: ChatMessageBubbleContentNode {
|
||||
private let textNode: TextNode
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@ import WallpaperBackgroundNode
|
|||
import ChatControllerInteraction
|
||||
import ChatMessageForwardInfoNode
|
||||
import ChatMessageDateAndStatusNode
|
||||
import ChatMessageItemCommon
|
||||
|
||||
private let nameFont = Font.medium(14.0)
|
||||
private let inlineBotPrefixFont = Font.regular(14.0)
|
||||
|
|
|
|||
|
|
@ -21,6 +21,8 @@ import Markdown
|
|||
import ComponentFlow
|
||||
import AvatarStoryIndicatorComponent
|
||||
import AvatarNode
|
||||
import ChatMessageBubbleContentNode
|
||||
import ChatMessageItemCommon
|
||||
|
||||
class ChatMessageStoryMentionContentNode: ChatMessageBubbleContentNode {
|
||||
private var mediaBackgroundContent: WallpaperBubbleBackgroundNode?
|
||||
|
|
|
|||
|
|
@ -6,6 +6,8 @@ import AsyncDisplayKit
|
|||
import SwiftSignalKit
|
||||
import TelegramCore
|
||||
import TelegramPresentationData
|
||||
import ChatMessageBubbleContentNode
|
||||
import ChatMessageItemCommon
|
||||
|
||||
final class ChatMessageUnsupportedBubbleContentNode: ChatMessageBubbleContentNode {
|
||||
private var buttonNode: ChatMessageAttachedContentButtonNode
|
||||
|
|
|
|||
|
|
@ -18,6 +18,8 @@ import Markdown
|
|||
import RadialStatusNode
|
||||
import ComponentFlow
|
||||
import AudioTranscriptionPendingIndicatorComponent
|
||||
import ChatMessageBubbleContentNode
|
||||
import ChatMessageItemCommon
|
||||
|
||||
class ChatMessageWallpaperBubbleContentNode: ChatMessageBubbleContentNode {
|
||||
private var mediaBackgroundContent: WallpaperBubbleBackgroundNode?
|
||||
|
|
|
|||
|
|
@ -13,6 +13,8 @@ import InstantPageUI
|
|||
import UrlHandling
|
||||
import GalleryData
|
||||
import TelegramPresentationData
|
||||
import ChatMessageBubbleContentNode
|
||||
import ChatMessageItemCommon
|
||||
|
||||
private let titleFont: UIFont = Font.semibold(15.0)
|
||||
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ import TelegramPresentationData
|
|||
import MergeLists
|
||||
import AccountContext
|
||||
import ChatControllerInteraction
|
||||
import ChatHistoryEntry
|
||||
|
||||
enum ChatRecentActionsEntryContentIndex: Int32 {
|
||||
case header = 0
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ import TelegramPresentationData
|
|||
import AccountContext
|
||||
import WallpaperBackgroundNode
|
||||
import ChatControllerInteraction
|
||||
import ChatMessageItemCommon
|
||||
|
||||
private let titleFont = UIFont.systemFont(ofSize: 13.0)
|
||||
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ import TelegramPresentationData
|
|||
import AccountContext
|
||||
import WallpaperBackgroundNode
|
||||
import ChatControllerInteraction
|
||||
import ChatMessageItemCommon
|
||||
|
||||
private let titleFont = UIFont.systemFont(ofSize: 13.0)
|
||||
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ import AlertUI
|
|||
import PresentationDataUtils
|
||||
import ContactListUI
|
||||
import CounterContollerTitleView
|
||||
import EditableTokenListNode
|
||||
|
||||
private func peerTokenTitle(accountPeerId: PeerId, peer: Peer, strings: PresentationStrings, nameDisplayOrder: PresentationPersonNameOrder) -> String {
|
||||
if peer.id == accountPeerId {
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ import ContactListUI
|
|||
import ChatListUI
|
||||
import AnimationCache
|
||||
import MultiAnimationRenderer
|
||||
import EditableTokenListNode
|
||||
|
||||
private struct SearchResultEntry: Identifiable {
|
||||
let index: Int
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ import Display
|
|||
import MergeLists
|
||||
import AccountContext
|
||||
import ChatControllerInteraction
|
||||
import ChatHistoryEntry
|
||||
|
||||
func preparedChatHistoryViewTransition(from fromView: ChatHistoryView?, to toView: ChatHistoryView, reason: ChatHistoryViewTransitionReason, reverse: Bool, chatLocation: ChatLocation, controllerInteraction: ChatControllerInteraction, scrollPosition: ChatHistoryViewScrollPosition?, scrollAnimationCurve: ListViewAnimationCurve?, initialData: InitialMessageHistoryData?, keyboardButtonsMessage: Message?, cachedData: CachedPeerData?, cachedDataMessages: [MessageId: Message]?, readStateData: [PeerId: ChatHistoryCombinedInitialReadStateData]?, flashIndicators: Bool, updatedMessageSelection: Bool, messageTransitionNode: ChatMessageTransitionNode?, allUpdated: Bool) -> ChatHistoryViewTransition {
|
||||
var mergeResult: (deleteIndices: [Int], indicesAndItems: [(Int, ChatHistoryEntry, Int?)], updateIndices: [(Int, ChatHistoryEntry, Int)])
|
||||
|
|
|
|||
|
|
@ -42,6 +42,7 @@ import PeerInfoStoryGridScreen
|
|||
import TelegramAccountAuxiliaryMethods
|
||||
import PeerSelectionController
|
||||
import LegacyMessageInputPanel
|
||||
import ChatHistoryEntry
|
||||
|
||||
private final class AccountUserInterfaceInUseContext {
|
||||
let subscribers = Bag<(Bool) -> Void>()
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue