mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-06-16 05:55:20 +00:00
[Temp]
This commit is contained in:
parent
fba8f6b9f2
commit
bfb4c7bbad
@ -230,8 +230,6 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
|
|||||||
return super.displayNode as! ChatListControllerNode
|
return super.displayNode as! ChatListControllerNode
|
||||||
}
|
}
|
||||||
|
|
||||||
private let headerContentView = ComponentView<Empty>()
|
|
||||||
|
|
||||||
fileprivate private(set) var primaryContext: ChatListLocationContext?
|
fileprivate private(set) var primaryContext: ChatListLocationContext?
|
||||||
private let primaryInfoReady = Promise<Bool>()
|
private let primaryInfoReady = Promise<Bool>()
|
||||||
private let mainReady = Promise<Bool>()
|
private let mainReady = Promise<Bool>()
|
||||||
@ -275,8 +273,6 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
|
|||||||
|
|
||||||
private let isReorderingTabsValue = ValuePromise<Bool>(false)
|
private let isReorderingTabsValue = ValuePromise<Bool>(false)
|
||||||
|
|
||||||
private var searchContentNode: NavigationBarSearchContentNode?
|
|
||||||
|
|
||||||
private let navigationSecondaryContentNode: ASDisplayNode
|
private let navigationSecondaryContentNode: ASDisplayNode
|
||||||
private let tabContainerNode: ChatListFilterTabContainerNode
|
private let tabContainerNode: ChatListFilterTabContainerNode
|
||||||
private var tabContainerData: ([ChatListFilterTabEntry], Bool, Int32?)?
|
private var tabContainerData: ([ChatListFilterTabEntry], Bool, Int32?)?
|
||||||
@ -302,7 +298,7 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
|
|||||||
|
|
||||||
private var powerSavingMonitoringDisposable: Disposable?
|
private var powerSavingMonitoringDisposable: Disposable?
|
||||||
|
|
||||||
private var storySubscriptions: EngineStorySubscriptions?
|
private(set) var storySubscriptions: EngineStorySubscriptions?
|
||||||
|
|
||||||
private var storySubscriptionsDisposable: Disposable?
|
private var storySubscriptionsDisposable: Disposable?
|
||||||
private var preloadStorySubscriptionsDisposable: Disposable?
|
private var preloadStorySubscriptionsDisposable: Disposable?
|
||||||
@ -346,7 +342,7 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
|
|||||||
|
|
||||||
self.storyListHeight = 0.0
|
self.storyListHeight = 0.0
|
||||||
|
|
||||||
super.init(context: context, navigationBarPresentationData: NavigationBarPresentationData(presentationData: self.presentationData), mediaAccessoryPanelVisibility: .always, locationBroadcastPanelSource: .summary, groupCallPanelSource: groupCallPanelSource)
|
super.init(context: context, navigationBarPresentationData: nil, mediaAccessoryPanelVisibility: .always, locationBroadcastPanelSource: .summary, groupCallPanelSource: groupCallPanelSource)
|
||||||
|
|
||||||
self.tabBarItemContextActionType = .always
|
self.tabBarItemContextActionType = .always
|
||||||
self.automaticallyControlPresentationContextLayout = false
|
self.automaticallyControlPresentationContextLayout = false
|
||||||
@ -439,9 +435,10 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
|
|||||||
|
|
||||||
self.scrollToTop = { [weak self] in
|
self.scrollToTop = { [weak self] in
|
||||||
if let strongSelf = self {
|
if let strongSelf = self {
|
||||||
if let searchContentNode = strongSelf.searchContentNode {
|
/*if let searchContentNode = strongSelf.searchContentNode {
|
||||||
searchContentNode.updateExpansionProgress(1.0, animated: true)
|
searchContentNode.updateExpansionProgress(1.0, animated: true)
|
||||||
}
|
}*/
|
||||||
|
//TODO:scroll to top
|
||||||
strongSelf.chatListDisplayNode.scrollToTop()
|
strongSelf.chatListDisplayNode.scrollToTop()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -454,9 +451,10 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
|
|||||||
} else {
|
} else {
|
||||||
switch strongSelf.chatListDisplayNode.effectiveContainerNode.currentItemNode.visibleContentOffset() {
|
switch strongSelf.chatListDisplayNode.effectiveContainerNode.currentItemNode.visibleContentOffset() {
|
||||||
case .none, .unknown:
|
case .none, .unknown:
|
||||||
if let searchContentNode = strongSelf.searchContentNode {
|
//TODO:scroll to top
|
||||||
|
/*if let searchContentNode = strongSelf.searchContentNode {
|
||||||
searchContentNode.updateExpansionProgress(1.0, animated: true)
|
searchContentNode.updateExpansionProgress(1.0, animated: true)
|
||||||
}
|
}*/
|
||||||
strongSelf.chatListDisplayNode.effectiveContainerNode.currentItemNode.scrollToPosition(.top)
|
strongSelf.chatListDisplayNode.effectiveContainerNode.currentItemNode.scrollToPosition(.top)
|
||||||
case let .known(offset):
|
case let .known(offset):
|
||||||
let isFirstFilter = strongSelf.chatListDisplayNode.effectiveContainerNode.currentItemNode.chatListFilter == strongSelf.chatListDisplayNode.mainContainerNode.availableFilters.first?.filter
|
let isFirstFilter = strongSelf.chatListDisplayNode.effectiveContainerNode.currentItemNode.chatListFilter == strongSelf.chatListDisplayNode.mainContainerNode.availableFilters.first?.filter
|
||||||
@ -474,9 +472,10 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
|
|||||||
}
|
}
|
||||||
strongSelf.selectTab(id: targetTab)
|
strongSelf.selectTab(id: targetTab)
|
||||||
} else {
|
} else {
|
||||||
if let searchContentNode = strongSelf.searchContentNode {
|
//TODO:scroll to top
|
||||||
|
/*if let searchContentNode = strongSelf.searchContentNode {
|
||||||
searchContentNode.updateExpansionProgress(1.0, animated: true)
|
searchContentNode.updateExpansionProgress(1.0, animated: true)
|
||||||
}
|
}*/
|
||||||
if let inlineStackContainerNode = strongSelf.chatListDisplayNode.inlineStackContainerNode {
|
if let inlineStackContainerNode = strongSelf.chatListDisplayNode.inlineStackContainerNode {
|
||||||
inlineStackContainerNode.currentItemNode.scrollToPosition(.top)
|
inlineStackContainerNode.currentItemNode.scrollToPosition(.top)
|
||||||
} else {
|
} else {
|
||||||
@ -513,25 +512,13 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
|
|||||||
})
|
})
|
||||||
|
|
||||||
if !previewing {
|
if !previewing {
|
||||||
let placeholder: String
|
/*
|
||||||
let compactPlaceholder: String
|
|
||||||
|
|
||||||
var isForum = false
|
|
||||||
if case .forum = location {
|
|
||||||
isForum = true
|
|
||||||
placeholder = self.presentationData.strings.Common_Search
|
|
||||||
compactPlaceholder = self.presentationData.strings.Common_Search
|
|
||||||
} else {
|
|
||||||
placeholder = self.presentationData.strings.DialogList_SearchLabel
|
|
||||||
compactPlaceholder = self.presentationData.strings.DialogList_SearchLabelCompact
|
|
||||||
}
|
|
||||||
|
|
||||||
self.searchContentNode = NavigationBarSearchContentNode(theme: self.presentationData.theme, placeholder: placeholder, compactPlaceholder: compactPlaceholder, activate: { [weak self] in
|
self.searchContentNode = NavigationBarSearchContentNode(theme: self.presentationData.theme, placeholder: placeholder, compactPlaceholder: compactPlaceholder, activate: { [weak self] in
|
||||||
self?.chatListDisplayNode.mainContainerNode.currentItemNode.cancelTracking()
|
self?.chatListDisplayNode.mainContainerNode.currentItemNode.cancelTracking()
|
||||||
self?.activateSearch(filter: isForum ? .topics : .chats)
|
self?.activateSearch(filter: isForum ? .topics : .chats)
|
||||||
})
|
})
|
||||||
self.searchContentNode?.updateExpansionProgress(0.0)
|
self.searchContentNode?.updateExpansionProgress(0.0)
|
||||||
self.navigationBar?.setContentNode(self.searchContentNode, animated: false)
|
self.navigationBar?.setContentNode(self.searchContentNode, animated: false)*/
|
||||||
|
|
||||||
let tabsIsEmpty: Bool
|
let tabsIsEmpty: Bool
|
||||||
if let (resolvedItems, displayTabsAtBottom, _) = self.tabContainerData {
|
if let (resolvedItems, displayTabsAtBottom, _) = self.tabContainerData {
|
||||||
@ -794,7 +781,9 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
|
|||||||
)))
|
)))
|
||||||
]))
|
]))
|
||||||
|
|
||||||
strongSelf.searchContentNode?.placeholderNode.setAccessoryComponent(component: AnyComponent(Button(
|
let _ = contentComponent
|
||||||
|
//TODO:download indicator
|
||||||
|
/*strongSelf.searchContentNode?.placeholderNode.setAccessoryComponent(component: AnyComponent(Button(
|
||||||
content: contentComponent,
|
content: contentComponent,
|
||||||
action: {
|
action: {
|
||||||
guard let strongSelf = self else {
|
guard let strongSelf = self else {
|
||||||
@ -802,9 +791,9 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
|
|||||||
}
|
}
|
||||||
strongSelf.activateSearch(filter: .downloads, query: nil)
|
strongSelf.activateSearch(filter: .downloads, query: nil)
|
||||||
}
|
}
|
||||||
)))
|
)))*/
|
||||||
} else {
|
} else {
|
||||||
strongSelf.searchContentNode?.placeholderNode.setAccessoryComponent(component: nil)
|
//strongSelf.searchContentNode?.placeholderNode.setAccessoryComponent(component: nil)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -889,14 +878,14 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
|
|||||||
}
|
}
|
||||||
|
|
||||||
func findTitleView() -> ChatListTitleView? {
|
func findTitleView() -> ChatListTitleView? {
|
||||||
guard let componentView = self.headerContentView.view as? ChatListHeaderComponent.View else {
|
guard let componentView = self.chatListHeaderView() else {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
return componentView.findTitleView()
|
return componentView.findTitleView()
|
||||||
}
|
}
|
||||||
|
|
||||||
private var previousEmojiSetupTimestamp: Double?
|
private var previousEmojiSetupTimestamp: Double?
|
||||||
private func openStatusSetup(sourceView: UIView) {
|
func openStatusSetup(sourceView: UIView) {
|
||||||
let currentTimestamp = CACurrentMediaTime()
|
let currentTimestamp = CACurrentMediaTime()
|
||||||
if let previousTimestamp = self.previousEmojiSetupTimestamp, currentTimestamp < previousTimestamp + 1.0 {
|
if let previousTimestamp = self.previousEmojiSetupTimestamp, currentTimestamp < previousTimestamp + 1.0 {
|
||||||
return
|
return
|
||||||
@ -962,40 +951,6 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
|
|||||||
self.navigationItem.backBarButtonItem = backBarButtonItem
|
self.navigationItem.backBarButtonItem = backBarButtonItem
|
||||||
}
|
}
|
||||||
|
|
||||||
let placeholder: String
|
|
||||||
let compactPlaceholder: String
|
|
||||||
if case .forum = location {
|
|
||||||
placeholder = self.presentationData.strings.Common_Search
|
|
||||||
compactPlaceholder = self.presentationData.strings.Common_Search
|
|
||||||
} else {
|
|
||||||
placeholder = self.presentationData.strings.DialogList_SearchLabel
|
|
||||||
compactPlaceholder = self.presentationData.strings.DialogList_SearchLabelCompact
|
|
||||||
}
|
|
||||||
self.searchContentNode?.updateThemeAndPlaceholder(theme: self.presentationData.theme, placeholder: placeholder, compactPlaceholder: compactPlaceholder)
|
|
||||||
|
|
||||||
/*let editing = self.chatListDisplayNode.containerNode.currentItemNode.currentState.editing
|
|
||||||
if case .chatList(.root) = self.location {
|
|
||||||
self.primaryContext?.leftButton = AnyComponentWithIdentity(id: "edit", component: AnyComponent(NavigationButtonComponent(
|
|
||||||
content: .text(title: self.presentationData.strings.Common_Edit, isBold: false),
|
|
||||||
pressed: { [weak self] in
|
|
||||||
self?.editPressed()
|
|
||||||
}
|
|
||||||
)))
|
|
||||||
self.primaryContext?.rightButton = AnyComponentWithIdentity(id: "compose", component: AnyComponent(NavigationButtonComponent(
|
|
||||||
content: .icon(imageName: "Chat List/Compose Icon"),
|
|
||||||
pressed: { [weak self] in
|
|
||||||
self?.composePressed()
|
|
||||||
}
|
|
||||||
)))
|
|
||||||
} else {
|
|
||||||
self.primaryContext?.rightButton = AnyComponentWithIdentity(id: "edit", component: AnyComponent(NavigationButtonComponent(
|
|
||||||
content: .text(title: self.presentationData.strings.Common_Edit, isBold: false),
|
|
||||||
pressed: { [weak self] in
|
|
||||||
self?.editPressed()
|
|
||||||
}
|
|
||||||
)))
|
|
||||||
}*/
|
|
||||||
|
|
||||||
self.statusBar.statusBarStyle = self.presentationData.theme.rootController.statusBarStyle.style
|
self.statusBar.statusBarStyle = self.presentationData.theme.rootController.statusBarStyle.style
|
||||||
self.navigationBar?.updatePresentationData(NavigationBarPresentationData(presentationData: self.presentationData))
|
self.navigationBar?.updatePresentationData(NavigationBarPresentationData(presentationData: self.presentationData))
|
||||||
|
|
||||||
@ -1007,7 +962,7 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
|
|||||||
self.chatListDisplayNode.updatePresentationData(self.presentationData)
|
self.chatListDisplayNode.updatePresentationData(self.presentationData)
|
||||||
}
|
}
|
||||||
|
|
||||||
self.requestUpdateHeaderContent(transition: .immediate)
|
self.requestLayout(transition: .immediate)
|
||||||
}
|
}
|
||||||
|
|
||||||
override public func loadDisplayNode() {
|
override public func loadDisplayNode() {
|
||||||
@ -1299,23 +1254,38 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
|
|||||||
navigationController.filterController(strongSelf, animated: true)
|
navigationController.filterController(strongSelf, animated: true)
|
||||||
}
|
}
|
||||||
|
|
||||||
self.chatListDisplayNode.contentOffsetChanged = { [weak self] offset in
|
/*self.chatListDisplayNode.contentOffsetChanged = { [weak self] offset in
|
||||||
if let strongSelf = self, let searchContentNode = strongSelf.searchContentNode, let validLayout = strongSelf.validLayout {
|
if let strongSelf = self, let validLayout = strongSelf.validLayout {
|
||||||
var offset = offset
|
var offset = offset
|
||||||
if validLayout.inVoiceOver {
|
if validLayout.inVoiceOver {
|
||||||
offset = .known(0.0)
|
offset = .known(0.0)
|
||||||
}
|
}
|
||||||
//print("offset: \(offset), additionalHeight: \(searchContentNode.additionalHeight)")
|
|
||||||
searchContentNode.updateListVisibleContentOffset(offset, transition: strongSelf.chatListDisplayNode.temporaryContentOffsetChangeTransition ?? .immediate)
|
let offsetValue: CGFloat
|
||||||
|
switch offset {
|
||||||
|
case .none:
|
||||||
|
offsetValue = 0.0
|
||||||
|
case let .known(value):
|
||||||
|
offsetValue = value
|
||||||
|
case .unknown:
|
||||||
|
offsetValue = 10000.0
|
||||||
|
}
|
||||||
|
|
||||||
|
if let navigationBarView = strongSelf.chatListDisplayNode.navigationBarView.view as? ChatListNavigationBar.View {
|
||||||
|
navigationBarView.applyScroll(offset: offsetValue, transition: .immediate)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}*/
|
||||||
|
|
||||||
self.chatListDisplayNode.contentScrollingEnded = { [weak self] listView in
|
self.chatListDisplayNode.contentScrollingEnded = { [weak self] listView in
|
||||||
if let strongSelf = self, let searchContentNode = strongSelf.searchContentNode {
|
let _ = self
|
||||||
|
/*if let strongSelf = self, let searchContentNode = strongSelf.searchContentNode {
|
||||||
return fixListNodeScrolling(listView, searchNode: searchContentNode)
|
return fixListNodeScrolling(listView, searchNode: searchContentNode)
|
||||||
} else {
|
} else {
|
||||||
return false
|
return false
|
||||||
}
|
}*/
|
||||||
|
//TODO:fix scrolling
|
||||||
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
self.chatListDisplayNode.emptyListAction = { [weak self] _ in
|
self.chatListDisplayNode.emptyListAction = { [weak self] _ in
|
||||||
@ -1851,7 +1821,10 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
|
|||||||
|
|
||||||
strongSelf.chatListDisplayNode.isReorderingFilters = true
|
strongSelf.chatListDisplayNode.isReorderingFilters = true
|
||||||
strongSelf.isReorderingTabsValue.set(true)
|
strongSelf.isReorderingTabsValue.set(true)
|
||||||
strongSelf.searchContentNode?.setIsEnabled(false, animated: true)
|
|
||||||
|
//TODO:update search enabled
|
||||||
|
//strongSelf.searchContentNode?.setIsEnabled(false, animated: true)
|
||||||
|
|
||||||
(strongSelf.parent as? TabBarController)?.updateIsTabBarEnabled(false, transition: .animated(duration: 0.2, curve: .easeInOut))
|
(strongSelf.parent as? TabBarController)?.updateIsTabBarEnabled(false, transition: .animated(duration: 0.2, curve: .easeInOut))
|
||||||
if let layout = strongSelf.validLayout {
|
if let layout = strongSelf.validLayout {
|
||||||
strongSelf.updateLayout(layout: layout, transition: .animated(duration: 0.2, curve: .easeInOut))
|
strongSelf.updateLayout(layout: layout, transition: .animated(duration: 0.2, curve: .easeInOut))
|
||||||
@ -1934,6 +1907,22 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
|
|||||||
self.storySubscriptions = storySubscriptions
|
self.storySubscriptions = storySubscriptions
|
||||||
let isEmpty = storySubscriptions.items.isEmpty
|
let isEmpty = storySubscriptions.items.isEmpty
|
||||||
|
|
||||||
|
self.storyListHeight = isEmpty ? 0.0 : 94.0
|
||||||
|
|
||||||
|
let transition: ContainedViewLayoutTransition
|
||||||
|
if self.didAppear {
|
||||||
|
transition = .animated(duration: 0.4, curve: .spring)
|
||||||
|
} else {
|
||||||
|
transition = .immediate
|
||||||
|
}
|
||||||
|
|
||||||
|
let _ = wasEmpty
|
||||||
|
let _ = isEmpty
|
||||||
|
|
||||||
|
self.chatListDisplayNode.temporaryContentOffsetChangeTransition = transition
|
||||||
|
self.requestLayout(transition: transition)
|
||||||
|
self.chatListDisplayNode.temporaryContentOffsetChangeTransition = nil
|
||||||
|
|
||||||
self.chatListDisplayNode.mainContainerNode.currentItemNode.updateState { chatListState in
|
self.chatListDisplayNode.mainContainerNode.currentItemNode.updateState { chatListState in
|
||||||
var chatListState = chatListState
|
var chatListState = chatListState
|
||||||
|
|
||||||
@ -1951,23 +1940,6 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
|
|||||||
return chatListState
|
return chatListState
|
||||||
}
|
}
|
||||||
|
|
||||||
self.storyListHeight = isEmpty ? 0.0 : 94.0
|
|
||||||
|
|
||||||
let transition: ContainedViewLayoutTransition
|
|
||||||
if self.didAppear {
|
|
||||||
transition = .animated(duration: 0.4, curve: .spring)
|
|
||||||
} else {
|
|
||||||
transition = .immediate
|
|
||||||
}
|
|
||||||
|
|
||||||
if wasEmpty != isEmpty {
|
|
||||||
self.chatListDisplayNode.temporaryContentOffsetChangeTransition = transition
|
|
||||||
self.requestLayout(transition: transition)
|
|
||||||
self.chatListDisplayNode.temporaryContentOffsetChangeTransition = nil
|
|
||||||
} else {
|
|
||||||
self.requestUpdateHeaderContent(transition: transition)
|
|
||||||
}
|
|
||||||
|
|
||||||
self.storiesReady.set(.single(true))
|
self.storiesReady.set(.single(true))
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -2251,7 +2223,7 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if hasEmptyMark {
|
if hasEmptyMark {
|
||||||
if let componentView = self.headerContentView.view as? ChatListHeaderComponent.View {
|
if let componentView = self.chatListHeaderView() {
|
||||||
if let rightButtonView = componentView.rightButtonView {
|
if let rightButtonView = componentView.rightButtonView {
|
||||||
let absoluteFrame = rightButtonView.convert(rightButtonView.bounds, to: self.view)
|
let absoluteFrame = rightButtonView.convert(rightButtonView.bounds, to: self.view)
|
||||||
let text: String = self.presentationData.strings.ChatList_EmptyListTooltip
|
let text: String = self.presentationData.strings.ChatList_EmptyListTooltip
|
||||||
@ -2402,13 +2374,7 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func requestUpdateHeaderContent(transition: ContainedViewLayoutTransition) {
|
func updateHeaderContent(layout: ContainerViewLayout, transition: ContainedViewLayoutTransition) -> (primaryContent: ChatListHeaderComponent.Content?, secondaryContent: ChatListHeaderComponent.Content?) {
|
||||||
if let validLayout = self.validLayout {
|
|
||||||
self.updateHeaderContent(layout: validLayout, transition: transition)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private func updateHeaderContent(layout: ContainerViewLayout, transition: ContainedViewLayoutTransition) {
|
|
||||||
var primaryContent: ChatListHeaderComponent.Content?
|
var primaryContent: ChatListHeaderComponent.Content?
|
||||||
if let primaryContext = self.primaryContext {
|
if let primaryContext = self.primaryContext {
|
||||||
var backTitle: String?
|
var backTitle: String?
|
||||||
@ -2459,8 +2425,11 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
var storiesFraction: CGFloat = 0.0
|
return (primaryContent, secondaryContent)
|
||||||
if let searchContentNode = self.searchContentNode, case .chatList(.root) = self.location {
|
|
||||||
|
/*let storiesFraction: CGFloat = 0.0
|
||||||
|
//TODO:move to navigation bar
|
||||||
|
/*if let searchContentNode = self.searchContentNode, case .chatList(.root) = self.location {
|
||||||
if self.storyListHeight > 0.0 {
|
if self.storyListHeight > 0.0 {
|
||||||
let fraction = navigationBarSearchContentHeight / searchContentNode.nominalHeight
|
let fraction = navigationBarSearchContentHeight / searchContentNode.nominalHeight
|
||||||
|
|
||||||
@ -2471,7 +2440,7 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
|
|||||||
let visibleProgress: CGFloat = toLow + (searchContentNode.expansionProgress - fromLow) * (toHigh - toLow) / (fromHigh - fromLow)
|
let visibleProgress: CGFloat = toLow + (searchContentNode.expansionProgress - fromLow) * (toHigh - toLow) / (fromHigh - fromLow)
|
||||||
storiesFraction = max(0.0, min(1.0, visibleProgress))
|
storiesFraction = max(0.0, min(1.0, visibleProgress))
|
||||||
}
|
}
|
||||||
}
|
}*/
|
||||||
|
|
||||||
let _ = self.headerContentView.update(
|
let _ = self.headerContentView.update(
|
||||||
transition: Transition(transition),
|
transition: Transition(transition),
|
||||||
@ -2506,107 +2475,27 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
|
|||||||
if self.navigationBar?.customHeaderContentView !== componentView {
|
if self.navigationBar?.customHeaderContentView !== componentView {
|
||||||
self.navigationBar?.customHeaderContentView = componentView
|
self.navigationBar?.customHeaderContentView = componentView
|
||||||
}
|
}
|
||||||
}
|
}*/
|
||||||
if case .chatList(.root) = self.location {
|
|
||||||
if let componentView = self.headerContentView.view as? ChatListHeaderComponent.View {
|
|
||||||
componentView.storyPeerAction = { [weak self] peer in
|
|
||||||
guard let self else {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
let storyContent = StoryContentContextImpl(context: self.context, focusedPeerId: peer?.id)
|
|
||||||
let _ = (storyContent.state
|
|
||||||
|> take(1)
|
|
||||||
|> deliverOnMainQueue).start(next: { [weak self] storyContentState in
|
|
||||||
guard let self else {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if let peer, peer.id == self.context.account.peerId, storyContentState.slice == nil {
|
|
||||||
var cameraTransitionIn: StoryCameraTransitionIn?
|
|
||||||
if let componentView = self.headerContentView.view as? ChatListHeaderComponent.View {
|
|
||||||
if let transitionView = componentView.storyPeerListView()?.transitionViewForItem(peerId: self.context.account.peerId) {
|
|
||||||
cameraTransitionIn = StoryCameraTransitionIn(
|
|
||||||
sourceView: transitionView,
|
|
||||||
sourceRect: transitionView.bounds,
|
|
||||||
sourceCornerRadius: transitionView.bounds.height * 0.5
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if let rootController = self.context.sharedContext.mainWindow?.viewController as? TelegramRootControllerInterface {
|
|
||||||
rootController.openStoryCamera(transitionIn: cameraTransitionIn, transitionOut: { [weak self] _ in
|
|
||||||
guard let self else {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
if let componentView = self.headerContentView.view as? ChatListHeaderComponent.View {
|
|
||||||
if let transitionView = componentView.storyPeerListView()?.transitionViewForItem(peerId: self.context.account.peerId) {
|
|
||||||
return StoryCameraTransitionOut(
|
|
||||||
destinationView: transitionView,
|
|
||||||
destinationRect: transitionView.bounds,
|
|
||||||
destinationCornerRadius: transitionView.bounds.height * 0.5
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
var transitionIn: StoryContainerScreen.TransitionIn?
|
|
||||||
if let peer, let componentView = self.headerContentView.view as? ChatListHeaderComponent.View {
|
|
||||||
if let transitionView = componentView.storyPeerListView()?.transitionViewForItem(peerId: peer.id) {
|
|
||||||
transitionIn = StoryContainerScreen.TransitionIn(
|
|
||||||
sourceView: transitionView,
|
|
||||||
sourceRect: transitionView.bounds,
|
|
||||||
sourceCornerRadius: transitionView.bounds.height * 0.5
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let storyContainerScreen = StoryContainerScreen(
|
|
||||||
context: self.context,
|
|
||||||
content: storyContent,
|
|
||||||
transitionIn: transitionIn,
|
|
||||||
transitionOut: { [weak self] peerId, _ in
|
|
||||||
guard let self else {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
if let componentView = self.headerContentView.view as? ChatListHeaderComponent.View {
|
|
||||||
if let transitionView = componentView.storyPeerListView()?.transitionViewForItem(peerId: peerId) {
|
|
||||||
return StoryContainerScreen.TransitionOut(
|
|
||||||
destinationView: transitionView,
|
|
||||||
destinationRect: transitionView.bounds,
|
|
||||||
destinationCornerRadius: transitionView.bounds.height * 0.5,
|
|
||||||
destinationIsAvatar: true,
|
|
||||||
completed: {}
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
)
|
|
||||||
self.push(storyContainerScreen)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override public func updateNavigationBarLayout(_ layout: ContainerViewLayout, transition: ContainedViewLayoutTransition) {
|
override public func updateNavigationBarLayout(_ layout: ContainerViewLayout, transition: ContainedViewLayoutTransition) {
|
||||||
self.updateHeaderContent(layout: layout, transition: transition)
|
|
||||||
|
|
||||||
super.updateNavigationBarLayout(layout, transition: transition)
|
super.updateNavigationBarLayout(layout, transition: transition)
|
||||||
}
|
}
|
||||||
|
|
||||||
override public func containerLayoutUpdated(_ layout: ContainerViewLayout, transition: ContainedViewLayoutTransition) {
|
private func chatListHeaderView() -> ChatListHeaderComponent.View? {
|
||||||
if case .chatList(.root) = self.location, !self.isSearchActive {
|
if let navigationBarView = self.chatListDisplayNode.navigationBarView.view as? ChatListNavigationBar.View {
|
||||||
self.searchContentNode?.additionalHeight = (1.0 - self.chatListDisplayNode.inlineStackContainerTransitionFraction) * self.storyListHeight
|
if let componentView = navigationBarView.headerContent.view as? ChatListHeaderComponent.View {
|
||||||
|
return componentView
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
override public func containerLayoutUpdated(_ layout: ContainerViewLayout, transition: ContainedViewLayoutTransition) {
|
||||||
|
//TODO:move to chat list node
|
||||||
|
/*if case .chatList(.root) = self.location, !self.isSearchActive {
|
||||||
|
self.searchContentNode?.additionalHeight = (1.0 - self.chatListDisplayNode.inlineStackContainerTransitionFraction) * self.storyListHeight
|
||||||
|
}*/
|
||||||
|
|
||||||
super.containerLayoutUpdated(layout, transition: transition)
|
super.containerLayoutUpdated(layout, transition: transition)
|
||||||
|
|
||||||
@ -2616,14 +2505,100 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
|
|||||||
|
|
||||||
self.updateLayout(layout: layout, transition: transition)
|
self.updateLayout(layout: layout, transition: transition)
|
||||||
|
|
||||||
if let searchContentNode = self.searchContentNode, layout.inVoiceOver != wasInVoiceOver {
|
if layout.inVoiceOver != wasInVoiceOver {
|
||||||
searchContentNode.updateListVisibleContentOffset(.known(0.0))
|
|
||||||
self.chatListDisplayNode.scrollToTop()
|
self.chatListDisplayNode.scrollToTop()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if case .chatList(.root) = self.location, let componentView = self.chatListHeaderView() {
|
||||||
|
componentView.storyPeerAction = { [weak self] peer in
|
||||||
|
guard let self else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
let storyContent = StoryContentContextImpl(context: self.context, focusedPeerId: peer?.id)
|
||||||
|
let _ = (storyContent.state
|
||||||
|
|> take(1)
|
||||||
|
|> deliverOnMainQueue).start(next: { [weak self] storyContentState in
|
||||||
|
guard let self else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if let peer, peer.id == self.context.account.peerId, storyContentState.slice == nil {
|
||||||
|
var cameraTransitionIn: StoryCameraTransitionIn?
|
||||||
|
if let componentView = self.chatListHeaderView() {
|
||||||
|
if let transitionView = componentView.storyPeerListView()?.transitionViewForItem(peerId: self.context.account.peerId) {
|
||||||
|
cameraTransitionIn = StoryCameraTransitionIn(
|
||||||
|
sourceView: transitionView,
|
||||||
|
sourceRect: transitionView.bounds,
|
||||||
|
sourceCornerRadius: transitionView.bounds.height * 0.5
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if let rootController = self.context.sharedContext.mainWindow?.viewController as? TelegramRootControllerInterface {
|
||||||
|
rootController.openStoryCamera(transitionIn: cameraTransitionIn, transitionOut: { [weak self] _ in
|
||||||
|
guard let self else {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
if let componentView = self.chatListHeaderView() {
|
||||||
|
if let transitionView = componentView.storyPeerListView()?.transitionViewForItem(peerId: self.context.account.peerId) {
|
||||||
|
return StoryCameraTransitionOut(
|
||||||
|
destinationView: transitionView,
|
||||||
|
destinationRect: transitionView.bounds,
|
||||||
|
destinationCornerRadius: transitionView.bounds.height * 0.5
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
var transitionIn: StoryContainerScreen.TransitionIn?
|
||||||
|
if let peer, let componentView = self.chatListHeaderView() {
|
||||||
|
if let transitionView = componentView.storyPeerListView()?.transitionViewForItem(peerId: peer.id) {
|
||||||
|
transitionIn = StoryContainerScreen.TransitionIn(
|
||||||
|
sourceView: transitionView,
|
||||||
|
sourceRect: transitionView.bounds,
|
||||||
|
sourceCornerRadius: transitionView.bounds.height * 0.5
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let storyContainerScreen = StoryContainerScreen(
|
||||||
|
context: self.context,
|
||||||
|
content: storyContent,
|
||||||
|
transitionIn: transitionIn,
|
||||||
|
transitionOut: { [weak self] peerId, _ in
|
||||||
|
guard let self else {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if let componentView = self.chatListHeaderView() {
|
||||||
|
if let transitionView = componentView.storyPeerListView()?.transitionViewForItem(peerId: peerId) {
|
||||||
|
return StoryContainerScreen.TransitionOut(
|
||||||
|
destinationView: transitionView,
|
||||||
|
destinationRect: transitionView.bounds,
|
||||||
|
destinationCornerRadius: transitionView.bounds.height * 0.5,
|
||||||
|
destinationIsAvatar: true,
|
||||||
|
completed: {}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
)
|
||||||
|
self.push(storyContainerScreen)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public func transitionViewForOwnStoryItem() -> UIView? {
|
public func transitionViewForOwnStoryItem() -> UIView? {
|
||||||
if let componentView = self.headerContentView.view as? ChatListHeaderComponent.View {
|
if let componentView = self.chatListHeaderView() {
|
||||||
if let transitionView = componentView.storyPeerListView()?.transitionViewForItem(peerId: self.context.account.peerId) {
|
if let transitionView = componentView.storyPeerListView()?.transitionViewForItem(peerId: self.context.account.peerId) {
|
||||||
return transitionView
|
return transitionView
|
||||||
}
|
}
|
||||||
@ -2632,7 +2607,7 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
|
|||||||
}
|
}
|
||||||
|
|
||||||
public func animateStoryUploadRipple() {
|
public func animateStoryUploadRipple() {
|
||||||
if let componentView = self.headerContentView.view as? ChatListHeaderComponent.View {
|
if let componentView = self.chatListHeaderView() {
|
||||||
if let transitionView = componentView.storyPeerListView()?.transitionViewForItem(peerId: self.context.account.peerId) {
|
if let transitionView = componentView.storyPeerListView()?.transitionViewForItem(peerId: self.context.account.peerId) {
|
||||||
let localRect = transitionView.convert(transitionView.bounds, to: self.view)
|
let localRect = transitionView.convert(transitionView.bounds, to: self.view)
|
||||||
self.animateRipple(centerLocation: localRect.center)
|
self.animateRipple(centerLocation: localRect.center)
|
||||||
@ -2669,7 +2644,7 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
|
|||||||
tabContainerOffset += 44.0 + 20.0
|
tabContainerOffset += 44.0 + 20.0
|
||||||
}
|
}
|
||||||
|
|
||||||
let navigationBarHeight = self.navigationBar?.frame.maxY ?? 0.0
|
let navigationBarHeight: CGFloat = 100.0//self.navigationBar?.frame.maxY ?? 0.0
|
||||||
let secondaryContentHeight = self.navigationBar?.secondaryContentHeight ?? 0.0
|
let secondaryContentHeight = self.navigationBar?.secondaryContentHeight ?? 0.0
|
||||||
|
|
||||||
transition.updateFrame(node: self.navigationSecondaryContentNode, frame: CGRect(origin: CGPoint(x: 0.0, y: navigationBarHeight - self.additionalNavigationBarHeight - secondaryContentHeight + tabContainerOffset), size: CGSize(width: layout.size.width, height: secondaryContentHeight)))
|
transition.updateFrame(node: self.navigationSecondaryContentNode, frame: CGRect(origin: CGPoint(x: 0.0, y: navigationBarHeight - self.additionalNavigationBarHeight - secondaryContentHeight + tabContainerOffset), size: CGSize(width: layout.size.width, height: secondaryContentHeight)))
|
||||||
@ -2680,7 +2655,7 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
|
|||||||
self.tabContainerNode.update(size: CGSize(width: layout.size.width, height: 46.0), sideInset: layout.safeInsets.left, filters: self.tabContainerData?.0 ?? [], selectedFilter: self.chatListDisplayNode.mainContainerNode.currentItemFilter, isReordering: self.chatListDisplayNode.isReorderingFilters || (self.chatListDisplayNode.effectiveContainerNode.currentItemNode.currentState.editing && !self.chatListDisplayNode.didBeginSelectingChatsWhileEditing), isEditing: self.chatListDisplayNode.effectiveContainerNode.currentItemNode.currentState.editing, canReorderAllChats: self.isPremium, filtersLimit: self.tabContainerData?.2, transitionFraction: self.chatListDisplayNode.effectiveContainerNode.transitionFraction, presentationData: self.presentationData, transition: .animated(duration: 0.4, curve: .spring))
|
self.tabContainerNode.update(size: CGSize(width: layout.size.width, height: 46.0), sideInset: layout.safeInsets.left, filters: self.tabContainerData?.0 ?? [], selectedFilter: self.chatListDisplayNode.mainContainerNode.currentItemFilter, isReordering: self.chatListDisplayNode.isReorderingFilters || (self.chatListDisplayNode.effectiveContainerNode.currentItemNode.currentState.editing && !self.chatListDisplayNode.didBeginSelectingChatsWhileEditing), isEditing: self.chatListDisplayNode.effectiveContainerNode.currentItemNode.currentState.editing, canReorderAllChats: self.isPremium, filtersLimit: self.tabContainerData?.2, transitionFraction: self.chatListDisplayNode.effectiveContainerNode.transitionFraction, presentationData: self.presentationData, transition: .animated(duration: 0.4, curve: .spring))
|
||||||
}
|
}
|
||||||
|
|
||||||
self.chatListDisplayNode.containerLayoutUpdated(layout, navigationBarHeight: self.cleanNavigationHeight, visualNavigationHeight: navigationBarHeight, cleanNavigationBarHeight: self.cleanNavigationHeight, storiesInset: self.storyListHeight, transition: transition)
|
self.chatListDisplayNode.containerLayoutUpdated(layout, navigationBarHeight: navigationBarHeight, visualNavigationHeight: navigationBarHeight, cleanNavigationBarHeight: navigationBarHeight, storiesInset: self.storyListHeight, transition: transition)
|
||||||
}
|
}
|
||||||
|
|
||||||
override public func navigationStackConfigurationUpdated(next: [ViewController]) {
|
override public func navigationStackConfigurationUpdated(next: [ViewController]) {
|
||||||
@ -2708,9 +2683,8 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
self.requestUpdateHeaderContent(transition: .animated(duration: 0.3, curve: .spring))
|
//TODO:update search enabled
|
||||||
|
//self.searchContentNode?.setIsEnabled(false, animated: true)
|
||||||
self.searchContentNode?.setIsEnabled(false, animated: true)
|
|
||||||
|
|
||||||
self.chatListDisplayNode.didBeginSelectingChatsWhileEditing = false
|
self.chatListDisplayNode.didBeginSelectingChatsWhileEditing = false
|
||||||
self.chatListDisplayNode.effectiveContainerNode.updateState { state in
|
self.chatListDisplayNode.effectiveContainerNode.updateState { state in
|
||||||
@ -2729,7 +2703,10 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
|
|||||||
let skipLayoutUpdate = self.reorderingDonePressed()
|
let skipLayoutUpdate = self.reorderingDonePressed()
|
||||||
|
|
||||||
(self.navigationController as? NavigationController)?.updateMasterDetailsBlackout(nil, transition: .animated(duration: 0.4, curve: .spring))
|
(self.navigationController as? NavigationController)?.updateMasterDetailsBlackout(nil, transition: .animated(duration: 0.4, curve: .spring))
|
||||||
self.searchContentNode?.setIsEnabled(true, animated: true)
|
|
||||||
|
//TODO:update search enabled
|
||||||
|
//self.searchContentNode?.setIsEnabled(true, animated: true)
|
||||||
|
|
||||||
self.chatListDisplayNode.didBeginSelectingChatsWhileEditing = false
|
self.chatListDisplayNode.didBeginSelectingChatsWhileEditing = false
|
||||||
self.chatListDisplayNode.effectiveContainerNode.updateState { state in
|
self.chatListDisplayNode.effectiveContainerNode.updateState { state in
|
||||||
var state = state
|
var state = state
|
||||||
@ -2776,7 +2753,10 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
|
|||||||
strongSelf.chatListDisplayNode.isReorderingFilters = false
|
strongSelf.chatListDisplayNode.isReorderingFilters = false
|
||||||
strongSelf.isReorderingTabsValue.set(false)
|
strongSelf.isReorderingTabsValue.set(false)
|
||||||
(strongSelf.parent as? TabBarController)?.updateIsTabBarEnabled(true, transition: .animated(duration: 0.2, curve: .easeInOut))
|
(strongSelf.parent as? TabBarController)?.updateIsTabBarEnabled(true, transition: .animated(duration: 0.2, curve: .easeInOut))
|
||||||
strongSelf.searchContentNode?.setIsEnabled(true, animated: true)
|
|
||||||
|
//TODO:update search enabled
|
||||||
|
//strongSelf.searchContentNode?.setIsEnabled(true, animated: true)
|
||||||
|
|
||||||
if let layout = strongSelf.validLayout {
|
if let layout = strongSelf.validLayout {
|
||||||
strongSelf.updateLayout(layout: layout, transition: .animated(duration: 0.2, curve: .easeInOut))
|
strongSelf.updateLayout(layout: layout, transition: .animated(duration: 0.2, curve: .easeInOut))
|
||||||
}
|
}
|
||||||
@ -3446,24 +3426,43 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
|
|||||||
}
|
}
|
||||||
|
|
||||||
public private(set) var isSearchActive: Bool = false
|
public private(set) var isSearchActive: Bool = false
|
||||||
public func activateSearch(filter: ChatListSearchFilter = .chats, query: String? = nil) {
|
|
||||||
self.activateSearch(filter: filter, query: query, skipScrolling: false)
|
public func activateSearch(filter: ChatListSearchFilter, query: String? = nil) {
|
||||||
|
var searchContentNode: NavigationBarSearchContentNode?
|
||||||
|
if let navigationBarView = self.chatListDisplayNode.navigationBarView.view as? ChatListNavigationBar.View {
|
||||||
|
searchContentNode = navigationBarView.searchContentNode
|
||||||
|
}
|
||||||
|
|
||||||
|
if let searchContentNode {
|
||||||
|
self.activateSearch(filter: filter, query: query, skipScrolling: false, searchContentNode: searchContentNode)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public func activateSearch(query: String? = nil) {
|
||||||
|
var isForum = false
|
||||||
|
if case .forum = self.location {
|
||||||
|
isForum = true
|
||||||
|
}
|
||||||
|
|
||||||
|
let filter: ChatListSearchFilter = isForum ? .topics : .chats
|
||||||
|
self.activateSearch(filter: filter, query: query)
|
||||||
}
|
}
|
||||||
|
|
||||||
private func activateSearch(filter: ChatListSearchFilter = .chats, query: String? = nil, skipScrolling: Bool = false) {
|
func activateSearch(filter: ChatListSearchFilter = .chats, query: String? = nil, skipScrolling: Bool = false, searchContentNode: NavigationBarSearchContentNode) {
|
||||||
var filter = filter
|
var filter = filter
|
||||||
if case .forum = self.chatListDisplayNode.effectiveContainerNode.location {
|
if case .forum = self.chatListDisplayNode.effectiveContainerNode.location {
|
||||||
filter = .topics
|
filter = .topics
|
||||||
}
|
}
|
||||||
|
|
||||||
if self.displayNavigationBar {
|
if self.chatListDisplayNode.searchDisplayController == nil {
|
||||||
if !skipScrolling, let searchContentNode = self.searchContentNode, searchContentNode.expansionProgress != 1.0 {
|
/*if !skipScrolling, let searchContentNode = self.searchContentNode, searchContentNode.expansionProgress != 1.0 {
|
||||||
self.scrollToTop?()
|
self.scrollToTop?()
|
||||||
DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 0.2, execute: { [weak self] in
|
DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 0.2, execute: { [weak self] in
|
||||||
self?.activateSearch(filter: filter, query: query, skipScrolling: true)
|
self?.activateSearch(filter: filter, query: query, skipScrolling: true)
|
||||||
})
|
})
|
||||||
return
|
return
|
||||||
}
|
}*/
|
||||||
|
//TODO:scroll to top?
|
||||||
|
|
||||||
let _ = (combineLatest(self.chatListDisplayNode.mainContainerNode.currentItemNode.contentsReady |> take(1), self.context.account.postbox.tailChatListView(groupId: .root, count: 16, summaryComponents: ChatListEntrySummaryComponents(components: [:])) |> take(1))
|
let _ = (combineLatest(self.chatListDisplayNode.mainContainerNode.currentItemNode.contentsReady |> take(1), self.context.account.postbox.tailChatListView(groupId: .root, count: 16, summaryComponents: ChatListEntrySummaryComponents(components: [:])) |> take(1))
|
||||||
|> deliverOnMainQueue).start(next: { [weak self] _, chatListView in
|
|> deliverOnMainQueue).start(next: { [weak self] _, chatListView in
|
||||||
@ -3492,28 +3491,26 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
|
|||||||
})
|
})
|
||||||
snapshotView.layer.animatePosition(from: CGPoint(), to: CGPoint(x: 0.0, y: -strongSelf.storyListHeight), duration: 0.4, timingFunction: kCAMediaTimingFunctionSpring, removeOnCompletion: false)
|
snapshotView.layer.animatePosition(from: CGPoint(), to: CGPoint(x: 0.0, y: -strongSelf.storyListHeight), duration: 0.4, timingFunction: kCAMediaTimingFunctionSpring, removeOnCompletion: false)
|
||||||
}
|
}
|
||||||
|
|
||||||
if let searchContentNode = strongSelf.searchContentNode {
|
if let filterContainerNodeAndActivate = strongSelf.chatListDisplayNode.activateSearch(placeholderNode: searchContentNode.placeholderNode, displaySearchFilters: displaySearchFilters, hasDownloads: strongSelf.hasDownloads, initialFilter: filter, navigationController: strongSelf.navigationController as? NavigationController) {
|
||||||
if let filterContainerNodeAndActivate = strongSelf.chatListDisplayNode.activateSearch(placeholderNode: searchContentNode.placeholderNode, displaySearchFilters: displaySearchFilters, hasDownloads: strongSelf.hasDownloads, initialFilter: filter, navigationController: strongSelf.navigationController as? NavigationController) {
|
let (filterContainerNode, activate) = filterContainerNodeAndActivate
|
||||||
let (filterContainerNode, activate) = filterContainerNodeAndActivate
|
if displaySearchFilters {
|
||||||
if displaySearchFilters {
|
//TODO:search filters
|
||||||
strongSelf.navigationBar?.secondaryContentHeight = NavigationBar.defaultSecondaryContentHeight
|
strongSelf.navigationBar?.secondaryContentHeight = NavigationBar.defaultSecondaryContentHeight
|
||||||
strongSelf.navigationBar?.setSecondaryContentNode(filterContainerNode, animated: false)
|
strongSelf.navigationBar?.setSecondaryContentNode(filterContainerNode, animated: false)
|
||||||
}
|
}
|
||||||
strongSelf.searchContentNode?.additionalHeight = 0.0
|
|
||||||
|
activate(filter != .downloads)
|
||||||
activate(filter != .downloads)
|
|
||||||
|
if let searchContentNode = strongSelf.chatListDisplayNode.searchDisplayController?.contentNode as? ChatListSearchContainerNode {
|
||||||
if let searchContentNode = strongSelf.chatListDisplayNode.searchDisplayController?.contentNode as? ChatListSearchContainerNode {
|
searchContentNode.search(filter: filter, query: query)
|
||||||
searchContentNode.search(filter: filter, query: query)
|
}
|
||||||
}
|
|
||||||
|
let tabsOffset = 30.0 + strongSelf.storyListHeight
|
||||||
let tabsOffset = 30.0 + strongSelf.storyListHeight
|
|
||||||
|
Queue.mainQueue().justDispatch {
|
||||||
Queue.mainQueue().justDispatch {
|
filterContainerNode.layer.animatePosition(from: CGPoint(x: 0.0, y: tabsOffset), to: CGPoint(), duration: 0.4, timingFunction: kCAMediaTimingFunctionSpring, additive: true)
|
||||||
filterContainerNode.layer.animatePosition(from: CGPoint(x: 0.0, y: tabsOffset), to: CGPoint(), duration: 0.4, timingFunction: kCAMediaTimingFunctionSpring, additive: true)
|
filterContainerNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.3)
|
||||||
filterContainerNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.3)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3552,6 +3549,12 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
|
|||||||
|
|
||||||
|
|
||||||
var filterContainerNode: ASDisplayNode?
|
var filterContainerNode: ASDisplayNode?
|
||||||
|
|
||||||
|
var searchContentNode: NavigationBarSearchContentNode?
|
||||||
|
if let navigationBarView = self.chatListDisplayNode.navigationBarView.view as? ChatListNavigationBar.View {
|
||||||
|
searchContentNode = navigationBarView.searchContentNode
|
||||||
|
}
|
||||||
|
|
||||||
if animated, let searchContentNode = self.chatListDisplayNode.searchDisplayController?.contentNode as? ChatListSearchContainerNode {
|
if animated, let searchContentNode = self.chatListDisplayNode.searchDisplayController?.contentNode as? ChatListSearchContainerNode {
|
||||||
filterContainerNode = searchContentNode.filterContainerNode
|
filterContainerNode = searchContentNode.filterContainerNode
|
||||||
|
|
||||||
@ -3573,7 +3576,7 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if let searchContentNode = self.searchContentNode {
|
if let searchContentNode {
|
||||||
let previousFrame = searchContentNode.placeholderNode.frame
|
let previousFrame = searchContentNode.placeholderNode.frame
|
||||||
if case .chatList(.root) = self.location {
|
if case .chatList(.root) = self.location {
|
||||||
searchContentNode.placeholderNode.frame = previousFrame.offsetBy(dx: 0.0, dy: 94.0)
|
searchContentNode.placeholderNode.frame = previousFrame.offsetBy(dx: 0.0, dy: 94.0)
|
||||||
@ -3582,10 +3585,13 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
|
|||||||
searchContentNode.placeholderNode.frame = previousFrame
|
searchContentNode.placeholderNode.frame = previousFrame
|
||||||
}
|
}
|
||||||
|
|
||||||
|
self.requestLayout(transition: .animated(duration: 0.5, curve: .spring))
|
||||||
|
|
||||||
self.navigationBar?.secondaryContentHeight = (!tabsIsEmpty ? NavigationBar.defaultSecondaryContentHeight : 0.0)
|
self.navigationBar?.secondaryContentHeight = (!tabsIsEmpty ? NavigationBar.defaultSecondaryContentHeight : 0.0)
|
||||||
if case .chatList(.root) = self.location {
|
//TODO:move layout to navigation bar
|
||||||
|
/*if case .chatList(.root) = self.location {
|
||||||
self.searchContentNode?.additionalHeight = self.storyListHeight
|
self.searchContentNode?.additionalHeight = self.storyListHeight
|
||||||
}
|
}*/
|
||||||
self.navigationBar?.setSecondaryContentNode(self.navigationSecondaryContentNode, animated: false)
|
self.navigationBar?.setSecondaryContentNode(self.navigationSecondaryContentNode, animated: false)
|
||||||
|
|
||||||
let transition: ContainedViewLayoutTransition = animated ? .animated(duration: 0.4, curve: .spring) : .immediate
|
let transition: ContainedViewLayoutTransition = animated ? .animated(duration: 0.4, curve: .spring) : .immediate
|
||||||
@ -5539,7 +5545,7 @@ private final class ChatListLocationContext {
|
|||||||
self.ready.set(.single(true))
|
self.ready.set(.single(true))
|
||||||
}
|
}
|
||||||
|
|
||||||
self.parentController?.requestUpdateHeaderContent(transition: .immediate)
|
self.parentController?.requestLayout(transition: .immediate)
|
||||||
}
|
}
|
||||||
|
|
||||||
private func updateForum(
|
private func updateForum(
|
||||||
@ -5631,7 +5637,7 @@ private final class ChatListLocationContext {
|
|||||||
navigationController.replaceController(parentController, with: chatController, animated: true)
|
navigationController.replaceController(parentController, with: chatController, animated: true)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
self.parentController?.requestUpdateHeaderContent(transition: .immediate)
|
self.parentController?.requestLayout(transition: .immediate)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -18,6 +18,7 @@ import ActionPanelComponent
|
|||||||
import ComponentDisplayAdapters
|
import ComponentDisplayAdapters
|
||||||
import ComponentFlow
|
import ComponentFlow
|
||||||
import ChatFolderLinkPreviewScreen
|
import ChatFolderLinkPreviewScreen
|
||||||
|
import ChatListHeaderComponent
|
||||||
|
|
||||||
public enum ChatListContainerNodeFilter: Equatable {
|
public enum ChatListContainerNodeFilter: Equatable {
|
||||||
case all
|
case all
|
||||||
@ -876,7 +877,11 @@ public final class ChatListContainerNode: ASDisplayNode, UIGestureRecognizerDele
|
|||||||
self?.updatePeerGrouping?(peerId, group)
|
self?.updatePeerGrouping?(peerId, group)
|
||||||
}
|
}
|
||||||
itemNode.listNode.contentOffsetChanged = { [weak self] offset in
|
itemNode.listNode.contentOffsetChanged = { [weak self] offset in
|
||||||
self?.contentOffsetChanged?(offset)
|
guard let self else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
self.contentOffset = offset
|
||||||
|
self.contentOffsetChanged?(offset)
|
||||||
}
|
}
|
||||||
itemNode.listNode.contentScrollingEnded = { [weak self] listView in
|
itemNode.listNode.contentScrollingEnded = { [weak self] listView in
|
||||||
return self?.contentScrollingEnded?(listView) ?? false
|
return self?.contentScrollingEnded?(listView) ?? false
|
||||||
@ -947,6 +952,7 @@ public final class ChatListContainerNode: ASDisplayNode, UIGestureRecognizerDele
|
|||||||
public var peerSelected: ((EnginePeer, Int64?, Bool, Bool, ChatListNodeEntryPromoInfo?) -> Void)?
|
public var peerSelected: ((EnginePeer, Int64?, Bool, Bool, ChatListNodeEntryPromoInfo?) -> Void)?
|
||||||
var groupSelected: ((EngineChatList.Group) -> Void)?
|
var groupSelected: ((EngineChatList.Group) -> Void)?
|
||||||
var updatePeerGrouping: ((EnginePeer.Id, Bool) -> Void)?
|
var updatePeerGrouping: ((EnginePeer.Id, Bool) -> Void)?
|
||||||
|
var contentOffset: ListViewVisibleContentOffset?
|
||||||
public var contentOffsetChanged: ((ListViewVisibleContentOffset) -> Void)?
|
public var contentOffsetChanged: ((ListViewVisibleContentOffset) -> Void)?
|
||||||
public var contentScrollingEnded: ((ListView) -> Bool)?
|
public var contentScrollingEnded: ((ListView) -> Bool)?
|
||||||
var activateChatPreview: ((ChatListItem, Int64?, ASDisplayNode, ContextGesture?, CGPoint?) -> Void)?
|
var activateChatPreview: ((ChatListItem, Int64?, ASDisplayNode, ContextGesture?, CGPoint?) -> Void)?
|
||||||
@ -1490,12 +1496,15 @@ final class ChatListControllerNode: ASDisplayNode, UIGestureRecognizerDelegate {
|
|||||||
|
|
||||||
private var tapRecognizer: UITapGestureRecognizer?
|
private var tapRecognizer: UITapGestureRecognizer?
|
||||||
var navigationBar: NavigationBar?
|
var navigationBar: NavigationBar?
|
||||||
|
let navigationBarView = ComponentView<Empty>()
|
||||||
weak var controller: ChatListControllerImpl?
|
weak var controller: ChatListControllerImpl?
|
||||||
|
|
||||||
var toolbar: Toolbar?
|
var toolbar: Toolbar?
|
||||||
private var toolbarNode: ToolbarNode?
|
private var toolbarNode: ToolbarNode?
|
||||||
var toolbarActionSelected: ((ToolbarActionOption) -> Void)?
|
var toolbarActionSelected: ((ToolbarActionOption) -> Void)?
|
||||||
|
|
||||||
|
private var isSearchDisplayControllerActive: Bool = false
|
||||||
|
private var skipSearchDisplayControllerLayout: Bool = false
|
||||||
private(set) var searchDisplayController: SearchDisplayController?
|
private(set) var searchDisplayController: SearchDisplayController?
|
||||||
|
|
||||||
var isReorderingFilters: Bool = false
|
var isReorderingFilters: Bool = false
|
||||||
@ -1504,7 +1513,6 @@ final class ChatListControllerNode: ASDisplayNode, UIGestureRecognizerDelegate {
|
|||||||
|
|
||||||
private var containerLayout: (layout: ContainerViewLayout, navigationBarHeight: CGFloat, visualNavigationHeight: CGFloat, cleanNavigationBarHeight: CGFloat, storiesInset: CGFloat)?
|
private var containerLayout: (layout: ContainerViewLayout, navigationBarHeight: CGFloat, visualNavigationHeight: CGFloat, cleanNavigationBarHeight: CGFloat, storiesInset: CGFloat)?
|
||||||
|
|
||||||
var contentOffsetChanged: ((ListViewVisibleContentOffset) -> Void)?
|
|
||||||
var contentScrollingEnded: ((ListView) -> Bool)?
|
var contentScrollingEnded: ((ListView) -> Bool)?
|
||||||
|
|
||||||
var requestDeactivateSearch: (() -> Void)?
|
var requestDeactivateSearch: (() -> Void)?
|
||||||
@ -1695,7 +1703,105 @@ final class ChatListControllerNode: ASDisplayNode, UIGestureRecognizerDelegate {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private func updateNavigationBar(layout: ContainerViewLayout, transition: ContainedViewLayoutTransition) -> (navigationHeight: CGFloat, storiesInset: CGFloat) {
|
||||||
|
let headerContent = self.controller?.updateHeaderContent(layout: layout, transition: transition)
|
||||||
|
|
||||||
|
let navigationBarSize = self.navigationBarView.update(
|
||||||
|
transition: Transition(transition),
|
||||||
|
component: AnyComponent(ChatListNavigationBar(
|
||||||
|
context: self.context,
|
||||||
|
theme: self.presentationData.theme,
|
||||||
|
strings: self.presentationData.strings,
|
||||||
|
statusBarHeight: layout.statusBarHeight ?? 0.0,
|
||||||
|
sideInset: layout.safeInsets.left,
|
||||||
|
isSearchActive: self.isSearchDisplayControllerActive,
|
||||||
|
primaryContent: headerContent?.primaryContent,
|
||||||
|
secondaryContent: headerContent?.secondaryContent,
|
||||||
|
secondaryTransition: self.inlineStackContainerTransitionFraction,
|
||||||
|
storySubscriptions: self.controller?.storySubscriptions,
|
||||||
|
activateSearch: { [weak self] searchContentNode in
|
||||||
|
guard let self, let controller = self.controller else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
var isForum = false
|
||||||
|
if case .forum = controller.location {
|
||||||
|
isForum = true
|
||||||
|
}
|
||||||
|
|
||||||
|
let filter: ChatListSearchFilter = isForum ? .topics : .chats
|
||||||
|
|
||||||
|
controller.activateSearch(
|
||||||
|
filter: filter,
|
||||||
|
query: nil,
|
||||||
|
skipScrolling: false,
|
||||||
|
searchContentNode: searchContentNode
|
||||||
|
)
|
||||||
|
},
|
||||||
|
openStatusSetup: { [weak self] sourceView in
|
||||||
|
guard let self, let controller = self.controller else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
controller.openStatusSetup(sourceView: sourceView)
|
||||||
|
}
|
||||||
|
)),
|
||||||
|
environment: {},
|
||||||
|
containerSize: layout.size
|
||||||
|
)
|
||||||
|
if let navigationBarComponentView = self.navigationBarView.view as? ChatListNavigationBar.View {
|
||||||
|
navigationBarComponentView.deferScrollApplication = true
|
||||||
|
|
||||||
|
if navigationBarComponentView.superview == nil {
|
||||||
|
self.view.addSubview(navigationBarComponentView)
|
||||||
|
}
|
||||||
|
transition.updateFrame(view: navigationBarComponentView, frame: CGRect(origin: CGPoint(), size: navigationBarSize))
|
||||||
|
|
||||||
|
return (navigationBarSize.height, navigationBarComponentView.effectiveStoriesInsetHeight)
|
||||||
|
} else {
|
||||||
|
return (0.0, 0.0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private func updateNavigationScrolling(transition: ContainedViewLayoutTransition) {
|
||||||
|
let mainOffset: CGFloat
|
||||||
|
if let contentOffset = self.mainContainerNode.contentOffset, case let .known(value) = contentOffset {
|
||||||
|
mainOffset = value
|
||||||
|
} else {
|
||||||
|
mainOffset = 1000.0
|
||||||
|
}
|
||||||
|
|
||||||
|
let resultingOffset: CGFloat
|
||||||
|
if let inlineStackContainerNode = self.inlineStackContainerNode {
|
||||||
|
let inlineOffset: CGFloat
|
||||||
|
if let contentOffset = inlineStackContainerNode.contentOffset, case let .known(value) = contentOffset {
|
||||||
|
inlineOffset = value
|
||||||
|
} else {
|
||||||
|
inlineOffset = 1000.0
|
||||||
|
}
|
||||||
|
|
||||||
|
resultingOffset = mainOffset * (1.0 - self.inlineStackContainerTransitionFraction) + inlineOffset * self.inlineStackContainerTransitionFraction
|
||||||
|
} else {
|
||||||
|
resultingOffset = mainOffset
|
||||||
|
}
|
||||||
|
|
||||||
|
if let navigationBarComponentView = self.navigationBarView.view as? ChatListNavigationBar.View {
|
||||||
|
navigationBarComponentView.applyScroll(offset: resultingOffset, transition: Transition(transition))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func containerLayoutUpdated(_ layout: ContainerViewLayout, navigationBarHeight: CGFloat, visualNavigationHeight: CGFloat, cleanNavigationBarHeight: CGFloat, storiesInset: CGFloat, transition: ContainedViewLayoutTransition) {
|
func containerLayoutUpdated(_ layout: ContainerViewLayout, navigationBarHeight: CGFloat, visualNavigationHeight: CGFloat, cleanNavigationBarHeight: CGFloat, storiesInset: CGFloat, transition: ContainedViewLayoutTransition) {
|
||||||
|
var navigationBarHeight = navigationBarHeight
|
||||||
|
var visualNavigationHeight = visualNavigationHeight
|
||||||
|
var cleanNavigationBarHeight = cleanNavigationBarHeight
|
||||||
|
var storiesInset = storiesInset
|
||||||
|
|
||||||
|
let navigationBarLayout = self.updateNavigationBar(layout: layout, transition: transition)
|
||||||
|
|
||||||
|
navigationBarHeight = navigationBarLayout.navigationHeight
|
||||||
|
visualNavigationHeight = navigationBarLayout.navigationHeight
|
||||||
|
cleanNavigationBarHeight = navigationBarLayout.navigationHeight
|
||||||
|
storiesInset = navigationBarLayout.storiesInset
|
||||||
|
|
||||||
self.containerLayout = (layout, navigationBarHeight, visualNavigationHeight, cleanNavigationBarHeight, storiesInset)
|
self.containerLayout = (layout, navigationBarHeight, visualNavigationHeight, cleanNavigationBarHeight, storiesInset)
|
||||||
|
|
||||||
var insets = layout.insets(options: [.input])
|
var insets = layout.insets(options: [.input])
|
||||||
@ -1789,7 +1895,9 @@ final class ChatListControllerNode: ASDisplayNode, UIGestureRecognizerDelegate {
|
|||||||
var inlineInsets = insets
|
var inlineInsets = insets
|
||||||
inlineInsets.left = 0.0
|
inlineInsets.left = 0.0
|
||||||
|
|
||||||
inlineStackContainerNode.update(layout: inlineLayout, navigationBarHeight: navigationBarHeight, visualNavigationHeight: visualNavigationHeight, originalNavigationHeight: navigationBarHeight, cleanNavigationBarHeight: cleanNavigationBarHeight, insets: inlineInsets, isReorderingFilters: self.isReorderingFilters, isEditing: self.isEditing, inlineNavigationLocation: nil, inlineNavigationTransitionFraction: 0.0, storiesInset: storiesInset, transition: inlineStackContainerNodeTransition)
|
let inlineNavigationHeight: CGFloat = navigationBarLayout.navigationHeight - navigationBarLayout.storiesInset
|
||||||
|
|
||||||
|
inlineStackContainerNode.update(layout: inlineLayout, navigationBarHeight: inlineNavigationHeight, visualNavigationHeight: inlineNavigationHeight, originalNavigationHeight: inlineNavigationHeight, cleanNavigationBarHeight: inlineNavigationHeight, insets: inlineInsets, isReorderingFilters: self.isReorderingFilters, isEditing: self.isEditing, inlineNavigationLocation: nil, inlineNavigationTransitionFraction: 0.0, storiesInset: storiesInset, transition: inlineStackContainerNodeTransition)
|
||||||
|
|
||||||
if animateIn {
|
if animateIn {
|
||||||
transition.animatePosition(node: inlineStackContainerNode, from: CGPoint(x: inlineStackContainerNode.position.x + inlineStackContainerNode.bounds.width + UIScreenPixel, y: inlineStackContainerNode.position.y))
|
transition.animatePosition(node: inlineStackContainerNode, from: CGPoint(x: inlineStackContainerNode.position.x + inlineStackContainerNode.bounds.width + UIScreenPixel, y: inlineStackContainerNode.position.y))
|
||||||
@ -1799,12 +1907,21 @@ final class ChatListControllerNode: ASDisplayNode, UIGestureRecognizerDelegate {
|
|||||||
self.tapRecognizer?.isEnabled = self.isReorderingFilters
|
self.tapRecognizer?.isEnabled = self.isReorderingFilters
|
||||||
|
|
||||||
if let searchDisplayController = self.searchDisplayController {
|
if let searchDisplayController = self.searchDisplayController {
|
||||||
searchDisplayController.containerLayoutUpdated(layout, navigationBarHeight: cleanNavigationBarHeight, transition: transition)
|
if !self.skipSearchDisplayControllerLayout {
|
||||||
|
searchDisplayController.containerLayoutUpdated(layout, navigationBarHeight: cleanNavigationBarHeight, transition: transition)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
self.updateNavigationScrolling(transition: transition)
|
||||||
|
|
||||||
|
if let navigationBarComponentView = self.navigationBarView.view as? ChatListNavigationBar.View {
|
||||||
|
navigationBarComponentView.deferScrollApplication = false
|
||||||
|
navigationBarComponentView.applyCurrentScroll(transition: Transition(transition))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func activateSearch(placeholderNode: SearchBarPlaceholderNode, displaySearchFilters: Bool, hasDownloads: Bool, initialFilter: ChatListSearchFilter, navigationController: NavigationController?) -> (ASDisplayNode, (Bool) -> Void)? {
|
func activateSearch(placeholderNode: SearchBarPlaceholderNode, displaySearchFilters: Bool, hasDownloads: Bool, initialFilter: ChatListSearchFilter, navigationController: NavigationController?) -> (ASDisplayNode, (Bool) -> Void)? {
|
||||||
guard let (containerLayout, _, _, cleanNavigationBarHeight, _) = self.containerLayout, let navigationBar = self.navigationBar, self.searchDisplayController == nil else {
|
guard let (containerLayout, _, _, cleanNavigationBarHeight, _) = self.containerLayout, self.searchDisplayController == nil else {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1834,7 +1951,7 @@ final class ChatListControllerNode: ASDisplayNode, UIGestureRecognizerDelegate {
|
|||||||
self?.controller?.presentInGlobalOverlay(c, with: a)
|
self?.controller?.presentInGlobalOverlay(c, with: a)
|
||||||
}, navigationController: navigationController)
|
}, navigationController: navigationController)
|
||||||
|
|
||||||
self.searchDisplayController = SearchDisplayController(presentationData: self.presentationData, contentNode: contentNode, cancel: { [weak self] in
|
self.searchDisplayController = SearchDisplayController(presentationData: self.presentationData, mode: .list, contentNode: contentNode, cancel: { [weak self] in
|
||||||
if let requestDeactivateSearch = self?.requestDeactivateSearch {
|
if let requestDeactivateSearch = self?.requestDeactivateSearch {
|
||||||
requestDeactivateSearch()
|
requestDeactivateSearch()
|
||||||
}
|
}
|
||||||
@ -1846,29 +1963,42 @@ final class ChatListControllerNode: ASDisplayNode, UIGestureRecognizerDelegate {
|
|||||||
guard let strongSelf = self else {
|
guard let strongSelf = self else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
strongSelf.isSearchDisplayControllerActive = true
|
||||||
|
|
||||||
strongSelf.searchDisplayController?.containerLayoutUpdated(containerLayout, navigationBarHeight: cleanNavigationBarHeight, transition: .immediate)
|
strongSelf.searchDisplayController?.containerLayoutUpdated(containerLayout, navigationBarHeight: cleanNavigationBarHeight, transition: .immediate)
|
||||||
strongSelf.searchDisplayController?.activate(insertSubnode: { [weak self, weak placeholderNode] subnode, isSearchBar in
|
strongSelf.searchDisplayController?.activate(insertSubnode: { [weak self] subnode, isSearchBar in
|
||||||
if let strongSelf = self, let strongPlaceholderNode = placeholderNode {
|
guard let self else {
|
||||||
if isSearchBar {
|
return
|
||||||
strongPlaceholderNode.supernode?.insertSubnode(subnode, aboveSubnode: strongPlaceholderNode)
|
}
|
||||||
} else {
|
|
||||||
strongSelf.insertSubnode(subnode, belowSubnode: navigationBar)
|
if isSearchBar {
|
||||||
|
if let navigationBarComponentView = self.navigationBarView.view as? ChatListNavigationBar.View {
|
||||||
|
navigationBarComponentView.addSubnode(subnode)
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
self.insertSubnode(subnode, aboveSubnode: self.debugListView)
|
||||||
}
|
}
|
||||||
}, placeholder: placeholderNode, focus: focus)
|
}, placeholder: placeholderNode, focus: focus)
|
||||||
|
|
||||||
|
strongSelf.controller?.requestLayout(transition: .animated(duration: 0.5, curve: .spring))
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func deactivateSearch(placeholderNode: SearchBarPlaceholderNode, animated: Bool) -> (() -> Void)? {
|
func deactivateSearch(placeholderNode: SearchBarPlaceholderNode, animated: Bool) -> (() -> Void)? {
|
||||||
if let searchDisplayController = self.searchDisplayController {
|
if let searchDisplayController = self.searchDisplayController {
|
||||||
searchDisplayController.deactivate(placeholder: placeholderNode, animated: animated)
|
self.isSearchDisplayControllerActive = false
|
||||||
self.searchDisplayController = nil
|
self.searchDisplayController = nil
|
||||||
self.mainContainerNode.accessibilityElementsHidden = false
|
self.mainContainerNode.accessibilityElementsHidden = false
|
||||||
self.inlineStackContainerNode?.accessibilityElementsHidden = false
|
self.inlineStackContainerNode?.accessibilityElementsHidden = false
|
||||||
|
|
||||||
return { [weak self] in
|
return { [weak self] in
|
||||||
if let strongSelf = self, let (layout, _, _, cleanNavigationBarHeight, _) = strongSelf.containerLayout {
|
if let strongSelf = self, let (layout, _, _, cleanNavigationBarHeight, _) = strongSelf.containerLayout {
|
||||||
|
searchDisplayController.deactivate(placeholder: placeholderNode, animated: animated)
|
||||||
|
|
||||||
searchDisplayController.containerLayoutUpdated(layout, navigationBarHeight: cleanNavigationBarHeight, transition: .animated(duration: 0.4, curve: .spring))
|
searchDisplayController.containerLayoutUpdated(layout, navigationBarHeight: cleanNavigationBarHeight, transition: .animated(duration: 0.4, curve: .spring))
|
||||||
|
|
||||||
|
strongSelf.controller?.requestLayout(transition: .animated(duration: 0.4, curve: .spring))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -1884,15 +2014,17 @@ final class ChatListControllerNode: ASDisplayNode, UIGestureRecognizerDelegate {
|
|||||||
private var contentOffsetSyncLockedIn: Bool = false
|
private var contentOffsetSyncLockedIn: Bool = false
|
||||||
|
|
||||||
private func contentOffsetChanged(offset: ListViewVisibleContentOffset, isPrimary: Bool) {
|
private func contentOffsetChanged(offset: ListViewVisibleContentOffset, isPrimary: Bool) {
|
||||||
guard let inlineStackContainerNode = self.inlineStackContainerNode else {
|
|
||||||
self.contentOffsetChanged?(offset)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
guard let containerLayout = self.containerLayout else {
|
guard let containerLayout = self.containerLayout else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
let _ = containerLayout
|
||||||
|
if let inlineStackContainerNode = self.inlineStackContainerNode {
|
||||||
|
let _ = inlineStackContainerNode
|
||||||
|
}
|
||||||
|
|
||||||
if !isPrimary {
|
self.updateNavigationScrolling(transition: .immediate)
|
||||||
|
|
||||||
|
/*if !isPrimary {
|
||||||
self.contentOffsetChanged?(offset)
|
self.contentOffsetChanged?(offset)
|
||||||
if "".isEmpty {
|
if "".isEmpty {
|
||||||
return
|
return
|
||||||
@ -1933,7 +2065,7 @@ final class ChatListControllerNode: ASDisplayNode, UIGestureRecognizerDelegate {
|
|||||||
if !isPrimary {
|
if !isPrimary {
|
||||||
self.contentOffsetChanged?(offset)
|
self.contentOffsetChanged?(offset)
|
||||||
}
|
}
|
||||||
}
|
}*/
|
||||||
}
|
}
|
||||||
|
|
||||||
private func contentScrollingEnded(listView: ListView, isPrimary: Bool) -> Bool {
|
private func contentScrollingEnded(listView: ListView, isPrimary: Bool) -> Bool {
|
||||||
|
@ -3258,7 +3258,6 @@ public final class ChatListNode: ListView {
|
|||||||
|
|
||||||
if let previousStoriesInset = self.previousStoriesInset {
|
if let previousStoriesInset = self.previousStoriesInset {
|
||||||
additionalScrollDistance += previousStoriesInset - storiesInset
|
additionalScrollDistance += previousStoriesInset - storiesInset
|
||||||
additionalScrollDistance = 0.0
|
|
||||||
}
|
}
|
||||||
self.previousStoriesInset = storiesInset
|
self.previousStoriesInset = storiesInset
|
||||||
//print("storiesInset: \(storiesInset), additionalScrollDistance: \(additionalScrollDistance)")
|
//print("storiesInset: \(storiesInset), additionalScrollDistance: \(additionalScrollDistance)")
|
||||||
|
@ -1012,7 +1012,7 @@ public class SearchBarNode: ASDisplayNode, UITextFieldDelegate {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public func animateIn(from node: SearchBarPlaceholderNode, duration: Double, timingFunction: String) {
|
public func animateIn(from node: SearchBarPlaceholderNode, duration: Double, timingFunction: String) {
|
||||||
let initialTextBackgroundFrame = node.convert(node.backgroundNode.frame, to: self)
|
let initialTextBackgroundFrame = node.view.convert(node.backgroundNode.frame, to: self.view)
|
||||||
|
|
||||||
let initialBackgroundFrame = CGRect(origin: CGPoint(x: 0.0, y: 0.0), size: CGSize(width: self.bounds.size.width, height: max(0.0, initialTextBackgroundFrame.maxY + 8.0)))
|
let initialBackgroundFrame = CGRect(origin: CGPoint(x: 0.0, y: 0.0), size: CGSize(width: self.bounds.size.width, height: max(0.0, initialTextBackgroundFrame.maxY + 8.0)))
|
||||||
if let fromBackgroundColor = node.backgroundColor, let toBackgroundColor = self.backgroundNode.backgroundColor {
|
if let fromBackgroundColor = node.backgroundColor, let toBackgroundColor = self.backgroundNode.backgroundColor {
|
||||||
@ -1060,7 +1060,7 @@ public class SearchBarNode: ASDisplayNode, UITextFieldDelegate {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public func transitionOut(to node: SearchBarPlaceholderNode, transition: ContainedViewLayoutTransition, completion: @escaping () -> Void) {
|
public func transitionOut(to node: SearchBarPlaceholderNode, transition: ContainedViewLayoutTransition, completion: @escaping () -> Void) {
|
||||||
let targetTextBackgroundFrame = node.convert(node.backgroundNode.frame, to: self)
|
let targetTextBackgroundFrame = node.view.convert(node.backgroundNode.frame, to: self.view)
|
||||||
|
|
||||||
let duration: Double = transition.isAnimated ? 0.5 : 0.0
|
let duration: Double = transition.isAnimated ? 0.5 : 0.0
|
||||||
let timingFunction = kCAMediaTimingFunctionSpring
|
let timingFunction = kCAMediaTimingFunctionSpring
|
||||||
|
@ -18,7 +18,7 @@ public class NavigationBarSearchContentNode: NavigationBarContentNode {
|
|||||||
public var placeholderHeight: CGFloat?
|
public var placeholderHeight: CGFloat?
|
||||||
private var disabledOverlay: ASDisplayNode?
|
private var disabledOverlay: ASDisplayNode?
|
||||||
|
|
||||||
public private(set) var expansionProgress: CGFloat = 1.0
|
public var expansionProgress: CGFloat = 1.0
|
||||||
|
|
||||||
public var additionalHeight: CGFloat = 0.0
|
public var additionalHeight: CGFloat = 0.0
|
||||||
|
|
||||||
@ -103,7 +103,7 @@ public class NavigationBarSearchContentNode: NavigationBarContentNode {
|
|||||||
|
|
||||||
private func updatePlaceholder(_ progress: CGFloat, size: CGSize, leftInset: CGFloat, rightInset: CGFloat, transition: ContainedViewLayoutTransition) {
|
private func updatePlaceholder(_ progress: CGFloat, size: CGSize, leftInset: CGFloat, rightInset: CGFloat, transition: ContainedViewLayoutTransition) {
|
||||||
let padding: CGFloat = 10.0
|
let padding: CGFloat = 10.0
|
||||||
let baseWidth = self.bounds.width - padding * 2.0 - leftInset - rightInset
|
let baseWidth = size.width - padding * 2.0 - leftInset - rightInset
|
||||||
|
|
||||||
let fieldHeight: CGFloat = 36.0
|
let fieldHeight: CGFloat = 36.0
|
||||||
let fraction = fieldHeight / self.nominalHeight
|
let fraction = fieldHeight / self.nominalHeight
|
||||||
|
@ -21,6 +21,8 @@ swift_library(
|
|||||||
"//submodules/AsyncDisplayKit",
|
"//submodules/AsyncDisplayKit",
|
||||||
"//submodules/AnimationUI",
|
"//submodules/AnimationUI",
|
||||||
"//submodules/TelegramUI/Components/Stories/StoryPeerListComponent",
|
"//submodules/TelegramUI/Components/Stories/StoryPeerListComponent",
|
||||||
|
"//submodules/Components/ComponentDisplayAdapters",
|
||||||
|
"//submodules/SearchUI",
|
||||||
],
|
],
|
||||||
visibility = [
|
visibility = [
|
||||||
"//visibility:public",
|
"//visibility:public",
|
||||||
|
@ -0,0 +1,345 @@
|
|||||||
|
import Foundation
|
||||||
|
import UIKit
|
||||||
|
import Display
|
||||||
|
import AsyncDisplayKit
|
||||||
|
import ComponentFlow
|
||||||
|
import TelegramPresentationData
|
||||||
|
import ComponentDisplayAdapters
|
||||||
|
import SearchUI
|
||||||
|
import AccountContext
|
||||||
|
import TelegramCore
|
||||||
|
|
||||||
|
public final class ChatListNavigationBar: Component {
|
||||||
|
public let context: AccountContext
|
||||||
|
public let theme: PresentationTheme
|
||||||
|
public let strings: PresentationStrings
|
||||||
|
public let statusBarHeight: CGFloat
|
||||||
|
public let sideInset: CGFloat
|
||||||
|
public let isSearchActive: Bool
|
||||||
|
public let primaryContent: ChatListHeaderComponent.Content?
|
||||||
|
public let secondaryContent: ChatListHeaderComponent.Content?
|
||||||
|
public let secondaryTransition: CGFloat
|
||||||
|
public let storySubscriptions: EngineStorySubscriptions?
|
||||||
|
public let activateSearch: (NavigationBarSearchContentNode) -> Void
|
||||||
|
public let openStatusSetup: (UIView) -> Void
|
||||||
|
|
||||||
|
public init(
|
||||||
|
context: AccountContext,
|
||||||
|
theme: PresentationTheme,
|
||||||
|
strings: PresentationStrings,
|
||||||
|
statusBarHeight: CGFloat,
|
||||||
|
sideInset: CGFloat,
|
||||||
|
isSearchActive: Bool,
|
||||||
|
primaryContent: ChatListHeaderComponent.Content?,
|
||||||
|
secondaryContent: ChatListHeaderComponent.Content?,
|
||||||
|
secondaryTransition: CGFloat,
|
||||||
|
storySubscriptions: EngineStorySubscriptions?,
|
||||||
|
activateSearch: @escaping (NavigationBarSearchContentNode) -> Void,
|
||||||
|
openStatusSetup: @escaping (UIView) -> Void
|
||||||
|
) {
|
||||||
|
self.context = context
|
||||||
|
self.theme = theme
|
||||||
|
self.strings = strings
|
||||||
|
self.statusBarHeight = statusBarHeight
|
||||||
|
self.sideInset = sideInset
|
||||||
|
self.isSearchActive = isSearchActive
|
||||||
|
self.primaryContent = primaryContent
|
||||||
|
self.secondaryContent = secondaryContent
|
||||||
|
self.secondaryTransition = secondaryTransition
|
||||||
|
self.storySubscriptions = storySubscriptions
|
||||||
|
self.activateSearch = activateSearch
|
||||||
|
self.openStatusSetup = openStatusSetup
|
||||||
|
}
|
||||||
|
|
||||||
|
public static func ==(lhs: ChatListNavigationBar, rhs: ChatListNavigationBar) -> Bool {
|
||||||
|
if lhs.context !== rhs.context {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if lhs.theme !== rhs.theme {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if lhs.strings !== rhs.strings {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if lhs.statusBarHeight != rhs.statusBarHeight {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if lhs.sideInset != rhs.sideInset {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if lhs.isSearchActive != rhs.isSearchActive {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if lhs.primaryContent != rhs.primaryContent {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if lhs.secondaryContent != rhs.secondaryContent {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if lhs.secondaryTransition != rhs.secondaryTransition {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if lhs.storySubscriptions != rhs.storySubscriptions {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
private struct CurrentLayout {
|
||||||
|
var size: CGSize
|
||||||
|
|
||||||
|
init(size: CGSize) {
|
||||||
|
self.size = size
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public final class View: UIView {
|
||||||
|
private let backgroundView: BlurredBackgroundView
|
||||||
|
private let separatorLayer: SimpleLayer
|
||||||
|
|
||||||
|
public let headerContent = ComponentView<Empty>()
|
||||||
|
|
||||||
|
public private(set) var searchContentNode: NavigationBarSearchContentNode?
|
||||||
|
|
||||||
|
private var component: ChatListNavigationBar?
|
||||||
|
private weak var state: EmptyComponentState?
|
||||||
|
|
||||||
|
private var scrollTheme: PresentationTheme?
|
||||||
|
private var scrollStrings: PresentationStrings?
|
||||||
|
|
||||||
|
private var currentLayout: CurrentLayout?
|
||||||
|
private var rawScrollOffset: CGFloat?
|
||||||
|
private var clippedScrollOffset: CGFloat?
|
||||||
|
|
||||||
|
public var deferScrollApplication: Bool = false
|
||||||
|
private var hasDeferredScrollOffset: Bool = false
|
||||||
|
|
||||||
|
public private(set) var effectiveStoriesInsetHeight: CGFloat = 0.0
|
||||||
|
|
||||||
|
override public init(frame: CGRect) {
|
||||||
|
self.backgroundView = BlurredBackgroundView(color: .clear, enableBlur: true)
|
||||||
|
self.separatorLayer = SimpleLayer()
|
||||||
|
|
||||||
|
super.init(frame: frame)
|
||||||
|
|
||||||
|
self.addSubview(self.backgroundView)
|
||||||
|
self.layer.addSublayer(self.separatorLayer)
|
||||||
|
}
|
||||||
|
|
||||||
|
required init?(coder: NSCoder) {
|
||||||
|
fatalError("init(coder:) has not been implemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
override public func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
|
||||||
|
if !self.backgroundView.frame.contains(point) {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
guard let result = super.hitTest(point, with: event) else {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
public func applyCurrentScroll(transition: Transition) {
|
||||||
|
if let rawScrollOffset = self.rawScrollOffset, self.hasDeferredScrollOffset {
|
||||||
|
self.applyScroll(offset: rawScrollOffset, transition: transition)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public func applyScroll(offset: CGFloat, transition: Transition) {
|
||||||
|
self.rawScrollOffset = offset
|
||||||
|
|
||||||
|
if self.deferScrollApplication {
|
||||||
|
self.hasDeferredScrollOffset = true
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
guard let component = self.component, let currentLayout = self.currentLayout else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
let themeUpdated = component.theme !== self.scrollTheme || component.strings !== self.scrollStrings
|
||||||
|
|
||||||
|
self.scrollTheme = component.theme
|
||||||
|
self.scrollStrings = component.strings
|
||||||
|
|
||||||
|
let searchOffsetDistance: CGFloat = navigationBarSearchContentHeight
|
||||||
|
let defaultStoriesOffsetDistance: CGFloat = 94.0
|
||||||
|
let effectiveStoriesOffsetDistance: CGFloat
|
||||||
|
|
||||||
|
var minContentOffset: CGFloat = navigationBarSearchContentHeight
|
||||||
|
if !component.isSearchActive, let storySubscriptions = component.storySubscriptions, !storySubscriptions.items.isEmpty {
|
||||||
|
effectiveStoriesOffsetDistance = defaultStoriesOffsetDistance * (1.0 - component.secondaryTransition)
|
||||||
|
minContentOffset += effectiveStoriesOffsetDistance
|
||||||
|
} else {
|
||||||
|
effectiveStoriesOffsetDistance = 0.0
|
||||||
|
}
|
||||||
|
|
||||||
|
let clippedScrollOffset = min(minContentOffset, offset)
|
||||||
|
if self.clippedScrollOffset == clippedScrollOffset && !self.hasDeferredScrollOffset {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
self.hasDeferredScrollOffset = false
|
||||||
|
self.clippedScrollOffset = clippedScrollOffset
|
||||||
|
|
||||||
|
let visibleSize = CGSize(width: currentLayout.size.width, height: max(0.0, currentLayout.size.height - clippedScrollOffset))
|
||||||
|
|
||||||
|
self.backgroundView.update(size: visibleSize, transition: transition.containedViewLayoutTransition)
|
||||||
|
transition.setFrame(view: self.backgroundView, frame: CGRect(origin: CGPoint(), size: visibleSize))
|
||||||
|
transition.setFrame(layer: self.separatorLayer, frame: CGRect(origin: CGPoint(x: 0.0, y: visibleSize.height), size: CGSize(width: visibleSize.width, height: UIScreenPixel)))
|
||||||
|
|
||||||
|
let searchContentNode: NavigationBarSearchContentNode
|
||||||
|
if let current = self.searchContentNode {
|
||||||
|
searchContentNode = current
|
||||||
|
|
||||||
|
if themeUpdated {
|
||||||
|
let placeholder: String
|
||||||
|
let compactPlaceholder: String
|
||||||
|
|
||||||
|
placeholder = component.strings.Common_Search
|
||||||
|
compactPlaceholder = component.strings.Common_Search
|
||||||
|
|
||||||
|
searchContentNode.updateThemeAndPlaceholder(theme: component.theme, placeholder: placeholder, compactPlaceholder: compactPlaceholder)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
let placeholder: String
|
||||||
|
let compactPlaceholder: String
|
||||||
|
|
||||||
|
placeholder = component.strings.Common_Search
|
||||||
|
compactPlaceholder = component.strings.Common_Search
|
||||||
|
|
||||||
|
//TODO:localize
|
||||||
|
searchContentNode = NavigationBarSearchContentNode(
|
||||||
|
theme: component.theme,
|
||||||
|
placeholder: placeholder,
|
||||||
|
compactPlaceholder: compactPlaceholder,
|
||||||
|
activate: { [weak self] in
|
||||||
|
guard let self, let component = self.component, let searchContentNode = self.searchContentNode else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
component.activateSearch(searchContentNode)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
self.searchContentNode = searchContentNode
|
||||||
|
self.addSubview(searchContentNode.view)
|
||||||
|
}
|
||||||
|
|
||||||
|
let clippedStoriesOffset = max(0.0, min(clippedScrollOffset, defaultStoriesOffsetDistance))
|
||||||
|
let storiesOffsetFraction: CGFloat
|
||||||
|
if let storySubscriptions = component.storySubscriptions, !storySubscriptions.items.isEmpty {
|
||||||
|
storiesOffsetFraction = clippedStoriesOffset / defaultStoriesOffsetDistance
|
||||||
|
} else {
|
||||||
|
storiesOffsetFraction = 1.0
|
||||||
|
}
|
||||||
|
|
||||||
|
let searchSize = CGSize(width: currentLayout.size.width, height: navigationBarSearchContentHeight)
|
||||||
|
let searchFrame = CGRect(origin: CGPoint(x: 0.0, y: visibleSize.height - 0.0 - searchSize.height), size: searchSize)
|
||||||
|
|
||||||
|
let clippedSearchOffset = max(0.0, min(clippedScrollOffset - effectiveStoriesOffsetDistance, searchOffsetDistance))
|
||||||
|
let searchOffsetFraction = clippedSearchOffset / searchOffsetDistance
|
||||||
|
searchContentNode.expansionProgress = 1.0 - searchOffsetFraction
|
||||||
|
|
||||||
|
transition.setFrame(view: searchContentNode.view, frame: searchFrame)
|
||||||
|
searchContentNode.updateLayout(size: searchSize, leftInset: component.sideInset, rightInset: component.sideInset, transition: transition.containedViewLayoutTransition)
|
||||||
|
|
||||||
|
let headerContentSize = self.headerContent.update(
|
||||||
|
transition: transition,
|
||||||
|
component: AnyComponent(ChatListHeaderComponent(
|
||||||
|
sideInset: component.sideInset + 16.0,
|
||||||
|
primaryContent: component.primaryContent,
|
||||||
|
secondaryContent: component.secondaryContent,
|
||||||
|
secondaryTransition: component.secondaryTransition,
|
||||||
|
networkStatus: nil,
|
||||||
|
storySubscriptions: component.storySubscriptions,
|
||||||
|
storiesFraction: 1.0 - storiesOffsetFraction,
|
||||||
|
context: component.context,
|
||||||
|
theme: component.theme,
|
||||||
|
strings: component.strings,
|
||||||
|
openStatusSetup: { [weak self] sourceView in
|
||||||
|
guard let self, let component = self.component else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
component.openStatusSetup(sourceView)
|
||||||
|
},
|
||||||
|
toggleIsLocked: { [weak self] in
|
||||||
|
guard let self, let component = self.component else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
component.context.sharedContext.appLockContext.lock()
|
||||||
|
}
|
||||||
|
)),
|
||||||
|
environment: {},
|
||||||
|
containerSize: CGSize(width: currentLayout.size.width, height: 44.0)
|
||||||
|
)
|
||||||
|
let headerContentY: CGFloat
|
||||||
|
if component.isSearchActive {
|
||||||
|
headerContentY = -headerContentSize.height - effectiveStoriesOffsetDistance
|
||||||
|
} else {
|
||||||
|
if component.statusBarHeight < 1.0 {
|
||||||
|
headerContentY = 0.0
|
||||||
|
} else {
|
||||||
|
headerContentY = component.statusBarHeight + 12.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let headerContentFrame = CGRect(origin: CGPoint(x: 0.0, y: headerContentY), size: headerContentSize)
|
||||||
|
if let headerContentView = self.headerContent.view {
|
||||||
|
if headerContentView.superview == nil {
|
||||||
|
self.addSubview(headerContentView)
|
||||||
|
}
|
||||||
|
transition.setFrame(view: headerContentView, frame: headerContentFrame)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func update(component: ChatListNavigationBar, availableSize: CGSize, state: EmptyComponentState, environment: Environment<Empty>, transition: Transition) -> CGSize {
|
||||||
|
let themeUpdated = self.component?.theme !== component.theme
|
||||||
|
|
||||||
|
self.component = component
|
||||||
|
self.state = state
|
||||||
|
|
||||||
|
if themeUpdated {
|
||||||
|
self.backgroundView.updateColor(color: component.theme.rootController.navigationBar.blurredBackgroundColor, transition: .immediate)
|
||||||
|
self.separatorLayer.backgroundColor = component.theme.rootController.navigationBar.separatorColor.cgColor
|
||||||
|
}
|
||||||
|
|
||||||
|
var contentHeight = component.statusBarHeight
|
||||||
|
|
||||||
|
if component.statusBarHeight >= 1.0 {
|
||||||
|
contentHeight += 10.0
|
||||||
|
}
|
||||||
|
contentHeight += 44.0
|
||||||
|
|
||||||
|
if component.isSearchActive {
|
||||||
|
if component.statusBarHeight < 1.0 {
|
||||||
|
contentHeight += 8.0
|
||||||
|
}
|
||||||
|
self.effectiveStoriesInsetHeight = 0.0
|
||||||
|
} else {
|
||||||
|
if let storySubscriptions = component.storySubscriptions, !storySubscriptions.items.isEmpty {
|
||||||
|
let storiesHeight: CGFloat = 94.0 * (1.0 - component.secondaryTransition)
|
||||||
|
contentHeight += storiesHeight
|
||||||
|
self.effectiveStoriesInsetHeight = storiesHeight
|
||||||
|
} else {
|
||||||
|
self.effectiveStoriesInsetHeight = 0.0
|
||||||
|
}
|
||||||
|
|
||||||
|
contentHeight += navigationBarSearchContentHeight
|
||||||
|
}
|
||||||
|
|
||||||
|
let size = CGSize(width: availableSize.width, height: contentHeight)
|
||||||
|
self.currentLayout = CurrentLayout(size: size)
|
||||||
|
|
||||||
|
self.hasDeferredScrollOffset = true
|
||||||
|
|
||||||
|
return size
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public func makeView() -> View {
|
||||||
|
return View(frame: CGRect())
|
||||||
|
}
|
||||||
|
|
||||||
|
public func update(view: View, availableSize: CGSize, state: EmptyComponentState, environment: Environment<Empty>, transition: Transition) -> CGSize {
|
||||||
|
return view.update(component: self, availableSize: availableSize, state: state, environment: environment, transition: transition)
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user