mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-11-07 09:20:08 +00:00
Saved messages improvements
This commit is contained in:
parent
85b845e3cb
commit
ad271bf102
@ -1442,10 +1442,16 @@ public final class ChatListNode: ListView {
|
|||||||
}
|
}
|
||||||
switch error {
|
switch error {
|
||||||
case let .limitReached(count):
|
case let .limitReached(count):
|
||||||
|
var replaceImpl: ((ViewController) -> Void)?
|
||||||
let controller = PremiumLimitScreen(context: context, subject: .pinnedSavedPeers, count: Int32(count), action: {
|
let controller = PremiumLimitScreen(context: context, subject: .pinnedSavedPeers, count: Int32(count), action: {
|
||||||
|
let premiumScreen = PremiumIntroScreen(context: context, source: .pinnedChats)
|
||||||
|
replaceImpl?(premiumScreen)
|
||||||
return true
|
return true
|
||||||
})
|
})
|
||||||
self.push?(controller)
|
self.push?(controller)
|
||||||
|
replaceImpl = { [weak controller] c in
|
||||||
|
controller?.replace(with: c)
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|||||||
@ -138,7 +138,7 @@ extension UserLimitsConfiguration {
|
|||||||
}
|
}
|
||||||
|
|
||||||
self.maxPinnedChatCount = getValue("dialogs_pinned_limit", orElse: defaultValue.maxPinnedChatCount)
|
self.maxPinnedChatCount = getValue("dialogs_pinned_limit", orElse: defaultValue.maxPinnedChatCount)
|
||||||
self.maxPinnedSavedChatCount = getValue("saved_pinned_limit", orElse: defaultValue.maxPinnedSavedChatCount)
|
self.maxPinnedSavedChatCount = getValue("saved_dialogs_pinned_limit", orElse: defaultValue.maxPinnedSavedChatCount)
|
||||||
self.maxArchivedPinnedChatCount = getValue("dialogs_folder_pinned_limit", orElse: defaultValue.maxArchivedPinnedChatCount)
|
self.maxArchivedPinnedChatCount = getValue("dialogs_folder_pinned_limit", orElse: defaultValue.maxArchivedPinnedChatCount)
|
||||||
self.maxChannelsCount = getValue("channels_limit", orElse: defaultValue.maxChannelsCount)
|
self.maxChannelsCount = getValue("channels_limit", orElse: defaultValue.maxChannelsCount)
|
||||||
self.maxPublicLinksCount = getValue("channels_public_limit", orElse: defaultValue.maxPublicLinksCount)
|
self.maxPublicLinksCount = getValue("channels_public_limit", orElse: defaultValue.maxPublicLinksCount)
|
||||||
|
|||||||
@ -1064,13 +1064,13 @@ public extension TelegramEngine {
|
|||||||
public func toggleForumChannelTopicPinned(id: EnginePeer.Id, threadId: Int64) -> Signal<Never, SetForumChannelTopicPinnedError> {
|
public func toggleForumChannelTopicPinned(id: EnginePeer.Id, threadId: Int64) -> Signal<Never, SetForumChannelTopicPinnedError> {
|
||||||
return self.account.postbox.transaction { transaction -> ([Int64], Int) in
|
return self.account.postbox.transaction { transaction -> ([Int64], Int) in
|
||||||
if id == self.account.peerId {
|
if id == self.account.peerId {
|
||||||
var limit = 5
|
|
||||||
let appConfiguration: AppConfiguration = transaction.getPreferencesEntry(key: PreferencesKeys.appConfiguration)?.get(AppConfiguration.self) ?? AppConfiguration.defaultValue
|
let appConfiguration: AppConfiguration = transaction.getPreferencesEntry(key: PreferencesKeys.appConfiguration)?.get(AppConfiguration.self) ?? AppConfiguration.defaultValue
|
||||||
if let data = appConfiguration.data, let value = data["saved_pinned_limit"] as? Double {
|
|
||||||
limit = Int(value)
|
|
||||||
}
|
|
||||||
|
|
||||||
return (transaction.getPeerPinnedThreads(peerId: id), limit)
|
let accountPeer = transaction.getPeer(self.account.peerId)
|
||||||
|
let limitsConfiguration = UserLimitsConfiguration(appConfiguration: appConfiguration, isPremium: accountPeer?.isPremium ?? false)
|
||||||
|
let limit = limitsConfiguration.maxPinnedSavedChatCount
|
||||||
|
|
||||||
|
return (transaction.getPeerPinnedThreads(peerId: id), Int(limit))
|
||||||
} else {
|
} else {
|
||||||
var limit = 5
|
var limit = 5
|
||||||
let appConfiguration: AppConfiguration = transaction.getPreferencesEntry(key: PreferencesKeys.appConfiguration)?.get(AppConfiguration.self) ?? AppConfiguration.defaultValue
|
let appConfiguration: AppConfiguration = transaction.getPreferencesEntry(key: PreferencesKeys.appConfiguration)?.get(AppConfiguration.self) ?? AppConfiguration.defaultValue
|
||||||
|
|||||||
@ -24,6 +24,9 @@ swift_library(
|
|||||||
"//submodules/TelegramUIPreferences",
|
"//submodules/TelegramUIPreferences",
|
||||||
"//submodules/UIKitRuntimeUtils",
|
"//submodules/UIKitRuntimeUtils",
|
||||||
"//submodules/ChatPresentationInterfaceState",
|
"//submodules/ChatPresentationInterfaceState",
|
||||||
|
"//submodules/ContactsPeerItem",
|
||||||
|
"//submodules/ItemListUI",
|
||||||
|
"//submodules/ChatListSearchItemHeader",
|
||||||
],
|
],
|
||||||
visibility = [
|
visibility = [
|
||||||
"//visibility:public",
|
"//visibility:public",
|
||||||
|
|||||||
@ -13,6 +13,9 @@ import SwiftSignalKit
|
|||||||
import TelegramUIPreferences
|
import TelegramUIPreferences
|
||||||
import UIKitRuntimeUtils
|
import UIKitRuntimeUtils
|
||||||
import ChatPresentationInterfaceState
|
import ChatPresentationInterfaceState
|
||||||
|
import ContactsPeerItem
|
||||||
|
import ItemListUI
|
||||||
|
import ChatListSearchItemHeader
|
||||||
|
|
||||||
public final class ChatInlineSearchResultsListComponent: Component {
|
public final class ChatInlineSearchResultsListComponent: Component {
|
||||||
public struct Presentation: Equatable {
|
public struct Presentation: Equatable {
|
||||||
@ -65,7 +68,7 @@ public final class ChatInlineSearchResultsListComponent: Component {
|
|||||||
public enum Contents: Equatable {
|
public enum Contents: Equatable {
|
||||||
case empty
|
case empty
|
||||||
case tag(MemoryBuffer)
|
case tag(MemoryBuffer)
|
||||||
case search
|
case search(query: String, includeSavedPeers: Bool)
|
||||||
}
|
}
|
||||||
|
|
||||||
public let context: AccountContext
|
public let context: AccountContext
|
||||||
@ -74,8 +77,10 @@ public final class ChatInlineSearchResultsListComponent: Component {
|
|||||||
public let contents: Contents
|
public let contents: Contents
|
||||||
public let insets: UIEdgeInsets
|
public let insets: UIEdgeInsets
|
||||||
public let messageSelected: (EngineMessage) -> Void
|
public let messageSelected: (EngineMessage) -> Void
|
||||||
|
public let peerSelected: (EnginePeer) -> Void
|
||||||
public let loadTagMessages: (MemoryBuffer, MessageIndex?) -> Signal<MessageHistoryView, NoError>?
|
public let loadTagMessages: (MemoryBuffer, MessageIndex?) -> Signal<MessageHistoryView, NoError>?
|
||||||
public let getSearchResult: () -> Signal<SearchMessagesResult?, NoError>?
|
public let getSearchResult: () -> Signal<SearchMessagesResult?, NoError>?
|
||||||
|
public let getSavedPeers: (String) -> Signal<[(EnginePeer, MessageIndex?)], NoError>?
|
||||||
|
|
||||||
public init(
|
public init(
|
||||||
context: AccountContext,
|
context: AccountContext,
|
||||||
@ -84,8 +89,10 @@ public final class ChatInlineSearchResultsListComponent: Component {
|
|||||||
contents: Contents,
|
contents: Contents,
|
||||||
insets: UIEdgeInsets,
|
insets: UIEdgeInsets,
|
||||||
messageSelected: @escaping (EngineMessage) -> Void,
|
messageSelected: @escaping (EngineMessage) -> Void,
|
||||||
|
peerSelected: @escaping (EnginePeer) -> Void,
|
||||||
loadTagMessages: @escaping (MemoryBuffer, MessageIndex?) -> Signal<MessageHistoryView, NoError>?,
|
loadTagMessages: @escaping (MemoryBuffer, MessageIndex?) -> Signal<MessageHistoryView, NoError>?,
|
||||||
getSearchResult: @escaping () -> Signal<SearchMessagesResult?, NoError>?
|
getSearchResult: @escaping () -> Signal<SearchMessagesResult?, NoError>?,
|
||||||
|
getSavedPeers: @escaping (String) -> Signal<[(EnginePeer, MessageIndex?)], NoError>?
|
||||||
) {
|
) {
|
||||||
self.context = context
|
self.context = context
|
||||||
self.presentation = presentation
|
self.presentation = presentation
|
||||||
@ -93,8 +100,10 @@ public final class ChatInlineSearchResultsListComponent: Component {
|
|||||||
self.contents = contents
|
self.contents = contents
|
||||||
self.insets = insets
|
self.insets = insets
|
||||||
self.messageSelected = messageSelected
|
self.messageSelected = messageSelected
|
||||||
|
self.peerSelected = peerSelected
|
||||||
self.loadTagMessages = loadTagMessages
|
self.loadTagMessages = loadTagMessages
|
||||||
self.getSearchResult = getSearchResult
|
self.getSearchResult = getSearchResult
|
||||||
|
self.getSavedPeers = getSavedPeers
|
||||||
}
|
}
|
||||||
|
|
||||||
public static func ==(lhs: ChatInlineSearchResultsListComponent, rhs: ChatInlineSearchResultsListComponent) -> Bool {
|
public static func ==(lhs: ChatInlineSearchResultsListComponent, rhs: ChatInlineSearchResultsListComponent) -> Bool {
|
||||||
@ -116,23 +125,83 @@ public final class ChatInlineSearchResultsListComponent: Component {
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private enum Entry: Equatable, Comparable {
|
||||||
|
enum Id: Hashable {
|
||||||
|
case peer(EnginePeer.Id)
|
||||||
|
case message(EngineMessage.Id)
|
||||||
|
}
|
||||||
|
|
||||||
|
case peer(EnginePeer)
|
||||||
|
case message(EngineMessage)
|
||||||
|
|
||||||
|
var id: Id {
|
||||||
|
switch self {
|
||||||
|
case let .peer(peer):
|
||||||
|
return .peer(peer.id)
|
||||||
|
case let .message(message):
|
||||||
|
return .message(message.id)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static func ==(lhs: Entry, rhs: Entry) -> Bool {
|
||||||
|
switch lhs {
|
||||||
|
case let .peer(peer):
|
||||||
|
if case .peer(peer) = rhs {
|
||||||
|
return true
|
||||||
|
} else {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
case let .message(message):
|
||||||
|
if case .message(message) = rhs {
|
||||||
|
return true
|
||||||
|
} else {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static func <(lhs: Entry, rhs: Entry) -> Bool {
|
||||||
|
switch lhs {
|
||||||
|
case let .peer(lhsPeer):
|
||||||
|
switch rhs {
|
||||||
|
case let .peer(rhsPeer):
|
||||||
|
if lhsPeer.debugDisplayTitle != rhsPeer.debugDisplayTitle {
|
||||||
|
return lhsPeer.debugDisplayTitle < rhsPeer.debugDisplayTitle
|
||||||
|
}
|
||||||
|
return lhsPeer.id < rhsPeer.id
|
||||||
|
case .message:
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
case let .message(lhsMessage):
|
||||||
|
switch rhs {
|
||||||
|
case .peer:
|
||||||
|
return false
|
||||||
|
case let .message(rhsMessage):
|
||||||
|
return lhsMessage.index > rhsMessage.index
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private struct ContentsState: Equatable {
|
private struct ContentsState: Equatable {
|
||||||
enum ContentId: Equatable {
|
enum ContentId: Equatable {
|
||||||
case empty
|
case empty
|
||||||
case tag(MemoryBuffer)
|
case tag(MemoryBuffer)
|
||||||
case search
|
case search(String)
|
||||||
}
|
}
|
||||||
|
|
||||||
var id: Int
|
var id: Int
|
||||||
var contentId: ContentId
|
var contentId: ContentId
|
||||||
var entries: [EngineMessage]
|
var entries: [Entry]
|
||||||
|
var messages: [EngineMessage]
|
||||||
var hasEarlier: Bool
|
var hasEarlier: Bool
|
||||||
var hasLater: Bool
|
var hasLater: Bool
|
||||||
|
|
||||||
init(id: Int, contentId: ContentId, entries: [EngineMessage], hasEarlier: Bool, hasLater: Bool) {
|
init(id: Int, contentId: ContentId, entries: [Entry], messages: [EngineMessage], hasEarlier: Bool, hasLater: Bool) {
|
||||||
self.id = id
|
self.id = id
|
||||||
self.contentId = contentId
|
self.contentId = contentId
|
||||||
self.entries = entries
|
self.entries = entries
|
||||||
|
self.messages = messages
|
||||||
self.hasEarlier = hasEarlier
|
self.hasEarlier = hasEarlier
|
||||||
self.hasLater = hasLater
|
self.hasLater = hasLater
|
||||||
}
|
}
|
||||||
@ -248,11 +317,11 @@ public final class ChatInlineSearchResultsListComponent: Component {
|
|||||||
var loadAroundIndex: MessageIndex?
|
var loadAroundIndex: MessageIndex?
|
||||||
if visibleRange.firstIndex <= 5 {
|
if visibleRange.firstIndex <= 5 {
|
||||||
if contentsState.hasLater {
|
if contentsState.hasLater {
|
||||||
loadAroundIndex = contentsState.entries.first?.index
|
loadAroundIndex = contentsState.messages.first?.index
|
||||||
}
|
}
|
||||||
} else if visibleRange.lastIndex >= contentsState.entries.count - 5 {
|
} else if visibleRange.lastIndex >= contentsState.messages.count - 5 {
|
||||||
if contentsState.hasEarlier {
|
if contentsState.hasEarlier {
|
||||||
loadAroundIndex = contentsState.entries.last?.index
|
loadAroundIndex = contentsState.messages.last?.index
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -273,14 +342,19 @@ public final class ChatInlineSearchResultsListComponent: Component {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let messages = view.entries.reversed().map { entry in
|
||||||
|
return EngineMessage(entry.message)
|
||||||
|
}
|
||||||
|
|
||||||
let contentsId = self.nextContentsId
|
let contentsId = self.nextContentsId
|
||||||
self.nextContentsId += 1
|
self.nextContentsId += 1
|
||||||
self.contentsState = ContentsState(
|
self.contentsState = ContentsState(
|
||||||
id: contentsId,
|
id: contentsId,
|
||||||
contentId: .tag(tag),
|
contentId: .tag(tag),
|
||||||
entries: view.entries.reversed().map { entry in
|
entries: messages.map { message in
|
||||||
return EngineMessage(entry.message)
|
return .message(message)
|
||||||
},
|
},
|
||||||
|
messages: messages,
|
||||||
hasEarlier: view.earlierId != nil,
|
hasEarlier: view.earlierId != nil,
|
||||||
hasLater: view.laterId != nil
|
hasLater: view.laterId != nil
|
||||||
)
|
)
|
||||||
@ -316,6 +390,7 @@ public final class ChatInlineSearchResultsListComponent: Component {
|
|||||||
id: contentsId,
|
id: contentsId,
|
||||||
contentId: .empty,
|
contentId: .empty,
|
||||||
entries: [],
|
entries: [],
|
||||||
|
messages: [],
|
||||||
hasEarlier: false,
|
hasEarlier: false,
|
||||||
hasLater: false
|
hasLater: false
|
||||||
)
|
)
|
||||||
@ -346,14 +421,19 @@ public final class ChatInlineSearchResultsListComponent: Component {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let messages = view.entries.reversed().map { entry in
|
||||||
|
return EngineMessage(entry.message)
|
||||||
|
}
|
||||||
|
|
||||||
let contentsId = self.nextContentsId
|
let contentsId = self.nextContentsId
|
||||||
self.nextContentsId += 1
|
self.nextContentsId += 1
|
||||||
self.contentsState = ContentsState(
|
self.contentsState = ContentsState(
|
||||||
id: contentsId,
|
id: contentsId,
|
||||||
contentId: .tag(tag),
|
contentId: .tag(tag),
|
||||||
entries: view.entries.reversed().map { entry in
|
entries: messages.map { message in
|
||||||
return EngineMessage(entry.message)
|
return .message(message)
|
||||||
},
|
},
|
||||||
|
messages: messages,
|
||||||
hasEarlier: view.earlierId != nil,
|
hasEarlier: view.earlierId != nil,
|
||||||
hasLater: view.laterId != nil
|
hasLater: view.laterId != nil
|
||||||
)
|
)
|
||||||
@ -368,7 +448,7 @@ public final class ChatInlineSearchResultsListComponent: Component {
|
|||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
case .search:
|
case let .search(query, includeSavedPeers):
|
||||||
if previousComponent?.contents != component.contents {
|
if previousComponent?.contents != component.contents {
|
||||||
self.tagContents?.disposable?.dispose()
|
self.tagContents?.disposable?.dispose()
|
||||||
self.tagContents = nil
|
self.tagContents = nil
|
||||||
@ -379,21 +459,53 @@ public final class ChatInlineSearchResultsListComponent: Component {
|
|||||||
let disposable = MetaDisposable()
|
let disposable = MetaDisposable()
|
||||||
self.searchContents = (nil, disposable)
|
self.searchContents = (nil, disposable)
|
||||||
|
|
||||||
|
let savedPeers: Signal<[(EnginePeer, MessageIndex?)], NoError>
|
||||||
|
if includeSavedPeers, !query.isEmpty, let savedPeersSignal = component.getSavedPeers(query) {
|
||||||
|
savedPeers = savedPeersSignal
|
||||||
|
} else {
|
||||||
|
savedPeers = .single([])
|
||||||
|
}
|
||||||
|
|
||||||
if let historySignal = component.getSearchResult() {
|
if let historySignal = component.getSearchResult() {
|
||||||
disposable.set((historySignal
|
disposable.set((savedPeers
|
||||||
|> deliverOnMainQueue).startStrict(next: { [weak self] result in
|
|> mapToSignal { savedPeers -> Signal<([(EnginePeer, MessageIndex?)], SearchMessagesResult?), NoError> in
|
||||||
|
if savedPeers.isEmpty {
|
||||||
|
return historySignal
|
||||||
|
|> map { result in
|
||||||
|
return ([], result)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return (.single(nil) |> then(historySignal))
|
||||||
|
|> map { result in
|
||||||
|
return (savedPeers, result)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|> deliverOnMainQueue).startStrict(next: { [weak self] savedPeers, result in
|
||||||
guard let self else {
|
guard let self else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let messages: [EngineMessage] = result?.messages.map { entry in
|
||||||
|
return EngineMessage(entry)
|
||||||
|
} ?? []
|
||||||
|
|
||||||
|
var entries: [Entry] = []
|
||||||
|
for (peer, _) in savedPeers {
|
||||||
|
entries.append(.peer(peer))
|
||||||
|
}
|
||||||
|
for message in messages {
|
||||||
|
entries.append(.message(message))
|
||||||
|
}
|
||||||
|
entries.sort()
|
||||||
|
|
||||||
let contentsId = self.nextContentsId
|
let contentsId = self.nextContentsId
|
||||||
self.nextContentsId += 1
|
self.nextContentsId += 1
|
||||||
self.contentsState = ContentsState(
|
self.contentsState = ContentsState(
|
||||||
id: contentsId,
|
id: contentsId,
|
||||||
contentId: .search,
|
contentId: .search(query),
|
||||||
entries: result?.messages.map { entry in
|
entries: entries,
|
||||||
return EngineMessage(entry)
|
messages: messages,
|
||||||
} ?? [],
|
|
||||||
hasEarlier: false,
|
hasEarlier: false,
|
||||||
hasLater: false
|
hasLater: false
|
||||||
)
|
)
|
||||||
@ -418,17 +530,19 @@ public final class ChatInlineSearchResultsListComponent: Component {
|
|||||||
leftList: previousContentsState?.entries ?? [],
|
leftList: previousContentsState?.entries ?? [],
|
||||||
rightList: contentsState.entries,
|
rightList: contentsState.entries,
|
||||||
isLess: { lhs, rhs in
|
isLess: { lhs, rhs in
|
||||||
return lhs.index > rhs.index
|
return lhs < rhs
|
||||||
},
|
},
|
||||||
isEqual: { lhs, rhs in
|
isEqual: { lhs, rhs in
|
||||||
return lhs == rhs
|
return lhs == rhs
|
||||||
},
|
},
|
||||||
getId: { message in
|
getId: { entry in
|
||||||
return message.stableId
|
return entry.id
|
||||||
},
|
},
|
||||||
allUpdated: false
|
allUpdated: false
|
||||||
)
|
)
|
||||||
|
|
||||||
|
let displayMessagesHeader = contentsState.entries.count != contentsState.messages.count
|
||||||
|
|
||||||
let chatListPresentationData: ChatListPresentationData
|
let chatListPresentationData: ChatListPresentationData
|
||||||
if let current = self.currentChatListPresentationData, current.0 == component.presentation {
|
if let current = self.currentChatListPresentationData, current.0 == component.presentation {
|
||||||
chatListPresentationData = current.1
|
chatListPresentationData = current.1
|
||||||
@ -536,75 +650,107 @@ public final class ChatInlineSearchResultsListComponent: Component {
|
|||||||
self.chatListNodeInteraction = chatListNodeInteraction
|
self.chatListNodeInteraction = chatListNodeInteraction
|
||||||
}
|
}
|
||||||
|
|
||||||
let messageToItem: (EngineMessage) -> ListViewItem = { message -> ListViewItem in
|
let listPresentationData = ItemListPresentationData(component.context.sharedContext.currentPresentationData.with({ $0 }))
|
||||||
var effectiveAuthor: EnginePeer?
|
let peerSelected = component.peerSelected
|
||||||
|
|
||||||
if let forwardInfo = message.forwardInfo {
|
let entryToItem: (Entry) -> ListViewItem = { entry -> ListViewItem in
|
||||||
effectiveAuthor = forwardInfo.author.flatMap(EnginePeer.init)
|
switch entry {
|
||||||
if effectiveAuthor == nil, let authorSignature = forwardInfo.authorSignature {
|
case let .peer(peer):
|
||||||
effectiveAuthor = EnginePeer(TelegramUser(id: PeerId(namespace: Namespaces.Peer.Empty, id: PeerId.Id._internalFromInt64Value(Int64(authorSignature.persistentHashValue % 32))), accessHash: nil, firstName: authorSignature, lastName: nil, username: nil, phone: nil, photo: [], botInfo: nil, restrictionInfo: nil, flags: [], emojiStatus: nil, usernames: [], storiesHidden: nil, nameColor: nil, backgroundEmojiId: nil, profileColor: nil, profileBackgroundEmojiId: nil))
|
return ContactsPeerItem(
|
||||||
}
|
presentationData: listPresentationData,
|
||||||
}
|
sortOrder: component.presentation.nameSortOrder,
|
||||||
if let sourceAuthorInfo = message._asMessage().sourceAuthorInfo {
|
displayOrder: component.presentation.nameDisplayOrder,
|
||||||
if let originalAuthor = sourceAuthorInfo.originalAuthor, let peer = message.peers[originalAuthor] {
|
context: component.context,
|
||||||
effectiveAuthor = EnginePeer(peer)
|
peerMode: .generalSearch(isSavedMessages: true),
|
||||||
} else if let authorSignature = sourceAuthorInfo.originalAuthorName {
|
peer: .peer(peer: peer, chatPeer: peer),
|
||||||
effectiveAuthor = EnginePeer(TelegramUser(id: PeerId(namespace: Namespaces.Peer.Empty, id: PeerId.Id._internalFromInt64Value(Int64(authorSignature.persistentHashValue % 32))), accessHash: nil, firstName: authorSignature, lastName: nil, username: nil, phone: nil, photo: [], botInfo: nil, restrictionInfo: nil, flags: [], emojiStatus: nil, usernames: [], storiesHidden: nil, nameColor: nil, backgroundEmojiId: nil, profileColor: nil, profileBackgroundEmojiId: nil))
|
status: .none,
|
||||||
}
|
badge: nil,
|
||||||
}
|
|
||||||
if effectiveAuthor == nil {
|
|
||||||
effectiveAuthor = message.author
|
|
||||||
}
|
|
||||||
|
|
||||||
let renderedPeer: EngineRenderedPeer
|
|
||||||
if let effectiveAuthor {
|
|
||||||
renderedPeer = EngineRenderedPeer(peer: effectiveAuthor)
|
|
||||||
} else {
|
|
||||||
renderedPeer = EngineRenderedPeer(peerId: message.id.peerId, peers: [:], associatedMedia: [:])
|
|
||||||
}
|
|
||||||
|
|
||||||
return ChatListItem(
|
|
||||||
presentationData: chatListPresentationData,
|
|
||||||
context: component.context,
|
|
||||||
chatListLocation: .savedMessagesChats,
|
|
||||||
filterData: nil,
|
|
||||||
index: .forum(
|
|
||||||
pinnedIndex: .none,
|
|
||||||
timestamp: message.timestamp,
|
|
||||||
threadId: message.threadId ?? component.context.account.peerId.toInt64(),
|
|
||||||
namespace: message.id.namespace,
|
|
||||||
id: message.id.id
|
|
||||||
),
|
|
||||||
content: .peer(ChatListItemContent.PeerData(
|
|
||||||
messages: [message],
|
|
||||||
peer: renderedPeer,
|
|
||||||
threadInfo: nil,
|
|
||||||
combinedReadState: nil,
|
|
||||||
isRemovedFromTotalUnreadCount: false,
|
|
||||||
presence: nil,
|
|
||||||
hasUnseenMentions: false,
|
|
||||||
hasUnseenReactions: false,
|
|
||||||
draftState: nil,
|
|
||||||
inputActivities: nil,
|
|
||||||
promoInfo: nil,
|
|
||||||
ignoreUnreadBadge: false,
|
|
||||||
displayAsMessage: false,
|
|
||||||
hasFailedMessages: false,
|
|
||||||
forumTopicData: nil,
|
|
||||||
topForumTopicItems: [],
|
|
||||||
autoremoveTimeout: nil,
|
|
||||||
storyState: nil,
|
|
||||||
requiresPremiumForMessaging: false,
|
requiresPremiumForMessaging: false,
|
||||||
displayAsTopicList: false
|
enabled: true,
|
||||||
)),
|
selection: .none,
|
||||||
editing: false,
|
editing: ContactsPeerItemEditing(editable: false, editing: false, revealed: false),
|
||||||
hasActiveRevealControls: false,
|
index: nil,
|
||||||
selected: false,
|
header: displayMessagesHeader ? ChatListSearchItemHeader(type: .chats, theme: listPresentationData.theme, strings: listPresentationData.strings) : nil,
|
||||||
header: nil,
|
action: { [weak self] peer in
|
||||||
enableContextActions: false,
|
self?.listNode.clearHighlightAnimated(true)
|
||||||
hiddenOffset: false,
|
|
||||||
interaction: chatListNodeInteraction
|
if case let .peer(peer?, _) = peer {
|
||||||
)
|
peerSelected(peer)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
animationCache: component.context.animationCache,
|
||||||
|
animationRenderer: component.context.animationRenderer
|
||||||
|
)
|
||||||
|
case let .message(message):
|
||||||
|
var effectiveAuthor: EnginePeer?
|
||||||
|
|
||||||
|
if let forwardInfo = message.forwardInfo {
|
||||||
|
effectiveAuthor = forwardInfo.author.flatMap(EnginePeer.init)
|
||||||
|
if effectiveAuthor == nil, let authorSignature = forwardInfo.authorSignature {
|
||||||
|
effectiveAuthor = EnginePeer(TelegramUser(id: PeerId(namespace: Namespaces.Peer.Empty, id: PeerId.Id._internalFromInt64Value(Int64(authorSignature.persistentHashValue % 32))), accessHash: nil, firstName: authorSignature, lastName: nil, username: nil, phone: nil, photo: [], botInfo: nil, restrictionInfo: nil, flags: [], emojiStatus: nil, usernames: [], storiesHidden: nil, nameColor: nil, backgroundEmojiId: nil, profileColor: nil, profileBackgroundEmojiId: nil))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if let sourceAuthorInfo = message._asMessage().sourceAuthorInfo {
|
||||||
|
if let originalAuthor = sourceAuthorInfo.originalAuthor, let peer = message.peers[originalAuthor] {
|
||||||
|
effectiveAuthor = EnginePeer(peer)
|
||||||
|
} else if let authorSignature = sourceAuthorInfo.originalAuthorName {
|
||||||
|
effectiveAuthor = EnginePeer(TelegramUser(id: PeerId(namespace: Namespaces.Peer.Empty, id: PeerId.Id._internalFromInt64Value(Int64(authorSignature.persistentHashValue % 32))), accessHash: nil, firstName: authorSignature, lastName: nil, username: nil, phone: nil, photo: [], botInfo: nil, restrictionInfo: nil, flags: [], emojiStatus: nil, usernames: [], storiesHidden: nil, nameColor: nil, backgroundEmojiId: nil, profileColor: nil, profileBackgroundEmojiId: nil))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if effectiveAuthor == nil {
|
||||||
|
effectiveAuthor = message.author
|
||||||
|
}
|
||||||
|
|
||||||
|
let renderedPeer: EngineRenderedPeer
|
||||||
|
if let effectiveAuthor {
|
||||||
|
renderedPeer = EngineRenderedPeer(peer: effectiveAuthor)
|
||||||
|
} else {
|
||||||
|
renderedPeer = EngineRenderedPeer(peerId: message.id.peerId, peers: [:], associatedMedia: [:])
|
||||||
|
}
|
||||||
|
|
||||||
|
return ChatListItem(
|
||||||
|
presentationData: chatListPresentationData,
|
||||||
|
context: component.context,
|
||||||
|
chatListLocation: .savedMessagesChats,
|
||||||
|
filterData: nil,
|
||||||
|
index: .forum(
|
||||||
|
pinnedIndex: .none,
|
||||||
|
timestamp: message.timestamp,
|
||||||
|
threadId: message.threadId ?? component.context.account.peerId.toInt64(),
|
||||||
|
namespace: message.id.namespace,
|
||||||
|
id: message.id.id
|
||||||
|
),
|
||||||
|
content: .peer(ChatListItemContent.PeerData(
|
||||||
|
messages: [message],
|
||||||
|
peer: renderedPeer,
|
||||||
|
threadInfo: nil,
|
||||||
|
combinedReadState: nil,
|
||||||
|
isRemovedFromTotalUnreadCount: false,
|
||||||
|
presence: nil,
|
||||||
|
hasUnseenMentions: false,
|
||||||
|
hasUnseenReactions: false,
|
||||||
|
draftState: nil,
|
||||||
|
inputActivities: nil,
|
||||||
|
promoInfo: nil,
|
||||||
|
ignoreUnreadBadge: false,
|
||||||
|
displayAsMessage: false,
|
||||||
|
hasFailedMessages: false,
|
||||||
|
forumTopicData: nil,
|
||||||
|
topForumTopicItems: [],
|
||||||
|
autoremoveTimeout: nil,
|
||||||
|
storyState: nil,
|
||||||
|
requiresPremiumForMessaging: false,
|
||||||
|
displayAsTopicList: false
|
||||||
|
)),
|
||||||
|
editing: false,
|
||||||
|
hasActiveRevealControls: false,
|
||||||
|
selected: false,
|
||||||
|
header: displayMessagesHeader ? ChatListSearchItemHeader(type: .messages(location: nil), theme: listPresentationData.theme, strings: listPresentationData.strings) : nil,
|
||||||
|
enableContextActions: false,
|
||||||
|
hiddenOffset: false,
|
||||||
|
interaction: chatListNodeInteraction
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var scrollToItem: ListViewScrollToItem?
|
var scrollToItem: ListViewScrollToItem?
|
||||||
@ -626,7 +772,7 @@ public final class ChatInlineSearchResultsListComponent: Component {
|
|||||||
return ListViewInsertItem(
|
return ListViewInsertItem(
|
||||||
index: index,
|
index: index,
|
||||||
previousIndex: previousIndex,
|
previousIndex: previousIndex,
|
||||||
item: messageToItem(item),
|
item: entryToItem(item),
|
||||||
directionHint: nil,
|
directionHint: nil,
|
||||||
forceAnimateInsertion: false
|
forceAnimateInsertion: false
|
||||||
)
|
)
|
||||||
@ -635,7 +781,7 @@ public final class ChatInlineSearchResultsListComponent: Component {
|
|||||||
return ListViewUpdateItem(
|
return ListViewUpdateItem(
|
||||||
index: index,
|
index: index,
|
||||||
previousIndex: previousIndex,
|
previousIndex: previousIndex,
|
||||||
item: messageToItem(item),
|
item: entryToItem(item),
|
||||||
directionHint: nil
|
directionHint: nil
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
|
|||||||
@ -1292,17 +1292,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
|||||||
}
|
}
|
||||||
|
|
||||||
if !strongSelf.presentationInterfaceState.isPremium {
|
if !strongSelf.presentationInterfaceState.isPremium {
|
||||||
//TODO:localize
|
strongSelf.presentTagPremiumPaywall()
|
||||||
let context = strongSelf.context
|
|
||||||
var replaceImpl: ((ViewController) -> Void)?
|
|
||||||
let controller = PremiumDemoScreen(context: context, subject: .uniqueReactions, action: {
|
|
||||||
let controller = PremiumIntroScreen(context: context, source: .reactions)
|
|
||||||
replaceImpl?(controller)
|
|
||||||
})
|
|
||||||
replaceImpl = { [weak controller] c in
|
|
||||||
controller?.replace(with: c)
|
|
||||||
}
|
|
||||||
strongSelf.push(controller)
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1407,7 +1407,7 @@ class ChatControllerNode: ASDisplayNode, UIScrollViewDelegate {
|
|||||||
var inputPanelNodeHandlesTransition = false
|
var inputPanelNodeHandlesTransition = false
|
||||||
|
|
||||||
var dismissedInputPanelNode: ChatInputPanelNode?
|
var dismissedInputPanelNode: ChatInputPanelNode?
|
||||||
var dismissedSecondaryInputPanelNode: ASDisplayNode?
|
var dismissedSecondaryInputPanelNode: ChatInputPanelNode?
|
||||||
var dismissedAccessoryPanelNode: AccessoryPanelNode?
|
var dismissedAccessoryPanelNode: AccessoryPanelNode?
|
||||||
var dismissedInputContextPanelNode: ChatInputContextPanelNode?
|
var dismissedInputContextPanelNode: ChatInputContextPanelNode?
|
||||||
var dismissedOverlayContextPanelNode: ChatInputContextPanelNode?
|
var dismissedOverlayContextPanelNode: ChatInputContextPanelNode?
|
||||||
@ -1463,6 +1463,9 @@ class ChatControllerNode: ASDisplayNode, UIScrollViewDelegate {
|
|||||||
immediatelyLayoutSecondaryInputPanelAndAnimateAppearance = true
|
immediatelyLayoutSecondaryInputPanelAndAnimateAppearance = true
|
||||||
self.inputPanelClippingNode.insertSubnode(secondaryInputPanelNode, aboveSubnode: self.inputPanelBackgroundNode)
|
self.inputPanelClippingNode.insertSubnode(secondaryInputPanelNode, aboveSubnode: self.inputPanelBackgroundNode)
|
||||||
}
|
}
|
||||||
|
if let viewForOverlayContent = secondaryInputPanelNode.viewForOverlayContent, viewForOverlayContent.superview == nil {
|
||||||
|
self.inputPanelOverlayNode.view.addSubview(viewForOverlayContent)
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
let inputPanelHeight = secondaryInputPanelNode.updateLayout(width: layout.size.width, leftInset: layout.safeInsets.left, rightInset: layout.safeInsets.right, bottomInset: layout.intrinsicInsets.bottom, additionalSideInsets: layout.additionalInsets, maxHeight: layout.size.height - insets.top - inputPanelBottomInset, isSecondary: true, transition: transition, interfaceState: self.chatPresentationInterfaceState, metrics: layout.metrics, isMediaInputExpanded: self.inputPanelContainerNode.expansionFraction == 1.0)
|
let inputPanelHeight = secondaryInputPanelNode.updateLayout(width: layout.size.width, leftInset: layout.safeInsets.left, rightInset: layout.safeInsets.right, bottomInset: layout.intrinsicInsets.bottom, additionalSideInsets: layout.additionalInsets, maxHeight: layout.size.height - insets.top - inputPanelBottomInset, isSecondary: true, transition: transition, interfaceState: self.chatPresentationInterfaceState, metrics: layout.metrics, isMediaInputExpanded: self.inputPanelContainerNode.expansionFraction == 1.0)
|
||||||
secondaryInputPanelSize = CGSize(width: layout.size.width, height: inputPanelHeight)
|
secondaryInputPanelSize = CGSize(width: layout.size.width, height: inputPanelHeight)
|
||||||
@ -2092,6 +2095,14 @@ class ChatControllerNode: ASDisplayNode, UIScrollViewDelegate {
|
|||||||
|
|
||||||
transition.updateFrame(node: secondaryInputPanelNode, frame: apparentSecondaryInputPanelFrame)
|
transition.updateFrame(node: secondaryInputPanelNode, frame: apparentSecondaryInputPanelFrame)
|
||||||
transition.updateAlpha(node: secondaryInputPanelNode, alpha: 1.0)
|
transition.updateAlpha(node: secondaryInputPanelNode, alpha: 1.0)
|
||||||
|
|
||||||
|
if let viewForOverlayContent = secondaryInputPanelNode.viewForOverlayContent {
|
||||||
|
if inputPanelNodeHandlesTransition {
|
||||||
|
viewForOverlayContent.frame = apparentSecondaryInputPanelFrame
|
||||||
|
} else {
|
||||||
|
transition.updateFrame(view: viewForOverlayContent, frame: apparentSecondaryInputPanelFrame)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if let accessoryPanelNode = self.accessoryPanelNode, let accessoryPanelFrame = accessoryPanelFrame, !accessoryPanelNode.frame.equalTo(accessoryPanelFrame) {
|
if let accessoryPanelNode = self.accessoryPanelNode, let accessoryPanelFrame = accessoryPanelFrame, !accessoryPanelNode.frame.equalTo(accessoryPanelFrame) {
|
||||||
@ -2275,6 +2286,8 @@ class ChatControllerNode: ASDisplayNode, UIScrollViewDelegate {
|
|||||||
alphaCompleted = true
|
alphaCompleted = true
|
||||||
completed()
|
completed()
|
||||||
})
|
})
|
||||||
|
|
||||||
|
dismissedSecondaryInputPanelNode.viewForOverlayContent?.removeFromSuperview()
|
||||||
}
|
}
|
||||||
|
|
||||||
if let dismissedAccessoryPanelNode = dismissedAccessoryPanelNode {
|
if let dismissedAccessoryPanelNode = dismissedAccessoryPanelNode {
|
||||||
@ -2455,9 +2468,11 @@ class ChatControllerNode: ASDisplayNode, UIScrollViewDelegate {
|
|||||||
|
|
||||||
let mappedContents: ChatInlineSearchResultsListComponent.Contents
|
let mappedContents: ChatInlineSearchResultsListComponent.Contents
|
||||||
if let _ = self.chatPresentationInterfaceState.search?.resultsState {
|
if let _ = self.chatPresentationInterfaceState.search?.resultsState {
|
||||||
mappedContents = .search
|
mappedContents = .search(query: self.chatPresentationInterfaceState.search?.query ?? "", includeSavedPeers: self.alwaysShowSearchResultsAsList)
|
||||||
} else if let historyFilter = self.chatPresentationInterfaceState.historyFilter {
|
} else if let historyFilter = self.chatPresentationInterfaceState.historyFilter {
|
||||||
mappedContents = .tag(historyFilter.customTag)
|
mappedContents = .tag(historyFilter.customTag)
|
||||||
|
} else if let search = self.chatPresentationInterfaceState.search, self.alwaysShowSearchResultsAsList {
|
||||||
|
mappedContents = .search(query: search.query, includeSavedPeers: self.alwaysShowSearchResultsAsList)
|
||||||
} else {
|
} else {
|
||||||
mappedContents = .empty
|
mappedContents = .empty
|
||||||
}
|
}
|
||||||
@ -2494,6 +2509,34 @@ class ChatControllerNode: ASDisplayNode, UIScrollViewDelegate {
|
|||||||
return state.updatedDisplayHistoryFilterAsList(false)
|
return state.updatedDisplayHistoryFilterAsList(false)
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
peerSelected: { [weak self] peer in
|
||||||
|
guard let self else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
guard let navigationController = self.controller?.navigationController as? NavigationController else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
self.context.sharedContext.navigateToChatController(NavigateToChatControllerParams(
|
||||||
|
navigationController: navigationController,
|
||||||
|
context: self.context,
|
||||||
|
chatLocation: .replyThread(ChatReplyThreadMessage(
|
||||||
|
peerId: self.context.account.peerId,
|
||||||
|
threadId: peer.id.toInt64(),
|
||||||
|
channelMessageId: nil,
|
||||||
|
isChannelPost: false,
|
||||||
|
isForumPost: false,
|
||||||
|
maxMessage: nil,
|
||||||
|
maxReadIncomingMessageId: nil,
|
||||||
|
maxReadOutgoingMessageId: nil,
|
||||||
|
unreadCount: 0,
|
||||||
|
initialFilledHoles: IndexSet(),
|
||||||
|
initialAnchor: .automatic,
|
||||||
|
isNotAvailable: false
|
||||||
|
)),
|
||||||
|
subject: nil,
|
||||||
|
keepStack: .always
|
||||||
|
))
|
||||||
|
},
|
||||||
loadTagMessages: { tag, index in
|
loadTagMessages: { tag, index in
|
||||||
let input: ChatHistoryLocationInput
|
let input: ChatHistoryLocationInput
|
||||||
if let index {
|
if let index {
|
||||||
@ -2542,6 +2585,27 @@ class ChatControllerNode: ASDisplayNode, UIScrollViewDelegate {
|
|||||||
|> map { result in
|
|> map { result in
|
||||||
return result?.0
|
return result?.0
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
getSavedPeers: { [weak self] query in
|
||||||
|
guard let self else {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
let strings = self.chatPresentationInterfaceState.strings
|
||||||
|
let foundLocalPeers = context.engine.messages.searchLocalSavedMessagesPeers(query: query.lowercased(), indexNameMapping: [
|
||||||
|
context.account.peerId: [
|
||||||
|
PeerIndexNameRepresentation.title(title: strings.DialogList_MyNotes.lowercased(), addressNames: []),
|
||||||
|
PeerIndexNameRepresentation.title(title: "my notes".lowercased(), addressNames: [])
|
||||||
|
],
|
||||||
|
PeerId(namespace: Namespaces.Peer.CloudUser, id: PeerId.Id._internalFromInt64Value(2666000)): [
|
||||||
|
PeerIndexNameRepresentation.title(title: strings.ChatList_AuthorHidden.lowercased(), addressNames: [])
|
||||||
|
]
|
||||||
|
])
|
||||||
|
|> map { peers -> [(EnginePeer, MessageIndex?)] in
|
||||||
|
return peers.map { peer in
|
||||||
|
return (peer, nil)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return foundLocalPeers
|
||||||
}
|
}
|
||||||
)),
|
)),
|
||||||
environment: {},
|
environment: {},
|
||||||
@ -3375,6 +3439,15 @@ class ChatControllerNode: ASDisplayNode, UIScrollViewDelegate {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if let secondaryInputPanelNode = self.secondaryInputPanelNode, let viewForOverlayContent = secondaryInputPanelNode.viewForOverlayContent {
|
||||||
|
if let result = viewForOverlayContent.hitTest(self.view.convert(point, to: viewForOverlayContent), with: event) {
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
if maybeDismissOverlayContent {
|
||||||
|
viewForOverlayContent.maybeDismissContent(point: self.view.convert(point, to: viewForOverlayContent))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -37,8 +37,6 @@ func preloadedChatHistoryViewForLocation(_ location: ChatHistoryLocationInput, c
|
|||||||
}
|
}
|
||||||
|
|
||||||
func chatHistoryViewForLocation(_ location: ChatHistoryLocationInput, ignoreMessagesInTimestampRange: ClosedRange<Int32>?, context: AccountContext, chatLocation: ChatLocation, chatLocationContextHolder: Atomic<ChatLocationContextHolder?>, scheduled: Bool, fixedCombinedReadStates: MessageHistoryViewReadState?, tag: HistoryViewInputTag?, appendMessagesFromTheSameGroup: Bool, additionalData: [AdditionalMessageHistoryViewData], orderStatistics: MessageHistoryViewOrderStatistics = []) -> Signal<ChatHistoryViewUpdate, NoError> {
|
func chatHistoryViewForLocation(_ location: ChatHistoryLocationInput, ignoreMessagesInTimestampRange: ClosedRange<Int32>?, context: AccountContext, chatLocation: ChatLocation, chatLocationContextHolder: Atomic<ChatLocationContextHolder?>, scheduled: Bool, fixedCombinedReadStates: MessageHistoryViewReadState?, tag: HistoryViewInputTag?, appendMessagesFromTheSameGroup: Bool, additionalData: [AdditionalMessageHistoryViewData], orderStatistics: MessageHistoryViewOrderStatistics = []) -> Signal<ChatHistoryViewUpdate, NoError> {
|
||||||
print("request \(location.content)")
|
|
||||||
|
|
||||||
let account = context.account
|
let account = context.account
|
||||||
if scheduled {
|
if scheduled {
|
||||||
var first = true
|
var first = true
|
||||||
|
|||||||
@ -767,6 +767,8 @@ func contextMenuForChatPresentationInterfaceState(chatPresentationInterfaceState
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let isScheduled = chatPresentationInterfaceState.subject == .scheduledMessages
|
||||||
|
|
||||||
let dataSignal: Signal<(MessageContextMenuData, [MessageId: ChatUpdatingMessageMedia], InfoSummaryData, AppConfiguration, Bool, Int32, AvailableReactions?, TranslationSettings, LoggingSettings, NotificationSoundList?, EnginePeer?), NoError> = combineLatest(
|
let dataSignal: Signal<(MessageContextMenuData, [MessageId: ChatUpdatingMessageMedia], InfoSummaryData, AppConfiguration, Bool, Int32, AvailableReactions?, TranslationSettings, LoggingSettings, NotificationSoundList?, EnginePeer?), NoError> = combineLatest(
|
||||||
loadLimits,
|
loadLimits,
|
||||||
loadStickerSaveStatusSignal,
|
loadStickerSaveStatusSignal,
|
||||||
@ -804,6 +806,21 @@ func contextMenuForChatPresentationInterfaceState(chatPresentationInterfaceState
|
|||||||
loggingSettings = LoggingSettings.defaultSettings
|
loggingSettings = LoggingSettings.defaultSettings
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var messageActions = messageActions
|
||||||
|
if isEmbeddedMode {
|
||||||
|
messageActions = ChatAvailableMessageActions(
|
||||||
|
options: messageActions.options.intersection([.deleteLocally, .deleteGlobally, .forward]),
|
||||||
|
banAuthor: nil,
|
||||||
|
disableDelete: true,
|
||||||
|
isCopyProtected: messageActions.isCopyProtected,
|
||||||
|
setTag: false,
|
||||||
|
editTags: Set()
|
||||||
|
)
|
||||||
|
} else if isScheduled {
|
||||||
|
messageActions.setTag = false
|
||||||
|
messageActions.editTags = Set()
|
||||||
|
}
|
||||||
|
|
||||||
return (MessageContextMenuData(
|
return (MessageContextMenuData(
|
||||||
starStatus: stickerSaveStatus,
|
starStatus: stickerSaveStatus,
|
||||||
canReply: canReply && !isEmbeddedMode,
|
canReply: canReply && !isEmbeddedMode,
|
||||||
@ -811,14 +828,7 @@ func contextMenuForChatPresentationInterfaceState(chatPresentationInterfaceState
|
|||||||
canEdit: canEdit && !isEmbeddedMode,
|
canEdit: canEdit && !isEmbeddedMode,
|
||||||
canSelect: canSelect && !isEmbeddedMode,
|
canSelect: canSelect && !isEmbeddedMode,
|
||||||
resourceStatus: resourceStatus,
|
resourceStatus: resourceStatus,
|
||||||
messageActions: isEmbeddedMode ? ChatAvailableMessageActions(
|
messageActions: messageActions
|
||||||
options: messageActions.options.intersection([.deleteLocally, .deleteGlobally, .forward]),
|
|
||||||
banAuthor: nil,
|
|
||||||
disableDelete: true,
|
|
||||||
isCopyProtected: messageActions.isCopyProtected,
|
|
||||||
setTag: false,
|
|
||||||
editTags: Set()
|
|
||||||
) : messageActions
|
|
||||||
), updatingMessageMedia, infoSummaryData, appConfig, isMessageRead, messageViewsPrivacyTips, availableReactions, translationSettings, loggingSettings, notificationSoundList, accountPeer)
|
), updatingMessageMedia, infoSummaryData, appConfig, isMessageRead, messageViewsPrivacyTips, availableReactions, translationSettings, loggingSettings, notificationSoundList, accountPeer)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -590,20 +590,7 @@ final class ChatSearchTitleAccessoryPanelNode: ChatTitleAccessoryPanelNode, Chat
|
|||||||
guard let self, let interfaceInteraction = self.interfaceInteraction else {
|
guard let self, let interfaceInteraction = self.interfaceInteraction else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
//TODO:localize
|
(interfaceInteraction.chatController() as? ChatControllerImpl)?.presentTagPremiumPaywall()
|
||||||
var replaceImpl: ((ViewController) -> Void)?
|
|
||||||
let controller = self.context.sharedContext.makePremiumDemoController(context: self.context, subject: .uniqueReactions, action: { [weak self] in
|
|
||||||
guard let self else {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
let controller = self.context.sharedContext.makePremiumIntroController(context: self.context, source: .settings, forceDark: false, dismissed: nil)
|
|
||||||
replaceImpl?(controller)
|
|
||||||
})
|
|
||||||
replaceImpl = { [weak controller] c in
|
|
||||||
controller?.replace(with: c)
|
|
||||||
}
|
|
||||||
interfaceInteraction.chatController()?.push(controller)
|
|
||||||
})
|
})
|
||||||
self.promoView = promoView
|
self.promoView = promoView
|
||||||
self.scrollView.addSubview(promoView)
|
self.scrollView.addSubview(promoView)
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user