Refactoring [skip ci]

This commit is contained in:
Ali 2023-11-16 19:37:07 +04:00
parent 0483060cfb
commit 165b23570b
50 changed files with 539 additions and 159 deletions

View File

@ -808,6 +808,7 @@ public protocol TelegramRootControllerInterface: NavigationController {
func getContactsController() -> ViewController? func getContactsController() -> ViewController?
func getChatsController() -> ViewController? func getChatsController() -> ViewController?
func openSettings()
} }
public protocol SharedAccountContext: AnyObject { public protocol SharedAccountContext: AnyObject {
@ -864,6 +865,18 @@ public protocol SharedAccountContext: AnyObject {
func makeComposeController(context: AccountContext) -> ViewController func makeComposeController(context: AccountContext) -> ViewController
func makeChatListController(context: AccountContext, location: ChatListControllerLocation, controlsHistoryPreload: Bool, hideNetworkActivityStatus: Bool, previewing: Bool, enableDebugActions: Bool) -> ChatListController func makeChatListController(context: AccountContext, location: ChatListControllerLocation, controlsHistoryPreload: Bool, hideNetworkActivityStatus: Bool, previewing: Bool, enableDebugActions: Bool) -> ChatListController
func makeChatController(context: AccountContext, chatLocation: ChatLocation, subject: ChatControllerSubject?, botStart: ChatControllerInitialBotStart?, mode: ChatControllerPresentationMode) -> ChatController func makeChatController(context: AccountContext, chatLocation: ChatLocation, subject: ChatControllerSubject?, botStart: ChatControllerInitialBotStart?, mode: ChatControllerPresentationMode) -> ChatController
func makeChatHistoryListNode(
context: AccountContext,
updatedPresentationData: (initial: PresentationData, signal: Signal<PresentationData, NoError>),
chatLocation: ChatLocation,
chatLocationContextHolder: Atomic<ChatLocationContextHolder?>,
tagMask: MessageTags?,
source: ChatHistoryListSource,
subject: ChatControllerSubject?,
controllerInteraction: ChatControllerInteractionProtocol,
selectedMessages: Signal<Set<MessageId>?, NoError>,
mode: ChatHistoryListMode
) -> ChatHistoryListNode
func makeChatMessagePreviewItem(context: AccountContext, messages: [Message], theme: PresentationTheme, strings: PresentationStrings, wallpaper: TelegramWallpaper, fontSize: PresentationFontSize, chatBubbleCorners: PresentationChatBubbleCorners, dateTimeFormat: PresentationDateTimeFormat, nameOrder: PresentationPersonNameOrder, forcedResourceStatus: FileMediaResourceStatus?, tapMessage: ((Message) -> Void)?, clickThroughMessage: (() -> Void)?, backgroundNode: ASDisplayNode?, availableReactions: AvailableReactions?, isCentered: Bool) -> ListViewItem func makeChatMessagePreviewItem(context: AccountContext, messages: [Message], theme: PresentationTheme, strings: PresentationStrings, wallpaper: TelegramWallpaper, fontSize: PresentationFontSize, chatBubbleCorners: PresentationChatBubbleCorners, dateTimeFormat: PresentationDateTimeFormat, nameOrder: PresentationPersonNameOrder, forcedResourceStatus: FileMediaResourceStatus?, tapMessage: ((Message) -> Void)?, clickThroughMessage: (() -> Void)?, backgroundNode: ASDisplayNode?, availableReactions: AvailableReactions?, isCentered: Bool) -> ListViewItem
func makeChatMessageDateHeaderItem(context: AccountContext, timestamp: Int32, theme: PresentationTheme, strings: PresentationStrings, wallpaper: TelegramWallpaper, fontSize: PresentationFontSize, chatBubbleCorners: PresentationChatBubbleCorners, dateTimeFormat: PresentationDateTimeFormat, nameOrder: PresentationPersonNameOrder) -> ListViewItemHeader func makeChatMessageDateHeaderItem(context: AccountContext, timestamp: Int32, theme: PresentationTheme, strings: PresentationStrings, wallpaper: TelegramWallpaper, fontSize: PresentationFontSize, chatBubbleCorners: PresentationChatBubbleCorners, dateTimeFormat: PresentationDateTimeFormat, nameOrder: PresentationPersonNameOrder) -> ListViewItemHeader
func makePeerSharedMediaController(context: AccountContext, peerId: PeerId) -> ViewController? func makePeerSharedMediaController(context: AccountContext, peerId: PeerId) -> ViewController?
@ -904,7 +917,7 @@ public protocol SharedAccountContext: AnyObject {
func makeRecentSessionsController(context: AccountContext, activeSessionsContext: ActiveSessionsContext) -> ViewController & RecentSessionsController func makeRecentSessionsController(context: AccountContext, activeSessionsContext: ActiveSessionsContext) -> ViewController & RecentSessionsController
func makeChatQrCodeScreen(context: AccountContext, peer: Peer, threadId: Int64?) -> ViewController func makeChatQrCodeScreen(context: AccountContext, peer: Peer, threadId: Int64?, temporary: Bool) -> ViewController
func makePremiumIntroController(context: AccountContext, source: PremiumIntroSource, forceDark: Bool, dismissed: (() -> Void)?) -> ViewController func makePremiumIntroController(context: AccountContext, source: PremiumIntroSource, forceDark: Bool, dismissed: (() -> Void)?) -> ViewController
func makePremiumDemoController(context: AccountContext, subject: PremiumDemoSubject, action: @escaping () -> Void) -> ViewController func makePremiumDemoController(context: AccountContext, subject: PremiumDemoSubject, action: @escaping () -> Void) -> ViewController

View File

@ -875,6 +875,8 @@ public protocol ChatController: ViewController {
var isSelectingMessagesUpdated: ((Bool) -> Void)? { get set } var isSelectingMessagesUpdated: ((Bool) -> Void)? { get set }
func cancelSelectingMessages() func cancelSelectingMessages()
func activateSearch(domain: ChatSearchDomain, query: String)
func beginClearHistory(type: InteractiveHistoryClearingType)
} }
public protocol ChatMessagePreviewItemNode: AnyObject { public protocol ChatMessagePreviewItemNode: AnyObject {
@ -906,3 +908,80 @@ public protocol ChatMessageItemNodeProtocol: ListViewItemNode {
func targetForStoryTransition(id: StoryId) -> UIView? func targetForStoryTransition(id: StoryId) -> UIView?
func contentFrame() -> CGRect func contentFrame() -> CGRect
} }
public final class ChatControllerNavigationData: CustomViewControllerNavigationData {
public let peerId: PeerId
public let threadId: Int64?
public init(peerId: PeerId, threadId: Int64?) {
self.peerId = peerId
self.threadId = threadId
}
public func combine(summary: CustomViewControllerNavigationDataSummary?) -> CustomViewControllerNavigationDataSummary? {
if let summary = summary as? ChatControllerNavigationDataSummary {
return summary.adding(peerNavigationItem: ChatNavigationStackItem(peerId: self.peerId, threadId: threadId))
} else {
return ChatControllerNavigationDataSummary(peerNavigationItems: [ChatNavigationStackItem(peerId: self.peerId, threadId: threadId)])
}
}
}
public final class ChatControllerNavigationDataSummary: CustomViewControllerNavigationDataSummary {
public let peerNavigationItems: [ChatNavigationStackItem]
public init(peerNavigationItems: [ChatNavigationStackItem]) {
self.peerNavigationItems = peerNavigationItems
}
public func adding(peerNavigationItem: ChatNavigationStackItem) -> ChatControllerNavigationDataSummary {
var peerNavigationItems = self.peerNavigationItems
if let index = peerNavigationItems.firstIndex(of: peerNavigationItem) {
peerNavigationItems.removeSubrange(0 ... index)
}
peerNavigationItems.insert(peerNavigationItem, at: 0)
return ChatControllerNavigationDataSummary(peerNavigationItems: peerNavigationItems)
}
}
public enum ChatHistoryListSource {
public struct Quote {
public var text: String
public var offset: Int?
public init(text: String, offset: Int?) {
self.text = text
self.offset = offset
}
}
case `default`
case custom(messages: Signal<([Message], Int32, Bool), NoError>, messageId: MessageId, quote: Quote?, loadMore: (() -> Void)?)
}
public enum ChatHistoryListDisplayHeaders {
case none
case all
case allButLast
}
public enum ChatHistoryListMode: Equatable {
case bubbles
case list(search: Bool, reversed: Bool, reverseGroups: Bool, displayHeaders: ChatHistoryListDisplayHeaders, hintLinks: Bool, isGlobalSearch: Bool)
}
public protocol ChatControllerInteractionProtocol: AnyObject {
}
public enum ChatHistoryNodeHistoryState: Equatable {
case loading
case loaded(isEmpty: Bool)
}
public protocol ChatHistoryListNode: ListView {
var historyState: ValuePromise<ChatHistoryNodeHistoryState> { get }
func scrollToEndOfHistory()
func updateLayout(transition: ContainedViewLayoutTransition, updateSizeAndInsets: ListViewUpdateSizeAndInsets)
func messageInCurrentHistoryView(_ id: MessageId) -> Message?
}

View File

@ -286,11 +286,6 @@ public struct ChatPresentationImportState: Equatable {
} }
} }
public enum ChatHistoryNodeHistoryState: Equatable {
case loading
case loaded(isEmpty: Bool)
}
public struct ChatPresentationTranslationState: Equatable { public struct ChatPresentationTranslationState: Equatable {
public var isEnabled: Bool public var isEnabled: Bool
public var fromLang: String public var fromLang: String

View File

@ -449,7 +449,7 @@ public class ContactsController: ViewController {
let _ = (strongSelf.context.account.postbox.loadedPeerWithId(strongSelf.context.account.peerId) let _ = (strongSelf.context.account.postbox.loadedPeerWithId(strongSelf.context.account.peerId)
|> deliverOnMainQueue).start(next: { [weak self, weak controller] peer in |> deliverOnMainQueue).start(next: { [weak self, weak controller] peer in
if let strongSelf = self, let controller = controller { if let strongSelf = self, let controller = controller {
controller.present(strongSelf.context.sharedContext.makeChatQrCodeScreen(context: strongSelf.context, peer: peer, threadId: nil), in: .window(.root)) controller.present(strongSelf.context.sharedContext.makeChatQrCodeScreen(context: strongSelf.context, peer: peer, threadId: nil, temporary: false), in: .window(.root))
} }
}) })
} }

View File

@ -115,6 +115,7 @@ final class CallControllerNodeV2: ViewControllerTracingNode, CallControllerNodeP
avatarImage: nil, avatarImage: nil,
audioOutput: .internalSpeaker, audioOutput: .internalSpeaker,
isMicrophoneMuted: false, isMicrophoneMuted: false,
localVideo: nil,
remoteVideo: nil remoteVideo: nil
) )
if let peer = call.peer { if let peer = call.peer {
@ -424,7 +425,7 @@ private final class AdaptedCallVideoSource: VideoSource {
return return
} }
output = Output(y: yTexture, uv: uvTexture, rotationAngle: rotationAngle) output = Output(y: yTexture, uv: uvTexture, rotationAngle: rotationAngle, sourceId: videoFrameData.mirrorHorizontally || videoFrameData.mirrorVertically ? 1 : 0)
default: default:
return return
} }

