mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-06-16 05:55:20 +00:00
Fix search results gallery loading
This commit is contained in:
parent
7c7760fc5d
commit
d10e98b395
@ -5742,9 +5742,6 @@ Any member of this group will be able to see messages in the channel.";
|
|||||||
|
|
||||||
"Call.AccountIsLoggedOnCurrentDevice" = "Sorry, you can't call %@ because that account is logged in to Telegram on the device you're using for the call.";
|
"Call.AccountIsLoggedOnCurrentDevice" = "Sorry, you can't call %@ because that account is logged in to Telegram on the device you're using for the call.";
|
||||||
|
|
||||||
"ChatList.Search.SearchBeforeDate" = "Search before %@";
|
|
||||||
"ChatList.Search.SearchAfterDate" = "Search after %@";
|
|
||||||
|
|
||||||
"ChatList.Search.FilterMedia" = "Media";
|
"ChatList.Search.FilterMedia" = "Media";
|
||||||
"ChatList.Search.FilterPhotos" = "Photos";
|
"ChatList.Search.FilterPhotos" = "Photos";
|
||||||
"ChatList.Search.FilterVideos" = "Video";
|
"ChatList.Search.FilterVideos" = "Video";
|
||||||
|
@ -1,424 +0,0 @@
|
|||||||
import Foundation
|
|
||||||
import UIKit
|
|
||||||
import Display
|
|
||||||
import AsyncDisplayKit
|
|
||||||
import Postbox
|
|
||||||
import TelegramCore
|
|
||||||
import SyncCore
|
|
||||||
import SwiftSignalKit
|
|
||||||
import AccountContext
|
|
||||||
import TelegramPresentationData
|
|
||||||
import TelegramStringFormatting
|
|
||||||
import SolidRoundedButtonNode
|
|
||||||
import PresentationDataUtils
|
|
||||||
|
|
||||||
final class ChatListDatePickerScreen: ViewController {
|
|
||||||
private var controllerNode: ChatListDatePickerScreenNode {
|
|
||||||
return self.displayNode as! ChatListDatePickerScreenNode
|
|
||||||
}
|
|
||||||
|
|
||||||
private var animatedIn = false
|
|
||||||
|
|
||||||
private let context: AccountContext
|
|
||||||
private let dismissByTapOutside: Bool
|
|
||||||
private let completion: (Int32?, Bool) -> Void
|
|
||||||
|
|
||||||
private var presentationDataDisposable: Disposable?
|
|
||||||
|
|
||||||
init(context: AccountContext, dismissByTapOutside: Bool = true, completion: @escaping (Int32?, Bool) -> Void) {
|
|
||||||
self.context = context
|
|
||||||
self.dismissByTapOutside = dismissByTapOutside
|
|
||||||
self.completion = completion
|
|
||||||
|
|
||||||
super.init(navigationBarPresentationData: nil)
|
|
||||||
|
|
||||||
self.statusBar.statusBarStyle = .Ignore
|
|
||||||
|
|
||||||
self.blocksBackgroundWhenInOverlay = true
|
|
||||||
|
|
||||||
self.presentationDataDisposable = (context.sharedContext.presentationData
|
|
||||||
|> deliverOnMainQueue).start(next: { [weak self] presentationData in
|
|
||||||
if let strongSelf = self {
|
|
||||||
strongSelf.controllerNode.updatePresentationData(presentationData)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
self.statusBar.statusBarStyle = .Ignore
|
|
||||||
}
|
|
||||||
|
|
||||||
required init(coder aDecoder: NSCoder) {
|
|
||||||
fatalError("init(coder:) has not been implemented")
|
|
||||||
}
|
|
||||||
|
|
||||||
deinit {
|
|
||||||
self.presentationDataDisposable?.dispose()
|
|
||||||
}
|
|
||||||
|
|
||||||
override public func loadDisplayNode() {
|
|
||||||
self.displayNode = ChatListDatePickerScreenNode(context: self.context, dismissByTapOutside: self.dismissByTapOutside)
|
|
||||||
self.controllerNode.completion = { [weak self] date, after in
|
|
||||||
guard let strongSelf = self else {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
strongSelf.completion(date, after)
|
|
||||||
strongSelf.dismiss()
|
|
||||||
}
|
|
||||||
self.controllerNode.dismiss = { [weak self] in
|
|
||||||
self?.presentingViewController?.dismiss(animated: false, completion: nil)
|
|
||||||
}
|
|
||||||
self.controllerNode.cancel = { [weak self] in
|
|
||||||
self?.dismiss()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override public func loadView() {
|
|
||||||
super.loadView()
|
|
||||||
}
|
|
||||||
|
|
||||||
override public func viewDidAppear(_ animated: Bool) {
|
|
||||||
super.viewDidAppear(animated)
|
|
||||||
|
|
||||||
if !self.animatedIn {
|
|
||||||
self.animatedIn = true
|
|
||||||
self.controllerNode.animateIn()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override public func dismiss(completion: (() -> Void)? = nil) {
|
|
||||||
self.controllerNode.animateOut(completion: completion)
|
|
||||||
}
|
|
||||||
|
|
||||||
override public func containerLayoutUpdated(_ layout: ContainerViewLayout, transition: ContainedViewLayoutTransition) {
|
|
||||||
super.containerLayoutUpdated(layout, transition: transition)
|
|
||||||
|
|
||||||
self.controllerNode.containerLayoutUpdated(layout, navigationBarHeight: self.navigationHeight, transition: transition)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class ChatListDatePickerScreenNode: ViewControllerTracingNode, UIScrollViewDelegate {
|
|
||||||
private let context: AccountContext
|
|
||||||
private var presentationData: PresentationData
|
|
||||||
private let dismissByTapOutside: Bool
|
|
||||||
|
|
||||||
private let dimNode: ASDisplayNode
|
|
||||||
private let wrappingScrollNode: ASScrollNode
|
|
||||||
private let contentContainerNode: ASDisplayNode
|
|
||||||
private let effectNode: ASDisplayNode
|
|
||||||
private let backgroundNode: ASDisplayNode
|
|
||||||
private let contentBackgroundNode: ASDisplayNode
|
|
||||||
private let titleNode: ASTextNode
|
|
||||||
private let cancelButton: HighlightableButtonNode
|
|
||||||
private let beforeButton: SolidRoundedButtonNode
|
|
||||||
private let afterButton: SolidRoundedButtonNode
|
|
||||||
|
|
||||||
private var pickerView: UIDatePicker?
|
|
||||||
private let dateFormatter: DateFormatter
|
|
||||||
|
|
||||||
private var containerLayout: (ContainerViewLayout, CGFloat)?
|
|
||||||
|
|
||||||
var completion: ((Int32?, Bool) -> Void)?
|
|
||||||
var dismiss: (() -> Void)?
|
|
||||||
var cancel: (() -> Void)?
|
|
||||||
|
|
||||||
init(context: AccountContext, dismissByTapOutside: Bool) {
|
|
||||||
self.context = context
|
|
||||||
self.presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
|
||||||
self.dismissByTapOutside = dismissByTapOutside
|
|
||||||
|
|
||||||
self.wrappingScrollNode = ASScrollNode()
|
|
||||||
self.wrappingScrollNode.view.alwaysBounceVertical = true
|
|
||||||
self.wrappingScrollNode.view.delaysContentTouches = false
|
|
||||||
self.wrappingScrollNode.view.canCancelContentTouches = true
|
|
||||||
|
|
||||||
self.dimNode = ASDisplayNode()
|
|
||||||
self.dimNode.backgroundColor = UIColor(white: 0.0, alpha: 0.5)
|
|
||||||
|
|
||||||
self.contentContainerNode = ASDisplayNode()
|
|
||||||
self.contentContainerNode.isOpaque = false
|
|
||||||
|
|
||||||
self.backgroundNode = ASDisplayNode()
|
|
||||||
self.backgroundNode.clipsToBounds = true
|
|
||||||
self.backgroundNode.cornerRadius = 16.0
|
|
||||||
|
|
||||||
let backgroundColor: UIColor
|
|
||||||
let textColor: UIColor
|
|
||||||
let accentColor: UIColor
|
|
||||||
let buttonColor: UIColor
|
|
||||||
let buttonTextColor: UIColor
|
|
||||||
let blurStyle: UIBlurEffect.Style
|
|
||||||
|
|
||||||
backgroundColor = self.presentationData.theme.actionSheet.itemBackgroundColor
|
|
||||||
textColor = self.presentationData.theme.actionSheet.primaryTextColor
|
|
||||||
accentColor = self.presentationData.theme.actionSheet.controlAccentColor
|
|
||||||
buttonColor = self.presentationData.theme.actionSheet.opaqueItemBackgroundColor
|
|
||||||
buttonTextColor = accentColor
|
|
||||||
blurStyle = self.presentationData.theme.actionSheet.backgroundType == .light ? .light : .dark
|
|
||||||
|
|
||||||
self.effectNode = ASDisplayNode(viewBlock: {
|
|
||||||
return UIVisualEffectView(effect: UIBlurEffect(style: blurStyle))
|
|
||||||
})
|
|
||||||
|
|
||||||
self.contentBackgroundNode = ASDisplayNode()
|
|
||||||
self.contentBackgroundNode.backgroundColor = backgroundColor
|
|
||||||
|
|
||||||
let title: String = "Set Date"
|
|
||||||
|
|
||||||
self.titleNode = ASTextNode()
|
|
||||||
self.titleNode.attributedText = NSAttributedString(string: title, font: Font.bold(17.0), textColor: textColor)
|
|
||||||
|
|
||||||
self.cancelButton = HighlightableButtonNode()
|
|
||||||
self.cancelButton.setTitle(self.presentationData.strings.Common_Cancel, with: Font.regular(17.0), with: accentColor, for: .normal)
|
|
||||||
|
|
||||||
self.beforeButton = SolidRoundedButtonNode(theme: SolidRoundedButtonTheme(theme: self.presentationData.theme), height: 52.0, cornerRadius: 11.0, gloss: false)
|
|
||||||
|
|
||||||
self.afterButton = SolidRoundedButtonNode(theme: SolidRoundedButtonTheme(backgroundColor: buttonColor, foregroundColor: buttonTextColor), font: .regular, height: 52.0, cornerRadius: 11.0, gloss: false)
|
|
||||||
self.afterButton.title = self.presentationData.strings.Conversation_ScheduleMessage_SendWhenOnline
|
|
||||||
|
|
||||||
self.dateFormatter = DateFormatter()
|
|
||||||
self.dateFormatter.timeStyle = .none
|
|
||||||
self.dateFormatter.dateStyle = .short
|
|
||||||
self.dateFormatter.timeZone = TimeZone.current
|
|
||||||
|
|
||||||
super.init()
|
|
||||||
|
|
||||||
self.backgroundColor = nil
|
|
||||||
self.isOpaque = false
|
|
||||||
|
|
||||||
self.dimNode.view.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(self.dimTapGesture(_:))))
|
|
||||||
self.addSubnode(self.dimNode)
|
|
||||||
|
|
||||||
self.wrappingScrollNode.view.delegate = self
|
|
||||||
self.addSubnode(self.wrappingScrollNode)
|
|
||||||
|
|
||||||
self.wrappingScrollNode.addSubnode(self.backgroundNode)
|
|
||||||
self.wrappingScrollNode.addSubnode(self.contentContainerNode)
|
|
||||||
|
|
||||||
self.backgroundNode.addSubnode(self.effectNode)
|
|
||||||
self.backgroundNode.addSubnode(self.contentBackgroundNode)
|
|
||||||
self.contentContainerNode.addSubnode(self.titleNode)
|
|
||||||
self.contentContainerNode.addSubnode(self.cancelButton)
|
|
||||||
self.contentContainerNode.addSubnode(self.beforeButton)
|
|
||||||
self.contentContainerNode.addSubnode(self.afterButton)
|
|
||||||
|
|
||||||
self.cancelButton.addTarget(self, action: #selector(self.cancelButtonPressed), forControlEvents: .touchUpInside)
|
|
||||||
self.beforeButton.pressed = { [weak self] in
|
|
||||||
if let strongSelf = self, let pickerView = strongSelf.pickerView {
|
|
||||||
strongSelf.beforeButton.isUserInteractionEnabled = false
|
|
||||||
strongSelf.completion?(Int32(pickerView.date.timeIntervalSince1970), false)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
self.afterButton.pressed = { [weak self] in
|
|
||||||
if let strongSelf = self, let pickerView = strongSelf.pickerView {
|
|
||||||
strongSelf.afterButton.isUserInteractionEnabled = false
|
|
||||||
strongSelf.completion?(Int32(pickerView.date.timeIntervalSince1970), true)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
self.setupPickerView(currentTime: nil)
|
|
||||||
self.updateButtonTitle()
|
|
||||||
}
|
|
||||||
|
|
||||||
func setupPickerView(currentTime: Int32? = nil) {
|
|
||||||
var currentDate: Date?
|
|
||||||
if let pickerView = self.pickerView {
|
|
||||||
currentDate = pickerView.date
|
|
||||||
pickerView.removeFromSuperview()
|
|
||||||
}
|
|
||||||
|
|
||||||
let textColor: UIColor = self.presentationData.theme.actionSheet.primaryTextColor
|
|
||||||
|
|
||||||
let pickerView = UIDatePicker()
|
|
||||||
pickerView.timeZone = TimeZone(secondsFromGMT: 0)
|
|
||||||
pickerView.setValue(textColor, forKey: "textColor")
|
|
||||||
pickerView.datePickerMode = .countDownTimer
|
|
||||||
pickerView.datePickerMode = .date
|
|
||||||
pickerView.locale = Locale.current
|
|
||||||
pickerView.timeZone = TimeZone.current
|
|
||||||
pickerView.minuteInterval = 1
|
|
||||||
self.contentContainerNode.view.addSubview(pickerView)
|
|
||||||
pickerView.addTarget(self, action: #selector(self.datePickerUpdated), for: .valueChanged)
|
|
||||||
self.pickerView = pickerView
|
|
||||||
|
|
||||||
self.updateMinimumDate(currentTime: currentTime)
|
|
||||||
if let currentDate = currentDate {
|
|
||||||
pickerView.date = currentDate
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func updatePresentationData(_ presentationData: PresentationData) {
|
|
||||||
let previousTheme = self.presentationData.theme
|
|
||||||
self.presentationData = presentationData
|
|
||||||
|
|
||||||
if let effectView = self.effectNode.view as? UIVisualEffectView {
|
|
||||||
effectView.effect = UIBlurEffect(style: presentationData.theme.actionSheet.backgroundType == .light ? .light : .dark)
|
|
||||||
}
|
|
||||||
|
|
||||||
self.contentBackgroundNode.backgroundColor = self.presentationData.theme.actionSheet.itemBackgroundColor
|
|
||||||
self.titleNode.attributedText = NSAttributedString(string: self.titleNode.attributedText?.string ?? "", font: Font.bold(17.0), textColor: self.presentationData.theme.actionSheet.primaryTextColor)
|
|
||||||
|
|
||||||
if previousTheme !== presentationData.theme, let (layout, navigationBarHeight) = self.containerLayout {
|
|
||||||
self.setupPickerView()
|
|
||||||
self.containerLayoutUpdated(layout, navigationBarHeight: navigationBarHeight, transition: .immediate)
|
|
||||||
}
|
|
||||||
|
|
||||||
self.cancelButton.setTitle(self.presentationData.strings.Common_Cancel, with: Font.regular(17.0), with: self.presentationData.theme.actionSheet.controlAccentColor, for: .normal)
|
|
||||||
self.beforeButton.updateTheme(SolidRoundedButtonTheme(theme: self.presentationData.theme))
|
|
||||||
self.afterButton.updateTheme(SolidRoundedButtonTheme(backgroundColor: self.presentationData.theme.actionSheet.opaqueItemBackgroundColor, foregroundColor: self.presentationData.theme.actionSheet.controlAccentColor))
|
|
||||||
}
|
|
||||||
|
|
||||||
private func updateMinimumDate(currentTime: Int32? = nil) {
|
|
||||||
// let timeZone = TimeZone(secondsFromGMT: 0)!
|
|
||||||
// var calendar = Calendar(identifier: .gregorian)
|
|
||||||
// calendar.timeZone = timeZone
|
|
||||||
// let currentDate = Date()
|
|
||||||
// var components = calendar.dateComponents(Set([.era, .year, .month, .day, .hour, .minute, .second]), from: currentDate)
|
|
||||||
// components.second = 0
|
|
||||||
// let minute = (components.minute ?? 0) % 5
|
|
||||||
|
|
||||||
self.pickerView?.minimumDate = Date(timeIntervalSince1970: 1376438400.0)
|
|
||||||
self.pickerView?.maximumDate = Date(timeIntervalSinceNow: 2.0)
|
|
||||||
self.pickerView?.date = Date()
|
|
||||||
}
|
|
||||||
|
|
||||||
override func didLoad() {
|
|
||||||
super.didLoad()
|
|
||||||
|
|
||||||
if #available(iOSApplicationExtension 11.0, iOS 11.0, *) {
|
|
||||||
self.wrappingScrollNode.view.contentInsetAdjustmentBehavior = .never
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private func updateButtonTitle() {
|
|
||||||
guard let date = self.pickerView?.date else {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
self.beforeButton.title = self.presentationData.strings.ChatList_Search_SearchBeforeDate(self.dateFormatter.string(from: date)).0
|
|
||||||
self.afterButton.title = self.presentationData.strings.ChatList_Search_SearchAfterDate(self.dateFormatter.string(from: date)).0
|
|
||||||
}
|
|
||||||
|
|
||||||
@objc private func datePickerUpdated() {
|
|
||||||
self.updateButtonTitle()
|
|
||||||
// if let date = self.pickerView?.date, date < Date() {
|
|
||||||
// self.beforeButton.alpha = 0.4
|
|
||||||
// self.beforeButton.isUserInteractionEnabled = false
|
|
||||||
// } else {
|
|
||||||
// self.beforeButton.alpha = 1.0
|
|
||||||
// self.beforeButton.isUserInteractionEnabled = true
|
|
||||||
// }
|
|
||||||
}
|
|
||||||
|
|
||||||
@objc func cancelButtonPressed() {
|
|
||||||
self.cancel?()
|
|
||||||
}
|
|
||||||
|
|
||||||
@objc func dimTapGesture(_ recognizer: UITapGestureRecognizer) {
|
|
||||||
if self.dismissByTapOutside, case .ended = recognizer.state {
|
|
||||||
self.cancelButtonPressed()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func animateIn() {
|
|
||||||
self.dimNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.4)
|
|
||||||
|
|
||||||
let offset = self.bounds.size.height - self.contentBackgroundNode.frame.minY
|
|
||||||
|
|
||||||
let dimPosition = self.dimNode.layer.position
|
|
||||||
self.dimNode.layer.animatePosition(from: CGPoint(x: dimPosition.x, y: dimPosition.y - offset), to: dimPosition, duration: 0.3, timingFunction: kCAMediaTimingFunctionSpring)
|
|
||||||
self.layer.animateBoundsOriginYAdditive(from: -offset, to: 0.0, duration: 0.3, timingFunction: kCAMediaTimingFunctionSpring)
|
|
||||||
}
|
|
||||||
|
|
||||||
func animateOut(completion: (() -> Void)? = nil) {
|
|
||||||
var dimCompleted = false
|
|
||||||
var offsetCompleted = false
|
|
||||||
|
|
||||||
let internalCompletion: () -> Void = { [weak self] in
|
|
||||||
if let strongSelf = self, dimCompleted && offsetCompleted {
|
|
||||||
strongSelf.dismiss?()
|
|
||||||
}
|
|
||||||
completion?()
|
|
||||||
}
|
|
||||||
|
|
||||||
self.dimNode.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.3, removeOnCompletion: false, completion: { _ in
|
|
||||||
dimCompleted = true
|
|
||||||
internalCompletion()
|
|
||||||
})
|
|
||||||
|
|
||||||
let offset = self.bounds.size.height - self.contentBackgroundNode.frame.minY
|
|
||||||
let dimPosition = self.dimNode.layer.position
|
|
||||||
self.dimNode.layer.animatePosition(from: dimPosition, to: CGPoint(x: dimPosition.x, y: dimPosition.y - offset), duration: 0.3, timingFunction: kCAMediaTimingFunctionSpring, removeOnCompletion: false)
|
|
||||||
self.layer.animateBoundsOriginYAdditive(from: 0.0, to: -offset, duration: 0.3, timingFunction: kCAMediaTimingFunctionSpring, removeOnCompletion: false, completion: { _ in
|
|
||||||
offsetCompleted = true
|
|
||||||
internalCompletion()
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
|
|
||||||
if self.bounds.contains(point) {
|
|
||||||
if !self.contentBackgroundNode.bounds.contains(self.convert(point, to: self.contentBackgroundNode)) {
|
|
||||||
return self.dimNode.view
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return super.hitTest(point, with: event)
|
|
||||||
}
|
|
||||||
|
|
||||||
func scrollViewDidEndDragging(_ scrollView: UIScrollView, willDecelerate decelerate: Bool) {
|
|
||||||
let contentOffset = scrollView.contentOffset
|
|
||||||
let additionalTopHeight = max(0.0, -contentOffset.y)
|
|
||||||
|
|
||||||
if additionalTopHeight >= 30.0 {
|
|
||||||
self.cancelButtonPressed()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func containerLayoutUpdated(_ layout: ContainerViewLayout, navigationBarHeight: CGFloat, transition: ContainedViewLayoutTransition) {
|
|
||||||
self.containerLayout = (layout, navigationBarHeight)
|
|
||||||
|
|
||||||
var insets = layout.insets(options: [.statusBar, .input])
|
|
||||||
let cleanInsets = layout.insets(options: [.statusBar])
|
|
||||||
insets.top = max(10.0, insets.top)
|
|
||||||
|
|
||||||
var buttonOffset: CGFloat = 64.0
|
|
||||||
|
|
||||||
let bottomInset: CGFloat = 10.0 + cleanInsets.bottom
|
|
||||||
let titleHeight: CGFloat = 54.0
|
|
||||||
var contentHeight = titleHeight + bottomInset + 52.0 + 17.0
|
|
||||||
let pickerHeight: CGFloat = min(216.0, layout.size.height - contentHeight)
|
|
||||||
contentHeight = titleHeight + bottomInset + 52.0 + 17.0 + pickerHeight + buttonOffset
|
|
||||||
|
|
||||||
let width = horizontalContainerFillingSizeForLayout(layout: layout, sideInset: layout.safeInsets.left)
|
|
||||||
|
|
||||||
let sideInset = floor((layout.size.width - width) / 2.0)
|
|
||||||
let contentContainerFrame = CGRect(origin: CGPoint(x: sideInset, y: layout.size.height - contentHeight), size: CGSize(width: width, height: contentHeight))
|
|
||||||
let contentFrame = contentContainerFrame
|
|
||||||
|
|
||||||
var backgroundFrame = CGRect(origin: CGPoint(x: contentFrame.minX, y: contentFrame.minY), size: CGSize(width: contentFrame.width, height: contentFrame.height + 2000.0))
|
|
||||||
if backgroundFrame.minY < contentFrame.minY {
|
|
||||||
backgroundFrame.origin.y = contentFrame.minY
|
|
||||||
}
|
|
||||||
transition.updateFrame(node: self.backgroundNode, frame: backgroundFrame)
|
|
||||||
transition.updateFrame(node: self.effectNode, frame: CGRect(origin: CGPoint(), size: backgroundFrame.size))
|
|
||||||
transition.updateFrame(node: self.contentBackgroundNode, frame: CGRect(origin: CGPoint(), size: backgroundFrame.size))
|
|
||||||
transition.updateFrame(node: self.wrappingScrollNode, frame: CGRect(origin: CGPoint(), size: layout.size))
|
|
||||||
transition.updateFrame(node: self.dimNode, frame: CGRect(origin: CGPoint(), size: layout.size))
|
|
||||||
|
|
||||||
let titleSize = self.titleNode.measure(CGSize(width: width, height: titleHeight))
|
|
||||||
let titleFrame = CGRect(origin: CGPoint(x: floor((contentFrame.width - titleSize.width) / 2.0), y: 16.0), size: titleSize)
|
|
||||||
transition.updateFrame(node: self.titleNode, frame: titleFrame)
|
|
||||||
|
|
||||||
let cancelSize = self.cancelButton.measure(CGSize(width: width, height: titleHeight))
|
|
||||||
let cancelFrame = CGRect(origin: CGPoint(x: 16.0, y: 16.0), size: cancelSize)
|
|
||||||
transition.updateFrame(node: self.cancelButton, frame: cancelFrame)
|
|
||||||
|
|
||||||
let buttonInset: CGFloat = 16.0
|
|
||||||
let doneButtonHeight = self.beforeButton.updateLayout(width: contentFrame.width - buttonInset * 2.0, transition: transition)
|
|
||||||
transition.updateFrame(node: self.beforeButton, frame: CGRect(x: buttonInset, y: contentHeight - doneButtonHeight - insets.bottom - 16.0 - buttonOffset, width: contentFrame.width, height: doneButtonHeight))
|
|
||||||
|
|
||||||
let onlineButtonHeight = self.afterButton.updateLayout(width: contentFrame.width - buttonInset * 2.0, transition: transition)
|
|
||||||
transition.updateFrame(node: self.afterButton, frame: CGRect(x: buttonInset, y: contentHeight - onlineButtonHeight - insets.bottom - 16.0, width: contentFrame.width, height: onlineButtonHeight))
|
|
||||||
|
|
||||||
self.pickerView?.frame = CGRect(origin: CGPoint(x: 0.0, y: 54.0), size: CGSize(width: contentFrame.width, height: pickerHeight))
|
|
||||||
|
|
||||||
transition.updateFrame(node: self.contentContainerNode, frame: contentContainerFrame)
|
|
||||||
}
|
|
||||||
}
|
|
@ -375,7 +375,7 @@ public enum ChatListSearchEntry: Comparable, Identifiable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public func item(context: AccountContext, presentationData: PresentationData, enableHeaders: Bool, filter: ChatListNodePeersFilter, interaction: ChatListNodeInteraction, listInteraction: ListMessageItemInteraction, peerContextAction: ((Peer, ChatListSearchContextActionSource, ASDisplayNode, ContextGesture?) -> Void)?, toggleExpandLocalResults: @escaping () -> Void, toggleExpandGlobalResults: @escaping () -> Void, presentDatePicker: @escaping () -> Void, searchPeer: @escaping (Peer) -> Void, searchResults: [Message], searchOptions: ChatListSearchOptions?, messageContextAction: ((Message, ASDisplayNode?, CGRect?, UIGestureRecognizer?) -> Void)?) -> ListViewItem {
|
public func item(context: AccountContext, presentationData: PresentationData, enableHeaders: Bool, filter: ChatListNodePeersFilter, interaction: ChatListNodeInteraction, listInteraction: ListMessageItemInteraction, peerContextAction: ((Peer, ChatListSearchContextActionSource, ASDisplayNode, ContextGesture?) -> Void)?, toggleExpandLocalResults: @escaping () -> Void, toggleExpandGlobalResults: @escaping () -> Void, searchPeer: @escaping (Peer) -> Void, searchResults: [Message], searchOptions: ChatListSearchOptions?, messageContextAction: ((Message, ASDisplayNode?, CGRect?, UIGestureRecognizer?) -> Void)?) -> ListViewItem {
|
||||||
switch self {
|
switch self {
|
||||||
case let .localPeer(peer, associatedPeer, unreadBadge, _, theme, strings, nameSortOrder, nameDisplayOrder, expandType):
|
case let .localPeer(peer, associatedPeer, unreadBadge, _, theme, strings, nameSortOrder, nameDisplayOrder, expandType):
|
||||||
let primaryPeer: Peer
|
let primaryPeer: Peer
|
||||||
@ -583,12 +583,12 @@ private func chatListSearchContainerPreparedRecentTransition(from fromEntries: [
|
|||||||
return ChatListSearchContainerRecentTransition(deletions: deletions, insertions: insertions, updates: updates)
|
return ChatListSearchContainerRecentTransition(deletions: deletions, insertions: insertions, updates: updates)
|
||||||
}
|
}
|
||||||
|
|
||||||
public func chatListSearchContainerPreparedTransition(from fromEntries: [ChatListSearchEntry], to toEntries: [ChatListSearchEntry], displayingResults: Bool, isEmpty: Bool, searchQuery: String, context: AccountContext, presentationData: PresentationData, enableHeaders: Bool, filter: ChatListNodePeersFilter, interaction: ChatListNodeInteraction, listInteraction: ListMessageItemInteraction, peerContextAction: ((Peer, ChatListSearchContextActionSource, ASDisplayNode, ContextGesture?) -> Void)?, toggleExpandLocalResults: @escaping () -> Void, toggleExpandGlobalResults: @escaping () -> Void, presentDatePicker: @escaping () -> Void, searchPeer: @escaping (Peer) -> Void, searchResults: [Message], searchOptions: ChatListSearchOptions?, messageContextAction: ((Message, ASDisplayNode?, CGRect?, UIGestureRecognizer?) -> Void)?) -> ChatListSearchContainerTransition {
|
public func chatListSearchContainerPreparedTransition(from fromEntries: [ChatListSearchEntry], to toEntries: [ChatListSearchEntry], displayingResults: Bool, isEmpty: Bool, searchQuery: String, context: AccountContext, presentationData: PresentationData, enableHeaders: Bool, filter: ChatListNodePeersFilter, interaction: ChatListNodeInteraction, listInteraction: ListMessageItemInteraction, peerContextAction: ((Peer, ChatListSearchContextActionSource, ASDisplayNode, ContextGesture?) -> Void)?, toggleExpandLocalResults: @escaping () -> Void, toggleExpandGlobalResults: @escaping () -> Void, searchPeer: @escaping (Peer) -> Void, searchResults: [Message], searchOptions: ChatListSearchOptions?, messageContextAction: ((Message, ASDisplayNode?, CGRect?, UIGestureRecognizer?) -> Void)?) -> ChatListSearchContainerTransition {
|
||||||
let (deleteIndices, indicesAndItems, updateIndices) = mergeListsStableWithUpdates(leftList: fromEntries, rightList: toEntries)
|
let (deleteIndices, indicesAndItems, updateIndices) = mergeListsStableWithUpdates(leftList: fromEntries, rightList: toEntries)
|
||||||
|
|
||||||
let deletions = deleteIndices.map { ListViewDeleteItem(index: $0, directionHint: nil) }
|
let deletions = deleteIndices.map { ListViewDeleteItem(index: $0, directionHint: nil) }
|
||||||
let insertions = indicesAndItems.map { ListViewInsertItem(index: $0.0, previousIndex: $0.2, item: $0.1.item(context: context, presentationData: presentationData, enableHeaders: enableHeaders, filter: filter, interaction: interaction, listInteraction: listInteraction, peerContextAction: peerContextAction, toggleExpandLocalResults: toggleExpandLocalResults, toggleExpandGlobalResults: toggleExpandGlobalResults, presentDatePicker: presentDatePicker, searchPeer: searchPeer, searchResults: searchResults, searchOptions: searchOptions, messageContextAction: messageContextAction), directionHint: nil) }
|
let insertions = indicesAndItems.map { ListViewInsertItem(index: $0.0, previousIndex: $0.2, item: $0.1.item(context: context, presentationData: presentationData, enableHeaders: enableHeaders, filter: filter, interaction: interaction, listInteraction: listInteraction, peerContextAction: peerContextAction, toggleExpandLocalResults: toggleExpandLocalResults, toggleExpandGlobalResults: toggleExpandGlobalResults, searchPeer: searchPeer, searchResults: searchResults, searchOptions: searchOptions, messageContextAction: messageContextAction), directionHint: nil) }
|
||||||
let updates = updateIndices.map { ListViewUpdateItem(index: $0.0, previousIndex: $0.2, item: $0.1.item(context: context, presentationData: presentationData, enableHeaders: enableHeaders, filter: filter, interaction: interaction, listInteraction: listInteraction, peerContextAction: peerContextAction, toggleExpandLocalResults: toggleExpandLocalResults, toggleExpandGlobalResults: toggleExpandGlobalResults, presentDatePicker: presentDatePicker, searchPeer: searchPeer, searchResults: searchResults, searchOptions: searchOptions, messageContextAction: messageContextAction), directionHint: nil) }
|
let updates = updateIndices.map { ListViewUpdateItem(index: $0.0, previousIndex: $0.2, item: $0.1.item(context: context, presentationData: presentationData, enableHeaders: enableHeaders, filter: filter, interaction: interaction, listInteraction: listInteraction, peerContextAction: peerContextAction, toggleExpandLocalResults: toggleExpandLocalResults, toggleExpandGlobalResults: toggleExpandGlobalResults, searchPeer: searchPeer, searchResults: searchResults, searchOptions: searchOptions, messageContextAction: messageContextAction), directionHint: nil) }
|
||||||
|
|
||||||
return ChatListSearchContainerTransition(deletions: deletions, insertions: insertions, updates: updates, displayingResults: displayingResults, isEmpty: isEmpty, query: searchQuery)
|
return ChatListSearchContainerTransition(deletions: deletions, insertions: insertions, updates: updates, displayingResults: displayingResults, isEmpty: isEmpty, query: searchQuery)
|
||||||
}
|
}
|
||||||
@ -1496,22 +1496,6 @@ public final class ChatListSearchContainerNode: SearchDisplayControllerContentNo
|
|||||||
state.expandGlobalSearch = !state.expandGlobalSearch
|
state.expandGlobalSearch = !state.expandGlobalSearch
|
||||||
return state
|
return state
|
||||||
}
|
}
|
||||||
}, presentDatePicker: {
|
|
||||||
guard let strongSelf = self else {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
let controller = ChatListDatePickerScreen(context: strongSelf.context, dismissByTapOutside: true, completion: { [weak self] date, after in
|
|
||||||
guard let strongSelf = self else {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if let date = date {
|
|
||||||
strongSelf.updateSearchOptions(strongSelf.currentSearchOptions.withUpdatedMinDate(after ? date : nil).withUpdatedMaxDate(after ? nil : date))
|
|
||||||
} else {
|
|
||||||
strongSelf.updateSearchOptions(strongSelf.currentSearchOptions.withUpdatedMinDate(nil).withUpdatedMaxDate(nil))
|
|
||||||
}
|
|
||||||
})
|
|
||||||
strongSelf.dismissInput?()
|
|
||||||
strongSelf.interaction?.present(controller)
|
|
||||||
}, searchPeer: { peer in
|
}, searchPeer: { peer in
|
||||||
guard let strongSelf = self else {
|
guard let strongSelf = self else {
|
||||||
return
|
return
|
||||||
|
@ -352,6 +352,7 @@ public class GalleryController: ViewController, StandalonePresentableController
|
|||||||
private var entries: [MessageHistoryEntry] = []
|
private var entries: [MessageHistoryEntry] = []
|
||||||
private var hasLeftEntries: Bool = false
|
private var hasLeftEntries: Bool = false
|
||||||
private var hasRightEntries: Bool = false
|
private var hasRightEntries: Bool = false
|
||||||
|
private var loadingMore: Bool = false
|
||||||
private var tagMask: MessageTags?
|
private var tagMask: MessageTags?
|
||||||
private var centralEntryStableId: UInt32?
|
private var centralEntryStableId: UInt32?
|
||||||
private var configuration: GalleryConfiguration?
|
private var configuration: GalleryConfiguration?
|
||||||
@ -455,7 +456,7 @@ public class GalleryController: ViewController, StandalonePresentableController
|
|||||||
entries.append(MessageHistoryEntry(message: message, isRead: false, location: MessageHistoryEntryLocation(index: index, count: Int(totalCount)), monthLocation: nil, attributes: MutableMessageHistoryEntryAttributes(authorIsContact: false)))
|
entries.append(MessageHistoryEntry(message: message, isRead: false, location: MessageHistoryEntryLocation(index: index, count: Int(totalCount)), monthLocation: nil, attributes: MutableMessageHistoryEntryAttributes(authorIsContact: false)))
|
||||||
index -= 1
|
index -= 1
|
||||||
}
|
}
|
||||||
return GalleryMessageHistoryView.entries(entries, false, hasMore)
|
return GalleryMessageHistoryView.entries(entries, hasMore, false)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1063,9 +1064,60 @@ public class GalleryController: ViewController, StandalonePresentableController
|
|||||||
}
|
}
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
case let .custom(_, _, loadMore):
|
case let .custom(messages, _, loadMore):
|
||||||
if index >= strongSelf.entries.count - 3 && strongSelf.hasRightEntries {
|
if index >= strongSelf.entries.count - 3 && strongSelf.hasRightEntries && !strongSelf.loadingMore {
|
||||||
|
strongSelf.loadingMore = true
|
||||||
loadMore?()
|
loadMore?()
|
||||||
|
|
||||||
|
strongSelf.updateVisibleDisposable.set((messages
|
||||||
|
|> deliverOnMainQueue).start(next: { messages, totalCount, hasMore in
|
||||||
|
guard let strongSelf = self else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
var entries: [MessageHistoryEntry] = []
|
||||||
|
var index = messages.count - 1
|
||||||
|
for message in messages.reversed() {
|
||||||
|
entries.append(MessageHistoryEntry(message: message, isRead: false, location: MessageHistoryEntryLocation(index: index, count: Int(totalCount)), monthLocation: nil, attributes: MutableMessageHistoryEntryAttributes(authorIsContact: false)))
|
||||||
|
index -= 1
|
||||||
|
}
|
||||||
|
|
||||||
|
if entries.count > strongSelf.entries.count {
|
||||||
|
if strongSelf.invertItemOrder {
|
||||||
|
strongSelf.entries = entries.reversed()
|
||||||
|
strongSelf.hasLeftEntries = false
|
||||||
|
strongSelf.hasRightEntries = hasMore
|
||||||
|
} else {
|
||||||
|
strongSelf.entries = entries
|
||||||
|
strongSelf.hasLeftEntries = hasMore
|
||||||
|
strongSelf.hasRightEntries = false
|
||||||
|
}
|
||||||
|
if strongSelf.isViewLoaded {
|
||||||
|
var items: [GalleryItem] = []
|
||||||
|
var centralItemIndex: Int?
|
||||||
|
for entry in strongSelf.entries {
|
||||||
|
var isCentral = false
|
||||||
|
if entry.message.stableId == strongSelf.centralEntryStableId {
|
||||||
|
isCentral = true
|
||||||
|
}
|
||||||
|
if let item = galleryItemForEntry(context: strongSelf.context, presentationData: strongSelf.presentationData, entry: entry, isCentral: isCentral, streamVideos: false, fromPlayingVideo: isCentral && strongSelf.fromPlayingVideo, landscape: isCentral && strongSelf.landscape, timecode: isCentral ? strongSelf.timecode : nil, configuration: strongSelf.configuration, performAction: strongSelf.performAction, openActionOptions: strongSelf.openActionOptions, storeMediaPlaybackState: strongSelf.actionInteraction?.storeMediaPlaybackState ?? { _, _ in }, present: { [weak self] c, a in
|
||||||
|
if let strongSelf = self {
|
||||||
|
strongSelf.presentInGlobalOverlay(c, with: a)
|
||||||
|
}
|
||||||
|
}) {
|
||||||
|
if isCentral {
|
||||||
|
centralItemIndex = items.count
|
||||||
|
}
|
||||||
|
items.append(item)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
strongSelf.galleryNode.pager.replaceItems(items, centralItemIndex: centralItemIndex)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
strongSelf.loadingMore = false
|
||||||
|
}))
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
break
|
break
|
||||||
|
@ -101,7 +101,6 @@ public final class HashtagSearchController: TelegramBaseController {
|
|||||||
let firstTime = previousEntries == nil
|
let firstTime = previousEntries == nil
|
||||||
let transition = chatListSearchContainerPreparedTransition(from: previousEntries ?? [], to: entries, displayingResults: true, isEmpty: entries.isEmpty, searchQuery: "", context: strongSelf.context, presentationData: strongSelf.presentationData, enableHeaders: false, filter: [], interaction: interaction, listInteraction: listInteraction, peerContextAction: nil, toggleExpandLocalResults: {
|
let transition = chatListSearchContainerPreparedTransition(from: previousEntries ?? [], to: entries, displayingResults: true, isEmpty: entries.isEmpty, searchQuery: "", context: strongSelf.context, presentationData: strongSelf.presentationData, enableHeaders: false, filter: [], interaction: interaction, listInteraction: listInteraction, peerContextAction: nil, toggleExpandLocalResults: {
|
||||||
}, toggleExpandGlobalResults: {
|
}, toggleExpandGlobalResults: {
|
||||||
}, presentDatePicker: {
|
|
||||||
}, searchPeer: { _ in
|
}, searchPeer: { _ in
|
||||||
|
|
||||||
}, searchResults: [], searchOptions: nil, messageContextAction: nil)
|
}, searchResults: [], searchOptions: nil, messageContextAction: nil)
|
||||||
|
File diff suppressed because it is too large
Load Diff
Binary file not shown.
Loading…
x
Reference in New Issue
Block a user