mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2026-02-09 04:44:55 +00:00
228 lines
10 KiB
Swift
228 lines
10 KiB
Swift
import Foundation
|
|
import UIKit
|
|
import AsyncDisplayKit
|
|
import Display
|
|
import Postbox
|
|
import TelegramCore
|
|
import TelegramPresentationData
|
|
import ItemListUI
|
|
import PresentationDataUtils
|
|
import SearchBarNode
|
|
import GlassBackgroundComponent
|
|
import ComponentFlow
|
|
import ComponentDisplayAdapters
|
|
import AppBundle
|
|
import ActivityIndicator
|
|
|
|
private let searchBarFont = Font.regular(17.0)
|
|
|
|
final class GroupStickerSearchNavigationContentNode: NavigationBarContentNode, ItemListControllerSearchNavigationContentNode {
|
|
private struct Params: Equatable {
|
|
let size: CGSize
|
|
let leftInset: CGFloat
|
|
let rightInset: CGFloat
|
|
|
|
init(size: CGSize, leftInset: CGFloat, rightInset: CGFloat) {
|
|
self.size = size
|
|
self.leftInset = leftInset
|
|
self.rightInset = rightInset
|
|
}
|
|
}
|
|
|
|
private var theme: PresentationTheme
|
|
private let strings: PresentationStrings
|
|
|
|
private let cancel: () -> Void
|
|
|
|
private let backgroundContainer: GlassBackgroundContainerView
|
|
private let backgroundView: GlassBackgroundView
|
|
private let iconView: UIImageView
|
|
private var activityIndicator: ActivityIndicator?
|
|
private let searchBar: SearchBarNode
|
|
private let close: (background: GlassBackgroundView, icon: UIImageView)
|
|
|
|
private var params: Params?
|
|
|
|
private var queryUpdated: ((String) -> Void)?
|
|
var activity: Bool = false {
|
|
didSet {
|
|
if self.activity != oldValue {
|
|
if let params = self.params {
|
|
self.updateLayout(size: params.size, leftInset: params.leftInset, rightInset: params.rightInset, transition: .immediate)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
init(theme: PresentationTheme, strings: PresentationStrings, cancel: @escaping () -> Void, updateActivity: @escaping(@escaping(Bool)->Void) -> Void) {
|
|
self.theme = theme
|
|
self.strings = strings
|
|
|
|
self.cancel = cancel
|
|
|
|
self.backgroundContainer = GlassBackgroundContainerView()
|
|
self.backgroundView = GlassBackgroundView()
|
|
self.backgroundContainer.contentView.addSubview(self.backgroundView)
|
|
self.iconView = UIImageView()
|
|
self.backgroundView.contentView.addSubview(self.iconView)
|
|
|
|
self.close = (GlassBackgroundView(), UIImageView())
|
|
self.close.background.contentView.addSubview(self.close.icon)
|
|
|
|
self.searchBar = SearchBarNode(
|
|
theme: SearchBarNodeTheme(
|
|
background: .clear,
|
|
separator: .clear,
|
|
inputFill: .clear,
|
|
primaryText: theme.chat.inputPanel.panelControlColor,
|
|
placeholder: theme.chat.inputPanel.inputPlaceholderColor,
|
|
inputIcon: theme.chat.inputPanel.inputControlColor,
|
|
inputClear: theme.chat.inputPanel.inputControlColor,
|
|
accent: theme.chat.inputPanel.panelControlAccentColor,
|
|
keyboard: theme.rootController.keyboardColor
|
|
),
|
|
strings: strings,
|
|
fieldStyle: .inlineNavigation,
|
|
forceSeparator: false,
|
|
displayBackground: false,
|
|
cancelText: nil
|
|
)
|
|
|
|
super.init()
|
|
|
|
self.view.addSubview(self.backgroundContainer)
|
|
self.backgroundView.contentView.addSubview(self.searchBar.view)
|
|
|
|
self.backgroundContainer.contentView.addSubview(self.close.background)
|
|
self.close.background.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(self.onCloseTapGesture(_:))))
|
|
|
|
self.searchBar.cancel = { [weak self] in
|
|
self?.searchBar.deactivate(clear: false)
|
|
self?.cancel()
|
|
}
|
|
|
|
self.searchBar.textUpdated = { [weak self] query, _ in
|
|
self?.queryUpdated?(query)
|
|
}
|
|
|
|
updateActivity({ [weak self] value in
|
|
guard let self else {
|
|
return
|
|
}
|
|
self.activity = value
|
|
})
|
|
|
|
self.updatePlaceholder()
|
|
}
|
|
|
|
@objc private func onCloseTapGesture(_ recognizer: UITapGestureRecognizer) {
|
|
if case .ended = recognizer.state {
|
|
self.searchBar.cancel?()
|
|
}
|
|
}
|
|
|
|
func setQueryUpdated(_ f: @escaping (String) -> Void) {
|
|
self.queryUpdated = f
|
|
}
|
|
|
|
func updateTheme(_ theme: PresentationTheme) {
|
|
self.theme = theme
|
|
self.searchBar.updateThemeAndStrings(theme: SearchBarNodeTheme(theme: self.theme), strings: self.strings)
|
|
self.updatePlaceholder()
|
|
}
|
|
|
|
func updatePlaceholder() {
|
|
self.searchBar.placeholderString = NSAttributedString(string: self.strings.Common_Search, font: searchBarFont, textColor: self.theme.rootController.navigationSearchBar.inputPlaceholderTextColor)
|
|
}
|
|
|
|
override var nominalHeight: CGFloat {
|
|
return 60.0
|
|
}
|
|
|
|
override func updateLayout(size: CGSize, leftInset: CGFloat, rightInset: CGFloat, transition: ContainedViewLayoutTransition) {
|
|
self.params = Params(size: size, leftInset: leftInset, rightInset: rightInset)
|
|
|
|
let transition = ComponentTransition(transition)
|
|
|
|
let backgroundFrame = CGRect(origin: CGPoint(x: leftInset + 16.0, y: 6.0), size: CGSize(width: size.width - 16.0 * 2.0 - leftInset - rightInset - 44.0 - 8.0, height: 44.0))
|
|
let closeFrame = CGRect(origin: CGPoint(x: size.width - 16.0 - rightInset - 44.0, y: backgroundFrame.minY), size: CGSize(width: 44.0, height: 44.0))
|
|
|
|
transition.setFrame(view: self.backgroundContainer, frame: CGRect(origin: CGPoint(), size: size))
|
|
self.backgroundContainer.update(size: size, isDark: self.theme.overallDarkAppearance, transition: transition)
|
|
|
|
transition.setFrame(view: self.backgroundView, frame: backgroundFrame)
|
|
self.backgroundView.update(size: backgroundFrame.size, cornerRadius: backgroundFrame.height * 0.5, isDark: self.theme.overallDarkAppearance, tintColor: .init(kind: .panel, color: UIColor(white: self.theme.overallDarkAppearance ? 0.0 : 1.0, alpha: 0.6)), isInteractive: true, transition: transition)
|
|
|
|
if self.iconView.image == nil {
|
|
self.iconView.image = UIImage(bundleImageName: "Navigation/Search")?.withRenderingMode(.alwaysTemplate)
|
|
}
|
|
transition.setTintColor(view: self.iconView, color: self.theme.rootController.navigationSearchBar.inputIconColor)
|
|
|
|
if let image = self.iconView.image {
|
|
let imageSize: CGSize
|
|
let iconFrame: CGRect
|
|
let iconFraction: CGFloat = 0.8
|
|
imageSize = CGSize(width: image.size.width * iconFraction, height: image.size.height * iconFraction)
|
|
iconFrame = CGRect(origin: CGPoint(x: 12.0, y: floor((backgroundFrame.height - imageSize.height) * 0.5)), size: imageSize)
|
|
transition.setPosition(view: self.iconView, position: iconFrame.center)
|
|
transition.setBounds(view: self.iconView, bounds: CGRect(origin: CGPoint(), size: iconFrame.size))
|
|
}
|
|
|
|
if self.activity {
|
|
let activityIndicator: ActivityIndicator
|
|
if let current = self.activityIndicator {
|
|
activityIndicator = current
|
|
} else {
|
|
activityIndicator = ActivityIndicator(type: .custom(self.theme.chat.inputPanel.inputControlColor, 14.0, 14.0, false))
|
|
self.activityIndicator = activityIndicator
|
|
self.backgroundView.contentView.addSubview(activityIndicator.view)
|
|
}
|
|
let indicatorSize = activityIndicator.measure(CGSize(width: 32.0, height: 32.0))
|
|
let indicatorFrame = CGRect(origin: CGPoint(x: 15.0, y: floorToScreenPixels((backgroundFrame.height - indicatorSize.height) * 0.5)), size: indicatorSize)
|
|
transition.setPosition(view: activityIndicator.view, position: indicatorFrame.center)
|
|
transition.setBounds(view: activityIndicator.view, bounds: CGRect(origin: CGPoint(), size: indicatorFrame.size))
|
|
} else if let activityIndicator = self.activityIndicator {
|
|
self.activityIndicator = nil
|
|
activityIndicator.view.removeFromSuperview()
|
|
}
|
|
self.iconView.isHidden = self.activity
|
|
|
|
let searchBarFrame = CGRect(origin: CGPoint(x: 36.0, y: 0.0), size: CGSize(width: backgroundFrame.width - 36.0 - 4.0, height: 44.0))
|
|
transition.setFrame(view: self.searchBar.view, frame: searchBarFrame)
|
|
self.searchBar.updateLayout(boundingSize: searchBarFrame.size, leftInset: 0.0, rightInset: 0.0, transition: transition.containedViewLayoutTransition)
|
|
|
|
if self.close.icon.image == nil {
|
|
self.close.icon.image = generateImage(CGSize(width: 40.0, height: 40.0), contextGenerator: { size, context in
|
|
context.clear(CGRect(origin: CGPoint(), size: size))
|
|
|
|
context.setLineWidth(2.0)
|
|
context.setLineCap(.round)
|
|
context.setStrokeColor(UIColor.white.cgColor)
|
|
|
|
context.beginPath()
|
|
context.move(to: CGPoint(x: 12.0, y: 12.0))
|
|
context.addLine(to: CGPoint(x: size.width - 12.0, y: size.height - 12.0))
|
|
context.move(to: CGPoint(x: size.width - 12.0, y: 12.0))
|
|
context.addLine(to: CGPoint(x: 12.0, y: size.height - 12.0))
|
|
context.strokePath()
|
|
})?.withRenderingMode(.alwaysTemplate)
|
|
}
|
|
|
|
if let image = close.icon.image {
|
|
self.close.icon.frame = image.size.centered(in: CGRect(origin: CGPoint(), size: closeFrame.size))
|
|
}
|
|
self.close.icon.tintColor = self.theme.chat.inputPanel.panelControlColor
|
|
|
|
transition.setFrame(view: self.close.background, frame: closeFrame)
|
|
self.close.background.update(size: closeFrame.size, cornerRadius: closeFrame.height * 0.5, isDark: self.theme.overallDarkAppearance, tintColor: .init(kind: .panel, color: UIColor(white: self.theme.overallDarkAppearance ? 0.0 : 1.0, alpha: 0.6)), isInteractive: true, transition: transition)
|
|
}
|
|
|
|
func activate() {
|
|
self.searchBar.activate()
|
|
}
|
|
|
|
func deactivate() {
|
|
self.searchBar.deactivate(clear: false)
|
|
}
|
|
}
|