mirror of
https://github.com/TelegramMessenger/Telegram-iOS.git
synced 2026-07-05 19:28:46 +02:00
Glass
This commit is contained in:
parent
dca1f06e91
commit
0c3530d8a8
105 changed files with 1034 additions and 880 deletions
|
|
@ -440,21 +440,57 @@ class TargetBuilder {
|
|||
}
|
||||
}
|
||||
|
||||
// Add SDK frameworks
|
||||
// Collect SDK frameworks from this module and all transitive dependencies
|
||||
var allSdkFrameworks: Set<String> = []
|
||||
if let sdkFrameworks = module.sdkFrameworks {
|
||||
for framework in sdkFrameworks {
|
||||
let fileRef = PBXFileReference(
|
||||
sourceTree: .sdkRoot,
|
||||
name: "\(framework).framework",
|
||||
lastKnownFileType: "wrapper.framework",
|
||||
path: "System/Library/Frameworks/\(framework).framework"
|
||||
)
|
||||
pbxproj.add(object: fileRef)
|
||||
let buildFile = PBXBuildFile(file: fileRef)
|
||||
pbxproj.add(object: buildFile)
|
||||
frameworksPhase.files?.append(buildFile)
|
||||
allSdkFrameworks.formUnion(sdkFrameworks)
|
||||
}
|
||||
for depName in allDeps {
|
||||
if let depModule = modules[depName], let depFrameworks = depModule.sdkFrameworks {
|
||||
allSdkFrameworks.formUnion(depFrameworks)
|
||||
}
|
||||
}
|
||||
|
||||
// Add SDK frameworks
|
||||
for framework in allSdkFrameworks {
|
||||
let fileRef = PBXFileReference(
|
||||
sourceTree: .sdkRoot,
|
||||
name: "\(framework).framework",
|
||||
lastKnownFileType: "wrapper.framework",
|
||||
path: "System/Library/Frameworks/\(framework).framework"
|
||||
)
|
||||
pbxproj.add(object: fileRef)
|
||||
let buildFile = PBXBuildFile(file: fileRef)
|
||||
pbxproj.add(object: buildFile)
|
||||
frameworksPhase.files?.append(buildFile)
|
||||
}
|
||||
|
||||
// Collect SDK dylibs from this module and all transitive dependencies
|
||||
var allSdkDylibs: Set<String> = []
|
||||
if let sdkDylibs = module.sdkDylibs {
|
||||
allSdkDylibs.formUnion(sdkDylibs)
|
||||
}
|
||||
for depName in allDeps {
|
||||
if let depModule = modules[depName], let depDylibs = depModule.sdkDylibs {
|
||||
allSdkDylibs.formUnion(depDylibs)
|
||||
}
|
||||
}
|
||||
|
||||
// Add SDK dylibs (system libraries like libz, libiconv, etc.)
|
||||
for dylib in allSdkDylibs {
|
||||
// Clean up the library name - remove 'lib' prefix if present
|
||||
let libName = dylib.hasPrefix("lib") ? String(dylib.dropFirst(3)) : dylib
|
||||
let fileRef = PBXFileReference(
|
||||
sourceTree: .sdkRoot,
|
||||
name: "lib\(libName).tbd",
|
||||
lastKnownFileType: "sourcecode.text-based-dylib-definition",
|
||||
path: "usr/lib/lib\(libName).tbd"
|
||||
)
|
||||
pbxproj.add(object: fileRef)
|
||||
let buildFile = PBXBuildFile(file: fileRef)
|
||||
pbxproj.add(object: buildFile)
|
||||
frameworksPhase.files?.append(buildFile)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1216,7 +1216,7 @@ public enum ChatHistoryListDisplayHeaders {
|
|||
|
||||
public enum ChatHistoryListMode: Equatable {
|
||||
case bubbles
|
||||
case list(search: Bool, reversed: Bool, reverseGroups: Bool, displayHeaders: ChatHistoryListDisplayHeaders, hintLinks: Bool, isGlobalSearch: Bool)
|
||||
case list(reversed: Bool, reverseGroups: Bool, displayHeaders: ChatHistoryListDisplayHeaders, hintLinks: Bool, isGlobalSearch: Bool)
|
||||
}
|
||||
|
||||
public protocol ChatControllerInteractionProtocol: AnyObject {
|
||||
|
|
|
|||
|
|
@ -196,7 +196,6 @@ public final class BrowserBookmarksScreen: ViewController {
|
|||
controllerInteraction: self.controllerInteraction,
|
||||
selectedMessages: .single(nil),
|
||||
mode: .list(
|
||||
search: false,
|
||||
reversed: false,
|
||||
reverseGroups: false,
|
||||
displayHeaders: .none,
|
||||
|
|
@ -287,9 +286,9 @@ public final class BrowserBookmarksScreen: ViewController {
|
|||
}
|
||||
let tagMask: MessageTags = .webPage
|
||||
|
||||
self.searchDisplayController = SearchDisplayController(presentationData: self.presentationData, mode: .list, placeholder: self.presentationData.strings.Common_Search, hasBackground: true, contentNode: ChatHistorySearchContainerNode(context: self.context, peerId: self.context.account.peerId, threadId: nil, tagMask: tagMask, interfaceInteraction: self.controllerInteraction), cancel: { [weak self] in
|
||||
self.searchDisplayController = SearchDisplayController(presentationData: self.presentationData, mode: .navigation, placeholder: self.presentationData.strings.Common_Search, hasBackground: true, contentNode: ChatHistorySearchContainerNode(context: self.context, peerId: self.context.account.peerId, threadId: nil, tagMask: tagMask, interfaceInteraction: self.controllerInteraction), cancel: { [weak self] in
|
||||
self?.controller?.deactivateSearch()
|
||||
})
|
||||
}, fieldStyle: placeholderNode.fieldStyle)
|
||||
|
||||
self.searchDisplayController?.containerLayoutUpdated(layout, navigationBarHeight: navigationBarHeight, transition: .immediate)
|
||||
self.searchDisplayController?.activate(insertSubnode: { [weak self, weak placeholderNode] subnode, isSearchBar in
|
||||
|
|
@ -372,7 +371,9 @@ public final class BrowserBookmarksScreen: ViewController {
|
|||
self.openUrl = openUrl
|
||||
self.addBookmark = addBookmark
|
||||
|
||||
super.init(navigationBarPresentationData: NavigationBarPresentationData(presentationData: self.presentationData))
|
||||
super.init(navigationBarPresentationData: NavigationBarPresentationData(presentationData: self.presentationData, style: .glass))
|
||||
|
||||
self._hasGlassStyle = true
|
||||
|
||||
self.navigationPresentation = .modal
|
||||
self.supportedOrientations = ViewControllerSupportedOrientations(regularSize: .all, compactSize: .portrait)
|
||||
|
|
@ -435,7 +436,7 @@ public final class BrowserBookmarksScreen: ViewController {
|
|||
|
||||
private func updateThemeAndStrings() {
|
||||
self.statusBar.statusBarStyle = self.presentationData.theme.rootController.statusBarStyle.style
|
||||
self.navigationBar?.updatePresentationData(NavigationBarPresentationData(presentationData: self.presentationData), transition: .immediate)
|
||||
self.navigationBar?.updatePresentationData(NavigationBarPresentationData(presentationData: self.presentationData, style: .glass), transition: .immediate)
|
||||
self.searchContentNode?.updateThemeAndPlaceholder(theme: self.presentationData.theme, placeholder: self.presentationData.strings.Common_Search)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,22 +0,0 @@
|
|||
load("@build_bazel_rules_swift//swift:swift.bzl", "swift_library")
|
||||
|
||||
swift_library(
|
||||
name = "ChatListSearchItemNode",
|
||||
module_name = "ChatListSearchItemNode",
|
||||
srcs = glob([
|
||||
"Sources/**/*.swift",
|
||||
]),
|
||||
copts = [
|
||||
"-warnings-as-errors",
|
||||
],
|
||||
deps = [
|
||||
"//submodules/SSignalKit/SwiftSignalKit:SwiftSignalKit",
|
||||
"//submodules/AsyncDisplayKit:AsyncDisplayKit",
|
||||
"//submodules/Display:Display",
|
||||
"//submodules/TelegramPresentationData:TelegramPresentationData",
|
||||
"//submodules/SearchBarNode:SearchBarNode",
|
||||
],
|
||||
visibility = [
|
||||
"//visibility:public",
|
||||
],
|
||||
)
|
||||
|
|
@ -1,168 +0,0 @@
|
|||
import Foundation
|
||||
import UIKit
|
||||
import AsyncDisplayKit
|
||||
import Display
|
||||
import SwiftSignalKit
|
||||
import TelegramPresentationData
|
||||
import SearchBarNode
|
||||
|
||||
private let searchBarFont = Font.regular(17.0)
|
||||
|
||||
public protocol ChatListSearchItemNeighbour: ListViewItem {
|
||||
var isPinned: Bool { get }
|
||||
}
|
||||
|
||||
public class ChatListSearchItem: ListViewItem {
|
||||
public let selectable: Bool = false
|
||||
|
||||
public let theme: PresentationTheme
|
||||
public let isEnabled: Bool
|
||||
private let placeholder: String
|
||||
private let activate: () -> Void
|
||||
|
||||
public init(theme: PresentationTheme, isEnabled: Bool = true, placeholder: String, activate: @escaping () -> Void) {
|
||||
self.theme = theme
|
||||
self.isEnabled = isEnabled
|
||||
self.placeholder = placeholder
|
||||
self.activate = activate
|
||||
}
|
||||
|
||||
public func nodeConfiguredForParams(async: @escaping (@escaping () -> Void) -> Void, params: ListViewItemLayoutParams, synchronousLoads: Bool, previousItem: ListViewItem?, nextItem: ListViewItem?, completion: @escaping (ListViewItemNode, @escaping () -> (Signal<Void, NoError>?, (ListViewItemApply) -> Void)) -> Void) {
|
||||
async {
|
||||
let node = ChatListSearchItemNode()
|
||||
node.placeholder = self.placeholder
|
||||
|
||||
let makeLayout = node.asyncLayout()
|
||||
var nextIsPinned = false
|
||||
if let nextItem = nextItem as? ChatListSearchItemNeighbour, nextItem.isPinned {
|
||||
nextIsPinned = true
|
||||
}
|
||||
let (layout, apply) = makeLayout(self, params, nextIsPinned, self.isEnabled)
|
||||
|
||||
node.contentSize = layout.contentSize
|
||||
node.insets = layout.insets
|
||||
|
||||
node.activate = self.activate
|
||||
Queue.mainQueue().async {
|
||||
completion(node, {
|
||||
return (nil, { _ in
|
||||
apply(false)
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public func updateNode(async: @escaping (@escaping () -> Void) -> Void, node: @escaping () -> ListViewItemNode, params: ListViewItemLayoutParams, previousItem: ListViewItem?, nextItem: ListViewItem?, animation: ListViewItemUpdateAnimation, completion: @escaping (ListViewItemNodeLayout, @escaping (ListViewItemApply) -> Void) -> Void) {
|
||||
Queue.mainQueue().async {
|
||||
if let nodeValue = node() as? ChatListSearchItemNode {
|
||||
nodeValue.placeholder = self.placeholder
|
||||
let layout = nodeValue.asyncLayout()
|
||||
async {
|
||||
var nextIsPinned = false
|
||||
if let nextItem = nextItem as? ChatListSearchItemNeighbour, nextItem.isPinned {
|
||||
nextIsPinned = true
|
||||
}
|
||||
let (nodeLayout, apply) = layout(self, params, nextIsPinned, self.isEnabled)
|
||||
Queue.mainQueue().async {
|
||||
completion(nodeLayout, { _ in
|
||||
apply(animation.isAnimated)
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class ChatListSearchItemNode: ListViewItemNode {
|
||||
public let searchBarNode: SearchBarPlaceholderNode
|
||||
private var disabledOverlay: ASDisplayNode?
|
||||
public var placeholder: String?
|
||||
|
||||
fileprivate var activate: (() -> Void)? {
|
||||
didSet {
|
||||
self.searchBarNode.activate = self.activate
|
||||
}
|
||||
}
|
||||
|
||||
required public init() {
|
||||
self.searchBarNode = SearchBarPlaceholderNode(fieldStyle: .modern)
|
||||
|
||||
super.init(layerBacked: false, dynamicBounce: false)
|
||||
|
||||
self.addSubnode(self.searchBarNode)
|
||||
}
|
||||
|
||||
override public func layoutForParams(_ params: ListViewItemLayoutParams, item: ListViewItem, previousItem: ListViewItem?, nextItem: ListViewItem?) {
|
||||
let makeLayout = self.asyncLayout()
|
||||
var nextIsPinned = false
|
||||
if let nextItem = nextItem as? ChatListSearchItemNeighbour, nextItem.isPinned {
|
||||
nextIsPinned = true
|
||||
}
|
||||
let (layout, apply) = makeLayout(item as! ChatListSearchItem, params, nextIsPinned, (item as! ChatListSearchItem).isEnabled)
|
||||
apply(false)
|
||||
self.contentSize = layout.contentSize
|
||||
self.insets = layout.insets
|
||||
}
|
||||
|
||||
public func asyncLayout() -> (_ item: ChatListSearchItem, _ params: ListViewItemLayoutParams, _ nextIsPinned: Bool, _ isEnabled: Bool) -> (ListViewItemNodeLayout, (Bool) -> Void) {
|
||||
let searchBarNodeLayout = self.searchBarNode.asyncLayout()
|
||||
let placeholder = self.placeholder
|
||||
|
||||
return { [weak self] item, params, nextIsPinned, isEnabled in
|
||||
let baseWidth = params.width - params.leftInset - params.rightInset
|
||||
|
||||
let backgroundColor = nextIsPinned ? item.theme.chatList.pinnedItemBackgroundColor : item.theme.chatList.itemBackgroundColor
|
||||
let placeholderColor = item.theme.list.itemSecondaryTextColor
|
||||
|
||||
let placeholderString = NSAttributedString(string: placeholder ?? "", font: searchBarFont, textColor: placeholderColor)
|
||||
let (_, searchBarApply) = searchBarNodeLayout(placeholderString, placeholderString, CGSize(width: baseWidth - 20.0, height: 36.0), 1.0, placeholderColor, nextIsPinned ? item.theme.chatList.pinnedSearchBarColor : item.theme.chatList.regularSearchBarColor, backgroundColor, .immediate)
|
||||
|
||||
let layout = ListViewItemNodeLayout(contentSize: CGSize(width: params.width, height: 54.0), insets: UIEdgeInsets())
|
||||
|
||||
return (layout, { animated in
|
||||
if let strongSelf = self {
|
||||
let transition: ContainedViewLayoutTransition
|
||||
if animated {
|
||||
transition = .animated(duration: 0.3, curve: .easeInOut)
|
||||
} else {
|
||||
transition = .immediate
|
||||
}
|
||||
|
||||
let searchBarFrame = CGRect(origin: CGPoint(x: params.leftInset + 10.0, y: 8.0), size: CGSize(width: baseWidth - 20.0, height: 36.0))
|
||||
strongSelf.searchBarNode.frame = searchBarFrame
|
||||
searchBarApply()
|
||||
|
||||
strongSelf.searchBarNode.bounds = CGRect(origin: CGPoint(), size: CGSize(width: baseWidth - 20.0, height: 36.0))
|
||||
|
||||
if !item.isEnabled {
|
||||
if strongSelf.disabledOverlay == nil {
|
||||
let disabledOverlay = ASDisplayNode()
|
||||
strongSelf.addSubnode(disabledOverlay)
|
||||
strongSelf.disabledOverlay = disabledOverlay
|
||||
if animated {
|
||||
disabledOverlay.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.25)
|
||||
}
|
||||
}
|
||||
if let disabledOverlay = strongSelf.disabledOverlay {
|
||||
disabledOverlay.backgroundColor = backgroundColor.withAlphaComponent(0.4)
|
||||
disabledOverlay.frame = searchBarFrame
|
||||
}
|
||||
} else if let disabledOverlay = strongSelf.disabledOverlay {
|
||||
strongSelf.disabledOverlay = nil
|
||||
if animated {
|
||||
disabledOverlay.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.3, removeOnCompletion: false, completion: { [weak disabledOverlay] _ in
|
||||
disabledOverlay?.removeFromSupernode()
|
||||
})
|
||||
} else {
|
||||
disabledOverlay.removeFromSupernode()
|
||||
}
|
||||
}
|
||||
|
||||
transition.updateBackgroundColor(node: strongSelf, color: backgroundColor)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -29,7 +29,6 @@ swift_library(
|
|||
"//submodules/ActivityIndicator:ActivityIndicator",
|
||||
"//submodules/SearchBarNode:SearchBarNode",
|
||||
"//submodules/ChatListSearchRecentPeersNode:ChatListSearchRecentPeersNode",
|
||||
"//submodules/ChatListSearchItemNode:ChatListSearchItemNode",
|
||||
"//submodules/ChatListSearchItemHeader:ChatListSearchItemHeader",
|
||||
"//submodules/TemporaryCachedPeerDataManager:TemporaryCachedPeerDataManager",
|
||||
"//submodules/PeerPresenceStatusManager:PeerPresenceStatusManager",
|
||||
|
|
|
|||
|
|
@ -2946,6 +2946,14 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
|
|||
return
|
||||
}
|
||||
|
||||
#if DEBUG
|
||||
if "".isEmpty {
|
||||
(self.navigationController as? NavigationController)?.pushViewController(oldChannelsController(context: self.context, intent: .join, completed: { value in
|
||||
}))
|
||||
return
|
||||
}
|
||||
#endif
|
||||
|
||||
var reachedCountLimit = false
|
||||
var premiumNeeded = false
|
||||
var hasActiveCall = false
|
||||
|
|
@ -4668,8 +4676,12 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
|
|||
public private(set) var isSearchActive: Bool = false
|
||||
|
||||
public func activateSearch(filter: ChatListSearchFilter, query: String? = nil) {
|
||||
self.activateSearchInternal(isFromTabBar: false, filter: filter, query: query)
|
||||
}
|
||||
|
||||
public func activateSearchInternal(isFromTabBar: Bool, filter: ChatListSearchFilter, query: String? = nil) {
|
||||
var searchContentNode: NavigationBarSearchContentNode?
|
||||
if let navigationBarView = self.chatListDisplayNode.navigationBarView.view as? ChatListNavigationBar.View {
|
||||
if !isFromTabBar, let navigationBarView = self.chatListDisplayNode.navigationBarView.view as? ChatListNavigationBar.View {
|
||||
searchContentNode = navigationBarView.searchContentNode
|
||||
}
|
||||
|
||||
|
|
@ -4714,7 +4726,7 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
|
|||
do {
|
||||
let displaySearchFilters = true
|
||||
|
||||
if let filterContainerNodeAndActivate = await self.chatListDisplayNode.activateSearch(placeholderNode: searchContentNode?.placeholderNode, displaySearchFilters: displaySearchFilters, hasDownloads: self.hasDownloads, initialFilter: filter, navigationController: self.navigationController as? NavigationController, searchBarIsExternal: true) {
|
||||
if let filterContainerNodeAndActivate = await self.chatListDisplayNode.activateSearch(placeholderNode: searchContentNode?.placeholderNode, displaySearchFilters: displaySearchFilters, hasDownloads: self.hasDownloads, initialFilter: filter, navigationController: self.navigationController as? NavigationController, searchBarIsExternal: searchContentNode == nil) {
|
||||
let activate = filterContainerNodeAndActivate
|
||||
|
||||
activate(filter != .downloads)
|
||||
|
|
@ -4726,10 +4738,15 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
|
|||
|
||||
let transition: ContainedViewLayoutTransition = .animated(duration: 0.4, curve: .spring)
|
||||
self.setDisplayNavigationBar(false, transition: transition)
|
||||
self.updateTabBarSearchState(ViewController.TabBarSearchState(isActive: true), transition: transition)
|
||||
if let searchBarNode = self.currentTabBarSearchNode?() as? SearchBarNode {
|
||||
self.chatListDisplayNode.searchDisplayController?.setSearchBar(searchBarNode)
|
||||
searchBarNode.activate()
|
||||
if searchContentNode == nil {
|
||||
self.updateTabBarSearchState(ViewController.TabBarSearchState(isActive: true), transition: transition)
|
||||
|
||||
if let searchBarNode = self.currentTabBarSearchNode?() as? SearchBarNode {
|
||||
self.chatListDisplayNode.searchDisplayController?.setSearchBar(searchBarNode)
|
||||
searchBarNode.activate()
|
||||
}
|
||||
} else {
|
||||
(self.parent as? TabBarController)?.updateIsTabBarHidden(true, transition: transition)
|
||||
}
|
||||
|
||||
self.isSearchActive = true
|
||||
|
|
@ -4791,6 +4808,7 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
|
|||
completion?()
|
||||
|
||||
self.updateTabBarSearchState(ViewController.TabBarSearchState(isActive: false), transition: transition)
|
||||
(self.parent as? TabBarController)?.updateIsTabBarHidden(false, transition: transition)
|
||||
|
||||
self.isSearchActive = false
|
||||
if let navigationController = self.navigationController as? NavigationController {
|
||||
|
|
@ -4814,14 +4832,6 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
|
|||
return
|
||||
}
|
||||
|
||||
#if DEBUG
|
||||
if "".isEmpty {
|
||||
(self.navigationController as? NavigationController)?.pushViewController(oldChannelsController(context: self.context, intent: .join, completed: { value in
|
||||
}))
|
||||
return
|
||||
}
|
||||
#endif
|
||||
|
||||
guard let navigationController = self.navigationController as? NavigationController else {
|
||||
return
|
||||
}
|
||||
|
|
@ -6256,7 +6266,7 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
|
|||
}
|
||||
|
||||
override public func tabBarActivateSearch() {
|
||||
self.activateSearch()
|
||||
self.activateSearchInternal(isFromTabBar: true, filter: .chats, query: nil)
|
||||
}
|
||||
|
||||
override public func tabBarDeactivateSearch() {
|
||||
|
|
|
|||
|
|
@ -1098,7 +1098,7 @@ final class ChatListControllerNode: ASDisplayNode, ASGestureRecognizerDelegate {
|
|||
private var toolbarNode: ToolbarNode?
|
||||
var toolbarActionSelected: ((ToolbarActionOption) -> Void)?
|
||||
|
||||
private var isSearchDisplayControllerActive: Bool = false
|
||||
private var isSearchDisplayControllerActive: ChatListNavigationBar.ActiveSearch?
|
||||
private var skipSearchDisplayControllerLayout: Bool = false
|
||||
private(set) var searchDisplayController: SearchDisplayController?
|
||||
private var disappearingSearchDisplayController: SearchDisplayController?
|
||||
|
|
@ -1556,8 +1556,8 @@ final class ChatListControllerNode: ASDisplayNode, ASGestureRecognizerDelegate {
|
|||
strings: self.presentationData.strings,
|
||||
statusBarHeight: layout.statusBarHeight ?? 0.0,
|
||||
sideInset: layout.safeInsets.left,
|
||||
search: nil, //ChatListNavigationBar.Search(isEnabled: true),
|
||||
isSearchActive: self.isSearchDisplayControllerActive,
|
||||
search: ChatListNavigationBar.Search(isEnabled: true),
|
||||
activeSearch: self.isSearchDisplayControllerActive,
|
||||
primaryContent: headerContent?.primaryContent,
|
||||
secondaryContent: headerContent?.secondaryContent,
|
||||
secondaryTransition: self.inlineStackContainerTransitionFraction,
|
||||
|
|
@ -1654,7 +1654,7 @@ final class ChatListControllerNode: ASDisplayNode, ASGestureRecognizerDelegate {
|
|||
}
|
||||
|
||||
var offset = resultingOffset
|
||||
if self.isSearchDisplayControllerActive {
|
||||
if self.isSearchDisplayControllerActive != nil {
|
||||
offset = 0.0
|
||||
}
|
||||
|
||||
|
|
@ -1715,8 +1715,7 @@ final class ChatListControllerNode: ASDisplayNode, ASGestureRecognizerDelegate {
|
|||
var storiesInset = storiesInset
|
||||
|
||||
let navigationBarLayout = self.updateNavigationBar(layout: layout, deferScrollApplication: true, transition: ComponentTransition(transition))
|
||||
//self.mainContainerNode.initialScrollingOffset = ChatListNavigationBar.searchScrollHeight + navigationBarLayout.storiesInset
|
||||
self.mainContainerNode.initialScrollingOffset = navigationBarLayout.storiesInset
|
||||
self.mainContainerNode.initialScrollingOffset = ChatListNavigationBar.searchScrollHeight + navigationBarLayout.storiesInset
|
||||
|
||||
navigationBarHeight = navigationBarLayout.navigationHeight
|
||||
visualNavigationHeight = navigationBarLayout.navigationHeight
|
||||
|
|
@ -1891,7 +1890,7 @@ final class ChatListControllerNode: ASDisplayNode, ASGestureRecognizerDelegate {
|
|||
if let requestDeactivateSearch = self?.requestDeactivateSearch {
|
||||
requestDeactivateSearch()
|
||||
}
|
||||
}, searchBarIsExternal: searchBarIsExternal)
|
||||
}, fieldStyle: placeholderNode?.fieldStyle ?? .modern, searchBarIsExternal: searchBarIsExternal)
|
||||
self.mainContainerNode.accessibilityElementsHidden = true
|
||||
self.inlineStackContainerNode?.accessibilityElementsHidden = true
|
||||
|
||||
|
|
@ -1900,7 +1899,7 @@ final class ChatListControllerNode: ASDisplayNode, ASGestureRecognizerDelegate {
|
|||
return
|
||||
}
|
||||
|
||||
strongSelf.isSearchDisplayControllerActive = true
|
||||
strongSelf.isSearchDisplayControllerActive = ChatListNavigationBar.ActiveSearch(isExternal: placeholderNode == nil)
|
||||
|
||||
strongSelf.searchDisplayController?.containerLayoutUpdated(containerLayout, navigationBarHeight: cleanNavigationBarHeight, transition: .immediate)
|
||||
strongSelf.searchDisplayController?.activate(insertSubnode: { [weak self] subnode, isSearchBar in
|
||||
|
|
@ -1910,7 +1909,7 @@ final class ChatListControllerNode: ASDisplayNode, ASGestureRecognizerDelegate {
|
|||
|
||||
if isSearchBar {
|
||||
if let navigationBarComponentView = self.navigationBarView.view as? ChatListNavigationBar.View {
|
||||
navigationBarComponentView.addSubnode(subnode)
|
||||
navigationBarComponentView.searchContentNode?.addSubnode(subnode)
|
||||
}
|
||||
} else {
|
||||
self.insertSubnode(subnode, aboveSubnode: self.debugListView)
|
||||
|
|
@ -1923,7 +1922,7 @@ final class ChatListControllerNode: ASDisplayNode, ASGestureRecognizerDelegate {
|
|||
|
||||
func deactivateSearch(placeholderNode: SearchBarPlaceholderNode?, animated: Bool) -> (() -> Void)? {
|
||||
if let searchDisplayController = self.searchDisplayController {
|
||||
self.isSearchDisplayControllerActive = false
|
||||
self.isSearchDisplayControllerActive = nil
|
||||
self.searchDisplayController = nil
|
||||
self.disappearingSearchDisplayController = searchDisplayController
|
||||
self.mainContainerNode.accessibilityElementsHidden = false
|
||||
|
|
|
|||
|
|
@ -768,12 +768,15 @@ public final class ChatListSearchContainerNode: SearchDisplayControllerContentNo
|
|||
filters = defaultAvailableSearchPanes(isForum: isForum, hasDownloads: self.hasDownloads, hasPublicPosts: self.showPublicPostsTab).map(\.filter)
|
||||
}
|
||||
|
||||
var filtersSideInset: CGFloat = 12.0
|
||||
if layout.insets(options: [.input]).bottom <= 84.0 {
|
||||
filtersSideInset = 20.0
|
||||
var filtersInsets = UIEdgeInsets(top: 0.0, left: 12.0, bottom: layout.insets(options: [.input]).bottom + 34.0, right: 12.0)
|
||||
if layout.insets(options: [.input]).bottom <= 30.0 {
|
||||
filtersInsets = ContainerViewLayout.concentricInsets(bottomInset: layout.insets(options: [.input]).bottom, innerDiameter: 40.0, sideInset: 32.0)
|
||||
} else if layout.insets(options: [.input]).bottom <= 84.0 {
|
||||
filtersInsets.left = 20.0
|
||||
filtersInsets.right = filtersInsets.left
|
||||
}
|
||||
|
||||
self.filterContainerNode.update(size: CGSize(width: layout.size.width - (layout.safeInsets.left + filtersSideInset) * 2.0, height: 40.0), sideInset: 0.0, filters: filters.map { .filter($0) }, displayGlobalPostsNewBadge: self.displayGlobalPostsNewBadge, selectedFilter: self.selectedFilter?.id, transitionFraction: self.transitionFraction, presentationData: self.presentationData, transition: .animated(duration: 0.4, curve: .spring))
|
||||
self.filterContainerNode.update(size: CGSize(width: layout.size.width - (layout.safeInsets.left + filtersInsets.left) * 2.0, height: 40.0), sideInset: 0.0, filters: filters.map { .filter($0) }, displayGlobalPostsNewBadge: self.displayGlobalPostsNewBadge, selectedFilter: self.selectedFilter?.id, transitionFraction: self.transitionFraction, presentationData: self.presentationData, transition: .animated(duration: 0.4, curve: .spring))
|
||||
}
|
||||
|
||||
override public func containerLayoutUpdated(_ layout: ContainerViewLayout, navigationBarHeight: CGFloat, transition: ContainedViewLayoutTransition) {
|
||||
|
|
@ -784,12 +787,20 @@ public final class ChatListSearchContainerNode: SearchDisplayControllerContentNo
|
|||
|
||||
let topInset = navigationBarHeight
|
||||
|
||||
var filtersSideInset: CGFloat = 12.0
|
||||
if layout.insets(options: [.input]).bottom <= 84.0 {
|
||||
filtersSideInset = 20.0
|
||||
var filtersInsets = UIEdgeInsets(top: 0.0, left: 12.0, bottom: layout.insets(options: [.input]).bottom, right: 12.0)
|
||||
if layout.insets(options: [.input]).bottom <= 30.0 {
|
||||
filtersInsets = ContainerViewLayout.concentricInsets(bottomInset: layout.insets(options: [.input]).bottom, innerDiameter: 40.0, sideInset: 32.0)
|
||||
} else if layout.insets(options: [.input]).bottom <= 84.0 {
|
||||
filtersInsets.left = 20.0
|
||||
filtersInsets.right = filtersInsets.left
|
||||
} else {
|
||||
if let inputHeight = layout.inputHeight, filtersInsets.bottom == inputHeight {
|
||||
filtersInsets.bottom += 8.0
|
||||
}
|
||||
filtersInsets.bottom = max(8.0, filtersInsets.bottom)
|
||||
}
|
||||
|
||||
transition.updateFrame(node: self.filterContainerNode, frame: CGRect(origin: CGPoint(x: layout.safeInsets.left + filtersSideInset, y: layout.size.height - layout.insets(options: [.input]).bottom - 40.0 + 6.0), size: CGSize(width: layout.size.width - (layout.safeInsets.left + filtersSideInset) * 2.0, height: 40.0)))
|
||||
transition.updateFrame(node: self.filterContainerNode, frame: CGRect(origin: CGPoint(x: layout.safeInsets.left + filtersInsets.left, y: layout.size.height - filtersInsets.bottom - 40.0), size: CGSize(width: layout.size.width - (layout.safeInsets.left + filtersInsets.left) * 2.0, height: 40.0)))
|
||||
self.updateFilterContainerNode(layout: layout, transition: transition)
|
||||
|
||||
if isFirstTime {
|
||||
|
|
|
|||
|
|
@ -15,7 +15,6 @@ import PeerOnlineMarkerNode
|
|||
import LocalizedPeerData
|
||||
import PeerPresenceStatusManager
|
||||
import PhotoResources
|
||||
import ChatListSearchItemNode
|
||||
import ContextUI
|
||||
import ChatInterfaceState
|
||||
import TextFormat
|
||||
|
|
@ -454,7 +453,7 @@ private final class ChatListItemTagListComponent: Component {
|
|||
}
|
||||
}
|
||||
|
||||
public class ChatListItem: ListViewItem, ChatListSearchItemNeighbour {
|
||||
public class ChatListItem: ListViewItem {
|
||||
public enum EnabledContextActions {
|
||||
public struct Actions: OptionSet {
|
||||
public var rawValue: Int32
|
||||
|
|
|
|||
|
|
@ -489,7 +489,25 @@ public struct ComponentTransition {
|
|||
}
|
||||
|
||||
public func setAlpha(view: UIView, alpha: CGFloat, delay: Double = 0.0, completion: ((Bool) -> Void)? = nil) {
|
||||
self.setAlpha(layer: view.layer, alpha: alpha, delay: delay, completion: completion)
|
||||
if view.alpha == alpha {
|
||||
completion?(true)
|
||||
return
|
||||
}
|
||||
switch self.animation {
|
||||
case .none:
|
||||
view.alpha = alpha
|
||||
view.layer.removeAnimation(forKey: "opacity")
|
||||
completion?(true)
|
||||
case .curve:
|
||||
let previousAlpha: Float
|
||||
if view.layer.animation(forKey: "opacity") != nil {
|
||||
previousAlpha = view.layer.presentation()?.opacity ?? Float(view.alpha)
|
||||
} else {
|
||||
previousAlpha = Float(view.alpha)
|
||||
}
|
||||
view.alpha = alpha
|
||||
self.animateAlpha(layer: view.layer, from: CGFloat(previousAlpha), to: alpha, delay: delay, completion: completion)
|
||||
}
|
||||
}
|
||||
|
||||
public func setAlpha(layer: CALayer, alpha: CGFloat, delay: Double = 0.0, completion: ((Bool) -> Void)? = nil) {
|
||||
|
|
|
|||
|
|
@ -1664,7 +1664,7 @@ final class ComposePollScreenComponent: Component {
|
|||
component: AnyComponentWithIdentity(id: "close", component: AnyComponent(
|
||||
BundleIconComponent(
|
||||
name: "Navigation/Close",
|
||||
tintColor: environment.theme.rootController.navigationBar.glassBarButtonForegroundColor
|
||||
tintColor: environment.theme.chat.inputPanel.panelControlColor
|
||||
)
|
||||
)),
|
||||
action: { [weak self] _ in
|
||||
|
|
|
|||
|
|
@ -22,7 +22,6 @@ swift_library(
|
|||
"//submodules/ChatListSearchItemHeader:ChatListSearchItemHeader",
|
||||
"//submodules/ItemListPeerItem:ItemListPeerItem",
|
||||
"//submodules/ContactsPeerItem:ContactsPeerItem",
|
||||
"//submodules/ChatListSearchItemNode:ChatListSearchItemNode",
|
||||
"//submodules/TelegramPermissionsUI:TelegramPermissionsUI",
|
||||
"//submodules/TelegramNotices:TelegramNotices",
|
||||
"//submodules/AlertUI:AlertUI",
|
||||
|
|
|
|||
|
|
@ -16,7 +16,6 @@ import AccountContext
|
|||
import TelegramPermissions
|
||||
import TelegramNotices
|
||||
import ContactsPeerItem
|
||||
import ChatListSearchItemNode
|
||||
import ChatListSearchItemHeader
|
||||
import SearchUI
|
||||
import TelegramPermissionsUI
|
||||
|
|
@ -96,7 +95,6 @@ private enum ContactListNodeEntry: Comparable, Identifiable {
|
|||
var hasUnseenCloseFriends: Bool
|
||||
}
|
||||
|
||||
case search(PresentationTheme, PresentationStrings)
|
||||
case sort(PresentationTheme, PresentationStrings, ContactsSortOrder)
|
||||
case permissionInfo(PresentationTheme, String, String, Bool)
|
||||
case permissionEnable(PresentationTheme, String)
|
||||
|
|
@ -107,8 +105,6 @@ private enum ContactListNodeEntry: Comparable, Identifiable {
|
|||
|
||||
var stableId: ContactListNodeEntryId {
|
||||
switch self {
|
||||
case .search:
|
||||
return .search
|
||||
case .sort:
|
||||
return .sort
|
||||
case .permissionInfo:
|
||||
|
|
@ -133,10 +129,6 @@ private enum ContactListNodeEntry: Comparable, Identifiable {
|
|||
|
||||
func item(context: AccountContext, presentationData: PresentationData, interaction: ContactListNodeInteraction, isSearch: Bool, listStyle: ItemListStyle) -> ListViewItem {
|
||||
switch self {
|
||||
case let .search(theme, strings):
|
||||
return ChatListSearchItem(theme: theme, placeholder: strings.Contacts_SearchLabel, activate: {
|
||||
interaction.activateSearch()
|
||||
})
|
||||
case let .sort(_, strings, sortOrder):
|
||||
var text = strings.Contacts_SortedByName
|
||||
if case .presence = sortOrder {
|
||||
|
|
@ -270,12 +262,6 @@ private enum ContactListNodeEntry: Comparable, Identifiable {
|
|||
|
||||
static func ==(lhs: ContactListNodeEntry, rhs: ContactListNodeEntry) -> Bool {
|
||||
switch lhs {
|
||||
case let .search(lhsTheme, lhsStrings):
|
||||
if case let .search(rhsTheme, rhsStrings) = rhs, lhsTheme === rhsTheme, lhsStrings === rhsStrings {
|
||||
return true
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
case let .sort(lhsTheme, lhsStrings, lhsSortOrder):
|
||||
if case let .sort(rhsTheme, rhsStrings, rhsSortOrder) = rhs, lhsTheme === rhsTheme, lhsStrings === rhsStrings, lhsSortOrder == rhsSortOrder {
|
||||
return true
|
||||
|
|
@ -376,39 +362,35 @@ private enum ContactListNodeEntry: Comparable, Identifiable {
|
|||
|
||||
static func <(lhs: ContactListNodeEntry, rhs: ContactListNodeEntry) -> Bool {
|
||||
switch lhs {
|
||||
case .search:
|
||||
return true
|
||||
case .sort:
|
||||
switch rhs {
|
||||
case .search:
|
||||
return false
|
||||
default:
|
||||
return true
|
||||
}
|
||||
case .permissionInfo:
|
||||
switch rhs {
|
||||
case .search, .sort:
|
||||
case .sort:
|
||||
return false
|
||||
default:
|
||||
return true
|
||||
}
|
||||
case .permissionEnable:
|
||||
switch rhs {
|
||||
case .search, .sort, .permissionInfo:
|
||||
case .sort, .permissionInfo:
|
||||
return false
|
||||
default:
|
||||
return true
|
||||
}
|
||||
case .permissionLimited:
|
||||
switch rhs {
|
||||
case .search, .sort, .permissionInfo, .permissionEnable:
|
||||
case .sort, .permissionInfo, .permissionEnable:
|
||||
return false
|
||||
default:
|
||||
return true
|
||||
}
|
||||
case let .option(lhsIndex, _, _, _, _):
|
||||
switch rhs {
|
||||
case .search, .sort, .permissionInfo, .permissionEnable, .permissionLimited:
|
||||
case .sort, .permissionInfo, .permissionEnable, .permissionLimited:
|
||||
return false
|
||||
case let .option(rhsIndex, _, _, _, _):
|
||||
return lhsIndex < rhsIndex
|
||||
|
|
@ -417,14 +399,14 @@ private enum ContactListNodeEntry: Comparable, Identifiable {
|
|||
}
|
||||
case let .header(lhsIndex, _):
|
||||
switch rhs {
|
||||
case .search, .sort, .permissionInfo, .permissionEnable, .permissionLimited, .option:
|
||||
case .sort, .permissionInfo, .permissionEnable, .permissionLimited, .option:
|
||||
return false
|
||||
case let .header(rhsIndex, _), let .peer(rhsIndex, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _):
|
||||
return lhsIndex < rhsIndex
|
||||
}
|
||||
case let .peer(lhsIndex, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _):
|
||||
switch rhs {
|
||||
case .search, .sort, .permissionInfo, .permissionEnable, .permissionLimited, .option:
|
||||
case .sort, .permissionInfo, .permissionEnable, .permissionLimited, .option:
|
||||
return false
|
||||
case let .peer(rhsIndex, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _), let .header(rhsIndex, _):
|
||||
// if (lhsStoryData == nil) != (rhsStoryData == nil) {
|
||||
|
|
@ -901,9 +883,6 @@ private func preparedContactListNodeTransition(context: AccountContext, presenta
|
|||
switch entry {
|
||||
case .sort:
|
||||
shouldFixScroll = true
|
||||
case .search:
|
||||
//indexSections.apend(CollectionIndexNode.searchIndex)
|
||||
break
|
||||
case let .peer(_, _, _, header, _, _, _, _, _, _, _, _, _, _, _, _):
|
||||
if let header = header as? ContactListNameIndexHeader {
|
||||
if !existingSections.contains(header.letter) {
|
||||
|
|
@ -1419,11 +1398,6 @@ public final class ContactListNode: ASDisplayNode {
|
|||
var peerIndex = 0
|
||||
loop: for entry in entries {
|
||||
switch entry {
|
||||
case .search:
|
||||
if section == CollectionIndexNode.searchIndex {
|
||||
strongSelf.listNode.transaction(deleteIndices: [], insertIndicesAndItems: [], updateIndicesAndItems: [], options: [.PreferSynchronousDrawing, .PreferSynchronousResourceLoading], scrollToItem: ListViewScrollToItem(index: index, position: .top(-navigationBarSearchContentHeight), animated: false, curve: .Default(duration: nil), directionHint: .Down), additionalScrollDistance: 0.0, updateSizeAndInsets: updateSizeAndInsets, stationaryItemRange: nil, updateOpaqueState: nil, completion: { _ in })
|
||||
break loop
|
||||
}
|
||||
case let .peer(_, _, _, header, _, _, _, _, _, _, _, _, _, _, _, _):
|
||||
if let header = header as? ContactListNameIndexHeader {
|
||||
if let scalar = UnicodeScalar(header.letter) {
|
||||
|
|
|
|||
|
|
@ -342,7 +342,7 @@ public class ContactsController: ViewController {
|
|||
}
|
||||
|
||||
self.contactsNode.contactListNode.activateSearch = { [weak self] in
|
||||
self?.activateSearch()
|
||||
self?.activateSearch(isFromTabBar: false)
|
||||
}
|
||||
|
||||
self.contactsNode.contactListNode.openPeer = { [weak self] peer, _, _, _ in
|
||||
|
|
@ -579,12 +579,17 @@ public class ContactsController: ViewController {
|
|||
self.sortButton.contextAction?(self.sortButton.containerNode, nil)
|
||||
}
|
||||
|
||||
private func activateSearch() {
|
||||
self.contactsNode.activateSearch(placeholderNode: self.searchContentNode()?.placeholderNode)
|
||||
self.updateTabBarSearchState(ViewController.TabBarSearchState(isActive: true), transition: .animated(duration: 0.5, curve: .spring))
|
||||
if let searchBarNode = self.currentTabBarSearchNode?() as? SearchBarNode {
|
||||
self.contactsNode.searchDisplayController?.setSearchBar(searchBarNode)
|
||||
searchBarNode.activate()
|
||||
private func activateSearch(isFromTabBar: Bool) {
|
||||
let placeholderNode = isFromTabBar ? nil : self.searchContentNode()?.placeholderNode
|
||||
self.contactsNode.activateSearch(placeholderNode: placeholderNode)
|
||||
if placeholderNode != nil {
|
||||
(self.parent as? TabBarController)?.updateIsTabBarHidden(true, transition: .animated(duration: 0.5, curve: .spring))
|
||||
} else {
|
||||
self.updateTabBarSearchState(ViewController.TabBarSearchState(isActive: true), transition: .animated(duration: 0.5, curve: .spring))
|
||||
if let searchBarNode = self.currentTabBarSearchNode?() as? SearchBarNode {
|
||||
self.contactsNode.searchDisplayController?.setSearchBar(searchBarNode)
|
||||
searchBarNode.activate()
|
||||
}
|
||||
}
|
||||
self.requestLayout(transition: .animated(duration: 0.5, curve: .spring))
|
||||
}
|
||||
|
|
@ -592,6 +597,7 @@ public class ContactsController: ViewController {
|
|||
private func deactivateSearch(animated: Bool) {
|
||||
self.contactsNode.deactivateSearch(placeholderNode: self.searchContentNode()?.placeholderNode, animated: animated)
|
||||
self.updateTabBarSearchState(ViewController.TabBarSearchState(isActive: false), transition: .animated(duration: 0.5, curve: .spring))
|
||||
(self.parent as? TabBarController)?.updateIsTabBarHidden(false, transition: .animated(duration: 0.5, curve: .spring))
|
||||
self.requestLayout(transition: .animated(duration: 0.5, curve: .spring))
|
||||
}
|
||||
|
||||
|
|
@ -799,7 +805,7 @@ public class ContactsController: ViewController {
|
|||
}
|
||||
|
||||
override public func tabBarActivateSearch() {
|
||||
self.activateSearch()
|
||||
self.activateSearch(isFromTabBar: true)
|
||||
}
|
||||
|
||||
override public func tabBarDeactivateSearch() {
|
||||
|
|
|
|||
|
|
@ -53,7 +53,7 @@ final class ContactsControllerNode: ASDisplayNode, ASGestureRecognizerDelegate {
|
|||
|
||||
private let context: AccountContext
|
||||
private(set) var searchDisplayController: SearchDisplayController?
|
||||
private var isSearchDisplayControllerActive: Bool = false
|
||||
private var isSearchDisplayControllerActive: ChatListNavigationBar.ActiveSearch?
|
||||
private var storiesUnlocked: Bool = false
|
||||
|
||||
private var containerLayout: (ContainerViewLayout, CGFloat)?
|
||||
|
|
@ -360,8 +360,8 @@ final class ContactsControllerNode: ASDisplayNode, ASGestureRecognizerDelegate {
|
|||
strings: self.presentationData.strings,
|
||||
statusBarHeight: layout.statusBarHeight ?? 0.0,
|
||||
sideInset: layout.safeInsets.left,
|
||||
search: nil,//ChatListNavigationBar.Search(isEnabled: true),
|
||||
isSearchActive: self.isSearchDisplayControllerActive,
|
||||
search: ChatListNavigationBar.Search(isEnabled: true),
|
||||
activeSearch: self.isSearchDisplayControllerActive,
|
||||
primaryContent: primaryContent,
|
||||
secondaryContent: nil,
|
||||
secondaryTransition: 0.0,
|
||||
|
|
@ -415,7 +415,7 @@ final class ContactsControllerNode: ASDisplayNode, ASGestureRecognizerDelegate {
|
|||
|
||||
private func updateNavigationScrolling(transition: ContainedViewLayoutTransition) {
|
||||
var offset = self.getEffectiveNavigationScrollingOffset()
|
||||
if self.isSearchDisplayControllerActive {
|
||||
if self.isSearchDisplayControllerActive != nil {
|
||||
offset = 0.0
|
||||
}
|
||||
|
||||
|
|
@ -482,10 +482,10 @@ final class ContactsControllerNode: ASDisplayNode, ASGestureRecognizerDelegate {
|
|||
return
|
||||
}
|
||||
|
||||
self.isSearchDisplayControllerActive = true
|
||||
self.isSearchDisplayControllerActive = ChatListNavigationBar.ActiveSearch(isExternal: placeholderNode == nil)
|
||||
self.storiesUnlocked = false
|
||||
|
||||
self.searchDisplayController = SearchDisplayController(presentationData: self.presentationData, mode: .list, contentNode: ContactsSearchContainerNode(context: self.context, glass: true, externalSearchBar: true, onlyWriteable: false, categories: [.cloudContacts, .global, .deviceContacts], addContact: { [weak self] phoneNumber in
|
||||
self.searchDisplayController = SearchDisplayController(presentationData: self.presentationData, mode: .navigation, contentNode: ContactsSearchContainerNode(context: self.context, glass: true, externalSearchBar: true, onlyWriteable: false, categories: [.cloudContacts, .global, .deviceContacts], addContact: { [weak self] phoneNumber in
|
||||
if let requestAddContact = self?.requestAddContact {
|
||||
requestAddContact(phoneNumber)
|
||||
}
|
||||
|
|
@ -503,14 +503,14 @@ final class ContactsControllerNode: ASDisplayNode, ASGestureRecognizerDelegate {
|
|||
if let requestDeactivateSearch = self?.requestDeactivateSearch {
|
||||
requestDeactivateSearch()
|
||||
}
|
||||
}, searchBarIsExternal: placeholderNode == nil)
|
||||
}, fieldStyle: placeholderNode?.fieldStyle ?? .modern, searchBarIsExternal: placeholderNode == nil)
|
||||
|
||||
self.searchDisplayController?.containerLayoutUpdated(containerLayout, navigationBarHeight: navigationBarHeight, transition: .immediate)
|
||||
self.searchDisplayController?.activate(insertSubnode: { [weak self] subnode, isSearchBar in
|
||||
if let strongSelf = self {
|
||||
if isSearchBar {
|
||||
if let navigationBarComponentView = strongSelf.navigationBarView.view as? ChatListNavigationBar.View {
|
||||
navigationBarComponentView.addSubnode(subnode)
|
||||
navigationBarComponentView.searchContentNode?.addSubnode(subnode)
|
||||
}
|
||||
} else {
|
||||
strongSelf.insertSubnode(subnode, aboveSubnode: strongSelf.contactListNode)
|
||||
|
|
@ -520,21 +520,10 @@ final class ContactsControllerNode: ASDisplayNode, ASGestureRecognizerDelegate {
|
|||
}
|
||||
|
||||
func deactivateSearch(placeholderNode: SearchBarPlaceholderNode?, animated: Bool) {
|
||||
self.isSearchDisplayControllerActive = false
|
||||
self.isSearchDisplayControllerActive = nil
|
||||
if let searchDisplayController = self.searchDisplayController {
|
||||
var previousFrame: CGRect?
|
||||
if let placeholderNode {
|
||||
let previousFrameValue = placeholderNode.frame
|
||||
previousFrame = previousFrameValue
|
||||
placeholderNode.frame = previousFrameValue.offsetBy(dx: 0.0, dy: 54.0)
|
||||
}
|
||||
|
||||
searchDisplayController.deactivate(placeholder: placeholderNode, animated: animated)
|
||||
self.searchDisplayController = nil
|
||||
|
||||
if let placeholderNode, let previousFrame {
|
||||
placeholderNode.frame = previousFrame
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -293,7 +293,7 @@ public final class ContactsSearchContainerNode: SearchDisplayControllerContentNo
|
|||
self.themeAndStringsPromise = Promise((self.presentationData.theme, self.presentationData.strings))
|
||||
|
||||
self.dimNode = ASDisplayNode()
|
||||
self.dimNode.backgroundColor = glass ? .clear : UIColor.black.withAlphaComponent(0.5)
|
||||
self.dimNode.backgroundColor = .clear
|
||||
|
||||
self.backgroundNode = ASDisplayNode()
|
||||
self.backgroundNode.backgroundColor = self.presentationData.theme.list.plainBackgroundColor
|
||||
|
|
@ -693,8 +693,22 @@ public final class ContactsSearchContainerNode: SearchDisplayControllerContentNo
|
|||
|
||||
self.backgroundNode.frame = CGRect(origin: .zero, size: CGSize(width: layout.size.width, height: navigationBarHeight))
|
||||
|
||||
self.listNode.frame = CGRect(origin: CGPoint(x: 0.0, y: navigationBarHeight), size: CGSize(width: layout.size.width, height: layout.size.height - topInset))
|
||||
self.listNode.transaction(deleteIndices: [], insertIndicesAndItems: [], updateIndicesAndItems: [], options: [.Synchronous], scrollToItem: nil, updateSizeAndInsets: ListViewUpdateSizeAndInsets(size: layout.size, insets: UIEdgeInsets(top: 0.0, left: layout.safeInsets.left, bottom: layout.intrinsicInsets.bottom, right: layout.safeInsets.right), duration: 0.0, curve: .Default(duration: nil)), stationaryItemRange: nil, updateOpaqueState: nil, completion: { _ in })
|
||||
self.listNode.frame = CGRect(origin: CGPoint(x: 0.0, y: 0.0), size: CGSize(width: layout.size.width, height: layout.size.height))
|
||||
let listDuration: Double
|
||||
let listCurve: ListViewAnimationCurve
|
||||
switch transition {
|
||||
case .immediate:
|
||||
listDuration = 0.0
|
||||
listCurve = .Default(duration: nil)
|
||||
case let .animated(duration, curve):
|
||||
listDuration = duration
|
||||
if case .spring = curve {
|
||||
listCurve = .Spring(duration: duration)
|
||||
} else {
|
||||
listCurve = .Default(duration: nil)
|
||||
}
|
||||
}
|
||||
self.listNode.transaction(deleteIndices: [], insertIndicesAndItems: [], updateIndicesAndItems: [], options: [.Synchronous], scrollToItem: nil, updateSizeAndInsets: ListViewUpdateSizeAndInsets(size: layout.size, insets: UIEdgeInsets(top: topInset, left: layout.safeInsets.left, bottom: layout.intrinsicInsets.bottom, right: layout.safeInsets.right), duration: listDuration, curve: listCurve), stationaryItemRange: nil, updateOpaqueState: nil, completion: { _ in })
|
||||
|
||||
let size = layout.size
|
||||
let sideInset = layout.safeInsets.left
|
||||
|
|
@ -797,14 +811,14 @@ public final class ContactsSearchContainerNode: SearchDisplayControllerContentNo
|
|||
strongSelf.containerLayoutUpdated(layout, navigationBarHeight: navigationBarHeight, transition: .immediate)
|
||||
}
|
||||
|
||||
let containerTransition = ContainedViewLayoutTransition.animated(duration: 0.3, curve: .easeInOut)
|
||||
containerTransition.updateAlpha(node: strongSelf.listNode, alpha: isSearching ? 1.0 : 0.0)
|
||||
containerTransition.updateAlpha(node: strongSelf.backgroundNode, alpha: isSearching ? 1.0 : 0.0)
|
||||
//let containerTransition = ContainedViewLayoutTransition.animated(duration: 0.3, curve: .easeInOut)
|
||||
ContainedViewLayoutTransition.immediate.updateAlpha(node: strongSelf.listNode, alpha: isSearching ? 1.0 : 0.0)
|
||||
ContainedViewLayoutTransition.immediate.updateAlpha(node: strongSelf.backgroundNode, alpha: isSearching ? 1.0 : 0.0)
|
||||
strongSelf.dimNode.isHidden = isSearching
|
||||
|
||||
containerTransition.updateAlpha(node: strongSelf.emptyResultsAnimationNode, alpha: emptyResults ? 1.0 : 0.0)
|
||||
containerTransition.updateAlpha(node: strongSelf.emptyResultsTitleNode, alpha: emptyResults ? 1.0 : 0.0)
|
||||
containerTransition.updateAlpha(node: strongSelf.emptyResultsTextNode, alpha: emptyResults ? 1.0 : 0.0)
|
||||
ContainedViewLayoutTransition.immediate.updateAlpha(node: strongSelf.emptyResultsAnimationNode, alpha: emptyResults ? 1.0 : 0.0)
|
||||
ContainedViewLayoutTransition.immediate.updateAlpha(node: strongSelf.emptyResultsTitleNode, alpha: emptyResults ? 1.0 : 0.0)
|
||||
ContainedViewLayoutTransition.immediate.updateAlpha(node: strongSelf.emptyResultsTextNode, alpha: emptyResults ? 1.0 : 0.0)
|
||||
strongSelf.emptyResultsAnimationNode.visibility = emptyResults
|
||||
})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -36,8 +36,9 @@ public class InviteContactsController: ViewController, MFMessageComposeViewContr
|
|||
|
||||
self.presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
||||
|
||||
super.init(navigationBarPresentationData: NavigationBarPresentationData(presentationData: self.presentationData))
|
||||
super.init(navigationBarPresentationData: NavigationBarPresentationData(presentationData: self.presentationData, style: .glass))
|
||||
|
||||
self._hasGlassStyle = true
|
||||
self.navigationPresentation = .modal
|
||||
|
||||
self.statusBar.statusBarStyle = self.presentationData.theme.rootController.statusBarStyle.style
|
||||
|
|
@ -86,7 +87,7 @@ public class InviteContactsController: ViewController, MFMessageComposeViewContr
|
|||
|
||||
private func updateThemeAndStrings() {
|
||||
self.statusBar.statusBarStyle = self.presentationData.theme.rootController.statusBarStyle.style
|
||||
self.navigationBar?.updatePresentationData(NavigationBarPresentationData(presentationData: self.presentationData), transition: .immediate)
|
||||
self.navigationBar?.updatePresentationData(NavigationBarPresentationData(presentationData: self.presentationData, style: .glass), transition: .immediate)
|
||||
self.searchContentNode?.updateThemeAndPlaceholder(theme: self.presentationData.theme, placeholder: self.presentationData.strings.Common_Search)
|
||||
self.title = self.presentationData.strings.Contacts_InviteFriends
|
||||
self.navigationItem.backBarButtonItem = UIBarButtonItem(title: self.presentationData.strings.Common_Back, style: .plain, target: nil, action: nil)
|
||||
|
|
|
|||
|
|
@ -518,7 +518,7 @@ final class InviteContactsControllerNode: ASDisplayNode {
|
|||
if let requestDeactivateSearch = self?.requestDeactivateSearch {
|
||||
requestDeactivateSearch()
|
||||
}
|
||||
})
|
||||
}, fieldStyle: placeholderNode.fieldStyle)
|
||||
|
||||
self.searchDisplayController?.containerLayoutUpdated(containerLayout, navigationBarHeight: navigationBarHeight, transition: .immediate)
|
||||
self.searchDisplayController?.activate(insertSubnode: { [weak self, weak placeholderNode] subnode, isSearchBar in
|
||||
|
|
|
|||
|
|
@ -398,7 +398,7 @@ public final class AuthorizationSequenceCountrySelectionController: ViewControll
|
|||
component: AnyComponentWithIdentity(id: "close", component: AnyComponent(
|
||||
BundleIconComponent(
|
||||
name: "Navigation/Close",
|
||||
tintColor: self.theme.rootController.navigationBar.glassBarButtonForegroundColor
|
||||
tintColor: self.theme.chat.inputPanel.panelControlColor
|
||||
)
|
||||
)),
|
||||
action: { [weak self] _ in
|
||||
|
|
@ -419,7 +419,7 @@ public final class AuthorizationSequenceCountrySelectionController: ViewControll
|
|||
component: AnyComponentWithIdentity(id: "search", component: AnyComponent(
|
||||
BundleIconComponent(
|
||||
name: "Navigation/Search",
|
||||
tintColor: self.theme.rootController.navigationBar.glassBarButtonForegroundColor
|
||||
tintColor: self.theme.chat.inputPanel.panelControlColor
|
||||
)
|
||||
)),
|
||||
action: { [weak self] _ in
|
||||
|
|
|
|||
|
|
@ -254,9 +254,7 @@ public protocol CustomViewControllerNavigationDataSummary: AnyObject {
|
|||
let statusBarHeight: CGFloat = layout.statusBarHeight ?? 0.0
|
||||
var defaultNavigationBarHeight: CGFloat
|
||||
if self._presentedInModal && self._hasGlassStyle {
|
||||
defaultNavigationBarHeight = 66.0
|
||||
} else if self._presentedInModal && layout.orientation == .portrait {
|
||||
defaultNavigationBarHeight = 60.0
|
||||
defaultNavigationBarHeight = 68.0
|
||||
} else {
|
||||
defaultNavigationBarHeight = 60.0
|
||||
}
|
||||
|
|
@ -459,14 +457,29 @@ public protocol CustomViewControllerNavigationDataSummary: AnyObject {
|
|||
}
|
||||
if let navigationBar = self.navigationBar {
|
||||
if let contentNode = navigationBar.contentNode, case .expansion = contentNode.mode, !self.displayNavigationBar {
|
||||
navigationBarFrame.origin.y -= navigationLayout.defaultContentHeight
|
||||
navigationBarFrame.size.height += contentNode.height + navigationLayout.defaultContentHeight + statusBarHeight
|
||||
navigationBarFrame.origin.y -= navigationLayout.defaultContentHeight + statusBarHeight
|
||||
navigationBarFrame.size.height += contentNode.height + navigationLayout.defaultContentHeight + statusBarHeight * 2.0
|
||||
if self._presentedInModal && self._hasGlassStyle {
|
||||
navigationBarFrame.size.height += 8.0
|
||||
}
|
||||
}
|
||||
//navigationBar.backgroundColor = .blue
|
||||
if let _ = navigationBar.contentNode, let _ = navigationBar.secondaryContentNode, !self.displayNavigationBar {
|
||||
navigationBarFrame.size.height += navigationBar.secondaryContentHeight
|
||||
}
|
||||
|
||||
navigationBar.updateLayout(size: navigationBarFrame.size, defaultHeight: navigationLayout.defaultContentHeight, additionalTopHeight: statusBarHeight, additionalContentHeight: self.additionalNavigationBarHeight, additionalBackgroundHeight: additionalBackgroundHeight, additionalCutout: additionalCutout, leftInset: layout.safeInsets.left, rightInset: layout.safeInsets.right, appearsHidden: !self.displayNavigationBar, isLandscape: isLandscape, transition: transition)
|
||||
var additionalTopHeight = statusBarHeight
|
||||
if !self.displayNavigationBar {
|
||||
additionalTopHeight -= statusBarHeight
|
||||
if statusBarHeight != 0.0 {
|
||||
additionalTopHeight += 6.0
|
||||
}
|
||||
}
|
||||
if self._presentedInModal && self._hasGlassStyle {
|
||||
additionalTopHeight += 8.0
|
||||
}
|
||||
|
||||
navigationBar.updateLayout(size: navigationBarFrame.size, defaultHeight: navigationLayout.defaultContentHeight, additionalTopHeight: additionalTopHeight, additionalContentHeight: self.additionalNavigationBarHeight, additionalBackgroundHeight: additionalBackgroundHeight, additionalCutout: additionalCutout, leftInset: layout.safeInsets.left, rightInset: layout.safeInsets.right, appearsHidden: !self.displayNavigationBar, isLandscape: isLandscape, transition: transition)
|
||||
if !transition.isAnimated {
|
||||
navigationBar.layer.removeAnimation(forKey: "bounds")
|
||||
navigationBar.layer.removeAnimation(forKey: "position")
|
||||
|
|
|
|||
|
|
@ -1393,7 +1393,7 @@ final class LocationPickerControllerNode: ViewControllerTracingNode, CLLocationM
|
|||
component: AnyComponentWithIdentity(id: isPickingLocation ? "back" : "close", component: AnyComponent(
|
||||
BundleIconComponent(
|
||||
name: isPickingLocation ? "Navigation/Back" : "Navigation/Close",
|
||||
tintColor: self.presentationData.theme.rootController.navigationBar.glassBarButtonForegroundColor
|
||||
tintColor: self.presentationData.theme.chat.inputPanel.panelControlColor
|
||||
)
|
||||
)),
|
||||
action: { [weak self] _ in
|
||||
|
|
@ -1428,7 +1428,7 @@ final class LocationPickerControllerNode: ViewControllerTracingNode, CLLocationM
|
|||
component: AnyComponentWithIdentity(id: "search", component: AnyComponent(
|
||||
BundleIconComponent(
|
||||
name: "Navigation/Search",
|
||||
tintColor: self.presentationData.theme.rootController.navigationBar.glassBarButtonForegroundColor
|
||||
tintColor: self.presentationData.theme.chat.inputPanel.panelControlColor
|
||||
)
|
||||
)),
|
||||
action: { [weak self] _ in
|
||||
|
|
|
|||
|
|
@ -2586,7 +2586,7 @@ public final class MediaPickerScreenImpl: ViewController, MediaPickerScreen, Att
|
|||
component: AnyComponentWithIdentity(id: isBack ? "back" : "close", component: AnyComponent(
|
||||
BundleIconComponent(
|
||||
name: isBack ? "Navigation/Back" : "Navigation/Close",
|
||||
tintColor: self.presentationData.theme.rootController.navigationBar.glassBarButtonForegroundColor
|
||||
tintColor: self.presentationData.theme.chat.inputPanel.panelControlColor
|
||||
)
|
||||
)),
|
||||
action: { [weak self] _ in
|
||||
|
|
@ -2619,7 +2619,7 @@ public final class MediaPickerScreenImpl: ViewController, MediaPickerScreen, Att
|
|||
content: LottieComponent.AppBundleContent(
|
||||
name: "anim_morewide"
|
||||
),
|
||||
color: self.presentationData.theme.rootController.navigationBar.glassBarButtonForegroundColor,
|
||||
color: self.presentationData.theme.chat.inputPanel.panelControlColor,
|
||||
size: CGSize(width: 34.0, height: 34.0),
|
||||
playOnce: self.moreButtonPlayOnce
|
||||
)
|
||||
|
|
|
|||
|
|
@ -242,7 +242,7 @@ private final class CreateExternalMediaStreamScreenComponent: CombinedComponent
|
|||
component: AnyComponentWithIdentity(id: "close", component: AnyComponent(
|
||||
BundleIconComponent(
|
||||
name: "Navigation/Close",
|
||||
tintColor: theme.rootController.navigationBar.glassBarButtonForegroundColor
|
||||
tintColor: theme.chat.inputPanel.panelControlColor
|
||||
)
|
||||
)),
|
||||
action: { _ in
|
||||
|
|
|
|||
|
|
@ -164,7 +164,7 @@ private final class ChannelDiscussionSearchNavigationContentNode: NavigationBarC
|
|||
primaryText: theme.chat.inputPanel.panelControlColor,
|
||||
placeholder: theme.chat.inputPanel.inputPlaceholderColor,
|
||||
inputIcon: theme.chat.inputPanel.inputControlColor,
|
||||
inputClear: theme.chat.inputPanel.inputControlColor,
|
||||
inputClear: theme.chat.inputPanel.panelControlColor,
|
||||
accent: theme.chat.inputPanel.panelControlAccentColor,
|
||||
keyboard: theme.rootController.keyboardColor
|
||||
),
|
||||
|
|
|
|||
|
|
@ -685,7 +685,7 @@ class ChannelMembersSearchControllerNode: ASDisplayNode {
|
|||
if let requestDeactivateSearch = self?.requestDeactivateSearch {
|
||||
requestDeactivateSearch()
|
||||
}
|
||||
})
|
||||
}, fieldStyle: placeholderNode.fieldStyle)
|
||||
|
||||
self.searchDisplayController?.containerLayoutUpdated(containerLayout, navigationBarHeight: navigationBarHeight, transition: .immediate)
|
||||
self.searchDisplayController?.activate(insertSubnode: { [weak self, weak placeholderNode] subnode, isSearchBar in
|
||||
|
|
|
|||
|
|
@ -79,7 +79,7 @@ final class GroupInfoSearchNavigationContentNode: NavigationBarContentNode, Item
|
|||
primaryText: theme.chat.inputPanel.panelControlColor,
|
||||
placeholder: theme.chat.inputPanel.inputPlaceholderColor,
|
||||
inputIcon: theme.chat.inputPanel.inputControlColor,
|
||||
inputClear: theme.chat.inputPanel.inputControlColor,
|
||||
inputClear: theme.chat.inputPanel.panelControlColor,
|
||||
accent: theme.chat.inputPanel.panelControlAccentColor,
|
||||
keyboard: theme.rootController.keyboardColor
|
||||
),
|
||||
|
|
|
|||
|
|
@ -163,7 +163,7 @@ private final class PremiumGiftCodeSheetContent: CombinedComponent {
|
|||
component: AnyComponentWithIdentity(id: "close", component: AnyComponent(
|
||||
BundleIconComponent(
|
||||
name: "Navigation/Close",
|
||||
tintColor: theme.rootController.navigationBar.glassBarButtonForegroundColor
|
||||
tintColor: theme.chat.inputPanel.panelControlColor
|
||||
)
|
||||
)),
|
||||
action: { _ in
|
||||
|
|
|
|||
|
|
@ -864,7 +864,7 @@ private final class LimitSheetContent: CombinedComponent {
|
|||
component: AnyComponentWithIdentity(id: "close", component: AnyComponent(
|
||||
BundleIconComponent(
|
||||
name: "Navigation/Close",
|
||||
tintColor: theme.rootController.navigationBar.glassBarButtonForegroundColor
|
||||
tintColor: theme.chat.inputPanel.panelControlColor
|
||||
)
|
||||
)),
|
||||
action: { _ in
|
||||
|
|
|
|||
|
|
@ -170,7 +170,7 @@ private final class SheetContent: CombinedComponent {
|
|||
component: AnyComponentWithIdentity(id: "close", component: AnyComponent(
|
||||
BundleIconComponent(
|
||||
name: "Navigation/Close",
|
||||
tintColor: theme.rootController.navigationBar.glassBarButtonForegroundColor
|
||||
tintColor: theme.chat.inputPanel.panelControlColor
|
||||
)
|
||||
)),
|
||||
action: { _ in
|
||||
|
|
|
|||
|
|
@ -21,6 +21,8 @@ swift_library(
|
|||
"//submodules/AvatarNode:AvatarNode",
|
||||
"//submodules/AccountContext:AccountContext",
|
||||
"//submodules/TelegramUI/Components/EmojiStatusComponent",
|
||||
"//submodules/TelegramUI/Components/GlassBackgroundComponent",
|
||||
"//submodules/Components/ComponentDisplayAdapters",
|
||||
],
|
||||
visibility = [
|
||||
"//visibility:public",
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ import AvatarNode
|
|||
import AccountContext
|
||||
import ComponentFlow
|
||||
import EmojiStatusComponent
|
||||
import ComponentDisplayAdapters
|
||||
|
||||
private func generateLoupeIcon(color: UIColor) -> UIImage? {
|
||||
return generateTintedImage(image: UIImage(bundleImageName: "Components/Search Bar/Loupe"), color: color)
|
||||
|
|
@ -549,7 +550,10 @@ private class SearchBarTextField: UITextField, UIScrollViewDelegate {
|
|||
|
||||
super.init(frame: CGRect())
|
||||
|
||||
self.addSubnode(self.placeholderLabel)
|
||||
if case .glass = style {
|
||||
} else {
|
||||
self.addSubnode(self.placeholderLabel)
|
||||
}
|
||||
self.addSubnode(self.prefixLabel)
|
||||
self.addSubnode(self.clippingNode)
|
||||
self.clippingNode.addSubnode(self.tokenContainerNode)
|
||||
|
|
@ -685,8 +689,11 @@ private class SearchBarTextField: UITextField, UIScrollViewDelegate {
|
|||
let textRect = self.textRect(forBounds: bounds)
|
||||
let labelSize = self.placeholderLabel.updateLayout(textRect.size)
|
||||
|
||||
if case .inlineNavigation = self.style {
|
||||
placeholderYOffset += 0.0//(bounds.height - labelSize.height) * 0.5
|
||||
switch self.style {
|
||||
case .glass, .inlineNavigation:
|
||||
placeholderYOffset += 0.0
|
||||
case .legacy, .modern:
|
||||
break
|
||||
}
|
||||
|
||||
self.placeholderLabel.frame = CGRect(origin: CGPoint(x: textRect.minX + placeholderXOffset, y: floorToScreenPixels(bounds.height - labelSize.height) * 0.5), size: labelSize)
|
||||
|
|
@ -821,10 +828,11 @@ public enum SearchBarStyle {
|
|||
case modern
|
||||
case legacy
|
||||
case inlineNavigation
|
||||
case glass
|
||||
|
||||
var font: UIFont {
|
||||
switch self {
|
||||
case .modern, .inlineNavigation:
|
||||
case .modern, .inlineNavigation, .glass:
|
||||
return Font.regular(17.0)
|
||||
case .legacy:
|
||||
return Font.regular(14.0)
|
||||
|
|
@ -835,6 +843,8 @@ public enum SearchBarStyle {
|
|||
switch self {
|
||||
case .modern, .inlineNavigation:
|
||||
return 21.0
|
||||
case .glass:
|
||||
return 22.0
|
||||
case .legacy:
|
||||
return 14.0
|
||||
}
|
||||
|
|
@ -844,6 +854,8 @@ public enum SearchBarStyle {
|
|||
switch self {
|
||||
case .inlineNavigation:
|
||||
return 48.0
|
||||
case .glass:
|
||||
return 44.0
|
||||
case .modern:
|
||||
return 36.0
|
||||
case .legacy:
|
||||
|
|
@ -855,6 +867,8 @@ public enum SearchBarStyle {
|
|||
switch self {
|
||||
case .inlineNavigation:
|
||||
return 0.0
|
||||
case .glass:
|
||||
return 20.0
|
||||
case .modern:
|
||||
return 10.0
|
||||
case .legacy:
|
||||
|
|
@ -889,6 +903,8 @@ public class SearchBarNode: ASDisplayNode, UITextFieldDelegate {
|
|||
private let clearButton: HighlightableButtonNode
|
||||
private let cancelButton: HighlightableButtonNode
|
||||
|
||||
private var takenSearchPlaceholderContentView: SearchBarPlaceholderContentView?
|
||||
|
||||
public var placeholderString: NSAttributedString? {
|
||||
get {
|
||||
return self.textField.placeholderString
|
||||
|
|
@ -953,6 +969,9 @@ public class SearchBarNode: ASDisplayNode, UITextFieldDelegate {
|
|||
activityIndicator.removeFromSupernode()
|
||||
}
|
||||
self.iconNode.isHidden = self.activity
|
||||
if let takenSearchPlaceholderContentView = self.takenSearchPlaceholderContentView {
|
||||
takenSearchPlaceholderContentView.updateSearchIconVisibility(isVisible: !self.activity)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -977,7 +996,7 @@ public class SearchBarNode: ASDisplayNode, UITextFieldDelegate {
|
|||
|
||||
private var validLayout: (CGSize, CGFloat, CGFloat)?
|
||||
|
||||
private let fieldStyle: SearchBarStyle
|
||||
public let fieldStyle: SearchBarStyle
|
||||
private let forceSeparator: Bool
|
||||
private var theme: SearchBarNodeTheme?
|
||||
private var strings: PresentationStrings?
|
||||
|
|
@ -1023,16 +1042,20 @@ public class SearchBarNode: ASDisplayNode, UITextFieldDelegate {
|
|||
|
||||
super.init()
|
||||
|
||||
if case .inlineNavigation = self.fieldStyle {
|
||||
} else {
|
||||
switch self.fieldStyle {
|
||||
case .glass, .inlineNavigation:
|
||||
break
|
||||
case .legacy, .modern:
|
||||
self.addSubnode(self.backgroundNode)
|
||||
self.addSubnode(self.separatorNode)
|
||||
self.addSubnode(self.textBackgroundNode)
|
||||
}
|
||||
self.view.addSubview(self.textField)
|
||||
|
||||
if case .inlineNavigation = self.fieldStyle {
|
||||
} else {
|
||||
switch self.fieldStyle {
|
||||
case .glass, .inlineNavigation:
|
||||
break
|
||||
case .legacy, .modern:
|
||||
self.addSubnode(self.iconNode)
|
||||
self.addSubnode(self.cancelButton)
|
||||
}
|
||||
|
|
@ -1121,16 +1144,22 @@ public class SearchBarNode: ASDisplayNode, UITextFieldDelegate {
|
|||
textBackgroundHeight = self.fieldStyle.height
|
||||
}
|
||||
let verticalOffset: CGFloat
|
||||
if case .inlineNavigation = self.fieldStyle {
|
||||
switch self.fieldStyle {
|
||||
case .inlineNavigation, .glass:
|
||||
verticalOffset = -textBackgroundHeight
|
||||
} else {
|
||||
case .legacy, .modern:
|
||||
verticalOffset = boundingSize.height - 82.0
|
||||
}
|
||||
let cancelButtonSize = self.cancelButton.measure(CGSize(width: 100.0, height: CGFloat.infinity))
|
||||
transition.updateFrame(node: self.cancelButton, frame: CGRect(origin: CGPoint(x: contentFrame.maxX - 10.0 - cancelButtonSize.width, y: verticalOffset + textBackgroundHeight + floorToScreenPixels((textBackgroundHeight - cancelButtonSize.height) / 2.0)), size: cancelButtonSize))
|
||||
|
||||
let padding = self.fieldStyle.padding
|
||||
var textBackgroundFrame = CGRect(origin: CGPoint(x: contentFrame.minX + padding, y: verticalOffset + textBackgroundHeight), size: CGSize(width: contentFrame.width - padding * 2.0 - (self.hasCancelButton ? cancelButtonSize.width + 11.0 : 0.0), height: textBackgroundHeight))
|
||||
var textBackgroundFrame = CGRect(origin: CGPoint(x: contentFrame.minX + padding, y: verticalOffset + textBackgroundHeight), size: CGSize(width: contentFrame.width - padding - (self.hasCancelButton ? cancelButtonSize.width + 11.0 : 0.0), height: textBackgroundHeight))
|
||||
if case .glass = self.fieldStyle {
|
||||
textBackgroundFrame.size.width -= 8.0
|
||||
} else {
|
||||
textBackgroundFrame.size.width -= padding
|
||||
}
|
||||
transition.updateFrame(node: self.textBackgroundNode, frame: textBackgroundFrame)
|
||||
|
||||
var textFrame = CGRect(origin: CGPoint(x: 0.0, y: textBackgroundFrame.minY), size: CGSize(width: max(1.0, textBackgroundFrame.size.width - 24.0 - 27.0), height: textBackgroundFrame.size.height))
|
||||
|
|
@ -1172,7 +1201,24 @@ public class SearchBarNode: ASDisplayNode, UITextFieldDelegate {
|
|||
}
|
||||
|
||||
public func animateIn(from node: SearchBarPlaceholderNode, duration: Double, timingFunction: String) {
|
||||
let initialTextBackgroundFrame = node.view.convert(node.backgroundNode.frame, to: self.view)
|
||||
let takenSearchPlaceholderContentView = node.takeContents()
|
||||
takenSearchPlaceholderContentView.onCancel = { [weak self] in
|
||||
guard let self else {
|
||||
return
|
||||
}
|
||||
self.cancel?()
|
||||
}
|
||||
self.takenSearchPlaceholderContentView = takenSearchPlaceholderContentView
|
||||
self.view.insertSubview(takenSearchPlaceholderContentView, at: 0)
|
||||
|
||||
let sourceFrame = node.view.convert(node.bounds, to: self.view)
|
||||
let targetFrame = CGRect(origin: CGPoint(x: 16.0, y: 0.0), size: CGSize(width: max(0.0, self.bounds.width - 16.0 * 2.0), height: 44.0))
|
||||
let transition: ContainedViewLayoutTransition = .animated(duration: duration, curve: timingFunction == kCAMediaTimingFunctionSpring ? .spring : .easeInOut)
|
||||
takenSearchPlaceholderContentView.frame = sourceFrame
|
||||
transition.updateFrame(view: takenSearchPlaceholderContentView, frame: targetFrame)
|
||||
takenSearchPlaceholderContentView.update(size: targetFrame.size, isActive: true, transition: transition)
|
||||
|
||||
/*let initialTextBackgroundFrame = node.view.convert(node.backgroundView.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)))
|
||||
if let fromBackgroundColor = node.backgroundColor, let toBackgroundColor = self.backgroundNode.backgroundColor {
|
||||
|
|
@ -1186,7 +1232,7 @@ public class SearchBarNode: ASDisplayNode, UITextFieldDelegate {
|
|||
self.separatorNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: duration)
|
||||
self.separatorNode.layer.animateFrame(from: initialSeparatorFrame, to: self.separatorNode.frame, duration: duration, timingFunction: timingFunction)
|
||||
|
||||
if let fromTextBackgroundColor = node.backgroundNode.backgroundColor, let toTextBackgroundColor = self.textBackgroundNode.backgroundColor {
|
||||
if let fromTextBackgroundColor = node.backgroundView.backgroundColor, let toTextBackgroundColor = self.textBackgroundNode.backgroundColor {
|
||||
self.textBackgroundNode.layer.animate(from: fromTextBackgroundColor.cgColor, to: toTextBackgroundColor.cgColor, keyPath: "backgroundColor", timingFunction: timingFunction, duration: duration * 1.0)
|
||||
}
|
||||
self.textBackgroundNode.layer.animateFrame(from: initialTextBackgroundFrame, to: self.textBackgroundNode.frame, duration: duration, timingFunction: timingFunction)
|
||||
|
|
@ -1211,7 +1257,7 @@ public class SearchBarNode: ASDisplayNode, UITextFieldDelegate {
|
|||
|
||||
let cancelButtonFrame = self.cancelButton.frame
|
||||
self.cancelButton.layer.animatePosition(from: CGPoint(x: self.bounds.size.width + cancelButtonFrame.size.width / 2.0, y: initialTextBackgroundFrame.midY), to: self.cancelButton.layer.position, duration: duration, timingFunction: timingFunction)
|
||||
node.isHidden = true
|
||||
node.isHidden = true*/
|
||||
}
|
||||
|
||||
public func deactivate(clear: Bool = true) {
|
||||
|
|
@ -1225,7 +1271,7 @@ public class SearchBarNode: ASDisplayNode, UITextFieldDelegate {
|
|||
}
|
||||
|
||||
public func transitionOut(to node: SearchBarPlaceholderNode, transition: ContainedViewLayoutTransition, completion: @escaping () -> Void) {
|
||||
let targetTextBackgroundFrame = node.view.convert(node.backgroundNode.frame, to: self.view)
|
||||
/*let targetTextBackgroundFrame = node.view.convert(node.backgroundView.frame, to: self.view)
|
||||
|
||||
let duration: Double = transition.isAnimated ? 0.5 : 0.0
|
||||
let timingFunction = kCAMediaTimingFunctionSpring
|
||||
|
|
@ -1341,8 +1387,8 @@ public class SearchBarNode: ASDisplayNode, UITextFieldDelegate {
|
|||
let transitionBackgroundNode = ASDisplayNode()
|
||||
transitionBackgroundNode.isLayerBacked = true
|
||||
transitionBackgroundNode.displaysAsynchronously = false
|
||||
transitionBackgroundNode.backgroundColor = node.backgroundNode.backgroundColor
|
||||
transitionBackgroundNode.cornerRadius = node.backgroundNode.cornerRadius
|
||||
transitionBackgroundNode.backgroundColor = node.backgroundView.backgroundColor
|
||||
transitionBackgroundNode.cornerRadius = node.backgroundView.layer.cornerRadius
|
||||
self.insertSubnode(transitionBackgroundNode, aboveSubnode: self.textBackgroundNode)
|
||||
|
||||
transitionBackgroundNode.layer.animateFrame(from: self.textBackgroundNode.frame, to: targetTextBackgroundFrame, duration: duration, timingFunction: timingFunction, removeOnCompletion: false)
|
||||
|
|
@ -1365,7 +1411,52 @@ public class SearchBarNode: ASDisplayNode, UITextFieldDelegate {
|
|||
self.iconNode.layer.animateFrame(from: self.iconNode.frame, to: targetIconFrame, duration: duration, timingFunction: timingFunction, removeOnCompletion: false)
|
||||
|
||||
let cancelButtonFrame = self.cancelButton.frame
|
||||
self.cancelButton.layer.animatePosition(from: self.cancelButton.layer.position, to: CGPoint(x: self.bounds.size.width + cancelButtonFrame.size.width / 2.0, y: targetTextBackgroundFrame.midY), duration: duration, timingFunction: timingFunction, removeOnCompletion: false)
|
||||
self.cancelButton.layer.animatePosition(from: self.cancelButton.layer.position, to: CGPoint(x: self.bounds.size.width + cancelButtonFrame.size.width / 2.0, y: targetTextBackgroundFrame.midY), duration: duration, timingFunction: timingFunction, removeOnCompletion: false)*/
|
||||
|
||||
if let takenSearchPlaceholderContentView = self.takenSearchPlaceholderContentView {
|
||||
let transition = ComponentTransition(transition)
|
||||
let alphaTransition: ComponentTransition = transition.animation.isImmediate ? .immediate : .easeInOut(duration: 0.2)
|
||||
|
||||
let sourceFrame = node.view.convert(node.bounds, to: self.view)
|
||||
takenSearchPlaceholderContentView.update(size: sourceFrame.size, isActive: false, transition: transition.containedViewLayoutTransition)
|
||||
takenSearchPlaceholderContentView.updatePlaceholderVisibility(isVisible: true)
|
||||
takenSearchPlaceholderContentView.updateSearchIconVisibility(isVisible: true)
|
||||
|
||||
transition.setFrame(view: takenSearchPlaceholderContentView, frame: sourceFrame, completion: { [weak node] _ in
|
||||
node?.putBackContents()
|
||||
completion()
|
||||
})
|
||||
|
||||
let textBackgroundHeight: CGFloat
|
||||
if case .inlineNavigation = self.fieldStyle {
|
||||
textBackgroundHeight = sourceFrame.height
|
||||
} else {
|
||||
textBackgroundHeight = self.fieldStyle.height
|
||||
}
|
||||
|
||||
let padding = self.fieldStyle.padding
|
||||
var textBackgroundFrame = CGRect(origin: CGPoint(x: sourceFrame.minX + padding, y: sourceFrame.minY), size: CGSize(width: sourceFrame.width - padding, height: textBackgroundHeight))
|
||||
if case .glass = self.fieldStyle {
|
||||
textBackgroundFrame.size.width -= 8.0
|
||||
} else {
|
||||
textBackgroundFrame.size.width -= padding
|
||||
}
|
||||
|
||||
var textFrame = CGRect(origin: CGPoint(x: 0.0, y: textBackgroundFrame.minY), size: CGSize(width: max(1.0, textBackgroundFrame.size.width - 24.0 - 27.0), height: textBackgroundFrame.size.height))
|
||||
if case .inlineNavigation = self.fieldStyle {
|
||||
textFrame.size.width = sourceFrame.width - 27.0
|
||||
textBackgroundFrame.size.width = sourceFrame.width
|
||||
} else {
|
||||
textFrame.origin.x = textBackgroundFrame.minX + 24.0
|
||||
}
|
||||
transition.setFrame(view: self.textField, frame: textFrame)
|
||||
//alphaTransition.setAlpha(view: self.textField, alpha: 0.0)
|
||||
self.textField.isHidden = true
|
||||
|
||||
let clearSize = self.clearButton.bounds.size
|
||||
alphaTransition.setAlpha(view: self.clearButton.view, alpha: 0.0)
|
||||
transition.setFrame(view: self.clearButton.view, frame: CGRect(origin: CGPoint(x: textBackgroundFrame.maxX - 6.0 - clearSize.width, y: textBackgroundFrame.minY + floor((textBackgroundFrame.size.height - clearSize.height) / 2.0)), size: clearSize))
|
||||
}
|
||||
}
|
||||
|
||||
public func textFieldDidBeginEditing(_ textField: UITextField) {
|
||||
|
|
@ -1437,6 +1528,9 @@ public class SearchBarNode: ASDisplayNode, UITextFieldDelegate {
|
|||
let transition: ContainedViewLayoutTransition = animated ? .animated(duration: 0.3, curve: .spring) : .immediate
|
||||
let placeholderTransition = !isEmpty ? .immediate : transition
|
||||
placeholderTransition.updateAlpha(node: self.textField.placeholderLabel, alpha: isEmpty ? 1.0 : 0.0)
|
||||
if let takenSearchPlaceholderContentView = self.takenSearchPlaceholderContentView {
|
||||
takenSearchPlaceholderContentView.updatePlaceholderVisibility(isVisible: isEmpty)
|
||||
}
|
||||
|
||||
let clearIsHidden = (textIsEmpty && tokensEmpty) && self.prefixString == nil
|
||||
transition.updateAlpha(node: self.clearButton.imageNode, alpha: clearIsHidden ? 0.0 : 1.0)
|
||||
|
|
|
|||
|
|
@ -5,6 +5,8 @@ import AsyncDisplayKit
|
|||
import Display
|
||||
import AppBundle
|
||||
import ComponentFlow
|
||||
import GlassBackgroundComponent
|
||||
import ComponentDisplayAdapters
|
||||
|
||||
private let templateLoupeIcon = UIImage(bundleImageName: "Components/Search Bar/Loupe")
|
||||
|
||||
|
|
@ -21,44 +23,72 @@ private class SearchBarPlaceholderNodeView: UIView {
|
|||
}
|
||||
}
|
||||
|
||||
public class SearchBarPlaceholderNode: ASDisplayNode {
|
||||
public var activate: (() -> Void)?
|
||||
public final class SearchBarPlaceholderContentView: UIView {
|
||||
private struct Params {
|
||||
var placeholderString: NSAttributedString?
|
||||
var compactPlaceholderString: NSAttributedString?
|
||||
var constrainedSize: CGSize
|
||||
var expansionProgress: CGFloat
|
||||
var iconColor: UIColor
|
||||
var foregroundColor: UIColor
|
||||
var backgroundColor: UIColor
|
||||
var controlColor: UIColor
|
||||
var isActive: Bool
|
||||
|
||||
init(placeholderString: NSAttributedString?, compactPlaceholderString: NSAttributedString?, constrainedSize: CGSize, expansionProgress: CGFloat, iconColor: UIColor, foregroundColor: UIColor, backgroundColor: UIColor, controlColor: UIColor, isActive: Bool) {
|
||||
self.placeholderString = placeholderString
|
||||
self.compactPlaceholderString = compactPlaceholderString
|
||||
self.constrainedSize = constrainedSize
|
||||
self.expansionProgress = expansionProgress
|
||||
self.iconColor = iconColor
|
||||
self.foregroundColor = foregroundColor
|
||||
self.backgroundColor = backgroundColor
|
||||
self.controlColor = controlColor
|
||||
self.isActive = isActive
|
||||
}
|
||||
}
|
||||
|
||||
private let fieldStyle: SearchBarStyle
|
||||
public let backgroundNode: ASDisplayNode
|
||||
let fieldStyle: SearchBarStyle
|
||||
let backgroundNode: ASDisplayNode?
|
||||
let glassBackgroundView: GlassBackgroundView?
|
||||
private var fillBackgroundColor: UIColor
|
||||
private var foregroundColor: UIColor
|
||||
private var iconColor: UIColor
|
||||
public let iconNode: ASImageNode
|
||||
public let labelNode: TextNode
|
||||
let iconNode: ASImageNode
|
||||
let labelNode: TextNode
|
||||
|
||||
var pointerInteraction: PointerInteraction?
|
||||
private var close: (background: GlassBackgroundView, icon: UIImageView)?
|
||||
|
||||
public private(set) var placeholderString: NSAttributedString?
|
||||
private(set) var placeholderString: NSAttributedString?
|
||||
|
||||
private(set) var accessoryComponentContainer: UIView?
|
||||
private(set) var accessoryComponentView: ComponentHostView<Empty>?
|
||||
private var params: Params?
|
||||
|
||||
convenience public override init() {
|
||||
self.init(fieldStyle: .legacy)
|
||||
}
|
||||
public var onCancel: (() -> Void)?
|
||||
|
||||
public init(fieldStyle: SearchBarStyle = .legacy) {
|
||||
init(fieldStyle: SearchBarStyle) {
|
||||
self.fieldStyle = fieldStyle
|
||||
|
||||
self.backgroundNode = ASDisplayNode()
|
||||
self.backgroundNode.isLayerBacked = false
|
||||
self.backgroundNode.displaysAsynchronously = false
|
||||
|
||||
self.fillBackgroundColor = UIColor.white
|
||||
self.foregroundColor = UIColor(rgb: 0xededed)
|
||||
self.iconColor = UIColor(rgb: 0x000000, alpha: 0.0)
|
||||
|
||||
self.backgroundNode.backgroundColor = self.foregroundColor
|
||||
self.backgroundNode.cornerRadius = self.fieldStyle.cornerDiameter / 2.0
|
||||
switch fieldStyle {
|
||||
case .legacy, .modern:
|
||||
let backgroundNode = ASDisplayNode()
|
||||
backgroundNode.isLayerBacked = false
|
||||
backgroundNode.displaysAsynchronously = false
|
||||
backgroundNode.backgroundColor = self.foregroundColor
|
||||
backgroundNode.cornerRadius = self.fieldStyle.cornerDiameter / 2.0
|
||||
self.backgroundNode = backgroundNode
|
||||
|
||||
self.glassBackgroundView = nil
|
||||
case .inlineNavigation, .glass:
|
||||
self.glassBackgroundView = GlassBackgroundView()
|
||||
|
||||
self.backgroundNode = nil
|
||||
}
|
||||
|
||||
self.iconNode = ASImageNode()
|
||||
self.iconNode.isLayerBacked = true
|
||||
self.iconNode.displaysAsynchronously = false
|
||||
self.iconNode.displayWithoutProcessing = true
|
||||
|
||||
|
|
@ -66,51 +96,404 @@ public class SearchBarPlaceholderNode: ASDisplayNode {
|
|||
self.labelNode.isOpaque = false
|
||||
self.labelNode.isUserInteractionEnabled = false
|
||||
|
||||
super.init(frame: CGRect())
|
||||
|
||||
if let backgroundNode = self.backgroundNode {
|
||||
backgroundNode.isUserInteractionEnabled = true
|
||||
self.addSubview(backgroundNode.view)
|
||||
}
|
||||
if let glassBackgroundView = self.glassBackgroundView {
|
||||
self.addSubview(glassBackgroundView)
|
||||
|
||||
glassBackgroundView.contentView.addSubview(self.iconNode.view)
|
||||
glassBackgroundView.contentView.addSubview(self.labelNode.view)
|
||||
} else {
|
||||
self.addSubview(self.iconNode.view)
|
||||
self.addSubview(self.labelNode.view)
|
||||
}
|
||||
}
|
||||
|
||||
required public init?(coder: NSCoder) {
|
||||
fatalError("init(coder:) has not been implemented")
|
||||
}
|
||||
|
||||
@objc private func onCloseTapGesture(_ recognizer: UITapGestureRecognizer) {
|
||||
if case .ended = recognizer.state {
|
||||
self.onCancel?()
|
||||
}
|
||||
}
|
||||
|
||||
func updateLayout(
|
||||
placeholderString: NSAttributedString?,
|
||||
compactPlaceholderString: NSAttributedString?,
|
||||
constrainedSize: CGSize,
|
||||
expansionProgress: CGFloat,
|
||||
iconColor: UIColor,
|
||||
foregroundColor: UIColor,
|
||||
backgroundColor: UIColor,
|
||||
controlColor: UIColor,
|
||||
transition: ContainedViewLayoutTransition
|
||||
) -> CGFloat {
|
||||
let params = Params(
|
||||
placeholderString: placeholderString,
|
||||
compactPlaceholderString: compactPlaceholderString,
|
||||
constrainedSize: constrainedSize,
|
||||
expansionProgress: expansionProgress,
|
||||
iconColor: iconColor,
|
||||
foregroundColor: foregroundColor,
|
||||
backgroundColor: backgroundColor,
|
||||
controlColor: controlColor,
|
||||
isActive: false
|
||||
)
|
||||
self.params = params
|
||||
return self.updateLayout(params: params, transition: transition)
|
||||
}
|
||||
|
||||
public func update(size: CGSize, isActive: Bool, transition: ContainedViewLayoutTransition) {
|
||||
guard var params = self.params else {
|
||||
return
|
||||
}
|
||||
params.constrainedSize = size
|
||||
params.expansionProgress = 1.0
|
||||
params.isActive = isActive
|
||||
let _ = self.updateLayout(params: params, transition: transition)
|
||||
}
|
||||
|
||||
private func updateLayout(params: Params, transition: ContainedViewLayoutTransition) -> CGFloat {
|
||||
let labelLayout = TextNode.asyncLayout(self.labelNode)
|
||||
let currentForegroundColor = self.foregroundColor
|
||||
let currentIconColor = self.iconColor
|
||||
|
||||
let placeholderString: NSAttributedString?
|
||||
if params.constrainedSize.width < 350.0 {
|
||||
placeholderString = params.compactPlaceholderString
|
||||
} else {
|
||||
placeholderString = params.placeholderString
|
||||
}
|
||||
|
||||
let (labelLayoutResult, labelApply) = labelLayout(TextNodeLayoutArguments(attributedString: placeholderString, backgroundColor: .clear, maximumNumberOfLines: 1, truncationType: .end, constrainedSize: params.constrainedSize, alignment: .natural, cutout: nil, insets: UIEdgeInsets()))
|
||||
|
||||
var updatedColor: UIColor?
|
||||
var updatedIconImage: UIImage?
|
||||
if !currentForegroundColor.isEqual(params.foregroundColor) {
|
||||
updatedColor = params.foregroundColor
|
||||
}
|
||||
if !currentIconColor.isEqual(params.iconColor) {
|
||||
updatedIconImage = generateLoupeIcon(color: params.iconColor)
|
||||
}
|
||||
|
||||
let height = params.constrainedSize.height * params.expansionProgress
|
||||
|
||||
let _ = labelApply()
|
||||
|
||||
self.fillBackgroundColor = params.backgroundColor
|
||||
self.foregroundColor = params.foregroundColor
|
||||
self.iconColor = params.iconColor
|
||||
if let backgroundNode = self.backgroundNode {
|
||||
backgroundNode.isUserInteractionEnabled = params.expansionProgress > 0.9999
|
||||
}
|
||||
|
||||
if let updatedColor, let backgroundNode = self.backgroundNode {
|
||||
backgroundNode.backgroundColor = updatedColor
|
||||
}
|
||||
if let updatedIconImage {
|
||||
self.iconNode.image = updatedIconImage
|
||||
}
|
||||
|
||||
self.placeholderString = placeholderString
|
||||
|
||||
var iconSize = CGSize()
|
||||
var totalWidth = labelLayoutResult.size.width
|
||||
|
||||
var spacing: CGFloat = 4.0
|
||||
if params.isActive {
|
||||
spacing = 2.0
|
||||
}
|
||||
|
||||
let iconX: CGFloat
|
||||
if let iconImage = self.iconNode.image {
|
||||
iconSize = iconImage.size
|
||||
totalWidth += iconSize.width + spacing
|
||||
if params.isActive {
|
||||
iconX = 8.0
|
||||
} else {
|
||||
iconX = floor((params.constrainedSize.width - totalWidth) / 2.0)
|
||||
}
|
||||
transition.updateFrame(node: self.iconNode, frame: CGRect(origin: CGPoint(x: iconX, y: floorToScreenPixels((height - iconSize.height) / 2.0)), size: iconSize))
|
||||
} else {
|
||||
iconX = 12.0
|
||||
}
|
||||
var textOffset: CGFloat = 0.0
|
||||
if params.constrainedSize.height >= 36.0 {
|
||||
textOffset += 1.0
|
||||
}
|
||||
let labelX: CGFloat = iconX + iconSize.width + spacing
|
||||
let labelFrame = CGRect(origin: CGPoint(x: labelX, y: floorToScreenPixels((height - labelLayoutResult.size.height) / 2.0) + textOffset), size: labelLayoutResult.size)
|
||||
transition.updateFrame(node: self.labelNode, frame: labelFrame)
|
||||
|
||||
var innerAlpha = max(0.0, params.expansionProgress - 0.77) / 0.23
|
||||
if innerAlpha > 0.9999 {
|
||||
innerAlpha = 1.0
|
||||
} else if innerAlpha < 0.0001 {
|
||||
innerAlpha = 0.0
|
||||
}
|
||||
if self.labelNode.alpha != innerAlpha {
|
||||
if !transition.isAnimated {
|
||||
self.labelNode.layer.removeAnimation(forKey: "opacity")
|
||||
self.iconNode.layer.removeAnimation(forKey: "opacity")
|
||||
}
|
||||
|
||||
transition.updateAlpha(node: self.labelNode, alpha: innerAlpha)
|
||||
transition.updateAlpha(node: self.iconNode, alpha: innerAlpha)
|
||||
}
|
||||
|
||||
let outerAlpha = min(0.3, params.expansionProgress) / 0.3
|
||||
let cornerRadius = min(self.fieldStyle.cornerDiameter / 2.0, height / 2.0)
|
||||
|
||||
if let backgroundNode = self.backgroundNode, backgroundNode.cornerRadius != cornerRadius {
|
||||
if !transition.isAnimated {
|
||||
backgroundNode.layer.removeAnimation(forKey: "cornerRadius")
|
||||
}
|
||||
transition.updateCornerRadius(node: backgroundNode, cornerRadius: cornerRadius)
|
||||
}
|
||||
|
||||
if let backgroundNode = self.backgroundNode, backgroundNode.alpha != outerAlpha {
|
||||
if !transition.isAnimated {
|
||||
backgroundNode.layer.removeAnimation(forKey: "opacity")
|
||||
}
|
||||
transition.updateAlpha(node: backgroundNode, alpha: outerAlpha)
|
||||
}
|
||||
|
||||
var backgroundFrame = CGRect(origin: CGPoint(), size: CGSize(width: params.constrainedSize.width, height: height))
|
||||
if params.isActive {
|
||||
backgroundFrame.size.width -= 44.0 + 8.0
|
||||
}
|
||||
|
||||
if let backgroundNode = self.backgroundNode, backgroundNode.frame != backgroundFrame {
|
||||
if !transition.isAnimated {
|
||||
backgroundNode.layer.removeAnimation(forKey: "position")
|
||||
backgroundNode.layer.removeAnimation(forKey: "bounds")
|
||||
}
|
||||
transition.updateFrame(node: backgroundNode, frame: CGRect(origin: CGPoint(), size: CGSize(width: params.constrainedSize.width, height: height)))
|
||||
}
|
||||
|
||||
if let glassBackgroundView = self.glassBackgroundView {
|
||||
transition.updatePosition(layer: glassBackgroundView.layer, position: backgroundFrame.center)
|
||||
transition.updateBounds(layer: glassBackgroundView.layer, bounds: CGRect(origin: CGPoint(), size: backgroundFrame.size))
|
||||
var backgroundAlpha: CGFloat = 1.0
|
||||
if backgroundFrame.height < 16.0 {
|
||||
backgroundAlpha = max(0.0, min(1.0, backgroundFrame.height / 16.0))
|
||||
}
|
||||
ComponentTransition(transition).setAlpha(view: glassBackgroundView, alpha: backgroundAlpha)
|
||||
let isDark = params.backgroundColor.hsb.b < 0.5
|
||||
glassBackgroundView.update(size: backgroundFrame.size, cornerRadius: backgroundFrame.height * 0.5, isDark: isDark, tintColor: .init(kind: .panel, color: UIColor(white: isDark ? 0.0 : 1.0, alpha: 0.6)), isInteractive: true, transition: ComponentTransition(transition))
|
||||
|
||||
if params.isActive {
|
||||
let transition = ComponentTransition(transition)
|
||||
|
||||
let closeFrame = CGRect(origin: CGPoint(x: params.constrainedSize.width - 44.0, y: 0.0), size: CGSize(width: 44.0, height: 44.0))
|
||||
|
||||
let close: (background: GlassBackgroundView, icon: UIImageView)
|
||||
var closeTransition = transition
|
||||
if let current = self.close {
|
||||
close = current
|
||||
} else {
|
||||
closeTransition = closeTransition.withAnimation(.none)
|
||||
close = (GlassBackgroundView(), UIImageView())
|
||||
self.close = close
|
||||
|
||||
close.icon.image = generateImage(CGSize(width: 40.0, height: 40.0), contextGenerator: { size, context in
|
||||
context.clear(CGRect(origin: CGPoint(), size: size))
|
||||
|
||||
context.setLineWidth(2.0)
|
||||
context.setLineCap(.round)
|
||||
context.setStrokeColor(UIColor.white.cgColor)
|
||||
|
||||
context.beginPath()
|
||||
context.move(to: CGPoint(x: 12.0, y: 12.0))
|
||||
context.addLine(to: CGPoint(x: size.width - 12.0, y: size.height - 12.0))
|
||||
context.move(to: CGPoint(x: size.width - 12.0, y: 12.0))
|
||||
context.addLine(to: CGPoint(x: 12.0, y: size.height - 12.0))
|
||||
context.strokePath()
|
||||
})?.withRenderingMode(.alwaysTemplate)
|
||||
|
||||
close.background.contentView.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(self.onCloseTapGesture(_:))))
|
||||
|
||||
close.background.contentView.addSubview(close.icon)
|
||||
self.insertSubview(close.background, at: 0)
|
||||
|
||||
if let image = close.icon.image {
|
||||
close.icon.frame = image.size.centered(in: CGRect(origin: CGPoint(), size: closeFrame.size))
|
||||
}
|
||||
|
||||
close.background.frame = closeFrame.offsetBy(dx: closeFrame.width + 40.0, dy: 0.0)
|
||||
let isDark = params.backgroundColor.hsb.b < 0.5
|
||||
close.background.update(size: close.background.bounds.size, cornerRadius: close.background.bounds.height * 0.5, isDark: isDark, tintColor: .init(kind: .panel, color: UIColor(white: isDark ? 0.0 : 1.0, alpha: 0.6)), isInteractive: true, transition: .immediate)
|
||||
ComponentTransition.immediate.setScale(view: close.background, scale: 0.001)
|
||||
}
|
||||
|
||||
close.icon.tintColor = params.controlColor
|
||||
|
||||
transition.setPosition(view: close.background, position: closeFrame.center)
|
||||
transition.setBounds(view: close.background, bounds: CGRect(origin: CGPoint(), size: closeFrame.size))
|
||||
transition.setScale(view: close.background, scale: 1.0)
|
||||
|
||||
if let image = close.icon.image {
|
||||
transition.setFrame(view: close.icon, frame: image.size.centered(in: CGRect(origin: CGPoint(), size: closeFrame.size)))
|
||||
}
|
||||
|
||||
let isDark = params.backgroundColor.hsb.b < 0.5
|
||||
close.background.update(size: closeFrame.size, cornerRadius: closeFrame.height * 0.5, isDark: isDark, tintColor: .init(kind: .panel, color: UIColor(white: isDark ? 0.0 : 1.0, alpha: 0.6)), isInteractive: true, transition: closeTransition)
|
||||
} else {
|
||||
let transition = ComponentTransition(transition)
|
||||
|
||||
if let close = self.close {
|
||||
self.close = nil
|
||||
let closeBackground = close.background
|
||||
let closeFrame = CGRect(origin: CGPoint(x: params.constrainedSize.width - 44.0, y: 0.0), size: CGSize(width: 44.0, height: 44.0)).offsetBy(dx: 44.0 + 40.0, dy: 0.0)
|
||||
transition.setPosition(view: closeBackground, position: closeFrame.center)
|
||||
transition.setBounds(view: closeBackground, bounds: CGRect(origin: CGPoint(), size: closeFrame.size))
|
||||
let isDark = params.backgroundColor.hsb.b < 0.5
|
||||
closeBackground.update(size: closeFrame.size, cornerRadius: closeFrame.height * 0.5, isDark: isDark, tintColor: .init(kind: .panel, color: UIColor(white: isDark ? 0.0 : 1.0, alpha: 0.6)), isInteractive: true, transition: transition)
|
||||
transition.setScale(view: closeBackground, scale: 0.001, completion: { [weak closeBackground] _ in
|
||||
closeBackground?.removeFromSuperview()
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*if let accessoryComponentContainer = self.accessoryComponentContainer {
|
||||
accessoryComponentContainer.frame = CGRect(origin: CGPoint(x: constrainedSize.width - accessoryComponentContainer.bounds.width - 4.0, y: floor((constrainedSize.height * expansionProgress - accessoryComponentContainer.bounds.height) / 2.0)), size: accessoryComponentContainer.bounds.size)
|
||||
transition.updateAlpha(layer: accessoryComponentContainer.layer, alpha: innerAlpha)
|
||||
}*/
|
||||
|
||||
return height
|
||||
}
|
||||
|
||||
public func updatePlaceholderVisibility(isVisible: Bool) {
|
||||
self.labelNode.isHidden = !isVisible
|
||||
}
|
||||
|
||||
public func updateSearchIconVisibility(isVisible: Bool) {
|
||||
self.iconNode.isHidden = !isVisible
|
||||
}
|
||||
}
|
||||
|
||||
public class SearchBarPlaceholderNode: ASDisplayNode {
|
||||
private struct Params {
|
||||
var placeholderString: NSAttributedString?
|
||||
var compactPlaceholderString: NSAttributedString?
|
||||
var constrainedSize: CGSize
|
||||
var expansionProgress: CGFloat
|
||||
var iconColor: UIColor
|
||||
var foregroundColor: UIColor
|
||||
var backgroundColor: UIColor
|
||||
var controlColor: UIColor
|
||||
|
||||
init(placeholderString: NSAttributedString?, compactPlaceholderString: NSAttributedString?, constrainedSize: CGSize, expansionProgress: CGFloat, iconColor: UIColor, foregroundColor: UIColor, backgroundColor: UIColor, controlColor: UIColor) {
|
||||
self.placeholderString = placeholderString
|
||||
self.compactPlaceholderString = compactPlaceholderString
|
||||
self.constrainedSize = constrainedSize
|
||||
self.expansionProgress = expansionProgress
|
||||
self.iconColor = iconColor
|
||||
self.foregroundColor = foregroundColor
|
||||
self.backgroundColor = backgroundColor
|
||||
self.controlColor = controlColor
|
||||
}
|
||||
}
|
||||
|
||||
public var activate: (() -> Void)?
|
||||
|
||||
private let containerView: UIView
|
||||
private let contentView: SearchBarPlaceholderContentView
|
||||
|
||||
public var backgroundView: UIView {
|
||||
if let backgroundNode = self.contentView.backgroundNode {
|
||||
return backgroundNode.view
|
||||
} else if let glassBackgroundView = self.contentView.glassBackgroundView {
|
||||
return glassBackgroundView
|
||||
} else {
|
||||
preconditionFailure()
|
||||
}
|
||||
}
|
||||
|
||||
public var iconNode: ASImageNode {
|
||||
return self.contentView.iconNode
|
||||
}
|
||||
|
||||
public var labelNode: TextNode {
|
||||
return self.contentView.labelNode
|
||||
}
|
||||
|
||||
public var fieldStyle: SearchBarStyle {
|
||||
return self.contentView.fieldStyle
|
||||
}
|
||||
|
||||
var pointerInteraction: PointerInteraction?
|
||||
|
||||
public var placeholderString: NSAttributedString? {
|
||||
return self.contentView.placeholderString
|
||||
}
|
||||
|
||||
private(set) var accessoryComponentContainer: UIView?
|
||||
private(set) var accessoryComponentView: ComponentHostView<Empty>?
|
||||
|
||||
private var params: Params?
|
||||
private var currentLayoutHeight: CGFloat?
|
||||
private var isTakenOut: Bool = false
|
||||
|
||||
public init(fieldStyle: SearchBarStyle = .legacy) {
|
||||
self.containerView = UIView()
|
||||
self.contentView = SearchBarPlaceholderContentView(fieldStyle: fieldStyle)
|
||||
|
||||
super.init()
|
||||
|
||||
self.addSubnode(self.backgroundNode)
|
||||
self.addSubnode(self.iconNode)
|
||||
self.addSubnode(self.labelNode)
|
||||
|
||||
self.backgroundNode.isUserInteractionEnabled = true
|
||||
self.view.addSubview(self.containerView)
|
||||
self.containerView.addSubview(self.contentView)
|
||||
}
|
||||
|
||||
override public func didLoad() {
|
||||
super.didLoad()
|
||||
|
||||
let gestureRecognizer = TapLongTapOrDoubleTapGestureRecognizer(target: self, action: #selector(self.backgroundTap(_:)))
|
||||
gestureRecognizer.highlight = { [weak self] point in
|
||||
/*gestureRecognizer.highlight = { [weak self] point in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
if let _ = point {
|
||||
strongSelf.backgroundNode.layer.animate(from: (strongSelf.backgroundNode.backgroundColor ?? strongSelf.foregroundColor).cgColor, to: strongSelf.foregroundColor.withMultipliedBrightnessBy(0.9).cgColor, keyPath: "backgroundColor", timingFunction: CAMediaTimingFunctionName.easeInEaseOut.rawValue, duration: 0.2)
|
||||
strongSelf.backgroundNode.backgroundColor = strongSelf.foregroundColor.withMultipliedBrightnessBy(0.9)
|
||||
} else {
|
||||
strongSelf.backgroundNode.layer.animate(from: (strongSelf.backgroundNode.backgroundColor ?? strongSelf.foregroundColor).cgColor, to: strongSelf.foregroundColor.cgColor, keyPath: "backgroundColor", timingFunction: CAMediaTimingFunctionName.easeInEaseOut.rawValue, duration: 0.4)
|
||||
strongSelf.backgroundNode.backgroundColor = strongSelf.foregroundColor
|
||||
if let backgroundNode = strongSelf.contentView.backgroundNode {
|
||||
if let _ = point {
|
||||
backgroundNode.layer.animate(from: (backgroundNode.backgroundColor ?? strongSelf.foregroundColor).cgColor, to: strongSelf.foregroundColor.withMultipliedBrightnessBy(0.9).cgColor, keyPath: "backgroundColor", timingFunction: CAMediaTimingFunctionName.easeInEaseOut.rawValue, duration: 0.2)
|
||||
backgroundNode.backgroundColor = strongSelf.foregroundColor.withMultipliedBrightnessBy(0.9)
|
||||
} else {
|
||||
backgroundNode.layer.animate(from: (backgroundNode.backgroundColor ?? strongSelf.foregroundColor).cgColor, to: strongSelf.foregroundColor.cgColor, keyPath: "backgroundColor", timingFunction: CAMediaTimingFunctionName.easeInEaseOut.rawValue, duration: 0.4)
|
||||
backgroundNode.backgroundColor = strongSelf.foregroundColor
|
||||
}
|
||||
}
|
||||
}
|
||||
}*/
|
||||
gestureRecognizer.tapActionAtPoint = { _ in
|
||||
return .waitForSingleTap
|
||||
}
|
||||
self.backgroundNode.view.addGestureRecognizer(gestureRecognizer)
|
||||
self.containerView.addGestureRecognizer(gestureRecognizer)
|
||||
|
||||
self.pointerInteraction = PointerInteraction(node: self, style: .caret, willEnter: { [weak self] in
|
||||
/*self.pointerInteraction = PointerInteraction(node: self, style: .caret, willEnter: { [weak self] in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
strongSelf.backgroundNode.backgroundColor = strongSelf.foregroundColor.withMultipliedBrightnessBy(0.95)
|
||||
if let backgroundNode = strongSelf.contentView.backgroundNode {
|
||||
backgroundNode.backgroundColor = strongSelf.foregroundColor.withMultipliedBrightnessBy(0.95)
|
||||
}
|
||||
}, willExit: { [weak self] in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
strongSelf.backgroundNode.backgroundColor = strongSelf.foregroundColor
|
||||
})
|
||||
if let backgroundNode = strongSelf.contentView.backgroundNode {
|
||||
backgroundNode.backgroundColor = strongSelf.foregroundColor
|
||||
}
|
||||
})*/
|
||||
}
|
||||
|
||||
public func setAccessoryComponent(component: AnyComponent<Empty>?) {
|
||||
if let component = component {
|
||||
/*if let component = component {
|
||||
let accessoryComponentContainer: UIView
|
||||
if let current = self.accessoryComponentContainer {
|
||||
accessoryComponentContainer = current
|
||||
|
|
@ -142,119 +525,43 @@ public class SearchBarPlaceholderNode: ASDisplayNode {
|
|||
accessoryComponentView.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.2, removeOnCompletion: false, completion: { [weak accessoryComponentView] _ in
|
||||
accessoryComponentView?.removeFromSuperview()
|
||||
})
|
||||
}*/
|
||||
}
|
||||
|
||||
public func takeContents() -> SearchBarPlaceholderContentView {
|
||||
self.isTakenOut = true
|
||||
return self.contentView
|
||||
}
|
||||
|
||||
public func putBackContents() {
|
||||
self.isTakenOut = false
|
||||
self.containerView.addSubview(self.contentView)
|
||||
if let params = self.params {
|
||||
let _ = self.update(params: params, transition: .immediate)
|
||||
}
|
||||
}
|
||||
|
||||
public func asyncLayout() -> (_ placeholderString: NSAttributedString?, _ compactPlaceholderString: NSAttributedString?, _ constrainedSize: CGSize, _ expansionProgress: CGFloat, _ iconColor: UIColor, _ foregroundColor: UIColor, _ backgroundColor: UIColor, _ transition: ContainedViewLayoutTransition) -> (CGFloat, () -> Void) {
|
||||
let labelLayout = TextNode.asyncLayout(self.labelNode)
|
||||
let currentForegroundColor = self.foregroundColor
|
||||
let currentIconColor = self.iconColor
|
||||
public func updateLayout(placeholderString: NSAttributedString?, compactPlaceholderString: NSAttributedString?, constrainedSize: CGSize, expansionProgress: CGFloat, iconColor: UIColor, foregroundColor: UIColor, backgroundColor: UIColor, controlColor: UIColor, transition: ContainedViewLayoutTransition) -> CGFloat {
|
||||
let params = Params(placeholderString: placeholderString, compactPlaceholderString: compactPlaceholderString, constrainedSize: constrainedSize, expansionProgress: expansionProgress, iconColor: iconColor, foregroundColor: foregroundColor, backgroundColor: backgroundColor, controlColor: controlColor)
|
||||
self.params = params
|
||||
|
||||
return { fullPlaceholderString, compactPlaceholderString, constrainedSize, expansionProgress, iconColor, foregroundColor, backgroundColor, transition in
|
||||
let placeholderString: NSAttributedString?
|
||||
if constrainedSize.width < 350.0 {
|
||||
placeholderString = compactPlaceholderString
|
||||
} else {
|
||||
placeholderString = fullPlaceholderString
|
||||
}
|
||||
|
||||
let (labelLayoutResult, labelApply) = labelLayout(TextNodeLayoutArguments(attributedString: placeholderString, backgroundColor: .clear, maximumNumberOfLines: 1, truncationType: .end, constrainedSize: constrainedSize, alignment: .natural, cutout: nil, insets: UIEdgeInsets()))
|
||||
|
||||
var updatedColor: UIColor?
|
||||
var updatedIconImage: UIImage?
|
||||
if !currentForegroundColor.isEqual(foregroundColor) {
|
||||
updatedColor = foregroundColor
|
||||
}
|
||||
if !currentIconColor.isEqual(iconColor) {
|
||||
updatedIconImage = generateLoupeIcon(color: iconColor)
|
||||
}
|
||||
|
||||
let height = constrainedSize.height * expansionProgress
|
||||
return (height, { [weak self] in
|
||||
if let strongSelf = self {
|
||||
let _ = labelApply()
|
||||
|
||||
strongSelf.fillBackgroundColor = backgroundColor
|
||||
strongSelf.foregroundColor = foregroundColor
|
||||
strongSelf.iconColor = iconColor
|
||||
strongSelf.backgroundNode.isUserInteractionEnabled = expansionProgress > 0.9999
|
||||
|
||||
if let updatedColor = updatedColor {
|
||||
strongSelf.backgroundNode.backgroundColor = updatedColor
|
||||
}
|
||||
if let updatedIconImage = updatedIconImage {
|
||||
strongSelf.iconNode.image = updatedIconImage
|
||||
}
|
||||
|
||||
strongSelf.placeholderString = placeholderString
|
||||
|
||||
var iconSize = CGSize()
|
||||
var totalWidth = labelLayoutResult.size.width
|
||||
let spacing: CGFloat = 6.0
|
||||
|
||||
if let iconImage = strongSelf.iconNode.image {
|
||||
iconSize = iconImage.size
|
||||
totalWidth += iconSize.width + spacing
|
||||
transition.updateFrame(node: strongSelf.iconNode, frame: CGRect(origin: CGPoint(x: floor((constrainedSize.width - totalWidth) / 2.0), y: floorToScreenPixels((height - iconSize.height) / 2.0)), size: iconSize))
|
||||
}
|
||||
var textOffset: CGFloat = 0.0
|
||||
if constrainedSize.height >= 36.0 {
|
||||
textOffset += 1.0
|
||||
}
|
||||
let labelFrame = CGRect(origin: CGPoint(x: floor((constrainedSize.width - totalWidth) / 2.0) + iconSize.width + spacing, y: floorToScreenPixels((height - labelLayoutResult.size.height) / 2.0) + textOffset), size: labelLayoutResult.size)
|
||||
transition.updateFrame(node: strongSelf.labelNode, frame: labelFrame)
|
||||
|
||||
var innerAlpha = max(0.0, expansionProgress - 0.77) / 0.23
|
||||
if innerAlpha > 0.9999 {
|
||||
innerAlpha = 1.0
|
||||
} else if innerAlpha < 0.0001 {
|
||||
innerAlpha = 0.0
|
||||
}
|
||||
if strongSelf.labelNode.alpha != innerAlpha {
|
||||
if !transition.isAnimated {
|
||||
strongSelf.labelNode.layer.removeAnimation(forKey: "opacity")
|
||||
strongSelf.iconNode.layer.removeAnimation(forKey: "opacity")
|
||||
}
|
||||
|
||||
transition.updateAlpha(node: strongSelf.labelNode, alpha: innerAlpha)
|
||||
transition.updateAlpha(node: strongSelf.iconNode, alpha: innerAlpha)
|
||||
}
|
||||
|
||||
let outerAlpha = min(0.3, expansionProgress) / 0.3
|
||||
let cornerRadius = min(strongSelf.fieldStyle.cornerDiameter / 2.0, height / 2.0)
|
||||
|
||||
if strongSelf.backgroundNode.cornerRadius != cornerRadius {
|
||||
if !transition.isAnimated {
|
||||
strongSelf.backgroundNode.layer.removeAnimation(forKey: "cornerRadius")
|
||||
}
|
||||
transition.updateCornerRadius(node: strongSelf.backgroundNode, cornerRadius: cornerRadius)
|
||||
}
|
||||
|
||||
if strongSelf.backgroundNode.alpha != outerAlpha {
|
||||
if !transition.isAnimated {
|
||||
strongSelf.backgroundNode.layer.removeAnimation(forKey: "opacity")
|
||||
}
|
||||
transition.updateAlpha(node: strongSelf.backgroundNode, alpha: outerAlpha)
|
||||
}
|
||||
|
||||
if strongSelf.backgroundNode.frame != CGRect(origin: CGPoint(), size: CGSize(width: constrainedSize.width, height: height)) {
|
||||
if !transition.isAnimated {
|
||||
strongSelf.backgroundNode.layer.removeAnimation(forKey: "position")
|
||||
strongSelf.backgroundNode.layer.removeAnimation(forKey: "bounds")
|
||||
}
|
||||
transition.updateFrame(node: strongSelf.backgroundNode, frame: CGRect(origin: CGPoint(), size: CGSize(width: constrainedSize.width, height: height)))
|
||||
}
|
||||
|
||||
if let accessoryComponentContainer = strongSelf.accessoryComponentContainer {
|
||||
accessoryComponentContainer.frame = CGRect(origin: CGPoint(x: constrainedSize.width - accessoryComponentContainer.bounds.width - 4.0, y: floor((constrainedSize.height * expansionProgress - accessoryComponentContainer.bounds.height) / 2.0)), size: accessoryComponentContainer.bounds.size)
|
||||
transition.updateAlpha(layer: accessoryComponentContainer.layer, alpha: innerAlpha)
|
||||
|
||||
}
|
||||
}
|
||||
})
|
||||
if self.isTakenOut {
|
||||
return self.currentLayoutHeight ?? 44.0
|
||||
} else {
|
||||
let height = self.update(params: params, transition: transition)
|
||||
self.currentLayoutHeight = height
|
||||
return height
|
||||
}
|
||||
}
|
||||
|
||||
private func update(params: Params, transition: ContainedViewLayoutTransition) -> CGFloat {
|
||||
let height = self.contentView.updateLayout(placeholderString: params.placeholderString, compactPlaceholderString: params.compactPlaceholderString, constrainedSize: params.constrainedSize, expansionProgress: params.expansionProgress, iconColor: params.iconColor, foregroundColor: params.foregroundColor, backgroundColor: params.backgroundColor, controlColor: params.controlColor, transition: transition)
|
||||
let size = CGSize(width: params.constrainedSize.width, height: height)
|
||||
transition.updateFrame(view: self.containerView, frame: CGRect(origin: CGPoint(), size: size))
|
||||
transition.updateFrame(view: self.contentView, frame: CGRect(origin: CGPoint(), size: size))
|
||||
return height
|
||||
}
|
||||
|
||||
@objc private func backgroundTap(_ recognizer: TapLongTapOrDoubleTapGestureRecognizer) {
|
||||
if case .ended = recognizer.state {
|
||||
self.activate?()
|
||||
|
|
|
|||
|
|
@ -15,7 +15,6 @@ swift_library(
|
|||
"//submodules/Display",
|
||||
"//submodules/TelegramPresentationData",
|
||||
"//submodules/SearchBarNode",
|
||||
"//submodules/ChatListSearchItemNode",
|
||||
"//submodules/TelegramUI/Components/GlassBackgroundComponent",
|
||||
"//submodules/ComponentFlow",
|
||||
"//submodules/Components/ComponentDisplayAdapters",
|
||||
|
|
|
|||
|
|
@ -1,33 +1,6 @@
|
|||
import Foundation
|
||||
import AsyncDisplayKit
|
||||
import Display
|
||||
import ChatListSearchItemNode
|
||||
|
||||
public func fixSearchableListNodeScrolling(_ listNode: ListView) {
|
||||
var searchItemNode: ListViewItemNode?
|
||||
var nextItemNode: ListViewItemNode?
|
||||
|
||||
listNode.forEachItemNode { itemNode in
|
||||
if let itemNode = itemNode as? ChatListSearchItemNode {
|
||||
searchItemNode = itemNode
|
||||
} else if searchItemNode != nil && nextItemNode == nil {
|
||||
nextItemNode = itemNode as? ListViewItemNode
|
||||
}
|
||||
}
|
||||
|
||||
if let searchItemNode = searchItemNode {
|
||||
let itemFrame = searchItemNode.apparentFrame
|
||||
if itemFrame.contains(CGPoint(x: 0.0, y: listNode.insets.top)) {
|
||||
if itemFrame.minY + itemFrame.height * 0.6 < listNode.insets.top {
|
||||
if let nextItemNode = nextItemNode {
|
||||
listNode.ensureItemNodeVisibleAtTopInset(nextItemNode)
|
||||
}
|
||||
} else {
|
||||
listNode.ensureItemNodeVisibleAtTopInset(searchItemNode)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public func fixNavigationSearchableListNodeScrolling(_ listNode: ListView, searchNode: NavigationBarSearchContentNode) -> Bool {
|
||||
if searchNode.expansionProgress > 0.0 && searchNode.expansionProgress < 1.0 {
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ import AppBundle
|
|||
import ActivityIndicator
|
||||
|
||||
private let searchBarFont = Font.regular(17.0)
|
||||
public let navigationBarSearchContentHeight: CGFloat = 54.0
|
||||
public let navigationBarSearchContentHeight: CGFloat = 60.0
|
||||
|
||||
public class NavigationBarSearchContentNode: NavigationBarContentNode {
|
||||
private struct Params: Equatable {
|
||||
|
|
@ -45,7 +45,7 @@ public class NavigationBarSearchContentNode: NavigationBarContentNode {
|
|||
self.compactPlaceholder = compactPlaceholder ?? placeholder
|
||||
self.inline = inline
|
||||
|
||||
self.placeholderNode = SearchBarPlaceholderNode(fieldStyle: .modern)
|
||||
self.placeholderNode = SearchBarPlaceholderNode(fieldStyle: .glass)
|
||||
self.placeholderNode.labelNode.displaysAsynchronously = false
|
||||
|
||||
super.init()
|
||||
|
|
@ -56,6 +56,8 @@ public class NavigationBarSearchContentNode: NavigationBarContentNode {
|
|||
|
||||
self.addSubnode(self.placeholderNode)
|
||||
self.placeholderNode.activate = activate
|
||||
|
||||
//self.backgroundColor = .red
|
||||
}
|
||||
|
||||
public func updateThemeAndPlaceholder(theme: PresentationTheme, placeholder: String, compactPlaceholder: String? = nil) {
|
||||
|
|
@ -117,10 +119,10 @@ public class NavigationBarSearchContentNode: NavigationBarContentNode {
|
|||
}
|
||||
|
||||
private func updatePlaceholder(_ progress: CGFloat, size: CGSize, leftInset: CGFloat, rightInset: CGFloat, transition: ContainedViewLayoutTransition) {
|
||||
let padding: CGFloat = 10.0
|
||||
let padding: CGFloat = 16.0
|
||||
let baseWidth = size.width - padding * 2.0 - leftInset - rightInset
|
||||
|
||||
let fieldHeight: CGFloat = 36.0
|
||||
let fieldHeight: CGFloat = 44.0
|
||||
let fraction = fieldHeight / self.nominalHeight
|
||||
let fullFraction = navigationBarSearchContentHeight / self.nominalHeight
|
||||
|
||||
|
|
@ -131,8 +133,6 @@ public class NavigationBarSearchContentNode: NavigationBarContentNode {
|
|||
var visibleProgress: CGFloat = toLow + (self.expansionProgress - fromLow) * (toHigh - toLow) / (fromHigh - fromLow)
|
||||
visibleProgress = max(0.0, min(1.0, visibleProgress))
|
||||
|
||||
let searchBarNodeLayout = self.placeholderNode.asyncLayout()
|
||||
|
||||
let textColor = self.theme?.rootController.navigationSearchBar.inputPlaceholderTextColor ?? UIColor(rgb: 0x8e8e93)
|
||||
var fillColor = self.theme?.rootController.navigationSearchBar.inputFillColor ?? .clear
|
||||
if self.inline, let theme = self.theme, fillColor.distance(to: theme.list.blocksBackgroundColor) < 100 {
|
||||
|
|
@ -140,12 +140,12 @@ public class NavigationBarSearchContentNode: NavigationBarContentNode {
|
|||
}
|
||||
|
||||
let backgroundColor = self.theme?.rootController.navigationBar.opaqueBackgroundColor ?? .clear
|
||||
let controlColor = self.theme?.chat.inputPanel.panelControlColor ?? .black
|
||||
|
||||
let placeholderString = NSAttributedString(string: self.placeholder, font: searchBarFont, textColor: textColor)
|
||||
let compactPlaceholderString = NSAttributedString(string: self.compactPlaceholder, font: searchBarFont, textColor: textColor)
|
||||
|
||||
let (searchBarHeight, searchBarApply) = searchBarNodeLayout(placeholderString, compactPlaceholderString, CGSize(width: baseWidth, height: fieldHeight), visibleProgress, textColor, fillColor, backgroundColor, transition)
|
||||
searchBarApply()
|
||||
let searchBarHeight = self.placeholderNode.updateLayout(placeholderString: placeholderString, compactPlaceholderString: compactPlaceholderString, constrainedSize: CGSize(width: baseWidth, height: fieldHeight), expansionProgress: visibleProgress, iconColor: textColor, foregroundColor: fillColor, backgroundColor: backgroundColor, controlColor: controlColor, transition: transition)
|
||||
|
||||
let searchBarFrame = CGRect(origin: CGPoint(x: padding + leftInset, y: size.height + (1.0 - visibleProgress) * fieldHeight - 8.0 - fieldHeight), size: CGSize(width: baseWidth, height: fieldHeight))
|
||||
transition.updateFrame(node: self.placeholderNode, frame: searchBarFrame)
|
||||
|
|
|
|||
|
|
@ -157,6 +157,8 @@ public final class SearchDisplayController {
|
|||
}
|
||||
|
||||
public func containerLayoutUpdated(_ layout: ContainerViewLayout, navigationBarHeight: CGFloat, transition: ContainedViewLayoutTransition) {
|
||||
let defaultNavigationBarHeight = navigationBarHeight
|
||||
|
||||
let statusBarHeight: CGFloat = layout.statusBarHeight ?? 0.0
|
||||
let searchBarHeight: CGFloat = max(20.0, statusBarHeight) + 44.0
|
||||
let navigationBarOffset: CGFloat
|
||||
|
|
@ -173,14 +175,20 @@ public final class SearchDisplayController {
|
|||
navigationBarFrame.size.height = 64.0
|
||||
}
|
||||
navigationBarFrame.size.height += 10.0
|
||||
let navigationBarHeight = navigationBarFrame.maxY
|
||||
var navigationBarHeight = navigationBarFrame.maxY
|
||||
|
||||
if !self.searchBarIsExternal, let searchBar = self.searchBar {
|
||||
let searchBarFrame: CGRect
|
||||
if case .navigation = self.mode {
|
||||
searchBarFrame = CGRect(x: 0.0, y: 0.0, width: layout.size.width, height: 54.0)
|
||||
if case .glass = searchBar.fieldStyle {
|
||||
navigationBarHeight = defaultNavigationBarHeight
|
||||
searchBarFrame = CGRect(x: 0.0, y: 0.0, width: layout.size.width, height: 44.0)
|
||||
} else {
|
||||
searchBarFrame = CGRect(x: 0.0, y: 0.0, width: layout.size.width, height: 54.0)
|
||||
}
|
||||
} else {
|
||||
searchBarFrame = navigationBarFrame
|
||||
navigationBarHeight = navigationBarFrame.maxY + 8.0
|
||||
}
|
||||
transition.updateFrame(node: searchBar, frame: searchBarFrame)
|
||||
searchBar.updateLayout(boundingSize: searchBarFrame.size, leftInset: layout.safeInsets.left, rightInset: layout.safeInsets.right, transition: transition)
|
||||
|
|
@ -236,8 +244,6 @@ public final class SearchDisplayController {
|
|||
if !self.contentNode.hasDim {
|
||||
self.backgroundNode.alpha = 1.0
|
||||
self.backgroundNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.2, timingFunction: CAMediaTimingFunctionName.linear.rawValue)
|
||||
|
||||
self.backgroundNode.layer.animateScale(from: 0.85, to: 1.0, duration: 0.5, timingFunction: kCAMediaTimingFunctionSpring)
|
||||
}
|
||||
|
||||
if !self.searchBarIsExternal {
|
||||
|
|
@ -247,7 +253,7 @@ public final class SearchDisplayController {
|
|||
}
|
||||
} else {
|
||||
if let placeholder = placeholder {
|
||||
let initialTextBackgroundFrame = placeholder.convert(placeholder.backgroundNode.frame, to: nil)
|
||||
let initialTextBackgroundFrame = placeholder.convert(placeholder.backgroundView.frame, to: nil)
|
||||
let contentNodePosition = self.backgroundNode.layer.position
|
||||
if contentNode.animateBackgroundAppearance {
|
||||
self.backgroundNode.layer.animatePosition(from: CGPoint(x: contentNodePosition.x, y: contentNodePosition.y + (initialTextBackgroundFrame.maxY + 8.0 - contentNavigationBarHeight)), to: contentNodePosition, duration: 0.5, timingFunction: kCAMediaTimingFunctionSpring)
|
||||
|
|
|
|||
|
|
@ -23,7 +23,6 @@ swift_library(
|
|||
"//submodules/PresentationDataUtils:PresentationDataUtils",
|
||||
"//submodules/AvatarNode:AvatarNode",
|
||||
"//submodules/CallListUI:CallListUI",
|
||||
"//submodules/ChatListSearchItemNode:ChatListSearchItemNode",
|
||||
"//submodules/ChatListSearchItemHeader:ChatListSearchItemHeader",
|
||||
"//submodules/ChatListUI:ChatListUI",
|
||||
"//submodules/ContactsPeerItem:ContactsPeerItem",
|
||||
|
|
|
|||
|
|
@ -36,7 +36,7 @@ public class LocalizationListController: ViewController {
|
|||
|
||||
self.presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
||||
|
||||
super.init(navigationBarPresentationData: NavigationBarPresentationData(presentationData: self.presentationData))
|
||||
super.init(navigationBarPresentationData: NavigationBarPresentationData(presentationData: self.presentationData, style: .glass))
|
||||
|
||||
self.editItem = UIBarButtonItem(title: self.presentationData.strings.Common_Done, style: .done, target: self, action: #selector(self.editPressed))
|
||||
self.doneItem = UIBarButtonItem(title: self.presentationData.strings.Common_Edit, style: .plain, target: self, action: #selector(self.editPressed))
|
||||
|
|
@ -86,7 +86,7 @@ public class LocalizationListController: ViewController {
|
|||
|
||||
private func updateThemeAndStrings() {
|
||||
self.statusBar.statusBarStyle = self.presentationData.theme.rootController.statusBarStyle.style
|
||||
self.navigationBar?.updatePresentationData(NavigationBarPresentationData(presentationData: self.presentationData), transition: .immediate)
|
||||
self.navigationBar?.updatePresentationData(NavigationBarPresentationData(presentationData: self.presentationData, style: .glass), transition: .immediate)
|
||||
self.searchContentNode?.updateThemeAndPlaceholder(theme: self.presentationData.theme, placeholder: self.presentationData.strings.Common_Search)
|
||||
self.title = self.presentationData.strings.Settings_AppLanguage
|
||||
self.navigationItem.backBarButtonItem = UIBarButtonItem(title: self.presentationData.strings.Common_Back, style: .plain, target: nil, action: nil)
|
||||
|
|
|
|||
|
|
@ -165,7 +165,7 @@ private final class LocalizationListSearchContainerNode: SearchDisplayController
|
|||
self.presentationDataPromise = Promise(self.presentationData)
|
||||
|
||||
self.dimNode = ASDisplayNode()
|
||||
self.dimNode.backgroundColor = UIColor.black.withAlphaComponent(0.5)
|
||||
self.dimNode.backgroundColor = .clear
|
||||
|
||||
self.listNode = ListView()
|
||||
self.listNode.accessibilityPageScrolledString = { row, count in
|
||||
|
|
@ -809,7 +809,7 @@ final class LocalizationListControllerNode: ViewControllerTracingNode {
|
|||
|
||||
self.searchDisplayController = SearchDisplayController(presentationData: self.presentationData, contentNode: LocalizationListSearchContainerNode(context: self.context, listState: self.currentListState ?? LocalizationListState.defaultSettings, selectLocalization: { [weak self] info in self?.selectLocalization(info) }, applyingCode: self.applyingCode.get()), inline: true, cancel: { [weak self] in
|
||||
self?.requestDeactivateSearch()
|
||||
})
|
||||
}, fieldStyle: placeholderNode.fieldStyle)
|
||||
|
||||
self.searchDisplayController?.containerLayoutUpdated(containerLayout, navigationBarHeight: navigationBarHeight, transition: .immediate)
|
||||
self.searchDisplayController?.activate(insertSubnode: { [weak self, weak placeholderNode] subnode, isSearchBar in
|
||||
|
|
|
|||
|
|
@ -243,7 +243,6 @@ private final class NotificationExceptionArguments {
|
|||
}
|
||||
|
||||
private enum NotificationExceptionEntryId: Hashable {
|
||||
case search
|
||||
case peerId(Int64)
|
||||
case addException
|
||||
case removeAll
|
||||
|
|
@ -254,13 +253,6 @@ private enum NotificationExceptionEntryId: Hashable {
|
|||
|
||||
static func ==(lhs: NotificationExceptionEntryId, rhs: NotificationExceptionEntryId) -> Bool {
|
||||
switch lhs {
|
||||
case .search:
|
||||
switch rhs {
|
||||
case .search:
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
case .addException:
|
||||
switch rhs {
|
||||
case .addException:
|
||||
|
|
@ -302,7 +294,6 @@ private enum NotificationExceptionEntry : ItemListNodeEntry {
|
|||
|
||||
typealias ItemGenerationArguments = NotificationExceptionArguments
|
||||
|
||||
case search(PresentationTheme, PresentationStrings)
|
||||
case peer(index: Int, peer: EnginePeer, theme: PresentationTheme, strings: PresentationStrings, dateFormat: PresentationDateTimeFormat, nameDisplayOrder: PresentationPersonNameOrder, description: String, notificationSettings: TelegramPeerNotificationSettings, revealed: Bool, editing: Bool, isSearching: Bool)
|
||||
case addPeer(index: Int, peer: EnginePeer, theme: PresentationTheme, strings: PresentationStrings, dateFormat: PresentationDateTimeFormat, nameDisplayOrder: PresentationPersonNameOrder)
|
||||
case addException(PresentationTheme, PresentationStrings, NotificationExceptionMode.Mode, Bool)
|
||||
|
|
@ -311,10 +302,6 @@ private enum NotificationExceptionEntry : ItemListNodeEntry {
|
|||
func item(presentationData: ItemListPresentationData, arguments: Any) -> ListViewItem {
|
||||
let arguments = arguments as! NotificationExceptionArguments
|
||||
switch self {
|
||||
case let .search(theme, strings):
|
||||
return NotificationSearchItem(theme: theme, placeholder: strings.Common_Search, activate: {
|
||||
arguments.activateSearch()
|
||||
})
|
||||
case let .addException(theme, strings, mode, editing):
|
||||
let icon: UIImage?
|
||||
switch mode {
|
||||
|
|
@ -352,8 +339,6 @@ private enum NotificationExceptionEntry : ItemListNodeEntry {
|
|||
|
||||
var stableId: NotificationExceptionEntryId {
|
||||
switch self {
|
||||
case .search:
|
||||
return .search
|
||||
case .addException:
|
||||
return .addException
|
||||
case let .peer(_, peer, _, _, _, _, _, _, _, _, _):
|
||||
|
|
@ -367,13 +352,6 @@ private enum NotificationExceptionEntry : ItemListNodeEntry {
|
|||
|
||||
static func == (lhs: NotificationExceptionEntry, rhs: NotificationExceptionEntry) -> Bool {
|
||||
switch lhs {
|
||||
case let .search(lhsTheme, lhsStrings):
|
||||
switch rhs {
|
||||
case let .search(rhsTheme, rhsStrings):
|
||||
return lhsTheme === rhsTheme && lhsStrings === rhsStrings
|
||||
default:
|
||||
return false
|
||||
}
|
||||
case let .addException(lhsTheme, lhsStrings, lhsMode, lhsEditing):
|
||||
switch rhs {
|
||||
case let .addException(rhsTheme, rhsStrings, rhsMode, rhsEditing):
|
||||
|
|
@ -406,18 +384,16 @@ private enum NotificationExceptionEntry : ItemListNodeEntry {
|
|||
|
||||
static func <(lhs: NotificationExceptionEntry, rhs: NotificationExceptionEntry) -> Bool {
|
||||
switch lhs {
|
||||
case .search:
|
||||
return true
|
||||
case .addException:
|
||||
switch rhs {
|
||||
case .search, .addException:
|
||||
case .addException:
|
||||
return false
|
||||
default:
|
||||
return true
|
||||
}
|
||||
case let .peer(lhsIndex, _, _, _, _, _, _, _, _, _, _):
|
||||
switch rhs {
|
||||
case .search, .addException:
|
||||
case .addException:
|
||||
return false
|
||||
case let .peer(rhsIndex, _, _, _, _, _, _, _, _, _, _):
|
||||
return lhsIndex < rhsIndex
|
||||
|
|
@ -428,7 +404,7 @@ private enum NotificationExceptionEntry : ItemListNodeEntry {
|
|||
}
|
||||
case let .addPeer(lhsIndex, _, _, _, _, _):
|
||||
switch rhs {
|
||||
case .search, .addException:
|
||||
case .addException:
|
||||
return false
|
||||
case let .peer(rhsIndex, _, _, _, _, _, _, _, _, _, _):
|
||||
return lhsIndex < rhsIndex
|
||||
|
|
@ -936,7 +912,7 @@ final class NotificationExceptionsControllerNode: ViewControllerTracingNode {
|
|||
|
||||
self.searchDisplayController = SearchDisplayController(presentationData: self.presentationData, contentNode: NotificationExceptionsSearchContainerNode(context: self.context, mode: self.stateValue.modify {$0}.mode, arguments: self.arguments!), cancel: { [weak self] in
|
||||
self?.requestDeactivateSearch(true)
|
||||
})
|
||||
}, fieldStyle: placeholderNode.fieldStyle)
|
||||
|
||||
self.searchDisplayController?.containerLayoutUpdated(containerLayout, navigationBarHeight: navigationBarHeight, transition: .immediate)
|
||||
self.searchDisplayController?.activate(insertSubnode: { [weak self, weak placeholderNode] subnode, isSearchBar in
|
||||
|
|
@ -1007,7 +983,7 @@ private final class NotificationExceptionsSearchContainerNode: SearchDisplayCont
|
|||
self.themeAndStringsPromise = Promise((self.presentationData.theme, self.presentationData.strings))
|
||||
|
||||
self.dimNode = ASDisplayNode()
|
||||
self.dimNode.backgroundColor = UIColor.black.withAlphaComponent(0.5)
|
||||
self.dimNode.backgroundColor = .clear
|
||||
|
||||
self.listNode = ListView()
|
||||
self.listNode.accessibilityPageScrolledString = { row, count in
|
||||
|
|
|
|||
|
|
@ -39,7 +39,9 @@ public class NotificationExceptionsController: ViewController {
|
|||
self.updatedMode = updatedMode
|
||||
self.presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
||||
|
||||
super.init(navigationBarPresentationData: NavigationBarPresentationData(presentationData: self.presentationData))
|
||||
super.init(navigationBarPresentationData: NavigationBarPresentationData(presentationData: self.presentationData, style: .glass))
|
||||
|
||||
self._hasGlassStyle = true
|
||||
|
||||
self.removeAllItem = UIBarButtonItem(title: self.presentationData.strings.Notification_Exceptions_DeleteAll, style: .plain, target: self, action: #selector(self.removeAllPressed))
|
||||
self.editItem = UIBarButtonItem(title: self.presentationData.strings.Common_Done, style: .done, target: self, action: #selector(self.editPressed))
|
||||
|
|
@ -90,7 +92,7 @@ public class NotificationExceptionsController: ViewController {
|
|||
|
||||
private func updateThemeAndStrings() {
|
||||
self.statusBar.statusBarStyle = self.presentationData.theme.rootController.statusBarStyle.style
|
||||
self.navigationBar?.updatePresentationData(NavigationBarPresentationData(presentationData: self.presentationData), transition: .immediate)
|
||||
self.navigationBar?.updatePresentationData(NavigationBarPresentationData(presentationData: self.presentationData, style: .glass), transition: .immediate)
|
||||
self.searchContentNode?.updateThemeAndPlaceholder(theme: self.presentationData.theme, placeholder: self.presentationData.strings.Common_Search)
|
||||
self.title = self.presentationData.strings.Notifications_ExceptionsTitle
|
||||
self.navigationItem.backBarButtonItem = UIBarButtonItem(title: self.presentationData.strings.Common_Back, style: .plain, target: nil, action: nil)
|
||||
|
|
|
|||
|
|
@ -1,139 +0,0 @@
|
|||
import Foundation
|
||||
import UIKit
|
||||
import AsyncDisplayKit
|
||||
import Postbox
|
||||
import Display
|
||||
import SwiftSignalKit
|
||||
import TelegramPresentationData
|
||||
import ItemListUI
|
||||
import PresentationDataUtils
|
||||
import SearchBarNode
|
||||
|
||||
private let searchBarFont = Font.regular(14.0)
|
||||
|
||||
class NotificationSearchItem: ListViewItem, ItemListItem {
|
||||
let selectable: Bool = false
|
||||
|
||||
var sectionId: ItemListSectionId {
|
||||
return 0
|
||||
}
|
||||
var tag: ItemListItemTag? {
|
||||
return nil
|
||||
}
|
||||
var requestsNoInset: Bool {
|
||||
return true
|
||||
}
|
||||
|
||||
let theme: PresentationTheme
|
||||
private let placeholder: String
|
||||
private let activate: () -> Void
|
||||
|
||||
init(theme: PresentationTheme, placeholder: String, activate: @escaping () -> Void) {
|
||||
self.theme = theme
|
||||
self.placeholder = placeholder
|
||||
self.activate = activate
|
||||
}
|
||||
|
||||
func nodeConfiguredForParams(async: @escaping (@escaping () -> Void) -> Void, params: ListViewItemLayoutParams, synchronousLoads: Bool, previousItem: ListViewItem?, nextItem: ListViewItem?, completion: @escaping (ListViewItemNode, @escaping () -> (Signal<Void, NoError>?, (ListViewItemApply) -> Void)) -> Void) {
|
||||
async {
|
||||
let node = NotificationSearchItemNode()
|
||||
node.placeholder = self.placeholder
|
||||
|
||||
let makeLayout = node.asyncLayout()
|
||||
let (layout, apply) = makeLayout(self, params)
|
||||
|
||||
node.contentSize = layout.contentSize
|
||||
node.insets = layout.insets
|
||||
|
||||
node.activate = self.activate
|
||||
Queue.mainQueue().async {
|
||||
completion(node, {
|
||||
return (nil, { _ in
|
||||
apply(false)
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func updateNode(async: @escaping (@escaping () -> Void) -> Void, node: @escaping () -> ListViewItemNode, params: ListViewItemLayoutParams, previousItem: ListViewItem?, nextItem: ListViewItem?, animation: ListViewItemUpdateAnimation, completion: @escaping (ListViewItemNodeLayout, @escaping (ListViewItemApply) -> Void) -> Void) {
|
||||
Queue.mainQueue().async {
|
||||
if let nodeValue = node() as? NotificationSearchItemNode {
|
||||
let layout = nodeValue.asyncLayout()
|
||||
async {
|
||||
let (nodeLayout, apply) = layout(self, params)
|
||||
Queue.mainQueue().async {
|
||||
completion(nodeLayout, { _ in
|
||||
apply(animation.isAnimated)
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class NotificationSearchItemNode: ListViewItemNode {
|
||||
let searchBarNode: SearchBarPlaceholderNode
|
||||
var placeholder: String?
|
||||
|
||||
fileprivate var activate: (() -> Void)? {
|
||||
didSet {
|
||||
self.searchBarNode.activate = self.activate
|
||||
}
|
||||
}
|
||||
|
||||
override func animateRemoved(_ currentTimestamp: Double, duration: Double) {
|
||||
self.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.15, removeOnCompletion: false)
|
||||
}
|
||||
|
||||
required init() {
|
||||
self.searchBarNode = SearchBarPlaceholderNode()
|
||||
|
||||
super.init(layerBacked: false, dynamicBounce: false)
|
||||
|
||||
self.addSubnode(self.searchBarNode)
|
||||
}
|
||||
|
||||
override func layoutForParams(_ params: ListViewItemLayoutParams, item: ListViewItem, previousItem: ListViewItem?, nextItem: ListViewItem?) {
|
||||
let makeLayout = self.asyncLayout()
|
||||
let (layout, apply) = makeLayout(item as! NotificationSearchItem, params)
|
||||
apply(false)
|
||||
self.contentSize = layout.contentSize
|
||||
self.insets = layout.insets
|
||||
}
|
||||
|
||||
func asyncLayout() -> (_ item: NotificationSearchItem, _ params: ListViewItemLayoutParams) -> (ListViewItemNodeLayout, (Bool) -> Void) {
|
||||
let searchBarNodeLayout = self.searchBarNode.asyncLayout()
|
||||
let placeholder = self.placeholder
|
||||
|
||||
return { item, params in
|
||||
let baseWidth = params.width - params.leftInset - params.rightInset
|
||||
|
||||
let backgroundColor = item.theme.chatList.itemBackgroundColor
|
||||
|
||||
let placeholderString = NSAttributedString(string: placeholder ?? "", font: searchBarFont, textColor: UIColor(rgb: 0x8e8e93))
|
||||
let (_, searchBarApply) = searchBarNodeLayout(placeholderString, placeholderString, CGSize(width: baseWidth - 16.0, height: 28.0), 1.0, UIColor(rgb: 0x8e8e93), item.theme.chatList.regularSearchBarColor, backgroundColor, .immediate)
|
||||
|
||||
let layout = ListViewItemNodeLayout(contentSize: CGSize(width: params.width, height: 44.0), insets: UIEdgeInsets())
|
||||
|
||||
return (layout, { [weak self] animated in
|
||||
if let strongSelf = self {
|
||||
let transition: ContainedViewLayoutTransition
|
||||
if animated {
|
||||
transition = .animated(duration: 0.3, curve: .easeInOut)
|
||||
} else {
|
||||
transition = .immediate
|
||||
}
|
||||
|
||||
strongSelf.searchBarNode.frame = CGRect(origin: CGPoint(x: params.leftInset + 8.0, y: 8.0), size: CGSize(width: baseWidth - 16.0, height: 28.0))
|
||||
searchBarApply()
|
||||
|
||||
strongSelf.searchBarNode.bounds = CGRect(origin: CGPoint(), size: CGSize(width: baseWidth - 16.0, height: 28.0))
|
||||
|
||||
transition.updateBackgroundColor(node: strongSelf, color: backgroundColor)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -608,7 +608,7 @@ private final class SettingsSearchItemNode: ItemListControllerSearchNode {
|
|||
}
|
||||
}, resolvedFaqUrl: self.resolvedFaqUrl, exceptionsList: self.exceptionsList, archivedStickerPacks: self.archivedStickerPacks, privacySettings: self.privacySettings, hasTwoStepAuth: self.hasTwoStepAuth, twoStepAuthData: self.twoStepAuthData, activeSessionsContext: self.activeSessionsContext, webSessionsContext: self.webSessionsContext), cancel: { [weak self] in
|
||||
self?.cancel()
|
||||
})
|
||||
}, fieldStyle: placeholderNode.fieldStyle)
|
||||
|
||||
self.searchDisplayController?.containerLayoutUpdated(containerLayout, navigationBarHeight: navigationBarHeight, transition: .immediate)
|
||||
self.searchDisplayController?.activate(insertSubnode: { [weak self, weak placeholderNode] subnode, isSearchBar in
|
||||
|
|
|
|||
|
|
@ -153,7 +153,6 @@ swift_library(
|
|||
"//submodules/ChatListSearchItemHeader:ChatListSearchItemHeader",
|
||||
"//submodules/ItemListPeerItem:ItemListPeerItem",
|
||||
"//submodules/ContactsPeerItem:ContactsPeerItem",
|
||||
"//submodules/ChatListSearchItemNode:ChatListSearchItemNode",
|
||||
"//submodules/TelegramPermissionsUI:TelegramPermissionsUI",
|
||||
"//submodules/PeersNearbyIconNode:PeersNearbyIconNode",
|
||||
"//submodules/SolidRoundedButtonNode:SolidRoundedButtonNode",
|
||||
|
|
|
|||
|
|
@ -496,7 +496,7 @@ private final class RecentActionsSettingsSheetComponent: Component {
|
|||
component: AnyComponentWithIdentity(id: "close", component: AnyComponent(
|
||||
BundleIconComponent(
|
||||
name: "Navigation/Close",
|
||||
tintColor: environment.theme.rootController.navigationBar.glassBarButtonForegroundColor
|
||||
tintColor: environment.theme.chat.inputPanel.panelControlColor
|
||||
)
|
||||
)),
|
||||
action: { [weak self] _ in
|
||||
|
|
|
|||
|
|
@ -227,7 +227,7 @@ public final class AnimatedTextComponent: Component {
|
|||
itemText = [.icon(iconName, tint, offset)]
|
||||
}
|
||||
var index = 0
|
||||
for character in itemText {
|
||||
characterLoop: for character in itemText {
|
||||
let characterKey = CharacterKey(itemId: item.id, index: index, value: character.value)
|
||||
index += 1
|
||||
|
||||
|
|
@ -245,9 +245,17 @@ public final class AnimatedTextComponent: Component {
|
|||
var characterOffset: CGPoint = .zero
|
||||
switch character {
|
||||
case let .text(text):
|
||||
characterComponent = AnyComponent(MultilineTextComponent(
|
||||
text: .plain(NSAttributedString(string: text, font: component.font, textColor: component.color))
|
||||
))
|
||||
if text == " " {
|
||||
let spaceSize = NSAttributedString(string: " ", font: component.font, textColor: .black).boundingRect(with: CGSize(width: 100.0, height: 100.0), options: .usesLineFragmentOrigin, context: nil).size
|
||||
size.height = max(size.height, ceil(spaceSize.height))
|
||||
size.width += max(0.0, ceil(spaceSize.width))
|
||||
|
||||
continue characterLoop
|
||||
} else {
|
||||
characterComponent = AnyComponent(MultilineTextComponent(
|
||||
text: .plain(NSAttributedString(string: text, font: component.font, textColor: component.color))
|
||||
))
|
||||
}
|
||||
case let .icon(iconName, tint, offset):
|
||||
characterComponent = AnyComponent(BundleIconComponent(
|
||||
name: iconName,
|
||||
|
|
@ -318,7 +326,7 @@ public final class AnimatedTextComponent: Component {
|
|||
}
|
||||
|
||||
size.height = max(size.height, characterSize.height)
|
||||
size.width += max(0.0, characterSize.width - UIScreenPixel * 2.0)
|
||||
size.width += max(0.0, characterSize.width - UIScreenPixel)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -468,7 +468,7 @@ public func makeAttachmentFileControllerImpl(context: AccountContext, updatedPre
|
|||
component: AnyComponentWithIdentity(id: "close", component: AnyComponent(
|
||||
BundleIconComponent(
|
||||
name: "Navigation/Close",
|
||||
tintColor: presentationData.theme.rootController.navigationBar.glassBarButtonForegroundColor
|
||||
tintColor: presentationData.theme.chat.inputPanel.panelControlColor
|
||||
)
|
||||
)),
|
||||
action: { _ in
|
||||
|
|
@ -495,7 +495,7 @@ public func makeAttachmentFileControllerImpl(context: AccountContext, updatedPre
|
|||
component: AnyComponentWithIdentity(id: "search", component: AnyComponent(
|
||||
BundleIconComponent(
|
||||
name: "Navigation/Search",
|
||||
tintColor: presentationData.theme.rootController.navigationBar.glassBarButtonForegroundColor
|
||||
tintColor: presentationData.theme.chat.inputPanel.panelControlColor
|
||||
)
|
||||
)),
|
||||
action: { _ in
|
||||
|
|
@ -509,7 +509,7 @@ public func makeAttachmentFileControllerImpl(context: AccountContext, updatedPre
|
|||
}
|
||||
)
|
||||
let searchButtonComponent = state.searching ? nil : AnyComponentWithIdentity(id: "search", component: AnyComponent(searchButton))
|
||||
let searchButtonNode = existingSearchButton.modify { current in
|
||||
let searchButtonNode: BarComponentHostNode? = !state.searching ? existingSearchButton.modify { current in
|
||||
let buttonNode: BarComponentHostNode
|
||||
if let current {
|
||||
buttonNode = current
|
||||
|
|
@ -518,7 +518,7 @@ public func makeAttachmentFileControllerImpl(context: AccountContext, updatedPre
|
|||
buttonNode = BarComponentHostNode(component: searchButtonComponent, size: barButtonSize)
|
||||
}
|
||||
return buttonNode
|
||||
}
|
||||
} : nil
|
||||
|
||||
let previousRecentDocuments = previousRecentDocuments.swap(recentDocuments)
|
||||
let crossfade = previousRecentDocuments == nil && recentDocuments != nil
|
||||
|
|
@ -542,6 +542,7 @@ public func makeAttachmentFileControllerImpl(context: AccountContext, updatedPre
|
|||
case .recent:
|
||||
title = presentationData.strings.Attachment_File
|
||||
case .audio:
|
||||
//TODO:localize
|
||||
title = "Audio"
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -56,7 +56,6 @@ public enum ChatHistoryEntry: Identifiable, Comparable {
|
|||
case UnreadEntry(MessageIndex, ChatPresentationData)
|
||||
case ReplyCountEntry(MessageIndex, Bool, Int, ChatPresentationData)
|
||||
case ChatInfoEntry(ChatInfoData, ChatPresentationData)
|
||||
case SearchEntry(PresentationTheme, PresentationStrings)
|
||||
|
||||
public var stableId: UInt64 {
|
||||
switch self {
|
||||
|
|
@ -79,8 +78,6 @@ public enum ChatHistoryEntry: Identifiable, Comparable {
|
|||
return UInt64(5) << 40
|
||||
case .ChatInfoEntry:
|
||||
return UInt64(6) << 40
|
||||
case .SearchEntry:
|
||||
return UInt64(7) << 40
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -101,8 +98,6 @@ public enum ChatHistoryEntry: Identifiable, Comparable {
|
|||
default:
|
||||
return MessageIndex.absoluteLowerBound()
|
||||
}
|
||||
case .SearchEntry:
|
||||
return MessageIndex.absoluteLowerBound()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -123,8 +118,6 @@ public enum ChatHistoryEntry: Identifiable, Comparable {
|
|||
default:
|
||||
return MessageIndex.absoluteLowerBound()
|
||||
}
|
||||
case .SearchEntry:
|
||||
return MessageIndex.absoluteLowerBound()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -297,12 +290,6 @@ public enum ChatHistoryEntry: Identifiable, Comparable {
|
|||
} else {
|
||||
return false
|
||||
}
|
||||
case let .SearchEntry(lhsTheme, lhsStrings):
|
||||
if case let .SearchEntry(rhsTheme, rhsStrings) = rhs, lhsTheme === rhsTheme, lhsStrings === rhsStrings {
|
||||
return true
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -158,7 +158,7 @@ public final class ChatHistorySearchContainerNode: SearchDisplayControllerConten
|
|||
self.themeAndStringsPromise = Promise((self.presentationData.theme, self.presentationData.strings, self.presentationData.dateTimeFormat, self.presentationData.listsFontSize))
|
||||
|
||||
self.dimNode = ASDisplayNode()
|
||||
self.dimNode.backgroundColor = UIColor.black.withAlphaComponent(0.5)
|
||||
self.dimNode.backgroundColor = .clear
|
||||
self.listNode = ListView()
|
||||
self.listNode.accessibilityPageScrolledString = { row, count in
|
||||
return presentationData.strings.VoiceOver_ScrollStatus(row, count).string
|
||||
|
|
|
|||
|
|
@ -721,7 +721,7 @@ public final class ChatQrCodeScreenImpl: ViewController, ChatQrCodeScreen {
|
|||
}
|
||||
|
||||
private func iconColors(theme: PresentationTheme) -> [String: UIColor] {
|
||||
let accentColor = theme.rootController.navigationBar.glassBarButtonForegroundColor
|
||||
let accentColor = theme.chat.inputPanel.panelControlColor
|
||||
var colors: [String: UIColor] = [:]
|
||||
colors["Sunny.Path 14.Path.Stroke 1"] = accentColor
|
||||
colors["Sunny.Path 15.Path.Stroke 1"] = accentColor
|
||||
|
|
@ -1470,7 +1470,7 @@ private class ChatQrCodeScreenNode: ViewControllerTracingNode, ASScrollViewDeleg
|
|||
component: AnyComponentWithIdentity(id: "close", component: AnyComponent(
|
||||
BundleIconComponent(
|
||||
name: "Navigation/Close",
|
||||
tintColor: self.presentationData.theme.rootController.navigationBar.glassBarButtonForegroundColor
|
||||
tintColor: self.presentationData.theme.chat.inputPanel.panelControlColor
|
||||
)
|
||||
)),
|
||||
action: { [weak self] _ in
|
||||
|
|
|
|||
|
|
@ -60,7 +60,7 @@ public final class ChatSearchNavigationContentNode: NavigationBarContentNode {
|
|||
primaryText: theme.chat.inputPanel.panelControlColor,
|
||||
placeholder: theme.chat.inputPanel.inputPlaceholderColor,
|
||||
inputIcon: theme.chat.inputPanel.inputControlColor,
|
||||
inputClear: theme.chat.inputPanel.inputControlColor,
|
||||
inputClear: theme.chat.inputPanel.panelControlColor,
|
||||
accent: theme.chat.inputPanel.panelControlAccentColor,
|
||||
keyboard: theme.rootController.keyboardColor
|
||||
),
|
||||
|
|
@ -242,7 +242,7 @@ public final class ChatSearchNavigationContentNode: NavigationBarContentNode {
|
|||
primaryText: presentationInterfaceState.theme.chat.inputPanel.panelControlColor,
|
||||
placeholder: presentationInterfaceState.theme.chat.inputPanel.inputPlaceholderColor,
|
||||
inputIcon: presentationInterfaceState.theme.chat.inputPanel.inputControlColor,
|
||||
inputClear: presentationInterfaceState.theme.chat.inputPanel.inputControlColor,
|
||||
inputClear: presentationInterfaceState.theme.chat.inputPanel.panelControlColor,
|
||||
accent: presentationInterfaceState.theme.chat.inputPanel.panelControlAccentColor,
|
||||
keyboard: presentationInterfaceState.theme.rootController.keyboardColor
|
||||
),
|
||||
|
|
|
|||
|
|
@ -30,13 +30,21 @@ public final class ChatListNavigationBar: Component {
|
|||
}
|
||||
}
|
||||
|
||||
public struct ActiveSearch: Equatable {
|
||||
public var isExternal: Bool
|
||||
|
||||
public init(isExternal: Bool) {
|
||||
self.isExternal = isExternal
|
||||
}
|
||||
}
|
||||
|
||||
public let context: AccountContext
|
||||
public let theme: PresentationTheme
|
||||
public let strings: PresentationStrings
|
||||
public let statusBarHeight: CGFloat
|
||||
public let sideInset: CGFloat
|
||||
public let search: Search?
|
||||
public let isSearchActive: Bool
|
||||
public let activeSearch: ActiveSearch?
|
||||
public let primaryContent: ChatListHeaderComponent.Content?
|
||||
public let secondaryContent: ChatListHeaderComponent.Content?
|
||||
public let secondaryTransition: CGFloat
|
||||
|
|
@ -59,7 +67,7 @@ public final class ChatListNavigationBar: Component {
|
|||
statusBarHeight: CGFloat,
|
||||
sideInset: CGFloat,
|
||||
search: Search?,
|
||||
isSearchActive: Bool,
|
||||
activeSearch: ActiveSearch?,
|
||||
primaryContent: ChatListHeaderComponent.Content?,
|
||||
secondaryContent: ChatListHeaderComponent.Content?,
|
||||
secondaryTransition: CGFloat,
|
||||
|
|
@ -81,7 +89,7 @@ public final class ChatListNavigationBar: Component {
|
|||
self.statusBarHeight = statusBarHeight
|
||||
self.sideInset = sideInset
|
||||
self.search = search
|
||||
self.isSearchActive = isSearchActive
|
||||
self.activeSearch = activeSearch
|
||||
self.primaryContent = primaryContent
|
||||
self.secondaryContent = secondaryContent
|
||||
self.secondaryTransition = secondaryTransition
|
||||
|
|
@ -117,7 +125,7 @@ public final class ChatListNavigationBar: Component {
|
|||
if lhs.search != rhs.search {
|
||||
return false
|
||||
}
|
||||
if lhs.isSearchActive != rhs.isSearchActive {
|
||||
if lhs.activeSearch != rhs.activeSearch {
|
||||
return false
|
||||
}
|
||||
if lhs.primaryContent != rhs.primaryContent {
|
||||
|
|
@ -290,16 +298,10 @@ public final class ChatListNavigationBar: Component {
|
|||
|
||||
let previousHeight = self.currentHeight
|
||||
|
||||
let edgeEffectHeight: CGFloat = currentLayout.size.height + 20.0
|
||||
var edgeEffectFrame = CGRect(origin: CGPoint(x: 0.0, y: 0.0), size: CGSize(width: currentLayout.size.width, height: edgeEffectHeight))
|
||||
if component.isSearchActive {
|
||||
edgeEffectFrame.origin.y -= 20.0
|
||||
}
|
||||
transition.setFrame(view: self.edgeEffectView, frame: edgeEffectFrame)
|
||||
self.edgeEffectView.update(content: component.theme.list.plainBackgroundColor, blur: true, alpha: 0.55, rect: edgeEffectFrame, edge: .top, edgeSize: 40.0, transition: transition)
|
||||
|
||||
self.currentHeight = visibleSize.height
|
||||
|
||||
var embeddedSearchBarExpansionHeight: CGFloat = 0.0
|
||||
var searchFrameValue: CGRect?
|
||||
if let search = component.search {
|
||||
let searchContentNode: NavigationBarSearchContentNode
|
||||
if let current = self.searchContentNode {
|
||||
|
|
@ -337,24 +339,37 @@ public final class ChatListNavigationBar: Component {
|
|||
self.addSubview(searchContentNode.view)
|
||||
}
|
||||
|
||||
let searchSize = CGSize(width: currentLayout.size.width - 6.0 * 2.0, height: navigationBarSearchContentHeight)
|
||||
var searchFrame = CGRect(origin: CGPoint(x: 6.0, y: visibleSize.height - searchSize.height), size: searchSize)
|
||||
let searchSize = CGSize(width: currentLayout.size.width, height: navigationBarSearchContentHeight)
|
||||
var searchFrame = CGRect(origin: CGPoint(x: 0.0, y: visibleSize.height - searchSize.height - self.bottomContentsContainer.bounds.height), size: searchSize)
|
||||
if let activeSearch = component.activeSearch, !activeSearch.isExternal {
|
||||
searchFrame.origin.y = component.statusBarHeight + 8.0
|
||||
}
|
||||
if component.tabsNode != nil {
|
||||
searchFrame.origin.y -= 40.0
|
||||
}
|
||||
if !component.isSearchActive {
|
||||
if let activeSearch = component.activeSearch {
|
||||
if !activeSearch.isExternal {
|
||||
searchFrame.origin.y -= component.accessoryPanelContainerHeight
|
||||
}
|
||||
} else {
|
||||
searchFrame.origin.y -= component.accessoryPanelContainerHeight
|
||||
}
|
||||
|
||||
let clippedSearchOffset = max(0.0, min(clippedScrollOffset, searchOffsetDistance))
|
||||
let searchOffsetFraction = clippedSearchOffset / searchOffsetDistance
|
||||
searchContentNode.expansionProgress = 1.0 - searchOffsetFraction
|
||||
embeddedSearchBarExpansionHeight = 60.0 - floorToScreenPixels((1.0 - searchOffsetFraction) * searchSize.height)
|
||||
|
||||
searchFrameValue = searchFrame
|
||||
transition.setFrameWithAdditivePosition(view: searchContentNode.view, frame: searchFrame)
|
||||
|
||||
searchContentNode.updateLayout(size: searchSize, leftInset: component.sideInset, rightInset: component.sideInset, transition: transition.containedViewLayoutTransition)
|
||||
|
||||
transition.setAlpha(view: searchContentNode.view, alpha: search.isEnabled ? 1.0 : 0.5)
|
||||
var searchAlpha: CGFloat = search.isEnabled ? 1.0 : 0.5
|
||||
if let activeSearch = component.activeSearch, activeSearch.isExternal {
|
||||
searchAlpha = 0.0
|
||||
}
|
||||
transition.setAlpha(view: searchContentNode.view, alpha: searchAlpha)
|
||||
searchContentNode.isUserInteractionEnabled = search.isEnabled
|
||||
} else {
|
||||
if let searchContentNode = self.searchContentNode {
|
||||
|
|
@ -363,6 +378,21 @@ public final class ChatListNavigationBar: Component {
|
|||
}
|
||||
}
|
||||
|
||||
let edgeEffectHeight: CGFloat = currentLayout.size.height + 20.0
|
||||
var edgeEffectFrame = CGRect(origin: CGPoint(x: 0.0, y: 0.0), size: CGSize(width: currentLayout.size.width, height: edgeEffectHeight))
|
||||
if component.search != nil {
|
||||
if component.activeSearch != nil {
|
||||
edgeEffectFrame.origin.y -= 16.0
|
||||
} else {
|
||||
edgeEffectFrame.origin.y -= embeddedSearchBarExpansionHeight
|
||||
}
|
||||
} else if component.activeSearch != nil {
|
||||
edgeEffectFrame.origin.y -= 16.0
|
||||
}
|
||||
transition.setFrame(view: self.edgeEffectView, frame: edgeEffectFrame)
|
||||
self.edgeEffectView.update(content: component.theme.list.plainBackgroundColor, blur: true, alpha: 0.55, rect: edgeEffectFrame, edge: .top, edgeSize: 40.0, transition: transition)
|
||||
|
||||
|
||||
let headerTransition = transition
|
||||
|
||||
let storiesOffsetFraction: CGFloat
|
||||
|
|
@ -443,7 +473,7 @@ public final class ChatListNavigationBar: Component {
|
|||
containerSize: CGSize(width: currentLayout.size.width, height: 44.0)
|
||||
)
|
||||
let headerContentY: CGFloat
|
||||
if component.isSearchActive {
|
||||
if component.activeSearch != nil {
|
||||
headerContentY = -headerContentSize.height
|
||||
} else {
|
||||
if component.statusBarHeight < 1.0 {
|
||||
|
|
@ -460,11 +490,11 @@ public final class ChatListNavigationBar: Component {
|
|||
}
|
||||
transition.setFrameWithAdditivePosition(view: headerContentView, frame: headerContentFrame)
|
||||
|
||||
if component.isSearchActive != (headerContentView.alpha == 0.0) {
|
||||
headerContentView.alpha = component.isSearchActive ? 0.0 : 1.0
|
||||
if (component.activeSearch != nil) != (headerContentView.alpha == 0.0) {
|
||||
headerContentView.alpha = component.activeSearch != nil ? 0.0 : 1.0
|
||||
|
||||
if !transition.animation.isImmediate {
|
||||
if component.isSearchActive {
|
||||
if component.activeSearch != nil {
|
||||
headerContentView.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.14)
|
||||
} else {
|
||||
headerContentView.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.3)
|
||||
|
|
@ -473,7 +503,17 @@ public final class ChatListNavigationBar: Component {
|
|||
}
|
||||
}
|
||||
|
||||
transition.setPosition(view: self.bottomContentsContainer, position: CGPoint(x: 0.0, y: component.isSearchActive ? -self.bottomContentsContainer.bounds.height : visibleSize.height - self.bottomContentsContainer.bounds.height))
|
||||
let bottomContentsContainerPosition: CGPoint
|
||||
if let activeSearch = component.activeSearch {
|
||||
if let searchFrameValue, !activeSearch.isExternal {
|
||||
bottomContentsContainerPosition = CGPoint(x: 0.0, y: searchFrameValue.maxY - 8.0)
|
||||
} else {
|
||||
bottomContentsContainerPosition = CGPoint(x: 0.0, y: -self.bottomContentsContainer.bounds.height)
|
||||
}
|
||||
} else {
|
||||
bottomContentsContainerPosition = CGPoint(x: 0.0, y: visibleSize.height - self.bottomContentsContainer.bounds.height)
|
||||
}
|
||||
transition.setPosition(view: self.bottomContentsContainer, position: bottomContentsContainerPosition)
|
||||
|
||||
if component.tabsNode !== self.tabsNode {
|
||||
if let tabsNode = self.tabsNode {
|
||||
|
|
@ -495,7 +535,7 @@ public final class ChatListNavigationBar: Component {
|
|||
}
|
||||
|
||||
var tabsFrame = CGRect(origin: CGPoint(x: 0.0, y: visibleSize.height), size: CGSize(width: visibleSize.width, height: 46.0))
|
||||
if component.isSearchActive {
|
||||
if component.activeSearch != nil {
|
||||
} else {
|
||||
tabsFrame.origin.y -= component.accessoryPanelContainerHeight
|
||||
}
|
||||
|
|
@ -504,7 +544,7 @@ public final class ChatListNavigationBar: Component {
|
|||
}
|
||||
|
||||
var accessoryPanelContainerFrame = CGRect(origin: CGPoint(x: 0.0, y: visibleSize.height), size: CGSize(width: visibleSize.width, height: component.accessoryPanelContainerHeight))
|
||||
if component.isSearchActive {
|
||||
if component.activeSearch != nil {
|
||||
} else {
|
||||
accessoryPanelContainerFrame.origin.y -= component.accessoryPanelContainerHeight
|
||||
}
|
||||
|
|
@ -571,7 +611,7 @@ public final class ChatListNavigationBar: Component {
|
|||
statusBarHeight: component.statusBarHeight,
|
||||
sideInset: component.sideInset,
|
||||
search: component.search,
|
||||
isSearchActive: component.isSearchActive,
|
||||
activeSearch: component.activeSearch,
|
||||
primaryContent: component.primaryContent,
|
||||
secondaryContent: component.secondaryContent,
|
||||
secondaryTransition: component.secondaryTransition,
|
||||
|
|
@ -637,7 +677,11 @@ public final class ChatListNavigationBar: Component {
|
|||
if component.statusBarHeight >= 1.0 {
|
||||
contentHeight += 3.0
|
||||
}
|
||||
if !component.isSearchActive {
|
||||
if let activeSearch = component.activeSearch {
|
||||
if !activeSearch.isExternal {
|
||||
contentHeight += navigationBarSearchContentHeight
|
||||
}
|
||||
} else {
|
||||
contentHeight += 44.0
|
||||
contentHeight += 8.0
|
||||
|
||||
|
|
@ -697,7 +741,13 @@ public final class ChatListNavigationBar: Component {
|
|||
headersContentHeight += 3.0
|
||||
transition.setBounds(view: self.bottomContentsContainer, bounds: CGRect(origin: CGPoint(), size: CGSize(width: availableSize.width, height: headersContentHeight)))
|
||||
|
||||
if !component.isSearchActive {
|
||||
if let activeSearch = component.activeSearch, !activeSearch.isExternal {
|
||||
transition.setAlpha(view: self.bottomContentsContainer, alpha: 0.0)
|
||||
} else {
|
||||
transition.setAlpha(view: self.bottomContentsContainer, alpha: 1.0)
|
||||
}
|
||||
|
||||
if component.activeSearch == nil {
|
||||
contentHeight += headersContentHeight
|
||||
|
||||
if component.tabsNode != nil {
|
||||
|
|
|
|||
|
|
@ -229,7 +229,7 @@ public final class NavigationButtonComponent: Component {
|
|||
self.addSubnode(moreButton)
|
||||
}
|
||||
|
||||
let buttonSize = CGSize(width: 30.0, height: 44.0)
|
||||
let buttonSize = CGSize(width: 44.0, height: 44.0)
|
||||
size.width = 44.0
|
||||
|
||||
moreButton.setContent(.more(MoreHeaderButton.optionsCircleImage(color: theme.rootController.navigationBar.buttonColor)))
|
||||
|
|
|
|||
|
|
@ -179,7 +179,7 @@ private final class ChatScheduleTimeSheetContentComponent: Component {
|
|||
component: AnyComponentWithIdentity(id: "close", component: AnyComponent(
|
||||
BundleIconComponent(
|
||||
name: "Navigation/Close",
|
||||
tintColor: environment.theme.rootController.navigationBar.glassBarButtonForegroundColor
|
||||
tintColor: environment.theme.chat.inputPanel.panelControlColor
|
||||
)
|
||||
)),
|
||||
action: { [weak self] _ in
|
||||
|
|
|
|||
|
|
@ -1586,7 +1586,7 @@ final class ComposeTodoScreenComponent: Component {
|
|||
component: AnyComponentWithIdentity(id: "close", component: AnyComponent(
|
||||
BundleIconComponent(
|
||||
name: "Navigation/Close",
|
||||
tintColor: environment.theme.rootController.navigationBar.glassBarButtonForegroundColor
|
||||
tintColor: environment.theme.chat.inputPanel.panelControlColor
|
||||
)
|
||||
)),
|
||||
action: { [weak self] _ in
|
||||
|
|
|
|||
|
|
@ -897,7 +897,7 @@ final class NewContactScreenComponent: Component {
|
|||
component: AnyComponentWithIdentity(id: "close", component: AnyComponent(
|
||||
BundleIconComponent(
|
||||
name: "Navigation/Close",
|
||||
tintColor: environment.theme.rootController.navigationBar.glassBarButtonForegroundColor
|
||||
tintColor: environment.theme.chat.inputPanel.panelControlColor
|
||||
)
|
||||
)),
|
||||
action: { [weak self] _ in
|
||||
|
|
|
|||
|
|
@ -529,7 +529,7 @@ private final class SheetContent: CombinedComponent {
|
|||
component: AnyComponentWithIdentity(id: isBack ? "back" : "close", component: AnyComponent(
|
||||
BundleIconComponent(
|
||||
name: isBack ? "Navigation/Back" : "Navigation/Close",
|
||||
tintColor: environment.theme.rootController.navigationBar.glassBarButtonForegroundColor
|
||||
tintColor: environment.theme.chat.inputPanel.panelControlColor
|
||||
)
|
||||
)),
|
||||
action: { [weak state] _ in
|
||||
|
|
|
|||
|
|
@ -116,7 +116,7 @@ private final class SheetContent: CombinedComponent {
|
|||
component: AnyComponentWithIdentity(id: "close", component: AnyComponent(
|
||||
BundleIconComponent(
|
||||
name: "Navigation/Close",
|
||||
tintColor: theme.rootController.navigationBar.glassBarButtonForegroundColor
|
||||
tintColor: theme.chat.inputPanel.panelControlColor
|
||||
)
|
||||
)),
|
||||
action: { _ in
|
||||
|
|
|
|||
|
|
@ -1152,7 +1152,7 @@ final class GiftOptionsScreenComponent: Component {
|
|||
component: AnyComponentWithIdentity(id: "close", component: AnyComponent(
|
||||
BundleIconComponent(
|
||||
name: "Navigation/Close",
|
||||
tintColor: theme.rootController.navigationBar.glassBarButtonForegroundColor
|
||||
tintColor: theme.chat.inputPanel.panelControlColor
|
||||
)
|
||||
)),
|
||||
action: { _ in
|
||||
|
|
|
|||
|
|
@ -1122,7 +1122,7 @@ private final class GiftSetupScreenComponent: Component {
|
|||
component: AnyComponentWithIdentity(id: "close", component: AnyComponent(
|
||||
BundleIconComponent(
|
||||
name: "Navigation/Close",
|
||||
tintColor: environment.theme.rootController.navigationBar.glassBarButtonForegroundColor
|
||||
tintColor: environment.theme.chat.inputPanel.panelControlColor
|
||||
)
|
||||
)),
|
||||
action: { [weak self] _ in
|
||||
|
|
|
|||
|
|
@ -472,7 +472,7 @@ private final class GiftAuctionAcquiredScreenComponent: Component {
|
|||
component: AnyComponentWithIdentity(id: "close", component: AnyComponent(
|
||||
BundleIconComponent(
|
||||
name: "Navigation/Close",
|
||||
tintColor: environment.theme.rootController.navigationBar.glassBarButtonForegroundColor
|
||||
tintColor: environment.theme.chat.inputPanel.panelControlColor
|
||||
)
|
||||
)),
|
||||
action: { [weak self] _ in
|
||||
|
|
|
|||
|
|
@ -389,7 +389,7 @@ private final class GiftAuctionActiveBidsScreenComponent: Component {
|
|||
component: AnyComponentWithIdentity(id: "close", component: AnyComponent(
|
||||
BundleIconComponent(
|
||||
name: "Navigation/Close",
|
||||
tintColor: environment.theme.rootController.navigationBar.glassBarButtonForegroundColor
|
||||
tintColor: environment.theme.chat.inputPanel.panelControlColor
|
||||
)
|
||||
)),
|
||||
action: { [weak self] _ in
|
||||
|
|
|
|||
|
|
@ -2645,7 +2645,7 @@ private final class GiftAuctionBidScreenComponent: Component {
|
|||
component: AnyComponentWithIdentity(id: "close", component: AnyComponent(
|
||||
BundleIconComponent(
|
||||
name: "Navigation/Close",
|
||||
tintColor: environment.theme.rootController.navigationBar.glassBarButtonForegroundColor
|
||||
tintColor: environment.theme.chat.inputPanel.panelControlColor
|
||||
)
|
||||
)),
|
||||
action: { [weak self] _ in
|
||||
|
|
@ -2678,7 +2678,7 @@ private final class GiftAuctionBidScreenComponent: Component {
|
|||
content: LottieComponent.AppBundleContent(
|
||||
name: "anim_morewide"
|
||||
),
|
||||
color: environment.theme.rootController.navigationBar.glassBarButtonForegroundColor,
|
||||
color: environment.theme.chat.inputPanel.panelControlColor,
|
||||
size: CGSize(width: 34.0, height: 34.0),
|
||||
playOnce: self.moreButtonPlayOnce
|
||||
)
|
||||
|
|
|
|||
|
|
@ -256,7 +256,7 @@ private final class GiftAuctionInfoSheetContent: CombinedComponent {
|
|||
component: AnyComponentWithIdentity(id: "close", component: AnyComponent(
|
||||
BundleIconComponent(
|
||||
name: "Navigation/Close",
|
||||
tintColor: theme.rootController.navigationBar.glassBarButtonForegroundColor
|
||||
tintColor: theme.chat.inputPanel.panelControlColor
|
||||
)
|
||||
)),
|
||||
action: { [weak state] _ in
|
||||
|
|
|
|||
|
|
@ -97,7 +97,7 @@ private final class SheetContent: CombinedComponent {
|
|||
component: AnyComponentWithIdentity(id: "close", component: AnyComponent(
|
||||
BundleIconComponent(
|
||||
name: "Navigation/Close",
|
||||
tintColor: theme.rootController.navigationBar.glassBarButtonForegroundColor
|
||||
tintColor: theme.chat.inputPanel.panelControlColor
|
||||
)
|
||||
)),
|
||||
action: { _ in
|
||||
|
|
|
|||
|
|
@ -640,7 +640,7 @@ private final class GiftValueSheetContent: CombinedComponent {
|
|||
component: AnyComponentWithIdentity(id: "close", component: AnyComponent(
|
||||
BundleIconComponent(
|
||||
name: "Navigation/Close",
|
||||
tintColor: theme.rootController.navigationBar.glassBarButtonForegroundColor
|
||||
tintColor: theme.chat.inputPanel.panelControlColor
|
||||
)
|
||||
)),
|
||||
action: { [weak state] _ in
|
||||
|
|
|
|||
|
|
@ -544,8 +544,8 @@ public class GlassBackgroundView: UIView {
|
|||
nativeParamsView.lumaMin = 0.0
|
||||
nativeParamsView.lumaMax = 0.15
|
||||
} else {
|
||||
nativeParamsView.lumaMin = 0.7
|
||||
nativeParamsView.lumaMax = 0.71
|
||||
nativeParamsView.lumaMin = 0.8
|
||||
nativeParamsView.lumaMax = 0.801
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -638,8 +638,8 @@ public final class GlassBackgroundContainerView: UIView {
|
|||
nativeParamsView.lumaMin = 0.0
|
||||
nativeParamsView.lumaMax = 0.15
|
||||
} else {
|
||||
nativeParamsView.lumaMin = 0.7
|
||||
nativeParamsView.lumaMax = 0.71
|
||||
nativeParamsView.lumaMin = 0.8
|
||||
nativeParamsView.lumaMax = 0.801
|
||||
}
|
||||
|
||||
transition.setFrame(view: nativeView, frame: CGRect(origin: CGPoint(), size: size))
|
||||
|
|
|
|||
|
|
@ -168,7 +168,11 @@ public final class GlassBarButtonComponent: Component {
|
|||
componentTransition.setFrame(view: view, frame: componentFrame)
|
||||
}
|
||||
|
||||
let effectiveState = component.state ?? .glass
|
||||
let effectiveState: DisplayState = component.state ?? .glass
|
||||
/*if "".isEmpty {
|
||||
effectiveState = .glass
|
||||
}*/
|
||||
|
||||
var genericAlpha: CGFloat = 1.0
|
||||
var glassAlpha: CGFloat = 1.0
|
||||
switch effectiveState {
|
||||
|
|
|
|||
|
|
@ -77,7 +77,7 @@ final class GroupStickerSearchNavigationContentNode: NavigationBarContentNode, I
|
|||
primaryText: theme.chat.inputPanel.panelControlColor,
|
||||
placeholder: theme.chat.inputPanel.inputPlaceholderColor,
|
||||
inputIcon: theme.chat.inputPanel.inputControlColor,
|
||||
inputClear: theme.chat.inputPanel.inputControlColor,
|
||||
inputClear: theme.chat.inputPanel.panelControlColor,
|
||||
accent: theme.chat.inputPanel.panelControlAccentColor,
|
||||
keyboard: theme.rootController.keyboardColor
|
||||
),
|
||||
|
|
|
|||
|
|
@ -109,7 +109,7 @@ private final class SheetContent: CombinedComponent {
|
|||
component: AnyComponentWithIdentity(id: "close", component: AnyComponent(
|
||||
BundleIconComponent(
|
||||
name: "Navigation/Close",
|
||||
tintColor: theme.rootController.navigationBar.glassBarButtonForegroundColor
|
||||
tintColor: theme.chat.inputPanel.panelControlColor
|
||||
)
|
||||
)),
|
||||
action: { _ in
|
||||
|
|
|
|||
|
|
@ -286,7 +286,7 @@ final class MiniAppListScreenComponent: Component {
|
|||
statusBarHeight: statusBarHeight,
|
||||
sideInset: insets.left,
|
||||
search: ChatListNavigationBar.Search(isEnabled: true),
|
||||
isSearchActive: self.isSearchDisplayControllerActive,
|
||||
activeSearch: self.isSearchDisplayControllerActive ? ChatListNavigationBar.ActiveSearch(isExternal: false) : nil,
|
||||
primaryContent: headerContent,
|
||||
secondaryContent: nil,
|
||||
secondaryTransition: 0.0,
|
||||
|
|
|
|||
|
|
@ -793,6 +793,9 @@ public final class NavigationBarImpl: ASDisplayNode, NavigationBar {
|
|||
|
||||
let additionalExpansionHeight: CGFloat = self.secondaryContentNode != nil && appearsHidden ? (self.secondaryContentHeight * self.secondaryContentNodeDisplayFraction) : 0.0
|
||||
contentNodeFrame = CGRect(origin: CGPoint(x: 0.0, y: size.height - (appearsHidden ? 0.0 : additionalContentHeight) - expansionHeight - apparentAdditionalHeight - additionalExpansionHeight), size: CGSize(width: size.width, height: expansionHeight))
|
||||
if appearsHidden {
|
||||
contentNodeFrame.origin.y = size.height - contentNode.height + contentVerticalOrigin
|
||||
}
|
||||
if appearsHidden {
|
||||
if self.secondaryContentNode != nil {
|
||||
contentNodeFrame.origin.y += self.secondaryContentHeight * self.secondaryContentNodeDisplayFraction
|
||||
|
|
@ -805,7 +808,7 @@ public final class NavigationBarImpl: ASDisplayNode, NavigationBar {
|
|||
|
||||
transition.updateFrame(node: self.stripeNode, frame: CGRect(x: (additionalCutout?.width ?? 0.0), y: size.height + additionalBackgroundHeight, width: size.width - (additionalCutout?.width ?? 0.0), height: UIScreenPixel))
|
||||
|
||||
let nominalHeight: CGFloat = 56.0
|
||||
let nominalHeight: CGFloat = 60.0
|
||||
|
||||
var leftTitleInset: CGFloat = leftInset + 1.0
|
||||
var rightTitleInset: CGFloat = rightInset + 1.0
|
||||
|
|
@ -947,10 +950,7 @@ public final class NavigationBarImpl: ASDisplayNode, NavigationBar {
|
|||
}
|
||||
self.titleNode.alpha = 1.0
|
||||
|
||||
var titleOffset: CGFloat = 0.0
|
||||
if self.presentationData.theme.backgroundColor == .clear && self.presentationData.theme.separatorColor == .clear {
|
||||
titleOffset += 3.0
|
||||
}
|
||||
let titleOffset: CGFloat = 0.0
|
||||
transition.updateFrame(node: self.titleNode, frame: CGRect(origin: CGPoint(x: floor((size.width - titleSize.width) / 2.0), y: contentVerticalOrigin + titleOffset + floorToScreenPixels((nominalHeight - titleSize.height) / 2.0)), size: titleSize))
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -80,7 +80,7 @@ final class PeerInfoListPaneNode: ASDisplayNode, PeerInfoPaneNode {
|
|||
self.selectedMessages = chatControllerInteraction.selectionState.flatMap { $0.selectedIds }
|
||||
self.selectedMessagesPromise.set(.single(self.selectedMessages))
|
||||
|
||||
self.listNode = context.sharedContext.makeChatHistoryListNode(context: context, updatedPresentationData: updatedPresentationData ?? (context.sharedContext.currentPresentationData.with({ $0 }), context.sharedContext.presentationData), chatLocation: chatLocation, chatLocationContextHolder: chatLocationContextHolder, tag: .tag(tagMask), source: .default, subject: nil, controllerInteraction: chatControllerInteraction, selectedMessages: self.selectedMessagesPromise.get(), mode: .list(search: false, reversed: false, reverseGroups: false, displayHeaders: .allButLast, hintLinks: tagMask == .webPage, isGlobalSearch: false))
|
||||
self.listNode = context.sharedContext.makeChatHistoryListNode(context: context, updatedPresentationData: updatedPresentationData ?? (context.sharedContext.currentPresentationData.with({ $0 }), context.sharedContext.presentationData), chatLocation: chatLocation, chatLocationContextHolder: chatLocationContextHolder, tag: .tag(tagMask), source: .default, subject: nil, controllerInteraction: chatControllerInteraction, selectedMessages: self.selectedMessagesPromise.get(), mode: .list(reversed: false, reverseGroups: false, displayHeaders: .allButLast, hintLinks: tagMask == .webPage, isGlobalSearch: false))
|
||||
self.listNode.clipsToBounds = true
|
||||
self.listNode.defaultToSynchronousTransactionWhileScrolling = true
|
||||
self.listNode.scroller.bounces = false
|
||||
|
|
|
|||
|
|
@ -11436,6 +11436,9 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, PeerInfoScreenNodePro
|
|||
guard let (layout, navigationBarHeight) = self.validLayout, self.searchDisplayController == nil else {
|
||||
return
|
||||
}
|
||||
guard let controller = self.controller else {
|
||||
return
|
||||
}
|
||||
|
||||
if let currentPaneKey = self.paneContainerNode.currentPaneKey, case .savedMessages = currentPaneKey, let paneNode = self.paneContainerNode.currentPane?.node as? PeerInfoChatPaneNode {
|
||||
paneNode.activateSearch()
|
||||
|
|
@ -11448,8 +11451,6 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, PeerInfoScreenNodePro
|
|||
self.headerNode.navigationButtonContainer.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.3, timingFunction: CAMediaTimingFunctionName.easeOut.rawValue)
|
||||
|
||||
if self.isSettings {
|
||||
(self.controller?.parent as? TabBarController)?.updateIsTabBarHidden(true, transition: .animated(duration: 0.3, curve: .linear))
|
||||
|
||||
if let settings = self.data?.globalSettings {
|
||||
self.searchDisplayController = SearchDisplayController(presentationData: self.presentationData, mode: .list, placeholder: self.presentationData.strings.Settings_Search, hasBackground: true, hasSeparator: true, contentNode: SettingsSearchContainerNode(context: self.context, openResult: { [weak self] result in
|
||||
if let strongSelf = self, let navigationController = strongSelf.controller?.navigationController as? NavigationController {
|
||||
|
|
@ -11478,7 +11479,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, PeerInfoScreenNodePro
|
|||
}
|
||||
}, resolvedFaqUrl: self.cachedFaq.get(), exceptionsList: .single(settings.notificationExceptions), archivedStickerPacks: .single(settings.archivedStickerPacks), privacySettings: .single(settings.privacySettings), hasTwoStepAuth: self.hasTwoStepAuth.get(), twoStepAuthData: self.twoStepAccessConfiguration.get(), activeSessionsContext: self.activeSessionsContextAndCount.get() |> map { $0?.0 }, webSessionsContext: self.activeSessionsContextAndCount.get() |> map { $0?.2 }), cancel: { [weak self] in
|
||||
self?.deactivateSearch()
|
||||
})
|
||||
}, searchBarIsExternal: true)
|
||||
}
|
||||
} else if let currentPaneKey = self.paneContainerNode.currentPaneKey, case .members = currentPaneKey {
|
||||
self.searchDisplayController = SearchDisplayController(presentationData: self.presentationData, mode: .list, placeholder: self.presentationData.strings.Common_Search, hasBackground: true, hasSeparator: true, contentNode: ChannelMembersSearchContainerNode(context: self.context, forceTheme: nil, peerId: self.peerId, mode: .searchMembers, filters: [], searchContext: self.groupMembersSearchContext, openPeer: { [weak self] peer, participant in
|
||||
|
|
@ -11592,25 +11593,34 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, PeerInfoScreenNodePro
|
|||
transition.updateAlpha(node: navigationBar, alpha: 0.0)
|
||||
}
|
||||
|
||||
self.searchDisplayController?.containerLayoutUpdated(layout, navigationBarHeight: navigationBarHeight + 10.0, transition: .immediate)
|
||||
self.searchDisplayController?.containerLayoutUpdated(layout, navigationBarHeight: navigationBarHeight, transition: .immediate)
|
||||
self.searchDisplayController?.activate(insertSubnode: { [weak self] subnode, isSearchBar in
|
||||
if let strongSelf = self, let navigationBar = strongSelf.controller?.navigationBar {
|
||||
strongSelf.insertSubnode(subnode, belowSubnode: navigationBar)
|
||||
}
|
||||
}, placeholder: nil)
|
||||
|
||||
if self.isSettings {
|
||||
controller.updateTabBarSearchState(ViewController.TabBarSearchState(isActive: true), transition: transition)
|
||||
if let searchBarNode = controller.currentTabBarSearchNode?() as? SearchBarNode {
|
||||
self.searchDisplayController?.setSearchBar(searchBarNode)
|
||||
searchBarNode.activate()
|
||||
}
|
||||
}
|
||||
|
||||
self.containerLayoutUpdated(layout: layout, navigationHeight: navigationBarHeight, transition: .immediate)
|
||||
}
|
||||
|
||||
private func deactivateSearch() {
|
||||
guard let searchDisplayController = self.searchDisplayController else {
|
||||
func deactivateSearch() {
|
||||
guard let controller = self.controller, let searchDisplayController = self.searchDisplayController else {
|
||||
return
|
||||
}
|
||||
self.searchDisplayController = nil
|
||||
searchDisplayController.deactivate(placeholder: nil)
|
||||
|
||||
if self.isSettings {
|
||||
(self.controller?.parent as? TabBarController)?.updateIsTabBarHidden(false, transition: .animated(duration: 0.3, curve: .linear))
|
||||
(self.controller?.parent as? TabBarController)?.updateIsTabBarHidden(false, transition: .animated(duration: 0.4, curve: .spring))
|
||||
controller.updateTabBarSearchState(ViewController.TabBarSearchState(isActive: false), transition: .animated(duration: 0.4, curve: .spring))
|
||||
}
|
||||
|
||||
let transition: ContainedViewLayoutTransition = .animated(duration: 0.35, curve: .easeInOut)
|
||||
|
|
@ -14276,6 +14286,10 @@ public final class PeerInfoScreenImpl: ViewController, PeerInfoScreen, KeyShortc
|
|||
self.controllerNode.activateSearch()
|
||||
}
|
||||
|
||||
override public func tabBarDeactivateSearch() {
|
||||
self.controllerNode.deactivateSearch()
|
||||
}
|
||||
|
||||
public static func openSavedMessagesMoreMenu(context: AccountContext, sourceController: ViewController, isViewingAsTopics: Bool, sourceView: UIView, gesture: ContextGesture?) {
|
||||
let _ = (context.engine.data.get(TelegramEngine.EngineData.Item.Peer.Peer(id: context.account.peerId))
|
||||
|> deliverOnMainQueue).startStandalone(next: { peer in
|
||||
|
|
|
|||
|
|
@ -391,7 +391,7 @@ private final class OldChannelsSearchItemNode: ItemListControllerSearchNode {
|
|||
|
||||
self.searchDisplayController = SearchDisplayController(presentationData: self.presentationData, contentNode: OldChannelsSearchContainerNode(context: self.context, peers: self.peers, selectedPeerIds: self.selectedPeerIds, togglePeer: self.togglePeer), cancel: { [weak self] in
|
||||
self?.cancel()
|
||||
})
|
||||
}, fieldStyle: placeholderNode.fieldStyle)
|
||||
|
||||
self.searchDisplayController?.containerLayoutUpdated(containerLayout, navigationBarHeight: navigationBarHeight, transition: .immediate)
|
||||
self.searchDisplayController?.activate(insertSubnode: { [weak self, weak placeholderNode] subnode, isSearchBar in
|
||||
|
|
|
|||
|
|
@ -113,7 +113,9 @@ public final class PeerSelectionControllerImpl: ViewController, PeerSelectionCon
|
|||
self.immediatelyActivateMultipleSelection = params.immediatelyActivateMultipleSelection
|
||||
self.multipleSelectionLimit = params.multipleSelectionLimit
|
||||
|
||||
super.init(navigationBarPresentationData: NavigationBarPresentationData(presentationData: self.presentationData))
|
||||
super.init(navigationBarPresentationData: NavigationBarPresentationData(presentationData: self.presentationData, style: .glass))
|
||||
|
||||
self._hasGlassStyle = true
|
||||
|
||||
self.statusBar.statusBarStyle = self.presentationData.theme.rootController.statusBarStyle.style
|
||||
|
||||
|
|
@ -245,7 +247,7 @@ public final class PeerSelectionControllerImpl: ViewController, PeerSelectionCon
|
|||
|
||||
private func updateThemeAndStrings() {
|
||||
self.statusBar.statusBarStyle = self.presentationData.theme.rootController.statusBarStyle.style
|
||||
self.navigationBar?.updatePresentationData(NavigationBarPresentationData(presentationData: self.presentationData), transition: .immediate)
|
||||
self.navigationBar?.updatePresentationData(NavigationBarPresentationData(presentationData: self.presentationData, style: .glass), transition: .immediate)
|
||||
self.searchContentNode?.updateThemeAndPlaceholder(theme: self.presentationData.theme, placeholder: self.presentationData.strings.Common_Search)
|
||||
self.title = self.customTitle ?? self.presentationData.strings.Conversation_ForwardTitle
|
||||
self.navigationItem.backBarButtonItem = UIBarButtonItem(title: self.presentationData.strings.Common_Back, style: .plain, target: nil, action: nil)
|
||||
|
|
|
|||
|
|
@ -1363,7 +1363,7 @@ final class PeerSelectionControllerNode: ASDisplayNode {
|
|||
if let requestDeactivateSearch = self?.requestDeactivateSearch {
|
||||
requestDeactivateSearch()
|
||||
}
|
||||
}
|
||||
}, fieldStyle: placeholderNode.fieldStyle
|
||||
)
|
||||
|
||||
self.searchDisplayController?.containerLayoutUpdated(containerLayout, navigationBarHeight: navigationBarHeight, transition: .immediate)
|
||||
|
|
@ -1438,7 +1438,7 @@ final class PeerSelectionControllerNode: ASDisplayNode {
|
|||
if let requestDeactivateSearch = self?.requestDeactivateSearch {
|
||||
requestDeactivateSearch()
|
||||
}
|
||||
})
|
||||
}, fieldStyle: placeholderNode.fieldStyle)
|
||||
|
||||
self.searchDisplayController?.containerLayoutUpdated(containerLayout, navigationBarHeight: navigationBarHeight, transition: .immediate)
|
||||
self.searchDisplayController?.activate(insertSubnode: { [weak self, weak placeholderNode] subnode, isSearchBar in
|
||||
|
|
|
|||
|
|
@ -292,7 +292,7 @@ public final class SearchInputPanelComponent: Component {
|
|||
component: AnyComponentWithIdentity(id: "close", component: AnyComponent(
|
||||
BundleIconComponent(
|
||||
name: "Navigation/Close",
|
||||
tintColor: component.theme.rootController.navigationBar.glassBarButtonForegroundColor
|
||||
tintColor: component.theme.chat.inputPanel.panelControlColor
|
||||
)
|
||||
)),
|
||||
action: { [weak self] _ in
|
||||
|
|
|
|||
|
|
@ -816,7 +816,7 @@ final class QuickReplySetupScreenComponent: Component {
|
|||
statusBarHeight: statusBarHeight,
|
||||
sideInset: insets.left,
|
||||
search: ChatListNavigationBar.Search(isEnabled: !self.isEditing),
|
||||
isSearchActive: self.isSearchDisplayControllerActive,
|
||||
activeSearch: self.isSearchDisplayControllerActive ? ChatListNavigationBar.ActiveSearch(isExternal: false) : nil,
|
||||
primaryContent: headerContent,
|
||||
secondaryContent: nil,
|
||||
secondaryTransition: 0.0,
|
||||
|
|
|
|||
|
|
@ -127,7 +127,7 @@ private final class BirthdayPickerSheetContentComponent: Component {
|
|||
component: AnyComponentWithIdentity(id: "close", component: AnyComponent(
|
||||
BundleIconComponent(
|
||||
name: "Navigation/Close",
|
||||
tintColor: environment.theme.rootController.navigationBar.glassBarButtonForegroundColor
|
||||
tintColor: environment.theme.chat.inputPanel.panelControlColor
|
||||
)
|
||||
)),
|
||||
action: { [weak self] _ in
|
||||
|
|
|
|||
|
|
@ -540,7 +540,8 @@ final class LanguageSelectionScreenNode: ViewControllerTracingNode {
|
|||
inline: true,
|
||||
cancel: { [weak self] in
|
||||
self?.requestDeactivateSearch()
|
||||
}
|
||||
},
|
||||
fieldStyle: placeholderNode.fieldStyle
|
||||
)
|
||||
|
||||
self.searchDisplayController?.containerLayoutUpdated(containerLayout, navigationBarHeight: navigationBarHeight, transition: .immediate)
|
||||
|
|
|
|||
|
|
@ -218,7 +218,7 @@ final class PeerSelectionScreenComponent: Component {
|
|||
private var channels: [PeerSelectionScreen.ChannelInfo]?
|
||||
private var channelsDisposable: Disposable?
|
||||
|
||||
private var isSearchDisplayControllerActive: Bool = false
|
||||
private var isSearchDisplayControllerActive: ChatListNavigationBar.ActiveSearch?
|
||||
private var searchQuery: String = ""
|
||||
private let searchQueryComponentSeparationCharacterSet: CharacterSet
|
||||
|
||||
|
|
@ -318,7 +318,7 @@ final class PeerSelectionScreenComponent: Component {
|
|||
statusBarHeight: statusBarHeight,
|
||||
sideInset: insets.left,
|
||||
search: ChatListNavigationBar.Search(isEnabled: true),
|
||||
isSearchActive: self.isSearchDisplayControllerActive,
|
||||
activeSearch: self.isSearchDisplayControllerActive,
|
||||
primaryContent: headerContent,
|
||||
secondaryContent: nil,
|
||||
secondaryTransition: 0.0,
|
||||
|
|
@ -335,7 +335,7 @@ final class PeerSelectionScreenComponent: Component {
|
|||
return
|
||||
}
|
||||
|
||||
self.isSearchDisplayControllerActive = true
|
||||
self.isSearchDisplayControllerActive = ChatListNavigationBar.ActiveSearch(isExternal: false)
|
||||
self.state?.updated(transition: .spring(duration: 0.4))
|
||||
},
|
||||
openStatusSetup: { _ in
|
||||
|
|
@ -385,7 +385,7 @@ final class PeerSelectionScreenComponent: Component {
|
|||
let resultingOffset = mainOffset
|
||||
|
||||
var offset = resultingOffset
|
||||
if self.isSearchDisplayControllerActive {
|
||||
if self.isSearchDisplayControllerActive != nil {
|
||||
offset = 0.0
|
||||
}
|
||||
|
||||
|
|
@ -468,7 +468,7 @@ final class PeerSelectionScreenComponent: Component {
|
|||
self.navigationHeight = navigationHeight
|
||||
|
||||
var removedSearchBar: SearchBarNode?
|
||||
if self.isSearchDisplayControllerActive {
|
||||
if self.isSearchDisplayControllerActive != nil {
|
||||
let searchBarNode: SearchBarNode
|
||||
var searchBarTransition = transition
|
||||
if let current = self.searchBarNode {
|
||||
|
|
@ -488,7 +488,7 @@ final class PeerSelectionScreenComponent: Component {
|
|||
guard let self else {
|
||||
return
|
||||
}
|
||||
self.isSearchDisplayControllerActive = false
|
||||
self.isSearchDisplayControllerActive = nil
|
||||
self.state?.updated(transition: .spring(duration: 0.4))
|
||||
}
|
||||
searchBarNode.textUpdated = { [weak self] query, _ in
|
||||
|
|
|
|||
|
|
@ -35,7 +35,9 @@ public class TimezoneSelectionScreen: ViewController {
|
|||
|
||||
self.presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
||||
|
||||
super.init(navigationBarPresentationData: NavigationBarPresentationData(presentationData: self.presentationData))
|
||||
super.init(navigationBarPresentationData: NavigationBarPresentationData(presentationData: self.presentationData, style: .glass))
|
||||
|
||||
self._hasGlassStyle = true
|
||||
|
||||
self.statusBar.statusBarStyle = self.presentationData.theme.rootController.statusBarStyle.style
|
||||
|
||||
|
|
@ -82,7 +84,7 @@ public class TimezoneSelectionScreen: ViewController {
|
|||
|
||||
private func updateThemeAndStrings() {
|
||||
self.statusBar.statusBarStyle = self.presentationData.theme.rootController.statusBarStyle.style
|
||||
self.navigationBar?.updatePresentationData(NavigationBarPresentationData(presentationData: self.presentationData), transition: .immediate)
|
||||
self.navigationBar?.updatePresentationData(NavigationBarPresentationData(presentationData: self.presentationData, style: .glass), transition: .immediate)
|
||||
self.searchContentNode?.updateThemeAndPlaceholder(theme: self.presentationData.theme, placeholder: self.presentationData.strings.Common_Search)
|
||||
self.title = self.presentationData.strings.Settings_AppLanguage
|
||||
self.navigationItem.backBarButtonItem = UIBarButtonItem(title: self.presentationData.strings.Common_Back, style: .plain, target: nil, action: nil)
|
||||
|
|
|
|||
|
|
@ -109,7 +109,7 @@ private final class TimezoneListSearchContainerNode: SearchDisplayControllerCont
|
|||
self.presentationDataPromise = Promise(self.presentationData)
|
||||
|
||||
self.dimNode = ASDisplayNode()
|
||||
self.dimNode.backgroundColor = UIColor.black.withAlphaComponent(0.5)
|
||||
self.dimNode.backgroundColor = .clear
|
||||
|
||||
self.listNode = ListView()
|
||||
self.listNode.accessibilityPageScrolledString = { row, count in
|
||||
|
|
@ -523,7 +523,7 @@ final class TimezoneSelectionScreenNode: ViewControllerTracingNode {
|
|||
|
||||
self.searchDisplayController = SearchDisplayController(presentationData: self.presentationData, contentNode: TimezoneListSearchContainerNode(context: self.context, timeZoneList: timeZoneList, action: self.action), inline: true, cancel: { [weak self] in
|
||||
self?.requestDeactivateSearch()
|
||||
})
|
||||
}, fieldStyle: placeholderNode.fieldStyle)
|
||||
|
||||
self.searchDisplayController?.containerLayoutUpdated(containerLayout, navigationBarHeight: navigationBarHeight, transition: .immediate)
|
||||
self.searchDisplayController?.activate(insertSubnode: { [weak self, weak placeholderNode] subnode, isSearchBar in
|
||||
|
|
|
|||
|
|
@ -889,7 +889,7 @@ final class LiveStreamSettingsScreenComponent: Component {
|
|||
component: AnyComponentWithIdentity(id: "close", component: AnyComponent(
|
||||
BundleIconComponent(
|
||||
name: "Navigation/Close",
|
||||
tintColor: environment.theme.rootController.navigationBar.glassBarButtonForegroundColor
|
||||
tintColor: environment.theme.chat.inputPanel.panelControlColor
|
||||
)
|
||||
)),
|
||||
action: { [weak self] _ in
|
||||
|
|
|
|||
|
|
@ -2772,7 +2772,7 @@ final class ShareWithPeersScreenComponent: Component {
|
|||
component: AnyComponentWithIdentity(id: "close", component: AnyComponent(
|
||||
BundleIconComponent(
|
||||
name: "Navigation/Close",
|
||||
tintColor: environment.theme.rootController.navigationBar.glassBarButtonForegroundColor
|
||||
tintColor: environment.theme.chat.inputPanel.panelControlColor
|
||||
)
|
||||
)),
|
||||
action: { [weak self] _ in
|
||||
|
|
|
|||
|
|
@ -677,7 +677,7 @@ private final class StarsTransactionSheetContent: CombinedComponent {
|
|||
component: AnyComponentWithIdentity(id: "close", component: AnyComponent(
|
||||
BundleIconComponent(
|
||||
name: "Navigation/Close",
|
||||
tintColor: theme.rootController.navigationBar.glassBarButtonForegroundColor
|
||||
tintColor: theme.chat.inputPanel.panelControlColor
|
||||
)
|
||||
)),
|
||||
action: { _ in
|
||||
|
|
|
|||
|
|
@ -348,7 +348,7 @@ private final class SheetContent: CombinedComponent {
|
|||
component: AnyComponentWithIdentity(id: "close", component: AnyComponent(
|
||||
BundleIconComponent(
|
||||
name: "Navigation/Close",
|
||||
tintColor: theme.rootController.navigationBar.glassBarButtonForegroundColor
|
||||
tintColor: theme.chat.inputPanel.panelControlColor
|
||||
)
|
||||
)),
|
||||
action: { _ in
|
||||
|
|
|
|||
|
|
@ -95,7 +95,7 @@ private final class SheetContent: CombinedComponent {
|
|||
component: AnyComponentWithIdentity(id: "close", component: AnyComponent(
|
||||
BundleIconComponent(
|
||||
name: "Navigation/Close",
|
||||
tintColor: theme.rootController.navigationBar.glassBarButtonForegroundColor
|
||||
tintColor: theme.chat.inputPanel.panelControlColor
|
||||
)
|
||||
)),
|
||||
action: { _ in
|
||||
|
|
|
|||
|
|
@ -227,7 +227,7 @@ private final class StoryStealthModeSheetContentComponent: Component {
|
|||
component: AnyComponentWithIdentity(id: "close", component: AnyComponent(
|
||||
BundleIconComponent(
|
||||
name: "Navigation/Close",
|
||||
tintColor: environment.theme.rootController.navigationBar.glassBarButtonForegroundColor
|
||||
tintColor: environment.theme.chat.inputPanel.panelControlColor
|
||||
)
|
||||
)),
|
||||
action: { _ in
|
||||
|
|
|
|||
|
|
@ -202,7 +202,7 @@ public final class NavigationSearchView: UIView {
|
|||
primaryText: params.theme.chat.inputPanel.panelControlColor,
|
||||
placeholder: params.theme.chat.inputPanel.inputPlaceholderColor,
|
||||
inputIcon: params.theme.chat.inputPanel.inputControlColor,
|
||||
inputClear: params.theme.chat.inputPanel.inputControlColor,
|
||||
inputClear: params.theme.chat.inputPanel.panelControlColor,
|
||||
accent: params.theme.chat.inputPanel.panelControlAccentColor,
|
||||
keyboard: params.theme.rootController.keyboardColor
|
||||
),
|
||||
|
|
|
|||
|
|
@ -7269,6 +7269,10 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
|||
override public func viewWillDisappear(_ animated: Bool) {
|
||||
super.viewWillDisappear(animated)
|
||||
|
||||
if #available(iOS 18.0, *) {
|
||||
} else {
|
||||
//TODO:release
|
||||
}
|
||||
UIView.performWithoutAnimation {
|
||||
self.view.endEditing(true)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -41,7 +41,6 @@ func chatHistoryEntriesForView(
|
|||
includeUnreadEntry: Bool,
|
||||
includeEmptyEntry: Bool,
|
||||
includeChatInfoEntry: Bool,
|
||||
includeSearchEntry: Bool,
|
||||
includeEmbeddedSavedChatInfo: Bool,
|
||||
reverse: Bool,
|
||||
groupMessages: Bool,
|
||||
|
|
@ -680,12 +679,6 @@ func chatHistoryEntriesForView(
|
|||
entries.append(.MessageEntry(updatedMessage, presentationData, false, nil, .none, ChatMessageEntryAttributes(rank: nil, isContact: false, contentTypeHint: .generic, updatingMedia: nil, isPlaying: false, isCentered: false, authorStoryStats: nil, displayContinueThreadFooter: false)))
|
||||
}
|
||||
}
|
||||
} else if includeSearchEntry {
|
||||
if view.laterId == nil {
|
||||
if !view.entries.isEmpty {
|
||||
entries.append(.SearchEntry(presentationData.theme.theme, presentationData.strings))
|
||||
}
|
||||
}
|
||||
}
|
||||
if addBotForumHeader {
|
||||
entries.append(.ChatInfoEntry(.newThreadInfo, presentationData))
|
||||
|
|
|
|||
|
|
@ -11,7 +11,6 @@ import TelegramUIPreferences
|
|||
import MediaResources
|
||||
import AccountContext
|
||||
import TemporaryCachedPeerDataManager
|
||||
import ChatListSearchItemNode
|
||||
import Emoji
|
||||
import AppBundle
|
||||
import ListMessageItem
|
||||
|
|
@ -229,7 +228,7 @@ private func mappedInsertEntries(context: AccountContext, chatLocation: ChatLoca
|
|||
switch mode {
|
||||
case .bubbles:
|
||||
item = ChatMessageItemImpl(presentationData: presentationData, context: context, chatLocation: chatLocation, associatedData: associatedData, controllerInteraction: controllerInteraction, content: .message(message: message, read: read, selection: selection, attributes: attributes, location: location), disableDate: disableFloatingDateHeaders || message.timestamp < 10)
|
||||
case let .list(_, _, _, displayHeaders, hintLinks, isGlobalSearch):
|
||||
case let .list(_, _, displayHeaders, hintLinks, isGlobalSearch):
|
||||
let displayHeader: Bool
|
||||
switch displayHeaders {
|
||||
case .none:
|
||||
|
|
@ -267,10 +266,6 @@ private func mappedInsertEntries(context: AccountContext, chatLocation: ChatLoca
|
|||
item = ChatNewThreadInfoItem(controllerInteraction: controllerInteraction, presentationData: presentationData, context: context)
|
||||
}
|
||||
return ListViewInsertItem(index: entry.index, previousIndex: entry.previousIndex, item: item, directionHint: entry.directionHint)
|
||||
case let .SearchEntry(theme, strings):
|
||||
return ListViewInsertItem(index: entry.index, previousIndex: entry.previousIndex, item: ChatListSearchItem(theme: theme, placeholder: strings.Common_Search, activate: {
|
||||
controllerInteraction.openSearch()
|
||||
}), directionHint: entry.directionHint)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -288,7 +283,7 @@ private func mappedUpdateEntries(context: AccountContext, chatLocation: ChatLoca
|
|||
switch mode {
|
||||
case .bubbles:
|
||||
item = ChatMessageItemImpl(presentationData: presentationData, context: context, chatLocation: chatLocation, associatedData: associatedData, controllerInteraction: controllerInteraction, content: .message(message: message, read: read, selection: selection, attributes: attributes, location: location), disableDate: disableFloatingDateHeaders || message.timestamp < 10)
|
||||
case let .list(_, _, _, displayHeaders, hintLinks, isGlobalSearch):
|
||||
case let .list(_, _, displayHeaders, hintLinks, isGlobalSearch):
|
||||
let displayHeader: Bool
|
||||
switch displayHeaders {
|
||||
case .none:
|
||||
|
|
@ -326,10 +321,6 @@ private func mappedUpdateEntries(context: AccountContext, chatLocation: ChatLoca
|
|||
item = ChatNewThreadInfoItem(controllerInteraction: controllerInteraction, presentationData: presentationData, context: context)
|
||||
}
|
||||
return ListViewUpdateItem(index: entry.index, previousIndex: entry.previousIndex, item: item, directionHint: entry.directionHint)
|
||||
case let .SearchEntry(theme, strings):
|
||||
return ListViewUpdateItem(index: entry.index, previousIndex: entry.previousIndex, item: ChatListSearchItem(theme: theme, placeholder: strings.Common_Search, activate: {
|
||||
controllerInteraction.openSearch()
|
||||
}), directionHint: entry.directionHint)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -2022,14 +2013,11 @@ public final class ChatHistoryListNodeImpl: ListView, ChatHistoryNode, ChatHisto
|
|||
|
||||
var reverse = false
|
||||
var reverseGroups = false
|
||||
var includeSearchEntry = false
|
||||
if case let .list(search, reverseValue, reverseGroupsValue, _, _, _) = mode {
|
||||
includeSearchEntry = search
|
||||
if case let .list(reverseValue, reverseGroupsValue, _, _, _) = mode {
|
||||
reverse = reverseValue
|
||||
reverseGroups = reverseGroupsValue
|
||||
}
|
||||
|
||||
|
||||
var isPremium = false
|
||||
if case let .user(user) = accountPeer, user.isPremium {
|
||||
isPremium = true
|
||||
|
|
@ -2087,7 +2075,6 @@ public final class ChatHistoryListNodeImpl: ListView, ChatHistoryNode, ChatHisto
|
|||
includeUnreadEntry: mode == .bubbles,
|
||||
includeEmptyEntry: mode == .bubbles && tag == nil,
|
||||
includeChatInfoEntry: mode == .bubbles,
|
||||
includeSearchEntry: includeSearchEntry && tag != nil,
|
||||
includeEmbeddedSavedChatInfo: includeEmbeddedSavedChatInfo,
|
||||
reverse: reverse,
|
||||
groupMessages: mode == .bubbles,
|
||||
|
|
@ -4551,7 +4538,7 @@ public final class ChatHistoryListNodeImpl: ListView, ChatHistoryNode, ChatHisto
|
|||
switch self.mode {
|
||||
case .bubbles:
|
||||
item = ChatMessageItemImpl(presentationData: presentationData, context: self.context, chatLocation: self.chatLocation, associatedData: associatedData, controllerInteraction: self.controllerInteraction, content: .message(message: message, read: read, selection: selection, attributes: attributes, location: location), disableDate: disableFloatingDateHeaders)
|
||||
case let .list(_, _, _, displayHeaders, hintLinks, isGlobalSearch):
|
||||
case let .list(_, _, displayHeaders, hintLinks, isGlobalSearch):
|
||||
let displayHeader: Bool
|
||||
switch displayHeaders {
|
||||
case .none:
|
||||
|
|
@ -4629,7 +4616,7 @@ public final class ChatHistoryListNodeImpl: ListView, ChatHistoryNode, ChatHisto
|
|||
switch self.mode {
|
||||
case .bubbles:
|
||||
item = ChatMessageItemImpl(presentationData: presentationData, context: self.context, chatLocation: self.chatLocation, associatedData: associatedData, controllerInteraction: self.controllerInteraction, content: .message(message: message, read: read, selection: selection, attributes: attributes, location: location), disableDate: disableFloatingDateHeaders)
|
||||
case let .list(_, _, _, displayHeaders, hintLinks, isGlobalSearch):
|
||||
case let .list(_, _, displayHeaders, hintLinks, isGlobalSearch):
|
||||
let displayHeader: Bool
|
||||
switch displayHeaders {
|
||||
case .none:
|
||||
|
|
|
|||
|
|
@ -41,8 +41,9 @@ public class ComposeControllerImpl: ViewController, ComposeController {
|
|||
|
||||
self.presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
||||
|
||||
super.init(navigationBarPresentationData: NavigationBarPresentationData(presentationData: self.presentationData))
|
||||
super.init(navigationBarPresentationData: NavigationBarPresentationData(presentationData: self.presentationData, style: .glass))
|
||||
|
||||
self._hasGlassStyle = true
|
||||
self.navigationPresentation = .modal
|
||||
|
||||
self.statusBar.statusBarStyle = self.presentationData.theme.rootController.statusBarStyle.style
|
||||
|
|
@ -51,8 +52,6 @@ public class ComposeControllerImpl: ViewController, ComposeController {
|
|||
|
||||
self.navigationItem.backBarButtonItem = UIBarButtonItem(title: self.presentationData.strings.Common_Back, style: .plain, target: nil, action: nil)
|
||||
|
||||
self.navigationItem.leftBarButtonItem = UIBarButtonItem(title: self.presentationData.strings.Common_Cancel, style: .plain, target: self, action: #selector(cancelPressed))
|
||||
|
||||
self.scrollToTop = { [weak self] in
|
||||
if let strongSelf = self {
|
||||
if let searchContentNode = strongSelf.searchContentNode {
|
||||
|
|
@ -93,7 +92,7 @@ public class ComposeControllerImpl: ViewController, ComposeController {
|
|||
|
||||
private func updateThemeAndStrings() {
|
||||
self.statusBar.statusBarStyle = self.presentationData.theme.rootController.statusBarStyle.style
|
||||
self.navigationBar?.updatePresentationData(NavigationBarPresentationData(presentationData: self.presentationData), transition: .immediate)
|
||||
self.navigationBar?.updatePresentationData(NavigationBarPresentationData(presentationData: self.presentationData, style: .glass), transition: .immediate)
|
||||
self.searchContentNode?.updateThemeAndPlaceholder(theme: self.presentationData.theme, placeholder: self.presentationData.strings.Common_Search)
|
||||
self.title = self.presentationData.strings.Compose_NewMessage
|
||||
self.navigationItem.backBarButtonItem = UIBarButtonItem(title: self.presentationData.strings.Common_Back, style: .plain, target: nil, action: nil)
|
||||
|
|
|
|||
|
|
@ -131,7 +131,7 @@ final class ComposeControllerNode: ASDisplayNode {
|
|||
self.requestOpenDisabledPeerFromSearch?(peer, reason)
|
||||
}, contextAction: nil), cancel: { [weak self] in
|
||||
self?.requestDeactivateSearch?()
|
||||
})
|
||||
}, fieldStyle: placeholderNode.fieldStyle)
|
||||
|
||||
self.searchDisplayController?.containerLayoutUpdated(containerLayout, navigationBarHeight: navigationBarHeight, transition: .immediate)
|
||||
self.searchDisplayController?.activate(insertSubnode: { [weak self, weak placeholderNode] subnode, isSearchBar in
|
||||
|
|
|
|||
|
|
@ -133,7 +133,9 @@ class ContactSelectionControllerImpl: ViewController, ContactSelectionController
|
|||
self.presentationData = self.presentationData.withUpdated(theme: self.presentationData.theme.withModalBlocksBackground())
|
||||
}
|
||||
|
||||
super.init(navigationBarPresentationData: NavigationBarPresentationData(theme: NavigationBarTheme(rootControllerTheme: self.presentationData.theme, hideBackground: glass, hideSeparator: glass), strings: NavigationBarStrings(presentationStrings: self.presentationData.strings)))
|
||||
super.init(navigationBarPresentationData: NavigationBarPresentationData(theme: NavigationBarTheme(rootControllerTheme: self.presentationData.theme, hideBackground: glass, hideSeparator: glass, style: .glass), strings: NavigationBarStrings(presentationStrings: self.presentationData.strings)))
|
||||
|
||||
self._hasGlassStyle = true
|
||||
|
||||
self.blocksBackgroundWhenInOverlay = true
|
||||
self.acceptsFocusWhenInOverlay = true
|
||||
|
|
@ -247,7 +249,7 @@ class ContactSelectionControllerImpl: ViewController, ContactSelectionController
|
|||
component: AnyComponentWithIdentity(id: "close", component: AnyComponent(
|
||||
BundleIconComponent(
|
||||
name: "Navigation/Close",
|
||||
tintColor: self.presentationData.theme.rootController.navigationBar.glassBarButtonForegroundColor
|
||||
tintColor: self.presentationData.theme.chat.inputPanel.panelControlColor
|
||||
)
|
||||
)),
|
||||
action: { [weak self] _ in
|
||||
|
|
@ -268,7 +270,7 @@ class ContactSelectionControllerImpl: ViewController, ContactSelectionController
|
|||
component: AnyComponentWithIdentity(id: "search", component: AnyComponent(
|
||||
BundleIconComponent(
|
||||
name: "Navigation/Search",
|
||||
tintColor: self.presentationData.theme.rootController.navigationBar.glassBarButtonForegroundColor
|
||||
tintColor: self.presentationData.theme.chat.inputPanel.panelControlColor
|
||||
)
|
||||
)),
|
||||
action: { [weak self] _ in
|
||||
|
|
@ -307,7 +309,7 @@ class ContactSelectionControllerImpl: ViewController, ContactSelectionController
|
|||
if case .glass = self.style {
|
||||
glass = true
|
||||
}
|
||||
self.navigationBar?.updatePresentationData(NavigationBarPresentationData(theme: NavigationBarTheme(rootControllerTheme: self.presentationData.theme, hideBackground: glass, hideSeparator: glass), strings: NavigationBarStrings(presentationStrings: self.presentationData.strings)), transition: .immediate)
|
||||
self.navigationBar?.updatePresentationData(NavigationBarPresentationData(theme: NavigationBarTheme(rootControllerTheme: self.presentationData.theme, hideBackground: glass, hideSeparator: glass, style: .glass), strings: NavigationBarStrings(presentationStrings: self.presentationData.strings)), transition: .immediate)
|
||||
(self.searchContentNode as? NavigationBarSearchContentNode)?.updateThemeAndPlaceholder(theme: self.presentationData.theme, placeholder: self.presentationData.strings.Common_Search)
|
||||
self.title = self.titleProducer(self.presentationData.strings)
|
||||
self.tabBarItem.title = self.presentationData.strings.Contacts_Title
|
||||
|
|
|
|||
|
|
@ -477,7 +477,7 @@ final class ContactSelectionControllerNode: ASDisplayNode {
|
|||
if let requestDeactivateSearch = self?.requestDeactivateSearch {
|
||||
requestDeactivateSearch()
|
||||
}
|
||||
})
|
||||
}, fieldStyle: placeholderNode.fieldStyle)
|
||||
|
||||
self.searchDisplayController?.containerLayoutUpdated(containerLayout, navigationBarHeight: navigationBarHeight, transition: .immediate)
|
||||
self.searchDisplayController?.activate(insertSubnode: { [weak self, weak placeholderNode] subnode, isSearchBar in
|
||||
|
|
|
|||
|
|
@ -259,7 +259,7 @@ final class OverlayAudioPlayerControllerNode: ViewControllerTracingNode, ASGestu
|
|||
|
||||
let chatLocationContextHolder = Atomic<ChatLocationContextHolder?>(value: nil)
|
||||
|
||||
self.historyNode = ChatHistoryListNodeImpl(context: context, updatedPresentationData: (context.sharedContext.currentPresentationData.with({ $0 }), context.sharedContext.presentationData), chatLocation: chatLocation, chatLocationContextHolder: chatLocationContextHolder, adMessagesContext: nil, tag: .tag(tagMask), source: self.source, subject: .message(id: .id(initialMessageId), highlight: ChatControllerSubject.MessageHighlight(quote: nil), timecode: nil, setupReply: false), controllerInteraction: self.controllerInteraction, selectedMessages: .single(nil), mode: .list(search: false, reversed: self.currentIsReversed, reverseGroups: !self.currentIsReversed, displayHeaders: .none, hintLinks: false, isGlobalSearch: self.isGlobalSearch), isChatPreview: false, messageTransitionNode: { return nil })
|
||||
self.historyNode = ChatHistoryListNodeImpl(context: context, updatedPresentationData: (context.sharedContext.currentPresentationData.with({ $0 }), context.sharedContext.presentationData), chatLocation: chatLocation, chatLocationContextHolder: chatLocationContextHolder, adMessagesContext: nil, tag: .tag(tagMask), source: self.source, subject: .message(id: .id(initialMessageId), highlight: ChatControllerSubject.MessageHighlight(quote: nil), timecode: nil, setupReply: false), controllerInteraction: self.controllerInteraction, selectedMessages: .single(nil), mode: .list(reversed: self.currentIsReversed, reverseGroups: !self.currentIsReversed, displayHeaders: .none, hintLinks: false, isGlobalSearch: self.isGlobalSearch), isChatPreview: false, messageTransitionNode: { return nil })
|
||||
self.historyNode.clipsToBounds = true
|
||||
|
||||
super.init()
|
||||
|
|
@ -881,7 +881,7 @@ final class OverlayAudioPlayerControllerNode: ViewControllerTracingNode, ASGestu
|
|||
}
|
||||
|
||||
let chatLocationContextHolder = Atomic<ChatLocationContextHolder?>(value: nil)
|
||||
let historyNode = ChatHistoryListNodeImpl(context: self.context, updatedPresentationData: (self.context.sharedContext.currentPresentationData.with({ $0 }), self.context.sharedContext.presentationData), chatLocation: self.chatLocation, chatLocationContextHolder: chatLocationContextHolder, adMessagesContext: nil, tag: .tag(tagMask), source: self.source, subject: .message(id: .id(messageId), highlight: ChatControllerSubject.MessageHighlight(quote: nil), timecode: nil, setupReply: false), controllerInteraction: self.controllerInteraction, selectedMessages: .single(nil), mode: .list(search: false, reversed: self.currentIsReversed, reverseGroups: !self.currentIsReversed, displayHeaders: .none, hintLinks: false, isGlobalSearch: self.isGlobalSearch), isChatPreview: false, messageTransitionNode: { return nil })
|
||||
let historyNode = ChatHistoryListNodeImpl(context: self.context, updatedPresentationData: (self.context.sharedContext.currentPresentationData.with({ $0 }), self.context.sharedContext.presentationData), chatLocation: self.chatLocation, chatLocationContextHolder: chatLocationContextHolder, adMessagesContext: nil, tag: .tag(tagMask), source: self.source, subject: .message(id: .id(messageId), highlight: ChatControllerSubject.MessageHighlight(quote: nil), timecode: nil, setupReply: false), controllerInteraction: self.controllerInteraction, selectedMessages: .single(nil), mode: .list(reversed: self.currentIsReversed, reverseGroups: !self.currentIsReversed, displayHeaders: .none, hintLinks: false, isGlobalSearch: self.isGlobalSearch), isChatPreview: false, messageTransitionNode: { return nil })
|
||||
historyNode.clipsToBounds = true
|
||||
historyNode.preloadPages = true
|
||||
historyNode.stackFromBottom = true
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue