From a8f46638526b60a32c7fe185e897d149aba7b01b Mon Sep 17 00:00:00 2001 From: Ilya Laktyushin Date: Mon, 28 Sep 2020 16:39:24 +0400 Subject: [PATCH] Search filters fixes --- .../Sources/ChatListControllerNode.swift | 7 ++- .../Sources/ChatListSearchContainerNode.swift | 54 +++++++++------- .../ChatListSearchFiltersContainerNode.swift | 6 +- .../Sources/ChatListSearchListPaneNode.swift | 39 +++++------- .../ChatListUI/Sources/DateSuggestion.swift | 63 ++++++++++++------- .../ChatHistorySearchContainerNode.swift | 2 +- 6 files changed, 100 insertions(+), 71 deletions(-) diff --git a/submodules/ChatListUI/Sources/ChatListControllerNode.swift b/submodules/ChatListUI/Sources/ChatListControllerNode.swift index b9d0a65c25..1aa28b6f09 100644 --- a/submodules/ChatListUI/Sources/ChatListControllerNode.swift +++ b/submodules/ChatListUI/Sources/ChatListControllerNode.swift @@ -1151,7 +1151,12 @@ final class ChatListControllerNode: ASDisplayNode { return nil } - let contentNode = ChatListSearchContainerNode(context: self.context, filter: [], groupId: self.groupId, openPeer: { [weak self] peer, dismissSearch in + var filter: ChatListNodePeersFilter = [] + if false, case .group = self.groupId { + filter.insert(.excludeRecent) + } + + let contentNode = ChatListSearchContainerNode(context: self.context, filter: filter, groupId: self.groupId, openPeer: { [weak self] peer, dismissSearch in self?.requestOpenPeerFromSearch?(peer, dismissSearch) }, openDisabledPeer: { _ in }, openRecentPeerOptions: { [weak self] peer in diff --git a/submodules/ChatListUI/Sources/ChatListSearchContainerNode.swift b/submodules/ChatListUI/Sources/ChatListSearchContainerNode.swift index 1303a08282..709257facb 100644 --- a/submodules/ChatListUI/Sources/ChatListSearchContainerNode.swift +++ b/submodules/ChatListUI/Sources/ChatListSearchContainerNode.swift @@ -39,7 +39,7 @@ private enum ChatListTokenId: Int32 { final class ChatListSearchInteraction { let openPeer: (Peer, Bool) -> Void let openDisabledPeer: (Peer) -> Void - let openMessage: (Peer, MessageId) -> Void + let openMessage: (Peer, MessageId, Bool) -> Void let openUrl: (String) -> Void let clearRecentSearch: () -> Void let addContact: (String) -> Void @@ -52,7 +52,7 @@ final class ChatListSearchInteraction { let updateSuggestedPeers: ([Peer], ChatListSearchPaneKey) -> Void let getSelectedMessageIds: () -> Set? - 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?) { + init(openPeer: @escaping (Peer, Bool) -> Void, openDisabledPeer: @escaping (Peer) -> Void, openMessage: @escaping (Peer, MessageId, Bool) -> 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?) { self.openPeer = openPeer self.openDisabledPeer = openDisabledPeer self.openMessage = openMessage @@ -102,7 +102,7 @@ public final class ChatListSearchContainerNode: SearchDisplayControllerContentNo private var presentationData: PresentationData private var presentationDataDisposable: Disposable? - private let suggestedDates = Promise<[(Date, String?)]>([]) + private let suggestedDates = Promise<[(Date?, Date, String?)]>([]) private let suggestedPeers = Promise<[Peer]>([]) private var suggestedFilters: [ChatListSearchFilter]? private let suggestedFiltersDisposable = MetaDisposable() @@ -149,8 +149,8 @@ public final class ChatListSearchContainerNode: SearchDisplayControllerContentNo } }, openDisabledPeer: { peer in openDisabledPeer(peer) - }, openMessage: { peer, messageId in - originalOpenMessage(peer, messageId, true) + }, openMessage: { peer, messageId, deactivateOnAction in + originalOpenMessage(peer, messageId, deactivateOnAction) if peer.id.namespace != Namespaces.Peer.SecretChat { addAppLogEvent(postbox: context.account.postbox, type: "search_global_open_message", peerId: peer.id, data: .dictionary(["msg_id": .number(Double(messageId.id))])) } @@ -269,7 +269,7 @@ public final class ChatListSearchContainerNode: SearchDisplayControllerContentNo } var key: ChatListSearchPaneKey? - var maxDate = strongSelf.currentSearchOptions.maxDate + var date = strongSelf.currentSearchOptions.date var peer = strongSelf.currentSearchOptions.peer switch filter { @@ -285,8 +285,8 @@ public final class ChatListSearchContainerNode: SearchDisplayControllerContentNo key = .music case .voice: key = .voice - case let .date(date, title): - maxDate = (date, title) + case let .date(minDate, maxDate, title): + date = (minDate, maxDate, title) case let .peer(id, isGroup, _, compactDisplayTitle): peer = (id, isGroup, compactDisplayTitle) } @@ -294,16 +294,28 @@ public final class ChatListSearchContainerNode: SearchDisplayControllerContentNo if let key = key { strongSelf.paneContainerNode.requestSelectPane(key) } else { - strongSelf.updateSearchOptions(strongSelf.currentSearchOptions.withUpdatedMaxDate(maxDate).withUpdatedPeer(peer), clearQuery: true) + strongSelf.updateSearchOptions(strongSelf.currentSearchOptions.withUpdatedDate(date).withUpdatedPeer(peer), clearQuery: true) } } - self.suggestedFiltersDisposable.set((combineLatest(self.suggestedPeers.get(), self.suggestedDates.get(), self.selectedFilterKeyPromise.get()) - |> mapToSignal { peers, dates, selectedFilter -> Signal<([Peer], [(Date, String?)], ChatListSearchFilterEntryId?), NoError> in - if (peers.isEmpty && dates.isEmpty) || peers.isEmpty { + let suggestedPeers = self.searchQuery.get() + |> mapToSignal { query -> Signal<[Peer], NoError> in + if let query = query { + return context.account.postbox.searchPeers(query: query.lowercased()) + |> map { local -> [Peer] in + return Array(local.compactMap { $0.peer }.prefix(10)) + } + } else { + return .single([]) + } + } + + self.suggestedFiltersDisposable.set((combineLatest(suggestedPeers, self.suggestedDates.get(), self.selectedFilterKeyPromise.get(), self.searchQuery.get()) + |> mapToSignal { peers, dates, selectedFilter, searchQuery -> Signal<([Peer], [(Date?, Date, String?)], ChatListSearchFilterEntryId?), NoError> in + if searchQuery?.isEmpty ?? true { return .single((peers, dates, selectedFilter)) } else { - return (.complete() |> delay(0.2, queue: Queue.mainQueue())) + return (.complete() |> delay(0.25, queue: Queue.mainQueue())) |> then(.single((peers, dates, selectedFilter))) } } |> map { peers, dates, selectedFilter -> [ChatListSearchFilter] in @@ -313,9 +325,9 @@ public final class ChatListSearchContainerNode: SearchDisplayControllerContentNo formatter.timeStyle = .none formatter.dateStyle = .medium - for (date, string) in dates { - let title = string ?? formatter.string(from: date) - suggestedFilters.append(.date(Int32(date.timeIntervalSince1970), title)) + for (minDate, maxDate, string) in dates { + let title = string ?? formatter.string(from: maxDate) + suggestedFilters.append(.date(minDate.flatMap { Int32($0.timeIntervalSince1970) }, Int32(maxDate.timeIntervalSince1970), title)) } } if !peers.isEmpty && selectedFilter != .filter(ChatListSearchFilter.chats.id) { @@ -339,7 +351,7 @@ public final class ChatListSearchContainerNode: SearchDisplayControllerContentNo } var filteredFilters: [ChatListSearchFilter] = [] for filter in filters { - if case .date = filter, strongSelf.searchOptionsValue?.maxDate == nil { + if case .date = filter, strongSelf.searchOptionsValue?.date == nil { filteredFilters.append(filter) } if case .peer = filter, strongSelf.searchOptionsValue?.peer == nil { @@ -390,7 +402,7 @@ public final class ChatListSearchContainerNode: SearchDisplayControllerContentNo } private var currentSearchOptions: ChatListSearchOptions { - return self.searchOptionsValue ?? ChatListSearchOptions(peer: nil, minDate: nil, maxDate: nil) + return self.searchOptionsValue ?? ChatListSearchOptions(peer: nil, date: nil) } public override func searchTokensUpdated(tokens: [SearchBarToken]) { @@ -399,8 +411,8 @@ public final class ChatListSearchContainerNode: SearchDisplayControllerContentNo for token in tokens { tokensIdSet.insert(token.id) } - if !tokensIdSet.contains(ChatListTokenId.date.rawValue) && updatedOptions?.maxDate != nil { - updatedOptions = updatedOptions?.withUpdatedMaxDate(nil) + if !tokensIdSet.contains(ChatListTokenId.date.rawValue) && updatedOptions?.date != nil { + updatedOptions = updatedOptions?.withUpdatedDate(nil) } if !tokensIdSet.contains(ChatListTokenId.peer.rawValue) && updatedOptions?.peer != nil { updatedOptions = updatedOptions?.withUpdatedPeer(nil) @@ -429,7 +441,7 @@ public final class ChatListSearchContainerNode: SearchDisplayControllerContentNo tokens.append(SearchBarToken(id: ChatListTokenId.peer.rawValue, icon:image, title: peerName)) } - if let (_, dateTitle) = options?.maxDate { + if let (_, _, dateTitle) = options?.date { tokens.append(SearchBarToken(id: ChatListTokenId.date.rawValue, icon: UIImage(bundleImageName: "Chat List/Search/Calendar"), title: dateTitle)) self.suggestedDates.set(.single([])) diff --git a/submodules/ChatListUI/Sources/ChatListSearchFiltersContainerNode.swift b/submodules/ChatListUI/Sources/ChatListSearchFiltersContainerNode.swift index 3c2ca17581..95dbe65460 100644 --- a/submodules/ChatListUI/Sources/ChatListSearchFiltersContainerNode.swift +++ b/submodules/ChatListUI/Sources/ChatListSearchFiltersContainerNode.swift @@ -15,7 +15,7 @@ enum ChatListSearchFilter: Equatable { case music case voice case peer(PeerId, Bool, String, String) - case date(Int32, String) + case date(Int32?, Int32, String) var id: Int32 { switch self { @@ -33,7 +33,7 @@ enum ChatListSearchFilter: Equatable { return 5 case let .peer(peerId, _, _, _): return peerId.id - case let .date(date, _): + case let .date(_, date, _): return date } } @@ -139,7 +139,7 @@ private final class ItemNode: ASDisplayNode { image = UIImage(bundleImageName: "Chat List/Search/User") } icon = generateTintedImage(image: image, color: color) - case let .date(_, displayTitle): + case let .date(_, _, displayTitle): title = displayTitle icon = generateTintedImage(image: UIImage(bundleImageName: "Chat List/Search/Calendar"), color: color) } diff --git a/submodules/ChatListUI/Sources/ChatListSearchListPaneNode.swift b/submodules/ChatListUI/Sources/ChatListSearchListPaneNode.swift index 033f9e5c0c..2317a930e1 100644 --- a/submodules/ChatListUI/Sources/ChatListSearchListPaneNode.swift +++ b/submodules/ChatListUI/Sources/ChatListSearchListPaneNode.swift @@ -615,23 +615,18 @@ public enum ChatListSearchContextActionSource { public struct ChatListSearchOptions { let peer: (PeerId, Bool, String)? - let minDate: (Int32, String)? - let maxDate: (Int32, String)? + let date: (Int32?, Int32, String)? var isEmpty: Bool { - return self.peer == nil && self.minDate == nil && self.maxDate == nil + return self.peer == nil && self.date == nil } func withUpdatedPeer(_ peerIdIsGroupAndName: (PeerId, Bool, String)?) -> ChatListSearchOptions { - return ChatListSearchOptions(peer: peerIdIsGroupAndName, minDate: self.minDate, maxDate: self.maxDate) + return ChatListSearchOptions(peer: peerIdIsGroupAndName, date: self.date) } - func withUpdatedMinDate(_ minDateAndTitle: (Int32, String)?) -> ChatListSearchOptions { - return ChatListSearchOptions(peer: self.peer, minDate: minDateAndTitle, maxDate: self.maxDate) - } - - func withUpdatedMaxDate(_ maxDateAndTitle: (Int32, String)?) -> ChatListSearchOptions { - return ChatListSearchOptions(peer: self.peer, minDate: self.minDate, maxDate: maxDateAndTitle) + func withUpdatedDate(_ minDateMaxDateAndTitle: (Int32?, Int32, String)?) -> ChatListSearchOptions { + return ChatListSearchOptions(peer: self.peer, date: minDateMaxDateAndTitle) } } @@ -880,12 +875,12 @@ final class ChatListSearchListPaneNode: ASDisplayNode, ChatListSearchPaneNode { let location: SearchMessagesLocation if let options = options { if let (peerId, _, _) = options.peer { - location = .peer(peerId: peerId, fromId: nil, tags: tagMask, topMsgId: nil, minDate: options.minDate?.0, maxDate: options.maxDate?.0) + location = .peer(peerId: peerId, fromId: nil, tags: tagMask, topMsgId: nil, minDate: options.date?.0, maxDate: options.date?.1) } else { if let groupId = groupId { - location = .group(groupId: groupId, tags: tagMask, minDate: options.minDate?.0, maxDate: options.maxDate?.0) + location = .group(groupId: groupId, tags: tagMask, minDate: options.date?.0, maxDate: options.date?.1) } else { - location = .general(tags: tagMask, minDate: options.minDate?.0, maxDate: options.maxDate?.0) + location = .general(tags: tagMask, minDate: options.date?.0, maxDate: options.date?.1) } } } else { @@ -1208,8 +1203,8 @@ final class ChatListSearchListPaneNode: ASDisplayNode, ChatListSearchPaneNode { }, additionalCategorySelected: { _ in }, messageSelected: { [weak self] peer, message, _ in interaction.dismissInput() - if let peer = message.peers[message.id.peerId] { - interaction.openMessage(peer, message.id) + if let strongSelf = self, let peer = message.peers[message.id.peerId] { + interaction.openMessage(peer, message.id, strongSelf.key == .chats) } self?.listNode.clearHighlightAnimated(true) }, groupSelected: { _ in @@ -1336,7 +1331,7 @@ final class ChatListSearchListPaneNode: ASDisplayNode, ChatListSearchPaneNode { } } - if strongSelf.tagMask != nil || strongSelf.searchOptionsValue?.maxDate != nil || strongSelf.searchOptionsValue?.peer != nil { + if strongSelf.tagMask != nil || strongSelf.searchOptionsValue?.date != nil || strongSelf.searchOptionsValue?.peer != nil { entriesAndFlags?.0 = filteredEntries } } @@ -2013,7 +2008,7 @@ final class ChatListSearchListPaneNode: ASDisplayNode, ChatListSearchPaneNode { emptyResultsTitle = strongSelf.presentationData.strings.ChatList_Search_NoResults emptyResultsText = strongSelf.presentationData.strings.ChatList_Search_NoResultsQueryDescription(query).0 } else { - if let searchOptions = searchOptions, searchOptions.minDate == nil && searchOptions.maxDate == nil && searchOptions.peer == nil { + if let searchOptions = searchOptions, searchOptions.date == nil && searchOptions.peer == nil { emptyResultsTitle = strongSelf.presentationData.strings.ChatList_Search_NoResultsFilter if strongSelf.tagMask == .photoOrVideo { emptyResultsText = strongSelf.presentationData.strings.ChatList_Search_NoResultsFitlerMedia @@ -2047,7 +2042,7 @@ final class ChatListSearchListPaneNode: ASDisplayNode, ChatListSearchPaneNode { strongSelf.emptyResultsTextNode.isHidden = !emptyResults strongSelf.emptyResultsAnimationNode.visibility = emptyResults - let displayPlaceholder = transition.isLoading && (strongSelf.key != .chats || strongSelf.searchOptionsValue?.peer != nil || strongSelf.searchOptionsValue?.minDate != nil || strongSelf.searchOptionsValue?.maxDate != nil) + let displayPlaceholder = transition.isLoading && (strongSelf.key != .chats || strongSelf.searchOptionsValue?.peer != nil || strongSelf.searchOptionsValue?.date != nil) ContainedViewLayoutTransition.animated(duration: 0.2, curve: .easeInOut).updateAlpha(node: strongSelf.shimmerNode, alpha: displayPlaceholder ? 1.0 : 0.0) strongSelf.recentListNode.isHidden = displayingResults || strongSelf.peersFilter.contains(.excludeRecent) @@ -2274,7 +2269,7 @@ private final class ChatListSearchShimmerNode: ASDisplayNode { return ListMessageItem(presentationData: ChatPresentationData(presentationData: presentationData), context: context, chatLocation: .peer(peer1.id), interaction: ListMessageItemInteraction.default, message: message, selection: .none, displayHeader: false, customHeader: nil, hintIsLink: true, isGlobalSearchResult: true) case .files: var media: [Media] = [] - media.append(TelegramMediaFile(fileId: MediaId(namespace: 0, id: 0), partialReference: nil, resource: LocalFileMediaResource(fileId: 0), previewRepresentations: [], videoThumbnails: [], immediateThumbnailData: nil, mimeType: "audio/ogg", size: 0, attributes: [.Audio(isVoice: false, duration: 0, title: nil, performer: nil, waveform: MemoryBuffer(data: Data()))])) + media.append(TelegramMediaFile(fileId: MediaId(namespace: 0, id: 0), partialReference: nil, resource: LocalFileMediaResource(fileId: 0), previewRepresentations: [], videoThumbnails: [], immediateThumbnailData: nil, mimeType: "application/text", size: 0, attributes: [.FileName(fileName: "Text.txt")])) let message = Message(stableId: 0, stableVersion: 0, id: MessageId(peerId: peer1.id, namespace: 0, id: 0), globallyUniqueId: nil, groupingKey: nil, groupInfo: nil, threadId: nil, timestamp: timestamp1, flags: [], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: peer1, text: "Text", attributes: [], media: media, peers: peers, associatedMessages: SimpleDictionary(), associatedMessageIds: []) return ListMessageItem(presentationData: ChatPresentationData(presentationData: presentationData), context: context, chatLocation: .peer(peer1.id), interaction: ListMessageItemInteraction.default, message: message, selection: .none, displayHeader: false, customHeader: nil, hintIsLink: false, isGlobalSearchResult: true) @@ -2356,7 +2351,7 @@ private final class ChatListSearchShimmerNode: ASDisplayNode { fillLabelPlaceholderRect(origin: CGPoint(x: titleFrame.minX + 120.0 + 10.0, y: currentY + floor((itemHeight - fakeLabelPlaceholderHeight) / 2.0)), width: 60.0) let dateFrame = itemNode.dateNode.frame.offsetBy(dx: 0.0, dy: currentY) - fillLabelPlaceholderRect(origin: CGPoint(x: dateFrame.maxX - 30.0, y: dateFrame.minY), width: 30.0) + fillLabelPlaceholderRect(origin: CGPoint(x: dateFrame.maxX - 30.0, y: floor(dateFrame.midY - fakeLabelPlaceholderHeight / 2.0)), width: 30.0) context.setBlendMode(.normal) context.setFillColor(presentationData.theme.chatList.itemSeparatorColor.cgColor) @@ -2381,7 +2376,7 @@ private final class ChatListSearchShimmerNode: ASDisplayNode { fillLabelPlaceholderRect(origin: CGPoint(x: descriptionFrame.minX, y: floor(descriptionFrame.midY - fakeLabelPlaceholderHeight / 2.0)), width: isVoice ? 60.0 : 240.0) let dateFrame = itemNode.dateNode.frame.offsetBy(dx: 0.0, dy: currentY) - fillLabelPlaceholderRect(origin: CGPoint(x: dateFrame.maxX - 30.0, y: dateFrame.minY), width: 30.0) + fillLabelPlaceholderRect(origin: CGPoint(x: dateFrame.maxX - 30.0, y: floor(dateFrame.midY - fakeLabelPlaceholderHeight / 2.0)), width: 30.0) context.setBlendMode(.normal) context.setFillColor(presentationData.theme.chatList.itemSeparatorColor.cgColor) @@ -2401,7 +2396,7 @@ private final class ChatListSearchShimmerNode: ASDisplayNode { fillLabelPlaceholderRect(origin: CGPoint(x: authorFrame.minX, y: floor(authorFrame.midY - fakeLabelPlaceholderHeight / 2.0)), width: 60.0) let dateFrame = itemNode.dateNode.frame.offsetBy(dx: 0.0, dy: currentY) - fillLabelPlaceholderRect(origin: CGPoint(x: dateFrame.maxX - 30.0, y: dateFrame.minY), width: 30.0) + fillLabelPlaceholderRect(origin: CGPoint(x: dateFrame.maxX - 30.0, y: floor(dateFrame.midY - fakeLabelPlaceholderHeight / 2.0)), width: 30.0) context.setBlendMode(.normal) context.setFillColor(presentationData.theme.chatList.itemSeparatorColor.cgColor) diff --git a/submodules/ChatListUI/Sources/DateSuggestion.swift b/submodules/ChatListUI/Sources/DateSuggestion.swift index 6a85e9b16a..d43602be7b 100644 --- a/submodules/ChatListUI/Sources/DateSuggestion.swift +++ b/submodules/ChatListUI/Sources/DateSuggestion.swift @@ -4,7 +4,7 @@ import TelegramStringFormatting private let telegramReleaseDate = Date(timeIntervalSince1970: 1376438400.0) -func suggestDates(for string: String, strings: PresentationStrings, dateTimeFormat: PresentationDateTimeFormat) -> [(Date, String?)] { +func suggestDates(for string: String, strings: PresentationStrings, dateTimeFormat: PresentationDateTimeFormat) -> [(minDate: Date?, maxDate: Date, string: String?)] { let string = string.folding(options: .diacriticInsensitive, locale: .current).trimmingCharacters(in: .whitespacesAndNewlines).lowercased() if string.count < 3 { return [] @@ -39,9 +39,14 @@ func suggestDates(for string: String, strings: PresentationStrings, dateTimeForm let yesterday = strings.Weekday_Yesterday let dateSeparator = dateTimeFormat.dateSeparator - var result: [(Date, String?)] = [] + var result: [(Date?, Date, String?)] = [] let calendar = Calendar.current + func getLowerDate(for date: Date) -> Date { + let components = calendar.dateComponents(in: .current, from: date) + let upperComponents = DateComponents(year: components.year, month: components.month, day: components.day, hour: 0, minute: 0, second: 0) + return calendar.date(from: upperComponents)! + } func getUpperDate(for date: Date) -> Date { let components = calendar.dateComponents(in: .current, from: date) let upperComponents = DateComponents(year: components.year, month: components.month, day: components.day, hour: 23, minute: 59, second: 59) @@ -54,15 +59,23 @@ func suggestDates(for string: String, strings: PresentationStrings, dateTimeForm return [] } - let midnight = calendar.startOfDay(for: now) + let midnightDate = calendar.startOfDay(for: now) if today.lowercased().hasPrefix(string) { - let todayDate = getUpperDate(for: midnight) - result.append((todayDate, today)) + let todayDate = getUpperDate(for: midnightDate) + result.append((midnightDate, todayDate, today)) } if yesterday.lowercased().hasPrefix(string) { - let yesterdayMidnight = calendar.date(byAdding: .day, value: -1, to: midnight)! + let yesterdayMidnight = calendar.date(byAdding: .day, value: -1, to: midnightDate)! let yesterdayDate = getUpperDate(for: yesterdayMidnight) - result.append((yesterdayDate, yesterday)) + result.append((yesterdayMidnight, yesterdayDate, yesterday)) + } + + func getLowerMonthDate(month: Int, year: Int) -> Date { + let monthComponents = DateComponents(year: year, month: month) + let date = calendar.date(from: monthComponents)! + let range = calendar.range(of: .day, in: .month, for: date)! + let upperComponents = DateComponents(year: year, month: month, day: 1, hour: 0, minute: 0, second: 0) + return calendar.date(from: upperComponents)! } func getUpperMonthDate(month: Int, year: Int) -> Date { @@ -77,9 +90,10 @@ func suggestDates(for string: String, strings: PresentationStrings, dateTimeForm let decimalRange = string.rangeOfCharacter(from: .decimalDigits) if decimalRange != nil { if string.count == 4, let value = Int(string), value <= year { - let date = getUpperMonthDate(month: 12, year: value) - if date > telegramReleaseDate { - result.append((date, "\(value)")) + let minDate = getLowerMonthDate(month: 1, year: value) + let maxDate = getUpperMonthDate(month: 12, year: value) + if maxDate > telegramReleaseDate { + result.append((minDate, maxDate, "\(value)")) } } else { do { @@ -95,11 +109,11 @@ func suggestDates(for string: String, strings: PresentationStrings, dateTimeForm if stringComponents.count < 3 { for i in 0..<5 { if let date = calendar.date(byAdding: .year, value: -i, to: resultDate) { - result.append((date, nil)) + result.append((nil, date, nil)) } } } else if resultDate < now { - result.append((resultDate, nil)) + result.append((nil, resultDate, nil)) } } let dd = try NSDataDetector(types: NSTextCheckingResult.CheckingType.date.rawValue) @@ -121,13 +135,14 @@ func suggestDates(for string: String, strings: PresentationStrings, dateTimeForm 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) + let lowerAnchorDate = getLowerDate(for: date) + let upperAnchorDate = 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)) + if let lowerDate = calendar.date(byAdding: .hour, value: -24 * 7 * i, to: lowerAnchorDate), let upperDate = calendar.date(byAdding: .hour, value: -24 * 7 * i, to: upperAnchorDate) { + if calendar.isDate(upperDate, equalTo: now, toGranularity: .weekOfYear) { + result.append((lowerDate, upperDate, value.0)) } else { - result.append((date, nil)) + result.append((lowerDate, upperDate, nil)) } } } @@ -143,15 +158,17 @@ func suggestDates(for string: String, strings: PresentationStrings, dateTimeForm 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)))) + let lowerDate = getLowerMonthDate(month: month, year: year) + let upperDate = getUpperMonthDate(month: month, year: year) + if upperDate <= now && upperDate > telegramReleaseDate { + result.append((lowerDate, upperDate, 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, stringForMonth(strings: strings, month: Int32(month - 1), ofYear: Int32(i - 1900)))) + let lowerDate = getUpperMonthDate(month: month, year: i) + let upperDate = getUpperMonthDate(month: month, year: i) + if upperDate <= now && upperDate > telegramReleaseDate { + result.append((lowerDate, upperDate, stringForMonth(strings: strings, month: Int32(month - 1), ofYear: Int32(i - 1900)))) } } } diff --git a/submodules/TelegramUI/Sources/ChatHistorySearchContainerNode.swift b/submodules/TelegramUI/Sources/ChatHistorySearchContainerNode.swift index c2e5c5df56..bed8167a49 100644 --- a/submodules/TelegramUI/Sources/ChatHistorySearchContainerNode.swift +++ b/submodules/TelegramUI/Sources/ChatHistorySearchContainerNode.swift @@ -286,7 +286,7 @@ final class ChatHistorySearchContainerNode: SearchDisplayControllerContentNode { transition.updateFrame(node: self.emptyResultsTextNode, frame: CGRect(origin: CGPoint(x: layout.safeInsets.left + padding + (layout.size.width - layout.safeInsets.left - layout.safeInsets.right - padding * 2.0 - emptyTextSize.width) / 2.0, y: emptyTitleY + emptyTitleSize.height + emptyTextSpacing), size: emptyTextSize)) self.listNode.frame = CGRect(origin: CGPoint(), size: layout.size) - self.listNode.transaction(deleteIndices: [], insertIndicesAndItems: [], updateIndicesAndItems: [], options: [.Synchronous], scrollToItem: nil, updateSizeAndInsets: ListViewUpdateSizeAndInsets(size: layout.size, insets: UIEdgeInsets(top: topInset, left: 0.0, bottom: layout.intrinsicInsets.bottom, right: 0.0), duration: 0.0, curve: .Default(duration: nil)), stationaryItemRange: nil, updateOpaqueState: nil, completion: { _ in }) + self.listNode.transaction(deleteIndices: [], insertIndicesAndItems: [], updateIndicesAndItems: [], options: [.Synchronous], scrollToItem: nil, updateSizeAndInsets: ListViewUpdateSizeAndInsets(size: layout.size, insets: UIEdgeInsets(top: topInset, left: layout.safeInsets.left, bottom: layout.intrinsicInsets.bottom, right: layout.safeInsets.right), duration: 0.0, curve: .Default(duration: nil)), stationaryItemRange: nil, updateOpaqueState: nil, completion: { _ in }) if firstValidLayout {