View File

@ -412,6 +412,9 @@ swift_library(
"//submodules/TelegramUI/Components/PeerAllowedReactionsScreen", "//submodules/TelegramUI/Components/PeerAllowedReactionsScreen",
"//submodules/MetalEngine", "//submodules/MetalEngine",
"//submodules/TelegramUI/Components/DustEffect", "//submodules/TelegramUI/Components/DustEffect",
"//submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen",
"//submodules/TelegramUI/Components/Chat/ChatMessageSelectionInputPanelNode",
"//submodules/TelegramUI/Components/Chat/ChatQrCodeScreen",
] + select({ ] + select({
"@build_bazel_rules_apple//apple:ios_arm64": appcenter_targets, "@build_bazel_rules_apple//apple:ios_arm64": appcenter_targets,
"//build-system:ios_sim_arm64": [], "//build-system:ios_sim_arm64": [],

View File

@ -0,0 +1,30 @@
load("@build_bazel_rules_swift//swift:swift.bzl", "swift_library")
swift_library(
name = "ChatHistorySearchContainerNode",
module_name = "ChatHistorySearchContainerNode",
srcs = glob([
"Sources/**/*.swift",
]),
copts = [
"-warnings-as-errors",
],
deps = [
"//submodules/AsyncDisplayKit",
"//submodules/Display",
"//submodules/SSignalKit/SwiftSignalKit",
"//submodules/Postbox",
"//submodules/TelegramCore",
"//submodules/TelegramPresentationData",
"//submodules/MergeLists",
"//submodules/AccountContext",
"//submodules/SearchUI",
"//submodules/TelegramUIPreferences",
"//submodules/ListMessageItem",
"//submodules/TelegramUI/Components/ChatControllerInteraction",
"//submodules/TelegramUI/Components/Chat/ChatMessageItemView",
],
visibility = [
"//visibility:public",
],
)

View File

@ -14,6 +14,26 @@ import ListMessageItem
import ChatControllerInteraction import ChatControllerInteraction
import ChatMessageItemView import ChatMessageItemView
private extension ListMessageItemInteraction {
convenience init(controllerInteraction: ChatControllerInteraction) {
self.init(openMessage: { message, mode -> Bool in
return controllerInteraction.openMessage(message, OpenMessageParams(mode: mode))
}, openMessageContextMenu: { message, bool, node, rect, gesture in
controllerInteraction.openMessageContextMenu(message, bool, node, rect, gesture, nil)
}, toggleMessagesSelection: { messageId, selected in
controllerInteraction.toggleMessagesSelection(messageId, selected)
}, openUrl: { url, param1, param2, message in
controllerInteraction.openUrl(ChatControllerInteraction.OpenUrl(url: url, concealed: param1, external: param2, message: message))
}, openInstantPage: { message, data in
controllerInteraction.openInstantPage(message, data)
}, longTap: { action, message in
controllerInteraction.longTap(action, message)
}, getHiddenMedia: {
return controllerInteraction.hiddenMedia
})
}
}
private enum ChatHistorySearchEntryStableId: Hashable { private enum ChatHistorySearchEntryStableId: Hashable {
case messageId(MessageId) case messageId(MessageId)
} }
@ -94,7 +114,7 @@ private func chatHistorySearchContainerPreparedTransition(from fromEntries: [Cha
return ChatHistorySearchContainerTransition(deletions: deletions, insertions: insertions, updates: updates, query: query, displayingResults: displayingResults) return ChatHistorySearchContainerTransition(deletions: deletions, insertions: insertions, updates: updates, query: query, displayingResults: displayingResults)
} }
final class ChatHistorySearchContainerNode: SearchDisplayControllerContentNode { public final class ChatHistorySearchContainerNode: SearchDisplayControllerContentNode {
private let context: AccountContext private let context: AccountContext
private let dimNode: ASDisplayNode private let dimNode: ASDisplayNode
@ -106,7 +126,7 @@ final class ChatHistorySearchContainerNode: SearchDisplayControllerContentNode {
private var containerLayout: (ContainerViewLayout, CGFloat)? private var containerLayout: (ContainerViewLayout, CGFloat)?
private var currentEntries: [ChatHistorySearchEntry]? private var currentEntries: [ChatHistorySearchEntry]?
var currentMessages: [MessageId: Message]? public var currentMessages: [MessageId: Message]?
private var currentQuery: String? private var currentQuery: String?
private let searchQuery = Promise<String?>() private let searchQuery = Promise<String?>()
@ -114,7 +134,7 @@ final class ChatHistorySearchContainerNode: SearchDisplayControllerContentNode {
private let searchDisposable = MetaDisposable() private let searchDisposable = MetaDisposable()
private let _isSearching = ValuePromise<Bool>(false, ignoreRepeated: true) private let _isSearching = ValuePromise<Bool>(false, ignoreRepeated: true)
override var isSearching: Signal<Bool, NoError> { override public var isSearching: Signal<Bool, NoError> {
return self._isSearching.get() return self._isSearching.get()
} }
@ -125,11 +145,11 @@ final class ChatHistorySearchContainerNode: SearchDisplayControllerContentNode {
private var enqueuedTransitions: [(ChatHistorySearchContainerTransition, Bool)] = [] private var enqueuedTransitions: [(ChatHistorySearchContainerTransition, Bool)] = []
public override var hasDim: Bool { override public var hasDim: Bool {
return true return true
} }
init(context: AccountContext, peerId: PeerId, threadId: Int64?, tagMask: MessageTags, interfaceInteraction: ChatControllerInteraction) { public init(context: AccountContext, peerId: PeerId, threadId: Int64?, tagMask: MessageTags, interfaceInteraction: ChatControllerInteraction) {
self.context = context self.context = context
let presentationData = context.sharedContext.currentPresentationData.with { $0 } let presentationData = context.sharedContext.currentPresentationData.with { $0 }
@ -236,13 +256,13 @@ final class ChatHistorySearchContainerNode: SearchDisplayControllerContentNode {
self.searchDisposable.dispose() self.searchDisposable.dispose()
} }
override func didLoad() { override public func didLoad() {
super.didLoad() super.didLoad()
self.dimNode.view.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(self.dimTapGesture(_:)))) self.dimNode.view.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(self.dimTapGesture(_:))))
} }
override func searchTextUpdated(text: String) { override public func searchTextUpdated(text: String) {
if text.isEmpty { if text.isEmpty {
self.searchQuery.set(.single(nil)) self.searchQuery.set(.single(nil))
} else { } else {
@ -250,7 +270,7 @@ final class ChatHistorySearchContainerNode: SearchDisplayControllerContentNode {
} }
} }
override func containerLayoutUpdated(_ layout: ContainerViewLayout, navigationBarHeight: CGFloat, transition: ContainedViewLayoutTransition) { override public func containerLayoutUpdated(_ layout: ContainerViewLayout, navigationBarHeight: CGFloat, transition: ContainedViewLayoutTransition) {
let firstValidLayout = self.containerLayout == nil let firstValidLayout = self.containerLayout == nil
self.containerLayout = (layout, navigationBarHeight) self.containerLayout = (layout, navigationBarHeight)
@ -327,13 +347,13 @@ final class ChatHistorySearchContainerNode: SearchDisplayControllerContentNode {
} }
} }
@objc func dimTapGesture(_ recognizer: UITapGestureRecognizer) { @objc private func dimTapGesture(_ recognizer: UITapGestureRecognizer) {
if case .ended = recognizer.state { if case .ended = recognizer.state {
self.cancel?() self.cancel?()
} }
} }
func messageForGallery(_ id: MessageId) -> Message? { public func messageForGallery(_ id: MessageId) -> Message? {
if let currentEntries = self.currentEntries { if let currentEntries = self.currentEntries {
for entry in currentEntries { for entry in currentEntries {
switch entry { switch entry {
@ -347,7 +367,7 @@ final class ChatHistorySearchContainerNode: SearchDisplayControllerContentNode {
return nil return nil
} }
func updateHiddenMedia() { public func updateHiddenMedia() {
self.listNode.forEachItemNode { itemNode in self.listNode.forEachItemNode { itemNode in
if let itemNode = itemNode as? ChatMessageItemView { if let itemNode = itemNode as? ChatMessageItemView {
itemNode.updateHiddenMedia() itemNode.updateHiddenMedia()
@ -357,7 +377,7 @@ final class ChatHistorySearchContainerNode: SearchDisplayControllerContentNode {
} }
} }
func transitionNodeForGallery(messageId: MessageId, media: Media) -> (ASDisplayNode, CGRect, () -> (UIView?, UIView?))? { public func transitionNodeForGallery(messageId: MessageId, media: Media) -> (ASDisplayNode, CGRect, () -> (UIView?, UIView?))? {
var transitionNode: (ASDisplayNode, CGRect, () -> (UIView?, UIView?))? var transitionNode: (ASDisplayNode, CGRect, () -> (UIView?, UIView?))?
self.listNode.forEachItemNode { itemNode in self.listNode.forEachItemNode { itemNode in
if let itemNode = itemNode as? ChatMessageItemView { if let itemNode = itemNode as? ChatMessageItemView {

View File

@ -0,0 +1,26 @@
load("@build_bazel_rules_swift//swift:swift.bzl", "swift_library")
swift_library(
name = "ChatMessageSelectionInputPanelNode",
module_name = "ChatMessageSelectionInputPanelNode",
srcs = glob([
"Sources/**/*.swift",
]),
copts = [
"-warnings-as-errors",
],
deps = [
"//submodules/AsyncDisplayKit",
"//submodules/Display",
"//submodules/Postbox",
"//submodules/TelegramCore",
"//submodules/SSignalKit/SwiftSignalKit",
"//submodules/TelegramPresentationData",
"//submodules/AppBundle",
"//submodules/ChatPresentationInterfaceState",
"//submodules/TelegramUI/Components/Chat/ChatInputPanelNode",
],
visibility = [
"//visibility:public",
],
)

View File

@ -11,7 +11,7 @@ import AppBundle
import ChatPresentationInterfaceState import ChatPresentationInterfaceState
import ChatInputPanelNode import ChatInputPanelNode
final class ChatMessageSelectionInputPanelNode: ChatInputPanelNode { public final class ChatMessageSelectionInputPanelNode: ChatInputPanelNode {
private let deleteButton: HighlightableButtonNode private let deleteButton: HighlightableButtonNode
private let reportButton: HighlightableButtonNode private let reportButton: HighlightableButtonNode
private let forwardButton: HighlightableButtonNode private let forwardButton: HighlightableButtonNode
@ -27,7 +27,7 @@ final class ChatMessageSelectionInputPanelNode: ChatInputPanelNode {
private let canDeleteMessagesDisposable = MetaDisposable() private let canDeleteMessagesDisposable = MetaDisposable()
var selectedMessages = Set<MessageId>() { public var selectedMessages = Set<MessageId>() {
didSet { didSet {
if oldValue != self.selectedMessages { if oldValue != self.selectedMessages {
self.forwardButton.isEnabled = self.selectedMessages.count != 0 self.forwardButton.isEnabled = self.selectedMessages.count != 0
@ -53,7 +53,7 @@ final class ChatMessageSelectionInputPanelNode: ChatInputPanelNode {
} }
} }
init(theme: PresentationTheme, strings: PresentationStrings, peerMedia: Bool = false) { public init(theme: PresentationTheme, strings: PresentationStrings, peerMedia: Bool = false) {
self.theme = theme self.theme = theme
self.peerMedia = peerMedia self.peerMedia = peerMedia
@ -108,7 +108,7 @@ final class ChatMessageSelectionInputPanelNode: ChatInputPanelNode {
self.canDeleteMessagesDisposable.dispose() self.canDeleteMessagesDisposable.dispose()
} }
func updateTheme(theme: PresentationTheme) { public func updateTheme(theme: PresentationTheme) {
if self.theme !== theme { if self.theme !== theme {
self.theme = theme self.theme = theme
@ -125,15 +125,15 @@ final class ChatMessageSelectionInputPanelNode: ChatInputPanelNode {
} }
} }
@objc func deleteButtonPressed() { @objc private func deleteButtonPressed() {
self.interfaceInteraction?.deleteSelectedMessages() self.interfaceInteraction?.deleteSelectedMessages()
} }
@objc func reportButtonPressed() { @objc private func reportButtonPressed() {
self.interfaceInteraction?.reportSelectedMessages() self.interfaceInteraction?.reportSelectedMessages()
} }
@objc func forwardButtonPressed() { @objc private func forwardButtonPressed() {
if let _ = self.presentationInterfaceState?.renderedPeer?.peer as? TelegramSecretChat { if let _ = self.presentationInterfaceState?.renderedPeer?.peer as? TelegramSecretChat {
return return
} }
@ -144,7 +144,7 @@ final class ChatMessageSelectionInputPanelNode: ChatInputPanelNode {
} }
} }
@objc func shareButtonPressed() { @objc private func shareButtonPressed() {
if let _ = self.presentationInterfaceState?.renderedPeer?.peer as? TelegramSecretChat { if let _ = self.presentationInterfaceState?.renderedPeer?.peer as? TelegramSecretChat {
return return
} }
@ -155,7 +155,7 @@ final class ChatMessageSelectionInputPanelNode: ChatInputPanelNode {
} }
} }
override func updateLayout(width: CGFloat, leftInset: CGFloat, rightInset: CGFloat, bottomInset: CGFloat, additionalSideInsets: UIEdgeInsets, maxHeight: CGFloat, isSecondary: Bool, transition: ContainedViewLayoutTransition, interfaceState: ChatPresentationInterfaceState, metrics: LayoutMetrics, isMediaInputExpanded: Bool) -> CGFloat { override public func updateLayout(width: CGFloat, leftInset: CGFloat, rightInset: CGFloat, bottomInset: CGFloat, additionalSideInsets: UIEdgeInsets, maxHeight: CGFloat, isSecondary: Bool, transition: ContainedViewLayoutTransition, interfaceState: ChatPresentationInterfaceState, metrics: LayoutMetrics, isMediaInputExpanded: Bool) -> CGFloat {
self.validLayout = (width, leftInset, rightInset, bottomInset, additionalSideInsets, maxHeight, metrics, isSecondary, isMediaInputExpanded) self.validLayout = (width, leftInset, rightInset, bottomInset, additionalSideInsets, maxHeight, metrics, isSecondary, isMediaInputExpanded)
let panelHeight = defaultHeight(metrics: metrics) let panelHeight = defaultHeight(metrics: metrics)
@ -242,7 +242,7 @@ final class ChatMessageSelectionInputPanelNode: ChatInputPanelNode {
return panelHeight return panelHeight
} }
override func minimalHeight(interfaceState: ChatPresentationInterfaceState, metrics: LayoutMetrics) -> CGFloat { override public func minimalHeight(interfaceState: ChatPresentationInterfaceState, metrics: LayoutMetrics) -> CGFloat {
return defaultHeight(metrics: metrics) return defaultHeight(metrics: metrics)
} }
} }

View File

@ -0,0 +1,51 @@
load("@build_bazel_rules_swift//swift:swift.bzl", "swift_library")
swift_library(
name = "ChatQrCodeScreen",
module_name = "ChatQrCodeScreen",
srcs = glob([
"Sources/**/*.swift",
]),
copts = [
"-warnings-as-errors",
],
deps = [
"//submodules/Display",
"//submodules/AsyncDisplayKit",
"//submodules/Postbox",
"//submodules/TelegramCore",
"//submodules/SSignalKit/SwiftSignalKit",
"//submodules/AccountContext",
"//submodules/SolidRoundedButtonNode",
"//submodules/TelegramPresentationData",
"//submodules/TelegramUIPreferences",
"//submodules/TelegramNotices",
"//submodules/PresentationDataUtils",
"//submodules/AnimationUI",
"//submodules/MergeLists",
"//submodules/MediaResources",
"//submodules/StickerResources",
"//submodules/WallpaperResources",
"//submodules/TooltipUI",
"//submodules/AnimatedStickerNode",
"//submodules/TelegramAnimatedStickerNode",
"//submodules/ShimmerEffect",
"//submodules/WallpaperBackgroundNode",
"//submodules/QrCode",
"//submodules/AvatarNode",
"//submodules/ShareController",
"//submodules/TelegramStringFormatting",
"//submodules/PhotoResources",
"//submodules/TextFormat",
"//submodules/MediaPlayer:UniversalMediaPlayer",
"//submodules/TelegramUniversalVideoContent",
"//submodules/GalleryUI",
"//submodules/SaveToCameraRoll",
"//submodules/SegmentedControlNode",
"//submodules/AnimatedCountLabelNode",
"//submodules/HexColor",
],
visibility = [
"//visibility:public",
],
)

View File

@ -34,6 +34,7 @@ import GalleryUI
import SaveToCameraRoll import SaveToCameraRoll
import SegmentedControlNode import SegmentedControlNode
import AnimatedCountLabelNode import AnimatedCountLabelNode
import HexColor
private func closeButtonImage(theme: PresentationTheme) -> UIImage? { private func closeButtonImage(theme: PresentationTheme) -> UIImage? {
return generateImage(CGSize(width: 30.0, height: 30.0), contextGenerator: { size, context in return generateImage(CGSize(width: 30.0, height: 30.0), contextGenerator: { size, context in
@ -560,15 +561,15 @@ private final class ThemeSettingsThemeItemIconNode : ListViewItemNode {
} }
} }
final class ChatQrCodeScreen: ViewController { public final class ChatQrCodeScreen: ViewController {
static let themeCrossfadeDuration: Double = 0.3 public static let themeCrossfadeDuration: Double = 0.3
static let themeCrossfadeDelay: Double = 0.05 public static let themeCrossfadeDelay: Double = 0.05
enum Subject { public enum Subject {
case peer(peer: Peer, threadId: Int64?, temporary: Bool) case peer(peer: Peer, threadId: Int64?, temporary: Bool)
case messages([Message]) case messages([Message])
var fileName: String { public var fileName: String {
switch self { switch self {
case let .peer(peer, threadId, _): case let .peer(peer, threadId, _):
var result: String var result: String
@ -608,9 +609,9 @@ final class ChatQrCodeScreen: ViewController {
private var presentationThemePromise = Promise<PresentationTheme?>() private var presentationThemePromise = Promise<PresentationTheme?>()
private var presentationDataDisposable: Disposable? private var presentationDataDisposable: Disposable?
var dismissed: (() -> Void)? public var dismissed: (() -> Void)?
init(context: AccountContext, subject: ChatQrCodeScreen.Subject) { public init(context: AccountContext, subject: ChatQrCodeScreen.Subject) {
self.context = context self.context = context
self.presentationData = context.sharedContext.currentPresentationData.with { $0 } self.presentationData = context.sharedContext.currentPresentationData.with { $0 }
self.subject = subject self.subject = subject
@ -641,7 +642,7 @@ final class ChatQrCodeScreen: ViewController {
self.ready.set(self.controllerNode.ready.get()) self.ready.set(self.controllerNode.ready.get())
} }
required init(coder aDecoder: NSCoder) { required public init(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented") fatalError("init(coder:) has not been implemented")
} }
@ -1265,8 +1266,11 @@ private class ChatQrCodeScreenNode: ViewControllerTracingNode, UIScrollViewDeleg
let newIconColors = iconColors(theme: self.presentationData.theme) let newIconColors = iconColors(theme: self.presentationData.theme)
if !self.switchThemeButton.isUserInteractionEnabled { if !self.switchThemeButton.isUserInteractionEnabled {
Queue.mainQueue().after(ChatThemeScreen.themeCrossfadeDelay) { let themeCrossfadeDuration: Double = 0.3
self.switchThemeIconAnimator = DisplayLinkAnimator(duration: ChatThemeScreen.themeCrossfadeDuration * UIView.animationDurationFactor(), from: 0.0, to: 1.0, update: { [weak self] value in let themeCrossfadeDelay: Double = 0.25
Queue.mainQueue().after(themeCrossfadeDelay) {
self.switchThemeIconAnimator = DisplayLinkAnimator(duration: themeCrossfadeDuration * UIView.animationDurationFactor(), from: 0.0, to: 1.0, update: { [weak self] value in
self?.animationNode.setColors(colors: interpolateColors(from: previousIconColors, to: newIconColors, fraction: value)) self?.animationNode.setColors(colors: interpolateColors(from: previousIconColors, to: newIconColors, fraction: value))
}, completion: { [weak self] in }, completion: { [weak self] in
self?.switchThemeIconAnimator?.invalidate() self?.switchThemeIconAnimator?.invalidate()
@ -1278,7 +1282,7 @@ private class ChatQrCodeScreenNode: ViewControllerTracingNode, UIScrollViewDeleg
} }
} }
override func didLoad() { override public func didLoad() {
super.didLoad() super.didLoad()
self.wrappingScrollNode.view.delegate = self self.wrappingScrollNode.view.delegate = self
@ -1289,11 +1293,11 @@ private class ChatQrCodeScreenNode: ViewControllerTracingNode, UIScrollViewDeleg
self.listNode.view.disablesInteractiveTransitionGestureRecognizer = true self.listNode.view.disablesInteractiveTransitionGestureRecognizer = true
} }
@objc func cancelButtonPressed() { @objc private func cancelButtonPressed() {
self.cancel?() self.cancel?()
} }
@objc func switchThemePressed() { @objc private func switchThemePressed() {
self.switchThemeButton.isUserInteractionEnabled = false self.switchThemeButton.isUserInteractionEnabled = false
Queue.mainQueue().after(0.5) { Queue.mainQueue().after(0.5) {
self.switchThemeButton.isUserInteractionEnabled = true self.switchThemeButton.isUserInteractionEnabled = true
@ -1376,7 +1380,7 @@ private class ChatQrCodeScreenNode: ViewControllerTracingNode, UIScrollViewDeleg
} }
private var animatedOut = false private var animatedOut = false
func animateIn() { public func animateIn() {
let offset = self.bounds.size.height - self.contentBackgroundNode.frame.minY let offset = self.bounds.size.height - self.contentBackgroundNode.frame.minY
let transition = ContainedViewLayoutTransition.animated(duration: 0.4, curve: .spring) let transition = ContainedViewLayoutTransition.animated(duration: 0.4, curve: .spring)
@ -1387,7 +1391,7 @@ private class ChatQrCodeScreenNode: ViewControllerTracingNode, UIScrollViewDeleg
}) })
} }
func animateOut(completion: (() -> Void)? = nil) { public func animateOut(completion: (() -> Void)? = nil) {
self.animatedOut = true self.animatedOut = true
let offset = self.bounds.size.height - self.contentBackgroundNode.frame.minY let offset = self.bounds.size.height - self.contentBackgroundNode.frame.minY
@ -1399,7 +1403,7 @@ private class ChatQrCodeScreenNode: ViewControllerTracingNode, UIScrollViewDeleg
}) })
} }
func scrollViewDidEndDragging(_ scrollView: UIScrollView, willDecelerate decelerate: Bool) { public func scrollViewDidEndDragging(_ scrollView: UIScrollView, willDecelerate decelerate: Bool) {
let contentOffset = scrollView.contentOffset let contentOffset = scrollView.contentOffset
let additionalTopHeight = max(0.0, -contentOffset.y) let additionalTopHeight = max(0.0, -contentOffset.y)
@ -1408,7 +1412,7 @@ private class ChatQrCodeScreenNode: ViewControllerTracingNode, UIScrollViewDeleg
} }
} }
func containerLayoutUpdated(_ layout: ContainerViewLayout, navigationBarHeight: CGFloat, transition: ContainedViewLayoutTransition) { public func containerLayoutUpdated(_ layout: ContainerViewLayout, navigationBarHeight: CGFloat, transition: ContainedViewLayoutTransition) {
self.containerLayout = (layout, navigationBarHeight) self.containerLayout = (layout, navigationBarHeight)
var insets = layout.insets(options: [.statusBar, .input]) var insets = layout.insets(options: [.statusBar, .input])

View File

@ -115,7 +115,7 @@ public struct OpenMessageParams {
} }
} }
public final class ChatControllerInteraction { public final class ChatControllerInteraction: ChatControllerInteractionProtocol {
public enum OpenPeerSource { public enum OpenPeerSource {
case `default` case `default`
case reaction case reaction

View File

@ -0,0 +1,19 @@
load("@build_bazel_rules_swift//swift:swift.bzl", "swift_library")
swift_library(
name = "MultiScaleTextNode",
module_name = "MultiScaleTextNode",
srcs = glob([
"Sources/**/*.swift",
]),
copts = [
"-warnings-as-errors",
],
deps = [
"//submodules/Display",
"//submodules/AsyncDisplayKit",
],
visibility = [
"//visibility:public",
],
)

View File

@ -18,29 +18,38 @@ private final class MultiScaleTextStateNode: ASDisplayNode {
} }
} }
final class MultiScaleTextState { public final class MultiScaleTextState {
struct Attributes { public struct Attributes {
var font: UIFont public var font: UIFont
var color: UIColor public var color: UIColor
public init(font: UIFont, color: UIColor) {
self.font = font
self.color = color
}
} }
let attributes: Attributes public let attributes: Attributes
let constrainedSize: CGSize public let constrainedSize: CGSize
init(attributes: Attributes, constrainedSize: CGSize) { public init(attributes: Attributes, constrainedSize: CGSize) {
self.attributes = attributes self.attributes = attributes
self.constrainedSize = constrainedSize self.constrainedSize = constrainedSize
} }
} }
struct MultiScaleTextLayout { public struct MultiScaleTextLayout {
var size: CGSize public var size: CGSize
public init(size: CGSize) {
self.size = size
}
} }
final class MultiScaleTextNode: ASDisplayNode { public final class MultiScaleTextNode: ASDisplayNode {
private let stateNodes: [AnyHashable: MultiScaleTextStateNode] private let stateNodes: [AnyHashable: MultiScaleTextStateNode]
init(stateKeys: [AnyHashable]) { public init(stateKeys: [AnyHashable]) {
self.stateNodes = Dictionary(stateKeys.map { ($0, MultiScaleTextStateNode()) }, uniquingKeysWith: { lhs, _ in lhs }) self.stateNodes = Dictionary(stateKeys.map { ($0, MultiScaleTextStateNode()) }, uniquingKeysWith: { lhs, _ in lhs })
super.init() super.init()
@ -50,11 +59,11 @@ final class MultiScaleTextNode: ASDisplayNode {
} }
} }
func stateNode(forKey key: AnyHashable) -> ASDisplayNode? { public func stateNode(forKey key: AnyHashable) -> ASDisplayNode? {
return self.stateNodes[key]?.textNode return self.stateNodes[key]?.textNode
} }
func updateLayout(text: String, states: [AnyHashable: MultiScaleTextState], mainState: AnyHashable) -> [AnyHashable: MultiScaleTextLayout] { public func updateLayout(text: String, states: [AnyHashable: MultiScaleTextState], mainState: AnyHashable) -> [AnyHashable: MultiScaleTextLayout] {
assert(Set(states.keys) == Set(self.stateNodes.keys)) assert(Set(states.keys) == Set(self.stateNodes.keys))
assert(states[mainState] != nil) assert(states[mainState] != nil)
@ -85,7 +94,7 @@ final class MultiScaleTextNode: ASDisplayNode {
return result return result
} }
func update(stateFractions: [AnyHashable: CGFloat], alpha: CGFloat = 1.0, transition: ContainedViewLayoutTransition) { public func update(stateFractions: [AnyHashable: CGFloat], alpha: CGFloat = 1.0, transition: ContainedViewLayoutTransition) {
var fractionSum: CGFloat = 0.0 var fractionSum: CGFloat = 0.0
for (_, fraction) in stateFractions { for (_, fraction) in stateFractions {
fractionSum += fraction fractionSum += fraction

View File

@ -0,0 +1,135 @@
load("@build_bazel_rules_swift//swift:swift.bzl", "swift_library")
swift_library(
name = "PeerInfoScreen",
module_name = "PeerInfoScreen",
srcs = glob([
"Sources/**/*.swift",
]),
copts = [
"-warnings-as-errors",
],
deps = [
"//submodules/AccountContext",
"//submodules/AccountUtils",
"//submodules/ActionSheetPeerItem",
"//submodules/ActivityIndicator",
"//submodules/TelegramUI/Components/AnimationCache",
"//submodules/AnimationUI",
"//submodules/AppBundle",
"//submodules/AsyncDisplayKit",
"//submodules/TelegramUI/Components/AvatarEditorScreen",
"//submodules/AvatarNode",
"//submodules/TelegramUI/Components/Stories/AvatarStoryIndicatorComponent",
"//submodules/AvatarVideoNode",
"//submodules/CalendarMessageScreen",
"//submodules/CallListUI",
"//submodules/TelegramUI/Components/Chat/ChatAvatarNavigationNode",
"//submodules/TelegramUI/Components/ChatControllerInteraction",
"//submodules/ChatInterfaceState",
"//submodules/TelegramUI/Components/ChatListHeaderComponent",
"//submodules/ChatListUI",
"//submodules/TelegramUI/Components/Chat/ChatMessageItemView",
"//submodules/ChatPresentationInterfaceState",
"//submodules/TelegramUI/Components/ChatTimerScreen",
"//submodules/TelegramUI/Components/ChatTitleView",
"//submodules/Components/ComponentDisplayAdapters",
"//submodules/ComponentFlow",
"//submodules/ContextUI",
"//submodules/PeerInfoUI/CreateExternalMediaStreamScreen",
"//submodules/DeviceAccess",
"//submodules/Display",
"//submodules/TelegramUI/Components/EmojiStatusComponent",
"//submodules/TelegramUI/Components/EmojiStatusSelectionComponent",
"//submodules/EncryptionKeyVisualization",
"//submodules/TelegramUI/Components/EntityKeyboard",
"//submodules/TelegramUI/Components/ForumCreateTopicScreen",
"//submodules/GalleryData",
"//submodules/GalleryUI",
"//submodules/Geocoding",
"//submodules/HashtagSearchUI",
"//submodules/InstantPageCache",
"//submodules/InviteLinksUI",
"//submodules/ItemListAddressItem",
"//submodules/ItemListPeerActionItem",
"//submodules/ItemListPeerItem",
"//submodules/ItemListUI",
"//submodules/LegacyComponents",
"//submodules/LegacyMediaPickerUI",
"//submodules/LegacyUI",
"//submodules/ListMessageItem",
"//submodules/LocationResources",
"//submodules/LocationUI",
"//submodules/ManagedAnimationNode",
"//submodules/MapResourceToAvatarSizes",
"//submodules/Markdown",
"//submodules/MediaResources",
"//submodules/MergeLists",
"//submodules/TelegramUI/Components/MultiAnimationRenderer",
"//submodules/TelegramUI/Components/NotificationExceptionsScreen",
"//submodules/NotificationMuteSettingsUI",
"//submodules/TelegramUI/Components/NotificationPeerExceptionController",
"//submodules/NotificationSoundSelectionUI",
"//submodules/OpenInExternalAppUI",
"//submodules/OverlayStatusController",
"//submodules/PassportUI",
"//submodules/PasswordSetupUI",
"//submodules/PaymentMethodUI",
"//submodules/TelegramUI/Components/PeerAllowedReactionsScreen",
"//submodules/PeerAvatarGalleryUI",
"//submodules/PeerInfoAvatarListNode",
"//submodules/TelegramUI/Components/PeerInfo/PeerInfoStoryGridScreen",
"//submodules/PeerInfoUI",
"//submodules/TelegramUI/Components/PeerInfo/PeerInfoVisualMediaPaneNode",
"//submodules/TelegramUI/Components/Settings/PeerNameColorScreen",
"//submodules/PeerPresenceStatusManager",
"//submodules/TelegramUI/Components/PeerReportScreen",
"//submodules/PhoneNumberFormat",
"//submodules/PhotoResources",
"//submodules/Postbox",
"//submodules/PremiumUI",
"//submodules/PresentationDataUtils",
"//submodules/QrCodeUI",
"//submodules/RadialStatusNode",
"//submodules/SaveToCameraRoll",
"//submodules/SearchBarNode",
"//submodules/SearchUI",
"//submodules/TelegramUI/Components/SendInviteLinkScreen",
"//submodules/SettingsUI",
"//submodules/ShareController",
"//submodules/TelegramUI/Components/ShareWithPeersScreen",
"//submodules/StatisticsUI",
"//submodules/StickerPackPreviewUI",
"//submodules/StickerResources",
"//submodules/TelegramUI/Components/StorageUsageScreen",
"//submodules/TelegramUI/Components/Stories/StoryContainerScreen",
"//submodules/SSignalKit/SwiftSignalKit",
"//submodules/TelegramBaseController",
"//submodules/TelegramCallsUI",
"//submodules/TelegramCore",
"//submodules/TelegramIntents",
"//submodules/TelegramNotices",
"//submodules/TelegramPresentationData",
"//submodules/TelegramStringFormatting",
"//submodules/TelegramUIPreferences",
"//submodules/TelegramUniversalVideoContent",
"//submodules/TelegramVoip",
"//submodules/TemporaryCachedPeerDataManager",
"//submodules/TextFormat",
"//submodules/TooltipUI",
"//submodules/TranslateUI",
"//submodules/UndoUI",
"//submodules/MediaPlayer:UniversalMediaPlayer",
"//submodules/WebSearchUI",
"//submodules/WebUI",
"//submodules/TelegramUI/Components/MultiScaleTextNode",
"//submodules/GridMessageSelectionNode",
"//submodules/ChatMessageInteractiveMediaBadge",
"//submodules/SoftwareVideo",
"//submodules/TelegramUI/Components/Chat/ChatMessageSelectionInputPanelNode",
"//submodules/TelegramUI/Components/Chat/ChatHistorySearchContainerNode",
],
visibility = [
"//visibility:public",
],
)

View File

@ -78,7 +78,7 @@ final class PeerInfoListPaneNode: ASDisplayNode, PeerInfoPaneNode {
self.selectedMessages = chatControllerInteraction.selectionState.flatMap { $0.selectedIds } self.selectedMessages = chatControllerInteraction.selectionState.flatMap { $0.selectedIds }
self.selectedMessagesPromise.set(.single(self.selectedMessages)) self.selectedMessagesPromise.set(.single(self.selectedMessages))
self.listNode = ChatHistoryListNode(context: context, updatedPresentationData: updatedPresentationData ?? (context.sharedContext.currentPresentationData.with({ $0 }), context.sharedContext.presentationData), chatLocation: chatLocation, chatLocationContextHolder: chatLocationContextHolder, tagMask: tagMask, subject: nil, controllerInteraction: chatControllerInteraction, selectedMessages: self.selectedMessagesPromise.get(), mode: .list(search: false, reversed: false, reverseGroups: false, displayHeaders: .allButLast, hintLinks: tagMask == .webPage, isGlobalSearch: false)) self.listNode = context.sharedContext.makeChatHistoryListNode(context: context, updatedPresentationData: updatedPresentationData ?? (context.sharedContext.currentPresentationData.with({ $0 }), context.sharedContext.presentationData), chatLocation: chatLocation, chatLocationContextHolder: chatLocationContextHolder, tagMask: tagMask, source: .default, subject: nil, controllerInteraction: chatControllerInteraction, selectedMessages: self.selectedMessagesPromise.get(), mode: .list(search: false, reversed: false, reverseGroups: false, displayHeaders: .allButLast, hintLinks: tagMask == .webPage, isGlobalSearch: false))
self.listNode.clipsToBounds = true self.listNode.clipsToBounds = true
self.listNode.defaultToSynchronousTransactionWhileScrolling = true self.listNode.defaultToSynchronousTransactionWhileScrolling = true
self.listNode.scroller.bounces = false self.listNode.scroller.bounces = false

View File

@ -403,7 +403,7 @@ private func peerInfoScreenInputData(context: AccountContext, peerId: EnginePeer
} }
} }
func keepPeerInfoScreenDataHot(context: AccountContext, peerId: PeerId, chatLocation: ChatLocation, chatLocationContextHolder: Atomic<ChatLocationContextHolder?>) -> Signal<Never, NoError> { public func keepPeerInfoScreenDataHot(context: AccountContext, peerId: PeerId, chatLocation: ChatLocation, chatLocationContextHolder: Atomic<ChatLocationContextHolder?>) -> Signal<Never, NoError> {
return peerInfoScreenInputData(context: context, peerId: peerId, isSettings: false) return peerInfoScreenInputData(context: context, peerId: peerId, isSettings: false)
|> mapToSignal { inputData -> Signal<Never, NoError> in |> mapToSignal { inputData -> Signal<Never, NoError> in
switch inputData { switch inputData {

View File

@ -34,6 +34,7 @@ import PeerInfoVisualMediaPaneNode
import AvatarStoryIndicatorComponent import AvatarStoryIndicatorComponent
import ComponentDisplayAdapters import ComponentDisplayAdapters
import ChatAvatarNavigationNode import ChatAvatarNavigationNode
import MultiScaleTextNode
enum PeerInfoHeaderButtonKey: Hashable { enum PeerInfoHeaderButtonKey: Hashable {
case message case message

View File

@ -96,8 +96,10 @@ import ShareWithPeersScreen
import ItemListPeerItem import ItemListPeerItem
import PeerNameColorScreen import PeerNameColorScreen
import PeerAllowedReactionsScreen import PeerAllowedReactionsScreen
import ChatMessageSelectionInputPanelNode
import ChatHistorySearchContainerNode
enum PeerInfoAvatarEditingMode { public enum PeerInfoAvatarEditingMode {
case generic case generic
case accept case accept
case suggest case suggest
@ -2455,7 +2457,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, PeerInfoScreenNodePro
} }
let gesture: ContextGesture? = anyRecognizer as? ContextGesture let gesture: ContextGesture? = anyRecognizer as? ContextGesture
let _ = (chatAvailableMessageActionsImpl(engine: strongSelf.context.engine, accountPeerId: strongSelf.context.account.peerId, messageIds: [message.id]) let _ = (strongSelf.context.sharedContext.chatAvailableMessageActions(engine: strongSelf.context.engine, accountPeerId: strongSelf.context.account.peerId, messageIds: [message.id])
|> deliverOnMainQueue).startStandalone(next: { actions in |> deliverOnMainQueue).startStandalone(next: { actions in
guard let strongSelf = self else { guard let strongSelf = self else {
return return
@ -2621,7 +2623,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, PeerInfoScreenNodePro
if let previewData = previewData { if let previewData = previewData {
let context = strongSelf.context let context = strongSelf.context
let strings = strongSelf.presentationData.strings let strings = strongSelf.presentationData.strings
let items = chatAvailableMessageActionsImpl(engine: strongSelf.context.engine, accountPeerId: strongSelf.context.account.peerId, messageIds: [message.id]) let items = strongSelf.context.sharedContext.chatAvailableMessageActions(engine: strongSelf.context.engine, accountPeerId: strongSelf.context.account.peerId, messageIds: [message.id])
|> map { actions -> [ContextMenuItem] in |> map { actions -> [ContextMenuItem] in
var items: [ContextMenuItem] = [] var items: [ContextMenuItem] = []
@ -5895,17 +5897,17 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, PeerInfoScreenNodePro
private func openChatWithMessageSearch() { private func openChatWithMessageSearch() {
if let navigationController = (self.controller?.navigationController as? NavigationController) { if let navigationController = (self.controller?.navigationController as? NavigationController) {
if case let .replyThread(currentMessage) = self.chatLocation, let current = navigationController.viewControllers.first(where: { controller in if case let .replyThread(currentMessage) = self.chatLocation, let current = navigationController.viewControllers.first(where: { controller in
if let controller = controller as? ChatControllerImpl, case let .replyThread(message) = controller.chatLocation, message.messageId == currentMessage.messageId { if let controller = controller as? ChatController, case let .replyThread(message) = controller.chatLocation, message.messageId == currentMessage.messageId {
return true return true
} }
return false return false
}) as? ChatControllerImpl { }) as? ChatController {
var viewControllers = navigationController.viewControllers var viewControllers = navigationController.viewControllers
if let index = viewControllers.firstIndex(of: current) { if let index = viewControllers.firstIndex(of: current) {
viewControllers.removeSubrange(index + 1 ..< viewControllers.count) viewControllers.removeSubrange(index + 1 ..< viewControllers.count)
} }
navigationController.setViewControllers(viewControllers, animated: true) navigationController.setViewControllers(viewControllers, animated: true)
current.activateSearch() current.activateSearch(domain: .everything, query: "")
} else if let peer = self.data?.chatPeer { } else if let peer = self.data?.chatPeer {
self.context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: self.context, chatLocation: .peer(EnginePeer(peer)), keepStack: self.nearbyPeerDistance != nil ? .always : .default, activateMessageSearch: (.everything, ""), peerNearbyData: self.nearbyPeerDistance.flatMap({ ChatPeerNearbyData(distance: $0) }), completion: { [weak self] _ in self.context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: self.context, chatLocation: .peer(EnginePeer(peer)), keepStack: self.nearbyPeerDistance != nil ? .always : .default, activateMessageSearch: (.everything, ""), peerNearbyData: self.nearbyPeerDistance.flatMap({ ChatPeerNearbyData(distance: $0) }), completion: { [weak self] _ in
if let strongSelf = self, strongSelf.nearbyPeerDistance != nil { if let strongSelf = self, strongSelf.nearbyPeerDistance != nil {
@ -6615,7 +6617,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, PeerInfoScreenNodePro
} }
self.context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: self.context, chatLocation: .peer(EnginePeer(peer)), keepStack: self.nearbyPeerDistance != nil ? .always : .default, peerNearbyData: self.nearbyPeerDistance.flatMap({ ChatPeerNearbyData(distance: $0) }), setupController: { controller in self.context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: self.context, chatLocation: .peer(EnginePeer(peer)), keepStack: self.nearbyPeerDistance != nil ? .always : .default, peerNearbyData: self.nearbyPeerDistance.flatMap({ ChatPeerNearbyData(distance: $0) }), setupController: { controller in
(controller as? ChatControllerImpl)?.beginClearHistory(type: type) controller.beginClearHistory(type: type)
}, completion: { [weak self] _ in }, completion: { [weak self] _ in
if let strongSelf = self, strongSelf.nearbyPeerDistance != nil { if let strongSelf = self, strongSelf.nearbyPeerDistance != nil {
var viewControllers = navigationController.viewControllers var viewControllers = navigationController.viewControllers
@ -8358,7 +8360,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, PeerInfoScreenNodePro
if self.isSettings && self.data?.globalSettings?.privacySettings?.phoneDiscoveryEnabled == false && (self.data?.peer?.addressName ?? "").isEmpty { if self.isSettings && self.data?.globalSettings?.privacySettings?.phoneDiscoveryEnabled == false && (self.data?.peer?.addressName ?? "").isEmpty {
temporary = true temporary = true
} }
controller.present(ChatQrCodeScreen(context: self.context, subject: .peer(peer: peer, threadId: threadId, temporary: temporary)), in: .window(.root)) controller.present(self.context.sharedContext.makeChatQrCodeScreen(context: self.context, peer: peer, threadId: threadId, temporary: temporary), in: .window(.root))
} }
private func openPostStory() { private func openPostStory() {
@ -9054,7 +9056,8 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, PeerInfoScreenNodePro
proceed(chatController) proceed(chatController)
}) })
} else { } else {
proceed(ChatControllerImpl(context: strongSelf.context, chatLocation: .peer(id: peerId))) let chatController = strongSelf.context.sharedContext.makeChatController(context: strongSelf.context, chatLocation: .peer(id: peerId), subject: .none, botStart: nil, mode: .standard(previewing: false))
proceed(chatController)
} }
} }
}) })
@ -10211,7 +10214,7 @@ public final class PeerInfoScreenImpl: ViewController, PeerInfoScreen, KeyShortc
private let chatLocation: ChatLocation private let chatLocation: ChatLocation
private let chatLocationContextHolder = Atomic<ChatLocationContextHolder?>(value: nil) private let chatLocationContextHolder = Atomic<ChatLocationContextHolder?>(value: nil)
weak var parentController: TelegramRootController? public weak var parentController: TelegramRootControllerInterface?
fileprivate var presentationData: PresentationData fileprivate var presentationData: PresentationData
private var presentationDataDisposable: Disposable? private var presentationDataDisposable: Disposable?
@ -10639,21 +10642,21 @@ public final class PeerInfoScreenImpl: ViewController, PeerInfoScreen, KeyShortc
} }
} }
func updateProfilePhoto(_ image: UIImage, mode: PeerInfoAvatarEditingMode) { public func updateProfilePhoto(_ image: UIImage, mode: PeerInfoAvatarEditingMode) {
if !self.isNodeLoaded { if !self.isNodeLoaded {
self.loadDisplayNode() self.loadDisplayNode()
} }
self.controllerNode.updateProfilePhoto(image, mode: mode) self.controllerNode.updateProfilePhoto(image, mode: mode)
} }
func updateProfileVideo(_ image: UIImage, mode: PeerInfoAvatarEditingMode, asset: Any?, adjustments: TGVideoEditAdjustments?, fallback: Bool = false) { public func updateProfileVideo(_ image: UIImage, mode: PeerInfoAvatarEditingMode, asset: Any?, adjustments: TGVideoEditAdjustments?, fallback: Bool = false) {
if !self.isNodeLoaded { if !self.isNodeLoaded {
self.loadDisplayNode() self.loadDisplayNode()
} }
self.controllerNode.updateProfileVideo(image, asset: asset, adjustments: adjustments, mode: mode) self.controllerNode.updateProfileVideo(image, asset: asset, adjustments: adjustments, mode: mode)
} }
static func displayChatNavigationMenu(context: AccountContext, chatNavigationStack: [ChatNavigationStackItem], nextFolderId: Int32?, parentController: ViewController, backButtonView: UIView, navigationController: NavigationController, gesture: ContextGesture) { public static func displayChatNavigationMenu(context: AccountContext, chatNavigationStack: [ChatNavigationStackItem], nextFolderId: Int32?, parentController: ViewController, backButtonView: UIView, navigationController: NavigationController, gesture: ContextGesture) {
let peerMap = EngineDataMap( let peerMap = EngineDataMap(
Set(chatNavigationStack.map(\.peerId)).map(TelegramEngine.EngineData.Item.Peer.Peer.init) Set(chatNavigationStack.map(\.peerId)).map(TelegramEngine.EngineData.Item.Peer.Peer.init)
) )
@ -10741,7 +10744,7 @@ public final class PeerInfoScreenImpl: ViewController, PeerInfoScreen, KeyShortc
})) }))
}))) })))
} }
let contextController = ContextController(presentationData: presentationData, source: .reference(ChatControllerContextReferenceContentSource(controller: parentController, sourceView: backButtonView, insets: UIEdgeInsets(), contentInsets: UIEdgeInsets(top: 0.0, left: -15.0, bottom: 0.0, right: -15.0))), items: .single(ContextController.Items(content: .list(items))), gesture: gesture) let contextController = ContextController(presentationData: presentationData, source: .reference(PeerInfoControllerContextReferenceContentSource(controller: parentController, sourceView: backButtonView, insets: UIEdgeInsets(), contentInsets: UIEdgeInsets(top: 0.0, left: -15.0, bottom: 0.0, right: -15.0))), items: .single(ContextController.Items(content: .list(items))), gesture: gesture)
parentController.presentInGlobalOverlay(contextController) parentController.presentInGlobalOverlay(contextController)
}) })
} }
@ -11335,7 +11338,7 @@ private final class PeerInfoContextReferenceContentSource: ContextReferenceConte
} }
} }
func presentAddMembersImpl(context: AccountContext, updatedPresentationData: (initial: PresentationData, signal: Signal<PresentationData, NoError>)?, parentController: ViewController, groupPeer: Peer, selectAddMemberDisposable: MetaDisposable, addMemberDisposable: MetaDisposable) { public func presentAddMembersImpl(context: AccountContext, updatedPresentationData: (initial: PresentationData, signal: Signal<PresentationData, NoError>)?, parentController: ViewController, groupPeer: Peer, selectAddMemberDisposable: MetaDisposable, addMemberDisposable: MetaDisposable) {
let members: Promise<[PeerId]> = Promise() let members: Promise<[PeerId]> = Promise()
if groupPeer.id.namespace == Namespaces.Peer.CloudChannel { if groupPeer.id.namespace == Namespaces.Peer.CloudChannel {
/*var membersDisposable: Disposable? /*var membersDisposable: Disposable?
@ -12012,3 +12015,21 @@ private final class AccountPeerContextItemNode: ASDisplayNode, ContextMenuCustom
}) })
} }
} }
private final class PeerInfoControllerContextReferenceContentSource: ContextReferenceContentSource {
let controller: ViewController
let sourceView: UIView
let insets: UIEdgeInsets
let contentInsets: UIEdgeInsets
init(controller: ViewController, sourceView: UIView, insets: UIEdgeInsets, contentInsets: UIEdgeInsets = UIEdgeInsets()) {
self.controller = controller
self.sourceView = sourceView
self.insets = insets
self.contentInsets = contentInsets
}
func transitionInfo() -> ContextControllerReferenceViewInfo? {
return ContextControllerReferenceViewInfo(referenceView: self.sourceView, contentAreaInScreenSpace: UIScreen.main.bounds.inset(by: self.insets), insets: self.contentInsets)
}
}

View File

@ -115,6 +115,8 @@ import ChatMessageAnimatedStickerItemNode
import ChatMessageBubbleItemNode import ChatMessageBubbleItemNode
import ChatNavigationButton import ChatNavigationButton
import WebsiteType import WebsiteType
import ChatQrCodeScreen
import PeerInfoScreen
public enum ChatControllerPeekActions { public enum ChatControllerPeekActions {
case standard case standard
@ -11814,7 +11816,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
self.moreBarButton.contextAction?(self.moreBarButton.containerNode, nil) self.moreBarButton.contextAction?(self.moreBarButton.containerNode, nil)
} }
func beginClearHistory(type: InteractiveHistoryClearingType) { public func beginClearHistory(type: InteractiveHistoryClearingType) {
guard case let .peer(peerId) = self.chatLocation else { guard case let .peer(peerId) = self.chatLocation else {
return return
} }
@ -18404,7 +18406,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
} }
} }
func activateSearch(domain: ChatSearchDomain = .everything, query: String = "") { public func activateSearch(domain: ChatSearchDomain = .everything, query: String = "") {
self.focusOnSearchAfterAppearance = (domain, query) self.focusOnSearchAfterAppearance = (domain, query)
self.interfaceInteraction?.beginMessageSearch(domain, query) self.interfaceInteraction?.beginMessageSearch(domain, query)
} }
@ -18673,38 +18675,3 @@ func peerMessageSelectedReactions(context: AccountContext, message: Message) ->
return (reactions, result) return (reactions, result)
} }
} }
final class ChatControllerNavigationData: CustomViewControllerNavigationData {
let peerId: PeerId
let threadId: Int64?
init(peerId: PeerId, threadId: Int64?) {
self.peerId = peerId
self.threadId = threadId
}
func combine(summary: CustomViewControllerNavigationDataSummary?) -> CustomViewControllerNavigationDataSummary? {
if let summary = summary as? ChatControllerNavigationDataSummary {
return summary.adding(peerNavigationItem: ChatNavigationStackItem(peerId: self.peerId, threadId: threadId))
} else {
return ChatControllerNavigationDataSummary(peerNavigationItems: [ChatNavigationStackItem(peerId: self.peerId, threadId: threadId)])
}
}
}
final class ChatControllerNavigationDataSummary: CustomViewControllerNavigationDataSummary {
let peerNavigationItems: [ChatNavigationStackItem]
init(peerNavigationItems: [ChatNavigationStackItem]) {
self.peerNavigationItems = peerNavigationItems
}
func adding(peerNavigationItem: ChatNavigationStackItem) -> ChatControllerNavigationDataSummary {
var peerNavigationItems = self.peerNavigationItems
if let index = peerNavigationItems.firstIndex(of: peerNavigationItem) {
peerNavigationItems.removeSubrange(0 ... index)
}
peerNavigationItems.insert(peerNavigationItem, at: 0)
return ChatControllerNavigationDataSummary(peerNavigationItems: peerNavigationItems)
}
}

View File

@ -154,7 +154,7 @@ class ChatControllerNode: ASDisplayNode, UIScrollViewDelegate {
let contentContainerNode: ASDisplayNode let contentContainerNode: ASDisplayNode
let contentDimNode: ASDisplayNode let contentDimNode: ASDisplayNode
let backgroundNode: WallpaperBackgroundNode let backgroundNode: WallpaperBackgroundNode
let historyNode: ChatHistoryListNode let historyNode: ChatHistoryListNodeImpl
var blurredHistoryNode: ASImageNode? var blurredHistoryNode: ASImageNode?
let historyNodeContainer: ASDisplayNode let historyNodeContainer: ASDisplayNode
let loadingNode: ChatLoadingNode let loadingNode: ChatLoadingNode
@ -604,7 +604,7 @@ class ChatControllerNode: ASDisplayNode, UIScrollViewDelegate {
} }
var getMessageTransitionNode: (() -> ChatMessageTransitionNodeImpl?)? var getMessageTransitionNode: (() -> ChatMessageTransitionNodeImpl?)?
self.historyNode = ChatHistoryListNode(context: context, updatedPresentationData: controller?.updatedPresentationData ?? (context.sharedContext.currentPresentationData.with({ $0 }), context.sharedContext.presentationData), chatLocation: chatLocation, chatLocationContextHolder: chatLocationContextHolder, tagMask: nil, source: source, subject: subject, controllerInteraction: controllerInteraction, selectedMessages: self.selectedMessagesPromise.get(), messageTransitionNode: { self.historyNode = ChatHistoryListNodeImpl(context: context, updatedPresentationData: controller?.updatedPresentationData ?? (context.sharedContext.currentPresentationData.with({ $0 }), context.sharedContext.presentationData), chatLocation: chatLocation, chatLocationContextHolder: chatLocationContextHolder, tagMask: nil, source: source, subject: subject, controllerInteraction: controllerInteraction, selectedMessages: self.selectedMessagesPromise.get(), messageTransitionNode: {
return getMessageTransitionNode?() return getMessageTransitionNode?()
}) })
self.historyNode.rotated = true self.historyNode.rotated = true
@ -3725,7 +3725,7 @@ class ChatControllerNode: ASDisplayNode, UIScrollViewDelegate {
final class SnapshotState { final class SnapshotState {
let backgroundNode: WallpaperBackgroundNode let backgroundNode: WallpaperBackgroundNode
fileprivate let historySnapshotState: ChatHistoryListNode.SnapshotState fileprivate let historySnapshotState: ChatHistoryListNodeImpl.SnapshotState
let titleViewSnapshotState: ChatTitleView.SnapshotState? let titleViewSnapshotState: ChatTitleView.SnapshotState?
let avatarSnapshotState: ChatAvatarNavigationNode.SnapshotState? let avatarSnapshotState: ChatAvatarNavigationNode.SnapshotState?
let navigationButtonsSnapshotState: ChatHistoryNavigationButtons.SnapshotState let navigationButtonsSnapshotState: ChatHistoryNavigationButtons.SnapshotState
@ -3736,7 +3736,7 @@ class ChatControllerNode: ASDisplayNode, UIScrollViewDelegate {
fileprivate init( fileprivate init(
backgroundNode: WallpaperBackgroundNode, backgroundNode: WallpaperBackgroundNode,
historySnapshotState: ChatHistoryListNode.SnapshotState, historySnapshotState: ChatHistoryListNodeImpl.SnapshotState,
titleViewSnapshotState: ChatTitleView.SnapshotState?, titleViewSnapshotState: ChatTitleView.SnapshotState?,
avatarSnapshotState: ChatAvatarNavigationNode.SnapshotState?, avatarSnapshotState: ChatAvatarNavigationNode.SnapshotState?,
navigationButtonsSnapshotState: ChatHistoryNavigationButtons.SnapshotState, navigationButtonsSnapshotState: ChatHistoryNavigationButtons.SnapshotState,

View File

@ -399,7 +399,7 @@ func chatHistoryEntriesForView(
if !entries.isEmpty, case let .MessageEntry(lastMessage, _, _, _, _, _) = entries[entries.count - 1], let message = adMessage { if !entries.isEmpty, case let .MessageEntry(lastMessage, _, _, _, _, _) = entries[entries.count - 1], let message = adMessage {
var nextAdMessageId: Int32 = 10000 var nextAdMessageId: Int32 = 10000
let updatedMessage = Message( let updatedMessage = Message(
stableId: ChatHistoryListNode.fixedAdMessageStableId, stableId: ChatHistoryListNodeImpl.fixedAdMessageStableId,
stableVersion: message.stableVersion, stableVersion: message.stableVersion,
id: MessageId(peerId: message.id.peerId, namespace: message.id.namespace, id: nextAdMessageId), id: MessageId(peerId: message.id.peerId, namespace: message.id.namespace, id: nextAdMessageId),
globallyUniqueId: nil, globallyUniqueId: nil,

View File

@ -42,17 +42,6 @@ struct ChatTopVisibleMessageRange: Equatable {
private let historyMessageCount: Int = 44 private let historyMessageCount: Int = 44
public enum ChatHistoryListDisplayHeaders {
case none
case all
case allButLast
}
public enum ChatHistoryListMode: Equatable {
case bubbles
case list(search: Bool, reversed: Bool, reverseGroups: Bool, displayHeaders: ChatHistoryListDisplayHeaders, hintLinks: Bool, isGlobalSearch: Bool)
}
enum ChatHistoryViewScrollPosition { enum ChatHistoryViewScrollPosition {
case unread(index: MessageIndex) case unread(index: MessageIndex)
case positionRestoration(index: MessageIndex, relativeOffset: CGFloat) case positionRestoration(index: MessageIndex, relativeOffset: CGFloat)
@ -436,22 +425,7 @@ private struct ChatHistoryAnimatedEmojiConfiguration {
private var nextClientId: Int32 = 1 private var nextClientId: Int32 = 1
public enum ChatHistoryListSource { public final class ChatHistoryListNodeImpl: ListView, ChatHistoryNode, ChatHistoryListNode {
public struct Quote {
public var text: String
public var offset: Int?
public init(text: String, offset: Int?) {
self.text = text
self.offset = offset
}
}
case `default`
case custom(messages: Signal<([Message], Int32, Bool), NoError>, messageId: MessageId, quote: Quote?, loadMore: (() -> Void)?)
}
public final class ChatHistoryListNode: ListView, ChatHistoryNode {
static let fixedAdMessageStableId: UInt32 = UInt32.max - 5000 static let fixedAdMessageStableId: UInt32 = UInt32.max - 5000
private let context: AccountContext private let context: AccountContext
@ -702,7 +676,7 @@ public final class ChatHistoryListNode: ListView, ChatHistoryNode {
private var dustEffectLayer: DustEffectLayer? private var dustEffectLayer: DustEffectLayer?
public init(context: AccountContext, updatedPresentationData: (initial: PresentationData, signal: Signal<PresentationData, NoError>), chatLocation: ChatLocation, chatLocationContextHolder: Atomic<ChatLocationContextHolder?>, tagMask: MessageTags?, source: ChatHistoryListSource = .default, subject: ChatControllerSubject?, controllerInteraction: ChatControllerInteraction, selectedMessages: Signal<Set<MessageId>?, NoError>, mode: ChatHistoryListMode = .bubbles, messageTransitionNode: @escaping () -> ChatMessageTransitionNodeImpl? = { nil }) { public init(context: AccountContext, updatedPresentationData: (initial: PresentationData, signal: Signal<PresentationData, NoError>), chatLocation: ChatLocation, chatLocationContextHolder: Atomic<ChatLocationContextHolder?>, tagMask: MessageTags?, source: ChatHistoryListSource, subject: ChatControllerSubject?, controllerInteraction: ChatControllerInteraction, selectedMessages: Signal<Set<MessageId>?, NoError>, mode: ChatHistoryListMode = .bubbles, messageTransitionNode: @escaping () -> ChatMessageTransitionNodeImpl?) {
var tagMask = tagMask var tagMask = tagMask
if case .pinnedMessages = subject { if case .pinnedMessages = subject {
tagMask = .pinned tagMask = .pinned
@ -2184,7 +2158,7 @@ public final class ChatHistoryListNode: ListView, ChatHistoryNode {
} else if let attribute = attribute as? ReactionsMessageAttribute, attribute.hasUnseen { } else if let attribute = attribute as? ReactionsMessageAttribute, attribute.hasUnseen {
hasUnseenReactions = true hasUnseenReactions = true
} else if let attribute = attribute as? AdMessageAttribute { } else if let attribute = attribute as? AdMessageAttribute {
if message.stableId != ChatHistoryListNode.fixedAdMessageStableId { if message.stableId != ChatHistoryListNodeImpl.fixedAdMessageStableId {
visibleAdOpaqueIds.append(attribute.opaqueId) visibleAdOpaqueIds.append(attribute.opaqueId)
} }
} else if let _ = attribute as? ReplyStoryAttribute { } else if let _ = attribute as? ReplyStoryAttribute {

View File

@ -5,6 +5,7 @@ import Postbox
import SwiftSignalKit import SwiftSignalKit
import Display import Display
import ChatPresentationInterfaceState import ChatPresentationInterfaceState
import AccountContext
public enum ChatHistoryNodeLoadState: Equatable { public enum ChatHistoryNodeLoadState: Equatable {
public enum EmptyType: Equatable { public enum EmptyType: Equatable {

View File

@ -7,6 +7,7 @@ import ChatPresentationInterfaceState
import ChatInputPanelNode import ChatInputPanelNode
import ChatBotStartInputPanelNode import ChatBotStartInputPanelNode
import ChatChannelSubscriberInputPanelNode import ChatChannelSubscriberInputPanelNode
import ChatMessageSelectionInputPanelNode
func inputPanelForChatPresentationIntefaceState(_ chatPresentationInterfaceState: ChatPresentationInterfaceState, context: AccountContext, currentPanel: ChatInputPanelNode?, currentSecondaryPanel: ChatInputPanelNode?, textInputPanelNode: ChatTextInputPanelNode?, interfaceInteraction: ChatPanelInterfaceInteraction?) -> (primary: ChatInputPanelNode?, secondary: ChatInputPanelNode?) { func inputPanelForChatPresentationIntefaceState(_ chatPresentationInterfaceState: ChatPresentationInterfaceState, context: AccountContext, currentPanel: ChatInputPanelNode?, currentSecondaryPanel: ChatInputPanelNode?, textInputPanelNode: ChatTextInputPanelNode?, interfaceInteraction: ChatPanelInterfaceInteraction?) -> (primary: ChatInputPanelNode?, secondary: ChatInputPanelNode?) {
if let renderedPeer = chatPresentationInterfaceState.renderedPeer, renderedPeer.peer?.restrictionText(platform: "ios", contentSettings: context.currentContentSettings.with { $0 }) != nil { if let renderedPeer = chatPresentationInterfaceState.renderedPeer, renderedPeer.peer?.restrictionText(platform: "ios", contentSettings: context.currentContentSettings.with { $0 }) != nil {

View File

@ -889,7 +889,7 @@ public final class ChatMessageTransitionNodeImpl: ASDisplayNode, ChatMessageTran
} }
} }
private let listNode: ChatHistoryListNode private let listNode: ChatHistoryListNodeImpl
private let getContentAreaInScreenSpace: () -> CGRect private let getContentAreaInScreenSpace: () -> CGRect
private let onTransitionEvent: (ContainedViewLayoutTransition) -> Void private let onTransitionEvent: (ContainedViewLayoutTransition) -> Void
@ -907,7 +907,7 @@ public final class ChatMessageTransitionNodeImpl: ASDisplayNode, ChatMessageTran
return !self.animatingItemNodes.isEmpty return !self.animatingItemNodes.isEmpty
} }
init(listNode: ChatHistoryListNode, getContentAreaInScreenSpace: @escaping () -> CGRect, onTransitionEvent: @escaping (ContainedViewLayoutTransition) -> Void) { init(listNode: ChatHistoryListNodeImpl, getContentAreaInScreenSpace: @escaping () -> CGRect, onTransitionEvent: @escaping (ContainedViewLayoutTransition) -> Void) {
self.listNode = listNode self.listNode = listNode
self.getContentAreaInScreenSpace = getContentAreaInScreenSpace self.getContentAreaInScreenSpace = getContentAreaInScreenSpace
self.onTransitionEvent = onTransitionEvent self.onTransitionEvent = onTransitionEvent

View File

@ -36,8 +36,8 @@ final class OverlayAudioPlayerControllerNode: ViewControllerTracingNode, UIGestu
private let historyBackgroundNode: ASDisplayNode private let historyBackgroundNode: ASDisplayNode
private let historyBackgroundContentNode: ASDisplayNode private let historyBackgroundContentNode: ASDisplayNode
private var floatingHeaderOffset: CGFloat? private var floatingHeaderOffset: CGFloat?
private var historyNode: ChatHistoryListNode private var historyNode: ChatHistoryListNodeImpl
private var replacementHistoryNode: ChatHistoryListNode? private var replacementHistoryNode: ChatHistoryListNodeImpl?
private var replacementHistoryNodeFloatingOffset: CGFloat? private var replacementHistoryNodeFloatingOffset: CGFloat?
private var validLayout: ContainerViewLayout? private var validLayout: ContainerViewLayout?
@ -216,7 +216,7 @@ final class OverlayAudioPlayerControllerNode: ViewControllerTracingNode, UIGestu
self.isGlobalSearch = false self.isGlobalSearch = false
} }
self.historyNode = ChatHistoryListNode(context: context, updatedPresentationData: (context.sharedContext.currentPresentationData.with({ $0 }), context.sharedContext.presentationData), chatLocation: chatLocation, chatLocationContextHolder: chatLocationContextHolder, tagMask: tagMask, source: source, subject: .message(id: .id(initialMessageId), highlight: ChatControllerSubject.MessageHighlight(quote: nil), timecode: nil), controllerInteraction: self.controllerInteraction, selectedMessages: .single(nil), mode: .list(search: false, reversed: self.currentIsReversed, reverseGroups: !self.currentIsReversed, displayHeaders: .none, hintLinks: false, isGlobalSearch: self.isGlobalSearch)) self.historyNode = ChatHistoryListNodeImpl(context: context, updatedPresentationData: (context.sharedContext.currentPresentationData.with({ $0 }), context.sharedContext.presentationData), chatLocation: chatLocation, chatLocationContextHolder: chatLocationContextHolder, tagMask: tagMask, source: source, subject: .message(id: .id(initialMessageId), highlight: ChatControllerSubject.MessageHighlight(quote: nil), timecode: nil), controllerInteraction: self.controllerInteraction, selectedMessages: .single(nil), mode: .list(search: false, reversed: self.currentIsReversed, reverseGroups: !self.currentIsReversed, displayHeaders: .none, hintLinks: false, isGlobalSearch: self.isGlobalSearch), messageTransitionNode: { return nil })
self.historyNode.clipsToBounds = true self.historyNode.clipsToBounds = true
super.init() super.init()
@ -558,7 +558,7 @@ final class OverlayAudioPlayerControllerNode: ViewControllerTracingNode, UIGestu
} }
let chatLocationContextHolder = Atomic<ChatLocationContextHolder?>(value: nil) let chatLocationContextHolder = Atomic<ChatLocationContextHolder?>(value: nil)
let historyNode = ChatHistoryListNode(context: self.context, updatedPresentationData: (self.context.sharedContext.currentPresentationData.with({ $0 }), self.context.sharedContext.presentationData), chatLocation: self.chatLocation, chatLocationContextHolder: chatLocationContextHolder, tagMask: tagMask, subject: .message(id: .id(messageId), highlight: ChatControllerSubject.MessageHighlight(quote: nil), timecode: nil), controllerInteraction: self.controllerInteraction, selectedMessages: .single(nil), mode: .list(search: false, reversed: self.currentIsReversed, reverseGroups: !self.currentIsReversed, displayHeaders: .none, hintLinks: false, isGlobalSearch: self.isGlobalSearch)) let historyNode = ChatHistoryListNodeImpl(context: self.context, updatedPresentationData: (self.context.sharedContext.currentPresentationData.with({ $0 }), self.context.sharedContext.presentationData), chatLocation: self.chatLocation, chatLocationContextHolder: chatLocationContextHolder, tagMask: tagMask, source: .default, subject: .message(id: .id(messageId), highlight: ChatControllerSubject.MessageHighlight(quote: nil), timecode: nil), controllerInteraction: self.controllerInteraction, selectedMessages: .single(nil), mode: .list(search: false, reversed: self.currentIsReversed, reverseGroups: !self.currentIsReversed, displayHeaders: .none, hintLinks: false, isGlobalSearch: self.isGlobalSearch), messageTransitionNode: { return nil })
historyNode.clipsToBounds = true historyNode.clipsToBounds = true
historyNode.preloadPages = true historyNode.preloadPages = true
historyNode.stackFromBottom = true historyNode.stackFromBottom = true

View File

@ -47,6 +47,8 @@ import ChatHistoryEntry
import ChatMessageItem import ChatMessageItem
import ChatMessageItemImpl import ChatMessageItemImpl
import ChatRecentActionsController import ChatRecentActionsController
import PeerInfoScreen
import ChatQrCodeScreen
private final class AccountUserInterfaceInUseContext { private final class AccountUserInterfaceInUseContext {
let subscribers = Bag<(Bool) -> Void>() let subscribers = Bag<(Bool) -> Void>()
@ -1432,6 +1434,33 @@ public final class SharedAccountContextImpl: SharedAccountContext {
return ChatControllerImpl(context: context, chatLocation: chatLocation, subject: subject, botStart: botStart, mode: mode) return ChatControllerImpl(context: context, chatLocation: chatLocation, subject: subject, botStart: botStart, mode: mode)
} }
public func makeChatHistoryListNode(
context: AccountContext,
updatedPresentationData: (initial: PresentationData, signal: Signal<PresentationData, NoError>),
chatLocation: ChatLocation,
chatLocationContextHolder: Atomic<ChatLocationContextHolder?>,
tagMask: MessageTags?,
source: ChatHistoryListSource,
subject: ChatControllerSubject?,
controllerInteraction: ChatControllerInteractionProtocol,
selectedMessages: Signal<Set<MessageId>?, NoError>,
mode: ChatHistoryListMode
) -> ChatHistoryListNode {
return ChatHistoryListNodeImpl(
context: context,
updatedPresentationData: updatedPresentationData,
chatLocation: chatLocation,
chatLocationContextHolder: chatLocationContextHolder,
tagMask: tagMask,
source: source,
subject: subject,
controllerInteraction: controllerInteraction as! ChatControllerInteraction,
selectedMessages: selectedMessages,
mode: mode,
messageTransitionNode: { return nil }
)
}
public func makePeerSharedMediaController(context: AccountContext, peerId: PeerId) -> ViewController? { public func makePeerSharedMediaController(context: AccountContext, peerId: PeerId) -> ViewController? {
return nil return nil
} }
@ -1633,8 +1662,8 @@ public final class SharedAccountContextImpl: SharedAccountContext {
return recentSessionsController(context: context, activeSessionsContext: activeSessionsContext, webSessionsContext: context.engine.privacy.webSessions(), websitesOnly: false) return recentSessionsController(context: context, activeSessionsContext: activeSessionsContext, webSessionsContext: context.engine.privacy.webSessions(), websitesOnly: false)
} }
public func makeChatQrCodeScreen(context: AccountContext, peer: Peer, threadId: Int64?) -> ViewController { public func makeChatQrCodeScreen(context: AccountContext, peer: Peer, threadId: Int64?, temporary: Bool) -> ViewController {
return ChatQrCodeScreen(context: context, subject: .peer(peer: peer, threadId: threadId, temporary: false)) return ChatQrCodeScreen(context: context, subject: .peer(peer: peer, threadId: threadId, temporary: temporary))
} }
public func makePrivacyAndSecurityController(context: AccountContext) -> ViewController { public func makePrivacyAndSecurityController(context: AccountContext) -> ViewController {

View File

@ -27,6 +27,7 @@ import LocalMediaResources
import ImageCompression import ImageCompression
import TextFormat import TextFormat
import MediaEditor import MediaEditor
import PeerInfoScreen
private class DetailsChatPlaceholderNode: ASDisplayNode, NavigationDetailsPlaceholderNode { private class DetailsChatPlaceholderNode: ASDisplayNode, NavigationDetailsPlaceholderNode {
private var presentationData: PresentationData private var presentationData: PresentationData