mirror of
https://github.com/TelegramMessenger/Telegram-iOS.git
synced 2026-07-06 03:33:41 +02:00
Glass
This commit is contained in:
parent
3982aa3f9e
commit
a63c90aa00
41 changed files with 550 additions and 503 deletions
|
|
@ -34,6 +34,9 @@ swift_library(
|
||||||
"//submodules/InviteLinksUI",
|
"//submodules/InviteLinksUI",
|
||||||
"//submodules/UndoUI",
|
"//submodules/UndoUI",
|
||||||
"//submodules/TelegramCallsUI",
|
"//submodules/TelegramCallsUI",
|
||||||
|
"//submodules/TelegramUI/Components/EdgeEffect",
|
||||||
|
"//submodules/ComponentFlow",
|
||||||
|
"//submodules/Components/ComponentDisplayAdapters",
|
||||||
],
|
],
|
||||||
visibility = [
|
visibility = [
|
||||||
"//visibility:public",
|
"//visibility:public",
|
||||||
|
|
|
||||||
|
|
@ -361,10 +361,10 @@ public final class CallListController: TelegramBaseController {
|
||||||
if empty {
|
if empty {
|
||||||
switch strongSelf.mode {
|
switch strongSelf.mode {
|
||||||
case .tab:
|
case .tab:
|
||||||
strongSelf.navigationItem.setLeftBarButton(nil, animated: true)
|
strongSelf.navigationItem.setLeftBarButton(nil, animated: strongSelf.controllerNode.didSetReady)
|
||||||
strongSelf.navigationItem.setRightBarButton(nil, animated: true)
|
strongSelf.navigationItem.setRightBarButton(nil, animated: strongSelf.controllerNode.didSetReady)
|
||||||
case .navigation:
|
case .navigation:
|
||||||
strongSelf.navigationItem.setRightBarButton(nil, animated: true)
|
strongSelf.navigationItem.setRightBarButton(nil, animated: strongSelf.controllerNode.didSetReady)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
var pressedImpl: (() -> Void)?
|
var pressedImpl: (() -> Void)?
|
||||||
|
|
@ -381,25 +381,24 @@ public final class CallListController: TelegramBaseController {
|
||||||
switch strongSelf.mode {
|
switch strongSelf.mode {
|
||||||
case .tab:
|
case .tab:
|
||||||
if strongSelf.editingMode {
|
if strongSelf.editingMode {
|
||||||
strongSelf.navigationItem.setLeftBarButton(UIBarButtonItem(title: strongSelf.presentationData.strings.Common_Done, style: .done, target: strongSelf, action: #selector(strongSelf.donePressed)), animated: true)
|
strongSelf.navigationItem.setLeftBarButton(UIBarButtonItem(title: strongSelf.presentationData.strings.Common_Done, style: .done, target: strongSelf, action: #selector(strongSelf.donePressed)), animated: strongSelf.controllerNode.didSetReady)
|
||||||
strongSelf.navigationItem.setRightBarButton(UIBarButtonItem(customDisplayNode: buttonNode), animated: true)
|
strongSelf.navigationItem.setRightBarButton(UIBarButtonItem(customDisplayNode: buttonNode), animated: strongSelf.controllerNode.didSetReady)
|
||||||
strongSelf.navigationItem.rightBarButtonItem?.setCustomAction({
|
strongSelf.navigationItem.rightBarButtonItem?.setCustomAction({
|
||||||
pressedImpl?()
|
pressedImpl?()
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
strongSelf.navigationItem.setLeftBarButton(UIBarButtonItem(title: strongSelf.presentationData.strings.Common_Edit, style: .plain, target: strongSelf, action: #selector(strongSelf.editPressed)), animated: true)
|
strongSelf.navigationItem.setLeftBarButton(UIBarButtonItem(title: strongSelf.presentationData.strings.Common_Edit, style: .plain, target: strongSelf, action: #selector(strongSelf.editPressed)), animated: strongSelf.controllerNode.didSetReady)
|
||||||
//strongSelf.navigationItem.setRightBarButton(UIBarButtonItem(image: PresentationResourcesRootController.navigationCallIcon(strongSelf.presentationData.theme), style: .plain, target: self, action: #selector(strongSelf.callPressed)), animated: true)
|
strongSelf.navigationItem.setRightBarButton(nil, animated: strongSelf.controllerNode.didSetReady)
|
||||||
strongSelf.navigationItem.setRightBarButton(nil, animated: true)
|
|
||||||
}
|
}
|
||||||
case .navigation:
|
case .navigation:
|
||||||
if strongSelf.editingMode {
|
if strongSelf.editingMode {
|
||||||
strongSelf.navigationItem.setLeftBarButton(UIBarButtonItem(customDisplayNode: buttonNode), animated: true)
|
strongSelf.navigationItem.setLeftBarButton(UIBarButtonItem(customDisplayNode: buttonNode), animated: strongSelf.controllerNode.didSetReady)
|
||||||
strongSelf.navigationItem.leftBarButtonItem?.setCustomAction({
|
strongSelf.navigationItem.leftBarButtonItem?.setCustomAction({
|
||||||
pressedImpl?()
|
pressedImpl?()
|
||||||
})
|
})
|
||||||
strongSelf.navigationItem.setRightBarButton(UIBarButtonItem(title: strongSelf.presentationData.strings.Common_Done, style: .done, target: strongSelf, action: #selector(strongSelf.donePressed)), animated: true)
|
strongSelf.navigationItem.setRightBarButton(UIBarButtonItem(title: strongSelf.presentationData.strings.Common_Done, style: .done, target: strongSelf, action: #selector(strongSelf.donePressed)), animated: strongSelf.controllerNode.didSetReady)
|
||||||
} else {
|
} else {
|
||||||
strongSelf.navigationItem.setRightBarButton(UIBarButtonItem(title: strongSelf.presentationData.strings.Common_Edit, style: .plain, target: strongSelf, action: #selector(strongSelf.editPressed)), animated: true)
|
strongSelf.navigationItem.setRightBarButton(UIBarButtonItem(title: strongSelf.presentationData.strings.Common_Edit, style: .plain, target: strongSelf, action: #selector(strongSelf.editPressed)), animated: strongSelf.controllerNode.didSetReady)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -15,6 +15,9 @@ import AnimatedStickerNode
|
||||||
import TelegramAnimatedStickerNode
|
import TelegramAnimatedStickerNode
|
||||||
import AppBundle
|
import AppBundle
|
||||||
import ItemListPeerActionItem
|
import ItemListPeerActionItem
|
||||||
|
import EdgeEffect
|
||||||
|
import ComponentFlow
|
||||||
|
import ComponentDisplayAdapters
|
||||||
|
|
||||||
private struct CallListNodeListViewTransition {
|
private struct CallListNodeListViewTransition {
|
||||||
let callListView: CallListNodeView
|
let callListView: CallListNodeView
|
||||||
|
|
@ -185,7 +188,7 @@ final class CallListControllerNode: ASDisplayNode {
|
||||||
private var containerLayout: (ContainerViewLayout, CGFloat)?
|
private var containerLayout: (ContainerViewLayout, CGFloat)?
|
||||||
|
|
||||||
private let _ready = ValuePromise<Bool>()
|
private let _ready = ValuePromise<Bool>()
|
||||||
private var didSetReady = false
|
private(set) var didSetReady = false
|
||||||
var ready: Signal<Bool, NoError> {
|
var ready: Signal<Bool, NoError> {
|
||||||
return _ready.get()
|
return _ready.get()
|
||||||
}
|
}
|
||||||
|
|
@ -220,6 +223,8 @@ final class CallListControllerNode: ASDisplayNode {
|
||||||
private let emptyButtonIconNode: ASImageNode
|
private let emptyButtonIconNode: ASImageNode
|
||||||
private let emptyButtonTextNode: ImmediateTextNode
|
private let emptyButtonTextNode: ImmediateTextNode
|
||||||
|
|
||||||
|
private let edgeEffectView: EdgeEffectView
|
||||||
|
|
||||||
private let call: (EngineMessage) -> Void
|
private let call: (EngineMessage) -> Void
|
||||||
private let joinGroupCall: (EnginePeer.Id, EngineGroupCallDescription) -> Void
|
private let joinGroupCall: (EnginePeer.Id, EngineGroupCallDescription) -> Void
|
||||||
private let openNewCall: () -> Void
|
private let openNewCall: () -> Void
|
||||||
|
|
@ -277,6 +282,8 @@ final class CallListControllerNode: ASDisplayNode {
|
||||||
self.emptyButtonIconNode.displaysAsynchronously = false
|
self.emptyButtonIconNode.displaysAsynchronously = false
|
||||||
self.emptyButtonIconNode.isUserInteractionEnabled = false
|
self.emptyButtonIconNode.isUserInteractionEnabled = false
|
||||||
|
|
||||||
|
self.edgeEffectView = EdgeEffectView()
|
||||||
|
|
||||||
super.init()
|
super.init()
|
||||||
|
|
||||||
self.setViewBlock({
|
self.setViewBlock({
|
||||||
|
|
@ -289,6 +296,8 @@ final class CallListControllerNode: ASDisplayNode {
|
||||||
self.addSubnode(self.emptyButtonTextNode)
|
self.addSubnode(self.emptyButtonTextNode)
|
||||||
self.addSubnode(self.emptyButtonIconNode)
|
self.addSubnode(self.emptyButtonIconNode)
|
||||||
self.addSubnode(self.emptyButtonNode)
|
self.addSubnode(self.emptyButtonNode)
|
||||||
|
|
||||||
|
self.view.addSubview(self.edgeEffectView)
|
||||||
|
|
||||||
switch self.mode {
|
switch self.mode {
|
||||||
case .tab:
|
case .tab:
|
||||||
|
|
@ -945,5 +954,10 @@ final class CallListControllerNode: ASDisplayNode {
|
||||||
self.dequeuedInitialTransitionOnLayout = true
|
self.dequeuedInitialTransitionOnLayout = true
|
||||||
self.dequeueTransition()
|
self.dequeueTransition()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let edgeEffectHeight: CGFloat = layout.intrinsicInsets.bottom
|
||||||
|
let edgeEffectFrame = CGRect(origin: CGPoint(x: 0.0, y: layout.size.height - edgeEffectHeight), size: CGSize(width: layout.size.width, height: edgeEffectHeight))
|
||||||
|
transition.updateFrame(view: self.edgeEffectView, frame: edgeEffectFrame)
|
||||||
|
self.edgeEffectView.update(content: self.presentationData.theme.list.plainBackgroundColor, rect: edgeEffectFrame, edge: .bottom, edgeSize: edgeEffectFrame.height, transition: ComponentTransition(transition))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2102,9 +2102,7 @@ public class ChatListItemNode: ItemListRevealOptionsItemNode {
|
||||||
let effectiveBackgroundColor: UIColor
|
let effectiveBackgroundColor: UIColor
|
||||||
if item.isPinned {
|
if item.isPinned {
|
||||||
onlineIcon = PresentationResourcesChatList.recentStatusOnlineIcon(item.presentationData.theme, state: .pinned, voiceChat: self.onlineIsVoiceChat)
|
onlineIcon = PresentationResourcesChatList.recentStatusOnlineIcon(item.presentationData.theme, state: .pinned, voiceChat: self.onlineIsVoiceChat)
|
||||||
//TODO:localize
|
effectiveBackgroundColor = item.presentationData.theme.chatList.pinnedItemBackgroundColor
|
||||||
effectiveBackgroundColor = item.presentationData.theme.chatList.itemBackgroundColor
|
|
||||||
//effectiveBackgroundColor = item.presentationData.theme.chatList.pinnedItemBackgroundColor
|
|
||||||
} else {
|
} else {
|
||||||
onlineIcon = PresentationResourcesChatList.recentStatusOnlineIcon(item.presentationData.theme, state: .regular, voiceChat: self.onlineIsVoiceChat)
|
onlineIcon = PresentationResourcesChatList.recentStatusOnlineIcon(item.presentationData.theme, state: .regular, voiceChat: self.onlineIsVoiceChat)
|
||||||
effectiveBackgroundColor = item.presentationData.theme.chatList.itemBackgroundColor
|
effectiveBackgroundColor = item.presentationData.theme.chatList.itemBackgroundColor
|
||||||
|
|
@ -2118,9 +2116,7 @@ public class ChatListItemNode: ItemListRevealOptionsItemNode {
|
||||||
if let avatarLiveBadge = self.avatarLiveBadge {
|
if let avatarLiveBadge = self.avatarLiveBadge {
|
||||||
let effectiveBackgroundColor: UIColor
|
let effectiveBackgroundColor: UIColor
|
||||||
if item.isPinned {
|
if item.isPinned {
|
||||||
//TODO:localize
|
effectiveBackgroundColor = item.presentationData.theme.chatList.pinnedItemBackgroundColor
|
||||||
effectiveBackgroundColor = item.presentationData.theme.chatList.itemBackgroundColor
|
|
||||||
//effectiveBackgroundColor = item.presentationData.theme.chatList.pinnedItemBackgroundColor
|
|
||||||
} else {
|
} else {
|
||||||
effectiveBackgroundColor = item.presentationData.theme.chatList.itemBackgroundColor
|
effectiveBackgroundColor = item.presentationData.theme.chatList.itemBackgroundColor
|
||||||
}
|
}
|
||||||
|
|
@ -4133,9 +4129,7 @@ public class ChatListItemNode: ItemListRevealOptionsItemNode {
|
||||||
|
|
||||||
let effectiveBackgroundColor: UIColor
|
let effectiveBackgroundColor: UIColor
|
||||||
if item.isPinned {
|
if item.isPinned {
|
||||||
//TODO:localize
|
effectiveBackgroundColor = item.presentationData.theme.chatList.pinnedItemBackgroundColor
|
||||||
effectiveBackgroundColor = item.presentationData.theme.chatList.itemBackgroundColor
|
|
||||||
//effectiveBackgroundColor = item.presentationData.theme.chatList.pinnedItemBackgroundColor
|
|
||||||
} else {
|
} else {
|
||||||
effectiveBackgroundColor = item.presentationData.theme.chatList.itemBackgroundColor
|
effectiveBackgroundColor = item.presentationData.theme.chatList.itemBackgroundColor
|
||||||
}
|
}
|
||||||
|
|
@ -4156,9 +4150,7 @@ public class ChatListItemNode: ItemListRevealOptionsItemNode {
|
||||||
effectiveBackgroundColor = item.presentationData.theme.chatList.itemHighlightedBackgroundColor
|
effectiveBackgroundColor = item.presentationData.theme.chatList.itemHighlightedBackgroundColor
|
||||||
} else if case let .chatList(index) = item.index, index.pinningIndex != nil {
|
} else if case let .chatList(index) = item.index, index.pinningIndex != nil {
|
||||||
onlineIcon = PresentationResourcesChatList.recentStatusOnlineIcon(item.presentationData.theme, state: .pinned, voiceChat: onlineIsVoiceChat)
|
onlineIcon = PresentationResourcesChatList.recentStatusOnlineIcon(item.presentationData.theme, state: .pinned, voiceChat: onlineIsVoiceChat)
|
||||||
//TODO:localize
|
effectiveBackgroundColor = item.presentationData.theme.chatList.pinnedItemBackgroundColor
|
||||||
effectiveBackgroundColor = item.presentationData.theme.chatList.itemBackgroundColor
|
|
||||||
//effectiveBackgroundColor = item.presentationData.theme.chatList.pinnedItemBackgroundColor
|
|
||||||
} else {
|
} else {
|
||||||
onlineIcon = PresentationResourcesChatList.recentStatusOnlineIcon(item.presentationData.theme, state: .regular, voiceChat: onlineIsVoiceChat)
|
onlineIcon = PresentationResourcesChatList.recentStatusOnlineIcon(item.presentationData.theme, state: .regular, voiceChat: onlineIsVoiceChat)
|
||||||
effectiveBackgroundColor = item.presentationData.theme.chatList.itemBackgroundColor
|
effectiveBackgroundColor = item.presentationData.theme.chatList.itemBackgroundColor
|
||||||
|
|
@ -5070,9 +5062,7 @@ public class ChatListItemNode: ItemListRevealOptionsItemNode {
|
||||||
backgroundColor = theme.itemBackgroundColor
|
backgroundColor = theme.itemBackgroundColor
|
||||||
highlightedBackgroundColor = theme.itemHighlightedBackgroundColor
|
highlightedBackgroundColor = theme.itemHighlightedBackgroundColor
|
||||||
} else {
|
} else {
|
||||||
//TODO:localize
|
backgroundColor = theme.pinnedItemBackgroundColor
|
||||||
backgroundColor = item.presentationData.theme.chatList.itemBackgroundColor
|
|
||||||
//backgroundColor = theme.pinnedItemBackgroundColor
|
|
||||||
highlightedBackgroundColor = theme.pinnedItemHighlightedBackgroundColor
|
highlightedBackgroundColor = theme.pinnedItemHighlightedBackgroundColor
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|
|
||||||
|
|
@ -3251,8 +3251,10 @@ public final class ChatListNode: ListView {
|
||||||
if entryCount - 1 - i < 0 {
|
if entryCount - 1 - i < 0 {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if case .PeerEntry = transition.chatListView.filteredEntries[entryCount - 1 - i] {
|
switch transition.chatListView.filteredEntries[entryCount - 1 - i] {
|
||||||
} else {
|
case .PeerEntry, .GroupReferenceEntry:
|
||||||
|
break
|
||||||
|
default:
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if case let .index(index) = transition.chatListView.filteredEntries[entryCount - 1 - i].sortIndex, case let .chatList(chatListIndex) = index, chatListIndex.pinningIndex != nil {
|
if case let .index(index) = transition.chatListView.filteredEntries[entryCount - 1 - i].sortIndex, case let .chatList(chatListIndex) = index, chatListIndex.pinningIndex != nil {
|
||||||
|
|
|
||||||
|
|
@ -142,7 +142,7 @@ private final class AuthorizationSequenceCountrySelectionNavigationContentNode:
|
||||||
|
|
||||||
self.cancel = cancel
|
self.cancel = cancel
|
||||||
|
|
||||||
self.searchBar = SearchBarNode(theme: SearchBarNodeTheme(theme: theme), strings: strings, fieldStyle: .modern)
|
self.searchBar = SearchBarNode(theme: SearchBarNodeTheme(theme: theme), presentationTheme: theme, strings: strings, fieldStyle: .modern)
|
||||||
let placeholderText = strings.Common_Search
|
let placeholderText = strings.Common_Search
|
||||||
let searchBarFont = Font.regular(17.0)
|
let searchBarFont = Font.regular(17.0)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -980,7 +980,7 @@ private final class SearchNavigationContentNode: NavigationBarContentNode {
|
||||||
|
|
||||||
self.cancel = cancel
|
self.cancel = cancel
|
||||||
|
|
||||||
self.searchBar = SearchBarNode(theme: SearchBarNodeTheme(theme: theme), strings: strings, fieldStyle: .modern, cancelText: strings.Common_Done)
|
self.searchBar = SearchBarNode(theme: SearchBarNodeTheme(theme: theme), presentationTheme: theme, strings: strings, fieldStyle: .modern, cancelText: strings.Common_Done)
|
||||||
let placeholderText = placeholder?(strings) ?? strings.Common_Search
|
let placeholderText = placeholder?(strings) ?? strings.Common_Search
|
||||||
let searchBarFont = Font.regular(17.0)
|
let searchBarFont = Font.regular(17.0)
|
||||||
|
|
||||||
|
|
@ -1004,7 +1004,7 @@ private final class SearchNavigationContentNode: NavigationBarContentNode {
|
||||||
self.theme = theme
|
self.theme = theme
|
||||||
self.strings = strings
|
self.strings = strings
|
||||||
|
|
||||||
self.searchBar.updateThemeAndStrings(theme: SearchBarNodeTheme(theme: theme), strings: strings)
|
self.searchBar.updateThemeAndStrings(theme: SearchBarNodeTheme(theme: theme), presentationTheme: theme, strings: strings)
|
||||||
}
|
}
|
||||||
|
|
||||||
func setQueryUpdated(_ f: @escaping (String, String?) -> Void) {
|
func setQueryUpdated(_ f: @escaping (String, String?) -> Void) {
|
||||||
|
|
|
||||||
|
|
@ -59,7 +59,7 @@ public final class HashtagSearchController: TelegramBaseController {
|
||||||
}
|
}
|
||||||
self.presentationData = presentationData
|
self.presentationData = presentationData
|
||||||
|
|
||||||
super.init(context: context, navigationBarPresentationData: NavigationBarPresentationData(presentationData: self.presentationData), mediaAccessoryPanelVisibility: .specific(size: .compact), locationBroadcastPanelSource: .none, groupCallPanelSource: .none)
|
super.init(context: context, navigationBarPresentationData: NavigationBarPresentationData(presentationData: self.presentationData, style: .glass), mediaAccessoryPanelVisibility: .specific(size: .compact), locationBroadcastPanelSource: .none, groupCallPanelSource: .none)
|
||||||
|
|
||||||
self.statusBar.statusBarStyle = self.presentationData.theme.rootController.statusBarStyle.style
|
self.statusBar.statusBarStyle = self.presentationData.theme.rootController.statusBarStyle.style
|
||||||
|
|
||||||
|
|
@ -87,7 +87,7 @@ public final class HashtagSearchController: TelegramBaseController {
|
||||||
if previousTheme !== presentationData.theme || previousStrings !== presentationData.strings {
|
if previousTheme !== presentationData.theme || previousStrings !== presentationData.strings {
|
||||||
self.statusBar.statusBarStyle = self.presentationData.theme.rootController.statusBarStyle.style
|
self.statusBar.statusBarStyle = self.presentationData.theme.rootController.statusBarStyle.style
|
||||||
|
|
||||||
self.navigationBar?.updatePresentationData(NavigationBarPresentationData(presentationData: self.presentationData), transition: .immediate)
|
self.navigationBar?.updatePresentationData(NavigationBarPresentationData(presentationData: self.presentationData, style: .glass), transition: .immediate)
|
||||||
self.controllerNode.updatePresentationData(self.presentationData)
|
self.controllerNode.updatePresentationData(self.presentationData)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -79,7 +79,7 @@ final class HashtagSearchNavigationContentNode: NavigationBarContentNode {
|
||||||
var initialQuery = initialQuery
|
var initialQuery = initialQuery
|
||||||
initialQuery.removeFirst()
|
initialQuery.removeFirst()
|
||||||
|
|
||||||
self.searchBar = SearchBarNode(theme: SearchBarNodeTheme(theme: theme, hasSeparator: false), strings: strings, fieldStyle: .modern, icon: icon, displayBackground: false)
|
self.searchBar = SearchBarNode(theme: SearchBarNodeTheme(theme: theme, hasSeparator: false), presentationTheme: theme, strings: strings, fieldStyle: .modern, icon: icon, displayBackground: false)
|
||||||
self.searchBar.text = initialQuery
|
self.searchBar.text = initialQuery
|
||||||
self.searchBar.placeholderString = NSAttributedString(string: strings.HashtagSearch_SearchPlaceholder, font: searchBarFont, textColor: theme.rootController.navigationSearchBar.inputPlaceholderTextColor)
|
self.searchBar.placeholderString = NSAttributedString(string: strings.HashtagSearch_SearchPlaceholder, font: searchBarFont, textColor: theme.rootController.navigationSearchBar.inputPlaceholderTextColor)
|
||||||
|
|
||||||
|
|
@ -111,7 +111,7 @@ final class HashtagSearchNavigationContentNode: NavigationBarContentNode {
|
||||||
|
|
||||||
func updateTheme(_ theme: PresentationTheme) {
|
func updateTheme(_ theme: PresentationTheme) {
|
||||||
self.theme = theme
|
self.theme = theme
|
||||||
self.searchBar.updateThemeAndStrings(theme: SearchBarNodeTheme(theme: theme, hasSeparator: false), strings: self.strings)
|
self.searchBar.updateThemeAndStrings(theme: SearchBarNodeTheme(theme: theme, hasSeparator: false), presentationTheme: theme, strings: self.strings)
|
||||||
}
|
}
|
||||||
|
|
||||||
func setQueryUpdated(_ f: @escaping (String) -> Void) {
|
func setQueryUpdated(_ f: @escaping (String) -> Void) {
|
||||||
|
|
|
||||||
|
|
@ -38,7 +38,7 @@ final class SearchNavigationContentNode: NavigationBarContentNode, ItemListContr
|
||||||
|
|
||||||
self.cancel = cancel
|
self.cancel = cancel
|
||||||
|
|
||||||
self.searchBar = SearchBarNode(theme: SearchBarNodeTheme(theme: theme, hasSeparator: false), strings: strings, fieldStyle: .modern, displayBackground: false)
|
self.searchBar = SearchBarNode(theme: SearchBarNodeTheme(theme: theme, hasSeparator: false), presentationTheme: theme, strings: strings, fieldStyle: .modern, displayBackground: false)
|
||||||
|
|
||||||
super.init()
|
super.init()
|
||||||
|
|
||||||
|
|
@ -66,7 +66,7 @@ final class SearchNavigationContentNode: NavigationBarContentNode, ItemListContr
|
||||||
|
|
||||||
func updateTheme(_ theme: PresentationTheme) {
|
func updateTheme(_ theme: PresentationTheme) {
|
||||||
self.theme = theme
|
self.theme = theme
|
||||||
self.searchBar.updateThemeAndStrings(theme: SearchBarNodeTheme(theme: self.theme), strings: self.strings)
|
self.searchBar.updateThemeAndStrings(theme: SearchBarNodeTheme(theme: self.theme), presentationTheme: self.theme, strings: self.strings)
|
||||||
self.updatePlaceholder()
|
self.updatePlaceholder()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,7 @@ final class LocationSearchNavigationContentNode: NavigationBarContentNode {
|
||||||
self.presentationData = presentationData
|
self.presentationData = presentationData
|
||||||
self.interaction = interaction
|
self.interaction = interaction
|
||||||
|
|
||||||
self.searchBar = SearchBarNode(theme: SearchBarNodeTheme(theme: presentationData.theme, hasSeparator: false), strings: presentationData.strings, fieldStyle: .modern)
|
self.searchBar = SearchBarNode(theme: SearchBarNodeTheme(theme: presentationData.theme, hasSeparator: false), presentationTheme: presentationData.theme, strings: presentationData.strings, fieldStyle: .modern)
|
||||||
self.searchBar.placeholderString = NSAttributedString(string: presentationData.strings.Map_Search, font: searchBarFont, textColor: presentationData.theme.rootController.navigationSearchBar.inputPlaceholderTextColor)
|
self.searchBar.placeholderString = NSAttributedString(string: presentationData.strings.Map_Search, font: searchBarFont, textColor: presentationData.theme.rootController.navigationSearchBar.inputPlaceholderTextColor)
|
||||||
|
|
||||||
super.init()
|
super.init()
|
||||||
|
|
@ -58,6 +58,6 @@ final class LocationSearchNavigationContentNode: NavigationBarContentNode {
|
||||||
|
|
||||||
func updatePresentationData(_ presentationData: PresentationData) {
|
func updatePresentationData(_ presentationData: PresentationData) {
|
||||||
self.presentationData = presentationData
|
self.presentationData = presentationData
|
||||||
self.searchBar.updateThemeAndStrings(theme: SearchBarNodeTheme(theme: presentationData.theme, hasSeparator: false), strings: presentationData.strings)
|
self.searchBar.updateThemeAndStrings(theme: SearchBarNodeTheme(theme: presentationData.theme, hasSeparator: false), presentationTheme: presentationData.theme, strings: presentationData.strings)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -168,6 +168,7 @@ private final class ChannelDiscussionSearchNavigationContentNode: NavigationBarC
|
||||||
accent: theme.chat.inputPanel.panelControlAccentColor,
|
accent: theme.chat.inputPanel.panelControlAccentColor,
|
||||||
keyboard: theme.rootController.keyboardColor
|
keyboard: theme.rootController.keyboardColor
|
||||||
),
|
),
|
||||||
|
presentationTheme: theme,
|
||||||
strings: strings,
|
strings: strings,
|
||||||
fieldStyle: .inlineNavigation,
|
fieldStyle: .inlineNavigation,
|
||||||
forceSeparator: false,
|
forceSeparator: false,
|
||||||
|
|
|
||||||
|
|
@ -83,6 +83,7 @@ final class GroupInfoSearchNavigationContentNode: NavigationBarContentNode, Item
|
||||||
accent: theme.chat.inputPanel.panelControlAccentColor,
|
accent: theme.chat.inputPanel.panelControlAccentColor,
|
||||||
keyboard: theme.rootController.keyboardColor
|
keyboard: theme.rootController.keyboardColor
|
||||||
),
|
),
|
||||||
|
presentationTheme: theme,
|
||||||
strings: strings,
|
strings: strings,
|
||||||
fieldStyle: .inlineNavigation,
|
fieldStyle: .inlineNavigation,
|
||||||
forceSeparator: false,
|
forceSeparator: false,
|
||||||
|
|
|
||||||
|
|
@ -894,6 +894,9 @@ public class SearchBarNode: ASDisplayNode, UITextFieldDelegate {
|
||||||
|
|
||||||
public var tokensUpdated: (([SearchBarToken]) -> Void)?
|
public var tokensUpdated: (([SearchBarToken]) -> Void)?
|
||||||
|
|
||||||
|
private let inlineSearchPlaceholder: SearchBarPlaceholderNode
|
||||||
|
private var inlineSearchPlaceholderContentsView: SearchBarPlaceholderContentView?
|
||||||
|
|
||||||
private let backgroundNode: NavigationBackgroundNode
|
private let backgroundNode: NavigationBackgroundNode
|
||||||
private let separatorNode: ASDisplayNode
|
private let separatorNode: ASDisplayNode
|
||||||
private let textBackgroundNode: ASDisplayNode
|
private let textBackgroundNode: ASDisplayNode
|
||||||
|
|
@ -972,6 +975,9 @@ public class SearchBarNode: ASDisplayNode, UITextFieldDelegate {
|
||||||
if let takenSearchPlaceholderContentView = self.takenSearchPlaceholderContentView {
|
if let takenSearchPlaceholderContentView = self.takenSearchPlaceholderContentView {
|
||||||
takenSearchPlaceholderContentView.updateSearchIconVisibility(isVisible: !self.activity)
|
takenSearchPlaceholderContentView.updateSearchIconVisibility(isVisible: !self.activity)
|
||||||
}
|
}
|
||||||
|
if let inlineSearchPlaceholderContentsView = self.inlineSearchPlaceholderContentsView {
|
||||||
|
inlineSearchPlaceholderContentsView.updateSearchIconVisibility(isVisible: !self.activity)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -999,14 +1005,21 @@ public class SearchBarNode: ASDisplayNode, UITextFieldDelegate {
|
||||||
public let fieldStyle: SearchBarStyle
|
public let fieldStyle: SearchBarStyle
|
||||||
private let forceSeparator: Bool
|
private let forceSeparator: Bool
|
||||||
private var theme: SearchBarNodeTheme?
|
private var theme: SearchBarNodeTheme?
|
||||||
|
private var presentationTheme: PresentationTheme
|
||||||
private var strings: PresentationStrings?
|
private var strings: PresentationStrings?
|
||||||
private let cancelText: String?
|
private let cancelText: String?
|
||||||
|
|
||||||
public init(theme: SearchBarNodeTheme, strings: PresentationStrings, fieldStyle: SearchBarStyle = .legacy, icon: Icon = .loupe, forceSeparator: Bool = false, displayBackground: Bool = true, cancelText: String? = nil) {
|
private var isAnimatingOut: Bool = false
|
||||||
|
|
||||||
|
public init(theme: SearchBarNodeTheme, presentationTheme: PresentationTheme, strings: PresentationStrings, fieldStyle: SearchBarStyle = .legacy, icon: Icon = .loupe, forceSeparator: Bool = false, displayBackground: Bool = true, cancelText: String? = nil) {
|
||||||
|
self.presentationTheme = presentationTheme
|
||||||
|
|
||||||
self.fieldStyle = fieldStyle
|
self.fieldStyle = fieldStyle
|
||||||
self.forceSeparator = forceSeparator
|
self.forceSeparator = forceSeparator
|
||||||
self.cancelText = cancelText
|
self.cancelText = cancelText
|
||||||
self.icon = icon
|
self.icon = icon
|
||||||
|
|
||||||
|
self.inlineSearchPlaceholder = SearchBarPlaceholderNode(fieldStyle: .glass)
|
||||||
|
|
||||||
self.backgroundNode = NavigationBackgroundNode(color: theme.background)
|
self.backgroundNode = NavigationBackgroundNode(color: theme.background)
|
||||||
self.backgroundNode.isUserInteractionEnabled = false
|
self.backgroundNode.isUserInteractionEnabled = false
|
||||||
|
|
@ -1043,7 +1056,9 @@ public class SearchBarNode: ASDisplayNode, UITextFieldDelegate {
|
||||||
super.init()
|
super.init()
|
||||||
|
|
||||||
switch self.fieldStyle {
|
switch self.fieldStyle {
|
||||||
case .glass, .inlineNavigation:
|
case .glass:
|
||||||
|
break
|
||||||
|
case .inlineNavigation:
|
||||||
break
|
break
|
||||||
case .legacy, .modern:
|
case .legacy, .modern:
|
||||||
self.addSubnode(self.backgroundNode)
|
self.addSubnode(self.backgroundNode)
|
||||||
|
|
@ -1085,11 +1100,11 @@ public class SearchBarNode: ASDisplayNode, UITextFieldDelegate {
|
||||||
self.cancelButton.addTarget(self, action: #selector(self.cancelPressed), forControlEvents: .touchUpInside)
|
self.cancelButton.addTarget(self, action: #selector(self.cancelPressed), forControlEvents: .touchUpInside)
|
||||||
self.clearButton.addTarget(self, action: #selector(self.clearPressed), forControlEvents: .touchUpInside)
|
self.clearButton.addTarget(self, action: #selector(self.clearPressed), forControlEvents: .touchUpInside)
|
||||||
|
|
||||||
self.updateThemeAndStrings(theme: theme, strings: strings)
|
self.updateThemeAndStrings(theme: theme, presentationTheme: presentationTheme, strings: strings)
|
||||||
self.updateIsEmpty(animated: false)
|
self.updateIsEmpty(animated: false)
|
||||||
}
|
}
|
||||||
|
|
||||||
public func updateThemeAndStrings(theme: SearchBarNodeTheme, strings: PresentationStrings) {
|
public func updateThemeAndStrings(theme: SearchBarNodeTheme, presentationTheme: PresentationTheme, strings: PresentationStrings) {
|
||||||
if self.theme != theme || self.strings !== strings {
|
if self.theme != theme || self.strings !== strings {
|
||||||
self.clearButton.accessibilityLabel = strings.WebSearch_RecentSectionClear
|
self.clearButton.accessibilityLabel = strings.WebSearch_RecentSectionClear
|
||||||
self.cancelButton.accessibilityLabel = self.cancelText ?? strings.Common_Cancel
|
self.cancelButton.accessibilityLabel = self.cancelText ?? strings.Common_Cancel
|
||||||
|
|
@ -1122,6 +1137,7 @@ public class SearchBarNode: ASDisplayNode, UITextFieldDelegate {
|
||||||
}
|
}
|
||||||
|
|
||||||
self.theme = theme
|
self.theme = theme
|
||||||
|
self.presentationTheme = presentationTheme
|
||||||
self.strings = strings
|
self.strings = strings
|
||||||
if let (boundingSize, leftInset, rightInset) = self.validLayout {
|
if let (boundingSize, leftInset, rightInset) = self.validLayout {
|
||||||
self.updateLayout(boundingSize: boundingSize, leftInset: leftInset, rightInset: rightInset, transition: .immediate)
|
self.updateLayout(boundingSize: boundingSize, leftInset: leftInset, rightInset: rightInset, transition: .immediate)
|
||||||
|
|
@ -1184,6 +1200,45 @@ public class SearchBarNode: ASDisplayNode, UITextFieldDelegate {
|
||||||
transition.updateFrame(node: self.clearButton, frame: CGRect(origin: CGPoint(x: textBackgroundFrame.maxX - 6.0 - clearSize.width, y: textBackgroundFrame.minY + floor((textBackgroundFrame.size.height - clearSize.height) / 2.0)), size: clearSize))
|
transition.updateFrame(node: self.clearButton, frame: CGRect(origin: CGPoint(x: textBackgroundFrame.maxX - 6.0 - clearSize.width, y: textBackgroundFrame.minY + floor((textBackgroundFrame.size.height - clearSize.height) / 2.0)), size: clearSize))
|
||||||
|
|
||||||
self.textField.frame = textFrame
|
self.textField.frame = textFrame
|
||||||
|
|
||||||
|
let searchPlaceholderFrame = CGRect(origin: CGPoint(x: 16.0, y: 0.0), size: CGSize(width: max(0.0, boundingSize.width - 16.0 * 2.0), height: 44.0))
|
||||||
|
|
||||||
|
if case .glass = self.fieldStyle, self.takenSearchPlaceholderContentView == nil {
|
||||||
|
transition.updateFrame(node: self.inlineSearchPlaceholder, frame: searchPlaceholderFrame)
|
||||||
|
if let theme = self.theme {
|
||||||
|
let _ = self.inlineSearchPlaceholder.updateLayout(
|
||||||
|
placeholderString: self.placeholderString,
|
||||||
|
compactPlaceholderString: self.placeholderString,
|
||||||
|
constrainedSize: searchPlaceholderFrame.size,
|
||||||
|
expansionProgress: 1.0,
|
||||||
|
iconColor: theme.inputIcon,
|
||||||
|
foregroundColor: self.presentationTheme.chat.inputPanel.panelControlColor,
|
||||||
|
backgroundColor: self.presentationTheme.rootController.navigationBar.opaqueBackgroundColor,
|
||||||
|
controlColor: self.presentationTheme.chat.inputPanel.panelControlColor,
|
||||||
|
transition: transition
|
||||||
|
)
|
||||||
|
if self.inlineSearchPlaceholderContentsView == nil {
|
||||||
|
let inlineSearchPlaceholderContentsView = self.inlineSearchPlaceholder.takeContents()
|
||||||
|
inlineSearchPlaceholderContentsView.onCancel = { [weak self] in
|
||||||
|
guard let self else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
self.cancel?()
|
||||||
|
}
|
||||||
|
self.inlineSearchPlaceholderContentsView = inlineSearchPlaceholderContentsView
|
||||||
|
self.view.insertSubview(inlineSearchPlaceholderContentsView, at: 0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if let inlineSearchPlaceholderContentsView = self.inlineSearchPlaceholderContentsView {
|
||||||
|
inlineSearchPlaceholderContentsView.update(size: searchPlaceholderFrame.size, isActive: true, transition: transition)
|
||||||
|
transition.updateFrame(view: inlineSearchPlaceholderContentsView, frame: searchPlaceholderFrame)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if !self.isAnimatingOut, let takenSearchPlaceholderContentView = self.takenSearchPlaceholderContentView {
|
||||||
|
transition.updateFrame(view: takenSearchPlaceholderContentView, frame: searchPlaceholderFrame)
|
||||||
|
takenSearchPlaceholderContentView.update(size: searchPlaceholderFrame.size, isActive: true, transition: transition)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@objc private func tapGesture(_ recognizer: UITapGestureRecognizer) {
|
@objc private func tapGesture(_ recognizer: UITapGestureRecognizer) {
|
||||||
|
|
@ -1201,6 +1256,8 @@ public class SearchBarNode: ASDisplayNode, UITextFieldDelegate {
|
||||||
}
|
}
|
||||||
|
|
||||||
public func animateIn(from node: SearchBarPlaceholderNode, duration: Double, timingFunction: String) {
|
public func animateIn(from node: SearchBarPlaceholderNode, duration: Double, timingFunction: String) {
|
||||||
|
self.inlineSearchPlaceholder.isHidden = true
|
||||||
|
|
||||||
let takenSearchPlaceholderContentView = node.takeContents()
|
let takenSearchPlaceholderContentView = node.takeContents()
|
||||||
takenSearchPlaceholderContentView.onCancel = { [weak self] in
|
takenSearchPlaceholderContentView.onCancel = { [weak self] in
|
||||||
guard let self else {
|
guard let self else {
|
||||||
|
|
@ -1210,6 +1267,9 @@ public class SearchBarNode: ASDisplayNode, UITextFieldDelegate {
|
||||||
}
|
}
|
||||||
self.takenSearchPlaceholderContentView = takenSearchPlaceholderContentView
|
self.takenSearchPlaceholderContentView = takenSearchPlaceholderContentView
|
||||||
self.view.insertSubview(takenSearchPlaceholderContentView, at: 0)
|
self.view.insertSubview(takenSearchPlaceholderContentView, at: 0)
|
||||||
|
if let inlineSearchPlaceholderContentsView = self.inlineSearchPlaceholderContentsView {
|
||||||
|
inlineSearchPlaceholderContentsView.removeFromSuperview()
|
||||||
|
}
|
||||||
|
|
||||||
let sourceFrame = node.view.convert(node.bounds, to: self.view)
|
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 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))
|
||||||
|
|
@ -1271,6 +1331,8 @@ public class SearchBarNode: ASDisplayNode, UITextFieldDelegate {
|
||||||
}
|
}
|
||||||
|
|
||||||
public func transitionOut(to node: SearchBarPlaceholderNode, transition: ContainedViewLayoutTransition, completion: @escaping () -> Void) {
|
public func transitionOut(to node: SearchBarPlaceholderNode, transition: ContainedViewLayoutTransition, completion: @escaping () -> Void) {
|
||||||
|
self.isAnimatingOut = true
|
||||||
|
|
||||||
/*let targetTextBackgroundFrame = node.view.convert(node.backgroundView.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 duration: Double = transition.isAnimated ? 0.5 : 0.0
|
||||||
|
|
@ -1531,6 +1593,7 @@ public class SearchBarNode: ASDisplayNode, UITextFieldDelegate {
|
||||||
if let takenSearchPlaceholderContentView = self.takenSearchPlaceholderContentView {
|
if let takenSearchPlaceholderContentView = self.takenSearchPlaceholderContentView {
|
||||||
takenSearchPlaceholderContentView.updatePlaceholderVisibility(isVisible: isEmpty)
|
takenSearchPlaceholderContentView.updatePlaceholderVisibility(isVisible: isEmpty)
|
||||||
}
|
}
|
||||||
|
self.inlineSearchPlaceholderContentsView?.updatePlaceholderVisibility(isVisible: isEmpty)
|
||||||
|
|
||||||
let clearIsHidden = (textIsEmpty && tokensEmpty) && self.prefixString == nil
|
let clearIsHidden = (textIsEmpty && tokensEmpty) && self.prefixString == nil
|
||||||
transition.updateAlpha(node: self.clearButton.imageNode, alpha: clearIsHidden ? 0.0 : 1.0)
|
transition.updateAlpha(node: self.clearButton.imageNode, alpha: clearIsHidden ? 0.0 : 1.0)
|
||||||
|
|
|
||||||
|
|
@ -49,13 +49,15 @@ public final class SearchBarPlaceholderContentView: UIView {
|
||||||
}
|
}
|
||||||
|
|
||||||
let fieldStyle: SearchBarStyle
|
let fieldStyle: SearchBarStyle
|
||||||
let backgroundNode: ASDisplayNode?
|
let plainBackgroundView: UIImageView
|
||||||
let glassBackgroundView: GlassBackgroundView?
|
let glassBackgroundView: GlassBackgroundView?
|
||||||
private var fillBackgroundColor: UIColor
|
private var fillBackgroundColor: UIColor
|
||||||
private var foregroundColor: UIColor
|
private var foregroundColor: UIColor
|
||||||
private var iconColor: UIColor
|
private var iconColor: UIColor
|
||||||
let iconNode: ASImageNode
|
let iconNode: ASImageNode
|
||||||
let labelNode: TextNode
|
let labelNode: TextNode
|
||||||
|
let plainIconNode: ASImageNode
|
||||||
|
let plainLabelNode: TextNode
|
||||||
|
|
||||||
private var close: (background: GlassBackgroundView, icon: UIImageView)?
|
private var close: (background: GlassBackgroundView, icon: UIImageView)?
|
||||||
|
|
||||||
|
|
@ -72,20 +74,13 @@ public final class SearchBarPlaceholderContentView: UIView {
|
||||||
self.foregroundColor = UIColor(rgb: 0xededed)
|
self.foregroundColor = UIColor(rgb: 0xededed)
|
||||||
self.iconColor = UIColor(rgb: 0x000000, alpha: 0.0)
|
self.iconColor = UIColor(rgb: 0x000000, alpha: 0.0)
|
||||||
|
|
||||||
|
self.plainBackgroundView = UIImageView()
|
||||||
|
|
||||||
switch fieldStyle {
|
switch fieldStyle {
|
||||||
case .legacy, .modern:
|
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
|
self.glassBackgroundView = nil
|
||||||
case .inlineNavigation, .glass:
|
case .inlineNavigation, .glass:
|
||||||
self.glassBackgroundView = GlassBackgroundView()
|
self.glassBackgroundView = GlassBackgroundView()
|
||||||
|
|
||||||
self.backgroundNode = nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
self.iconNode = ASImageNode()
|
self.iconNode = ASImageNode()
|
||||||
|
|
@ -96,20 +91,27 @@ public final class SearchBarPlaceholderContentView: UIView {
|
||||||
self.labelNode.isOpaque = false
|
self.labelNode.isOpaque = false
|
||||||
self.labelNode.isUserInteractionEnabled = false
|
self.labelNode.isUserInteractionEnabled = false
|
||||||
|
|
||||||
|
self.plainIconNode = ASImageNode()
|
||||||
|
self.plainIconNode.displaysAsynchronously = false
|
||||||
|
self.plainIconNode.displayWithoutProcessing = true
|
||||||
|
|
||||||
|
self.plainLabelNode = TextNode()
|
||||||
|
self.plainLabelNode.isOpaque = false
|
||||||
|
self.plainLabelNode.isUserInteractionEnabled = false
|
||||||
|
|
||||||
super.init(frame: CGRect())
|
super.init(frame: CGRect())
|
||||||
|
|
||||||
if let backgroundNode = self.backgroundNode {
|
self.plainBackgroundView.isUserInteractionEnabled = true
|
||||||
backgroundNode.isUserInteractionEnabled = true
|
self.addSubview(self.plainBackgroundView)
|
||||||
self.addSubview(backgroundNode.view)
|
|
||||||
}
|
self.plainBackgroundView.addSubview(self.plainIconNode.view)
|
||||||
|
self.plainBackgroundView.addSubview(self.plainLabelNode.view)
|
||||||
|
|
||||||
if let glassBackgroundView = self.glassBackgroundView {
|
if let glassBackgroundView = self.glassBackgroundView {
|
||||||
self.addSubview(glassBackgroundView)
|
self.addSubview(glassBackgroundView)
|
||||||
|
|
||||||
glassBackgroundView.contentView.addSubview(self.iconNode.view)
|
glassBackgroundView.contentView.addSubview(self.iconNode.view)
|
||||||
glassBackgroundView.contentView.addSubview(self.labelNode.view)
|
glassBackgroundView.contentView.addSubview(self.labelNode.view)
|
||||||
} else {
|
|
||||||
self.addSubview(self.iconNode.view)
|
|
||||||
self.addSubview(self.labelNode.view)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -161,6 +163,7 @@ public final class SearchBarPlaceholderContentView: UIView {
|
||||||
|
|
||||||
private func updateLayout(params: Params, transition: ContainedViewLayoutTransition) -> CGFloat {
|
private func updateLayout(params: Params, transition: ContainedViewLayoutTransition) -> CGFloat {
|
||||||
let labelLayout = TextNode.asyncLayout(self.labelNode)
|
let labelLayout = TextNode.asyncLayout(self.labelNode)
|
||||||
|
let plainLabelLayout = TextNode.asyncLayout(self.plainLabelNode)
|
||||||
let currentForegroundColor = self.foregroundColor
|
let currentForegroundColor = self.foregroundColor
|
||||||
let currentIconColor = self.iconColor
|
let currentIconColor = self.iconColor
|
||||||
|
|
||||||
|
|
@ -172,6 +175,7 @@ public final class SearchBarPlaceholderContentView: UIView {
|
||||||
}
|
}
|
||||||
|
|
||||||
let (labelLayoutResult, labelApply) = labelLayout(TextNodeLayoutArguments(attributedString: placeholderString, backgroundColor: .clear, maximumNumberOfLines: 1, truncationType: .end, constrainedSize: params.constrainedSize, alignment: .natural, cutout: nil, insets: UIEdgeInsets()))
|
let (labelLayoutResult, labelApply) = labelLayout(TextNodeLayoutArguments(attributedString: placeholderString, backgroundColor: .clear, maximumNumberOfLines: 1, truncationType: .end, constrainedSize: params.constrainedSize, alignment: .natural, cutout: nil, insets: UIEdgeInsets()))
|
||||||
|
let (_, plainLabelApply) = plainLabelLayout(TextNodeLayoutArguments(attributedString: placeholderString, backgroundColor: .clear, maximumNumberOfLines: 1, truncationType: .end, constrainedSize: params.constrainedSize, alignment: .natural, cutout: nil, insets: UIEdgeInsets()))
|
||||||
|
|
||||||
var updatedColor: UIColor?
|
var updatedColor: UIColor?
|
||||||
var updatedIconImage: UIImage?
|
var updatedIconImage: UIImage?
|
||||||
|
|
@ -185,19 +189,19 @@ public final class SearchBarPlaceholderContentView: UIView {
|
||||||
let height = params.constrainedSize.height * params.expansionProgress
|
let height = params.constrainedSize.height * params.expansionProgress
|
||||||
|
|
||||||
let _ = labelApply()
|
let _ = labelApply()
|
||||||
|
let _ = plainLabelApply()
|
||||||
|
|
||||||
self.fillBackgroundColor = params.backgroundColor
|
self.fillBackgroundColor = params.backgroundColor
|
||||||
self.foregroundColor = params.foregroundColor
|
self.foregroundColor = params.foregroundColor
|
||||||
self.iconColor = params.iconColor
|
self.iconColor = params.iconColor
|
||||||
if let backgroundNode = self.backgroundNode {
|
self.plainBackgroundView.isUserInteractionEnabled = params.expansionProgress > 0.9999
|
||||||
backgroundNode.isUserInteractionEnabled = params.expansionProgress > 0.9999
|
|
||||||
}
|
|
||||||
|
|
||||||
if let updatedColor, let backgroundNode = self.backgroundNode {
|
if let updatedColor {
|
||||||
backgroundNode.backgroundColor = updatedColor
|
self.plainBackgroundView.backgroundColor = updatedColor
|
||||||
}
|
}
|
||||||
if let updatedIconImage {
|
if let updatedIconImage {
|
||||||
self.iconNode.image = updatedIconImage
|
self.iconNode.image = updatedIconImage
|
||||||
|
self.plainIconNode.image = updatedIconImage
|
||||||
}
|
}
|
||||||
|
|
||||||
self.placeholderString = placeholderString
|
self.placeholderString = placeholderString
|
||||||
|
|
@ -220,6 +224,7 @@ public final class SearchBarPlaceholderContentView: UIView {
|
||||||
iconX = floor((params.constrainedSize.width - totalWidth) / 2.0)
|
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))
|
transition.updateFrame(node: self.iconNode, frame: CGRect(origin: CGPoint(x: iconX, y: floorToScreenPixels((height - iconSize.height) / 2.0)), size: iconSize))
|
||||||
|
transition.updateFrame(node: self.plainIconNode, frame: CGRect(origin: CGPoint(x: iconX, y: floorToScreenPixels((height - iconSize.height) / 2.0)), size: iconSize))
|
||||||
} else {
|
} else {
|
||||||
iconX = 12.0
|
iconX = 12.0
|
||||||
}
|
}
|
||||||
|
|
@ -230,6 +235,7 @@ public final class SearchBarPlaceholderContentView: UIView {
|
||||||
let labelX: CGFloat = iconX + iconSize.width + spacing
|
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)
|
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)
|
transition.updateFrame(node: self.labelNode, frame: labelFrame)
|
||||||
|
transition.updateFrame(node: self.plainLabelNode, frame: labelFrame)
|
||||||
|
|
||||||
var innerAlpha = max(0.0, params.expansionProgress - 0.77) / 0.23
|
var innerAlpha = max(0.0, params.expansionProgress - 0.77) / 0.23
|
||||||
if innerAlpha > 0.9999 {
|
if innerAlpha > 0.9999 {
|
||||||
|
|
@ -241,27 +247,36 @@ public final class SearchBarPlaceholderContentView: UIView {
|
||||||
if !transition.isAnimated {
|
if !transition.isAnimated {
|
||||||
self.labelNode.layer.removeAnimation(forKey: "opacity")
|
self.labelNode.layer.removeAnimation(forKey: "opacity")
|
||||||
self.iconNode.layer.removeAnimation(forKey: "opacity")
|
self.iconNode.layer.removeAnimation(forKey: "opacity")
|
||||||
|
self.plainLabelNode.layer.removeAnimation(forKey: "opacity")
|
||||||
|
self.plainIconNode.layer.removeAnimation(forKey: "opacity")
|
||||||
}
|
}
|
||||||
|
|
||||||
transition.updateAlpha(node: self.labelNode, alpha: innerAlpha)
|
transition.updateAlpha(node: self.labelNode, alpha: innerAlpha)
|
||||||
transition.updateAlpha(node: self.iconNode, alpha: innerAlpha)
|
transition.updateAlpha(node: self.iconNode, alpha: innerAlpha)
|
||||||
|
|
||||||
|
transition.updateAlpha(node: self.plainLabelNode, alpha: innerAlpha)
|
||||||
|
transition.updateAlpha(node: self.plainIconNode, alpha: innerAlpha)
|
||||||
}
|
}
|
||||||
|
|
||||||
let outerAlpha = min(0.3, params.expansionProgress) / 0.3
|
let outerAlpha = min(0.3, params.expansionProgress) / 0.3
|
||||||
let cornerRadius = min(self.fieldStyle.cornerDiameter / 2.0, height / 2.0)
|
let cornerRadius = height * 0.5
|
||||||
|
|
||||||
if let backgroundNode = self.backgroundNode, backgroundNode.cornerRadius != cornerRadius {
|
if self.plainBackgroundView.layer.cornerRadius != cornerRadius {
|
||||||
if !transition.isAnimated {
|
if !transition.isAnimated {
|
||||||
backgroundNode.layer.removeAnimation(forKey: "cornerRadius")
|
self.plainBackgroundView.layer.removeAnimation(forKey: "cornerRadius")
|
||||||
}
|
}
|
||||||
transition.updateCornerRadius(node: backgroundNode, cornerRadius: cornerRadius)
|
transition.updateCornerRadius(layer: self.plainBackgroundView.layer, cornerRadius: cornerRadius)
|
||||||
}
|
}
|
||||||
|
|
||||||
if let backgroundNode = self.backgroundNode, backgroundNode.alpha != outerAlpha {
|
var plainBackgroundAlpha = outerAlpha
|
||||||
|
if params.isActive {
|
||||||
|
plainBackgroundAlpha = 0.0
|
||||||
|
}
|
||||||
|
if self.plainBackgroundView.alpha != plainBackgroundAlpha {
|
||||||
if !transition.isAnimated {
|
if !transition.isAnimated {
|
||||||
backgroundNode.layer.removeAnimation(forKey: "opacity")
|
self.plainBackgroundView.layer.removeAnimation(forKey: "opacity")
|
||||||
}
|
}
|
||||||
transition.updateAlpha(node: backgroundNode, alpha: outerAlpha)
|
transition.updateAlpha(layer: self.plainBackgroundView.layer, alpha: plainBackgroundAlpha)
|
||||||
}
|
}
|
||||||
|
|
||||||
var backgroundFrame = CGRect(origin: CGPoint(), size: CGSize(width: params.constrainedSize.width, height: height))
|
var backgroundFrame = CGRect(origin: CGPoint(), size: CGSize(width: params.constrainedSize.width, height: height))
|
||||||
|
|
@ -269,12 +284,12 @@ public final class SearchBarPlaceholderContentView: UIView {
|
||||||
backgroundFrame.size.width -= 44.0 + 8.0
|
backgroundFrame.size.width -= 44.0 + 8.0
|
||||||
}
|
}
|
||||||
|
|
||||||
if let backgroundNode = self.backgroundNode, backgroundNode.frame != backgroundFrame {
|
if self.plainBackgroundView.frame != backgroundFrame {
|
||||||
if !transition.isAnimated {
|
if !transition.isAnimated {
|
||||||
backgroundNode.layer.removeAnimation(forKey: "position")
|
self.plainBackgroundView.layer.removeAnimation(forKey: "position")
|
||||||
backgroundNode.layer.removeAnimation(forKey: "bounds")
|
self.plainBackgroundView.layer.removeAnimation(forKey: "bounds")
|
||||||
}
|
}
|
||||||
transition.updateFrame(node: backgroundNode, frame: CGRect(origin: CGPoint(), size: CGSize(width: params.constrainedSize.width, height: height)))
|
transition.updateFrame(view: self.plainBackgroundView, frame: CGRect(origin: CGPoint(), size: CGSize(width: params.constrainedSize.width, height: height)))
|
||||||
}
|
}
|
||||||
|
|
||||||
if let glassBackgroundView = self.glassBackgroundView {
|
if let glassBackgroundView = self.glassBackgroundView {
|
||||||
|
|
@ -284,6 +299,9 @@ public final class SearchBarPlaceholderContentView: UIView {
|
||||||
if backgroundFrame.height < 16.0 {
|
if backgroundFrame.height < 16.0 {
|
||||||
backgroundAlpha = max(0.0, min(1.0, backgroundFrame.height / 16.0))
|
backgroundAlpha = max(0.0, min(1.0, backgroundFrame.height / 16.0))
|
||||||
}
|
}
|
||||||
|
if !params.isActive {
|
||||||
|
backgroundAlpha = 0.0
|
||||||
|
}
|
||||||
ComponentTransition(transition).setAlpha(view: glassBackgroundView, alpha: backgroundAlpha)
|
ComponentTransition(transition).setAlpha(view: glassBackgroundView, alpha: backgroundAlpha)
|
||||||
let isDark = params.backgroundColor.hsb.b < 0.5
|
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))
|
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))
|
||||||
|
|
@ -372,10 +390,12 @@ public final class SearchBarPlaceholderContentView: UIView {
|
||||||
|
|
||||||
public func updatePlaceholderVisibility(isVisible: Bool) {
|
public func updatePlaceholderVisibility(isVisible: Bool) {
|
||||||
self.labelNode.isHidden = !isVisible
|
self.labelNode.isHidden = !isVisible
|
||||||
|
self.plainLabelNode.isHidden = !isVisible
|
||||||
}
|
}
|
||||||
|
|
||||||
public func updateSearchIconVisibility(isVisible: Bool) {
|
public func updateSearchIconVisibility(isVisible: Bool) {
|
||||||
self.iconNode.isHidden = !isVisible
|
self.iconNode.isHidden = !isVisible
|
||||||
|
self.plainIconNode.isHidden = !isVisible
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -408,12 +428,10 @@ public class SearchBarPlaceholderNode: ASDisplayNode {
|
||||||
private let contentView: SearchBarPlaceholderContentView
|
private let contentView: SearchBarPlaceholderContentView
|
||||||
|
|
||||||
public var backgroundView: UIView {
|
public var backgroundView: UIView {
|
||||||
if let backgroundNode = self.contentView.backgroundNode {
|
if let glassBackgroundView = self.contentView.glassBackgroundView {
|
||||||
return backgroundNode.view
|
|
||||||
} else if let glassBackgroundView = self.contentView.glassBackgroundView {
|
|
||||||
return glassBackgroundView
|
return glassBackgroundView
|
||||||
} else {
|
} else {
|
||||||
preconditionFailure()
|
return self.contentView.plainBackgroundView
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -57,7 +57,7 @@ public final class SearchDisplayController {
|
||||||
self.searchBarIsExternal = searchBarIsExternal
|
self.searchBarIsExternal = searchBarIsExternal
|
||||||
|
|
||||||
if !searchBarIsExternal {
|
if !searchBarIsExternal {
|
||||||
self.searchBar = SearchBarNode(theme: SearchBarNodeTheme(theme: presentationData.theme, hasBackground: hasBackground, hasSeparator: hasSeparator, inline: inline), strings: presentationData.strings, fieldStyle: fieldStyle, forceSeparator: hasSeparator, displayBackground: hasBackground)
|
self.searchBar = SearchBarNode(theme: SearchBarNodeTheme(theme: presentationData.theme, hasBackground: hasBackground, hasSeparator: hasSeparator, inline: inline), presentationTheme: presentationData.theme, strings: presentationData.strings, fieldStyle: fieldStyle, forceSeparator: hasSeparator, displayBackground: hasBackground)
|
||||||
}
|
}
|
||||||
self.backgroundNode = BackgroundNode()
|
self.backgroundNode = BackgroundNode()
|
||||||
self.backgroundNode.allowsGroupOpacity = true
|
self.backgroundNode.allowsGroupOpacity = true
|
||||||
|
|
@ -143,7 +143,7 @@ public final class SearchDisplayController {
|
||||||
|
|
||||||
public func updatePresentationData(_ presentationData: PresentationData) {
|
public func updatePresentationData(_ presentationData: PresentationData) {
|
||||||
if !self.searchBarIsExternal {
|
if !self.searchBarIsExternal {
|
||||||
self.searchBar?.updateThemeAndStrings(theme: SearchBarNodeTheme(theme: presentationData.theme, hasSeparator: self.hasSeparator, inline: self.inline), strings: presentationData.strings)
|
self.searchBar?.updateThemeAndStrings(theme: SearchBarNodeTheme(theme: presentationData.theme, hasSeparator: self.hasSeparator, inline: self.inline), presentationTheme: presentationData.theme, strings: presentationData.strings)
|
||||||
}
|
}
|
||||||
self.contentNode.updatePresentationData(presentationData)
|
self.contentNode.updatePresentationData(presentationData)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -988,7 +988,7 @@ extension StoreMessage {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (flags & (1 << 17)) != 0 {
|
if (flags & (1 << 19)) != 0 {
|
||||||
attributes.append(ContentRequiresValidationMessageAttribute())
|
attributes.append(ContentRequiresValidationMessageAttribute())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1174,7 +1174,7 @@ extension StoreMessage {
|
||||||
threadId = 1
|
threadId = 1
|
||||||
}
|
}
|
||||||
|
|
||||||
if (flags & (1 << 17)) != 0 {
|
if (flags & (1 << 19)) != 0 {
|
||||||
attributes.append(ContentRequiresValidationMessageAttribute())
|
attributes.append(ContentRequiresValidationMessageAttribute())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -62,7 +62,8 @@ public struct TelegramChatAdminRightsFlags: OptionSet, Hashable {
|
||||||
.canPostStories,
|
.canPostStories,
|
||||||
.canEditStories,
|
.canEditStories,
|
||||||
.canDeleteStories,
|
.canDeleteStories,
|
||||||
.canManageDirect
|
.canManageDirect,
|
||||||
|
.canBanUsers
|
||||||
]
|
]
|
||||||
|
|
||||||
public static func peerSpecific(peer: EnginePeer) -> TelegramChatAdminRightsFlags {
|
public static func peerSpecific(peer: EnginePeer) -> TelegramChatAdminRightsFlags {
|
||||||
|
|
|
||||||
|
|
@ -504,7 +504,7 @@ public func makeDefaultDarkPresentationTheme(extendingThemeReference: Presentati
|
||||||
pinnedBadgeColor: UIColor(rgb: 0x767677),
|
pinnedBadgeColor: UIColor(rgb: 0x767677),
|
||||||
pinnedSearchBarColor: UIColor(rgb: 0x272728),
|
pinnedSearchBarColor: UIColor(rgb: 0x272728),
|
||||||
regularSearchBarColor: UIColor(rgb: 0x272728),
|
regularSearchBarColor: UIColor(rgb: 0x272728),
|
||||||
sectionHeaderFillColor: UIColor(rgb: 0x1c1c1d),
|
sectionHeaderFillColor: .black,
|
||||||
sectionHeaderTextColor: UIColor(rgb: 0xffffff),
|
sectionHeaderTextColor: UIColor(rgb: 0xffffff),
|
||||||
verifiedIconFillColor: UIColor(rgb: 0xffffff),
|
verifiedIconFillColor: UIColor(rgb: 0xffffff),
|
||||||
verifiedIconForegroundColor: UIColor(rgb: 0x000000),
|
verifiedIconForegroundColor: UIColor(rgb: 0x000000),
|
||||||
|
|
|
||||||
|
|
@ -714,7 +714,7 @@ public func makeDefaultDarkTintedPresentationTheme(extendingThemeReference: Pres
|
||||||
pinnedBadgeColor: mainSecondaryTextColor.withAlphaComponent(0.5),
|
pinnedBadgeColor: mainSecondaryTextColor.withAlphaComponent(0.5),
|
||||||
pinnedSearchBarColor: accentColor.withMultiplied(hue: 1.029, saturation: 0.609, brightness: 0.12),
|
pinnedSearchBarColor: accentColor.withMultiplied(hue: 1.029, saturation: 0.609, brightness: 0.12),
|
||||||
regularSearchBarColor: accentColor.withMultiplied(hue: 1.029, saturation: 0.609, brightness: 0.12),
|
regularSearchBarColor: accentColor.withMultiplied(hue: 1.029, saturation: 0.609, brightness: 0.12),
|
||||||
sectionHeaderFillColor: mainBackgroundColor,
|
sectionHeaderFillColor: .black,
|
||||||
sectionHeaderTextColor: mainSecondaryTextColor.withAlphaComponent(0.5),
|
sectionHeaderTextColor: mainSecondaryTextColor.withAlphaComponent(0.5),
|
||||||
verifiedIconFillColor: accentColor,
|
verifiedIconFillColor: accentColor,
|
||||||
verifiedIconForegroundColor: .white,
|
verifiedIconForegroundColor: .white,
|
||||||
|
|
|
||||||
|
|
@ -565,8 +565,8 @@ public func makeDefaultDayPresentationTheme(extendingThemeReference: Presentatio
|
||||||
pinnedBadgeColor: UIColor(rgb: 0xb6b6bb),
|
pinnedBadgeColor: UIColor(rgb: 0xb6b6bb),
|
||||||
pinnedSearchBarColor: UIColor(rgb: 0xe5e5e5),
|
pinnedSearchBarColor: UIColor(rgb: 0xe5e5e5),
|
||||||
regularSearchBarColor: UIColor(rgb: 0xe9e9e9),
|
regularSearchBarColor: UIColor(rgb: 0xe9e9e9),
|
||||||
sectionHeaderFillColor: UIColor(rgb: 0xf7f7f7),
|
sectionHeaderFillColor: .white,
|
||||||
sectionHeaderTextColor: UIColor(rgb: 0x8e8e93),
|
sectionHeaderTextColor: .black,
|
||||||
verifiedIconFillColor: defaultDayAccentColor,
|
verifiedIconFillColor: defaultDayAccentColor,
|
||||||
verifiedIconForegroundColor: UIColor(rgb: 0xffffff),
|
verifiedIconForegroundColor: UIColor(rgb: 0xffffff),
|
||||||
secretIconColor: UIColor(rgb: 0x00b12c),
|
secretIconColor: UIColor(rgb: 0x00b12c),
|
||||||
|
|
|
||||||
|
|
@ -25,7 +25,7 @@ final class ChatRecentActionsSearchNavigationContentNode: NavigationBarContentNo
|
||||||
|
|
||||||
self.cancel = cancel
|
self.cancel = cancel
|
||||||
|
|
||||||
self.searchBar = SearchBarNode(theme: SearchBarNodeTheme(theme: theme, hasSeparator: false), strings: strings, fieldStyle: .modern, displayBackground: false)
|
self.searchBar = SearchBarNode(theme: SearchBarNodeTheme(theme: theme, hasSeparator: false), presentationTheme: theme, strings: strings, fieldStyle: .modern, displayBackground: false)
|
||||||
let placeholderText = strings.Common_Search
|
let placeholderText = strings.Common_Search
|
||||||
self.searchBar.placeholderString = NSAttributedString(string: placeholderText, font: searchBarFont, textColor: theme.rootController.navigationSearchBar.inputPlaceholderTextColor)
|
self.searchBar.placeholderString = NSAttributedString(string: placeholderText, font: searchBarFont, textColor: theme.rootController.navigationSearchBar.inputPlaceholderTextColor)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -64,6 +64,7 @@ public final class ChatSearchNavigationContentNode: NavigationBarContentNode {
|
||||||
accent: theme.chat.inputPanel.panelControlAccentColor,
|
accent: theme.chat.inputPanel.panelControlAccentColor,
|
||||||
keyboard: theme.rootController.keyboardColor
|
keyboard: theme.rootController.keyboardColor
|
||||||
),
|
),
|
||||||
|
presentationTheme: theme,
|
||||||
strings: strings,
|
strings: strings,
|
||||||
fieldStyle: .inlineNavigation,
|
fieldStyle: .inlineNavigation,
|
||||||
forceSeparator: false,
|
forceSeparator: false,
|
||||||
|
|
@ -246,6 +247,7 @@ public final class ChatSearchNavigationContentNode: NavigationBarContentNode {
|
||||||
accent: presentationInterfaceState.theme.chat.inputPanel.panelControlAccentColor,
|
accent: presentationInterfaceState.theme.chat.inputPanel.panelControlAccentColor,
|
||||||
keyboard: presentationInterfaceState.theme.rootController.keyboardColor
|
keyboard: presentationInterfaceState.theme.rootController.keyboardColor
|
||||||
),
|
),
|
||||||
|
presentationTheme: presentationInterfaceState.theme,
|
||||||
strings: presentationInterfaceState.strings
|
strings: presentationInterfaceState.strings
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -359,6 +359,9 @@ public final class ChatListNavigationBar: Component {
|
||||||
let searchOffsetFraction = clippedSearchOffset / searchOffsetDistance
|
let searchOffsetFraction = clippedSearchOffset / searchOffsetDistance
|
||||||
searchContentNode.expansionProgress = 1.0 - searchOffsetFraction
|
searchContentNode.expansionProgress = 1.0 - searchOffsetFraction
|
||||||
embeddedSearchBarExpansionHeight = 60.0 - floorToScreenPixels((1.0 - searchOffsetFraction) * searchSize.height)
|
embeddedSearchBarExpansionHeight = 60.0 - floorToScreenPixels((1.0 - searchOffsetFraction) * searchSize.height)
|
||||||
|
if searchOffsetFraction > 0.0 {
|
||||||
|
searchFrame.origin.y -= (60.0 - 44.0) * 0.5 * searchOffsetFraction
|
||||||
|
}
|
||||||
|
|
||||||
searchFrameValue = searchFrame
|
searchFrameValue = searchFrame
|
||||||
transition.setFrameWithAdditivePosition(view: searchContentNode.view, frame: searchFrame)
|
transition.setFrameWithAdditivePosition(view: searchContentNode.view, frame: searchFrame)
|
||||||
|
|
@ -479,7 +482,7 @@ public final class ChatListNavigationBar: Component {
|
||||||
if component.statusBarHeight < 1.0 {
|
if component.statusBarHeight < 1.0 {
|
||||||
headerContentY = 0.0
|
headerContentY = 0.0
|
||||||
} else {
|
} else {
|
||||||
headerContentY = component.statusBarHeight + 5.0
|
headerContentY = component.statusBarHeight + 10.0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let headerContentFrame = CGRect(origin: CGPoint(x: 0.0, y: headerContentY), size: headerContentSize)
|
let headerContentFrame = CGRect(origin: CGPoint(x: 0.0, y: headerContentY), size: headerContentSize)
|
||||||
|
|
@ -683,7 +686,7 @@ public final class ChatListNavigationBar: Component {
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
contentHeight += 44.0
|
contentHeight += 44.0
|
||||||
contentHeight += 8.0
|
contentHeight += 7.0
|
||||||
|
|
||||||
if component.search != nil {
|
if component.search != nil {
|
||||||
contentHeight += navigationBarSearchContentHeight
|
contentHeight += navigationBarSearchContentHeight
|
||||||
|
|
@ -696,8 +699,6 @@ public final class ChatListNavigationBar: Component {
|
||||||
transition.setFrame(view: disappearingHeaderPanelsView, frame: headerPanelsFrame)
|
transition.setFrame(view: disappearingHeaderPanelsView, frame: headerPanelsFrame)
|
||||||
}
|
}
|
||||||
if let headerPanels = component.headerPanels {
|
if let headerPanels = component.headerPanels {
|
||||||
headersContentHeight += 4.0
|
|
||||||
|
|
||||||
let headerPanelsView: ComponentView<Empty>
|
let headerPanelsView: ComponentView<Empty>
|
||||||
var headerPanelsTransition = transition
|
var headerPanelsTransition = transition
|
||||||
if let current = self.headerPanelsView {
|
if let current = self.headerPanelsView {
|
||||||
|
|
|
||||||
|
|
@ -116,7 +116,7 @@ public final class NavigationButtonComponent: Component {
|
||||||
|
|
||||||
switch component.content {
|
switch component.content {
|
||||||
case let .text(title, isBold):
|
case let .text(title, isBold):
|
||||||
textString = NSAttributedString(string: title, font: isBold ? Font.bold(17.0) : Font.regular(17.0), textColor: theme.chat.inputPanel.panelControlColor)
|
textString = NSAttributedString(string: title, font: isBold ? Font.bold(17.0) : Font.medium(17.0), textColor: theme.chat.inputPanel.panelControlColor)
|
||||||
case .more:
|
case .more:
|
||||||
isMore = true
|
isMore = true
|
||||||
case let .icon(imageNameValue):
|
case let .icon(imageNameValue):
|
||||||
|
|
@ -140,7 +140,7 @@ public final class NavigationButtonComponent: Component {
|
||||||
|
|
||||||
textView.attributedText = textString
|
textView.attributedText = textString
|
||||||
let textSize = textView.updateLayout(availableSize)
|
let textSize = textView.updateLayout(availableSize)
|
||||||
let textInset: CGFloat = 10.0
|
let textInset: CGFloat = 12.0
|
||||||
size.width = max(44.0, textSize.width + textInset * 2.0)
|
size.width = max(44.0, textSize.width + textInset * 2.0)
|
||||||
|
|
||||||
textView.frame = CGRect(origin: CGPoint(x: floor((size.width - textSize.width) / 2.0), y: floor((availableSize.height - textSize.height) / 2.0)), size: textSize)
|
textView.frame = CGRect(origin: CGPoint(x: floor((size.width - textSize.width) / 2.0), y: floor((availableSize.height - textSize.height) / 2.0)), size: textSize)
|
||||||
|
|
|
||||||
|
|
@ -1010,13 +1010,7 @@ public final class ChatTitleComponent: Component {
|
||||||
let containerSize = CGSize(width: contentSize.width + containerSideInset * 2.0, height: 44.0)
|
let containerSize = CGSize(width: contentSize.width + containerSideInset * 2.0, height: 44.0)
|
||||||
let containerFrame = CGRect(origin: CGPoint(x: floorToScreenPixels((availableSize.width - containerSize.width) * 0.5), y: floorToScreenPixels((availableSize.height - containerSize.height) * 0.5)), size: containerSize)
|
let containerFrame = CGRect(origin: CGPoint(x: floorToScreenPixels((availableSize.width - containerSize.width) * 0.5), y: floorToScreenPixels((availableSize.height - containerSize.height) * 0.5)), size: containerSize)
|
||||||
|
|
||||||
var titleFrame = CGRect(origin: CGPoint(x: floor((containerFrame.width - titleSize.width) * 0.5), y: floor((containerFrame.height - contentSize.height) * 0.5)), size: titleSize)
|
let titleFrame = CGRect(origin: CGPoint(x: titleLeftIconsWidth + floor((containerFrame.width - titleSize.width - titleLeftIconsWidth - titleRightIconsWidth) * 0.5), y: floor((containerFrame.height - contentSize.height) * 0.5)), size: titleSize)
|
||||||
if titleFrame.origin.x + titleFrame.width + titleRightIconsWidth > containerFrame.width - containerSideInset {
|
|
||||||
titleFrame.origin.x = containerFrame.width - containerSideInset - titleFrame.width - titleRightIconsWidth
|
|
||||||
}
|
|
||||||
if titleFrame.origin.x - titleLeftIconsWidth < containerSideInset {
|
|
||||||
titleFrame.origin.x = containerSideInset + titleLeftIconsWidth
|
|
||||||
}
|
|
||||||
if let titleView = self.title.view {
|
if let titleView = self.title.view {
|
||||||
if titleView.superview == nil {
|
if titleView.superview == nil {
|
||||||
titleView.isUserInteractionEnabled = false
|
titleView.isUserInteractionEnabled = false
|
||||||
|
|
@ -1130,6 +1124,8 @@ public final class ChatTitleComponent: Component {
|
||||||
if let backgroundView = self.backgroundView {
|
if let backgroundView = self.backgroundView {
|
||||||
self.backgroundView = nil
|
self.backgroundView = nil
|
||||||
backgroundView.removeFromSuperview()
|
backgroundView.removeFromSuperview()
|
||||||
|
}
|
||||||
|
if self.contentContainer.superview !== self {
|
||||||
self.addSubview(self.contentContainer)
|
self.addSubview(self.contentContainer)
|
||||||
}
|
}
|
||||||
transition.setFrame(view: self.contentContainer, frame: containerFrame)
|
transition.setFrame(view: self.contentContainer, frame: containerFrame)
|
||||||
|
|
|
||||||
|
|
@ -77,33 +77,33 @@ public class EdgeEffectView: UIView {
|
||||||
}
|
}
|
||||||
|
|
||||||
if blur {
|
if blur {
|
||||||
let gradientMaskLayer = SimpleGradientLayer()
|
|
||||||
let baseGradientAlpha: CGFloat = 1.0
|
|
||||||
let numSteps = 8
|
|
||||||
let firstStep = 1
|
|
||||||
let firstLocation = 0.8
|
|
||||||
gradientMaskLayer.colors = (0 ..< numSteps).map { i in
|
|
||||||
if i < firstStep {
|
|
||||||
return UIColor(white: 1.0, alpha: 1.0).cgColor
|
|
||||||
} else {
|
|
||||||
let step: CGFloat = CGFloat(i - firstStep) / CGFloat(numSteps - firstStep - 1)
|
|
||||||
let value: CGFloat = 1.0 - bezierPoint(0.42, 0.0, 0.58, 1.0, step)
|
|
||||||
return UIColor(white: 1.0, alpha: baseGradientAlpha * value).cgColor
|
|
||||||
}
|
|
||||||
}
|
|
||||||
gradientMaskLayer.locations = (0 ..< numSteps).map { i -> NSNumber in
|
|
||||||
if i < firstStep {
|
|
||||||
return 0.0 as NSNumber
|
|
||||||
} else {
|
|
||||||
let step: CGFloat = CGFloat(i - firstStep) / CGFloat(numSteps - firstStep - 1)
|
|
||||||
return (firstLocation + (1.0 - firstLocation) * step) as NSNumber
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let blurView: VariableBlurView
|
let blurView: VariableBlurView
|
||||||
if let current = self.blurView {
|
if let current = self.blurView {
|
||||||
blurView = current
|
blurView = current
|
||||||
} else {
|
} else {
|
||||||
|
let gradientMaskLayer = SimpleGradientLayer()
|
||||||
|
let baseGradientAlpha: CGFloat = 1.0
|
||||||
|
let numSteps = 8
|
||||||
|
let firstStep = 1
|
||||||
|
let firstLocation = 0.8
|
||||||
|
gradientMaskLayer.colors = (0 ..< numSteps).map { i in
|
||||||
|
if i < firstStep {
|
||||||
|
return UIColor(white: 1.0, alpha: 1.0).cgColor
|
||||||
|
} else {
|
||||||
|
let step: CGFloat = CGFloat(i - firstStep) / CGFloat(numSteps - firstStep - 1)
|
||||||
|
let value: CGFloat = 1.0 - bezierPoint(0.42, 0.0, 0.58, 1.0, step)
|
||||||
|
return UIColor(white: 1.0, alpha: baseGradientAlpha * value).cgColor
|
||||||
|
}
|
||||||
|
}
|
||||||
|
gradientMaskLayer.locations = (0 ..< numSteps).map { i -> NSNumber in
|
||||||
|
if i < firstStep {
|
||||||
|
return 0.0 as NSNumber
|
||||||
|
} else {
|
||||||
|
let step: CGFloat = CGFloat(i - firstStep) / CGFloat(numSteps - firstStep - 1)
|
||||||
|
return (firstLocation + (1.0 - firstLocation) * step) as NSNumber
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
blurView = VariableBlurView(gradientMask: self.contentMaskView.image ?? UIImage(), maxBlurRadius: 8.0)
|
blurView = VariableBlurView(gradientMask: self.contentMaskView.image ?? UIImage(), maxBlurRadius: 8.0)
|
||||||
blurView.layer.mask = gradientMaskLayer
|
blurView.layer.mask = gradientMaskLayer
|
||||||
self.insertSubview(blurView, at: 0)
|
self.insertSubview(blurView, at: 0)
|
||||||
|
|
|
||||||
|
|
@ -535,9 +535,12 @@ public class GlassBackgroundView: UIView {
|
||||||
if transition.animation.isImmediate {
|
if transition.animation.isImmediate {
|
||||||
nativeView.effect = glassEffect
|
nativeView.effect = glassEffect
|
||||||
} else {
|
} else {
|
||||||
UIView.animate(withDuration: 0.2, animations: {
|
if let glassEffect, let currentEffect = nativeView.effect as? UIGlassEffect, currentEffect.tintColor == glassEffect.tintColor, currentEffect.isInteractive == glassEffect.isInteractive {
|
||||||
nativeView.effect = glassEffect
|
} else {
|
||||||
})
|
UIView.animate(withDuration: 0.15, animations: {
|
||||||
|
nativeView.effect = glassEffect
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -81,6 +81,7 @@ final class GroupStickerSearchNavigationContentNode: NavigationBarContentNode, I
|
||||||
accent: theme.chat.inputPanel.panelControlAccentColor,
|
accent: theme.chat.inputPanel.panelControlAccentColor,
|
||||||
keyboard: theme.rootController.keyboardColor
|
keyboard: theme.rootController.keyboardColor
|
||||||
),
|
),
|
||||||
|
presentationTheme: theme,
|
||||||
strings: strings,
|
strings: strings,
|
||||||
fieldStyle: .inlineNavigation,
|
fieldStyle: .inlineNavigation,
|
||||||
forceSeparator: false,
|
forceSeparator: false,
|
||||||
|
|
@ -127,7 +128,7 @@ final class GroupStickerSearchNavigationContentNode: NavigationBarContentNode, I
|
||||||
|
|
||||||
func updateTheme(_ theme: PresentationTheme) {
|
func updateTheme(_ theme: PresentationTheme) {
|
||||||
self.theme = theme
|
self.theme = theme
|
||||||
self.searchBar.updateThemeAndStrings(theme: SearchBarNodeTheme(theme: self.theme), strings: self.strings)
|
self.searchBar.updateThemeAndStrings(theme: SearchBarNodeTheme(theme: self.theme), presentationTheme: self.theme, strings: self.strings)
|
||||||
self.updatePlaceholder()
|
self.updatePlaceholder()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -460,6 +460,7 @@ final class MiniAppListScreenComponent: Component {
|
||||||
let searchBarTheme = SearchBarNodeTheme(theme: environment.theme, hasSeparator: false)
|
let searchBarTheme = SearchBarNodeTheme(theme: environment.theme, hasSeparator: false)
|
||||||
searchBarNode = SearchBarNode(
|
searchBarNode = SearchBarNode(
|
||||||
theme: searchBarTheme,
|
theme: searchBarTheme,
|
||||||
|
presentationTheme: environment.theme,
|
||||||
strings: environment.strings,
|
strings: environment.strings,
|
||||||
fieldStyle: .modern,
|
fieldStyle: .modern,
|
||||||
displayBackground: false
|
displayBackground: false
|
||||||
|
|
|
||||||
|
|
@ -151,7 +151,7 @@ private final class ItemComponent: Component {
|
||||||
if case let .item(item) = component.content, case .done = item.style {
|
if case let .item(item) = component.content, case .done = item.style {
|
||||||
titleFont = Font.bold(17.0)
|
titleFont = Font.bold(17.0)
|
||||||
} else {
|
} else {
|
||||||
titleFont = Font.regular(17.0)
|
titleFont = Font.medium(17.0)
|
||||||
}
|
}
|
||||||
|
|
||||||
let title: ComponentView<Empty>
|
let title: ComponentView<Empty>
|
||||||
|
|
@ -204,7 +204,7 @@ private final class NavigationButtonItemNode: ImmediateTextNode {
|
||||||
private let isGlass: Bool
|
private let isGlass: Bool
|
||||||
|
|
||||||
private func fontForCurrentState() -> UIFont {
|
private func fontForCurrentState() -> UIFont {
|
||||||
return self.bold ? UIFont.boldSystemFont(ofSize: 17.0) : UIFont.systemFont(ofSize: 17.0)
|
return self.bold ? Font.semibold(17.0) : Font.medium(17.0)
|
||||||
}
|
}
|
||||||
|
|
||||||
private func attributesForCurrentState() -> [NSAttributedString.Key: AnyObject] {
|
private func attributesForCurrentState() -> [NSAttributedString.Key: AnyObject] {
|
||||||
|
|
@ -711,7 +711,7 @@ public final class NavigationButtonNodeImpl: ContextControllerSourceNode, Naviga
|
||||||
var nodeInset: CGFloat = 0.0
|
var nodeInset: CGFloat = 0.0
|
||||||
if self.isGlass {
|
if self.isGlass {
|
||||||
if node.image == nil && node.node == nil {
|
if node.image == nil && node.node == nil {
|
||||||
nodeInset += 10.0
|
nodeInset += 12.0
|
||||||
}
|
}
|
||||||
if nodeSize.width + nodeInset * 2.0 < 44.0 {
|
if nodeSize.width + nodeInset * 2.0 < 44.0 {
|
||||||
nodeInset = floorToScreenPixels((44.0 - nodeSize.width) * 0.5)
|
nodeInset = floorToScreenPixels((44.0 - nodeSize.width) * 0.5)
|
||||||
|
|
|
||||||
|
|
@ -168,6 +168,7 @@ swift_library(
|
||||||
"//submodules/TelegramUI/Components/MediaManager/PeerMessagesMediaPlaylist",
|
"//submodules/TelegramUI/Components/MediaManager/PeerMessagesMediaPlaylist",
|
||||||
"//submodules/TelegramUI/Components/TextFieldComponent",
|
"//submodules/TelegramUI/Components/TextFieldComponent",
|
||||||
"//submodules/TelegramUI/Components/EdgeEffect",
|
"//submodules/TelegramUI/Components/EdgeEffect",
|
||||||
|
"//submodules/TelegramUI/Components/GlassBackgroundComponent",
|
||||||
],
|
],
|
||||||
visibility = [
|
visibility = [
|
||||||
"//visibility:public",
|
"//visibility:public",
|
||||||
|
|
|
||||||
|
|
@ -13,6 +13,23 @@ private enum MoreIconNodeState: Equatable {
|
||||||
case moreToSearch(Float)
|
case moreToSearch(Float)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private let glassBackArrowImage: UIImage? = {
|
||||||
|
let imageSize = CGSize(width: 44.0, height: 44.0)
|
||||||
|
let topRightPoint = CGPoint(x: 24.6, y: 14.0)
|
||||||
|
let centerPoint = CGPoint(x: 17.0, y: imageSize.height * 0.5)
|
||||||
|
return generateImage(imageSize, rotatedContext: { size, context in
|
||||||
|
context.clear(CGRect(origin: CGPoint(), size: size))
|
||||||
|
context.setStrokeColor(UIColor.white.cgColor)
|
||||||
|
context.setLineWidth(2.0)
|
||||||
|
context.setLineCap(.round)
|
||||||
|
context.setLineJoin(.round)
|
||||||
|
context.move(to: topRightPoint)
|
||||||
|
context.addLine(to: centerPoint)
|
||||||
|
context.addLine(to: CGPoint(x: topRightPoint.x, y: size.height - topRightPoint.y))
|
||||||
|
context.strokePath()
|
||||||
|
})?.withRenderingMode(.alwaysTemplate)
|
||||||
|
}()
|
||||||
|
|
||||||
private final class MoreIconNode: ManagedAnimationNode {
|
private final class MoreIconNode: ManagedAnimationNode {
|
||||||
private let duration: Double = 0.21
|
private let duration: Double = 0.21
|
||||||
private var iconState: MoreIconNodeState = .more
|
private var iconState: MoreIconNodeState = .more
|
||||||
|
|
@ -124,14 +141,11 @@ final class PeerInfoHeaderNavigationButton: HighlightableButtonNode {
|
||||||
let contextSourceNode: ContextReferenceContentNode
|
let contextSourceNode: ContextReferenceContentNode
|
||||||
private let textNode: ImmediateTextNode
|
private let textNode: ImmediateTextNode
|
||||||
private let iconNode: ASImageNode
|
private let iconNode: ASImageNode
|
||||||
private let backIconLayer: SimpleShapeLayer
|
|
||||||
private var animationNode: MoreIconNode?
|
private var animationNode: MoreIconNode?
|
||||||
private let backgroundNode: NavigationBackgroundNode
|
|
||||||
|
|
||||||
private var key: PeerInfoHeaderNavigationButtonKey?
|
private var key: PeerInfoHeaderNavigationButtonKey?
|
||||||
|
|
||||||
private var contentsColor: UIColor = .white
|
private var contentsColor: UIColor = .white
|
||||||
private var canBeExpanded: Bool = false
|
|
||||||
|
|
||||||
var action: ((ASDisplayNode, ContextGesture?) -> Void)?
|
var action: ((ASDisplayNode, ContextGesture?) -> Void)?
|
||||||
|
|
||||||
|
|
@ -146,27 +160,14 @@ final class PeerInfoHeaderNavigationButton: HighlightableButtonNode {
|
||||||
self.iconNode.displaysAsynchronously = false
|
self.iconNode.displaysAsynchronously = false
|
||||||
self.iconNode.displayWithoutProcessing = true
|
self.iconNode.displayWithoutProcessing = true
|
||||||
|
|
||||||
self.backIconLayer = SimpleShapeLayer()
|
super.init(pointerStyle: .insetRectangle(0.0, 0.0))
|
||||||
self.backIconLayer.lineWidth = 3.0
|
|
||||||
self.backIconLayer.lineCap = .round
|
|
||||||
self.backIconLayer.lineJoin = .round
|
|
||||||
self.backIconLayer.strokeColor = UIColor.white.cgColor
|
|
||||||
self.backIconLayer.fillColor = nil
|
|
||||||
self.backIconLayer.isHidden = true
|
|
||||||
self.backIconLayer.path = try? convertSvgPath("M10.5,2 L1.5,11 L10.5,20 ")
|
|
||||||
|
|
||||||
self.backgroundNode = NavigationBackgroundNode(color: .clear, enableBlur: true)
|
|
||||||
|
|
||||||
super.init(pointerStyle: .insetRectangle(-8.0, 2.0))
|
|
||||||
|
|
||||||
self.isAccessibilityElement = true
|
self.isAccessibilityElement = true
|
||||||
self.accessibilityTraits = .button
|
self.accessibilityTraits = .button
|
||||||
|
|
||||||
self.containerNode.addSubnode(self.contextSourceNode)
|
self.containerNode.addSubnode(self.contextSourceNode)
|
||||||
self.contextSourceNode.addSubnode(self.backgroundNode)
|
|
||||||
self.contextSourceNode.addSubnode(self.textNode)
|
self.contextSourceNode.addSubnode(self.textNode)
|
||||||
self.contextSourceNode.addSubnode(self.iconNode)
|
self.contextSourceNode.addSubnode(self.iconNode)
|
||||||
self.contextSourceNode.layer.addSublayer(self.backIconLayer)
|
|
||||||
|
|
||||||
self.addSubnode(self.containerNode)
|
self.addSubnode(self.containerNode)
|
||||||
|
|
||||||
|
|
@ -178,10 +179,6 @@ final class PeerInfoHeaderNavigationButton: HighlightableButtonNode {
|
||||||
}
|
}
|
||||||
|
|
||||||
self.addTarget(self, action: #selector(self.pressed), forControlEvents: .touchUpInside)
|
self.addTarget(self, action: #selector(self.pressed), forControlEvents: .touchUpInside)
|
||||||
|
|
||||||
if isReduceTransparencyEnabled() {
|
|
||||||
self.backgroundNode.isHidden = true
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@objc private func pressed() {
|
@objc private func pressed() {
|
||||||
|
|
@ -190,11 +187,7 @@ final class PeerInfoHeaderNavigationButton: HighlightableButtonNode {
|
||||||
}
|
}
|
||||||
|
|
||||||
override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
|
override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
|
||||||
var boundingRect = self.bounds
|
let boundingRect = self.bounds
|
||||||
if self.textNode.alpha != 0.0 {
|
|
||||||
boundingRect = boundingRect.union(self.textNode.frame)
|
|
||||||
}
|
|
||||||
boundingRect = boundingRect.insetBy(dx: -8.0, dy: -4.0)
|
|
||||||
if boundingRect.contains(point) {
|
if boundingRect.contains(point) {
|
||||||
return super.hitTest(self.bounds.center, with: event)
|
return super.hitTest(self.bounds.center, with: event)
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -202,31 +195,11 @@ final class PeerInfoHeaderNavigationButton: HighlightableButtonNode {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func updateContentsColor(backgroundColor: UIColor, contentsColor: UIColor, canBeExpanded: Bool, transition: ContainedViewLayoutTransition) {
|
func updateContentsColor(contentsColor: UIColor, transition: ContainedViewLayoutTransition) {
|
||||||
self.contentsColor = contentsColor
|
self.contentsColor = contentsColor
|
||||||
self.canBeExpanded = canBeExpanded
|
|
||||||
|
|
||||||
self.backgroundNode.updateColor(color: backgroundColor, transition: transition)
|
|
||||||
|
|
||||||
transition.updateTintColor(layer: self.textNode.layer, color: self.contentsColor)
|
transition.updateTintColor(layer: self.textNode.layer, color: self.contentsColor)
|
||||||
transition.updateTintColor(view: self.iconNode.view, color: self.contentsColor)
|
transition.updateTintColor(view: self.iconNode.view, color: self.contentsColor)
|
||||||
transition.updateStrokeColor(layer: self.backIconLayer, strokeColor: self.contentsColor)
|
|
||||||
|
|
||||||
switch self.key {
|
|
||||||
case .back:
|
|
||||||
transition.updateAlpha(layer: self.textNode.layer, alpha: canBeExpanded ? 1.0 : 0.0)
|
|
||||||
transition.updateTransformScale(node: self.textNode, scale: canBeExpanded ? 1.0 : 0.001)
|
|
||||||
|
|
||||||
var iconTransform = CATransform3DIdentity
|
|
||||||
iconTransform = CATransform3DScale(iconTransform, canBeExpanded ? 1.0 : 0.8, canBeExpanded ? 1.0 : 0.8, 1.0)
|
|
||||||
iconTransform = CATransform3DTranslate(iconTransform, canBeExpanded ? -7.0 : 0.0, 0.0, 0.0)
|
|
||||||
transition.updateTransform(node: self.iconNode, transform: CATransform3DGetAffineTransform(iconTransform))
|
|
||||||
|
|
||||||
transition.updateTransform(layer: self.backIconLayer, transform: CATransform3DGetAffineTransform(iconTransform))
|
|
||||||
transition.updateLineWidth(layer: self.backIconLayer, lineWidth: canBeExpanded ? 3.0 : 2.075)
|
|
||||||
default:
|
|
||||||
break
|
|
||||||
}
|
|
||||||
|
|
||||||
if let animationNode = self.animationNode {
|
if let animationNode = self.animationNode {
|
||||||
transition.updateTintColor(layer: animationNode.imageNode.layer, color: self.contentsColor)
|
transition.updateTintColor(layer: animationNode.imageNode.layer, color: self.contentsColor)
|
||||||
|
|
@ -239,7 +212,7 @@ final class PeerInfoHeaderNavigationButton: HighlightableButtonNode {
|
||||||
var iconOffset = CGPoint()
|
var iconOffset = CGPoint()
|
||||||
switch key {
|
switch key {
|
||||||
case .back:
|
case .back:
|
||||||
iconOffset = CGPoint(x: -1.0, y: 0.0)
|
iconOffset = CGPoint(x: 0.0, y: 0.0)
|
||||||
default:
|
default:
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
@ -258,9 +231,9 @@ final class PeerInfoHeaderNavigationButton: HighlightableButtonNode {
|
||||||
var animationState: MoreIconNodeState = .more
|
var animationState: MoreIconNodeState = .more
|
||||||
switch key {
|
switch key {
|
||||||
case .back:
|
case .back:
|
||||||
text = presentationData.strings.Common_Back
|
text = ""
|
||||||
accessibilityText = presentationData.strings.Common_Back
|
accessibilityText = presentationData.strings.Common_Back
|
||||||
icon = navigationBarBackArrowImage(color: .white)
|
icon = glassBackArrowImage
|
||||||
case .edit:
|
case .edit:
|
||||||
text = presentationData.strings.Common_Edit
|
text = presentationData.strings.Common_Edit
|
||||||
accessibilityText = text
|
accessibilityText = text
|
||||||
|
|
@ -323,7 +296,7 @@ final class PeerInfoHeaderNavigationButton: HighlightableButtonNode {
|
||||||
self.accessibilityLabel = accessibilityText
|
self.accessibilityLabel = accessibilityText
|
||||||
self.containerNode.isGestureEnabled = isGestureEnabled
|
self.containerNode.isGestureEnabled = isGestureEnabled
|
||||||
|
|
||||||
let font: UIFont = isBold ? Font.semibold(17.0) : Font.regular(17.0)
|
let font: UIFont = isBold ? Font.semibold(17.0) : Font.medium(17.0)
|
||||||
|
|
||||||
self.textNode.attributedText = NSAttributedString(string: text, font: font, textColor: .white)
|
self.textNode.attributedText = NSAttributedString(string: text, font: font, textColor: .white)
|
||||||
transition.updateTintColor(layer: self.textNode.layer, color: self.contentsColor)
|
transition.updateTintColor(layer: self.textNode.layer, color: self.contentsColor)
|
||||||
|
|
@ -357,70 +330,39 @@ final class PeerInfoHeaderNavigationButton: HighlightableButtonNode {
|
||||||
textSize = self.textNode.bounds.size
|
textSize = self.textNode.bounds.size
|
||||||
}
|
}
|
||||||
|
|
||||||
let inset: CGFloat = 0.0
|
let textInset: CGFloat = 12.0
|
||||||
var textInset: CGFloat = 0.0
|
|
||||||
switch key {
|
|
||||||
case .back:
|
|
||||||
textInset += 11.0
|
|
||||||
default:
|
|
||||||
break
|
|
||||||
}
|
|
||||||
|
|
||||||
let resultSize: CGSize
|
let resultSize: CGSize
|
||||||
|
|
||||||
let textFrame = CGRect(origin: CGPoint(x: inset + textInset, y: floor((height - textSize.height) / 2.0)), size: textSize)
|
let textFrame = CGRect(origin: CGPoint(x: textInset, y: floor((height - textSize.height) / 2.0)), size: textSize)
|
||||||
self.textNode.position = textFrame.center
|
self.textNode.position = textFrame.center
|
||||||
self.textNode.bounds = CGRect(origin: CGPoint(), size: textFrame.size)
|
self.textNode.bounds = CGRect(origin: CGPoint(), size: textFrame.size)
|
||||||
|
|
||||||
if let animationNode = self.animationNode {
|
if let animationNode = self.animationNode {
|
||||||
let animationSize = CGSize(width: 30.0, height: 30.0)
|
let animationSize = CGSize(width: 30.0, height: 30.0)
|
||||||
|
|
||||||
animationNode.frame = CGRect(origin: CGPoint(x: inset, y: floor((height - animationSize.height) / 2.0)), size: animationSize).offsetBy(dx: iconOffset.x, dy: iconOffset.y)
|
animationNode.frame = CGRect(origin: CGPoint(x: floor((height - animationSize.width) * 0.5), y: floor((height - animationSize.height) / 2.0)), size: animationSize).offsetBy(dx: iconOffset.x, dy: iconOffset.y)
|
||||||
|
|
||||||
let size = CGSize(width: animationSize.width + inset * 2.0, height: height)
|
let size = CGSize(width: height, height: height)
|
||||||
self.containerNode.frame = CGRect(origin: CGPoint(), size: size)
|
self.containerNode.frame = CGRect(origin: CGPoint(), size: size)
|
||||||
self.contextSourceNode.frame = CGRect(origin: CGPoint(), size: size)
|
self.contextSourceNode.frame = CGRect(origin: CGPoint(), size: size)
|
||||||
resultSize = size
|
resultSize = size
|
||||||
} else if let image = self.iconNode.image {
|
} else if let image = self.iconNode.image {
|
||||||
let iconFrame = CGRect(origin: CGPoint(x: inset, y: floor((height - image.size.height) / 2.0)), size: image.size).offsetBy(dx: iconOffset.x, dy: iconOffset.y)
|
let iconFrame = CGRect(origin: CGPoint(x: floor((height - image.size.width) * 0.5), y: floor((height - image.size.height) / 2.0)), size: image.size).offsetBy(dx: iconOffset.x, dy: iconOffset.y)
|
||||||
self.iconNode.position = iconFrame.center
|
self.iconNode.position = iconFrame.center
|
||||||
self.iconNode.bounds = CGRect(origin: CGPoint(), size: iconFrame.size)
|
self.iconNode.bounds = CGRect(origin: CGPoint(), size: iconFrame.size)
|
||||||
|
|
||||||
if case .back = key {
|
let size = CGSize(width: height, height: height)
|
||||||
self.backIconLayer.position = iconFrame.center
|
|
||||||
self.backIconLayer.bounds = CGRect(origin: CGPoint(), size: iconFrame.size)
|
|
||||||
|
|
||||||
self.iconNode.isHidden = true
|
|
||||||
self.backIconLayer.isHidden = false
|
|
||||||
} else {
|
|
||||||
self.iconNode.isHidden = false
|
|
||||||
self.backIconLayer.isHidden = true
|
|
||||||
}
|
|
||||||
|
|
||||||
let size = CGSize(width: image.size.width + inset * 2.0, height: height)
|
|
||||||
self.containerNode.frame = CGRect(origin: CGPoint(), size: size)
|
self.containerNode.frame = CGRect(origin: CGPoint(), size: size)
|
||||||
self.contextSourceNode.frame = CGRect(origin: CGPoint(), size: size)
|
self.contextSourceNode.frame = CGRect(origin: CGPoint(), size: size)
|
||||||
resultSize = size
|
resultSize = size
|
||||||
} else {
|
} else {
|
||||||
let size = CGSize(width: textSize.width + inset * 2.0, height: height)
|
let size = CGSize(width: textSize.width + textInset * 2.0, height: height)
|
||||||
self.containerNode.frame = CGRect(origin: CGPoint(), size: size)
|
self.containerNode.frame = CGRect(origin: CGPoint(), size: size)
|
||||||
self.contextSourceNode.frame = CGRect(origin: CGPoint(), size: size)
|
self.contextSourceNode.frame = CGRect(origin: CGPoint(), size: size)
|
||||||
resultSize = size
|
resultSize = size
|
||||||
}
|
}
|
||||||
|
|
||||||
let diameter: CGFloat = 32.0
|
|
||||||
let backgroundWidth: CGFloat
|
|
||||||
if self.iconNode.image != nil || self.animationNode != nil {
|
|
||||||
backgroundWidth = diameter
|
|
||||||
} else {
|
|
||||||
backgroundWidth = max(diameter, resultSize.width + 12.0 * 2.0)
|
|
||||||
}
|
|
||||||
let backgroundFrame = CGRect(origin: CGPoint(x: floor((resultSize.width - backgroundWidth) * 0.5), y: floor((resultSize.height - diameter) * 0.5)), size: CGSize(width: backgroundWidth, height: diameter))
|
|
||||||
transition.updateFrame(node: self.backgroundNode, frame: backgroundFrame)
|
|
||||||
self.backgroundNode.update(size: backgroundFrame.size, cornerRadius: diameter * 0.5, transition: transition)
|
|
||||||
|
|
||||||
self.hitTestSlop = UIEdgeInsets(top: -2.0, left: -12.0, bottom: -2.0, right: -12.0)
|
|
||||||
|
|
||||||
return resultSize
|
return resultSize
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,9 @@ import AsyncDisplayKit
|
||||||
import ContextUI
|
import ContextUI
|
||||||
import TelegramPresentationData
|
import TelegramPresentationData
|
||||||
import Display
|
import Display
|
||||||
|
import ComponentFlow
|
||||||
|
import ComponentDisplayAdapters
|
||||||
|
import GlassBackgroundComponent
|
||||||
|
|
||||||
enum PeerInfoHeaderNavigationButtonKey {
|
enum PeerInfoHeaderNavigationButtonKey {
|
||||||
case back
|
case back
|
||||||
|
|
@ -24,101 +27,125 @@ enum PeerInfoHeaderNavigationButtonKey {
|
||||||
case postStory
|
case postStory
|
||||||
}
|
}
|
||||||
|
|
||||||
struct PeerInfoHeaderNavigationButtonSpec: Equatable {
|
struct PeerInfoHeaderNavigationButtonSpec: Hashable {
|
||||||
let key: PeerInfoHeaderNavigationButtonKey
|
let key: PeerInfoHeaderNavigationButtonKey
|
||||||
let isForExpandedView: Bool
|
let isForExpandedView: Bool
|
||||||
}
|
}
|
||||||
|
|
||||||
final class PeerInfoHeaderNavigationButtonContainerNode: SparseNode {
|
final class PeerInfoHeaderNavigationButtonContainerNode: SparseNode {
|
||||||
private var presentationData: PresentationData?
|
private var presentationData: PresentationData?
|
||||||
private(set) var leftButtonNodes: [PeerInfoHeaderNavigationButtonKey: PeerInfoHeaderNavigationButton] = [:]
|
|
||||||
private(set) var rightButtonNodes: [PeerInfoHeaderNavigationButtonKey: PeerInfoHeaderNavigationButton] = [:]
|
private let backgroundContainer: GlassBackgroundContainerView
|
||||||
|
private let leftButtonsBackground: GlassBackgroundView
|
||||||
|
private let rightButtonsBackground: GlassBackgroundView
|
||||||
|
private let leftButtonsContainer: UIView
|
||||||
|
private let rightButtonsContainer: UIView
|
||||||
|
|
||||||
|
private(set) var leftButtonNodes: [PeerInfoHeaderNavigationButtonSpec: PeerInfoHeaderNavigationButton] = [:]
|
||||||
|
private(set) var rightButtonNodes: [PeerInfoHeaderNavigationButtonSpec: PeerInfoHeaderNavigationButton] = [:]
|
||||||
|
|
||||||
private var currentLeftButtons: [PeerInfoHeaderNavigationButtonSpec] = []
|
private var currentLeftButtons: [PeerInfoHeaderNavigationButtonSpec] = []
|
||||||
private var currentRightButtons: [PeerInfoHeaderNavigationButtonSpec] = []
|
private var currentRightButtons: [PeerInfoHeaderNavigationButtonSpec] = []
|
||||||
|
|
||||||
private var backgroundContentColor: UIColor = .clear
|
private var backgroundContentColor: UIColor = .clear
|
||||||
|
private var isOverColoredContents: Bool = false
|
||||||
private var contentsColor: UIColor = .white
|
private var contentsColor: UIColor = .white
|
||||||
private var canBeExpanded: Bool = false
|
|
||||||
|
|
||||||
var performAction: ((PeerInfoHeaderNavigationButtonKey, ContextReferenceContentNode?, ContextGesture?) -> Void)?
|
var performAction: ((PeerInfoHeaderNavigationButtonKey, ContextReferenceContentNode?, ContextGesture?) -> Void)?
|
||||||
|
|
||||||
func updateContentsColor(backgroundContentColor: UIColor, contentsColor: UIColor, canBeExpanded: Bool, transition: ContainedViewLayoutTransition) {
|
override init() {
|
||||||
self.backgroundContentColor = backgroundContentColor
|
self.backgroundContainer = GlassBackgroundContainerView()
|
||||||
self.contentsColor = contentsColor
|
self.leftButtonsBackground = GlassBackgroundView()
|
||||||
self.canBeExpanded = canBeExpanded
|
self.rightButtonsBackground = GlassBackgroundView()
|
||||||
|
|
||||||
for (_, button) in self.leftButtonNodes {
|
self.leftButtonsContainer = UIView()
|
||||||
button.updateContentsColor(backgroundColor: self.backgroundContentColor, contentsColor: self.contentsColor, canBeExpanded: canBeExpanded, transition: transition)
|
self.leftButtonsContainer.clipsToBounds = true
|
||||||
transition.updateSublayerTransformOffset(layer: button.layer, offset: CGPoint(x: canBeExpanded ? -8.0 : 0.0, y: 0.0))
|
self.rightButtonsContainer = UIView()
|
||||||
|
self.rightButtonsContainer.clipsToBounds = true
|
||||||
|
|
||||||
|
super.init()
|
||||||
|
|
||||||
|
self.view.addSubview(self.backgroundContainer)
|
||||||
|
self.backgroundContainer.contentView.addSubview(self.leftButtonsBackground)
|
||||||
|
self.backgroundContainer.contentView.addSubview(self.rightButtonsBackground)
|
||||||
|
|
||||||
|
self.leftButtonsBackground.contentView.addSubview(self.leftButtonsContainer)
|
||||||
|
self.rightButtonsBackground.contentView.addSubview(self.rightButtonsContainer)
|
||||||
|
}
|
||||||
|
|
||||||
|
func updateContentsColor(backgroundContentColor: UIColor, contentsColor: UIColor, isOverColoredContents: Bool, transition: ContainedViewLayoutTransition) {
|
||||||
|
self.backgroundContentColor = backgroundContentColor
|
||||||
|
self.isOverColoredContents = isOverColoredContents
|
||||||
|
self.contentsColor = contentsColor
|
||||||
|
|
||||||
|
guard let presentationData = self.presentationData else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
let normalButtonContentsColor: UIColor = self.isOverColoredContents ? .white : presentationData.theme.chat.inputPanel.panelControlColor
|
||||||
|
let expandedButtonContentsColor: UIColor = presentationData.theme.chat.inputPanel.panelControlColor
|
||||||
|
|
||||||
|
for (spec, button) in self.leftButtonNodes {
|
||||||
|
button.updateContentsColor(contentsColor: spec.isForExpandedView ? expandedButtonContentsColor : normalButtonContentsColor, transition: transition)
|
||||||
}
|
}
|
||||||
|
|
||||||
var accumulatedRightButtonOffset: CGFloat = canBeExpanded ? 16.0 : 0.0
|
|
||||||
for spec in self.currentRightButtons.reversed() {
|
for spec in self.currentRightButtons.reversed() {
|
||||||
guard let button = self.rightButtonNodes[spec.key] else {
|
guard let button = self.rightButtonNodes[spec] else {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
button.updateContentsColor(backgroundColor: self.backgroundContentColor, contentsColor: self.contentsColor, canBeExpanded: canBeExpanded, transition: transition)
|
button.updateContentsColor(contentsColor: spec.isForExpandedView ? expandedButtonContentsColor : normalButtonContentsColor, transition: transition)
|
||||||
if !spec.isForExpandedView {
|
}
|
||||||
transition.updateSublayerTransformOffset(layer: button.layer, offset: CGPoint(x: accumulatedRightButtonOffset, y: 0.0))
|
for (spec, button) in self.rightButtonNodes {
|
||||||
if self.backgroundContentColor.alpha != 0.0 {
|
if !self.currentRightButtons.contains(where: { $0 == spec }) {
|
||||||
accumulatedRightButtonOffset -= 6.0
|
button.updateContentsColor(contentsColor: spec.isForExpandedView ? expandedButtonContentsColor : normalButtonContentsColor, transition: transition)
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for (key, button) in self.rightButtonNodes {
|
|
||||||
if !self.currentRightButtons.contains(where: { $0.key == key }) {
|
|
||||||
button.updateContentsColor(backgroundColor: self.backgroundContentColor, contentsColor: self.contentsColor, canBeExpanded: canBeExpanded, transition: transition)
|
|
||||||
transition.updateSublayerTransformOffset(layer: button.layer, offset: CGPoint(x: 0.0, y: 0.0))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
self.updateBackgroundColors(transition: ComponentTransition(transition))
|
||||||
}
|
}
|
||||||
|
|
||||||
func update(size: CGSize, presentationData: PresentationData, leftButtons: [PeerInfoHeaderNavigationButtonSpec], rightButtons: [PeerInfoHeaderNavigationButtonSpec], expandFraction: CGFloat, shouldAnimateIn: Bool, transition: ContainedViewLayoutTransition) {
|
func update(size: CGSize, presentationData: PresentationData, leftButtons: [PeerInfoHeaderNavigationButtonSpec], rightButtons: [PeerInfoHeaderNavigationButtonSpec], expandFraction: CGFloat, shouldAnimateIn: Bool, transition: ContainedViewLayoutTransition) {
|
||||||
let sideInset: CGFloat = 24.0
|
transition.updateFrame(view: self.backgroundContainer, frame: CGRect(origin: CGPoint(), size: size))
|
||||||
let expandedSideInset: CGFloat = 16.0
|
|
||||||
|
|
||||||
let maximumExpandOffset: CGFloat = 14.0
|
let buttonHeight: CGFloat = 44.0
|
||||||
let expandOffset: CGFloat = -expandFraction * maximumExpandOffset
|
|
||||||
|
let sideInset: CGFloat = 16.0
|
||||||
|
|
||||||
|
var normalLeftButtonsWidth: CGFloat = 0.0
|
||||||
|
var expandedLeftButtonsWidth: CGFloat = 0.0
|
||||||
|
|
||||||
|
let maxBlur: CGFloat = 5.0
|
||||||
|
|
||||||
|
let normalButtonContentsColor: UIColor = self.isOverColoredContents ? .white : presentationData.theme.chat.inputPanel.panelControlColor
|
||||||
|
let expandedButtonContentsColor: UIColor = presentationData.theme.chat.inputPanel.panelControlColor
|
||||||
|
|
||||||
if self.currentLeftButtons != leftButtons || presentationData.strings !== self.presentationData?.strings {
|
if self.currentLeftButtons != leftButtons || presentationData.strings !== self.presentationData?.strings {
|
||||||
self.currentLeftButtons = leftButtons
|
self.currentLeftButtons = leftButtons
|
||||||
|
|
||||||
var nextRegularButtonOrigin = sideInset
|
|
||||||
var nextExpandedButtonOrigin = sideInset
|
|
||||||
for spec in leftButtons.reversed() {
|
for spec in leftButtons.reversed() {
|
||||||
let buttonNode: PeerInfoHeaderNavigationButton
|
let buttonNode: PeerInfoHeaderNavigationButton
|
||||||
var wasAdded = false
|
var wasAdded = false
|
||||||
if let current = self.leftButtonNodes[spec.key] {
|
if let current = self.leftButtonNodes[spec] {
|
||||||
buttonNode = current
|
buttonNode = current
|
||||||
} else {
|
} else {
|
||||||
wasAdded = true
|
wasAdded = true
|
||||||
buttonNode = PeerInfoHeaderNavigationButton()
|
buttonNode = PeerInfoHeaderNavigationButton()
|
||||||
self.leftButtonNodes[spec.key] = buttonNode
|
self.leftButtonNodes[spec] = buttonNode
|
||||||
self.addSubnode(buttonNode)
|
self.leftButtonsContainer.addSubview(buttonNode.view)
|
||||||
buttonNode.action = { [weak self] _, gesture in
|
buttonNode.action = { [weak self] _, gesture in
|
||||||
guard let strongSelf = self, let buttonNode = strongSelf.leftButtonNodes[spec.key] else {
|
guard let strongSelf = self, let buttonNode = strongSelf.leftButtonNodes[spec] else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
strongSelf.performAction?(spec.key, buttonNode.contextSourceNode, gesture)
|
strongSelf.performAction?(spec.key, buttonNode.contextSourceNode, gesture)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let buttonSize = buttonNode.update(key: spec.key, presentationData: presentationData, height: size.height)
|
let buttonSize = buttonNode.update(key: spec.key, presentationData: presentationData, height: buttonHeight)
|
||||||
var nextButtonOrigin = spec.isForExpandedView ? nextExpandedButtonOrigin : nextRegularButtonOrigin
|
let buttonFrame = CGRect(origin: CGPoint(x: spec.isForExpandedView ? expandedLeftButtonsWidth : normalLeftButtonsWidth, y: 0.0), size: buttonSize)
|
||||||
|
|
||||||
let buttonY: CGFloat
|
|
||||||
if case .back = spec.key {
|
|
||||||
buttonY = 0.0
|
|
||||||
} else {
|
|
||||||
buttonY = expandOffset + (spec.isForExpandedView ? maximumExpandOffset : 0.0)
|
|
||||||
}
|
|
||||||
let buttonFrame = CGRect(origin: CGPoint(x: nextButtonOrigin, y: buttonY), size: buttonSize)
|
|
||||||
|
|
||||||
nextButtonOrigin += buttonSize.width + 4.0
|
|
||||||
if spec.isForExpandedView {
|
if spec.isForExpandedView {
|
||||||
nextExpandedButtonOrigin = nextButtonOrigin
|
expandedLeftButtonsWidth += buttonSize.width
|
||||||
} else {
|
} else {
|
||||||
nextRegularButtonOrigin = nextButtonOrigin
|
normalLeftButtonsWidth += buttonSize.width
|
||||||
}
|
}
|
||||||
let alphaFactor: CGFloat
|
let alphaFactor: CGFloat
|
||||||
if case .back = spec.key {
|
if case .back = spec.key {
|
||||||
|
|
@ -126,48 +153,40 @@ final class PeerInfoHeaderNavigationButtonContainerNode: SparseNode {
|
||||||
} else {
|
} else {
|
||||||
alphaFactor = spec.isForExpandedView ? expandFraction : (1.0 - expandFraction)
|
alphaFactor = spec.isForExpandedView ? expandFraction : (1.0 - expandFraction)
|
||||||
}
|
}
|
||||||
|
|
||||||
if wasAdded {
|
if wasAdded {
|
||||||
buttonNode.frame = buttonFrame
|
buttonNode.frame = buttonFrame
|
||||||
buttonNode.alpha = 0.0
|
buttonNode.alpha = 0.0
|
||||||
|
ComponentTransition.immediate.setBlur(layer: buttonNode.layer, radius: maxBlur)
|
||||||
transition.updateAlpha(node: buttonNode, alpha: alphaFactor * alphaFactor)
|
transition.updateAlpha(node: buttonNode, alpha: alphaFactor * alphaFactor)
|
||||||
buttonNode.updateContentsColor(backgroundColor: self.backgroundContentColor, contentsColor: self.contentsColor, canBeExpanded: self.canBeExpanded, transition: .immediate)
|
ComponentTransition(transition).setBlur(layer: buttonNode.layer, radius: 0.0)
|
||||||
|
buttonNode.updateContentsColor(contentsColor: spec.isForExpandedView ? expandedButtonContentsColor : normalButtonContentsColor, transition: .immediate)
|
||||||
transition.updateSublayerTransformOffset(layer: buttonNode.layer, offset: CGPoint(x: canBeExpanded ? -8.0 : 0.0, y: 0.0))
|
|
||||||
} else {
|
} else {
|
||||||
transition.updateFrameAdditiveToCenter(node: buttonNode, frame: buttonFrame)
|
transition.updateFrameAdditiveToCenter(node: buttonNode, frame: buttonFrame)
|
||||||
transition.updateAlpha(node: buttonNode, alpha: alphaFactor * alphaFactor)
|
transition.updateAlpha(node: buttonNode, alpha: alphaFactor * alphaFactor)
|
||||||
|
ComponentTransition(transition).setBlur(layer: buttonNode.layer, radius: (1.0 - alphaFactor * alphaFactor) * maxBlur)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
var removeKeys: [PeerInfoHeaderNavigationButtonKey] = []
|
var removeKeys: [PeerInfoHeaderNavigationButtonSpec] = []
|
||||||
for (key, _) in self.leftButtonNodes {
|
for (spec, _) in self.leftButtonNodes {
|
||||||
if !leftButtons.contains(where: { $0.key == key }) {
|
if !leftButtons.contains(where: { $0 == spec }) {
|
||||||
removeKeys.append(key)
|
removeKeys.append(spec)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for key in removeKeys {
|
for spec in removeKeys {
|
||||||
if let buttonNode = self.leftButtonNodes.removeValue(forKey: key) {
|
if let buttonNode = self.leftButtonNodes.removeValue(forKey: spec) {
|
||||||
buttonNode.removeFromSupernode()
|
buttonNode.view.removeFromSuperview()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
var nextRegularButtonOrigin = sideInset
|
|
||||||
var nextExpandedButtonOrigin = sideInset
|
|
||||||
for spec in leftButtons.reversed() {
|
for spec in leftButtons.reversed() {
|
||||||
if let buttonNode = self.leftButtonNodes[spec.key] {
|
if let buttonNode = self.leftButtonNodes[spec] {
|
||||||
let buttonSize = buttonNode.bounds.size
|
let buttonSize = buttonNode.bounds.size
|
||||||
var nextButtonOrigin = spec.isForExpandedView ? nextExpandedButtonOrigin : nextRegularButtonOrigin
|
let buttonFrame = CGRect(origin: CGPoint(x: spec.isForExpandedView ? expandedLeftButtonsWidth : normalLeftButtonsWidth, y: 0.0), size: buttonSize)
|
||||||
let buttonY: CGFloat
|
|
||||||
if case .back = spec.key {
|
|
||||||
buttonY = 0.0
|
|
||||||
} else {
|
|
||||||
buttonY = expandOffset + (spec.isForExpandedView ? maximumExpandOffset : 0.0)
|
|
||||||
}
|
|
||||||
let buttonFrame = CGRect(origin: CGPoint(x: nextButtonOrigin, y: buttonY), size: buttonSize)
|
|
||||||
nextButtonOrigin += buttonSize.width + 4.0
|
|
||||||
if spec.isForExpandedView {
|
if spec.isForExpandedView {
|
||||||
nextExpandedButtonOrigin = nextButtonOrigin
|
expandedLeftButtonsWidth += buttonSize.width
|
||||||
} else {
|
} else {
|
||||||
nextRegularButtonOrigin = nextButtonOrigin
|
normalLeftButtonsWidth += buttonSize.width
|
||||||
}
|
}
|
||||||
transition.updateFrameAdditiveToCenter(node: buttonNode, frame: buttonFrame)
|
transition.updateFrameAdditiveToCenter(node: buttonNode, frame: buttonFrame)
|
||||||
let alphaFactor: CGFloat
|
let alphaFactor: CGFloat
|
||||||
|
|
@ -182,16 +201,17 @@ final class PeerInfoHeaderNavigationButtonContainerNode: SparseNode {
|
||||||
buttonTransition = .animated(duration: duration * 0.25, curve: curve)
|
buttonTransition = .animated(duration: duration * 0.25, curve: curve)
|
||||||
}
|
}
|
||||||
buttonTransition.updateAlpha(node: buttonNode, alpha: alphaFactor * alphaFactor)
|
buttonTransition.updateAlpha(node: buttonNode, alpha: alphaFactor * alphaFactor)
|
||||||
|
ComponentTransition(buttonTransition).setBlur(layer: buttonNode.layer, radius: (1.0 - alphaFactor * alphaFactor) * maxBlur)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var accumulatedRightButtonOffset: CGFloat = self.canBeExpanded ? 16.0 : 0.0
|
var normalRightButtonsWidth: CGFloat = 0.0
|
||||||
|
var expandedRightButtonsWidth: CGFloat = 0.0
|
||||||
|
|
||||||
if self.currentRightButtons != rightButtons || presentationData.strings !== self.presentationData?.strings {
|
if self.currentRightButtons != rightButtons || presentationData.strings !== self.presentationData?.strings {
|
||||||
self.currentRightButtons = rightButtons
|
self.currentRightButtons = rightButtons
|
||||||
|
|
||||||
var nextRegularButtonOrigin = size.width - sideInset - 8.0
|
|
||||||
var nextExpandedButtonOrigin = size.width - expandedSideInset
|
|
||||||
for spec in rightButtons.reversed() {
|
for spec in rightButtons.reversed() {
|
||||||
let buttonNode: PeerInfoHeaderNavigationButton
|
let buttonNode: PeerInfoHeaderNavigationButton
|
||||||
var wasAdded = false
|
var wasAdded = false
|
||||||
|
|
@ -201,32 +221,30 @@ final class PeerInfoHeaderNavigationButtonContainerNode: SparseNode {
|
||||||
key = .moreSearchSort
|
key = .moreSearchSort
|
||||||
}
|
}
|
||||||
|
|
||||||
if let current = self.rightButtonNodes[key] {
|
if let current = self.rightButtonNodes[spec] {
|
||||||
buttonNode = current
|
buttonNode = current
|
||||||
} else {
|
} else {
|
||||||
wasAdded = true
|
wasAdded = true
|
||||||
buttonNode = PeerInfoHeaderNavigationButton()
|
buttonNode = PeerInfoHeaderNavigationButton()
|
||||||
self.rightButtonNodes[key] = buttonNode
|
self.rightButtonNodes[spec] = buttonNode
|
||||||
self.addSubnode(buttonNode)
|
self.rightButtonsContainer.addSubview(buttonNode.view)
|
||||||
}
|
}
|
||||||
buttonNode.action = { [weak self] _, gesture in
|
buttonNode.action = { [weak self] _, gesture in
|
||||||
guard let strongSelf = self, let buttonNode = strongSelf.rightButtonNodes[key] else {
|
guard let strongSelf = self, let buttonNode = strongSelf.rightButtonNodes[spec] else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
strongSelf.performAction?(spec.key, buttonNode.contextSourceNode, gesture)
|
strongSelf.performAction?(spec.key, buttonNode.contextSourceNode, gesture)
|
||||||
}
|
}
|
||||||
let buttonSize = buttonNode.update(key: spec.key, presentationData: presentationData, height: size.height)
|
let buttonSize = buttonNode.update(key: spec.key, presentationData: presentationData, height: buttonHeight)
|
||||||
var nextButtonOrigin = spec.isForExpandedView ? nextExpandedButtonOrigin : nextRegularButtonOrigin
|
let buttonFrame = CGRect(origin: CGPoint(x: spec.isForExpandedView ? expandedRightButtonsWidth : normalRightButtonsWidth, y: 0.0), size: buttonSize)
|
||||||
let buttonFrame = CGRect(origin: CGPoint(x: nextButtonOrigin - buttonSize.width, y: expandOffset + (spec.isForExpandedView ? maximumExpandOffset : 0.0)), size: buttonSize)
|
|
||||||
nextButtonOrigin -= buttonSize.width + 15.0
|
|
||||||
if spec.isForExpandedView {
|
if spec.isForExpandedView {
|
||||||
nextExpandedButtonOrigin = nextButtonOrigin
|
expandedRightButtonsWidth += buttonSize.width
|
||||||
} else {
|
} else {
|
||||||
nextRegularButtonOrigin = nextButtonOrigin
|
normalRightButtonsWidth += buttonSize.width
|
||||||
}
|
}
|
||||||
let alphaFactor: CGFloat = spec.isForExpandedView ? expandFraction : (1.0 - expandFraction)
|
let alphaFactor: CGFloat = spec.isForExpandedView ? expandFraction : (1.0 - expandFraction)
|
||||||
if wasAdded {
|
if wasAdded {
|
||||||
buttonNode.updateContentsColor(backgroundColor: self.backgroundContentColor, contentsColor: self.contentsColor, canBeExpanded: self.canBeExpanded, transition: .immediate)
|
buttonNode.updateContentsColor(contentsColor: spec.isForExpandedView ? expandedButtonContentsColor : normalButtonContentsColor, transition: .immediate)
|
||||||
|
|
||||||
if shouldAnimateIn {
|
if shouldAnimateIn {
|
||||||
if key == .moreSearchSort || key == .searchWithTags || key == .standaloneSearch {
|
if key == .moreSearchSort || key == .searchWithTags || key == .standaloneSearch {
|
||||||
|
|
@ -236,62 +254,51 @@ final class PeerInfoHeaderNavigationButtonContainerNode: SparseNode {
|
||||||
|
|
||||||
buttonNode.frame = buttonFrame
|
buttonNode.frame = buttonFrame
|
||||||
buttonNode.alpha = 0.0
|
buttonNode.alpha = 0.0
|
||||||
|
ComponentTransition.immediate.setBlur(layer: buttonNode.layer, radius: maxBlur)
|
||||||
transition.updateAlpha(node: buttonNode, alpha: alphaFactor * alphaFactor)
|
transition.updateAlpha(node: buttonNode, alpha: alphaFactor * alphaFactor)
|
||||||
|
ComponentTransition(transition).setBlur(layer: buttonNode.layer, radius: (1.0 - alphaFactor * alphaFactor) * maxBlur)
|
||||||
if !spec.isForExpandedView {
|
|
||||||
transition.updateSublayerTransformOffset(layer: buttonNode.layer, offset: CGPoint(x: accumulatedRightButtonOffset, y: 0.0))
|
|
||||||
if self.backgroundContentColor.alpha != 0.0 {
|
|
||||||
accumulatedRightButtonOffset -= 6.0
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
transition.updateSublayerTransformOffset(layer: buttonNode.layer, offset: .zero)
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
transition.updateFrameAdditiveToCenter(node: buttonNode, frame: buttonFrame)
|
transition.updateFrameAdditiveToCenter(node: buttonNode, frame: buttonFrame)
|
||||||
transition.updateAlpha(node: buttonNode, alpha: alphaFactor * alphaFactor)
|
transition.updateAlpha(node: buttonNode, alpha: alphaFactor * alphaFactor)
|
||||||
|
ComponentTransition(transition).setBlur(layer: buttonNode.layer, radius: (1.0 - alphaFactor * alphaFactor) * maxBlur)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
var removeKeys: [PeerInfoHeaderNavigationButtonKey] = []
|
var removeKeys: [PeerInfoHeaderNavigationButtonSpec] = []
|
||||||
for (key, _) in self.rightButtonNodes {
|
for (spec, _) in self.rightButtonNodes {
|
||||||
if key == .moreSearchSort {
|
if spec.key == .moreSearchSort {
|
||||||
if !rightButtons.contains(where: { $0.key == .more || $0.key == .search || $0.key == .sort }) {
|
if !rightButtons.contains(where: { $0.key == .more || $0.key == .search || $0.key == .sort }) {
|
||||||
removeKeys.append(key)
|
removeKeys.append(spec)
|
||||||
}
|
}
|
||||||
} else if !rightButtons.contains(where: { $0.key == key }) {
|
} else if !rightButtons.contains(where: { $0 == spec }) {
|
||||||
removeKeys.append(key)
|
removeKeys.append(spec)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for key in removeKeys {
|
for spec in removeKeys {
|
||||||
if let buttonNode = self.rightButtonNodes.removeValue(forKey: key) {
|
if let buttonNode = self.rightButtonNodes.removeValue(forKey: spec) {
|
||||||
if key == .moreSearchSort || key == .searchWithTags || key == .standaloneSearch {
|
if spec.key == .moreSearchSort || spec.key == .searchWithTags || spec.key == .standaloneSearch {
|
||||||
buttonNode.layer.animateAlpha(from: buttonNode.alpha, to: 0.0, duration: 0.2, removeOnCompletion: false, completion: { [weak buttonNode] _ in
|
buttonNode.layer.animateAlpha(from: buttonNode.alpha, to: 0.0, duration: 0.2, removeOnCompletion: false, completion: { [weak buttonNode] _ in
|
||||||
buttonNode?.removeFromSupernode()
|
buttonNode?.view.removeFromSuperview()
|
||||||
})
|
})
|
||||||
buttonNode.layer.animateScale(from: 1.0, to: 0.001, duration: 0.2, removeOnCompletion: false)
|
buttonNode.layer.animateScale(from: 1.0, to: 0.001, duration: 0.2, removeOnCompletion: false)
|
||||||
} else {
|
} else {
|
||||||
buttonNode.removeFromSupernode()
|
buttonNode.view.removeFromSuperview()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
var nextRegularButtonOrigin = size.width - sideInset - 8.0
|
|
||||||
var nextExpandedButtonOrigin = size.width - expandedSideInset
|
|
||||||
|
|
||||||
for spec in rightButtons.reversed() {
|
for spec in rightButtons.reversed() {
|
||||||
var key = spec.key
|
var key = spec.key
|
||||||
if key == .more || key == .search || key == .sort {
|
if key == .more || key == .search || key == .sort {
|
||||||
key = .moreSearchSort
|
key = .moreSearchSort
|
||||||
}
|
}
|
||||||
|
|
||||||
if let buttonNode = self.rightButtonNodes[key] {
|
if let buttonNode = self.rightButtonNodes[spec] {
|
||||||
let buttonSize = buttonNode.bounds.size
|
let buttonSize = buttonNode.bounds.size
|
||||||
var nextButtonOrigin = spec.isForExpandedView ? nextExpandedButtonOrigin : nextRegularButtonOrigin
|
let buttonFrame = CGRect(origin: CGPoint(x: spec.isForExpandedView ? expandedRightButtonsWidth : normalRightButtonsWidth, y: 0.0), size: buttonSize)
|
||||||
let buttonFrame = CGRect(origin: CGPoint(x: nextButtonOrigin - buttonSize.width, y: expandOffset + (spec.isForExpandedView ? maximumExpandOffset : 0.0)), size: buttonSize)
|
|
||||||
nextButtonOrigin -= buttonSize.width + 15.0
|
|
||||||
if spec.isForExpandedView {
|
if spec.isForExpandedView {
|
||||||
nextExpandedButtonOrigin = nextButtonOrigin
|
expandedRightButtonsWidth += buttonSize.width
|
||||||
} else {
|
} else {
|
||||||
nextRegularButtonOrigin = nextButtonOrigin
|
normalRightButtonsWidth += buttonSize.width
|
||||||
}
|
}
|
||||||
transition.updateFrameAdditiveToCenter(node: buttonNode, frame: buttonFrame)
|
transition.updateFrameAdditiveToCenter(node: buttonNode, frame: buttonFrame)
|
||||||
let alphaFactor: CGFloat = spec.isForExpandedView ? expandFraction : (1.0 - expandFraction)
|
let alphaFactor: CGFloat = spec.isForExpandedView ? expandFraction : (1.0 - expandFraction)
|
||||||
|
|
@ -301,9 +308,60 @@ final class PeerInfoHeaderNavigationButtonContainerNode: SparseNode {
|
||||||
buttonTransition = .animated(duration: duration * 0.25, curve: curve)
|
buttonTransition = .animated(duration: duration * 0.25, curve: curve)
|
||||||
}
|
}
|
||||||
buttonTransition.updateAlpha(node: buttonNode, alpha: alphaFactor * alphaFactor)
|
buttonTransition.updateAlpha(node: buttonNode, alpha: alphaFactor * alphaFactor)
|
||||||
|
ComponentTransition(transition).setBlur(layer: buttonNode.layer, radius: (1.0 - alphaFactor * alphaFactor) * maxBlur)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
self.presentationData = presentationData
|
self.presentationData = presentationData
|
||||||
|
|
||||||
|
let buttonsY: CGFloat = floor((size.height - buttonHeight) * 0.5) + 2.0
|
||||||
|
|
||||||
|
let leftButtonsWidth = (1.0 - expandFraction) * normalLeftButtonsWidth + expandFraction * expandedLeftButtonsWidth
|
||||||
|
let rightButtonsWidth = (1.0 - expandFraction) * normalRightButtonsWidth + expandFraction * expandedRightButtonsWidth
|
||||||
|
|
||||||
|
var leftButtonsFrame = CGRect(origin: CGPoint(x: sideInset, y: buttonsY), size: CGSize(width: max(44.0, leftButtonsWidth), height: buttonHeight))
|
||||||
|
if leftButtonsWidth < 44.0 {
|
||||||
|
let leftFraction = leftButtonsWidth / 44.0
|
||||||
|
leftButtonsFrame.origin.x = floorToScreenPixels(leftFraction * sideInset + (1.0 - leftFraction) * (-44.0))
|
||||||
|
}
|
||||||
|
var rightButtonsFrame = CGRect(origin: CGPoint(x: size.width - sideInset - rightButtonsWidth, y: buttonsY), size: CGSize(width: max(44.0, rightButtonsWidth), height: buttonHeight))
|
||||||
|
if rightButtonsWidth < 44.0 {
|
||||||
|
let rightFraction = rightButtonsWidth / 44.0
|
||||||
|
rightButtonsFrame.origin.x = floorToScreenPixels(rightFraction * (size.width - sideInset - 44.0) + (1.0 - rightFraction) * size.width)
|
||||||
|
}
|
||||||
|
|
||||||
|
transition.updateFrame(view: self.leftButtonsBackground, frame: leftButtonsFrame)
|
||||||
|
transition.updateFrame(view: self.leftButtonsContainer, frame: CGRect(origin: CGPoint(), size: leftButtonsFrame.size))
|
||||||
|
self.leftButtonsContainer.layer.cornerRadius = leftButtonsFrame.height * 0.5
|
||||||
|
|
||||||
|
transition.updateFrame(view: self.rightButtonsBackground, frame: rightButtonsFrame)
|
||||||
|
transition.updateFrame(view: self.rightButtonsContainer, frame: CGRect(origin: CGPoint(), size: rightButtonsFrame.size))
|
||||||
|
self.rightButtonsContainer.layer.cornerRadius = rightButtonsFrame.height * 0.5
|
||||||
|
|
||||||
|
self.updateBackgroundColors(transition: ComponentTransition(transition))
|
||||||
|
}
|
||||||
|
|
||||||
|
private func updateBackgroundColors(transition: ComponentTransition) {
|
||||||
|
guard let presentationData = self.presentationData else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
let leftButtonsSize = self.leftButtonsBackground.bounds.size
|
||||||
|
let rightButtonsSize = self.rightButtonsBackground.bounds.size
|
||||||
|
|
||||||
|
let tintColor: GlassBackgroundView.TintColor
|
||||||
|
let tintIsDark: Bool
|
||||||
|
if self.isOverColoredContents {
|
||||||
|
tintColor = .init(kind: .custom, color: self.backgroundContentColor)
|
||||||
|
tintIsDark = presentationData.theme.overallDarkAppearance
|
||||||
|
} else {
|
||||||
|
tintColor = .init(kind: .panel, color: UIColor(white: presentationData.theme.overallDarkAppearance ? 0.0 : 1.0, alpha: 0.6))
|
||||||
|
tintIsDark = presentationData.theme.overallDarkAppearance
|
||||||
|
}
|
||||||
|
|
||||||
|
self.backgroundContainer.update(size: self.backgroundContainer.bounds.size, isDark: tintIsDark, transition: transition)
|
||||||
|
|
||||||
|
self.rightButtonsBackground.update(size: rightButtonsSize, cornerRadius: rightButtonsSize.height * 0.5, isDark: tintIsDark, tintColor: tintColor, isInteractive: true, transition: transition)
|
||||||
|
self.leftButtonsBackground.update(size: leftButtonsSize, cornerRadius: leftButtonsSize.height * 0.5, isDark: tintIsDark, tintColor: tintColor, isInteractive: true, transition: transition)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -44,6 +44,7 @@ import ProfileLevelInfoScreen
|
||||||
import PlainButtonComponent
|
import PlainButtonComponent
|
||||||
import BundleIconComponent
|
import BundleIconComponent
|
||||||
import MarqueeComponent
|
import MarqueeComponent
|
||||||
|
import EdgeEffect
|
||||||
|
|
||||||
final class PeerInfoHeaderNavigationTransition {
|
final class PeerInfoHeaderNavigationTransition {
|
||||||
let sourceNavigationBar: NavigationBar
|
let sourceNavigationBar: NavigationBar
|
||||||
|
|
@ -63,7 +64,7 @@ final class PeerInfoHeaderNavigationTransition {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
final class PeerInfoHeaderRegularContentNode: ASDisplayNode {
|
final class PeerInfoHeaderRegularContentNode: SparseNode {
|
||||||
}
|
}
|
||||||
|
|
||||||
enum PeerInfoHeaderTextFieldNodeKey: Equatable {
|
enum PeerInfoHeaderTextFieldNodeKey: Equatable {
|
||||||
|
|
@ -90,6 +91,7 @@ final class PeerInfoHeaderNode: ASDisplayNode {
|
||||||
private var state: PeerInfoState?
|
private var state: PeerInfoState?
|
||||||
private var peer: Peer?
|
private var peer: Peer?
|
||||||
private var threadData: MessageHistoryThreadData?
|
private var threadData: MessageHistoryThreadData?
|
||||||
|
private var isSearching: Bool = false
|
||||||
private var avatarSize: CGFloat?
|
private var avatarSize: CGFloat?
|
||||||
|
|
||||||
private let isOpenedFromChat: Bool
|
private let isOpenedFromChat: Bool
|
||||||
|
|
@ -151,17 +153,13 @@ final class PeerInfoHeaderNode: ASDisplayNode {
|
||||||
let usernameNode: MultiScaleTextNode
|
let usernameNode: MultiScaleTextNode
|
||||||
var actionButtonNodes: [PeerInfoHeaderButtonKey: PeerInfoHeaderActionButtonNode] = [:]
|
var actionButtonNodes: [PeerInfoHeaderButtonKey: PeerInfoHeaderActionButtonNode] = [:]
|
||||||
var buttonNodes: [PeerInfoHeaderButtonKey: PeerInfoHeaderButtonNode] = [:]
|
var buttonNodes: [PeerInfoHeaderButtonKey: PeerInfoHeaderButtonNode] = [:]
|
||||||
let backgroundNode: NavigationBackgroundNode
|
let panelsExpansionBackgroundView: UIView
|
||||||
let expandedBackgroundNode: NavigationBackgroundNode
|
let headerEdgeEffectView: EdgeEffectView
|
||||||
let separatorNode: ASDisplayNode
|
|
||||||
let navigationBackgroundNode: ASDisplayNode
|
|
||||||
let navigationBackgroundBackgroundNode: ASDisplayNode
|
|
||||||
var navigationTitle: String?
|
var navigationTitle: String?
|
||||||
let navigationTitleNode: ImmediateTextNode
|
|
||||||
let navigationSeparatorNode: ASDisplayNode
|
|
||||||
let navigationButtonContainer: PeerInfoHeaderNavigationButtonContainerNode
|
let navigationButtonContainer: PeerInfoHeaderNavigationButtonContainerNode
|
||||||
let editingNavigationBackgroundNode: NavigationBackgroundNode
|
let searchContainer: ASDisplayNode
|
||||||
let editingNavigationBackgroundSeparator: ASDisplayNode
|
let searchBarContainer: SparseNode
|
||||||
|
let editingEdgeEffectView: EdgeEffectView
|
||||||
|
|
||||||
var musicBackground: UIView?
|
var musicBackground: UIView?
|
||||||
var music: ComponentView<Empty>?
|
var music: ComponentView<Empty>?
|
||||||
|
|
@ -286,30 +284,16 @@ final class PeerInfoHeaderNode: ASDisplayNode {
|
||||||
self.avatarOverlayNode = PeerInfoEditingAvatarOverlayNode(context: context)
|
self.avatarOverlayNode = PeerInfoEditingAvatarOverlayNode(context: context)
|
||||||
self.avatarOverlayNode.isUserInteractionEnabled = false
|
self.avatarOverlayNode.isUserInteractionEnabled = false
|
||||||
|
|
||||||
self.navigationBackgroundNode = ASDisplayNode()
|
|
||||||
self.navigationBackgroundNode.isHidden = true
|
|
||||||
self.navigationBackgroundNode.isUserInteractionEnabled = false
|
|
||||||
|
|
||||||
self.navigationBackgroundBackgroundNode = ASDisplayNode()
|
|
||||||
self.navigationBackgroundBackgroundNode.isUserInteractionEnabled = false
|
|
||||||
|
|
||||||
self.navigationTitleNode = ImmediateTextNode()
|
|
||||||
|
|
||||||
self.navigationSeparatorNode = ASDisplayNode()
|
|
||||||
|
|
||||||
self.navigationButtonContainer = PeerInfoHeaderNavigationButtonContainerNode()
|
self.navigationButtonContainer = PeerInfoHeaderNavigationButtonContainerNode()
|
||||||
self.editingNavigationBackgroundNode = NavigationBackgroundNode(color: .clear, enableBlur: true)
|
self.searchBarContainer = SparseNode()
|
||||||
self.editingNavigationBackgroundSeparator = ASDisplayNode()
|
self.searchContainer = ASDisplayNode()
|
||||||
|
|
||||||
self.backgroundNode = NavigationBackgroundNode(color: .clear)
|
self.panelsExpansionBackgroundView = UIView()
|
||||||
self.backgroundNode.isHidden = true
|
self.headerEdgeEffectView = EdgeEffectView()
|
||||||
self.backgroundNode.isUserInteractionEnabled = false
|
self.headerEdgeEffectView.isUserInteractionEnabled = false
|
||||||
self.expandedBackgroundNode = NavigationBackgroundNode(color: .clear)
|
|
||||||
self.expandedBackgroundNode.isHidden = false
|
|
||||||
self.expandedBackgroundNode.isUserInteractionEnabled = false
|
|
||||||
|
|
||||||
self.separatorNode = ASDisplayNode()
|
self.editingEdgeEffectView = EdgeEffectView()
|
||||||
self.separatorNode.isLayerBacked = true
|
self.editingEdgeEffectView.isUserInteractionEnabled = false
|
||||||
|
|
||||||
self.animationCache = context.animationCache
|
self.animationCache = context.animationCache
|
||||||
self.animationRenderer = context.animationRenderer
|
self.animationRenderer = context.animationRenderer
|
||||||
|
|
@ -320,8 +304,9 @@ final class PeerInfoHeaderNode: ASDisplayNode {
|
||||||
self?.requestUpdateLayout?(false)
|
self?.requestUpdateLayout?(false)
|
||||||
}
|
}
|
||||||
|
|
||||||
self.addSubnode(self.backgroundNode)
|
self.view.addSubview(self.panelsExpansionBackgroundView)
|
||||||
self.addSubnode(self.expandedBackgroundNode)
|
self.addSubnode(self.searchContainer)
|
||||||
|
self.view.addSubview(self.headerEdgeEffectView)
|
||||||
self.view.addSubview(self.backgroundBannerView)
|
self.view.addSubview(self.backgroundBannerView)
|
||||||
self.titleNodeContainer.addSubnode(self.titleNode)
|
self.titleNodeContainer.addSubnode(self.titleNode)
|
||||||
self.subtitleNodeContainer.addSubnode(self.subtitleNode)
|
self.subtitleNodeContainer.addSubnode(self.subtitleNode)
|
||||||
|
|
@ -346,14 +331,9 @@ final class PeerInfoHeaderNode: ASDisplayNode {
|
||||||
|
|
||||||
self.addSubnode(self.editingContentNode)
|
self.addSubnode(self.editingContentNode)
|
||||||
self.addSubnode(self.avatarOverlayNode)
|
self.addSubnode(self.avatarOverlayNode)
|
||||||
self.addSubnode(self.navigationBackgroundNode)
|
self.view.addSubview(self.editingEdgeEffectView)
|
||||||
self.navigationBackgroundNode.addSubnode(self.navigationBackgroundBackgroundNode)
|
|
||||||
self.navigationBackgroundNode.addSubnode(self.navigationTitleNode)
|
|
||||||
self.navigationBackgroundNode.addSubnode(self.navigationSeparatorNode)
|
|
||||||
self.addSubnode(self.editingNavigationBackgroundNode)
|
|
||||||
self.addSubnode(self.editingNavigationBackgroundSeparator)
|
|
||||||
self.addSubnode(self.navigationButtonContainer)
|
self.addSubnode(self.navigationButtonContainer)
|
||||||
self.addSubnode(self.separatorNode)
|
self.addSubnode(self.searchBarContainer)
|
||||||
|
|
||||||
self.avatarListNode.avatarContainerNode.tapped = { [weak self] in
|
self.avatarListNode.avatarContainerNode.tapped = { [weak self] in
|
||||||
self?.initiateAvatarExpansion(gallery: false, first: false)
|
self?.initiateAvatarExpansion(gallery: false, first: false)
|
||||||
|
|
@ -509,7 +489,7 @@ final class PeerInfoHeaderNode: ASDisplayNode {
|
||||||
private var currentStatusIcon: CredibilityIcon?
|
private var currentStatusIcon: CredibilityIcon?
|
||||||
|
|
||||||
private var currentPanelStatusData: PeerInfoStatusData?
|
private var currentPanelStatusData: PeerInfoStatusData?
|
||||||
func update(width: CGFloat, containerHeight: CGFloat, containerInset: CGFloat, statusBarHeight: CGFloat, navigationHeight: CGFloat, isModalOverlay: Bool, isMediaOnly: Bool, contentOffset: CGFloat, paneContainerY: CGFloat, presentationData: PresentationData, peer: Peer?, cachedData: CachedPeerData?, threadData: MessageHistoryThreadData?, peerNotificationSettings: TelegramPeerNotificationSettings?, threadNotificationSettings: TelegramPeerNotificationSettings?, globalNotificationSettings: EngineGlobalNotificationSettings?, statusData: PeerInfoStatusData?, panelStatusData: (PeerInfoStatusData?, PeerInfoStatusData?, CGFloat?), isSecretChat: Bool, isContact: Bool, isSettings: Bool, state: PeerInfoState, profileGiftsContext: ProfileGiftsContext?, screenData: PeerInfoScreenData?, metrics: LayoutMetrics, deviceMetrics: DeviceMetrics, transition: ContainedViewLayoutTransition, additive: Bool, animateHeader: Bool) -> CGFloat {
|
func update(width: CGFloat, containerHeight: CGFloat, containerInset: CGFloat, statusBarHeight: CGFloat, navigationHeight: CGFloat, isModalOverlay: Bool, isMediaOnly: Bool, contentOffset: CGFloat, paneContainerY: CGFloat, presentationData: PresentationData, peer: Peer?, cachedData: CachedPeerData?, threadData: MessageHistoryThreadData?, peerNotificationSettings: TelegramPeerNotificationSettings?, threadNotificationSettings: TelegramPeerNotificationSettings?, globalNotificationSettings: EngineGlobalNotificationSettings?, statusData: PeerInfoStatusData?, panelStatusData: (PeerInfoStatusData?, PeerInfoStatusData?, CGFloat?), isSecretChat: Bool, isContact: Bool, isSettings: Bool, state: PeerInfoState, profileGiftsContext: ProfileGiftsContext?, screenData: PeerInfoScreenData?, isSearching: Bool, metrics: LayoutMetrics, deviceMetrics: DeviceMetrics, transition: ContainedViewLayoutTransition, additive: Bool, animateHeader: Bool) -> CGFloat {
|
||||||
if self.appliedCustomNavigationContentNode !== self.customNavigationContentNode {
|
if self.appliedCustomNavigationContentNode !== self.customNavigationContentNode {
|
||||||
if let previous = self.appliedCustomNavigationContentNode {
|
if let previous = self.appliedCustomNavigationContentNode {
|
||||||
transition.updateAlpha(node: previous, alpha: 0.0, completion: { [weak previous] _ in
|
transition.updateAlpha(node: previous, alpha: 0.0, completion: { [weak previous] _ in
|
||||||
|
|
@ -536,11 +516,15 @@ final class PeerInfoHeaderNode: ASDisplayNode {
|
||||||
self.state = state
|
self.state = state
|
||||||
self.peer = peer
|
self.peer = peer
|
||||||
self.threadData = threadData
|
self.threadData = threadData
|
||||||
|
self.isSearching = isSearching
|
||||||
self.avatarListNode.listContainerNode.peer = peer.flatMap(EnginePeer.init)
|
self.avatarListNode.listContainerNode.peer = peer.flatMap(EnginePeer.init)
|
||||||
|
|
||||||
let isFirstTime = self.validLayout == nil
|
let isFirstTime = self.validLayout == nil
|
||||||
self.validLayout = (width, statusBarHeight, deviceMetrics)
|
self.validLayout = (width, statusBarHeight, deviceMetrics)
|
||||||
|
|
||||||
|
self.searchBarContainer.isUserInteractionEnabled = isSearching
|
||||||
|
self.searchContainer.isUserInteractionEnabled = isSearching
|
||||||
|
|
||||||
let previousPanelStatusData = self.currentPanelStatusData
|
let previousPanelStatusData = self.currentPanelStatusData
|
||||||
self.currentPanelStatusData = panelStatusData.0
|
self.currentPanelStatusData = panelStatusData.0
|
||||||
|
|
||||||
|
|
@ -637,7 +621,7 @@ final class PeerInfoHeaderNode: ASDisplayNode {
|
||||||
|
|
||||||
transition.updateAlpha(node: self.regularContentNode, alpha: (state.isEditing || self.customNavigationContentNode != nil) ? 0.0 : 1.0)
|
transition.updateAlpha(node: self.regularContentNode, alpha: (state.isEditing || self.customNavigationContentNode != nil) ? 0.0 : 1.0)
|
||||||
if self.navigationTransition == nil {
|
if self.navigationTransition == nil {
|
||||||
transition.updateAlpha(node: self.navigationButtonContainer, alpha: self.customNavigationContentNode != nil ? 0.0 : 1.0)
|
transition.updateAlpha(node: self.navigationButtonContainer, alpha: (self.customNavigationContentNode != nil || isSearching) ? 0.0 : 1.0)
|
||||||
}
|
}
|
||||||
|
|
||||||
self.editingContentNode.alpha = state.isEditing ? 1.0 : 0.0
|
self.editingContentNode.alpha = state.isEditing ? 1.0 : 0.0
|
||||||
|
|
@ -656,10 +640,6 @@ final class PeerInfoHeaderNode: ASDisplayNode {
|
||||||
|
|
||||||
let avatarFrame = CGRect(origin: CGPoint(x: floor((width - avatarSize) / 2.0), y: statusBarHeight + 22.0), size: CGSize(width: avatarSize, height: avatarSize))
|
let avatarFrame = CGRect(origin: CGPoint(x: floor((width - avatarSize) / 2.0), y: statusBarHeight + 22.0), size: CGSize(width: avatarSize, height: avatarSize))
|
||||||
|
|
||||||
self.backgroundNode.updateColor(color: presentationData.theme.rootController.navigationBar.blurredBackgroundColor, transition: .immediate)
|
|
||||||
|
|
||||||
let headerBackgroundColor: UIColor = presentationData.theme.list.blocksBackgroundColor
|
|
||||||
|
|
||||||
let regularNavigationContentsAccentColor: UIColor = peer?.effectiveProfileColor != nil ? .white : presentationData.theme.list.itemAccentColor
|
let regularNavigationContentsAccentColor: UIColor = peer?.effectiveProfileColor != nil ? .white : presentationData.theme.list.itemAccentColor
|
||||||
let collapsedHeaderNavigationContentsAccentColor = presentationData.theme.list.itemAccentColor
|
let collapsedHeaderNavigationContentsAccentColor = presentationData.theme.list.itemAccentColor
|
||||||
let expandedAvatarNavigationContentsAccentColor: UIColor = .white
|
let expandedAvatarNavigationContentsAccentColor: UIColor = .white
|
||||||
|
|
@ -674,7 +654,7 @@ final class PeerInfoHeaderNode: ASDisplayNode {
|
||||||
|
|
||||||
let regularHeaderButtonBackgroundColor: UIColor
|
let regularHeaderButtonBackgroundColor: UIColor
|
||||||
let collapsedHeaderButtonBackgroundColor: UIColor = .clear
|
let collapsedHeaderButtonBackgroundColor: UIColor = .clear
|
||||||
let expandedAvatarHeaderButtonBackgroundColor: UIColor = UIColor(white: 1.0, alpha: 0.1)
|
let expandedAvatarHeaderButtonBackgroundColor: UIColor = UIColor(white: 0.0, alpha: 0.5)
|
||||||
|
|
||||||
let regularContentButtonForegroundColor: UIColor = peer?.effectiveProfileColor != nil ? UIColor.white : presentationData.theme.list.itemAccentColor
|
let regularContentButtonForegroundColor: UIColor = peer?.effectiveProfileColor != nil ? UIColor.white : presentationData.theme.list.itemAccentColor
|
||||||
let collapsedHeaderContentButtonForegroundColor = presentationData.theme.list.itemAccentColor
|
let collapsedHeaderContentButtonForegroundColor = presentationData.theme.list.itemAccentColor
|
||||||
|
|
@ -745,61 +725,21 @@ final class PeerInfoHeaderNode: ASDisplayNode {
|
||||||
navigationTransition = animateHeader ? .animated(duration: 0.2, curve: .easeInOut) : .immediate
|
navigationTransition = animateHeader ? .animated(duration: 0.2, curve: .easeInOut) : .immediate
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let editingEdgeEffectHeight: CGFloat = 40.0
|
||||||
|
let editingEdgeEffectFrame = CGRect(origin: CGPoint(x: 0.0, y: 0.0), size: CGSize(width: width, height: navigationHeight + 10.0))
|
||||||
|
transition.updateFrame(view: self.editingEdgeEffectView, frame: editingEdgeEffectFrame)
|
||||||
|
self.editingEdgeEffectView.update(content: presentationData.theme.list.blocksBackgroundColor, blur: true, rect: editingEdgeEffectFrame, edge: .top, edgeSize: editingEdgeEffectHeight, transition: ComponentTransition(transition))
|
||||||
let editingBackgroundAlpha: CGFloat
|
let editingBackgroundAlpha: CGFloat
|
||||||
if state.isEditing {
|
if state.isEditing {
|
||||||
editingBackgroundAlpha = max(0.0, min(1.0, contentOffset / 20.0))
|
editingBackgroundAlpha = max(0.0, min(1.0, contentOffset / 20.0))
|
||||||
} else {
|
} else {
|
||||||
editingBackgroundAlpha = 0.0
|
editingBackgroundAlpha = 0.0
|
||||||
}
|
}
|
||||||
|
ComponentTransition(transition).setAlpha(view: self.editingEdgeEffectView, alpha: editingBackgroundAlpha)
|
||||||
self.editingNavigationBackgroundSeparator.backgroundColor = presentationData.theme.rootController.navigationBar.separatorColor
|
|
||||||
self.editingNavigationBackgroundNode.updateColor(color: presentationData.theme.rootController.navigationBar.blurredBackgroundColor, transition: .immediate)
|
|
||||||
|
|
||||||
let editingNavigationBackgroundFrame = CGRect(origin: CGPoint(), size: CGSize(width: width, height: navigationHeight))
|
|
||||||
transition.updateFrame(node: self.editingNavigationBackgroundNode, frame: editingNavigationBackgroundFrame)
|
|
||||||
self.editingNavigationBackgroundNode.update(size: editingNavigationBackgroundFrame.size, transition: transition)
|
|
||||||
transition.updateFrame(node: self.editingNavigationBackgroundSeparator, frame: CGRect(origin: CGPoint(x: 0.0, y: editingNavigationBackgroundFrame.maxY), size: CGSize(width: width, height: UIScreenPixel)))
|
|
||||||
|
|
||||||
transition.updateAlpha(node: self.editingNavigationBackgroundNode, alpha: editingBackgroundAlpha)
|
|
||||||
transition.updateAlpha(node: self.editingNavigationBackgroundSeparator, alpha: editingBackgroundAlpha)
|
|
||||||
|
|
||||||
let backgroundBannerAlpha: CGFloat
|
let backgroundBannerAlpha: CGFloat
|
||||||
|
|
||||||
var effectiveSeparatorAlpha: CGFloat
|
do {
|
||||||
/*if let navigationTransition = self.navigationTransition {
|
|
||||||
transitionSourceHeight = navigationTransition.sourceNavigationBar.backgroundNode.bounds.height
|
|
||||||
transitionFraction = navigationTransition.fraction
|
|
||||||
|
|
||||||
innerBackgroundTransitionFraction = 0.0
|
|
||||||
backgroundBannerAlpha = 1.0
|
|
||||||
|
|
||||||
if let avatarNavigationNode = navigationTransition.sourceNavigationBar.rightButtonNode.singleCustomNode as? ChatAvatarNavigationNode {
|
|
||||||
if let statusView = avatarNavigationNode.statusView.view {
|
|
||||||
transitionSourceAvatarFrame = statusView.convert(statusView.bounds, to: navigationTransition.sourceNavigationBar.view)
|
|
||||||
} else {
|
|
||||||
transitionSourceAvatarFrame = avatarNavigationNode.avatarNode.view.convert(avatarNavigationNode.avatarNode.view.bounds, to: navigationTransition.sourceNavigationBar.view)
|
|
||||||
}
|
|
||||||
transition.updateAlpha(node: self.avatarListNode.avatarContainerNode.avatarNode, alpha: 1.0 - transitionFraction)
|
|
||||||
} else {
|
|
||||||
if deviceMetrics.hasDynamicIsland && statusBarHeight > 0.0 && !isLandscape {
|
|
||||||
transitionSourceAvatarFrame = CGRect(origin: CGPoint(x: avatarFrame.minX, y: -20.0), size: avatarFrame.size).insetBy(dx: avatarSize * 0.4, dy: avatarSize * 0.4)
|
|
||||||
} else {
|
|
||||||
transitionSourceAvatarFrame = avatarFrame.offsetBy(dx: 0.0, dy: -avatarFrame.maxY).insetBy(dx: avatarSize * 0.4, dy: avatarSize * 0.4)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
transitionSourceTitleFrame = navigationTransition.sourceTitleFrame
|
|
||||||
transitionSourceSubtitleFrame = navigationTransition.sourceSubtitleFrame
|
|
||||||
|
|
||||||
transition.updateAlpha(layer: self.backgroundBannerView.layer, alpha: 1.0 - transitionFraction)
|
|
||||||
|
|
||||||
self.expandedBackgroundNode.updateColor(color: presentationData.theme.rootController.navigationBar.blurredBackgroundColor.mixedWith(headerBackgroundColor, alpha: 1.0 - transitionFraction), forceKeepBlur: true, transition: transition)
|
|
||||||
effectiveSeparatorAlpha = transitionFraction
|
|
||||||
|
|
||||||
if self.isAvatarExpanded, case .animated = transition, transitionFraction == 1.0 {
|
|
||||||
self.avatarListNode.animateAvatarCollapse(transition: transition)
|
|
||||||
}
|
|
||||||
self.avatarClippingNode.clipsToBounds = false
|
|
||||||
} else*/ do {
|
|
||||||
let backgroundTransitionStepDistance: CGFloat = 50.0
|
let backgroundTransitionStepDistance: CGFloat = 50.0
|
||||||
var backgroundTransitionDistance: CGFloat = navigationHeight + panelWithAvatarHeight - backgroundTransitionStepDistance
|
var backgroundTransitionDistance: CGFloat = navigationHeight + panelWithAvatarHeight - backgroundTransitionStepDistance
|
||||||
if self.isSettings || self.isMyProfile {
|
if self.isSettings || self.isMyProfile {
|
||||||
|
|
@ -812,9 +752,6 @@ final class PeerInfoHeaderNode: ASDisplayNode {
|
||||||
innerBackgroundTransitionFraction = max(0.0, min(1.0, contentOffset / backgroundTransitionStepDistance))
|
innerBackgroundTransitionFraction = max(0.0, min(1.0, contentOffset / backgroundTransitionStepDistance))
|
||||||
}
|
}
|
||||||
|
|
||||||
self.expandedBackgroundNode.updateColor(color: presentationData.theme.rootController.navigationBar.opaqueBackgroundColor.mixedWith(headerBackgroundColor, alpha: 1.0 - innerBackgroundTransitionFraction), forceKeepBlur: true, transition: transition)
|
|
||||||
navigationTransition.updateAlpha(node: self.expandedBackgroundNode, alpha: state.isEditing ? 0.0 : 1.0)
|
|
||||||
|
|
||||||
if state.isEditing {
|
if state.isEditing {
|
||||||
backgroundBannerAlpha = 0.0
|
backgroundBannerAlpha = 0.0
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -826,8 +763,6 @@ final class PeerInfoHeaderNode: ASDisplayNode {
|
||||||
}
|
}
|
||||||
navigationTransition.updateAlpha(layer: self.backgroundBannerView.layer, alpha: backgroundBannerAlpha)
|
navigationTransition.updateAlpha(layer: self.backgroundBannerView.layer, alpha: backgroundBannerAlpha)
|
||||||
|
|
||||||
effectiveSeparatorAlpha = innerBackgroundTransitionFraction
|
|
||||||
|
|
||||||
self.avatarClippingNode.clipsToBounds = true
|
self.avatarClippingNode.clipsToBounds = true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1161,7 +1096,10 @@ final class PeerInfoHeaderNode: ASDisplayNode {
|
||||||
self.titleExpandedVerifiedIconSize = expandedIconSize
|
self.titleExpandedVerifiedIconSize = expandedIconSize
|
||||||
}
|
}
|
||||||
|
|
||||||
self.navigationButtonContainer.updateContentsColor(backgroundContentColor: headerButtonBackgroundColor, contentsColor: navigationContentsAccentColor, canBeExpanded: navigationContentsCanBeExpanded, transition: navigationTransition)
|
var actualNavigationContentsColor = navigationContentsAccentColor
|
||||||
|
actualNavigationContentsColor = presentationData.theme.chat.inputPanel.panelControlColor
|
||||||
|
|
||||||
|
self.navigationButtonContainer.updateContentsColor(backgroundContentColor: headerButtonBackgroundColor, contentsColor: actualNavigationContentsColor, isOverColoredContents: !navigationContentsCanBeExpanded, transition: navigationTransition)
|
||||||
|
|
||||||
self.titleNode.updateTintColor(color: navigationContentsPrimaryColor, transition: navigationTransition)
|
self.titleNode.updateTintColor(color: navigationContentsPrimaryColor, transition: navigationTransition)
|
||||||
self.subtitleNode.updateTintColor(color: navigationContentsSecondaryColor, transition: navigationTransition)
|
self.subtitleNode.updateTintColor(color: navigationContentsSecondaryColor, transition: navigationTransition)
|
||||||
|
|
@ -1189,25 +1127,6 @@ final class PeerInfoHeaderNode: ASDisplayNode {
|
||||||
self.avatarListNode.listContainerNode.currentItemNode?.updateTransitionFraction(transitionFraction, transition: transition)
|
self.avatarListNode.listContainerNode.currentItemNode?.updateTransitionFraction(transitionFraction, transition: transition)
|
||||||
self.avatarOverlayNode.updateTransitionFraction(transitionFraction, transition: transition)
|
self.avatarOverlayNode.updateTransitionFraction(transitionFraction, transition: transition)
|
||||||
|
|
||||||
if self.navigationTitle != presentationData.strings.EditProfile_Title || themeUpdated {
|
|
||||||
self.navigationTitleNode.attributedText = NSAttributedString(string: presentationData.strings.EditProfile_Title, font: Font.semibold(17.0), textColor: .white)
|
|
||||||
}
|
|
||||||
|
|
||||||
let navigationTitleSize = self.navigationTitleNode.updateLayout(CGSize(width: width, height: navigationHeight))
|
|
||||||
self.navigationTitleNode.frame = CGRect(origin: CGPoint(x: floorToScreenPixels((width - navigationTitleSize.width) / 2.0), y: navigationHeight - 44.0 + floorToScreenPixels((44.0 - navigationTitleSize.height) / 2.0)), size: navigationTitleSize)
|
|
||||||
|
|
||||||
self.navigationBackgroundNode.frame = CGRect(origin: CGPoint(), size: CGSize(width: width, height: navigationHeight))
|
|
||||||
self.navigationBackgroundBackgroundNode.frame = CGRect(origin: CGPoint(), size: CGSize(width: width, height: navigationHeight))
|
|
||||||
self.navigationSeparatorNode.frame = CGRect(origin: CGPoint(x: 0.0, y: navigationHeight), size: CGSize(width: width, height: UIScreenPixel))
|
|
||||||
self.navigationBackgroundBackgroundNode.backgroundColor = presentationData.theme.rootController.navigationBar.opaqueBackgroundColor
|
|
||||||
self.navigationSeparatorNode.backgroundColor = presentationData.theme.rootController.navigationBar.separatorColor
|
|
||||||
|
|
||||||
let navigationSeparatorAlpha: CGFloat = 0.0
|
|
||||||
transition.updateAlpha(node: self.navigationBackgroundBackgroundNode, alpha: 1.0 - navigationSeparatorAlpha)
|
|
||||||
transition.updateAlpha(node: self.navigationSeparatorNode, alpha: navigationSeparatorAlpha)
|
|
||||||
|
|
||||||
self.separatorNode.backgroundColor = presentationData.theme.list.itemBlocksSeparatorColor
|
|
||||||
|
|
||||||
let expandedAvatarControlsHeight: CGFloat = 61.0
|
let expandedAvatarControlsHeight: CGFloat = 61.0
|
||||||
var expandedAvatarListHeight = min(width, containerHeight - expandedAvatarControlsHeight)
|
var expandedAvatarListHeight = min(width, containerHeight - expandedAvatarControlsHeight)
|
||||||
if self.isSettings || self.isMyProfile {
|
if self.isSettings || self.isMyProfile {
|
||||||
|
|
@ -1638,7 +1557,7 @@ final class PeerInfoHeaderNode: ASDisplayNode {
|
||||||
|
|
||||||
let singleTitleLockOffset: CGFloat = ((peer?.id == self.context.account.peerId && !self.isMyProfile) || subtitleSize.height.isZero) ? 8.0 : 0.0
|
let singleTitleLockOffset: CGFloat = ((peer?.id == self.context.account.peerId && !self.isMyProfile) || subtitleSize.height.isZero) ? 8.0 : 0.0
|
||||||
|
|
||||||
let titleLockOffset: CGFloat = 7.0 + singleTitleLockOffset
|
let titleLockOffset: CGFloat = 16.0 + singleTitleLockOffset
|
||||||
let titleMaxLockOffset: CGFloat = 7.0
|
let titleMaxLockOffset: CGFloat = 7.0
|
||||||
let titleOffset: CGFloat
|
let titleOffset: CGFloat
|
||||||
let titleCollapseFraction: CGFloat
|
let titleCollapseFraction: CGFloat
|
||||||
|
|
@ -1697,38 +1616,37 @@ final class PeerInfoHeaderNode: ASDisplayNode {
|
||||||
|
|
||||||
let paneAreaExpansionDistance: CGFloat = 32.0
|
let paneAreaExpansionDistance: CGFloat = 32.0
|
||||||
let effectiveAreaExpansionFraction: CGFloat
|
let effectiveAreaExpansionFraction: CGFloat
|
||||||
|
let realAreaExpansionFraction: CGFloat
|
||||||
if state.isEditing {
|
if state.isEditing {
|
||||||
effectiveAreaExpansionFraction = 0.0
|
effectiveAreaExpansionFraction = 0.0
|
||||||
|
realAreaExpansionFraction = effectiveAreaExpansionFraction
|
||||||
} else if isSettings || isMyProfile {
|
} else if isSettings || isMyProfile {
|
||||||
var paneAreaExpansionDelta = (self.frame.maxY - navigationHeight) - contentOffset
|
var paneAreaExpansionDelta = (self.frame.maxY - navigationHeight) - contentOffset
|
||||||
paneAreaExpansionDelta = max(0.0, min(paneAreaExpansionDelta, paneAreaExpansionDistance))
|
paneAreaExpansionDelta = max(0.0, min(paneAreaExpansionDelta, paneAreaExpansionDistance))
|
||||||
effectiveAreaExpansionFraction = 1.0 - paneAreaExpansionDelta / paneAreaExpansionDistance
|
effectiveAreaExpansionFraction = 1.0 - paneAreaExpansionDelta / paneAreaExpansionDistance
|
||||||
|
|
||||||
|
do {
|
||||||
|
var paneAreaExpansionDelta = (paneContainerY - navigationHeight) - contentOffset
|
||||||
|
paneAreaExpansionDelta = max(0.0, min(paneAreaExpansionDelta, paneAreaExpansionDistance))
|
||||||
|
realAreaExpansionFraction = 1.0 - paneAreaExpansionDelta / paneAreaExpansionDistance
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
var paneAreaExpansionDelta = (paneContainerY - navigationHeight) - contentOffset
|
var paneAreaExpansionDelta = (paneContainerY - navigationHeight) - contentOffset
|
||||||
paneAreaExpansionDelta = max(0.0, min(paneAreaExpansionDelta, paneAreaExpansionDistance))
|
paneAreaExpansionDelta = max(0.0, min(paneAreaExpansionDelta, paneAreaExpansionDistance))
|
||||||
effectiveAreaExpansionFraction = 1.0 - paneAreaExpansionDelta / paneAreaExpansionDistance
|
effectiveAreaExpansionFraction = 1.0 - paneAreaExpansionDelta / paneAreaExpansionDistance
|
||||||
|
realAreaExpansionFraction = effectiveAreaExpansionFraction
|
||||||
}
|
}
|
||||||
|
|
||||||
let secondarySeparatorAlpha = 1.0 - effectiveAreaExpansionFraction
|
|
||||||
if self.navigationTransition == nil && !self.isSettings && effectiveSeparatorAlpha == 1.0 && secondarySeparatorAlpha < 1.0 {
|
|
||||||
effectiveSeparatorAlpha = secondarySeparatorAlpha
|
|
||||||
}
|
|
||||||
if self.customNavigationContentNode != nil {
|
|
||||||
effectiveSeparatorAlpha = 0.0
|
|
||||||
}
|
|
||||||
if state.isEditing {
|
|
||||||
effectiveSeparatorAlpha = 0.0
|
|
||||||
}
|
|
||||||
transition.updateAlpha(node: self.separatorNode, alpha: effectiveSeparatorAlpha)
|
|
||||||
|
|
||||||
self.titleNode.update(stateFractions: [
|
self.titleNode.update(stateFractions: [
|
||||||
TitleNodeStateRegular: self.isAvatarExpanded ? 0.0 : 1.0,
|
TitleNodeStateRegular: self.isAvatarExpanded ? 0.0 : 1.0,
|
||||||
TitleNodeStateExpanded: self.isAvatarExpanded ? 1.0 : 0.0
|
TitleNodeStateExpanded: self.isAvatarExpanded ? 1.0 : 0.0
|
||||||
], transition: transition)
|
], transition: transition)
|
||||||
|
|
||||||
let subtitleAlpha: CGFloat
|
transition.updateAlpha(node: self.titleNode, alpha: isSearching ? 0.0 : 1.0)
|
||||||
|
|
||||||
|
var subtitleAlpha: CGFloat
|
||||||
var subtitleOffset: CGFloat = 0.0
|
var subtitleOffset: CGFloat = 0.0
|
||||||
let panelSubtitleAlpha: CGFloat
|
var panelSubtitleAlpha: CGFloat
|
||||||
var panelSubtitleOffset: CGFloat = 0.0
|
var panelSubtitleOffset: CGFloat = 0.0
|
||||||
if self.isSettings {
|
if self.isSettings {
|
||||||
subtitleAlpha = 1.0 - titleCollapseFraction
|
subtitleAlpha = 1.0 - titleCollapseFraction
|
||||||
|
|
@ -1755,6 +1673,12 @@ final class PeerInfoHeaderNode: ASDisplayNode {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if isSearching {
|
||||||
|
subtitleAlpha = 0.0
|
||||||
|
panelSubtitleAlpha = 0.0
|
||||||
|
}
|
||||||
|
|
||||||
self.subtitleNode.update(stateFractions: [
|
self.subtitleNode.update(stateFractions: [
|
||||||
TitleNodeStateRegular: self.isAvatarExpanded ? 0.0 : 1.0,
|
TitleNodeStateRegular: self.isAvatarExpanded ? 0.0 : 1.0,
|
||||||
TitleNodeStateExpanded: self.isAvatarExpanded ? 1.0 : 0.0
|
TitleNodeStateExpanded: self.isAvatarExpanded ? 1.0 : 0.0
|
||||||
|
|
@ -2465,18 +2389,15 @@ final class PeerInfoHeaderNode: ASDisplayNode {
|
||||||
}
|
}
|
||||||
|
|
||||||
let backgroundFrame: CGRect
|
let backgroundFrame: CGRect
|
||||||
let separatorFrame: CGRect
|
|
||||||
|
|
||||||
var resolvedHeight: CGFloat
|
var resolvedHeight: CGFloat
|
||||||
|
|
||||||
if state.isEditing {
|
if state.isEditing {
|
||||||
resolvedHeight = editingContentHeight
|
resolvedHeight = editingContentHeight
|
||||||
backgroundFrame = CGRect(origin: CGPoint(x: 0.0, y: -2000.0 + max(navigationHeight, resolvedHeight - contentOffset)), size: CGSize(width: width, height: 2000.0))
|
backgroundFrame = CGRect(origin: CGPoint(x: 0.0, y: -2000.0 + max(navigationHeight, resolvedHeight - contentOffset)), size: CGSize(width: width, height: 2000.0))
|
||||||
separatorFrame = CGRect(origin: CGPoint(x: 0.0, y: max(navigationHeight, resolvedHeight - contentOffset)), size: CGSize(width: width, height: UIScreenPixel))
|
|
||||||
} else {
|
} else {
|
||||||
resolvedHeight = resolvedRegularHeight
|
resolvedHeight = resolvedRegularHeight
|
||||||
backgroundFrame = CGRect(origin: CGPoint(x: 0.0, y: -2000.0 + apparentHeight), size: CGSize(width: width, height: 2000.0))
|
backgroundFrame = CGRect(origin: CGPoint(x: 0.0, y: -2000.0 + apparentHeight), size: CGSize(width: width, height: 2000.0))
|
||||||
separatorFrame = CGRect(origin: CGPoint(x: 0.0, y: apparentHeight), size: CGSize(width: width, height: UIScreenPixel))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
transition.updateFrame(node: self.regularContentNode, frame: CGRect(origin: CGPoint(), size: CGSize(width: width, height: resolvedHeight)))
|
transition.updateFrame(node: self.regularContentNode, frame: CGRect(origin: CGPoint(), size: CGSize(width: width, height: resolvedHeight)))
|
||||||
|
|
@ -2582,20 +2503,29 @@ final class PeerInfoHeaderNode: ASDisplayNode {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let edgeEffectHeight: CGFloat = 40.0
|
||||||
|
let edgeEffectFrame = CGRect(origin: CGPoint(x: 0.0, y: 0.0), size: CGSize(width: backgroundFrame.width, height: navigationHeight + 10.0))
|
||||||
|
|
||||||
|
let panelsExpansionBackgroundFrame = CGRect(origin: CGPoint(x: 0.0, y: -2000.0 + paneContainerY - contentOffset), size: CGSize(width: width, height: 2000.0))
|
||||||
|
|
||||||
if additive {
|
if additive {
|
||||||
transition.updateFrameAdditive(node: self.backgroundNode, frame: backgroundFrame)
|
transition.updateFrameAdditive(layer: self.headerEdgeEffectView.layer, frame: edgeEffectFrame)
|
||||||
self.backgroundNode.update(size: self.backgroundNode.bounds.size, transition: transition)
|
transition.updateFrameAdditive(view: self.panelsExpansionBackgroundView, frame: panelsExpansionBackgroundFrame)
|
||||||
transition.updateFrameAdditive(node: self.expandedBackgroundNode, frame: backgroundFrame)
|
|
||||||
self.expandedBackgroundNode.update(size: self.expandedBackgroundNode.bounds.size, transition: transition)
|
|
||||||
transition.updateFrameAdditive(node: self.separatorNode, frame: separatorFrame)
|
|
||||||
} else {
|
} else {
|
||||||
transition.updateFrame(node: self.backgroundNode, frame: backgroundFrame)
|
transition.updateFrame(view: self.headerEdgeEffectView, frame: edgeEffectFrame)
|
||||||
self.backgroundNode.update(size: self.backgroundNode.bounds.size, transition: transition)
|
transition.updateFrame(view: self.panelsExpansionBackgroundView, frame: panelsExpansionBackgroundFrame)
|
||||||
transition.updateFrame(node: self.expandedBackgroundNode, frame: backgroundFrame)
|
|
||||||
self.expandedBackgroundNode.update(size: self.expandedBackgroundNode.bounds.size, transition: transition)
|
|
||||||
transition.updateFrame(node: self.separatorNode, frame: separatorFrame)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
self.panelsExpansionBackgroundView.backgroundColor = presentationData.theme.rootController.navigationBar.opaqueBackgroundColor
|
||||||
|
transition.updateAlpha(layer: self.panelsExpansionBackgroundView.layer, alpha: realAreaExpansionFraction)
|
||||||
|
if isSettings {
|
||||||
|
self.panelsExpansionBackgroundView.isHidden = true
|
||||||
|
}
|
||||||
|
|
||||||
|
self.headerEdgeEffectView.update(content: presentationData.theme.rootController.navigationBar.opaqueBackgroundColor, blur: true, rect: edgeEffectFrame, edge: .top, edgeSize: edgeEffectHeight, transition: ComponentTransition(transition))
|
||||||
|
|
||||||
|
navigationTransition.updateAlpha(layer: self.headerEdgeEffectView.layer, alpha: state.isEditing ? 0.0 : 1.0)
|
||||||
|
|
||||||
if !state.isEditing {
|
if !state.isEditing {
|
||||||
if !isSettings && !isMyProfile {
|
if !isSettings && !isMyProfile {
|
||||||
if self.isAvatarExpanded {
|
if self.isAvatarExpanded {
|
||||||
|
|
@ -2775,8 +2705,13 @@ final class PeerInfoHeaderNode: ASDisplayNode {
|
||||||
guard let result = super.hitTest(point, with: event) else {
|
guard let result = super.hitTest(point, with: event) else {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
if !self.backgroundNode.frame.contains(point) {
|
|
||||||
return nil
|
if self.isSearching {
|
||||||
|
if !result.isDescendant(of: self.searchBarContainer.view) && !result.isDescendant(of: self.searchContainer.view) {
|
||||||
|
return self.view
|
||||||
|
}
|
||||||
|
|
||||||
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
if let customNavigationContentNode = self.customNavigationContentNode {
|
if let customNavigationContentNode = self.customNavigationContentNode {
|
||||||
|
|
|
||||||
|
|
@ -10622,7 +10622,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, PeerInfoScreenNodePro
|
||||||
switch status {
|
switch status {
|
||||||
case .available:
|
case .available:
|
||||||
var cameraTransitionIn: StoryCameraTransitionIn?
|
var cameraTransitionIn: StoryCameraTransitionIn?
|
||||||
if let rightButton = self.headerNode.navigationButtonContainer.rightButtonNodes[.postStory] {
|
if let rightButton = self.headerNode.navigationButtonContainer.rightButtonNodes.first(where: { $0.key.key == .postStory })?.value {
|
||||||
cameraTransitionIn = StoryCameraTransitionIn(
|
cameraTransitionIn = StoryCameraTransitionIn(
|
||||||
sourceView: rightButton.view,
|
sourceView: rightButton.view,
|
||||||
sourceRect: rightButton.view.bounds,
|
sourceRect: rightButton.view.bounds,
|
||||||
|
|
@ -11452,7 +11452,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, PeerInfoScreenNodePro
|
||||||
|
|
||||||
if self.isSettings {
|
if self.isSettings {
|
||||||
if let settings = self.data?.globalSettings {
|
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
|
self.searchDisplayController = SearchDisplayController(presentationData: self.presentationData, mode: .navigation, 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 {
|
if let strongSelf = self, let navigationController = strongSelf.controller?.navigationController as? NavigationController {
|
||||||
result.present(strongSelf.context, navigationController, { [weak self] mode, controller in
|
result.present(strongSelf.context, navigationController, { [weak self] mode, controller in
|
||||||
if let strongSelf = self {
|
if let strongSelf = self {
|
||||||
|
|
@ -11482,7 +11482,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, PeerInfoScreenNodePro
|
||||||
}, searchBarIsExternal: true)
|
}, searchBarIsExternal: true)
|
||||||
}
|
}
|
||||||
} else if let currentPaneKey = self.paneContainerNode.currentPaneKey, case .members = currentPaneKey {
|
} 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
|
self.searchDisplayController = SearchDisplayController(presentationData: self.presentationData, mode: .navigation, 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
|
||||||
self?.openPeer(peerId: peer.id, navigation: .info(nil))
|
self?.openPeer(peerId: peer.id, navigation: .info(nil))
|
||||||
}, updateActivity: { _ in
|
}, updateActivity: { _ in
|
||||||
}, pushController: { [weak self] c in
|
}, pushController: { [weak self] c in
|
||||||
|
|
@ -11583,9 +11583,9 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, PeerInfoScreenNodePro
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
self.searchDisplayController = SearchDisplayController(presentationData: self.presentationData, mode: .list, placeholder: self.presentationData.strings.Common_Search, hasBackground: true, contentNode: ChatHistorySearchContainerNode(context: self.context, peerId: self.peerId, threadId: self.chatLocation.threadId, tagMask: tagMask, interfaceInteraction: self.chatInterfaceInteraction), cancel: { [weak self] in
|
self.searchDisplayController = SearchDisplayController(presentationData: self.presentationData, mode: .navigation, placeholder: self.presentationData.strings.Common_Search, hasBackground: false, contentNode: ChatHistorySearchContainerNode(context: self.context, peerId: self.peerId, threadId: self.chatLocation.threadId, tagMask: tagMask, interfaceInteraction: self.chatInterfaceInteraction), cancel: { [weak self] in
|
||||||
self?.deactivateSearch()
|
self?.deactivateSearch()
|
||||||
})
|
}, fieldStyle: .glass)
|
||||||
}
|
}
|
||||||
|
|
||||||
let transition: ContainedViewLayoutTransition = .animated(duration: 0.2, curve: .easeInOut)
|
let transition: ContainedViewLayoutTransition = .animated(duration: 0.2, curve: .easeInOut)
|
||||||
|
|
@ -11595,8 +11595,13 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, PeerInfoScreenNodePro
|
||||||
|
|
||||||
self.searchDisplayController?.containerLayoutUpdated(layout, navigationBarHeight: navigationBarHeight, transition: .immediate)
|
self.searchDisplayController?.containerLayoutUpdated(layout, navigationBarHeight: navigationBarHeight, transition: .immediate)
|
||||||
self.searchDisplayController?.activate(insertSubnode: { [weak self] subnode, isSearchBar in
|
self.searchDisplayController?.activate(insertSubnode: { [weak self] subnode, isSearchBar in
|
||||||
if let strongSelf = self, let navigationBar = strongSelf.controller?.navigationBar {
|
guard let self else {
|
||||||
strongSelf.insertSubnode(subnode, belowSubnode: navigationBar)
|
return
|
||||||
|
}
|
||||||
|
if isSearchBar {
|
||||||
|
self.headerNode.searchBarContainer.addSubnode(subnode)
|
||||||
|
} else {
|
||||||
|
self.headerNode.searchContainer.addSubnode(subnode)
|
||||||
}
|
}
|
||||||
}, placeholder: nil)
|
}, placeholder: nil)
|
||||||
|
|
||||||
|
|
@ -11627,12 +11632,15 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, PeerInfoScreenNodePro
|
||||||
if let navigationBar = self.controller?.navigationBar {
|
if let navigationBar = self.controller?.navigationBar {
|
||||||
transition.updateAlpha(node: navigationBar, alpha: 1.0)
|
transition.updateAlpha(node: navigationBar, alpha: 1.0)
|
||||||
}
|
}
|
||||||
|
if let (layout, navigationHeight) = self.validLayout {
|
||||||
|
self.containerLayoutUpdated(layout: layout, navigationHeight: navigationHeight, transition: .animated(duration: 0.4, curve: .spring), additive: false)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private weak var mediaGalleryContextMenu: ContextController?
|
private weak var mediaGalleryContextMenu: ContextController?
|
||||||
|
|
||||||
func displaySharedMediaFastScrollingTooltip() {
|
func displaySharedMediaFastScrollingTooltip() {
|
||||||
guard let buttonNode = self.headerNode.navigationButtonContainer.rightButtonNodes[.more] else {
|
guard let buttonNode = self.headerNode.navigationButtonContainer.rightButtonNodes.first(where: { $0.key.key == .more })?.value else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
guard let controller = self.controller else {
|
guard let controller = self.controller else {
|
||||||
|
|
@ -12582,8 +12590,8 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, PeerInfoScreenNodePro
|
||||||
}
|
}
|
||||||
let headerInset = sectionInset
|
let headerInset = sectionInset
|
||||||
|
|
||||||
let headerHeight = self.headerNode.update(width: layout.size.width, containerHeight: layout.size.height, containerInset: headerInset, statusBarHeight: layout.statusBarHeight ?? 0.0, navigationHeight: navigationHeight, isModalOverlay: layout.isModalOverlay, isMediaOnly: self.isMediaOnly, contentOffset: self.isMediaOnly ? 212.0 : self.scrollNode.view.contentOffset.y, paneContainerY: self.paneContainerNode.frame.minY, presentationData: self.presentationData, peer: self.data?.savedMessagesPeer ?? self.data?.peer, cachedData: self.data?.cachedData, threadData: self.data?.threadData, peerNotificationSettings: self.data?.peerNotificationSettings, threadNotificationSettings: self.data?.threadNotificationSettings, globalNotificationSettings: self.data?.globalNotificationSettings, statusData: self.data?.status, panelStatusData: self.customStatusData, isSecretChat: self.peerId.namespace == Namespaces.Peer.SecretChat, isContact: self.data?.isContact ?? false, isSettings: self.isSettings, state: self.state, profileGiftsContext: self.data?.profileGiftsContext, screenData: self.data, metrics: layout.metrics, deviceMetrics: layout.deviceMetrics, transition: self.headerNode.navigationTransition == nil ? transition : .immediate, additive: additive, animateHeader: transition.isAnimated && self.headerNode.navigationTransition == nil)
|
let headerHeight = self.headerNode.update(width: layout.size.width, containerHeight: layout.size.height, containerInset: headerInset, statusBarHeight: layout.statusBarHeight ?? 0.0, navigationHeight: navigationHeight, isModalOverlay: layout.isModalOverlay, isMediaOnly: self.isMediaOnly, contentOffset: self.isMediaOnly ? 212.0 : self.scrollNode.view.contentOffset.y, paneContainerY: self.paneContainerNode.frame.minY, presentationData: self.presentationData, peer: self.data?.savedMessagesPeer ?? self.data?.peer, cachedData: self.data?.cachedData, threadData: self.data?.threadData, peerNotificationSettings: self.data?.peerNotificationSettings, threadNotificationSettings: self.data?.threadNotificationSettings, globalNotificationSettings: self.data?.globalNotificationSettings, statusData: self.data?.status, panelStatusData: self.customStatusData, isSecretChat: self.peerId.namespace == Namespaces.Peer.SecretChat, isContact: self.data?.isContact ?? false, isSettings: self.isSettings, state: self.state, profileGiftsContext: self.data?.profileGiftsContext, screenData: self.data, isSearching: self.searchDisplayController != nil, metrics: layout.metrics, deviceMetrics: layout.deviceMetrics, transition: self.headerNode.navigationTransition == nil ? transition : .immediate, additive: additive, animateHeader: transition.isAnimated && self.headerNode.navigationTransition == nil)
|
||||||
let headerFrame = CGRect(origin: CGPoint(x: 0.0, y: contentHeight), size: CGSize(width: layout.size.width, height: headerHeight))
|
let headerFrame = CGRect(origin: CGPoint(x: 0.0, y: contentHeight), size: CGSize(width: layout.size.width, height: layout.size.height))
|
||||||
if additive {
|
if additive {
|
||||||
transition.updateFrameAdditive(node: self.headerNode, frame: headerFrame)
|
transition.updateFrameAdditive(node: self.headerNode, frame: headerFrame)
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -12967,7 +12975,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, PeerInfoScreenNodePro
|
||||||
}
|
}
|
||||||
let headerInset = sectionInset
|
let headerInset = sectionInset
|
||||||
|
|
||||||
let _ = self.headerNode.update(width: layout.size.width, containerHeight: layout.size.height, containerInset: headerInset, statusBarHeight: layout.statusBarHeight ?? 0.0, navigationHeight: navigationHeight, isModalOverlay: layout.isModalOverlay, isMediaOnly: self.isMediaOnly, contentOffset: self.isMediaOnly ? 212.0 : offsetY, paneContainerY: self.paneContainerNode.frame.minY, presentationData: self.presentationData, peer: self.data?.savedMessagesPeer ?? self.data?.peer, cachedData: self.data?.cachedData, threadData: self.data?.threadData, peerNotificationSettings: self.data?.peerNotificationSettings, threadNotificationSettings: self.data?.threadNotificationSettings, globalNotificationSettings: self.data?.globalNotificationSettings, statusData: self.data?.status, panelStatusData: self.customStatusData, isSecretChat: self.peerId.namespace == Namespaces.Peer.SecretChat, isContact: self.data?.isContact ?? false, isSettings: self.isSettings, state: self.state, profileGiftsContext: self.data?.profileGiftsContext, screenData: self.data, metrics: layout.metrics, deviceMetrics: layout.deviceMetrics, transition: self.headerNode.navigationTransition == nil ? transition : .immediate, additive: additive, animateHeader: animateHeader && self.headerNode.navigationTransition == nil)
|
let _ = self.headerNode.update(width: layout.size.width, containerHeight: layout.size.height, containerInset: headerInset, statusBarHeight: layout.statusBarHeight ?? 0.0, navigationHeight: navigationHeight, isModalOverlay: layout.isModalOverlay, isMediaOnly: self.isMediaOnly, contentOffset: self.isMediaOnly ? 212.0 : offsetY, paneContainerY: self.paneContainerNode.frame.minY, presentationData: self.presentationData, peer: self.data?.savedMessagesPeer ?? self.data?.peer, cachedData: self.data?.cachedData, threadData: self.data?.threadData, peerNotificationSettings: self.data?.peerNotificationSettings, threadNotificationSettings: self.data?.threadNotificationSettings, globalNotificationSettings: self.data?.globalNotificationSettings, statusData: self.data?.status, panelStatusData: self.customStatusData, isSecretChat: self.peerId.namespace == Namespaces.Peer.SecretChat, isContact: self.data?.isContact ?? false, isSettings: self.isSettings, state: self.state, profileGiftsContext: self.data?.profileGiftsContext, screenData: self.data, isSearching: self.searchDisplayController != nil, metrics: layout.metrics, deviceMetrics: layout.deviceMetrics, transition: self.headerNode.navigationTransition == nil ? transition : .immediate, additive: additive, animateHeader: animateHeader && self.headerNode.navigationTransition == nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
let paneAreaExpansionDistance: CGFloat = 32.0
|
let paneAreaExpansionDistance: CGFloat = 32.0
|
||||||
|
|
@ -12996,11 +13004,14 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, PeerInfoScreenNodePro
|
||||||
disableTabSwitching = true
|
disableTabSwitching = true
|
||||||
}
|
}
|
||||||
|
|
||||||
let navigationBarHeight: CGFloat = !self.isSettings && layout.isModalOverlay ? 56.0 : 44.0
|
let navigationBarHeight: CGFloat = !self.isSettings && layout.isModalOverlay ? 68.0 : 60.0
|
||||||
self.paneContainerNode.update(size: self.paneContainerNode.bounds.size, sideInset: layout.safeInsets.left, bottomInset: bottomInset, deviceMetrics: layout.deviceMetrics, visibleHeight: visibleHeight, expansionFraction: effectiveAreaExpansionFraction, presentationData: self.presentationData, data: self.data, areTabsHidden: self.headerNode.customNavigationContentNode != nil, disableTabSwitching: disableTabSwitching, navigationHeight: navigationHeight, transition: transition)
|
self.paneContainerNode.update(size: self.paneContainerNode.bounds.size, sideInset: layout.safeInsets.left, bottomInset: bottomInset, deviceMetrics: layout.deviceMetrics, visibleHeight: visibleHeight, expansionFraction: effectiveAreaExpansionFraction, presentationData: self.presentationData, data: self.data, areTabsHidden: self.headerNode.customNavigationContentNode != nil, disableTabSwitching: disableTabSwitching, navigationHeight: navigationHeight, transition: transition)
|
||||||
|
|
||||||
transition.updateFrame(node: self.headerNode.navigationButtonContainer, frame: CGRect(origin: CGPoint(x: layout.safeInsets.left, y: layout.statusBarHeight ?? 0.0), size: CGSize(width: layout.size.width - layout.safeInsets.left * 2.0, height: navigationBarHeight)))
|
transition.updateFrame(node: self.headerNode.navigationButtonContainer, frame: CGRect(origin: CGPoint(x: layout.safeInsets.left, y: layout.statusBarHeight ?? 0.0), size: CGSize(width: layout.size.width - layout.safeInsets.left * 2.0, height: navigationBarHeight)))
|
||||||
|
var searchBarContainerY: CGFloat = layout.statusBarHeight ?? 0.0
|
||||||
|
searchBarContainerY += floor((navigationBarHeight - 44.0) * 0.5) + 2.0
|
||||||
|
transition.updateFrame(node: self.headerNode.searchBarContainer, frame: CGRect(origin: CGPoint(x: layout.safeInsets.left, y: searchBarContainerY), size: CGSize(width: layout.size.width - layout.safeInsets.left * 2.0, height: navigationBarHeight)))
|
||||||
|
transition.updateFrame(node: self.headerNode.searchContainer, frame: CGRect(origin: CGPoint(), size: layout.size))
|
||||||
|
|
||||||
var leftNavigationButtons: [PeerInfoHeaderNavigationButtonSpec] = []
|
var leftNavigationButtons: [PeerInfoHeaderNavigationButtonSpec] = []
|
||||||
var rightNavigationButtons: [PeerInfoHeaderNavigationButtonSpec] = []
|
var rightNavigationButtons: [PeerInfoHeaderNavigationButtonSpec] = []
|
||||||
|
|
@ -13074,6 +13085,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, PeerInfoScreenNodePro
|
||||||
switch previousItem {
|
switch previousItem {
|
||||||
case .close, .item:
|
case .close, .item:
|
||||||
leftNavigationButtons.append(PeerInfoHeaderNavigationButtonSpec(key: .back, isForExpandedView: false))
|
leftNavigationButtons.append(PeerInfoHeaderNavigationButtonSpec(key: .back, isForExpandedView: false))
|
||||||
|
leftNavigationButtons.append(PeerInfoHeaderNavigationButtonSpec(key: .back, isForExpandedView: true))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
self.headerNode.navigationButtonContainer.update(size: CGSize(width: layout.size.width - layout.safeInsets.left * 2.0, height: navigationBarHeight), presentationData: self.presentationData, leftButtons: leftNavigationButtons, rightButtons: rightNavigationButtons, expandFraction: effectiveAreaExpansionFraction, shouldAnimateIn: animateHeader, transition: transition)
|
self.headerNode.navigationButtonContainer.update(size: CGSize(width: layout.size.width - layout.safeInsets.left * 2.0, height: navigationBarHeight), presentationData: self.presentationData, leftButtons: leftNavigationButtons, rightButtons: rightNavigationButtons, expandFraction: effectiveAreaExpansionFraction, shouldAnimateIn: animateHeader, transition: transition)
|
||||||
|
|
@ -14597,7 +14609,7 @@ private final class PeerInfoNavigationTransitionNode: ASDisplayNode, CustomNavig
|
||||||
}
|
}
|
||||||
let headerInset = sectionInset
|
let headerInset = sectionInset
|
||||||
|
|
||||||
topHeight = self.headerNode.update(width: layout.size.width, containerHeight: layout.size.height, containerInset: headerInset, statusBarHeight: layout.statusBarHeight ?? 0.0, navigationHeight: topNavigationBar.bounds.height, isModalOverlay: layout.isModalOverlay, isMediaOnly: false, contentOffset: 0.0, paneContainerY: 0.0, presentationData: self.presentationData, peer: self.screenNode.data?.savedMessagesPeer ?? self.screenNode.data?.peer, cachedData: self.screenNode.data?.cachedData, threadData: self.screenNode.data?.threadData, peerNotificationSettings: self.screenNode.data?.peerNotificationSettings, threadNotificationSettings: self.screenNode.data?.threadNotificationSettings, globalNotificationSettings: self.screenNode.data?.globalNotificationSettings, statusData: self.screenNode.data?.status, panelStatusData: (nil, nil, nil), isSecretChat: self.screenNode.peerId.namespace == Namespaces.Peer.SecretChat, isContact: self.screenNode.data?.isContact ?? false, isSettings: self.screenNode.isSettings, state: self.screenNode.state, profileGiftsContext: self.screenNode.data?.profileGiftsContext, screenData: self.screenNode.data, metrics: layout.metrics, deviceMetrics: layout.deviceMetrics, transition: transition, additive: false, animateHeader: false)
|
topHeight = self.headerNode.update(width: layout.size.width, containerHeight: layout.size.height, containerInset: headerInset, statusBarHeight: layout.statusBarHeight ?? 0.0, navigationHeight: topNavigationBar.bounds.height, isModalOverlay: layout.isModalOverlay, isMediaOnly: false, contentOffset: 0.0, paneContainerY: 0.0, presentationData: self.presentationData, peer: self.screenNode.data?.savedMessagesPeer ?? self.screenNode.data?.peer, cachedData: self.screenNode.data?.cachedData, threadData: self.screenNode.data?.threadData, peerNotificationSettings: self.screenNode.data?.peerNotificationSettings, threadNotificationSettings: self.screenNode.data?.threadNotificationSettings, globalNotificationSettings: self.screenNode.data?.globalNotificationSettings, statusData: self.screenNode.data?.status, panelStatusData: (nil, nil, nil), isSecretChat: self.screenNode.peerId.namespace == Namespaces.Peer.SecretChat, isContact: self.screenNode.data?.isContact ?? false, isSettings: self.screenNode.isSettings, state: self.screenNode.state, profileGiftsContext: self.screenNode.data?.profileGiftsContext, screenData: self.screenNode.data, isSearching: false, metrics: layout.metrics, deviceMetrics: layout.deviceMetrics, transition: transition, additive: false, animateHeader: false)
|
||||||
}
|
}
|
||||||
|
|
||||||
let titleScale = (fraction * previousTitleNode.view.bounds.height + (1.0 - fraction) * self.headerNode.titleNodeRawContainer.bounds.height) / previousTitleNode.view.bounds.height
|
let titleScale = (fraction * previousTitleNode.view.bounds.height + (1.0 - fraction) * self.headerNode.titleNodeRawContainer.bounds.height) / previousTitleNode.view.bounds.height
|
||||||
|
|
|
||||||
|
|
@ -1020,6 +1020,7 @@ final class QuickReplySetupScreenComponent: Component {
|
||||||
let searchBarTheme = SearchBarNodeTheme(theme: environment.theme, hasSeparator: false)
|
let searchBarTheme = SearchBarNodeTheme(theme: environment.theme, hasSeparator: false)
|
||||||
searchBarNode = SearchBarNode(
|
searchBarNode = SearchBarNode(
|
||||||
theme: searchBarTheme,
|
theme: searchBarTheme,
|
||||||
|
presentationTheme: environment.theme,
|
||||||
strings: environment.strings,
|
strings: environment.strings,
|
||||||
fieldStyle: .modern,
|
fieldStyle: .modern,
|
||||||
displayBackground: false
|
displayBackground: false
|
||||||
|
|
|
||||||
|
|
@ -478,6 +478,7 @@ final class PeerSelectionScreenComponent: Component {
|
||||||
let searchBarTheme = SearchBarNodeTheme(theme: environment.theme, hasSeparator: false)
|
let searchBarTheme = SearchBarNodeTheme(theme: environment.theme, hasSeparator: false)
|
||||||
searchBarNode = SearchBarNode(
|
searchBarNode = SearchBarNode(
|
||||||
theme: searchBarTheme,
|
theme: searchBarTheme,
|
||||||
|
presentationTheme: environment.theme,
|
||||||
strings: environment.strings,
|
strings: environment.strings,
|
||||||
fieldStyle: .modern,
|
fieldStyle: .modern,
|
||||||
displayBackground: false
|
displayBackground: false
|
||||||
|
|
|
||||||
|
|
@ -206,6 +206,7 @@ public final class NavigationSearchView: UIView {
|
||||||
accent: params.theme.chat.inputPanel.panelControlAccentColor,
|
accent: params.theme.chat.inputPanel.panelControlAccentColor,
|
||||||
keyboard: params.theme.rootController.keyboardColor
|
keyboard: params.theme.rootController.keyboardColor
|
||||||
),
|
),
|
||||||
|
presentationTheme: params.theme,
|
||||||
strings: params.strings,
|
strings: params.strings,
|
||||||
fieldStyle: .inlineNavigation,
|
fieldStyle: .inlineNavigation,
|
||||||
icon: .loupe,
|
icon: .loupe,
|
||||||
|
|
|
||||||
|
|
@ -573,7 +573,7 @@ final class ContactsSearchNavigationContentNode: NavigationBarContentNode {
|
||||||
init(presentationData: PresentationData, dismissSearch: @escaping () -> Void, updateSearchQuery: @escaping (String) -> Void) {
|
init(presentationData: PresentationData, dismissSearch: @escaping () -> Void, updateSearchQuery: @escaping (String) -> Void) {
|
||||||
self.presentationData = presentationData
|
self.presentationData = presentationData
|
||||||
|
|
||||||
self.searchBar = SearchBarNode(theme: SearchBarNodeTheme(theme: presentationData.theme, hasSeparator: false), strings: presentationData.strings, fieldStyle: .modern)
|
self.searchBar = SearchBarNode(theme: SearchBarNodeTheme(theme: presentationData.theme, hasSeparator: false), presentationTheme: presentationData.theme, strings: presentationData.strings, fieldStyle: .modern)
|
||||||
self.searchBar.placeholderString = NSAttributedString(string: presentationData.strings.Common_Search, font: searchBarFont, textColor: presentationData.theme.rootController.navigationSearchBar.inputPlaceholderTextColor)
|
self.searchBar.placeholderString = NSAttributedString(string: presentationData.strings.Common_Search, font: searchBarFont, textColor: presentationData.theme.rootController.navigationSearchBar.inputPlaceholderTextColor)
|
||||||
|
|
||||||
super.init()
|
super.init()
|
||||||
|
|
@ -617,7 +617,7 @@ final class ContactsSearchNavigationContentNode: NavigationBarContentNode {
|
||||||
|
|
||||||
func updatePresentationData(_ presentationData: PresentationData) {
|
func updatePresentationData(_ presentationData: PresentationData) {
|
||||||
self.presentationData = presentationData
|
self.presentationData = presentationData
|
||||||
self.searchBar.updateThemeAndStrings(theme: SearchBarNodeTheme(theme: presentationData.theme, hasSeparator: false), strings: presentationData.strings)
|
self.searchBar.updateThemeAndStrings(theme: SearchBarNodeTheme(theme: presentationData.theme, hasSeparator: false), presentationTheme: presentationData.theme, strings: presentationData.strings)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -22,7 +22,7 @@ final class WebSearchNavigationContentNode: NavigationBarContentNode {
|
||||||
self.theme = theme
|
self.theme = theme
|
||||||
self.strings = strings
|
self.strings = strings
|
||||||
|
|
||||||
self.searchBar = SearchBarNode(theme: SearchBarNodeTheme(theme: theme, hasSeparator: false), strings: strings, fieldStyle: .modern, displayBackground: !attachment)
|
self.searchBar = SearchBarNode(theme: SearchBarNodeTheme(theme: theme, hasSeparator: false), presentationTheme: theme, strings: strings, fieldStyle: .modern, displayBackground: !attachment)
|
||||||
self.searchBar.hasCancelButton = attachment
|
self.searchBar.hasCancelButton = attachment
|
||||||
self.searchBar.placeholderString = NSAttributedString(string: attachment ? strings.Attachment_SearchWeb : strings.Common_Search, font: searchBarFont, textColor: theme.rootController.navigationSearchBar.inputPlaceholderTextColor)
|
self.searchBar.placeholderString = NSAttributedString(string: attachment ? strings.Attachment_SearchWeb : strings.Common_Search, font: searchBarFont, textColor: theme.rootController.navigationSearchBar.inputPlaceholderTextColor)
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue