Merge commit '84efd043c1d8d29624db72fabb2ec26b7378f4bc'

This commit is contained in:
Ali 2020-09-23 22:59:14 +04:00
commit 6d694101c0
19 changed files with 210 additions and 135 deletions

View File

@ -56,6 +56,7 @@ swift_library(
"//submodules/ShareController:ShareController",
"//submodules/GridMessageSelectionNode:GridMessageSelectionNode",
"//submodules/ChatListFilterSettingsHeaderItem:ChatListFilterSettingsHeaderItem",
"//submodules/TelegramStringFormatting:TelegramStringFormatting",
],
visibility = [
"//visibility:public",

View File

@ -415,8 +415,8 @@ enum ChatListFilterTabEntry: Equatable {
switch self {
case .all:
return .all
case let .filter(filter):
return .filter(filter.id)
case let .filter(id, _, _):
return .filter(id)
}
}
@ -424,8 +424,8 @@ enum ChatListFilterTabEntry: Equatable {
switch self {
case .all:
return strings.ChatList_Tabs_AllChats
case let .filter(filter):
return filter.text
case let .filter(_, text, _):
return text
}
}
@ -433,8 +433,8 @@ enum ChatListFilterTabEntry: Equatable {
switch self {
case .all:
return strings.ChatList_Tabs_All
case let .filter(filter):
return filter.text
case let .filter(_, text, _):
return text
}
}
}
@ -700,8 +700,8 @@ final class ChatListFilterTabContainerNode: ASDisplayNode {
strongSelf.scrollNode.view.panGestureRecognizer.isEnabled = true
strongSelf.scrollNode.view.setContentOffset(strongSelf.scrollNode.view.contentOffset, animated: false)
switch filter {
case let .filter(filter):
strongSelf.contextGesture?(filter.id, sourceNode, gesture)
case let .filter(id, _, _):
strongSelf.contextGesture?(id, sourceNode, gesture)
default:
strongSelf.contextGesture?(nil, sourceNode, gesture)
}
@ -716,9 +716,9 @@ final class ChatListFilterTabContainerNode: ASDisplayNode {
unreadCount = count
unreadHasUnmuted = true
isNoFilter = true
case let .filter(filter):
unreadCount = filter.unread.value
unreadHasUnmuted = filter.unread.hasUnmuted
case let .filter(_, _, unread):
unreadCount = unread.value
unreadHasUnmuted = unread.hasUnmuted
}
if !wasAdded && (itemNode.unreadCount != 0) != (unreadCount != 0) {
badgeAnimations[filter.id] = (unreadCount != 0) ? .in : .out
@ -789,7 +789,7 @@ final class ChatListFilterTabContainerNode: ASDisplayNode {
var longTitlesWidth: CGFloat = resolvedSideInset
for i in 0 ..< tabSizes.count {
let (itemId, paneNodeSize, paneNodeShortSize, paneNode, wasAdded) = tabSizes[i]
let (_, paneNodeSize, _, _, _) = tabSizes[i]
longTitlesWidth += paneNodeSize.width
if i != tabSizes.count - 1 {
longTitlesWidth += minSpacing

View File

@ -49,10 +49,10 @@ final class ChatListSearchInteraction {
let peerContextAction: ((Peer, ChatListSearchContextActionSource, ASDisplayNode, ContextGesture?) -> Void)?
let present: (ViewController, Any?) -> Void
let dismissInput: () -> Void
let updateSuggestedPeers: ([Peer]) -> Void
let updateSuggestedPeers: ([Peer], ChatListSearchPaneKey) -> Void
let getSelectedMessageIds: () -> Set<MessageId>?
init(openPeer: @escaping (Peer, Bool) -> Void, openDisabledPeer: @escaping (Peer) -> Void, openMessage: @escaping (Peer, MessageId) -> Void, openUrl: @escaping (String) -> Void, clearRecentSearch: @escaping () -> Void, addContact: @escaping (String) -> Void, toggleMessageSelection: @escaping (MessageId, Bool) -> Void, messageContextAction: @escaping ((Message, ASDisplayNode?, CGRect?, UIGestureRecognizer?) -> Void), mediaMessageContextAction: @escaping ((Message, ASDisplayNode?, CGRect?, UIGestureRecognizer?) -> Void), peerContextAction: ((Peer, ChatListSearchContextActionSource, ASDisplayNode, ContextGesture?) -> Void)?, present: @escaping (ViewController, Any?) -> Void, dismissInput: @escaping () -> Void, updateSuggestedPeers: @escaping ([Peer]) -> Void, getSelectedMessageIds: @escaping () -> Set<MessageId>?) {
init(openPeer: @escaping (Peer, Bool) -> Void, openDisabledPeer: @escaping (Peer) -> Void, openMessage: @escaping (Peer, MessageId) -> Void, openUrl: @escaping (String) -> Void, clearRecentSearch: @escaping () -> Void, addContact: @escaping (String) -> Void, toggleMessageSelection: @escaping (MessageId, Bool) -> Void, messageContextAction: @escaping ((Message, ASDisplayNode?, CGRect?, UIGestureRecognizer?) -> Void), mediaMessageContextAction: @escaping ((Message, ASDisplayNode?, CGRect?, UIGestureRecognizer?) -> Void), peerContextAction: ((Peer, ChatListSearchContextActionSource, ASDisplayNode, ContextGesture?) -> Void)?, present: @escaping (ViewController, Any?) -> Void, dismissInput: @escaping () -> Void, updateSuggestedPeers: @escaping ([Peer], ChatListSearchPaneKey) -> Void, getSelectedMessageIds: @escaping () -> Set<MessageId>?) {
self.openPeer = openPeer
self.openDisabledPeer = openDisabledPeer
self.openMessage = openMessage
@ -215,8 +215,10 @@ public final class ChatListSearchContainerNode: SearchDisplayControllerContentNo
present(c, a)
}, dismissInput: { [weak self] in
self?.dismissInput()
}, updateSuggestedPeers: { [weak self] peers in
self?.suggestedPeers.set(.single(peers))
}, updateSuggestedPeers: { [weak self] peers, key in
if let strongSelf = self, strongSelf.paneContainerNode.currentPaneKey == key {
strongSelf.suggestedPeers.set(.single(peers))
}
}, getSelectedMessageIds: { [weak self] () -> Set<MessageId>? in
if let strongSelf = self {
return strongSelf.stateValue.selectedMessageIds
@ -297,7 +299,7 @@ public final class ChatListSearchContainerNode: SearchDisplayControllerContentNo
self.suggestedFiltersDisposable.set((combineLatest(self.suggestedPeers.get(), self.suggestedDates.get())
|> mapToSignal { peers, dates -> Signal<([Peer], [(Date, String?)]), NoError> in
if peers.isEmpty && dates.isEmpty {
if (peers.isEmpty && dates.isEmpty) || peers.isEmpty {
return .single((peers, dates))
} else {
return (.complete() |> delay(0.2, queue: Queue.mainQueue()))

View File

@ -226,7 +226,7 @@ final class ChatListSearchFiltersContainerNode: ASDisplayNode {
}
self.addSubnode(self.scrollNode)
self.addSubnode(self.selectedLineNode)
self.scrollNode.addSubnode(self.selectedLineNode)
}
func cancelAnimations() {
@ -254,6 +254,7 @@ final class ChatListSearchFiltersContainerNode: ASDisplayNode {
transition.updateFrame(node: self.scrollNode, frame: CGRect(origin: CGPoint(), size: size))
var hasSelection = false
for i in 0 ..< filters.count {
let filter = filters[i]
if case let .filter(type) = filter {
@ -272,6 +273,7 @@ final class ChatListSearchFiltersContainerNode: ASDisplayNode {
let selectionFraction: CGFloat
if selectedFilter == filter.id {
selectionFraction = 1.0 - abs(transitionFraction)
hasSelection = true
} else if i != 0 && selectedFilter == filters[i - 1].id {
selectionFraction = max(0.0, -transitionFraction)
} else if i != filters.count - 1 && selectedFilter == filters[i + 1].id {
@ -323,7 +325,7 @@ final class ChatListSearchFiltersContainerNode: ASDisplayNode {
}
let minSpacing: CGFloat = 24.0
let spacing = minSpacing
var spacing = minSpacing
let resolvedSideInset: CGFloat = 16.0 + sideInset
var leftOffset: CGFloat = resolvedSideInset
@ -340,6 +342,10 @@ final class ChatListSearchFiltersContainerNode: ASDisplayNode {
}
longTitlesWidth += resolvedSideInset
if longTitlesWidth < size.width && hasSelection {
spacing = (size.width - titlesWidth - resolvedSideInset * 2.0) / CGFloat(tabSizes.count - 1)
}
let verticalOffset: CGFloat = -3.0
for i in 0 ..< tabSizes.count {
let (_, paneNodeSize, paneNode, wasAdded) = tabSizes[i]
@ -347,14 +353,25 @@ final class ChatListSearchFiltersContainerNode: ASDisplayNode {
let paneFrame = CGRect(origin: CGPoint(x: leftOffset, y: floor((size.height - paneNodeSize.height) / 2.0) + verticalOffset), size: paneNodeSize)
if wasAdded {
var effectiveWasAdded = wasAdded
if !effectiveWasAdded && !self.bounds.intersects(self.scrollNode.convert(paneNode.frame, to: self)) && self.bounds.intersects(self.scrollNode.convert(paneFrame, to: self)) {
effectiveWasAdded = true
}
if effectiveWasAdded {
paneNode.frame = paneFrame
paneNode.alpha = 0.0
paneNode.subnodeTransform = CATransform3DMakeScale(0.1, 0.1, 1.0)
itemNodeTransition.updateSublayerTransformScale(node: paneNode, scale: 1.0)
itemNodeTransition.updateAlpha(node: paneNode, alpha: 1.0)
} else {
itemNodeTransition.updateFrameAdditive(node: paneNode, frame: paneFrame)
if self.bounds.intersects(self.scrollNode.convert(paneFrame, to: self)) {
itemNodeTransition.updateFrameAdditive(node: paneNode, frame: paneFrame)
} else {
paneNode.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.4) { [weak paneNode] _ in
paneNode?.frame = paneFrame
}
}
}
paneNode.updateArea(size: paneFrame.size, sideInset: spacing / 2.0, transition: itemNodeTransition)

View File

@ -634,6 +634,7 @@ final class ChatListSearchListPaneNode: ASDisplayNode, ChatListSearchPaneNode {
private let interaction: ChatListSearchInteraction
private let peersFilter: ChatListNodePeersFilter
private var presentationData: PresentationData
private let key: ChatListSearchPaneKey
private let tagMask: MessageTags?
private let navigationController: NavigationController?
@ -695,13 +696,30 @@ final class ChatListSearchListPaneNode: ASDisplayNode, ChatListSearchPaneNode {
private var hiddenMediaDisposable: Disposable?
init(context: AccountContext, interaction: ChatListSearchInteraction, tagMask: MessageTags?, peersFilter: ChatListNodePeersFilter, searchQuery: Signal<String?, NoError>, searchOptions: Signal<ChatListSearchOptions?, NoError>, navigationController: NavigationController?) {
init(context: AccountContext, interaction: ChatListSearchInteraction, key: ChatListSearchPaneKey, peersFilter: ChatListNodePeersFilter, searchQuery: Signal<String?, NoError>, searchOptions: Signal<ChatListSearchOptions?, NoError>, navigationController: NavigationController?) {
self.context = context
self.interaction = interaction
self.key = key
self.peersFilter = peersFilter
self.tagMask = tagMask
self.navigationController = navigationController
let tagMask: MessageTags?
switch key {
case .chats:
tagMask = nil
case .media:
tagMask = .photoOrVideo
case .links:
tagMask = .webPage
case .files:
tagMask = .file
case .music:
tagMask = .music
case .voice:
tagMask = .voiceOrInstantVideo
}
self.tagMask = tagMask
self.presentationData = context.sharedContext.currentPresentationData.with { $0 }
self.presentationDataPromise.set(.single(ChatListPresentationData(theme: self.presentationData.theme, fontSize: self.presentationData.listsFontSize, strings: self.presentationData.strings, dateTimeFormat: self.presentationData.dateTimeFormat, nameSortOrder: self.presentationData.nameSortOrder, nameDisplayOrder: self.presentationData.nameDisplayOrder, disableAnimations: self.presentationData.disableAnimations)))
@ -1190,8 +1208,8 @@ final class ChatListSearchListPaneNode: ASDisplayNode, ChatListSearchPaneNode {
return
}
switch item.content {
case let .peer(peer):
if let peer = peer.peer.peer {
case let .peer(_, peer, _, _, _, _, _, _, _, _, _, _):
if let peer = peer.peer {
peerContextAction(peer, .search, node, gesture)
}
case .groupReference:
@ -1353,7 +1371,7 @@ final class ChatListSearchListPaneNode: ASDisplayNode, ChatListSearchPaneNode {
strongSelf.ready.set(.single(true))
strongSelf.didSetReady = true
} else if tagMask != nil {
interaction.updateSuggestedPeers(Array(peers.prefix(8)))
interaction.updateSuggestedPeers(Array(peers.prefix(8)), strongSelf.key)
}
}
}))

View File

@ -117,7 +117,7 @@ private final class VisualMediaItemNode: ASDisplayNode {
if case .ended = recognizer.state {
if let (gesture, _) = recognizer.lastRecognizedGestureAndLocation {
if case .tap = gesture {
if let (item, _, _, _) = self.item {
if let _ = self.item {
var media: Media?
for value in message.media {
if let image = value as? TelegramMediaImage {
@ -225,7 +225,7 @@ private final class VisualMediaItemNode: ASDisplayNode {
self.fetchStatusDisposable.set((messageMediaFileStatus(context: context, messageId: message.id, file: file)
|> deliverOnMainQueue).start(next: { [weak self] status in
if let strongSelf = self, let (item, _, _, _) = strongSelf.item {
if let strongSelf = self, let _ = strongSelf.item {
strongSelf.resourceStatus = status
let isStreamable = isMediaStreamable(message: message, media: file)

View File

@ -81,21 +81,7 @@ private final class ChatListSearchPendingPane {
key: ChatListSearchPaneKey,
hasBecomeReady: @escaping (ChatListSearchPaneKey) -> Void
) {
let paneNode: ChatListSearchPaneNode
switch key {
case .chats:
paneNode = ChatListSearchListPaneNode(context: context, interaction: interaction, tagMask: nil, peersFilter: peersFilter, searchQuery: searchQuery, searchOptions: searchOptions, navigationController: navigationController)
case .media:
paneNode = ChatListSearchListPaneNode(context: context, interaction: interaction, tagMask: .photoOrVideo, peersFilter: [], searchQuery: searchQuery, searchOptions: searchOptions, navigationController: navigationController)
case .files:
paneNode = ChatListSearchListPaneNode(context: context, interaction: interaction, tagMask: .file, peersFilter: [], searchQuery: searchQuery, searchOptions: searchOptions, navigationController: navigationController)
case .links:
paneNode = ChatListSearchListPaneNode(context: context, interaction: interaction, tagMask: .webPage, peersFilter: [], searchQuery: searchQuery, searchOptions: searchOptions, navigationController: navigationController)
case .voice:
paneNode = ChatListSearchListPaneNode(context: context, interaction: interaction, tagMask: .voiceOrInstantVideo, peersFilter: [], searchQuery: searchQuery, searchOptions: searchOptions, navigationController: navigationController)
case .music:
paneNode = ChatListSearchListPaneNode(context: context, interaction: interaction, tagMask: .music, peersFilter: [], searchQuery: searchQuery, searchOptions: searchOptions, navigationController: navigationController)
}
let paneNode = ChatListSearchListPaneNode(context: context, interaction: interaction, key: key, peersFilter: key == .chats ? peersFilter : [], searchQuery: searchQuery, searchOptions: searchOptions, navigationController: navigationController)
self.pane = ChatListSearchPaneWrapper(key: key, node: paneNode)
self.disposable = (paneNode.isReady
@ -493,7 +479,7 @@ final class ChatListSearchPaneContainerNode: ASDisplayNode, UIGestureRecognizerD
transition.animateFrame(node: pane.node, from: paneFrame, to: paneFrame.offsetBy(dx: -paneSwitchAnimationOffset, dy: 0.0), completion: isAnimatingOut ? nil : { _ in
paneCompletion()
})
} else if let previousPaneKey = previousPaneKey, key == self.currentPaneKey {
} else if let _ = previousPaneKey, key == self.currentPaneKey {
pane.node.frame = adjustedFrame
let isAnimatingOut = pane.isAnimatingOut
pane.isAnimatingOut = true

View File

@ -1,5 +1,6 @@
import Foundation
import TelegramPresentationData
import TelegramStringFormatting
private let telegramReleaseDate = Date(timeIntervalSince1970: 1376438400.0)
@ -106,35 +107,46 @@ func suggestDates(for string: String, strings: PresentationStrings, dateTimeForm
}
}
} else {
for (day, value) in weekDays {
let dayName = value.0.lowercased()
let shortDayName = value.1.lowercased()
if string == shortDayName || (string.count >= shortDayName.count && dayName.hasPrefix(string)) {
var nextDateComponent = calendar.dateComponents([.hour, .minute, .second], from: now)
nextDateComponent.weekday = day + calendar.firstWeekday
if let date = calendar.nextDate(after: now, matching: nextDateComponent, matchingPolicy: .nextTime, direction: .backward) {
let upperDate = getUpperDate(for: date)
for i in 0..<5 {
if let date = calendar.date(byAdding: .hour, value: -24 * 7 * i, to: upperDate) {
if calendar.isDate(date, equalTo: now, toGranularity: .weekOfYear) {
result.append((date, value.0))
} else {
result.append((date, nil))
}
}
for (day, value) in weekDays {
let dayName = value.0.lowercased()
let shortDayName = value.1.lowercased()
if string == shortDayName || (string.count >= shortDayName.count && dayName.hasPrefix(string)) {
var nextDateComponent = calendar.dateComponents([.hour, .minute, .second], from: now)
nextDateComponent.weekday = day + calendar.firstWeekday
if let date = calendar.nextDate(after: now, matching: nextDateComponent, matchingPolicy: .nextTime, direction: .backward) {
let upperDate = getUpperDate(for: date)
for i in 0..<5 {
if let date = calendar.date(byAdding: .hour, value: -24 * 7 * i, to: upperDate) {
if calendar.isDate(date, equalTo: now, toGranularity: .weekOfYear) {
result.append((date, value.0))
} else {
result.append((date, nil))
}
}
}
}
}
for (month, value) in months {
let monthName = value.0.lowercased()
let shortMonthName = value.1.lowercased()
if string == shortMonthName || (string.count >= shortMonthName.count && monthName.hasPrefix(string)) {
}
let cleanString = string.trimmingCharacters(in: .decimalDigits).trimmingCharacters(in: .whitespacesAndNewlines)
let cleanDigits = string.trimmingCharacters(in: .letters).trimmingCharacters(in: .whitespacesAndNewlines)
for (month, value) in months {
let monthName = value.0.lowercased()
let shortMonthName = value.1.lowercased()
if cleanString == shortMonthName || (cleanString.count >= shortMonthName.count && monthName.hasPrefix(cleanString)) {
if cleanDigits.count == 4, let year = Int(cleanDigits) {
let date = getUpperMonthDate(month: month, year: year)
if date <= now && date > telegramReleaseDate {
result.append((date, stringForMonth(strings: strings, month: Int32(month - 1), ofYear: Int32(year - 1900))))
}
} else if cleanDigits.isEmpty {
for i in (year - 7 ... year).reversed() {
let date = getUpperMonthDate(month: month, year: i)
if date <= now && date > telegramReleaseDate {
result.append((date, nil))
result.append((date, stringForMonth(strings: strings, month: Int32(month - 1), ofYear: Int32(i - 1900))))
}
}
}

View File

@ -110,6 +110,9 @@ private final class DateSelectionActionSheetItemNode: ActionSheetItemNode {
self.pickerView.datePickerMode = .date
self.pickerView.date = Date(timeIntervalSince1970: Double(roundDateToDays(currentValue)))
self.pickerView.locale = localeWithStrings(strings)
if #available(iOS 13.4, *) {
self.pickerView.preferredDatePickerStyle = .wheels
}
if let minimumDate = minimumDate {
self.pickerView.minimumDate = minimumDate
}

View File

@ -44,8 +44,8 @@ final class GalleryTitleView: UIView, NavigationBarTitleView {
let leftInset: CGFloat = 0.0
let rightInset: CGFloat = 0.0
let authorNameSize = self.authorNameNode.measure(CGSize(width: size.width - 44.0 * 2.0 - 8.0 * 2.0 - leftInset - rightInset, height: CGFloat.greatestFiniteMagnitude))
let dateSize = self.dateNode.measure(CGSize(width: size.width - 44.0 * 2.0 - 8.0 * 2.0, height: CGFloat.greatestFiniteMagnitude))
let authorNameSize = self.authorNameNode.measure(CGSize(width: size.width - 8.0 * 2.0 - leftInset - rightInset, height: CGFloat.greatestFiniteMagnitude))
let dateSize = self.dateNode.measure(CGSize(width: size.width - 8.0 * 2.0, height: CGFloat.greatestFiniteMagnitude))
if authorNameSize.height.isZero {
self.dateNode.frame = CGRect(origin: CGPoint(x: floor((size.width - dateSize.width) / 2.0), y: floor((size.height - dateSize.height) / 2.0)), size: dateSize)

View File

@ -101,6 +101,9 @@ private final class PeerBanTimeoutActionSheetItemNode: ActionSheetItemNode {
self.pickerView.locale = localeWithStrings(strings)
self.pickerView.minimumDate = Date()
self.pickerView.maximumDate = Date(timeIntervalSince1970: Double(Int32.max - 1))
if #available(iOS 13.4, *) {
self.pickerView.preferredDatePickerStyle = .wheels
}
super.init(theme: theme)

View File

@ -56,6 +56,7 @@ public struct SearchBarToken {
private final class TokenNode: ASDisplayNode {
var theme: SearchBarNodeTheme
let token: SearchBarToken
let containerNode: ASDisplayNode
let iconNode: ASImageNode
let titleNode: ASTextNode
let backgroundNode: ASImageNode
@ -68,6 +69,8 @@ private final class TokenNode: ASDisplayNode {
init(theme: SearchBarNodeTheme, token: SearchBarToken) {
self.theme = theme
self.token = token
self.containerNode = ASDisplayNode()
self.containerNode.clipsToBounds = true
self.iconNode = ASImageNode()
self.iconNode.displaysAsynchronously = false
self.iconNode.displayWithoutProcessing = true
@ -82,8 +85,8 @@ private final class TokenNode: ASDisplayNode {
super.init()
self.clipsToBounds = true
self.addSubnode(self.backgroundNode)
self.addSubnode(self.containerNode)
self.containerNode.addSubnode(self.backgroundNode)
let backgroundColor = token.style?.backgroundColor ?? theme.inputIcon
let strokeColor = token.style?.strokeColor ?? backgroundColor
@ -91,10 +94,10 @@ private final class TokenNode: ASDisplayNode {
let foregroundColor = token.style?.foregroundColor ?? .white
self.iconNode.image = generateTintedImage(image: token.icon, color: foregroundColor)
self.addSubnode(self.iconNode)
self.containerNode.addSubnode(self.iconNode)
self.titleNode.attributedText = NSAttributedString(string: token.title, font: Font.regular(17.0), textColor: foregroundColor)
self.addSubnode(self.titleNode)
self.containerNode.addSubnode(self.titleNode)
}
override func didLoad() {
@ -108,8 +111,10 @@ private final class TokenNode: ASDisplayNode {
}
func animateIn() {
let targetFrame = self.frame
self.layer.animateFrame(from: CGRect(origin: targetFrame.origin, size: CGSize(width: 1.0, height: targetFrame.height)), to: targetFrame, duration: 0.3, timingFunction: kCAMediaTimingFunctionSpring)
let targetFrame = self.containerNode.frame
self.containerNode.layer.animateFrame(from: CGRect(origin: targetFrame.origin, size: CGSize(width: 1.0, height: targetFrame.height)), to: targetFrame, duration: 0.3, timingFunction: kCAMediaTimingFunctionSpring)
self.backgroundNode.layer.animateFrame(from: CGRect(origin: targetFrame.origin, size: CGSize(width: 1.0, height: targetFrame.height)), to: targetFrame, duration: 0.3, timingFunction: kCAMediaTimingFunctionSpring)
self.iconNode.layer.animateScale(from: 0.1, to: 1.0, duration: 0.3, timingFunction: kCAMediaTimingFunctionSpring)
self.iconNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.15)
self.titleNode.layer.animateScale(from: 0.1, to: 1.0, duration: 0.3, timingFunction: kCAMediaTimingFunctionSpring)
@ -163,6 +168,7 @@ private final class TokenNode: ASDisplayNode {
}
let size = CGSize(width: self.isCollapsed ? height : width, height: height)
transition.updateFrame(node: self.containerNode, frame: CGRect(origin: CGPoint(), size: size))
transition.updateFrame(node: self.backgroundNode, frame: CGRect(origin: CGPoint(), size: size))
transition.updateFrame(node: self.titleNode, frame: CGRect(origin: CGPoint(x: leftInset, y: floor((height - titleSize.height) / 2.0)), size: titleSize))
@ -419,9 +425,14 @@ private class SearchBarTextField: UITextField, UIScrollViewDelegate {
}
}
private weak var _scrollView: UIScrollView?
var scrollView: UIScrollView? {
if let scrollView = self._scrollView {
return scrollView
}
for view in self.subviews {
if let scrollView = view as? UIScrollView {
_scrollView = scrollView
return scrollView
}
}
@ -459,8 +470,10 @@ private class SearchBarTextField: UITextField, UIScrollViewDelegate {
return CGRect(origin: CGPoint(), size: CGSize())
}
var rect = bounds.insetBy(dx: 7.0, dy: 4.0)
rect.origin.y += 1.0
if #available(iOS 14.0, *) {
} else {
rect.origin.y += 1.0
}
let prefixSize = self.measurePrefixLabel.updateLayout(CGSize(width: floor(bounds.size.width * 0.7), height: bounds.size.height))
if !prefixSize.width.isZero {
let prefixOffset = prefixSize.width + 3.0
@ -494,13 +507,19 @@ private class SearchBarTextField: UITextField, UIScrollViewDelegate {
textOffset += 2.0
}
var placeholderOffset: CGFloat = 0.0
if #available(iOS 14.0, *) {
placeholderOffset = 1.0
} else {
}
let textRect = self.textRect(forBounds: bounds)
let labelSize = self.placeholderLabel.updateLayout(textRect.size)
self.placeholderLabel.frame = CGRect(origin: CGPoint(x: textRect.minX, y: textRect.minY + textOffset), size: labelSize)
self.placeholderLabel.frame = CGRect(origin: CGPoint(x: textRect.minX, y: textRect.minY + textOffset + placeholderOffset), size: labelSize)
let prefixSize = self.prefixLabel.updateLayout(CGSize(width: floor(bounds.size.width * 0.7), height: bounds.size.height))
let prefixBounds = bounds.insetBy(dx: 4.0, dy: 4.0)
self.prefixLabel.frame = CGRect(origin: CGPoint(x: prefixBounds.minX, y: prefixBounds.minY + textOffset), size: prefixSize)
self.prefixLabel.frame = CGRect(origin: CGPoint(x: prefixBounds.minX, y: prefixBounds.minY + textOffset + placeholderOffset), size: prefixSize)
}
override func deleteBackward() {
@ -1046,7 +1065,9 @@ public class SearchBarNode: ASDisplayNode, UITextFieldDelegate {
public func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
if let _ = self.textField.selectedTokenIndex {
self.textField.selectedTokenIndex = nil
if !string.isEmpty {
self.textField.selectedTokenIndex = nil
}
if string.range(of: " ") != nil {
return false
}
@ -1090,21 +1111,19 @@ public class SearchBarNode: ASDisplayNode, UITextFieldDelegate {
private func updateIsEmpty(animated: Bool = false) {
let isEmpty = (self.textField.text?.isEmpty ?? true) && self.tokens.isEmpty
let transition: ContainedViewLayoutTransition = animated ? .animated(duration: 0.3, curve: .spring) : .immediate
let placeholderTransition = !isEmpty ? .immediate : transition
placeholderTransition.updateAlpha(node: self.textField.placeholderLabel, alpha: isEmpty ? 1.0 : 0.0)
let clearIsHidden = isEmpty && self.prefixString == nil
transition.updateAlpha(node: self.clearButton, alpha: clearIsHidden ? 0.0 : 1.0)
transition.updateAlpha(node: self.clearButton.imageNode, alpha: clearIsHidden ? 0.0 : 1.0)
transition.updateTransformScale(node: self.clearButton, scale: clearIsHidden ? 0.2 : 1.0)
self.clearButton.isUserInteractionEnabled = !clearIsHidden
}
@objc private func cancelPressed() {
if let cancel = self.cancel {
cancel()
}
self.cancel?()
}
@objc private func clearPressed() {

View File

@ -105,6 +105,9 @@ private final class ThemeAutoNightTimeSelectionActionSheetItemNode: ActionSheetI
self.pickerView.timeZone = TimeZone(secondsFromGMT: 0)
self.pickerView.date = Date(timeIntervalSince1970: Double(currentValue))
self.pickerView.locale = Locale.current
if #available(iOS 13.4, *) {
self.pickerView.preferredDatePickerStyle = .wheels
}
super.init(theme: theme)

View File

@ -701,9 +701,9 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = {
dict[-1449145777] = { return Api.upload.CdnFile.parse_cdnFile($0) }
dict[1984136919] = { return Api.wallet.LiteResponse.parse_liteResponse($0) }
dict[415997816] = { return Api.help.InviteText.parse_inviteText($0) }
dict[-1937807902] = { return Api.BotInlineMessage.parse_botInlineMessageText($0) }
dict[982505656] = { return Api.BotInlineMessage.parse_botInlineMessageMediaGeo($0) }
dict[1984755728] = { return Api.BotInlineMessage.parse_botInlineMessageMediaAuto($0) }
dict[-1937807902] = { return Api.BotInlineMessage.parse_botInlineMessageText($0) }
dict[-1222451611] = { return Api.BotInlineMessage.parse_botInlineMessageMediaGeo($0) }
dict[-1970903652] = { return Api.BotInlineMessage.parse_botInlineMessageMediaVenue($0) }
dict[416402882] = { return Api.BotInlineMessage.parse_botInlineMessageMediaContact($0) }
dict[-1673717362] = { return Api.InputPeerNotifySettings.parse_inputPeerNotifySettings($0) }

View File

@ -19856,14 +19856,27 @@ public extension Api {
}
public enum BotInlineMessage: TypeConstructorDescription {
case botInlineMessageText(flags: Int32, message: String, entities: [Api.MessageEntity]?, replyMarkup: Api.ReplyMarkup?)
case botInlineMessageMediaGeo(flags: Int32, geo: Api.GeoPoint, replyMarkup: Api.ReplyMarkup?)
case botInlineMessageMediaAuto(flags: Int32, message: String, entities: [Api.MessageEntity]?, replyMarkup: Api.ReplyMarkup?)
case botInlineMessageText(flags: Int32, message: String, entities: [Api.MessageEntity]?, replyMarkup: Api.ReplyMarkup?)
case botInlineMessageMediaGeo(flags: Int32, geo: Api.GeoPoint, period: Int32, replyMarkup: Api.ReplyMarkup?)
case botInlineMessageMediaVenue(flags: Int32, geo: Api.GeoPoint, title: String, address: String, provider: String, venueId: String, venueType: String, replyMarkup: Api.ReplyMarkup?)
case botInlineMessageMediaContact(flags: Int32, phoneNumber: String, firstName: String, lastName: String, vcard: String, replyMarkup: Api.ReplyMarkup?)
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
switch self {
case .botInlineMessageMediaAuto(let flags, let message, let entities, let replyMarkup):
if boxed {
buffer.appendInt32(1984755728)
}
serializeInt32(flags, buffer: buffer, boxed: false)
serializeString(message, buffer: buffer, boxed: false)
if Int(flags) & Int(1 << 1) != 0 {buffer.appendInt32(481674261)
buffer.appendInt32(Int32(entities!.count))
for item in entities! {
item.serialize(buffer, true)
}}
if Int(flags) & Int(1 << 2) != 0 {replyMarkup!.serialize(buffer, true)}
break
case .botInlineMessageText(let flags, let message, let entities, let replyMarkup):
if boxed {
buffer.appendInt32(-1937807902)
@ -19877,25 +19890,13 @@ public extension Api {
}}
if Int(flags) & Int(1 << 2) != 0 {replyMarkup!.serialize(buffer, true)}
break
case .botInlineMessageMediaGeo(let flags, let geo, let replyMarkup):
case .botInlineMessageMediaGeo(let flags, let geo, let period, let replyMarkup):
if boxed {
buffer.appendInt32(982505656)
buffer.appendInt32(-1222451611)
}
serializeInt32(flags, buffer: buffer, boxed: false)
geo.serialize(buffer, true)
if Int(flags) & Int(1 << 2) != 0 {replyMarkup!.serialize(buffer, true)}
break
case .botInlineMessageMediaAuto(let flags, let message, let entities, let replyMarkup):
if boxed {
buffer.appendInt32(1984755728)
}
serializeInt32(flags, buffer: buffer, boxed: false)
serializeString(message, buffer: buffer, boxed: false)
if Int(flags) & Int(1 << 1) != 0 {buffer.appendInt32(481674261)
buffer.appendInt32(Int32(entities!.count))
for item in entities! {
item.serialize(buffer, true)
}}
serializeInt32(period, buffer: buffer, boxed: false)
if Int(flags) & Int(1 << 2) != 0 {replyMarkup!.serialize(buffer, true)}
break
case .botInlineMessageMediaVenue(let flags, let geo, let title, let address, let provider, let venueId, let venueType, let replyMarkup):
@ -19927,12 +19928,12 @@ public extension Api {
public func descriptionFields() -> (String, [(String, Any)]) {
switch self {
case .botInlineMessageText(let flags, let message, let entities, let replyMarkup):
return ("botInlineMessageText", [("flags", flags), ("message", message), ("entities", entities), ("replyMarkup", replyMarkup)])
case .botInlineMessageMediaGeo(let flags, let geo, let replyMarkup):
return ("botInlineMessageMediaGeo", [("flags", flags), ("geo", geo), ("replyMarkup", replyMarkup)])
case .botInlineMessageMediaAuto(let flags, let message, let entities, let replyMarkup):
return ("botInlineMessageMediaAuto", [("flags", flags), ("message", message), ("entities", entities), ("replyMarkup", replyMarkup)])
case .botInlineMessageText(let flags, let message, let entities, let replyMarkup):
return ("botInlineMessageText", [("flags", flags), ("message", message), ("entities", entities), ("replyMarkup", replyMarkup)])
case .botInlineMessageMediaGeo(let flags, let geo, let period, let replyMarkup):
return ("botInlineMessageMediaGeo", [("flags", flags), ("geo", geo), ("period", period), ("replyMarkup", replyMarkup)])
case .botInlineMessageMediaVenue(let flags, let geo, let title, let address, let provider, let venueId, let venueType, let replyMarkup):
return ("botInlineMessageMediaVenue", [("flags", flags), ("geo", geo), ("title", title), ("address", address), ("provider", provider), ("venueId", venueId), ("venueType", venueType), ("replyMarkup", replyMarkup)])
case .botInlineMessageMediaContact(let flags, let phoneNumber, let firstName, let lastName, let vcard, let replyMarkup):
@ -19940,6 +19941,30 @@ public extension Api {
}
}
public static func parse_botInlineMessageMediaAuto(_ reader: BufferReader) -> BotInlineMessage? {
var _1: Int32?
_1 = reader.readInt32()
var _2: String?
_2 = parseString(reader)
var _3: [Api.MessageEntity]?
if Int(_1!) & Int(1 << 1) != 0 {if let _ = reader.readInt32() {
_3 = Api.parseVector(reader, elementSignature: 0, elementType: Api.MessageEntity.self)
} }
var _4: Api.ReplyMarkup?
if Int(_1!) & Int(1 << 2) != 0 {if let signature = reader.readInt32() {
_4 = Api.parse(reader, signature: signature) as? Api.ReplyMarkup
} }
let _c1 = _1 != nil
let _c2 = _2 != nil
let _c3 = (Int(_1!) & Int(1 << 1) == 0) || _3 != nil
let _c4 = (Int(_1!) & Int(1 << 2) == 0) || _4 != nil
if _c1 && _c2 && _c3 && _c4 {
return Api.BotInlineMessage.botInlineMessageMediaAuto(flags: _1!, message: _2!, entities: _3, replyMarkup: _4)
}
else {
return nil
}
}
public static func parse_botInlineMessageText(_ reader: BufferReader) -> BotInlineMessage? {
var _1: Int32?
_1 = reader.readInt32()
@ -19971,39 +19996,18 @@ public extension Api {
if let signature = reader.readInt32() {
_2 = Api.parse(reader, signature: signature) as? Api.GeoPoint
}
var _3: Api.ReplyMarkup?
if Int(_1!) & Int(1 << 2) != 0 {if let signature = reader.readInt32() {
_3 = Api.parse(reader, signature: signature) as? Api.ReplyMarkup
} }
let _c1 = _1 != nil
let _c2 = _2 != nil
let _c3 = (Int(_1!) & Int(1 << 2) == 0) || _3 != nil
if _c1 && _c2 && _c3 {
return Api.BotInlineMessage.botInlineMessageMediaGeo(flags: _1!, geo: _2!, replyMarkup: _3)
}
else {
return nil
}
}
public static func parse_botInlineMessageMediaAuto(_ reader: BufferReader) -> BotInlineMessage? {
var _1: Int32?
_1 = reader.readInt32()
var _2: String?
_2 = parseString(reader)
var _3: [Api.MessageEntity]?
if Int(_1!) & Int(1 << 1) != 0 {if let _ = reader.readInt32() {
_3 = Api.parseVector(reader, elementSignature: 0, elementType: Api.MessageEntity.self)
} }
var _3: Int32?
_3 = reader.readInt32()
var _4: Api.ReplyMarkup?
if Int(_1!) & Int(1 << 2) != 0 {if let signature = reader.readInt32() {
_4 = Api.parse(reader, signature: signature) as? Api.ReplyMarkup
} }
let _c1 = _1 != nil
let _c2 = _2 != nil
let _c3 = (Int(_1!) & Int(1 << 1) == 0) || _3 != nil
let _c3 = _3 != nil
let _c4 = (Int(_1!) & Int(1 << 2) == 0) || _4 != nil
if _c1 && _c2 && _c3 && _c4 {
return Api.BotInlineMessage.botInlineMessageMediaAuto(flags: _1!, message: _2!, entities: _3, replyMarkup: _4)
return Api.BotInlineMessage.botInlineMessageMediaGeo(flags: _1!, geo: _2!, period: _3!, replyMarkup: _4)
}
else {
return nil

View File

@ -423,8 +423,8 @@ extension ChatContextResultMessage {
parsedReplyMarkup = ReplyMarkupMessageAttribute(apiMarkup: replyMarkup)
}
self = .text(text: message, entities: parsedEntities, disableUrlPreview: (flags & (1 << 0)) != 0, replyMarkup: parsedReplyMarkup)
case let .botInlineMessageMediaGeo(_, geo, replyMarkup):
let media = telegramMediaMapFromApiGeoPoint(geo, title: nil, address: nil, provider: nil, venueId: nil, venueType: nil, liveBroadcastingTimeout: nil)
case let .botInlineMessageMediaGeo(_, geo, period, replyMarkup):
let media = telegramMediaMapFromApiGeoPoint(geo, title: nil, address: nil, provider: nil, venueId: nil, venueType: nil, liveBroadcastingTimeout: period)
var parsedReplyMarkup: ReplyMarkupMessageAttribute?
if let replyMarkup = replyMarkup {
parsedReplyMarkup = ReplyMarkupMessageAttribute(apiMarkup: replyMarkup)

View File

@ -238,7 +238,7 @@ public func searchMessages(account: Account, location: SearchMessagesLocation, q
} else {
let lowerBound = state?.main.messages.last.flatMap({ $0.index })
let signal: Signal<Api.messages.Messages, MTRpcError>
if peer.id.namespace == Namespaces.Peer.CloudChannel && query.isEmpty && tags == nil && minDate == nil && maxDate == nil {
if peer.id.namespace == Namespaces.Peer.CloudChannel && query.isEmpty && fromId == nil && tags == nil && minDate == nil && maxDate == nil {
signal = account.network.request(Api.functions.messages.getHistory(peer: inputPeer, offsetId: lowerBound?.id.id ?? 0, offsetDate: 0, addOffset: 0, limit: limit, maxId: Int32.max - 1, minId: 0, hash: 0))
} else {
signal = account.network.request(Api.functions.messages.search(flags: flags, peer: inputPeer, q: query, fromId: fromInputUser, topMsgId: topMsgId?.id, filter: filter, minDate: minDate ?? 0, maxDate: maxDate ?? (Int32.max - 1), offsetId: lowerBound?.id.id ?? 0, addOffset: 0, limit: limit, maxId: Int32.max - 1, minId: 0, hash: 0))

View File

@ -92,6 +92,10 @@ private final class ChatDateSelectorItemNode: ActionSheetItemNode {
self.pickerView.minimumDate = Date(timeIntervalSince1970: 1376438400.0)
self.pickerView.maximumDate = Date(timeIntervalSinceNow: 2.0)
if #available(iOS 13.4, *) {
self.pickerView.preferredDatePickerStyle = .wheels
}
super.init(theme: theme)
self.view.addSubview(self.pickerView)

View File

@ -188,6 +188,9 @@ class ChatScheduleTimeControllerNode: ViewControllerTracingNode, UIScrollViewDel
pickerView.minuteInterval = 1
self.contentContainerNode.view.addSubview(pickerView)
pickerView.addTarget(self, action: #selector(self.datePickerUpdated), for: .valueChanged)
if #available(iOS 13.4, *) {
pickerView.preferredDatePickerStyle = .wheels
}
self.pickerView = pickerView
self.updateMinimumDate(currentTime: currentTime)