Swiftgram/submodules/TelegramUI/Sources/TelegramRootController.swift
2023-03-07 19:05:33 +04:00

251 lines
13 KiB
Swift

import Foundation
import UIKit
import Display
import AsyncDisplayKit
import Postbox
import TelegramCore
import SwiftSignalKit
import TelegramPresentationData
import AccountContext
import ContactListUI
import CallListUI
import ChatListUI
import SettingsUI
import AppBundle
import DatePickerNode
import DebugSettingsUI
import TabBarUI
import WallpaperBackgroundNode
import ChatPresentationInterfaceState
private class DetailsChatPlaceholderNode: ASDisplayNode, NavigationDetailsPlaceholderNode {
private var presentationData: PresentationData
private var presentationInterfaceState: ChatPresentationInterfaceState
let wallpaperBackgroundNode: WallpaperBackgroundNode
let emptyNode: ChatEmptyNode
init(context: AccountContext) {
self.presentationData = context.sharedContext.currentPresentationData.with { $0 }
self.presentationInterfaceState = ChatPresentationInterfaceState(chatWallpaper: self.presentationData.chatWallpaper, theme: self.presentationData.theme, strings: self.presentationData.strings, dateTimeFormat: self.presentationData.dateTimeFormat, nameDisplayOrder: self.presentationData.nameDisplayOrder, limitsConfiguration: context.currentLimitsConfiguration.with { $0 }, fontSize: self.presentationData.chatFontSize, bubbleCorners: self.presentationData.chatBubbleCorners, accountPeerId: context.account.peerId, mode: .standard(previewing: false), chatLocation: .peer(id: context.account.peerId), subject: nil, peerNearbyData: nil, greetingData: nil, pendingUnpinnedAllMessages: false, activeGroupCallInfo: nil, hasActiveGroupCall: false, importState: nil, threadData: nil, isGeneralThreadClosed: nil)
self.wallpaperBackgroundNode = createWallpaperBackgroundNode(context: context, forChatDisplay: true, useSharedAnimationPhase: true)
self.emptyNode = ChatEmptyNode(context: context, interaction: nil)
super.init()
self.addSubnode(self.wallpaperBackgroundNode)
self.addSubnode(self.emptyNode)
}
func updatePresentationData(_ presentationData: PresentationData) {
self.presentationData = presentationData
self.presentationInterfaceState = ChatPresentationInterfaceState(chatWallpaper: self.presentationData.chatWallpaper, theme: self.presentationData.theme, strings: self.presentationData.strings, dateTimeFormat: self.presentationData.dateTimeFormat, nameDisplayOrder: self.presentationData.nameDisplayOrder, limitsConfiguration: self.presentationInterfaceState.limitsConfiguration, fontSize: self.presentationData.chatFontSize, bubbleCorners: self.presentationData.chatBubbleCorners, accountPeerId: self.presentationInterfaceState.accountPeerId, mode: .standard(previewing: false), chatLocation: self.presentationInterfaceState.chatLocation, subject: nil, peerNearbyData: nil, greetingData: nil, pendingUnpinnedAllMessages: false, activeGroupCallInfo: nil, hasActiveGroupCall: false, importState: nil, threadData: nil, isGeneralThreadClosed: nil)
self.wallpaperBackgroundNode.update(wallpaper: presentationData.chatWallpaper)
}
func updateLayout(size: CGSize, needsTiling: Bool, transition: ContainedViewLayoutTransition) {
let contentBounds = CGRect(origin: .zero, size: size)
self.wallpaperBackgroundNode.updateLayout(size: size, displayMode: needsTiling ? .aspectFit : .aspectFill, transition: transition)
transition.updateFrame(node: self.wallpaperBackgroundNode, frame: contentBounds)
self.emptyNode.updateLayout(interfaceState: self.presentationInterfaceState, subject: .detailsPlaceholder, loadingNode: nil, backgroundNode: self.wallpaperBackgroundNode, size: contentBounds.size, insets: .zero, transition: transition)
transition.updateFrame(node: self.emptyNode, frame: CGRect(origin: .zero, size: size))
self.emptyNode.update(rect: contentBounds, within: contentBounds.size, transition: transition)
}
}
public final class TelegramRootController: NavigationController {
private let context: AccountContext
public var rootTabController: TabBarController?
public var contactsController: ContactsController?
public var callListController: CallListController?
public var chatListController: ChatListController?
public var accountSettingsController: PeerInfoScreen?
private var permissionsDisposable: Disposable?
private var presentationDataDisposable: Disposable?
private var presentationData: PresentationData
private var detailsPlaceholderNode: DetailsChatPlaceholderNode?
private var applicationInFocusDisposable: Disposable?
public init(context: AccountContext) {
self.context = context
self.presentationData = context.sharedContext.currentPresentationData.with { $0 }
super.init(mode: .automaticMasterDetail, theme: NavigationControllerTheme(presentationTheme: self.presentationData.theme))
self.presentationDataDisposable = (context.sharedContext.presentationData
|> deliverOnMainQueue).start(next: { [weak self] presentationData in
if let strongSelf = self {
strongSelf.detailsPlaceholderNode?.updatePresentationData(presentationData)
let previousTheme = strongSelf.presentationData.theme
strongSelf.presentationData = presentationData
if previousTheme !== presentationData.theme {
(strongSelf.rootTabController as? TabBarControllerImpl)?.updateTheme(navigationBarPresentationData: NavigationBarPresentationData(presentationData: presentationData), theme: TabBarControllerTheme(rootControllerTheme: presentationData.theme))
strongSelf.rootTabController?.statusBar.statusBarStyle = presentationData.theme.rootController.statusBarStyle.style
}
}
})
if context.sharedContext.applicationBindings.isMainApp {
self.applicationInFocusDisposable = (context.sharedContext.applicationBindings.applicationIsActive
|> distinctUntilChanged
|> deliverOn(Queue.mainQueue())).start(next: { value in
context.sharedContext.mainWindow?.setForceBadgeHidden(!value)
})
}
}
required public init(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
deinit {
self.permissionsDisposable?.dispose()
self.presentationDataDisposable?.dispose()
self.applicationInFocusDisposable?.dispose()
}
override public func containerLayoutUpdated(_ layout: ContainerViewLayout, transition: ContainedViewLayoutTransition) {
let needsRootWallpaperBackgroundNode: Bool
if case .regular = layout.metrics.widthClass {
needsRootWallpaperBackgroundNode = true
} else {
needsRootWallpaperBackgroundNode = false
}
if needsRootWallpaperBackgroundNode {
let detailsPlaceholderNode: DetailsChatPlaceholderNode
if let current = self.detailsPlaceholderNode {
detailsPlaceholderNode = current
} else {
detailsPlaceholderNode = DetailsChatPlaceholderNode(context: self.context)
detailsPlaceholderNode.wallpaperBackgroundNode.update(wallpaper: self.presentationData.chatWallpaper)
self.detailsPlaceholderNode = detailsPlaceholderNode
}
self.updateDetailsPlaceholderNode(detailsPlaceholderNode)
} else if let _ = self.detailsPlaceholderNode {
self.detailsPlaceholderNode = nil
self.updateDetailsPlaceholderNode(nil)
}
super.containerLayoutUpdated(layout, transition: transition)
}
public func addRootControllers(showCallsTab: Bool) {
let tabBarController = TabBarControllerImpl(navigationBarPresentationData: NavigationBarPresentationData(presentationData: self.presentationData), theme: TabBarControllerTheme(rootControllerTheme: self.presentationData.theme))
tabBarController.navigationPresentation = .master
let chatListController = self.context.sharedContext.makeChatListController(context: self.context, location: .chatList(groupId: .root), controlsHistoryPreload: true, hideNetworkActivityStatus: false, previewing: false, enableDebugActions: !GlobalExperimentalSettings.isAppStoreBuild)
if let sharedContext = self.context.sharedContext as? SharedAccountContextImpl {
chatListController.tabBarItem.badgeValue = sharedContext.switchingData.chatListBadge
}
let callListController = CallListController(context: self.context, mode: .tab)
var controllers: [ViewController] = []
let contactsController = ContactsController(context: self.context)
contactsController.switchToChatsController = { [weak self] in
self?.openChatsController(activateSearch: false)
}
controllers.append(contactsController)
if showCallsTab {
controllers.append(callListController)
}
controllers.append(chatListController)
var restoreSettignsController: (ViewController & SettingsController)?
if let sharedContext = self.context.sharedContext as? SharedAccountContextImpl {
restoreSettignsController = sharedContext.switchingData.settingsController
}
restoreSettignsController?.updateContext(context: self.context)
if let sharedContext = self.context.sharedContext as? SharedAccountContextImpl {
sharedContext.switchingData = (nil, nil, nil)
}
let accountSettingsController = PeerInfoScreenImpl(context: self.context, updatedPresentationData: nil, peerId: self.context.account.peerId, avatarInitiallyExpanded: false, isOpenedFromChat: false, nearbyPeerDistance: nil, reactionSourceMessageId: nil, callMessages: [], isSettings: true)
accountSettingsController.tabBarItemDebugTapAction = { [weak self] in
guard let strongSelf = self else {
return
}
strongSelf.pushViewController(debugController(sharedContext: strongSelf.context.sharedContext, context: strongSelf.context))
}
accountSettingsController.parentController = self
controllers.append(accountSettingsController)
tabBarController.setControllers(controllers, selectedIndex: restoreSettignsController != nil ? (controllers.count - 1) : (controllers.count - 2))
self.contactsController = contactsController
self.callListController = callListController
self.chatListController = chatListController
self.accountSettingsController = accountSettingsController
self.rootTabController = tabBarController
self.pushViewController(tabBarController, animated: false)
}
public func updateRootControllers(showCallsTab: Bool) {
guard let rootTabController = self.rootTabController as? TabBarControllerImpl else {
return
}
var controllers: [ViewController] = []
controllers.append(self.contactsController!)
if showCallsTab {
controllers.append(self.callListController!)
}
controllers.append(self.chatListController!)
controllers.append(self.accountSettingsController!)
rootTabController.setControllers(controllers, selectedIndex: nil)
}
public func openChatsController(activateSearch: Bool, filter: ChatListSearchFilter = .chats, query: String? = nil) {
guard let rootTabController = self.rootTabController else {
return
}
if activateSearch {
self.popToRoot(animated: false)
}
if let index = rootTabController.controllers.firstIndex(where: { $0 is ChatListController}) {
rootTabController.selectedIndex = index
}
if activateSearch {
self.chatListController?.activateSearch(filter: filter, query: query)
}
}
public func openRootCompose() {
self.chatListController?.activateCompose()
}
public func openRootCamera() {
guard let controller = self.viewControllers.last as? ViewController else {
return
}
controller.view.endEditing(true)
presentedLegacyShortcutCamera(context: self.context, saveCapturedMedia: false, saveEditedPhotos: false, mediaGrouping: true, parentController: controller)
}
public func openSettings() {
guard let rootTabController = self.rootTabController else {
return
}
self.popToRoot(animated: false)
if let index = rootTabController.controllers.firstIndex(where: { $0 is PeerInfoScreenImpl }) {
rootTabController.selectedIndex = index
}
}
}