Various improvements
This commit is contained in:
parent
18abe71dca
commit
34477605b1
35 changed files with 600 additions and 268 deletions
|
|
@ -815,7 +815,7 @@ class DefaultIntentHandler: INExtension, INSendMessageIntentHandling, INSearchFo
|
|||
|
||||
if let searchTerm = searchTerm {
|
||||
if !searchTerm.isEmpty {
|
||||
for renderedPeer in transaction.searchPeers(query: searchTerm) {
|
||||
for renderedPeer in transaction.searchPeers(query: searchTerm, predicate: nil) {
|
||||
if let peer = renderedPeer.peer, !(peer is TelegramSecretChat), !peer.isDeleted {
|
||||
peers.append(peer)
|
||||
}
|
||||
|
|
@ -988,7 +988,7 @@ private final class WidgetIntentHandler {
|
|||
|
||||
if let searchTerm = searchTerm {
|
||||
if !searchTerm.isEmpty {
|
||||
for renderedPeer in transaction.searchPeers(query: searchTerm) {
|
||||
for renderedPeer in transaction.searchPeers(query: searchTerm, predicate: nil) {
|
||||
if let peer = renderedPeer.peer, !(peer is TelegramSecretChat), !peer.isDeleted {
|
||||
peers.append(peer)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -34,7 +34,7 @@ private enum InnerState: Equatable {
|
|||
|
||||
public final class AuthorizationSequenceController: NavigationController, ASAuthorizationControllerDelegate, ASAuthorizationControllerPresentationContextProviding {
|
||||
static func navigationBarTheme(_ theme: PresentationTheme) -> NavigationBarTheme {
|
||||
return NavigationBarTheme(overallDarkAppearance: theme.overallDarkAppearance, buttonColor: theme.chat.inputPanel.panelControlColor, disabledButtonColor: theme.intro.disabledTextColor, primaryTextColor: theme.intro.primaryTextColor, backgroundColor: .clear, opaqueBackgroundColor: .clear, enableBackgroundBlur: false, separatorColor: .clear, badgeBackgroundColor: theme.rootController.navigationBar.badgeBackgroundColor, badgeStrokeColor: theme.rootController.navigationBar.badgeStrokeColor, badgeTextColor: theme.rootController.navigationBar.badgeTextColor, edgeEffectColor: .clear, style: .glass)
|
||||
return NavigationBarTheme(overallDarkAppearance: theme.overallDarkAppearance, buttonColor: theme.chat.inputPanel.panelControlColor, disabledButtonColor: theme.intro.disabledTextColor, primaryTextColor: theme.intro.primaryTextColor, backgroundColor: .clear, opaqueBackgroundColor: .clear, enableBackgroundBlur: false, separatorColor: .clear, badgeBackgroundColor: theme.rootController.navigationBar.badgeBackgroundColor, badgeStrokeColor: theme.rootController.navigationBar.badgeStrokeColor, badgeTextColor: theme.rootController.navigationBar.badgeTextColor, edgeEffectColor: .clear, accentButtonColor: theme.list.itemCheckColors.fillColor, accentForegroundColor: theme.list.itemCheckColors.foregroundColor, style: .glass)
|
||||
}
|
||||
|
||||
private let sharedContext: SharedAccountContext
|
||||
|
|
|
|||
|
|
@ -1949,7 +1949,21 @@ final class ChatListControllerNode: ASDisplayNode, ASGestureRecognizerDelegate {
|
|||
//filter.insert(.excludeRecent)
|
||||
}
|
||||
|
||||
let contentNode = ChatListSearchContainerNode(context: self.context, animationCache: self.animationCache, animationRenderer: self.animationRenderer, filter: filter, requestPeerType: nil, location: effectiveLocation, displaySearchFilters: displaySearchFilters, hasDownloads: hasDownloads, initialFilter: initialFilter, openPeer: { [weak self] peer, _, threadId, dismissSearch in
|
||||
var folder: (Int32, String)?
|
||||
if let folders = self.controller?.tabContainerData?.0 {
|
||||
switch self.effectiveContainerNode.currentItemFilter {
|
||||
case .all:
|
||||
break
|
||||
case let .filter(id):
|
||||
if let value = folders.first(where: { $0.id == .filter(id) }) {
|
||||
if case let .filter(_, text, _) = value {
|
||||
folder = (id, text.text)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let contentNode = ChatListSearchContainerNode(context: self.context, animationCache: self.animationCache, animationRenderer: self.animationRenderer, filter: filter, requestPeerType: nil, location: effectiveLocation, folder: folder, displaySearchFilters: displaySearchFilters, hasDownloads: hasDownloads, initialFilter: initialFilter, openPeer: { [weak self] peer, _, threadId, dismissSearch in
|
||||
self?.requestOpenPeerFromSearch?(peer, threadId, dismissSearch)
|
||||
}, openDisabledPeer: { _, _, _ in
|
||||
}, openRecentPeerOptions: { [weak self] peer in
|
||||
|
|
|
|||
|
|
@ -43,6 +43,7 @@ import ComponentDisplayAdapters
|
|||
|
||||
private enum ChatListTokenId: Int32 {
|
||||
case archive
|
||||
case folder
|
||||
case forum
|
||||
case filter
|
||||
case peer
|
||||
|
|
@ -102,6 +103,7 @@ public final class ChatListSearchContainerNode: SearchDisplayControllerContentNo
|
|||
private let peersFilter: ChatListNodePeersFilter
|
||||
private let requestPeerType: [ReplyMarkupButtonRequestPeerType]?
|
||||
private var location: ChatListControllerLocation
|
||||
private var folder: (Int32, String)?
|
||||
private let displaySearchFilters: Bool
|
||||
private let hasDownloads: Bool
|
||||
private var interaction: ChatListSearchInteraction?
|
||||
|
|
@ -165,7 +167,7 @@ public final class ChatListSearchContainerNode: SearchDisplayControllerContentNo
|
|||
private var recentAppsDisposable: Disposable?
|
||||
private var refreshedGlobalPostSearchStateDisposable: Disposable?
|
||||
|
||||
public init(context: AccountContext, animationCache: AnimationCache, animationRenderer: MultiAnimationRenderer, updatedPresentationData: (initial: PresentationData, signal: Signal<PresentationData, NoError>)? = nil, filter: ChatListNodePeersFilter, requestPeerType: [ReplyMarkupButtonRequestPeerType]?, location: ChatListControllerLocation, displaySearchFilters: Bool, hasDownloads: Bool, initialFilter: ChatListSearchFilter = .chats, openPeer originalOpenPeer: @escaping (EnginePeer, EnginePeer?, Int64?, Bool) -> Void, openDisabledPeer: @escaping (EnginePeer, Int64?, ChatListDisabledPeerReason) -> Void, openRecentPeerOptions: @escaping (EnginePeer) -> Void, openMessage originalOpenMessage: @escaping (EnginePeer, Int64?, EngineMessage.Id, Bool) -> Void, addContact: ((String) -> Void)?, peerContextAction: ((EnginePeer, ChatListSearchContextActionSource, ASDisplayNode, ContextGesture?, CGPoint?) -> Void)?, present: @escaping (ViewController, Any?) -> Void, presentInGlobalOverlay: @escaping (ViewController, Any?) -> Void, navigationController: NavigationController?, parentController: @escaping () -> ViewController?) {
|
||||
public init(context: AccountContext, animationCache: AnimationCache, animationRenderer: MultiAnimationRenderer, updatedPresentationData: (initial: PresentationData, signal: Signal<PresentationData, NoError>)? = nil, filter: ChatListNodePeersFilter, requestPeerType: [ReplyMarkupButtonRequestPeerType]?, location: ChatListControllerLocation, folder: (Int32, String)?, displaySearchFilters: Bool, hasDownloads: Bool, initialFilter: ChatListSearchFilter = .chats, openPeer originalOpenPeer: @escaping (EnginePeer, EnginePeer?, Int64?, Bool) -> Void, openDisabledPeer: @escaping (EnginePeer, Int64?, ChatListDisabledPeerReason) -> Void, openRecentPeerOptions: @escaping (EnginePeer) -> Void, openMessage originalOpenMessage: @escaping (EnginePeer, Int64?, EngineMessage.Id, Bool) -> Void, addContact: ((String) -> Void)?, peerContextAction: ((EnginePeer, ChatListSearchContextActionSource, ASDisplayNode, ContextGesture?, CGPoint?) -> Void)?, present: @escaping (ViewController, Any?) -> Void, presentInGlobalOverlay: @escaping (ViewController, Any?) -> Void, navigationController: NavigationController?, parentController: @escaping () -> ViewController?) {
|
||||
var initialFilter = initialFilter
|
||||
if case .chats = initialFilter, case .forum = location {
|
||||
initialFilter = .topics
|
||||
|
|
@ -175,6 +177,9 @@ public final class ChatListSearchContainerNode: SearchDisplayControllerContentNo
|
|||
self.peersFilter = filter
|
||||
self.requestPeerType = requestPeerType
|
||||
self.location = location
|
||||
|
||||
self.folder = folder
|
||||
|
||||
self.displaySearchFilters = displaySearchFilters
|
||||
self.hasDownloads = hasDownloads
|
||||
self.navigationController = navigationController
|
||||
|
|
@ -194,6 +199,11 @@ public final class ChatListSearchContainerNode: SearchDisplayControllerContentNo
|
|||
self.paneContainerNode.clipsToBounds = true
|
||||
|
||||
super.init()
|
||||
|
||||
if let folder {
|
||||
self.searchOptionsValue = self.currentSearchOptions.withUpdatedFolder(folder)
|
||||
self.searchOptions.set(.single(self.currentSearchOptions))
|
||||
}
|
||||
|
||||
self.backgroundColor = filter.contains(.excludeRecent) ? nil : self.presentationData.theme.chatList.backgroundColor
|
||||
|
||||
|
|
@ -588,7 +598,7 @@ public final class ChatListSearchContainerNode: SearchDisplayControllerContentNo
|
|||
}
|
||||
|
||||
private var currentSearchOptions: ChatListSearchOptions {
|
||||
return self.searchOptionsValue ?? ChatListSearchOptions(peer: nil, date: nil)
|
||||
return self.searchOptionsValue ?? ChatListSearchOptions(peer: nil, date: nil, folder: nil)
|
||||
}
|
||||
|
||||
public override func searchTokensUpdated(tokens: [SearchBarToken]) {
|
||||
|
|
@ -609,12 +619,19 @@ public final class ChatListSearchContainerNode: SearchDisplayControllerContentNo
|
|||
if !tokensIdSet.contains(ChatListTokenId.peer.rawValue) && updatedOptions?.peer != nil {
|
||||
updatedOptions = updatedOptions?.withUpdatedPeer(nil)
|
||||
}
|
||||
if !tokensIdSet.contains(ChatListTokenId.folder.rawValue) && updatedOptions?.folder != nil {
|
||||
updatedOptions = updatedOptions?.withUpdatedFolder(nil)
|
||||
self.folder = nil
|
||||
}
|
||||
self.updateSearchOptions(updatedOptions)
|
||||
}
|
||||
|
||||
private func updateSearchOptions(_ options: ChatListSearchOptions?, clearQuery: Bool = false) {
|
||||
var options = options
|
||||
var tokens: [SearchBarToken] = []
|
||||
if let folder = self.folder {
|
||||
tokens.append(SearchBarToken(id: ChatListTokenId.folder.rawValue, icon: nil, iconOffset: 0.0, peer: nil, title: folder.1, permanent: false))
|
||||
}
|
||||
if case .chatList(.archive) = self.location {
|
||||
tokens.append(SearchBarToken(id: ChatListTokenId.archive.rawValue, icon: UIImage(bundleImageName: "Chat List/Search/Archive"), iconOffset: -1.0, title: self.presentationData.strings.ChatList_Archive, permanent: false))
|
||||
} else if case .forum = self.location, let forumPeer = self.forumPeer {
|
||||
|
|
@ -737,10 +754,13 @@ public final class ChatListSearchContainerNode: SearchDisplayControllerContentNo
|
|||
key = .chats
|
||||
}
|
||||
self.paneContainerNode.requestSelectPane(key)
|
||||
self.updateSearchOptions(nil)
|
||||
self.updateSearchOptions(self.currentSearchOptions)
|
||||
self.searchTextUpdated(text: query ?? "")
|
||||
|
||||
var tokens: [SearchBarToken] = []
|
||||
if let folder = self.folder {
|
||||
tokens.append(SearchBarToken(id: ChatListTokenId.folder.rawValue, icon: nil, iconOffset: 0.0, peer: nil, title: folder.1, permanent: false))
|
||||
}
|
||||
if case .chatList(.archive) = self.location {
|
||||
tokens.append(SearchBarToken(id: ChatListTokenId.archive.rawValue, icon: UIImage(bundleImageName: "Chat List/Search/Archive"), iconOffset: -1.0, title: self.presentationData.strings.ChatList_Archive, permanent: false))
|
||||
} else if case .forum = self.location, let forumPeer = self.forumPeer {
|
||||
|
|
|
|||
|
|
@ -1448,17 +1448,22 @@ public enum ChatListSearchContextActionSource {
|
|||
public struct ChatListSearchOptions {
|
||||
let peer: (EnginePeer.Id, Bool, String)?
|
||||
let date: (Int32?, Int32, String)?
|
||||
let folder: (Int32, String)?
|
||||
|
||||
var isEmpty: Bool {
|
||||
return self.peer == nil && self.date == nil
|
||||
return self.peer == nil && self.date == nil && self.folder == nil
|
||||
}
|
||||
|
||||
func withUpdatedPeer(_ peerIdIsGroupAndName: (EnginePeer.Id, Bool, String)?) -> ChatListSearchOptions {
|
||||
return ChatListSearchOptions(peer: peerIdIsGroupAndName, date: self.date)
|
||||
return ChatListSearchOptions(peer: peerIdIsGroupAndName, date: self.date, folder: self.folder)
|
||||
}
|
||||
|
||||
func withUpdatedDate(_ minDateMaxDateAndTitle: (Int32?, Int32, String)?) -> ChatListSearchOptions {
|
||||
return ChatListSearchOptions(peer: self.peer, date: minDateMaxDateAndTitle)
|
||||
return ChatListSearchOptions(peer: self.peer, date: minDateMaxDateAndTitle, folder: self.folder)
|
||||
}
|
||||
|
||||
func withUpdatedFolder(_ folder: (Int32, String)?) -> ChatListSearchOptions {
|
||||
return ChatListSearchOptions(peer: self.peer, date: self.date, folder: folder)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -2065,7 +2070,7 @@ final class ChatListSearchListPaneNode: ASDisplayNode, ChatListSearchPaneNode {
|
|||
|
||||
var defaultFoundRemoteMessagesSignal: Signal<([FoundRemoteMessages], Bool), NoError> = .single(([FoundRemoteMessages(messages: [], readCounters: [:], threadsData: [:], totalCount: 0)], false))
|
||||
if key == .globalPosts, let data = context.currentAppConfiguration.with({ $0 }).data, let value = data["ios_load_empty_global_posts"] as? Double, value != 0.0 {
|
||||
let searchSignal = context.engine.messages.searchMessages(location: .general(scope: .globalPosts(allowPaidStars: nil), tags: nil, minDate: nil, maxDate: nil), query: "", state: nil, limit: 50)
|
||||
let searchSignal = context.engine.messages.searchMessages(location: .general(scope: .globalPosts(allowPaidStars: nil), tags: nil, minDate: nil, maxDate: nil, folderId: nil), query: "", state: nil, limit: 50)
|
||||
|> map { resultData -> ChatListSearchMessagesResult in
|
||||
let (result, updatedState) = resultData
|
||||
|
||||
|
|
@ -2089,7 +2094,7 @@ final class ChatListSearchListPaneNode: ASDisplayNode, ChatListSearchPaneNode {
|
|||
let foundItems: Signal<([ChatListSearchEntry], Bool, String?)?, NoError> = combineLatest(queue: .mainQueue(), searchQuery, self.approvedGlobalPostQueryState.get(), searchOptions, self.searchScopePromise.get(), downloadItems, globalPostSearchStateType, isPremium)
|
||||
|> debounceOnMainThread
|
||||
|> mapToSignal { [weak self] query, approvedGlobalPostQueryState, options, searchScope, downloadItems, _, _ -> Signal<([ChatListSearchEntry], Bool, String?)?, NoError> in
|
||||
if query == nil && options == nil && [.chats, .topics, .channels, .apps].contains(key) {
|
||||
if query == nil && (options == nil || options?.withUpdatedFolder(nil).isEmpty == true) && [.chats, .topics, .channels, .apps].contains(key) {
|
||||
let _ = currentRemotePeers.swap(nil)
|
||||
return .single(nil)
|
||||
}
|
||||
|
|
@ -2244,7 +2249,24 @@ final class ChatListSearchListPaneNode: ASDisplayNode, ChatListSearchPaneNode {
|
|||
return result
|
||||
}
|
||||
|
||||
let updatedLocalPeers = context.engine.contacts.searchLocalPeers(query: query.lowercased())
|
||||
var predicate: Signal<ChatListFilterPredicate?, NoError> = .single(nil)
|
||||
if let folderId = options?.folder?.0 {
|
||||
predicate = context.engine.peers.currentChatListFilters()
|
||||
|> take(1)
|
||||
|> map { filters -> ChatListFilterPredicate? in
|
||||
guard let filter = filters.first(where: { $0.id == folderId }) else {
|
||||
return nil
|
||||
}
|
||||
guard case let .filter(_, _, _, data) = filter else {
|
||||
return nil
|
||||
}
|
||||
return chatListFilterPredicate(filter: data, accountPeerId: context.account.peerId)
|
||||
}
|
||||
}
|
||||
|
||||
let updatedLocalPeers = predicate |> mapToSignal { predicate in
|
||||
return context.engine.contacts.searchLocalPeers(query: query.lowercased(), predicate: predicate)
|
||||
}
|
||||
|> mapToSignal { peers -> Signal<[EngineRenderedPeer], NoError> in
|
||||
return context.engine.data.subscribe(
|
||||
EngineDataMap(peers.map { peer in
|
||||
|
|
@ -2552,7 +2574,7 @@ final class ChatListSearchListPaneNode: ASDisplayNode, ChatListSearchPaneNode {
|
|||
if case .savedMessagesChats = location {
|
||||
foundRemotePeers = .single(([], [], [], false))
|
||||
} else if let query = query, case .chats = key {
|
||||
if query.hasPrefix("#") {
|
||||
if query.hasPrefix("#") || options?.folder != nil {
|
||||
foundRemotePeers = .single(([], [], [], false))
|
||||
} else {
|
||||
foundRemotePeers = (
|
||||
|
|
@ -2584,28 +2606,28 @@ final class ChatListSearchListPaneNode: ASDisplayNode, ChatListSearchPaneNode {
|
|||
}
|
||||
let searchLocations: [SearchMessagesLocation]
|
||||
if key == .globalPosts {
|
||||
searchLocations = [SearchMessagesLocation.general(scope: .globalPosts(allowPaidStars: approvedGlobalPostQueryState?.price), tags: nil, minDate: nil, maxDate: nil)]
|
||||
} else if let options = options {
|
||||
searchLocations = [SearchMessagesLocation.general(scope: .globalPosts(allowPaidStars: approvedGlobalPostQueryState?.price), tags: nil, minDate: nil, maxDate: nil, folderId: nil)]
|
||||
} else if let options {
|
||||
if case let .forum(peerId) = location {
|
||||
searchLocations = [.peer(peerId: peerId, fromId: nil, tags: tagMask, reactions: nil, threadId: nil, minDate: options.date?.0, maxDate: options.date?.1), .general(scope: .everywhere, tags: tagMask, minDate: options.date?.0, maxDate: options.date?.1)]
|
||||
searchLocations = [.peer(peerId: peerId, fromId: nil, tags: tagMask, reactions: nil, threadId: nil, minDate: options.date?.0, maxDate: options.date?.1), .general(scope: .everywhere, tags: tagMask, minDate: options.date?.0, maxDate: options.date?.1, folderId: nil)]
|
||||
} else if let (peerId, _, _) = options.peer {
|
||||
searchLocations = [.peer(peerId: peerId, fromId: nil, tags: tagMask, reactions: nil, threadId: nil, minDate: options.date?.0, maxDate: options.date?.1)]
|
||||
} else {
|
||||
if case let .chatList(groupId) = location, case .archive = groupId {
|
||||
searchLocations = [.group(groupId: groupId._asGroup(), tags: tagMask, minDate: options.date?.0, maxDate: options.date?.1)]
|
||||
} else {
|
||||
searchLocations = [.general(scope: searchScope, tags: tagMask, minDate: options.date?.0, maxDate: options.date?.1)]
|
||||
searchLocations = [.general(scope: searchScope, tags: tagMask, minDate: options.date?.0, maxDate: options.date?.1, folderId: options.folder?.0)]
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if case .channels = key {
|
||||
searchLocations = [.general(scope: .channels, tags: tagMask, minDate: nil, maxDate: nil)]
|
||||
searchLocations = [.general(scope: .channels, tags: tagMask, minDate: nil, maxDate: nil, folderId: nil)]
|
||||
} else if case let .forum(peerId) = location {
|
||||
searchLocations = [.peer(peerId: peerId, fromId: nil, tags: tagMask, reactions: nil, threadId: nil, minDate: nil, maxDate: nil), .general(scope: .everywhere, tags: tagMask, minDate: nil, maxDate: nil)]
|
||||
searchLocations = [.peer(peerId: peerId, fromId: nil, tags: tagMask, reactions: nil, threadId: nil, minDate: nil, maxDate: nil), .general(scope: .everywhere, tags: tagMask, minDate: nil, maxDate: nil, folderId: nil)]
|
||||
} else if case let .chatList(groupId) = location, case .archive = groupId {
|
||||
searchLocations = [.group(groupId: groupId._asGroup(), tags: tagMask, minDate: nil, maxDate: nil)]
|
||||
} else {
|
||||
searchLocations = [.general(scope: searchScope, tags: tagMask, minDate: nil, maxDate: nil)]
|
||||
searchLocations = [.general(scope: searchScope, tags: tagMask, minDate: nil, maxDate: nil, folderId: nil)]
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -2704,7 +2726,7 @@ final class ChatListSearchListPaneNode: ASDisplayNode, ChatListSearchPaneNode {
|
|||
let searchSignals: [Signal<(SearchMessagesResult, SearchMessagesState), NoError>]
|
||||
|
||||
if key == .globalPosts {
|
||||
searchSignals = [context.engine.messages.searchMessages(location: .general(scope: .globalPosts(allowPaidStars: approvedGlobalPostQueryState?.price), tags: nil, minDate: nil, maxDate: nil), query: finalQuery, state: nil, limit: 50)]
|
||||
searchSignals = [context.engine.messages.searchMessages(location: .general(scope: .globalPosts(allowPaidStars: approvedGlobalPostQueryState?.price), tags: nil, minDate: nil, maxDate: nil, folderId: nil), query: finalQuery, state: nil, limit: 50)]
|
||||
} else {
|
||||
searchSignals = searchLocations.map { searchLocation in
|
||||
return context.engine.messages.searchMessages(location: searchLocation, query: finalQuery, state: nil, limit: 50)
|
||||
|
|
|
|||
|
|
@ -503,6 +503,20 @@ public final class PagerComponent<ChildEnvironmentType: Equatable, TopPanelEnvir
|
|||
self.component?.contentIdUpdated(id)
|
||||
}
|
||||
|
||||
override public func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
|
||||
if self.alpha.isZero {
|
||||
return nil
|
||||
}
|
||||
for view in self.subviews.reversed() {
|
||||
if let result = view.hitTest(self.convert(point, to: view), with: event), result.isUserInteractionEnabled {
|
||||
return result
|
||||
}
|
||||
}
|
||||
|
||||
let result = super.hitTest(point, with: event)
|
||||
return result
|
||||
}
|
||||
|
||||
func update(component: PagerComponent<ChildEnvironmentType, TopPanelEnvironment>, availableSize: CGSize, state: EmptyComponentState, environment: Environment<EnvironmentType>, transition: ComponentTransition) -> CGSize {
|
||||
let previousPanelHideBehavior = self.component?.panelHideBehavior
|
||||
|
||||
|
|
|
|||
|
|
@ -28,10 +28,12 @@ public final class NavigationBarTheme {
|
|||
public let badgeStrokeColor: UIColor
|
||||
public let badgeTextColor: UIColor
|
||||
public let edgeEffectColor: UIColor?
|
||||
public let accentButtonColor: UIColor
|
||||
public let accentForegroundColor: UIColor
|
||||
public let style: NavigationBar.Style
|
||||
public let glassStyle: NavigationBar.GlassStyle
|
||||
|
||||
public init(overallDarkAppearance: Bool, buttonColor: UIColor, disabledButtonColor: UIColor, primaryTextColor: UIColor, backgroundColor: UIColor, opaqueBackgroundColor: UIColor? = nil, enableBackgroundBlur: Bool, separatorColor: UIColor, badgeBackgroundColor: UIColor, badgeStrokeColor: UIColor, badgeTextColor: UIColor, edgeEffectColor: UIColor? = nil, style: NavigationBar.Style = .legacy, glassStyle: NavigationBar.GlassStyle = .default) {
|
||||
public init(overallDarkAppearance: Bool, buttonColor: UIColor, disabledButtonColor: UIColor, primaryTextColor: UIColor, backgroundColor: UIColor, opaqueBackgroundColor: UIColor? = nil, enableBackgroundBlur: Bool, separatorColor: UIColor, badgeBackgroundColor: UIColor, badgeStrokeColor: UIColor, badgeTextColor: UIColor, edgeEffectColor: UIColor? = nil, accentButtonColor: UIColor, accentForegroundColor: UIColor, style: NavigationBar.Style = .legacy, glassStyle: NavigationBar.GlassStyle = .default) {
|
||||
self.overallDarkAppearance = overallDarkAppearance
|
||||
self.buttonColor = buttonColor
|
||||
self.disabledButtonColor = disabledButtonColor
|
||||
|
|
@ -44,16 +46,18 @@ public final class NavigationBarTheme {
|
|||
self.badgeStrokeColor = badgeStrokeColor
|
||||
self.badgeTextColor = badgeTextColor
|
||||
self.edgeEffectColor = edgeEffectColor
|
||||
self.accentButtonColor = accentButtonColor
|
||||
self.accentForegroundColor = accentForegroundColor
|
||||
self.style = style
|
||||
self.glassStyle = glassStyle
|
||||
}
|
||||
|
||||
public func withUpdatedBackgroundColor(_ color: UIColor) -> NavigationBarTheme {
|
||||
return NavigationBarTheme(overallDarkAppearance: self.overallDarkAppearance, buttonColor: self.buttonColor, disabledButtonColor: self.disabledButtonColor, primaryTextColor: self.primaryTextColor, backgroundColor: color, opaqueBackgroundColor: self.opaqueBackgroundColor, enableBackgroundBlur: false, separatorColor: self.separatorColor, badgeBackgroundColor: self.badgeBackgroundColor, badgeStrokeColor: self.badgeStrokeColor, badgeTextColor: self.badgeTextColor, edgeEffectColor: self.edgeEffectColor, style: self.style, glassStyle: self.glassStyle)
|
||||
return NavigationBarTheme(overallDarkAppearance: self.overallDarkAppearance, buttonColor: self.buttonColor, disabledButtonColor: self.disabledButtonColor, primaryTextColor: self.primaryTextColor, backgroundColor: color, opaqueBackgroundColor: self.opaqueBackgroundColor, enableBackgroundBlur: false, separatorColor: self.separatorColor, badgeBackgroundColor: self.badgeBackgroundColor, badgeStrokeColor: self.badgeStrokeColor, badgeTextColor: self.badgeTextColor, edgeEffectColor: self.edgeEffectColor, accentButtonColor: self.accentButtonColor, accentForegroundColor: self.accentForegroundColor, style: self.style, glassStyle: self.glassStyle)
|
||||
}
|
||||
|
||||
public func withUpdatedSeparatorColor(_ color: UIColor) -> NavigationBarTheme {
|
||||
return NavigationBarTheme(overallDarkAppearance: self.overallDarkAppearance, buttonColor: self.buttonColor, disabledButtonColor: self.disabledButtonColor, primaryTextColor: self.primaryTextColor, backgroundColor: self.backgroundColor, opaqueBackgroundColor: self.opaqueBackgroundColor, enableBackgroundBlur: self.enableBackgroundBlur, separatorColor: color, badgeBackgroundColor: self.badgeBackgroundColor, badgeStrokeColor: self.badgeStrokeColor, badgeTextColor: self.badgeTextColor, edgeEffectColor: self.edgeEffectColor, style: self.style, glassStyle: self.glassStyle)
|
||||
return NavigationBarTheme(overallDarkAppearance: self.overallDarkAppearance, buttonColor: self.buttonColor, disabledButtonColor: self.disabledButtonColor, primaryTextColor: self.primaryTextColor, backgroundColor: self.backgroundColor, opaqueBackgroundColor: self.opaqueBackgroundColor, enableBackgroundBlur: self.enableBackgroundBlur, separatorColor: color, badgeBackgroundColor: self.badgeBackgroundColor, badgeStrokeColor: self.badgeStrokeColor, badgeTextColor: self.badgeTextColor, edgeEffectColor: self.edgeEffectColor, accentButtonColor: self.accentButtonColor, accentForegroundColor: self.accentForegroundColor, style: self.style, glassStyle: self.glassStyle)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -681,7 +681,7 @@ private func galleryEntriesForMessageHistoryEntries(_ entries: [MessageHistoryEn
|
|||
}
|
||||
|
||||
public class GalleryController: ViewController, StandalonePresentableController, KeyShortcutResponder, GalleryControllerProtocol {
|
||||
public static let darkNavigationTheme = NavigationBarTheme(overallDarkAppearance: true, buttonColor: .white, disabledButtonColor: UIColor(rgb: 0x525252), primaryTextColor: .white, backgroundColor: UIColor(white: 0.0, alpha: 0.6), enableBackgroundBlur: false, separatorColor: UIColor(white: 0.0, alpha: 0.8), badgeBackgroundColor: .clear, badgeStrokeColor: .clear, badgeTextColor: .clear, edgeEffectColor: .clear, style: .glass)
|
||||
public static let darkNavigationTheme = NavigationBarTheme(overallDarkAppearance: true, buttonColor: .white, disabledButtonColor: UIColor(rgb: 0x525252), primaryTextColor: .white, backgroundColor: UIColor(white: 0.0, alpha: 0.6), enableBackgroundBlur: false, separatorColor: UIColor(white: 0.0, alpha: 0.8), badgeBackgroundColor: .clear, badgeStrokeColor: .clear, badgeTextColor: .clear, edgeEffectColor: .clear, accentButtonColor: .white, accentForegroundColor: .black, style: .glass)
|
||||
|
||||
private var galleryNode: GalleryControllerNode {
|
||||
return self.displayNode as! GalleryControllerNode
|
||||
|
|
|
|||
|
|
@ -54,7 +54,7 @@ final class HashtagSearchGlobalChatContents: ChatCustomContentsProtocol {
|
|||
if self.publicPosts {
|
||||
search = self.context.engine.messages.searchHashtagPosts(hashtag: self.query, state: nil)
|
||||
} else {
|
||||
search = self.context.engine.messages.searchMessages(location: .general(scope: .everywhere, tags: nil, minDate: nil, maxDate: nil), query: self.query, state: nil)
|
||||
search = self.context.engine.messages.searchMessages(location: .general(scope: .everywhere, tags: nil, minDate: nil, maxDate: nil, folderId: nil), query: self.query, state: nil)
|
||||
}
|
||||
|
||||
self.isSearchingPromise.set(true)
|
||||
|
|
@ -102,7 +102,7 @@ final class HashtagSearchGlobalChatContents: ChatCustomContentsProtocol {
|
|||
if self.publicPosts {
|
||||
search = self.context.engine.messages.searchHashtagPosts(hashtag: self.query, state: self.currentSearchState)
|
||||
} else {
|
||||
search = self.context.engine.messages.searchMessages(location: .general(scope: .everywhere, tags: nil, minDate: nil, maxDate: nil), query: self.query, state: currentSearchState)
|
||||
search = self.context.engine.messages.searchMessages(location: .general(scope: .everywhere, tags: nil, minDate: nil, maxDate: nil, folderId: nil), query: self.query, state: currentSearchState)
|
||||
}
|
||||
|
||||
self.historyViewDisposable?.dispose()
|
||||
|
|
|
|||
|
|
@ -39,7 +39,7 @@ public class SetupTwoStepVerificationController: ViewController {
|
|||
|
||||
self.presentationData = self.context.sharedContext.currentPresentationData.with { $0 }
|
||||
|
||||
super.init(navigationBarPresentationData: NavigationBarPresentationData(theme: NavigationBarTheme(overallDarkAppearance: self.presentationData.theme.overallDarkAppearance, buttonColor: self.presentationData.theme.rootController.navigationBar.accentTextColor, disabledButtonColor: self.presentationData.theme.rootController.navigationBar.disabledButtonColor, primaryTextColor: self.presentationData.theme.rootController.navigationBar.primaryTextColor, backgroundColor: .clear, enableBackgroundBlur: false, separatorColor: .clear, badgeBackgroundColor: .clear, badgeStrokeColor: .clear, badgeTextColor: .clear), strings: NavigationBarStrings(presentationStrings: self.presentationData.strings)))
|
||||
super.init(navigationBarPresentationData: NavigationBarPresentationData(theme: NavigationBarTheme(overallDarkAppearance: self.presentationData.theme.overallDarkAppearance, buttonColor: self.presentationData.theme.rootController.navigationBar.accentTextColor, disabledButtonColor: self.presentationData.theme.rootController.navigationBar.disabledButtonColor, primaryTextColor: self.presentationData.theme.rootController.navigationBar.primaryTextColor, backgroundColor: .clear, enableBackgroundBlur: false, separatorColor: .clear, badgeBackgroundColor: .clear, badgeStrokeColor: .clear, badgeTextColor: .clear, accentButtonColor: self.presentationData.theme.list.itemCheckColors.fillColor, accentForegroundColor: self.presentationData.theme.list.itemCheckColors.foregroundColor), strings: NavigationBarStrings(presentationStrings: self.presentationData.strings)))
|
||||
|
||||
self.statusBar.statusBarStyle = self.presentationData.theme.rootController.statusBarStyle.style
|
||||
|
||||
|
|
|
|||
|
|
@ -71,7 +71,7 @@ public final class TwoFactorDataInputScreen: ViewController {
|
|||
self.presentationData = self.sharedContext.currentPresentationData.with { $0 }
|
||||
|
||||
let defaultTheme = NavigationBarTheme(rootControllerTheme: self.presentationData.theme)
|
||||
let navigationBarTheme = NavigationBarTheme(overallDarkAppearance: defaultTheme.overallDarkAppearance, buttonColor: defaultTheme.buttonColor, disabledButtonColor: defaultTheme.disabledButtonColor, primaryTextColor: defaultTheme.primaryTextColor, backgroundColor: .clear, enableBackgroundBlur: false, separatorColor: .clear, badgeBackgroundColor: defaultTheme.badgeBackgroundColor, badgeStrokeColor: defaultTheme.badgeStrokeColor, badgeTextColor: defaultTheme.badgeTextColor)
|
||||
let navigationBarTheme = NavigationBarTheme(overallDarkAppearance: defaultTheme.overallDarkAppearance, buttonColor: defaultTheme.buttonColor, disabledButtonColor: defaultTheme.disabledButtonColor, primaryTextColor: defaultTheme.primaryTextColor, backgroundColor: .clear, enableBackgroundBlur: false, separatorColor: .clear, badgeBackgroundColor: defaultTheme.badgeBackgroundColor, badgeStrokeColor: defaultTheme.badgeStrokeColor, badgeTextColor: defaultTheme.badgeTextColor, accentButtonColor: defaultTheme.accentButtonColor, accentForegroundColor: defaultTheme.accentForegroundColor)
|
||||
|
||||
super.init(navigationBarPresentationData: NavigationBarPresentationData(theme: navigationBarTheme, strings: NavigationBarStrings(back: self.presentationData.strings.Common_Back, close: self.presentationData.strings.Common_Close)))
|
||||
|
||||
|
|
|
|||
|
|
@ -57,7 +57,7 @@ public final class TwoFactorAuthSplashScreen: ViewController {
|
|||
self.presentationData = self.sharedContext.currentPresentationData.with { $0 }
|
||||
|
||||
let defaultTheme = NavigationBarTheme(rootControllerTheme: self.presentationData.theme)
|
||||
let navigationBarTheme = NavigationBarTheme(overallDarkAppearance: defaultTheme.overallDarkAppearance, buttonColor: defaultTheme.buttonColor, disabledButtonColor: defaultTheme.disabledButtonColor, primaryTextColor: defaultTheme.primaryTextColor, backgroundColor: .clear, enableBackgroundBlur: false, separatorColor: .clear, badgeBackgroundColor: defaultTheme.badgeBackgroundColor, badgeStrokeColor: defaultTheme.badgeStrokeColor, badgeTextColor: defaultTheme.badgeTextColor)
|
||||
let navigationBarTheme = NavigationBarTheme(overallDarkAppearance: defaultTheme.overallDarkAppearance, buttonColor: defaultTheme.buttonColor, disabledButtonColor: defaultTheme.disabledButtonColor, primaryTextColor: defaultTheme.primaryTextColor, backgroundColor: .clear, enableBackgroundBlur: false, separatorColor: .clear, badgeBackgroundColor: defaultTheme.badgeBackgroundColor, badgeStrokeColor: defaultTheme.badgeStrokeColor, badgeTextColor: defaultTheme.badgeTextColor, accentButtonColor: defaultTheme.accentButtonColor, accentForegroundColor: defaultTheme.accentForegroundColor)
|
||||
|
||||
super.init(navigationBarPresentationData: NavigationBarPresentationData(theme: navigationBarTheme, strings: NavigationBarStrings(back: self.presentationData.strings.Common_Back, close: self.presentationData.strings.Common_Close)))
|
||||
|
||||
|
|
|
|||
|
|
@ -1213,9 +1213,9 @@ public final class Transaction {
|
|||
self.postbox?.reindexUnreadCounters(currentTransaction: self)
|
||||
}
|
||||
|
||||
public func searchPeers(query: String) -> [RenderedPeer] {
|
||||
public func searchPeers(query: String, predicate: ChatListFilterPredicate?) -> [RenderedPeer] {
|
||||
assert(!self.disposed)
|
||||
return self.postbox?.searchPeers(query: query) ?? []
|
||||
return self.postbox?.searchPeers(transaction: self, query: query, predicate: predicate) ?? []
|
||||
}
|
||||
|
||||
public func clearTimestampBasedAttribute(id: MessageId, tag: UInt16) {
|
||||
|
|
@ -3800,13 +3800,13 @@ final class PostboxImpl {
|
|||
} |> switchToLatest
|
||||
}
|
||||
|
||||
public func searchPeers(query: String) -> Signal<[RenderedPeer], NoError> {
|
||||
public func searchPeers(query: String, predicate: ChatListFilterPredicate?) -> Signal<[RenderedPeer], NoError> {
|
||||
return self.transaction { transaction -> Signal<[RenderedPeer], NoError> in
|
||||
return .single(transaction.searchPeers(query: query))
|
||||
return .single(transaction.searchPeers(query: query, predicate: predicate))
|
||||
} |> switchToLatest
|
||||
}
|
||||
|
||||
fileprivate func searchPeers(query: String) -> [RenderedPeer] {
|
||||
fileprivate func searchPeers(transaction: Transaction, query: String, predicate: ChatListFilterPredicate?) -> [RenderedPeer] {
|
||||
var peerIds = Set<PeerId>()
|
||||
var chatPeers: [RenderedPeer] = []
|
||||
|
||||
|
|
@ -3823,6 +3823,30 @@ final class PostboxImpl {
|
|||
}
|
||||
chatPeerIds.append(contentsOf: additionalChatPeerIds)
|
||||
|
||||
if let predicate {
|
||||
let globalNotificationSettings = self.getGlobalNotificationSettings(transaction: transaction)
|
||||
|
||||
let filterImpl: (PeerId) -> Bool = { peerId in
|
||||
guard let peer = self.peerTable.get(peerId) else {
|
||||
return false
|
||||
}
|
||||
let inclusion = self.chatListIndexTable.get(peerId: peerId)
|
||||
let isUnread = self.readStateTable.getCombinedState(peerId)?.isUnread ?? false
|
||||
let notificationsPeerId = peer.notificationSettingsPeerId ?? peerId
|
||||
let isContact = self.contactsTable.isContact(peerId: notificationsPeerId)
|
||||
let isRemovedFromTotalUnreadCount = resolvedIsRemovedFromTotalUnreadCount(globalSettings: globalNotificationSettings, peer: peer, peerSettings: self.peerNotificationSettingsTable.getEffective(notificationsPeerId))
|
||||
let messageTagSummaryResult = resolveChatListMessageTagSummaryResultCalculation(postbox: self, peerId: peer.id, threadId: nil, calculation: predicate.messageTagSummary)
|
||||
if predicate.includes(peer: peer, groupId: inclusion.inclusion.groupId ?? .root, isRemovedFromTotalUnreadCount: isRemovedFromTotalUnreadCount, isUnread: isUnread, isContact: isContact, messageTagSummaryResult: messageTagSummaryResult) {
|
||||
return true
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
chatPeerIds = chatPeerIds.filter(filterImpl)
|
||||
contactPeerIds = contactPeerIds.filter(filterImpl)
|
||||
}
|
||||
|
||||
for peerId in chatPeerIds {
|
||||
if let peer = self.peerTable.get(peerId) {
|
||||
var peers = SimpleDictionary<PeerId, Peer>()
|
||||
|
|
@ -4929,12 +4953,12 @@ public class Postbox {
|
|||
}
|
||||
}
|
||||
|
||||
public func searchPeers(query: String) -> Signal<[RenderedPeer], NoError> {
|
||||
public func searchPeers(query: String, predicate: ChatListFilterPredicate? = nil) -> Signal<[RenderedPeer], NoError> {
|
||||
return Signal { subscriber in
|
||||
let disposable = MetaDisposable()
|
||||
|
||||
self.impl.with { impl in
|
||||
disposable.set(impl.searchPeers(query: query).start(next: subscriber.putNext, error: subscriber.putError, completed: subscriber.putCompletion))
|
||||
disposable.set(impl.searchPeers(query: query, predicate: predicate).start(next: subscriber.putNext, error: subscriber.putError, completed: subscriber.putCompletion))
|
||||
}
|
||||
|
||||
return disposable
|
||||
|
|
|
|||
|
|
@ -77,7 +77,7 @@ public final class QrCodeScanScreen: ViewController {
|
|||
|
||||
self.presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
||||
|
||||
let navigationBarTheme = NavigationBarTheme(overallDarkAppearance: self.presentationData.theme.overallDarkAppearance, buttonColor: .white, disabledButtonColor: .white, primaryTextColor: .white, backgroundColor: .clear, enableBackgroundBlur: false, separatorColor: .clear, badgeBackgroundColor: .clear, badgeStrokeColor: .clear, badgeTextColor: .clear)
|
||||
let navigationBarTheme = NavigationBarTheme(overallDarkAppearance: self.presentationData.theme.overallDarkAppearance, buttonColor: .white, disabledButtonColor: .white, primaryTextColor: .white, backgroundColor: .clear, enableBackgroundBlur: false, separatorColor: .clear, badgeBackgroundColor: .clear, badgeStrokeColor: .clear, badgeTextColor: .clear, accentButtonColor: .white, accentForegroundColor: .black)
|
||||
|
||||
super.init(navigationBarPresentationData: NavigationBarPresentationData(theme: navigationBarTheme, strings: NavigationBarStrings(back: self.presentationData.strings.Common_Back, close: self.presentationData.strings.Common_Close)))
|
||||
|
||||
|
|
|
|||
|
|
@ -928,6 +928,9 @@ public class SearchBarNode: ASDisplayNode, UITextFieldDelegate {
|
|||
} set {
|
||||
self.textField.tokens = newValue
|
||||
self.updateIsEmpty(animated: true)
|
||||
if let (boundingSize, leftInset, rightInset) = self.validLayout {
|
||||
self.updateLayout(boundingSize: boundingSize, leftInset: leftInset, rightInset: rightInset, transition: .immediate)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -58,8 +58,8 @@ public extension TelegramEngine {
|
|||
return _internal_searchPeers(accountPeerId: self.account.peerId, postbox: self.account.postbox, network: self.account.network, query: query, scope: scope)
|
||||
}
|
||||
|
||||
public func searchLocalPeers(query: String, scope: TelegramSearchPeersScope = .everywhere) -> Signal<[EngineRenderedPeer], NoError> {
|
||||
return self.account.postbox.searchPeers(query: query)
|
||||
public func searchLocalPeers(query: String, scope: TelegramSearchPeersScope = .everywhere, predicate: ChatListFilterPredicate? = nil) -> Signal<[EngineRenderedPeer], NoError> {
|
||||
return self.account.postbox.searchPeers(query: query, predicate: predicate)
|
||||
|> map { peers in
|
||||
switch scope {
|
||||
case .everywhere:
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ import MtProtoKit
|
|||
|
||||
|
||||
public enum SearchMessagesLocation: Equatable {
|
||||
case general(scope: TelegramSearchPeersScope, tags: MessageTags?, minDate: Int32?, maxDate: Int32?)
|
||||
case general(scope: TelegramSearchPeersScope, tags: MessageTags?, minDate: Int32?, maxDate: Int32?, folderId: Int32?)
|
||||
case group(groupId: PeerGroupId, tags: MessageTags?, minDate: Int32?, maxDate: Int32?)
|
||||
case peer(peerId: PeerId, fromId: PeerId?, tags: MessageTags?, reactions: [MessageReaction.Reaction]?, threadId: Int64?, minDate: Int32?, maxDate: Int32?)
|
||||
case sentMedia(tags: MessageTags?)
|
||||
|
|
@ -471,7 +471,7 @@ func _internal_searchMessages(account: Account, location: SearchMessagesLocation
|
|||
}
|
||||
return combineLatest(peerMessages, additionalPeerMessages)
|
||||
}
|
||||
case let .general(_, tags, minDate, maxDate), let .group(_, tags, minDate, maxDate):
|
||||
case let .general(_, tags, minDate, maxDate, _), let .group(_, tags, minDate, maxDate):
|
||||
var flags: Int32 = 0
|
||||
let folderId: Int32?
|
||||
if case let .group(groupId, _, _, _) = location {
|
||||
|
|
@ -481,7 +481,7 @@ func _internal_searchMessages(account: Account, location: SearchMessagesLocation
|
|||
folderId = nil
|
||||
}
|
||||
|
||||
if case let .general(scope, _, _, _) = location, case let .globalPosts(allowPaidStars) = scope {
|
||||
if case let .general(scope, _, _, _, _) = location, case let .globalPosts(allowPaidStars) = scope {
|
||||
remoteSearchResult = account.postbox.transaction { transaction -> (Int32, MessageIndex?, Api.InputPeer) in
|
||||
var lowerBound: MessageIndex?
|
||||
if let state = state, let message = state.main.messages.last {
|
||||
|
|
@ -508,7 +508,7 @@ func _internal_searchMessages(account: Account, location: SearchMessagesLocation
|
|||
}
|
||||
}
|
||||
} else {
|
||||
if case let .general(scope, _, _, _) = location {
|
||||
if case let .general(scope, _, _, _, _) = location {
|
||||
switch scope {
|
||||
case .everywhere:
|
||||
break
|
||||
|
|
@ -567,9 +567,9 @@ func _internal_searchMessages(account: Account, location: SearchMessagesLocation
|
|||
|
||||
if state?.additional == nil {
|
||||
switch location {
|
||||
case let .general(_, tags, minDate, maxDate), let .group(_, tags, minDate, maxDate):
|
||||
case let .general(_, tags, minDate, maxDate, _), let .group(_, tags, minDate, maxDate):
|
||||
let secretMessages: [Message]
|
||||
if case let .general(scope, _, _, _) = location, case .channels = scope {
|
||||
if case let .general(scope, _, _, _, _) = location, case .channels = scope {
|
||||
secretMessages = []
|
||||
} else {
|
||||
secretMessages = transaction.searchMessages(peerId: nil, query: query, tags: tags)
|
||||
|
|
|
|||
|
|
@ -208,6 +208,7 @@ private enum ApplicationSpecificGlobalNotice: Int32 {
|
|||
case giftCraftingTips = 85
|
||||
case copyProtectionTips = 86
|
||||
case aiTextProcessingStyleSelectionTips = 87
|
||||
case savedMessagesChatListView = 88
|
||||
|
||||
var key: ValueBoxKey {
|
||||
let v = ValueBoxKey(length: 4)
|
||||
|
|
@ -589,6 +590,10 @@ private struct ApplicationSpecificNoticeKeys {
|
|||
static func aiTextProcessingStyleSelectionTips() -> NoticeEntryKey {
|
||||
return NoticeEntryKey(namespace: noticeNamespace(namespace: globalNamespace), key: ApplicationSpecificGlobalNotice.aiTextProcessingStyleSelectionTips.key)
|
||||
}
|
||||
|
||||
static func savedMessagesChatListView() -> NoticeEntryKey {
|
||||
return NoticeEntryKey(namespace: noticeNamespace(namespace: globalNamespace), key: ApplicationSpecificGlobalNotice.savedMessagesChatListView.key)
|
||||
}
|
||||
}
|
||||
|
||||
public struct ApplicationSpecificNotice {
|
||||
|
|
@ -2610,4 +2615,31 @@ public struct ApplicationSpecificNotice {
|
|||
return Int(previousValue)
|
||||
}
|
||||
}
|
||||
|
||||
public static func getSavedMessagesChatListView(accountManager: AccountManager<TelegramAccountManagerTypes>) -> Signal<Int32, NoError> {
|
||||
return accountManager.transaction { transaction -> Int32 in
|
||||
if let value = transaction.getNotice(ApplicationSpecificNoticeKeys.savedMessagesChatListView())?.get(ApplicationSpecificCounterNotice.self) {
|
||||
return value.value
|
||||
} else {
|
||||
return 0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static func incrementSavedMessagesChatListView(accountManager: AccountManager<TelegramAccountManagerTypes>, count: Int = 1) -> Signal<Int, NoError> {
|
||||
return accountManager.transaction { transaction -> Int in
|
||||
var currentValue: Int32 = 0
|
||||
if let value = transaction.getNotice(ApplicationSpecificNoticeKeys.savedMessagesChatListView())?.get(ApplicationSpecificCounterNotice.self) {
|
||||
currentValue = value.value
|
||||
}
|
||||
let previousValue = currentValue
|
||||
currentValue += Int32(count)
|
||||
|
||||
if let entry = CodableEntry(ApplicationSpecificCounterNotice(value: currentValue)) {
|
||||
transaction.setNotice(ApplicationSpecificNoticeKeys.savedMessagesChatListView(), entry)
|
||||
}
|
||||
|
||||
return Int(previousValue)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -69,7 +69,7 @@ public extension NavigationBarTheme {
|
|||
badgeTextColor = theme.badgeTextColor
|
||||
}
|
||||
|
||||
self.init(overallDarkAppearance: rootControllerTheme.overallDarkAppearance, buttonColor: buttonColor, disabledButtonColor: disabledButtonColor, primaryTextColor: theme.primaryTextColor, backgroundColor: hideBackground ? .clear : theme.blurredBackgroundColor, opaqueBackgroundColor: hideBackground ? .clear : theme.opaqueBackgroundColor, enableBackgroundBlur: enableBackgroundBlur, separatorColor: hideBackground || hideSeparator ? .clear : theme.separatorColor, badgeBackgroundColor: hideBadge ? .clear : badgeBackgroundColor, badgeStrokeColor: .clear, badgeTextColor: hideBadge ? .clear : badgeTextColor, edgeEffectColor: edgeEffectColor, style: style, glassStyle: glassStyle)
|
||||
self.init(overallDarkAppearance: rootControllerTheme.overallDarkAppearance, buttonColor: buttonColor, disabledButtonColor: disabledButtonColor, primaryTextColor: theme.primaryTextColor, backgroundColor: hideBackground ? .clear : theme.blurredBackgroundColor, opaqueBackgroundColor: hideBackground ? .clear : theme.opaqueBackgroundColor, enableBackgroundBlur: enableBackgroundBlur, separatorColor: hideBackground || hideSeparator ? .clear : theme.separatorColor, badgeBackgroundColor: hideBadge ? .clear : badgeBackgroundColor, badgeStrokeColor: .clear, badgeTextColor: hideBadge ? .clear : badgeTextColor, edgeEffectColor: edgeEffectColor, accentButtonColor: rootControllerTheme.list.itemCheckColors.fillColor, accentForegroundColor: rootControllerTheme.list.itemCheckColors.foregroundColor, style: style, glassStyle: glassStyle)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -756,7 +756,7 @@ public func makeAttachmentFileControllerImpl(
|
|||
case .audio:
|
||||
recentDocuments = .single(nil)
|
||||
|> then(
|
||||
context.engine.messages.searchMessages(location: .general(scope: .everywhere, tags: [.music], minDate: nil, maxDate: nil), query: "", state: nil)
|
||||
context.engine.messages.searchMessages(location: .general(scope: .everywhere, tags: [.music], minDate: nil, maxDate: nil, folderId: nil), query: "", state: nil)
|
||||
|> map { result -> [Message]? in
|
||||
return result.0.messages
|
||||
}
|
||||
|
|
|
|||
|
|
@ -530,7 +530,7 @@ public final class AttachmentFileSearchContainerNode: SearchDisplayControllerCon
|
|||
case .audio:
|
||||
shared = .single(nil)
|
||||
|> then(
|
||||
context.engine.messages.searchMessages(location: .general(scope: .everywhere, tags: [.music], minDate: nil, maxDate: nil), query: query, state: nil)
|
||||
context.engine.messages.searchMessages(location: .general(scope: .everywhere, tags: [.music], minDate: nil, maxDate: nil, folderId: nil), query: query, state: nil)
|
||||
|> delay(0.6, queue: Queue.mainQueue())
|
||||
|> map { result -> [Message]? in
|
||||
return result.0.messages.filter { !$0.isRestricted(platform: "ios", contentSettings: context.currentContentSettings.with { $0 }) }
|
||||
|
|
|
|||
|
|
@ -361,7 +361,7 @@ public final class ChatEntityKeyboardInputNode: ChatInputNode {
|
|||
|
||||
private let context: AccountContext
|
||||
private let stateContext: StateContext?
|
||||
private let entityKeyboardView: ComponentHostView<Empty>
|
||||
private let entityKeyboardView: ComponentView<Empty>
|
||||
|
||||
private let defaultToEmojiTab: Bool
|
||||
private var stableReorderableGroupOrder: [EntityKeyboardComponent.ReorderCategory: [ItemCollectionId]] = [:]
|
||||
|
|
@ -449,7 +449,7 @@ public final class ChatEntityKeyboardInputNode: ChatInputNode {
|
|||
}
|
||||
|
||||
public var canSwitchToTextInputAutomatically: Bool {
|
||||
if let pagerView = self.entityKeyboardView.componentView as? EntityKeyboardComponent.View, let centralId = pagerView.centralId {
|
||||
if let pagerView = self.entityKeyboardView.view as? EntityKeyboardComponent.View, let centralId = pagerView.centralId {
|
||||
if centralId == AnyHashable("emoji") {
|
||||
return false
|
||||
}
|
||||
|
|
@ -496,11 +496,11 @@ public final class ChatEntityKeyboardInputNode: ChatInputNode {
|
|||
|
||||
self.interaction = interaction
|
||||
|
||||
self.clippingView = UIView()
|
||||
self.clippingView = SparseContainerView()
|
||||
self.clippingView.clipsToBounds = true
|
||||
self.clippingView.layer.cornerRadius = keyboardCornerRadius
|
||||
|
||||
self.entityKeyboardView = ComponentHostView<Empty>()
|
||||
self.entityKeyboardView = ComponentView()
|
||||
|
||||
super.init()
|
||||
|
||||
|
|
@ -538,7 +538,6 @@ public final class ChatEntityKeyboardInputNode: ChatInputNode {
|
|||
)
|
||||
}
|
||||
|
||||
self.clippingView.addSubview(self.entityKeyboardView)
|
||||
self.view.addSubview(self.clippingView)
|
||||
|
||||
if let backgroundChromeView = self.backgroundChromeView {
|
||||
|
|
@ -692,7 +691,7 @@ public final class ChatEntityKeyboardInputNode: ChatInputNode {
|
|||
|
||||
for featuredStickerPack in stickerPacks {
|
||||
if featuredStickerPack.topItems.contains(where: { $0.file.fileId == file.fileId }) {
|
||||
if let pagerView = self.entityKeyboardView.componentView as? EntityKeyboardComponent.View, let emojiInputInteraction = self.emojiInputInteraction {
|
||||
if let pagerView = self.entityKeyboardView.view as? EntityKeyboardComponent.View, let emojiInputInteraction = self.emojiInputInteraction {
|
||||
pagerView.openCustomSearch(content: EmojiSearchContent(
|
||||
context: self.context,
|
||||
forceTheme: self.interaction?.forceTheme,
|
||||
|
|
@ -1326,7 +1325,7 @@ public final class ChatEntityKeyboardInputNode: ChatInputNode {
|
|||
))
|
||||
},
|
||||
openSearch: { [weak self] in
|
||||
if let strongSelf = self, let pagerView = strongSelf.entityKeyboardView.componentView as? EntityKeyboardComponent.View {
|
||||
if let strongSelf = self, let pagerView = strongSelf.entityKeyboardView.view as? EntityKeyboardComponent.View {
|
||||
pagerView.openSearch()
|
||||
}
|
||||
},
|
||||
|
|
@ -1630,7 +1629,7 @@ public final class ChatEntityKeyboardInputNode: ChatInputNode {
|
|||
var transition: ComponentTransition = .immediate
|
||||
var useAnimation = false
|
||||
|
||||
if let pagerView = strongSelf.entityKeyboardView.componentView as? EntityKeyboardComponent.View, let centralId = pagerView.centralId {
|
||||
if let pagerView = strongSelf.entityKeyboardView.view as? EntityKeyboardComponent.View, let centralId = pagerView.centralId {
|
||||
if centralId == AnyHashable("emoji") {
|
||||
useAnimation = strongSelf.currentInputData.emoji != inputData.emoji
|
||||
} else if centralId == AnyHashable("stickers"), strongSelf.currentInputData.stickers != nil, inputData.stickers != nil {
|
||||
|
|
@ -1710,7 +1709,7 @@ public final class ChatEntityKeyboardInputNode: ChatInputNode {
|
|||
gifContext.loadMore(token: token)
|
||||
},
|
||||
openSearch: { [weak self] in
|
||||
if let strongSelf = self, let pagerView = strongSelf.entityKeyboardView.componentView as? EntityKeyboardComponent.View {
|
||||
if let strongSelf = self, let pagerView = strongSelf.entityKeyboardView.view as? EntityKeyboardComponent.View {
|
||||
pagerView.openSearch()
|
||||
}
|
||||
},
|
||||
|
|
@ -1798,8 +1797,13 @@ public final class ChatEntityKeyboardInputNode: ChatInputNode {
|
|||
}
|
||||
|
||||
override public func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
|
||||
if let result = super.hitTest(point, with: event) {
|
||||
return result
|
||||
if self.alpha.isZero || !self.view.isUserInteractionEnabled {
|
||||
return nil
|
||||
}
|
||||
for subview in self.view.subviews.reversed() {
|
||||
if let result = subview.hitTest(self.view.convert(point, to: subview), with: event), result.isUserInteractionEnabled {
|
||||
return result
|
||||
}
|
||||
}
|
||||
|
||||
if let backgroundView = self.backgroundView, backgroundView.frame.contains(point) {
|
||||
|
|
@ -2025,7 +2029,12 @@ public final class ChatEntityKeyboardInputNode: ChatInputNode {
|
|||
entityKeyboardSizeFrame.origin.y += self.topBackgroundExtension
|
||||
}
|
||||
|
||||
transition.updateFrame(view: self.entityKeyboardView, frame: entityKeyboardSizeFrame)
|
||||
if let entityKeyboardComponentView = self.entityKeyboardView.view {
|
||||
if entityKeyboardComponentView.superview == nil {
|
||||
self.clippingView.addSubview(entityKeyboardComponentView)
|
||||
}
|
||||
transition.updateFrame(view: entityKeyboardComponentView, frame: entityKeyboardSizeFrame)
|
||||
}
|
||||
|
||||
transition.updateFrame(view: self.clippingView, frame: clippingFrame)
|
||||
|
||||
|
|
@ -2366,7 +2375,7 @@ public final class ChatEntityKeyboardInputNode: ChatInputNode {
|
|||
}
|
||||
|
||||
public func scrollToGroupEmoji() {
|
||||
if let pagerView = self.entityKeyboardView.componentView as? EntityKeyboardComponent.View {
|
||||
if let pagerView = self.entityKeyboardView.view as? EntityKeyboardComponent.View {
|
||||
pagerView.scrollToItemGroup(contentId: "emoji", groupId: "peerSpecific", subgroupId: nil)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -157,7 +157,8 @@ private final class ChatScheduleTimeSheetContentComponent: Component {
|
|||
self.environment = environment
|
||||
|
||||
if self.component == nil {
|
||||
if case .format = component.mode {
|
||||
switch component.mode {
|
||||
case .format, .search:
|
||||
self.minDate = Date(timeIntervalSince1970: 0.0)
|
||||
self.maxDate = Date(timeIntervalSince1970: Double(Int32.max - 1))
|
||||
if let currentTime = component.currentTime {
|
||||
|
|
@ -167,7 +168,7 @@ private final class ChatScheduleTimeSheetContentComponent: Component {
|
|||
} else {
|
||||
self.date = Date()
|
||||
}
|
||||
} else {
|
||||
default:
|
||||
self.updateMinimumDate(currentTime: component.currentTime, minimalTime: component.minimalTime)
|
||||
}
|
||||
self.repeatPeriod = component.currentRepeatPeriod
|
||||
|
|
@ -227,6 +228,9 @@ private final class ChatScheduleTimeSheetContentComponent: Component {
|
|||
title = strings.Conversation_FormatDate_Title
|
||||
case .poll:
|
||||
title = strings.CreatePoll_Deadline_Title
|
||||
case .search:
|
||||
//TODO:localize
|
||||
title = "Search"
|
||||
}
|
||||
let titleSize = self.title.update(
|
||||
transition: transition,
|
||||
|
|
@ -386,6 +390,8 @@ private final class ChatScheduleTimeSheetContentComponent: Component {
|
|||
var repeatValueFrame = CGRect()
|
||||
if case .format = component.mode {
|
||||
contentHeight += 8.0
|
||||
} else if case .search = component.mode {
|
||||
contentHeight += 8.0
|
||||
} else if case .poll = component.mode {
|
||||
contentHeight += 8.0
|
||||
} else {
|
||||
|
|
@ -497,6 +503,9 @@ private final class ChatScheduleTimeSheetContentComponent: Component {
|
|||
buttonTitle = component.currentTime != nil ? strings.Conversation_FormatDate_EditDate : strings.Conversation_FormatDate_AddDate
|
||||
case .poll:
|
||||
buttonTitle = strings.CreatePoll_Deadline_SetDeadline
|
||||
case .search:
|
||||
//TODO:localize
|
||||
buttonTitle = "Done"
|
||||
}
|
||||
|
||||
let buttonSideInset: CGFloat = 30.0
|
||||
|
|
@ -539,7 +548,13 @@ private final class ChatScheduleTimeSheetContentComponent: Component {
|
|||
}
|
||||
contentHeight += buttonSize.height
|
||||
|
||||
if case .format = component.mode, component.currentTime != nil {
|
||||
var isFormatOrSearch = false
|
||||
if case .format = component.mode {
|
||||
isFormatOrSearch = true
|
||||
} else if case .search = component.mode {
|
||||
isFormatOrSearch = true
|
||||
}
|
||||
if isFormatOrSearch && component.currentTime != nil {
|
||||
contentHeight += 8.0
|
||||
|
||||
let buttonSize = self.secondaryButton.update(
|
||||
|
|
@ -947,6 +962,7 @@ public class ChatScheduleTimeScreen: ViewControllerComponentContainer {
|
|||
case reminders
|
||||
case format
|
||||
case poll
|
||||
case search
|
||||
}
|
||||
|
||||
public struct Result {
|
||||
|
|
|
|||
|
|
@ -272,7 +272,7 @@ public final class EntityKeyboardComponent: Component {
|
|||
public final class View: UIView {
|
||||
private let tintContainerView: UIView
|
||||
|
||||
private let pagerView: ComponentHostView<EntityKeyboardChildEnvironment>
|
||||
private let pagerView: ComponentView<EntityKeyboardChildEnvironment>
|
||||
|
||||
private var component: EntityKeyboardComponent?
|
||||
public private(set) weak var state: EmptyComponentState?
|
||||
|
|
@ -295,20 +295,32 @@ public final class EntityKeyboardComponent: Component {
|
|||
|
||||
override init(frame: CGRect) {
|
||||
self.tintContainerView = UIView()
|
||||
self.pagerView = ComponentHostView<EntityKeyboardChildEnvironment>()
|
||||
self.pagerView = ComponentView()
|
||||
|
||||
super.init(frame: frame)
|
||||
|
||||
//self.clipsToBounds = true
|
||||
self.disablesInteractiveTransitionGestureRecognizer = true
|
||||
|
||||
self.addSubview(self.pagerView)
|
||||
}
|
||||
|
||||
required init?(coder: NSCoder) {
|
||||
fatalError("init(coder:) has not been implemented")
|
||||
}
|
||||
|
||||
override public func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
|
||||
if self.alpha.isZero {
|
||||
return nil
|
||||
}
|
||||
for view in self.subviews.reversed() {
|
||||
if let result = view.hitTest(self.convert(point, to: view), with: event), result.isUserInteractionEnabled {
|
||||
return result
|
||||
}
|
||||
}
|
||||
|
||||
let result = super.hitTest(point, with: event)
|
||||
return result
|
||||
}
|
||||
|
||||
func update(component: EntityKeyboardComponent, availableSize: CGSize, state: EmptyComponentState, environment: Environment<Empty>, transition: ComponentTransition) -> CGSize {
|
||||
self.state = state
|
||||
|
||||
|
|
@ -787,7 +799,12 @@ public final class EntityKeyboardComponent: Component {
|
|||
forceUpdate: forceUpdate,
|
||||
containerSize: availableSize
|
||||
)
|
||||
transition.setFrame(view: self.pagerView, frame: CGRect(origin: CGPoint(), size: pagerSize))
|
||||
if let pagerComponentView = self.pagerView.view {
|
||||
if pagerComponentView.superview == nil {
|
||||
self.insertSubview(pagerComponentView, at: 0)
|
||||
}
|
||||
transition.setFrame(view: pagerComponentView, frame: CGRect(origin: CGPoint(), size: pagerSize))
|
||||
}
|
||||
|
||||
let accountContext = component.emojiContent?.context ?? component.stickerContent?.context
|
||||
if let searchComponent = self.searchComponent, let accountContext = accountContext {
|
||||
|
|
|
|||
|
|
@ -441,9 +441,7 @@ public final class NavigationBarImpl: ASDisplayNode, NavigationBar {
|
|||
self.leftButtonNodeImpl.view.removeFromSuperview()
|
||||
|
||||
var backTitle: String?
|
||||
if case .glass = self.presentationData.theme.style {
|
||||
backTitle = ""
|
||||
} else if let customBackButtonText = self.customBackButtonText {
|
||||
if let customBackButtonText = self.customBackButtonText {
|
||||
backTitle = customBackButtonText
|
||||
} else if let leftBarButtonItem = item.leftBarButtonItem, leftBarButtonItem.backButtonAppearance {
|
||||
backTitle = leftBarButtonItem.title
|
||||
|
|
@ -460,6 +458,12 @@ public final class NavigationBarImpl: ASDisplayNode, NavigationBar {
|
|||
}
|
||||
}
|
||||
|
||||
if backTitle != nil {
|
||||
if case .glass = self.presentationData.theme.style {
|
||||
backTitle = ""
|
||||
}
|
||||
}
|
||||
|
||||
if let backTitle {
|
||||
self.backButtonNodeImpl.updateManualText(backTitle, isBack: true)
|
||||
if self.backButtonNodeImpl.supernode == nil {
|
||||
|
|
@ -631,10 +635,6 @@ public final class NavigationBarImpl: ASDisplayNode, NavigationBar {
|
|||
|
||||
self.backButtonNodeImpl.color = self.presentationData.theme.buttonColor
|
||||
self.backButtonNodeImpl.disabledColor = self.presentationData.theme.disabledButtonColor
|
||||
self.leftButtonNodeImpl.color = self.presentationData.theme.buttonColor
|
||||
self.leftButtonNodeImpl.disabledColor = self.presentationData.theme.disabledButtonColor
|
||||
self.rightButtonNodeImpl.color = self.presentationData.theme.buttonColor
|
||||
self.rightButtonNodeImpl.disabledColor = self.presentationData.theme.disabledButtonColor
|
||||
self.backButtonArrow.image = presentationData.theme.style == .glass ? generateTintedImage(image: glassBackArrowImage, color: self.presentationData.theme.buttonColor) : navigationBarBackArrowImage(color: self.presentationData.theme.buttonColor)
|
||||
if let title = self.title {
|
||||
self.titleNode.attributedText = NSAttributedString(string: title, font: NavigationBarImpl.titleFont, textColor: self.presentationData.theme.primaryTextColor)
|
||||
|
|
@ -753,10 +753,6 @@ public final class NavigationBarImpl: ASDisplayNode, NavigationBar {
|
|||
|
||||
self.backButtonNodeImpl.color = self.presentationData.theme.buttonColor
|
||||
self.backButtonNodeImpl.disabledColor = self.presentationData.theme.disabledButtonColor
|
||||
self.leftButtonNodeImpl.color = self.presentationData.theme.buttonColor
|
||||
self.leftButtonNodeImpl.disabledColor = self.presentationData.theme.disabledButtonColor
|
||||
self.rightButtonNodeImpl.color = self.presentationData.theme.buttonColor
|
||||
self.rightButtonNodeImpl.disabledColor = self.presentationData.theme.disabledButtonColor
|
||||
self.backButtonArrow.image = self.presentationData.theme.style == .glass ? generateTintedImage(image: glassBackArrowImage, color: self.presentationData.theme.buttonColor) : navigationBarBackArrowImage(color: self.presentationData.theme.buttonColor)
|
||||
if let title = self.title {
|
||||
self.titleNode.attributedText = NSAttributedString(string: title, font: NavigationBarImpl.titleFont, textColor: self.presentationData.theme.primaryTextColor)
|
||||
|
|
@ -906,6 +902,15 @@ public final class NavigationBarImpl: ASDisplayNode, NavigationBar {
|
|||
self.badgeNode.alpha = 1.0
|
||||
}
|
||||
} else if self.leftButtonNodeImpl.view.superview != nil {
|
||||
switch self.leftButtonNodeImpl.commonContentType {
|
||||
case .accent:
|
||||
self.leftButtonNodeImpl.color = self.presentationData.theme.accentForegroundColor
|
||||
self.leftButtonNodeImpl.disabledColor = self.presentationData.theme.accentForegroundColor.withMultipliedAlpha(0.5)
|
||||
case .generic:
|
||||
self.leftButtonNodeImpl.color = self.presentationData.theme.buttonColor
|
||||
self.leftButtonNodeImpl.disabledColor = self.presentationData.theme.disabledButtonColor
|
||||
}
|
||||
|
||||
let leftButtonSize = self.leftButtonNodeImpl.updateLayout(constrainedSize: CGSize(width: size.width, height: 44.0), isLandscape: isLandscape, isLeftAligned: true)
|
||||
leftTitleInset = leftButtonSize.width + leftButtonInset + 1.0
|
||||
|
||||
|
|
@ -937,6 +942,15 @@ public final class NavigationBarImpl: ASDisplayNode, NavigationBar {
|
|||
|
||||
var rightButtonsWidth: CGFloat = 0.0
|
||||
if self.rightButtonNodeImpl.view.superview != nil {
|
||||
switch self.rightButtonNodeImpl.commonContentType {
|
||||
case .accent:
|
||||
self.rightButtonNodeImpl.color = self.presentationData.theme.accentForegroundColor
|
||||
self.rightButtonNodeImpl.disabledColor = self.presentationData.theme.accentForegroundColor.withMultipliedAlpha(0.5)
|
||||
case .generic:
|
||||
self.rightButtonNodeImpl.color = self.presentationData.theme.buttonColor
|
||||
self.rightButtonNodeImpl.disabledColor = self.presentationData.theme.disabledButtonColor
|
||||
}
|
||||
|
||||
let rightButtonSize = self.rightButtonNodeImpl.updateLayout(constrainedSize: (CGSize(width: size.width, height: 44.0)), isLandscape: isLandscape, isLeftAligned: false)
|
||||
if !self.rightButtonNodeImpl.isEmpty {
|
||||
rightButtonsWidth += rightButtonSize.width
|
||||
|
|
@ -975,7 +989,16 @@ public final class NavigationBarImpl: ASDisplayNode, NavigationBar {
|
|||
leftButtonsBackgroundTransition.setBounds(view: leftButtonsBackgroundView.background, bounds: CGRect(origin: CGPoint(), size: leftButtonsBackgroundFrame.size))
|
||||
leftButtonsBackgroundTransition.setFrame(view: leftButtonsBackgroundView.container, frame: CGRect(origin: CGPoint(), size: leftButtonsBackgroundFrame.size))
|
||||
ComponentTransition(transition).setAlpha(view: leftButtonsBackgroundView.background, alpha: leftButtonsWidth == 0.0 ? 0.0 : 1.0)
|
||||
leftButtonsBackgroundView.background.update(size: leftButtonsBackgroundFrame.size, cornerRadius: leftButtonsBackgroundFrame.height * 0.5, isDark: self.presentationData.theme.overallDarkAppearance, tintColor: .init(kind: self.presentationData.theme.glassStyle == .clear ? .clear : .panel), isInteractive: true, isVisible: leftButtonsWidth != 0.0, transition: leftButtonsBackgroundTransition)
|
||||
|
||||
var leftButtonsColor: GlassBackgroundView.TintColor = .init(kind: self.presentationData.theme.glassStyle == .clear ? .clear : .panel)
|
||||
switch self.leftButtonNodeImpl.commonContentType {
|
||||
case .accent:
|
||||
leftButtonsColor = .init(kind: .custom(style: self.presentationData.theme.glassStyle == .clear ? .clear : .default, color: self.presentationData.theme.accentButtonColor))
|
||||
case .generic:
|
||||
break
|
||||
}
|
||||
|
||||
leftButtonsBackgroundView.background.update(size: leftButtonsBackgroundFrame.size, cornerRadius: leftButtonsBackgroundFrame.height * 0.5, isDark: self.presentationData.theme.overallDarkAppearance, tintColor: leftButtonsColor, isInteractive: true, isVisible: leftButtonsWidth != 0.0, transition: leftButtonsBackgroundTransition)
|
||||
}
|
||||
|
||||
if let rightButtonsBackgroundView = self.rightButtonsBackgroundView {
|
||||
|
|
@ -1001,8 +1024,16 @@ public final class NavigationBarImpl: ASDisplayNode, NavigationBar {
|
|||
})
|
||||
}
|
||||
|
||||
var rightButtonsColor: GlassBackgroundView.TintColor = .init(kind: self.presentationData.theme.glassStyle == .clear ? .clear : .panel)
|
||||
switch self.rightButtonNodeImpl.commonContentType {
|
||||
case .accent:
|
||||
rightButtonsColor = .init(kind: .custom(style: self.presentationData.theme.glassStyle == .clear ? .clear : .default, color: self.presentationData.theme.accentButtonColor))
|
||||
case .generic:
|
||||
break
|
||||
}
|
||||
|
||||
rightButtonsBackgroundView.background.isHidden = false
|
||||
rightButtonsBackgroundView.background.update(size: rightButtonsBackgroundFrame.size, cornerRadius: rightButtonsBackgroundFrame.height * 0.5, isDark: self.presentationData.theme.overallDarkAppearance, tintColor: .init(kind: self.presentationData.theme.glassStyle == .clear ? .clear : .panel), isInteractive: true, transition: rightButtonsBackgroundTransition)
|
||||
rightButtonsBackgroundView.background.update(size: rightButtonsBackgroundFrame.size, cornerRadius: rightButtonsBackgroundFrame.height * 0.5, isDark: self.presentationData.theme.overallDarkAppearance, tintColor: rightButtonsColor, isInteractive: true, transition: rightButtonsBackgroundTransition)
|
||||
} else {
|
||||
rightButtonsBackgroundView.background.isHidden = true
|
||||
}
|
||||
|
|
@ -1038,7 +1069,7 @@ public final class NavigationBarImpl: ASDisplayNode, NavigationBar {
|
|||
titleViewTransition = .immediate
|
||||
}
|
||||
|
||||
let titleSize = titleView.updateLayout(availableSize: CGSize(width: size.width - max(leftTitleInset, rightTitleInset) * 2.0, height: nominalHeight), transition: titleViewTransition)
|
||||
let titleSize = titleView.updateLayout(availableSize: CGSize(width: size.width - leftTitleInset - rightTitleInset, height: nominalHeight), transition: titleViewTransition)
|
||||
|
||||
var titleFrame = CGRect(origin: CGPoint(x: floorToScreenPixels((size.width - titleSize.width) * 0.5), y: contentVerticalOrigin + floorToScreenPixels((nominalHeight - titleSize.height) / 2.0)), size: titleSize)
|
||||
if titleFrame.origin.x + titleFrame.width > size.width - rightTitleInset {
|
||||
|
|
@ -1050,8 +1081,14 @@ public final class NavigationBarImpl: ASDisplayNode, NavigationBar {
|
|||
|
||||
titleViewTransition.updateFrame(view: titleView, frame: titleFrame)
|
||||
} else {
|
||||
let titleSize = CGSize(width: max(1.0, size.width - max(leftTitleInset, rightTitleInset) * 2.0), height: nominalHeight)
|
||||
let titleFrame = CGRect(origin: CGPoint(x: floor((size.width - titleSize.width) / 2.0), y: contentVerticalOrigin + floorToScreenPixels((nominalHeight - titleSize.height) / 2.0)), size: titleSize)
|
||||
let titleSize = CGSize(width: max(1.0, size.width - leftTitleInset - rightTitleInset), height: nominalHeight)
|
||||
var titleFrame = CGRect(origin: CGPoint(x: floor((size.width - titleSize.width) / 2.0), y: contentVerticalOrigin + floorToScreenPixels((nominalHeight - titleSize.height) / 2.0)), size: titleSize)
|
||||
if titleFrame.origin.x + titleFrame.width > size.width - rightTitleInset {
|
||||
titleFrame.origin.x = size.width - rightTitleInset - titleFrame.width
|
||||
}
|
||||
if titleFrame.origin.x < leftTitleInset {
|
||||
titleFrame.origin.x = leftTitleInset + floorToScreenPixels((size.width - leftTitleInset - rightTitleInset - titleFrame.width) * 0.5)
|
||||
}
|
||||
var titleViewTransition = transition
|
||||
if titleView.frame.isEmpty {
|
||||
titleViewTransition = .immediate
|
||||
|
|
|
|||
|
|
@ -261,7 +261,7 @@ private final class NavigationButtonItemNode: ImmediateTextNode {
|
|||
}
|
||||
}
|
||||
|
||||
private(set) var imageNode: ASImageNode?
|
||||
private(set) var imageView: UIImageView?
|
||||
|
||||
private var _image: UIImage?
|
||||
public var image: UIImage? {
|
||||
|
|
@ -271,23 +271,21 @@ private final class NavigationButtonItemNode: ImmediateTextNode {
|
|||
_image = value
|
||||
|
||||
if let _ = value {
|
||||
if self.imageNode == nil {
|
||||
let imageNode = ASImageNode()
|
||||
imageNode.displayWithoutProcessing = true
|
||||
imageNode.displaysAsynchronously = false
|
||||
self.imageNode = imageNode
|
||||
if self.imageView == nil {
|
||||
let imageView = UIImageView()
|
||||
self.imageView = imageView
|
||||
|
||||
self.addSubnode(imageNode)
|
||||
self.view.addSubview(imageView)
|
||||
}
|
||||
self.imageNode?.image = image
|
||||
if self.imageNode?.image?.renderingMode == .alwaysTemplate {
|
||||
self.imageNode?.tintColor = self.color
|
||||
self.imageView?.image = image
|
||||
if self.imageView?.image?.renderingMode == .alwaysTemplate {
|
||||
self.imageView?.tintColor = self.color
|
||||
} else {
|
||||
self.imageNode?.tintColor = nil
|
||||
self.imageView?.tintColor = nil
|
||||
}
|
||||
} else if let imageNode = self.imageNode {
|
||||
imageNode.removeFromSupernode()
|
||||
self.imageNode = nil
|
||||
} else if let imageView = self.imageView {
|
||||
imageView.removeFromSuperview()
|
||||
self.imageView = nil
|
||||
}
|
||||
|
||||
self.invalidateCalculatedLayout()
|
||||
|
|
@ -311,11 +309,15 @@ private final class NavigationButtonItemNode: ImmediateTextNode {
|
|||
|
||||
public var color: UIColor = UIColor(rgb: 0x0088ff) {
|
||||
didSet {
|
||||
if self.imageNode?.image?.renderingMode == .alwaysTemplate {
|
||||
self.imageNode?.tintColor = self.color
|
||||
}
|
||||
if let text = self._text {
|
||||
self.attributedText = NSAttributedString(string: text, attributes: self.attributesForCurrentState())
|
||||
if self.color != oldValue {
|
||||
if self.imageView?.image?.renderingMode == .alwaysTemplate {
|
||||
self.imageView?.tintColor = self.color
|
||||
} else {
|
||||
self.image = self.image
|
||||
}
|
||||
if let text = self._text {
|
||||
self.attributedText = NSAttributedString(string: text, attributes: self.attributesForCurrentState())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -422,11 +424,11 @@ private final class NavigationButtonItemNode: ImmediateTextNode {
|
|||
let size = CGSize(width: max(nodeSize.width, superSize.width), height: max(nodeSize.height, superSize.height))
|
||||
node.frame = CGRect(origin: CGPoint(), size: nodeSize)
|
||||
return size
|
||||
} else if let imageNode = self.imageNode {
|
||||
let nodeSize = imageNode.image?.size ?? CGSize()
|
||||
} else if let imageView = self.imageView {
|
||||
let nodeSize = imageView.image?.size ?? CGSize()
|
||||
let size = CGSize(width: max(nodeSize.width, superSize.width), height: max(44.0, max(nodeSize.height, superSize.height)))
|
||||
let imageFrame = CGRect(origin: CGPoint(x: floorToScreenPixels((size.width - nodeSize.width) / 2.0), y: floorToScreenPixels((size.height - nodeSize.height) / 2.0)), size: nodeSize)
|
||||
imageNode.frame = imageFrame
|
||||
imageView.frame = imageFrame
|
||||
return size
|
||||
} else {
|
||||
superSize.height = max(44.0, superSize.height)
|
||||
|
|
@ -524,9 +526,15 @@ private final class NavigationButtonItemNode: ImmediateTextNode {
|
|||
|
||||
|
||||
public final class NavigationButtonNodeImpl: ContextControllerSourceNode, NavigationButtonNode {
|
||||
enum ContentType {
|
||||
case accent
|
||||
case generic
|
||||
}
|
||||
|
||||
private let isGlass: Bool
|
||||
private var isBack: Bool = false
|
||||
|
||||
private var items: [UIBarButtonItem] = []
|
||||
private var nodes: [NavigationButtonItemNode] = []
|
||||
|
||||
private var disappearingNodes: [(frame: CGRect, size: CGSize, node: NavigationButtonItemNode)] = []
|
||||
|
|
@ -648,6 +656,8 @@ public final class NavigationButtonNodeImpl: ContextControllerSourceNode, Naviga
|
|||
}
|
||||
|
||||
public func updateItems(_ items: [UIBarButtonItem], animated: Bool) {
|
||||
self.items = items
|
||||
|
||||
for i in 0 ..< items.count {
|
||||
let node: NavigationButtonItemNode
|
||||
if self.nodes.count > i {
|
||||
|
|
@ -676,8 +686,11 @@ public final class NavigationButtonNodeImpl: ContextControllerSourceNode, Naviga
|
|||
node.alpha = self.manualAlpha
|
||||
node.item = items[i]
|
||||
if items[i].title == "___close" {
|
||||
//node.image = glassCloseImage
|
||||
node.image = generateTintedImage(image: UIImage(bundleImageName: "Navigation/Close"), color: self.color)
|
||||
node.image = generateTintedImage(image: UIImage(bundleImageName: "Navigation/Close"), color: .white)?.withRenderingMode(.alwaysTemplate)
|
||||
} else if items[i].title == "___clear" {
|
||||
node.image = generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Delete"), color: .white)?.withRenderingMode(.alwaysTemplate)
|
||||
} else if items[i].title == "___done" {
|
||||
node.image = generateTintedImage(image: UIImage(bundleImageName: "Navigation/Done"), color: .white)?.withRenderingMode(.alwaysTemplate)
|
||||
} else {
|
||||
node.image = items[i].image
|
||||
node.text = items[i].title ?? ""
|
||||
|
|
@ -749,7 +762,7 @@ public final class NavigationButtonNodeImpl: ContextControllerSourceNode, Naviga
|
|||
nodeOrigin.x += 16.0
|
||||
}
|
||||
|
||||
if !self.isGlass && node.node == nil && node.imageNode != nil && i == self.nodes.count - 1 {
|
||||
if !self.isGlass && node.node == nil && node.imageView != nil && i == self.nodes.count - 1 {
|
||||
nodeOrigin.x -= 5.0
|
||||
}
|
||||
}
|
||||
|
|
@ -791,4 +804,26 @@ public final class NavigationButtonNodeImpl: ContextControllerSourceNode, Naviga
|
|||
}
|
||||
return true
|
||||
}
|
||||
|
||||
var commonContentType: ContentType {
|
||||
var commonType: ContentType?
|
||||
for item in self.items {
|
||||
var nodeContentType: ContentType = .generic
|
||||
if item.title == "___close" {
|
||||
} else if item.title == "___clear" {
|
||||
} else if item.title == "___done" {
|
||||
nodeContentType = .accent
|
||||
}
|
||||
|
||||
if commonType == nil {
|
||||
commonType = nodeContentType
|
||||
} else {
|
||||
if commonType != nodeContentType {
|
||||
return .generic
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return commonType ?? .generic
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4949,7 +4949,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, PeerInfoScreenNodePro
|
|||
self?.deactivateSearch()
|
||||
}, fieldStyle: .glass)
|
||||
} else if let currentPaneKey = self.paneContainerNode.currentPaneKey, case .savedMessagesChats = currentPaneKey {
|
||||
let contentNode = ChatListSearchContainerNode(context: self.context, animationCache: self.context.animationCache, animationRenderer: self.context.animationRenderer, filter: [.removeSearchHeader], requestPeerType: nil, location: .savedMessagesChats(peerId: self.context.account.peerId), displaySearchFilters: false, hasDownloads: false, initialFilter: .chats, openPeer: { [weak self] peer, _, _, _ in
|
||||
let contentNode = ChatListSearchContainerNode(context: self.context, animationCache: self.context.animationCache, animationRenderer: self.context.animationRenderer, filter: [.removeSearchHeader], requestPeerType: nil, location: .savedMessagesChats(peerId: self.context.account.peerId), folder: nil, displaySearchFilters: false, hasDownloads: false, initialFilter: .chats, openPeer: { [weak self] peer, _, _, _ in
|
||||
guard let self else {
|
||||
return
|
||||
}
|
||||
|
|
@ -6460,7 +6460,9 @@ public final class PeerInfoScreenImpl: ViewController, PeerInfoScreen, KeyShortc
|
|||
separatorColor: .clear,
|
||||
badgeBackgroundColor: baseNavigationBarPresentationData.theme.badgeBackgroundColor,
|
||||
badgeStrokeColor: baseNavigationBarPresentationData.theme.badgeStrokeColor,
|
||||
badgeTextColor: baseNavigationBarPresentationData.theme.badgeTextColor
|
||||
badgeTextColor: baseNavigationBarPresentationData.theme.badgeTextColor,
|
||||
accentButtonColor: baseNavigationBarPresentationData.theme.accentButtonColor,
|
||||
accentForegroundColor: baseNavigationBarPresentationData.theme.accentForegroundColor
|
||||
), strings: baseNavigationBarPresentationData.strings))
|
||||
|
||||
self._hasGlassStyle = true
|
||||
|
|
|
|||
|
|
@ -1330,6 +1330,7 @@ final class PeerSelectionControllerNode: ASDisplayNode {
|
|||
filter: self.filter,
|
||||
requestPeerType: self.requestPeerType,
|
||||
location: chatListLocation,
|
||||
folder: nil,
|
||||
displaySearchFilters: false,
|
||||
hasDownloads: false,
|
||||
openPeer: { [weak self] peer, chatPeer, threadId, _ in
|
||||
|
|
|
|||
|
|
@ -1172,7 +1172,7 @@ extension ChatControllerImpl {
|
|||
}
|
||||
return updatedState
|
||||
})
|
||||
self.searchResult.set(.single((results, state, .general(scope: .channels, tags: nil, minDate: nil, maxDate: nil))))
|
||||
self.searchResult.set(.single((results, state, .general(scope: .channels, tags: nil, minDate: nil, maxDate: nil, folderId: nil))))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -2412,7 +2412,7 @@ extension ChatControllerImpl {
|
|||
}
|
||||
}
|
||||
}, openCalendarSearch: { [weak self] in
|
||||
self?.openCalendarSearch(timestamp: Int32(Date().timeIntervalSince1970))
|
||||
self?.openCalendarSearch(timestamp: Int32(Date().timeIntervalSince1970), isMedia: false)
|
||||
}, toggleMembersSearch: { [weak self] value in
|
||||
if let strongSelf = self {
|
||||
strongSelf.updateChatPresentationInterfaceState(animated: true, interactive: true, { state in
|
||||
|
|
|
|||
|
|
@ -3468,7 +3468,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
|||
switch strongSelf.chatLocation {
|
||||
case let .peer(peerId):
|
||||
if alreadyThere {
|
||||
strongSelf.openCalendarSearch(timestamp: timestamp)
|
||||
strongSelf.openCalendarSearch(timestamp: timestamp, isMedia: true)
|
||||
} else {
|
||||
strongSelf.navigateToMessage(from: nil, to: .index(MessageIndex(id: MessageId(peerId: peerId, namespace: 0, id: 0), timestamp: timestamp - Int32(NSTimeZone.local.secondsFromGMT()))), scrollPosition: .bottom(0.0), rememberInStack: false, animated: true, completion: nil)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ import ChatListUI
|
|||
import EmojiStatusComponent
|
||||
import TelegramUIPreferences
|
||||
import TranslateUI
|
||||
import TelegramNotices
|
||||
|
||||
extension ChatControllerImpl {
|
||||
final class ContentData {
|
||||
|
|
@ -507,6 +508,25 @@ extension ChatControllerImpl {
|
|||
messageOptionsTitleInfo = .single(nil)
|
||||
}
|
||||
|
||||
var savedMessagesChatsTip: Signal<Bool, NoError> = .single(false)
|
||||
if case .peer(context.account.peerId) = chatLocation {
|
||||
let hasSavedChats = context.engine.messages.savedMessagesHasPeersOtherThanSaved()
|
||||
if chatLocation.threadId == nil {
|
||||
savedMessagesChatsTip = hasSavedChats
|
||||
|> distinctUntilChanged
|
||||
|> mapToSignal { value -> Signal<Bool, NoError> in
|
||||
if !value {
|
||||
return .single(false)
|
||||
}
|
||||
return ApplicationSpecificNotice.getSavedMessagesChatListView(accountManager: context.sharedContext.accountManager)
|
||||
|> map { value -> Bool in
|
||||
return value < 5
|
||||
}
|
||||
}
|
||||
|> distinctUntilChanged
|
||||
}
|
||||
}
|
||||
|
||||
self.titleDisposable = (combineLatest(
|
||||
queue: Queue.mainQueue(),
|
||||
peerView.get(),
|
||||
|
|
@ -515,9 +535,10 @@ extension ChatControllerImpl {
|
|||
subtitleTextSignal,
|
||||
configuration,
|
||||
hasPeerInfo,
|
||||
messageOptionsTitleInfo
|
||||
messageOptionsTitleInfo,
|
||||
savedMessagesChatsTip
|
||||
)
|
||||
|> deliverOnMainQueue).startStrict(next: { [weak self] peerView, onlineMemberCount, displayedCount, subtitleText, configuration, hasPeerInfo, messageOptionsTitleInfo in
|
||||
|> deliverOnMainQueue).startStrict(next: { [weak self] peerView, onlineMemberCount, displayedCount, subtitleText, configuration, hasPeerInfo, messageOptionsTitleInfo, savedMessagesChatsTip in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
|
|
@ -586,7 +607,13 @@ extension ChatControllerImpl {
|
|||
strongSelf.state.chatTitleContent = .custom(title: [ChatTitleContent.TitleTextItem(id: AnyHashable(0), content: .text(channel.debugDisplayTitle))], subtitle: nil, isEnabled: true)
|
||||
}
|
||||
} else {
|
||||
strongSelf.state.chatTitleContent = .peer(peerView: ChatTitleContent.PeerData(peerView: peerView), customTitle: nil, customSubtitle: nil, onlineMemberCount: onlineMemberCount, isScheduledMessages: isScheduledMessages, isMuted: nil, customMessageCount: nil, isEnabled: hasPeerInfo)
|
||||
var customSubtitle: String?
|
||||
if savedMessagesChatsTip {
|
||||
//TODO:localize
|
||||
customSubtitle = "Tap to view as chats"
|
||||
}
|
||||
|
||||
strongSelf.state.chatTitleContent = .peer(peerView: ChatTitleContent.PeerData(peerView: peerView), customTitle: nil, customSubtitle: customSubtitle, onlineMemberCount: onlineMemberCount, isScheduledMessages: isScheduledMessages, isMuted: nil, customMessageCount: nil, isEnabled: hasPeerInfo)
|
||||
|
||||
let imageOverride: AvatarNodeImageOverride?
|
||||
if context.account.peerId == peer.id {
|
||||
|
|
|
|||
|
|
@ -10,83 +10,48 @@ import ChatControllerInteraction
|
|||
import Display
|
||||
import UIKit
|
||||
import UndoUI
|
||||
import ChatScheduleTimeController
|
||||
|
||||
extension ChatControllerImpl {
|
||||
func openCalendarSearch(timestamp: Int32) {
|
||||
func openCalendarSearch(timestamp: Int32, isMedia: Bool) {
|
||||
guard let peerId = self.chatLocation.peerId else {
|
||||
return
|
||||
}
|
||||
self.chatDisplayNode.dismissInput()
|
||||
|
||||
let initialTimestamp = timestamp
|
||||
var dismissCalendarScreen: (() -> Void)?
|
||||
var selectDay: ((Int32) -> Void)?
|
||||
var openClearHistory: ((Int32) -> Void)?
|
||||
|
||||
let enableMessageRangeDeletion: Bool = peerId.namespace == Namespaces.Peer.CloudUser
|
||||
|
||||
let displayMedia = self.presentationInterfaceState.historyFilter == nil
|
||||
|
||||
let calendarScreen = CalendarMessageScreen(
|
||||
context: self.context,
|
||||
peerId: peerId,
|
||||
calendarSource: self.context.engine.messages.sparseMessageCalendar(peerId: peerId, threadId: self.chatLocation.threadId, tag: .photoOrVideo, displayMedia: displayMedia),
|
||||
initialTimestamp: initialTimestamp,
|
||||
enableMessageRangeDeletion: enableMessageRangeDeletion,
|
||||
canNavigateToEmptyDays: true,
|
||||
navigateToDay: { [weak self] c, index, timestamp in
|
||||
guard let strongSelf = self else {
|
||||
c.dismiss()
|
||||
return
|
||||
}
|
||||
|
||||
strongSelf.alwaysShowSearchResultsAsList = false
|
||||
strongSelf.chatDisplayNode.alwaysShowSearchResultsAsList = false
|
||||
strongSelf.updateChatPresentationInterfaceState(animated: false, interactive: false, { state in
|
||||
return state.updatedDisplayHistoryFilterAsList(false).updatedSearch(nil)
|
||||
})
|
||||
|
||||
c.dismiss()
|
||||
|
||||
strongSelf.loadingMessage.set(.single(.generic))
|
||||
|
||||
let peerId: PeerId
|
||||
let threadId: Int64?
|
||||
switch strongSelf.chatLocation {
|
||||
case let .peer(peerIdValue):
|
||||
peerId = peerIdValue
|
||||
threadId = nil
|
||||
case let .replyThread(replyThreadMessage):
|
||||
peerId = replyThreadMessage.peerId
|
||||
threadId = replyThreadMessage.threadId
|
||||
case .customChatContents:
|
||||
return
|
||||
}
|
||||
|
||||
strongSelf.messageIndexDisposable.set((strongSelf.context.engine.messages.searchMessageIdByTimestamp(peerId: peerId, threadId: threadId, timestamp: timestamp) |> deliverOnMainQueue).startStrict(next: { messageId in
|
||||
if let strongSelf = self {
|
||||
strongSelf.loadingMessage.set(.single(nil))
|
||||
if let messageId = messageId {
|
||||
strongSelf.navigateToMessage(from: nil, to: .id(messageId, NavigateToMessageParams(timestamp: nil, quote: nil)), forceInCurrentChat: true)
|
||||
}
|
||||
if isMedia {
|
||||
let initialTimestamp = timestamp
|
||||
var dismissCalendarScreen: (() -> Void)?
|
||||
var selectDay: ((Int32) -> Void)?
|
||||
var openClearHistory: ((Int32) -> Void)?
|
||||
|
||||
let enableMessageRangeDeletion: Bool = peerId.namespace == Namespaces.Peer.CloudUser
|
||||
|
||||
let displayMedia = self.presentationInterfaceState.historyFilter == nil
|
||||
|
||||
let calendarScreen = CalendarMessageScreen(
|
||||
context: self.context,
|
||||
peerId: peerId,
|
||||
calendarSource: self.context.engine.messages.sparseMessageCalendar(peerId: peerId, threadId: self.chatLocation.threadId, tag: .photoOrVideo, displayMedia: displayMedia),
|
||||
initialTimestamp: initialTimestamp,
|
||||
enableMessageRangeDeletion: enableMessageRangeDeletion,
|
||||
canNavigateToEmptyDays: true,
|
||||
navigateToDay: { [weak self] c, index, timestamp in
|
||||
guard let strongSelf = self else {
|
||||
c.dismiss()
|
||||
return
|
||||
}
|
||||
}))
|
||||
},
|
||||
previewDay: { [weak self] timestamp, _, sourceNode, sourceRect, gesture in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
|
||||
var items: [ContextMenuItem] = []
|
||||
|
||||
items.append(.action(ContextMenuActionItem(text: strongSelf.presentationData.strings.Chat_JumpToDate, icon: { theme in
|
||||
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/GoToMessage"), color: theme.contextMenu.primaryColor)
|
||||
}, action: { _, f in
|
||||
f(.dismissWithoutContent)
|
||||
dismissCalendarScreen?()
|
||||
|
||||
|
||||
strongSelf.alwaysShowSearchResultsAsList = false
|
||||
strongSelf.chatDisplayNode.alwaysShowSearchResultsAsList = false
|
||||
strongSelf.updateChatPresentationInterfaceState(animated: false, interactive: false, { state in
|
||||
return state.updatedDisplayHistoryFilterAsList(false).updatedSearch(nil)
|
||||
})
|
||||
|
||||
c.dismiss()
|
||||
|
||||
strongSelf.loadingMessage.set(.single(.generic))
|
||||
|
||||
|
||||
let peerId: PeerId
|
||||
let threadId: Int64?
|
||||
switch strongSelf.chatLocation {
|
||||
|
|
@ -99,7 +64,7 @@ extension ChatControllerImpl {
|
|||
case .customChatContents:
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
strongSelf.messageIndexDisposable.set((strongSelf.context.engine.messages.searchMessageIdByTimestamp(peerId: peerId, threadId: threadId, timestamp: timestamp) |> deliverOnMainQueue).startStrict(next: { messageId in
|
||||
if let strongSelf = self {
|
||||
strongSelf.loadingMessage.set(.single(nil))
|
||||
|
|
@ -108,84 +73,168 @@ extension ChatControllerImpl {
|
|||
}
|
||||
}
|
||||
}))
|
||||
})))
|
||||
|
||||
if enableMessageRangeDeletion && (peerId.namespace == Namespaces.Peer.CloudUser || peerId.namespace == Namespaces.Peer.SecretChat) {
|
||||
items.append(.action(ContextMenuActionItem(text: strongSelf.presentationData.strings.DialogList_ClearHistoryConfirmation, textColor: .destructive, icon: { theme in
|
||||
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Delete"), color: theme.contextMenu.destructiveColor)
|
||||
},
|
||||
previewDay: { [weak self] timestamp, _, sourceNode, sourceRect, gesture in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
|
||||
var items: [ContextMenuItem] = []
|
||||
|
||||
items.append(.action(ContextMenuActionItem(text: strongSelf.presentationData.strings.Chat_JumpToDate, icon: { theme in
|
||||
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/GoToMessage"), color: theme.contextMenu.primaryColor)
|
||||
}, action: { _, f in
|
||||
f(.dismissWithoutContent)
|
||||
openClearHistory?(timestamp)
|
||||
})))
|
||||
|
||||
items.append(.separator)
|
||||
|
||||
items.append(.action(ContextMenuActionItem(text: strongSelf.presentationData.strings.Common_Select, icon: { theme in
|
||||
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Select"), color: theme.contextMenu.primaryColor)
|
||||
}, action: { _, f in
|
||||
f(.dismissWithoutContent)
|
||||
selectDay?(timestamp)
|
||||
})))
|
||||
}
|
||||
|
||||
let chatController = strongSelf.context.sharedContext.makeChatController(context: strongSelf.context, chatLocation: .peer(id: peerId), subject: .message(id: .timestamp(timestamp), highlight: nil, timecode: nil, setupReply: false), botStart: nil, mode: .standard(.previewing), params: nil)
|
||||
chatController.canReadHistory.set(false)
|
||||
|
||||
strongSelf.chatDisplayNode.messageTransitionNode.dismissMessageReactionContexts()
|
||||
|
||||
let contextController = makeContextController(presentationData: strongSelf.presentationData, source: .controller(ChatContextControllerContentSourceImpl(controller: chatController, sourceNode: sourceNode, sourceRect: sourceRect, passthroughTouches: true)), items: .single(ContextController.Items(content: .list(items))), gesture: gesture)
|
||||
strongSelf.presentInGlobalOverlay(contextController)
|
||||
}
|
||||
)
|
||||
|
||||
calendarScreen.completedWithRemoveMessagesInRange = { [weak self] range, type, dayCount, calendarSource in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
|
||||
let statusText: String
|
||||
switch type {
|
||||
case .forEveryone:
|
||||
statusText = strongSelf.presentationData.strings.Chat_MessageRangeDeleted_ForBothSides(Int32(dayCount))
|
||||
default:
|
||||
statusText = strongSelf.presentationData.strings.Chat_MessageRangeDeleted_ForMe(Int32(dayCount))
|
||||
}
|
||||
|
||||
strongSelf.chatDisplayNode.historyNode.ignoreMessagesInTimestampRange = range
|
||||
|
||||
strongSelf.present(UndoOverlayController(presentationData: strongSelf.context.sharedContext.currentPresentationData.with { $0 }, content: .removedChat(context: strongSelf.context, title: NSAttributedString(string: statusText), text: nil), elevatedLayout: false, action: { value in
|
||||
guard let strongSelf = self else {
|
||||
return false
|
||||
}
|
||||
|
||||
if value == .commit {
|
||||
let _ = calendarSource.removeMessagesInRange(minTimestamp: range.lowerBound, maxTimestamp: range.upperBound, type: type, completion: {
|
||||
Queue.mainQueue().after(1.0, {
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
dismissCalendarScreen?()
|
||||
|
||||
strongSelf.loadingMessage.set(.single(.generic))
|
||||
|
||||
let peerId: PeerId
|
||||
let threadId: Int64?
|
||||
switch strongSelf.chatLocation {
|
||||
case let .peer(peerIdValue):
|
||||
peerId = peerIdValue
|
||||
threadId = nil
|
||||
case let .replyThread(replyThreadMessage):
|
||||
peerId = replyThreadMessage.peerId
|
||||
threadId = replyThreadMessage.threadId
|
||||
case .customChatContents:
|
||||
return
|
||||
}
|
||||
|
||||
strongSelf.messageIndexDisposable.set((strongSelf.context.engine.messages.searchMessageIdByTimestamp(peerId: peerId, threadId: threadId, timestamp: timestamp) |> deliverOnMainQueue).startStrict(next: { messageId in
|
||||
if let strongSelf = self {
|
||||
strongSelf.loadingMessage.set(.single(nil))
|
||||
if let messageId = messageId {
|
||||
strongSelf.navigateToMessage(from: nil, to: .id(messageId, NavigateToMessageParams(timestamp: nil, quote: nil)), forceInCurrentChat: true)
|
||||
}
|
||||
}
|
||||
strongSelf.chatDisplayNode.historyNode.ignoreMessagesInTimestampRange = nil
|
||||
})
|
||||
})
|
||||
return true
|
||||
} else if value == .undo {
|
||||
strongSelf.chatDisplayNode.historyNode.ignoreMessagesInTimestampRange = nil
|
||||
return true
|
||||
}))
|
||||
})))
|
||||
|
||||
if enableMessageRangeDeletion && (peerId.namespace == Namespaces.Peer.CloudUser || peerId.namespace == Namespaces.Peer.SecretChat) {
|
||||
items.append(.action(ContextMenuActionItem(text: strongSelf.presentationData.strings.DialogList_ClearHistoryConfirmation, textColor: .destructive, icon: { theme in
|
||||
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Delete"), color: theme.contextMenu.destructiveColor)
|
||||
}, action: { _, f in
|
||||
f(.dismissWithoutContent)
|
||||
openClearHistory?(timestamp)
|
||||
})))
|
||||
|
||||
items.append(.separator)
|
||||
|
||||
items.append(.action(ContextMenuActionItem(text: strongSelf.presentationData.strings.Common_Select, icon: { theme in
|
||||
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Select"), color: theme.contextMenu.primaryColor)
|
||||
}, action: { _, f in
|
||||
f(.dismissWithoutContent)
|
||||
selectDay?(timestamp)
|
||||
})))
|
||||
}
|
||||
|
||||
let chatController = strongSelf.context.sharedContext.makeChatController(context: strongSelf.context, chatLocation: .peer(id: peerId), subject: .message(id: .timestamp(timestamp), highlight: nil, timecode: nil, setupReply: false), botStart: nil, mode: .standard(.previewing), params: nil)
|
||||
chatController.canReadHistory.set(false)
|
||||
|
||||
strongSelf.chatDisplayNode.messageTransitionNode.dismissMessageReactionContexts()
|
||||
|
||||
let contextController = makeContextController(presentationData: strongSelf.presentationData, source: .controller(ChatContextControllerContentSourceImpl(controller: chatController, sourceNode: sourceNode, sourceRect: sourceRect, passthroughTouches: true)), items: .single(ContextController.Items(content: .list(items))), gesture: gesture)
|
||||
strongSelf.presentInGlobalOverlay(contextController)
|
||||
}
|
||||
return false
|
||||
}), in: .current)
|
||||
}
|
||||
|
||||
self.effectiveNavigationController?.pushViewController(calendarScreen)
|
||||
|
||||
dismissCalendarScreen = { [weak calendarScreen] in
|
||||
calendarScreen?.dismiss(completion: nil)
|
||||
}
|
||||
selectDay = { [weak calendarScreen] timestamp in
|
||||
calendarScreen?.selectDay(timestamp: timestamp)
|
||||
}
|
||||
openClearHistory = { [weak calendarScreen] timestamp in
|
||||
calendarScreen?.openClearHistory(timestamp: timestamp)
|
||||
)
|
||||
|
||||
calendarScreen.completedWithRemoveMessagesInRange = { [weak self] range, type, dayCount, calendarSource in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
|
||||
let statusText: String
|
||||
switch type {
|
||||
case .forEveryone:
|
||||
statusText = strongSelf.presentationData.strings.Chat_MessageRangeDeleted_ForBothSides(Int32(dayCount))
|
||||
default:
|
||||
statusText = strongSelf.presentationData.strings.Chat_MessageRangeDeleted_ForMe(Int32(dayCount))
|
||||
}
|
||||
|
||||
strongSelf.chatDisplayNode.historyNode.ignoreMessagesInTimestampRange = range
|
||||
|
||||
strongSelf.present(UndoOverlayController(presentationData: strongSelf.context.sharedContext.currentPresentationData.with { $0 }, content: .removedChat(context: strongSelf.context, title: NSAttributedString(string: statusText), text: nil), elevatedLayout: false, action: { value in
|
||||
guard let strongSelf = self else {
|
||||
return false
|
||||
}
|
||||
|
||||
if value == .commit {
|
||||
let _ = calendarSource.removeMessagesInRange(minTimestamp: range.lowerBound, maxTimestamp: range.upperBound, type: type, completion: {
|
||||
Queue.mainQueue().after(1.0, {
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
strongSelf.chatDisplayNode.historyNode.ignoreMessagesInTimestampRange = nil
|
||||
})
|
||||
})
|
||||
return true
|
||||
} else if value == .undo {
|
||||
strongSelf.chatDisplayNode.historyNode.ignoreMessagesInTimestampRange = nil
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}), in: .current)
|
||||
}
|
||||
|
||||
self.effectiveNavigationController?.pushViewController(calendarScreen)
|
||||
|
||||
dismissCalendarScreen = { [weak calendarScreen] in
|
||||
calendarScreen?.dismiss(completion: nil)
|
||||
}
|
||||
selectDay = { [weak calendarScreen] timestamp in
|
||||
calendarScreen?.selectDay(timestamp: timestamp)
|
||||
}
|
||||
openClearHistory = { [weak calendarScreen] timestamp in
|
||||
calendarScreen?.openClearHistory(timestamp: timestamp)
|
||||
}
|
||||
} else {
|
||||
let controller = ChatScheduleTimeScreen(
|
||||
context: self.context,
|
||||
mode: .search,
|
||||
currentTime: nil,
|
||||
currentRepeatPeriod: nil,
|
||||
minimalTime: nil,
|
||||
isDark: false,
|
||||
completion: { [weak self] result in
|
||||
guard let self else {
|
||||
return
|
||||
}
|
||||
|
||||
self.alwaysShowSearchResultsAsList = false
|
||||
self.chatDisplayNode.alwaysShowSearchResultsAsList = false
|
||||
self.updateChatPresentationInterfaceState(animated: false, interactive: false, { state in
|
||||
return state.updatedDisplayHistoryFilterAsList(false).updatedSearch(nil)
|
||||
})
|
||||
|
||||
self.loadingMessage.set(.single(.generic))
|
||||
|
||||
let peerId: PeerId
|
||||
let threadId: Int64?
|
||||
switch self.chatLocation {
|
||||
case let .peer(peerIdValue):
|
||||
peerId = peerIdValue
|
||||
threadId = nil
|
||||
case let .replyThread(replyThreadMessage):
|
||||
peerId = replyThreadMessage.peerId
|
||||
threadId = replyThreadMessage.threadId
|
||||
case .customChatContents:
|
||||
return
|
||||
}
|
||||
|
||||
self.messageIndexDisposable.set((self.context.engine.messages.searchMessageIdByTimestamp(peerId: peerId, threadId: threadId, timestamp: result.time) |> deliverOnMainQueue).startStrict(next: { [weak self] messageId in
|
||||
guard let self else {
|
||||
return
|
||||
}
|
||||
self.loadingMessage.set(.single(nil))
|
||||
if let messageId {
|
||||
self.navigateToMessage(from: nil, to: .id(messageId, NavigateToMessageParams(timestamp: nil, quote: nil)), forceInCurrentChat: true)
|
||||
}
|
||||
}))
|
||||
}
|
||||
)
|
||||
self.push(controller)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -47,10 +47,14 @@ func leftNavigationButtonForChatInterfaceState(_ presentationInterfaceState: Cha
|
|||
}
|
||||
|
||||
if canClear {
|
||||
return ChatNavigationButton(action: .clearHistory, buttonItem: UIBarButtonItem(title: title, style: .plain, target: target, action: selector))
|
||||
let buttonItem = UIBarButtonItem(title: "___clear", style: .plain, target: target, action: selector)
|
||||
buttonItem.accessibilityLabel = title
|
||||
return ChatNavigationButton(action: .clearHistory, buttonItem: buttonItem)
|
||||
} else {
|
||||
title = strings.Conversation_ClearCache
|
||||
return ChatNavigationButton(action: .clearCache, buttonItem: UIBarButtonItem(title: title, style: .plain, target: target, action: selector))
|
||||
let buttonItem = UIBarButtonItem(title: "___clear", style: .plain, target: target, action: selector)
|
||||
buttonItem.accessibilityLabel = title
|
||||
return ChatNavigationButton(action: .clearCache, buttonItem: buttonItem)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -88,7 +92,7 @@ func rightNavigationButtonForChatInterfaceState(context: AccountContext, present
|
|||
if let currentButton = currentButton, currentButton.action == .cancelMessageSelection {
|
||||
return currentButton
|
||||
} else {
|
||||
let buttonItem = UIBarButtonItem(title: strings.Common_Cancel, style: .plain, target: target, action: selector)
|
||||
let buttonItem = UIBarButtonItem(title: "___done", style: .plain, target: target, action: selector)
|
||||
buttonItem.accessibilityLabel = strings.Common_Cancel
|
||||
return ChatNavigationButton(action: .cancelMessageSelection, buttonItem: buttonItem)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -60,7 +60,7 @@ final class WebSearchGalleryControllerPresentationArguments {
|
|||
}
|
||||
|
||||
class WebSearchGalleryController: ViewController {
|
||||
private static let navigationTheme = NavigationBarTheme(overallDarkAppearance: false, buttonColor: .white, disabledButtonColor: UIColor(rgb: 0x525252), primaryTextColor: .white, backgroundColor: .clear, enableBackgroundBlur: false, separatorColor: .clear, badgeBackgroundColor: .clear, badgeStrokeColor: .clear, badgeTextColor: .clear)
|
||||
private static let navigationTheme = NavigationBarTheme(overallDarkAppearance: false, buttonColor: .white, disabledButtonColor: UIColor(rgb: 0x525252), primaryTextColor: .white, backgroundColor: .clear, enableBackgroundBlur: false, separatorColor: .clear, badgeBackgroundColor: .clear, badgeStrokeColor: .clear, badgeTextColor: .clear, accentButtonColor: .white, accentForegroundColor: .black)
|
||||
|
||||
private var galleryNode: GalleryControllerNode {
|
||||
return self.displayNode as! GalleryControllerNode
|
||||
|
|
|
|||
|
|
@ -3800,7 +3800,9 @@ public final class WebAppController: ViewController, AttachmentContainable {
|
|||
separatorColor: UIColor(rgb: 0x000000, alpha: 0.25),
|
||||
badgeBackgroundColor: .clear,
|
||||
badgeStrokeColor: .clear,
|
||||
badgeTextColor: .clear
|
||||
badgeTextColor: .clear,
|
||||
accentButtonColor: self.presentationData.theme.list.itemCheckColors.fillColor,
|
||||
accentForegroundColor: self.presentationData.theme.list.itemCheckColors.foregroundColor
|
||||
),
|
||||
strings: NavigationBarStrings(back: "", close: "")
|
||||
)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue