mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-12-01 04:08:07 +00:00
Merge branch 'master' of gitlab.com:peter-iakovlev/telegram-ios
This commit is contained in:
commit
c322ac539d
@ -97,13 +97,15 @@ public enum ChatListItemContent {
|
|||||||
public var messageCount: Int?
|
public var messageCount: Int?
|
||||||
public var hideSeparator: Bool
|
public var hideSeparator: Bool
|
||||||
public var hideDate: Bool
|
public var hideDate: Bool
|
||||||
|
public var hidePeerStatus: Bool
|
||||||
|
|
||||||
public init(commandPrefix: String?, searchQuery: String?, messageCount: Int?, hideSeparator: Bool, hideDate: Bool) {
|
public init(commandPrefix: String?, searchQuery: String?, messageCount: Int?, hideSeparator: Bool, hideDate: Bool, hidePeerStatus: Bool) {
|
||||||
self.commandPrefix = commandPrefix
|
self.commandPrefix = commandPrefix
|
||||||
self.searchQuery = searchQuery
|
self.searchQuery = searchQuery
|
||||||
self.messageCount = messageCount
|
self.messageCount = messageCount
|
||||||
self.hideSeparator = hideSeparator
|
self.hideSeparator = hideSeparator
|
||||||
self.hideDate = hideDate
|
self.hideDate = hideDate
|
||||||
|
self.hidePeerStatus = hidePeerStatus
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2340,7 +2342,7 @@ public class ChatListItemNode: ItemListRevealOptionsItemNode {
|
|||||||
|
|
||||||
attributedText = foldLineBreaks(draftText)
|
attributedText = foldLineBreaks(draftText)
|
||||||
}
|
}
|
||||||
} else if let message = messages.first {
|
} else if let message = messages.last {
|
||||||
var composedString: NSMutableAttributedString
|
var composedString: NSMutableAttributedString
|
||||||
|
|
||||||
if let peerText = peerText {
|
if let peerText = peerText {
|
||||||
@ -2942,7 +2944,7 @@ public class ChatListItemNode: ItemListRevealOptionsItemNode {
|
|||||||
break
|
break
|
||||||
}
|
}
|
||||||
} else if case let .chat(itemPeer) = contentPeer, let peer = itemPeer.chatMainPeer {
|
} else if case let .chat(itemPeer) = contentPeer, let peer = itemPeer.chatMainPeer {
|
||||||
if case let .peer(peerData) = item.content, peerData.customMessageListData != nil {
|
if case let .peer(peerData) = item.content, peerData.customMessageListData?.hidePeerStatus == true {
|
||||||
currentCredibilityIconContent = nil
|
currentCredibilityIconContent = nil
|
||||||
} else if case .savedMessagesChats = item.chatListLocation, peer.id == item.context.account.peerId {
|
} else if case .savedMessagesChats = item.chatListLocation, peer.id == item.context.account.peerId {
|
||||||
currentCredibilityIconContent = nil
|
currentCredibilityIconContent = nil
|
||||||
|
|||||||
@ -1243,7 +1243,7 @@ public func selectivePrivacySettingsController(
|
|||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
let controller = selectivePrivacyPeersController(context: context, title: title, initialPeers: peerIds, initialEnableForPremium: stateValue.with({ $0 }).enableForPremium, displayPremiumCategory: displayPremiumCategory, updated: { updatedPeerIds, enableForPremium in
|
let controller = selectivePrivacyPeersController(context: context, title: title, initialPeers: peerIds, initialEnableForPremium: displayPremiumCategory && stateValue.with({ $0 }).enableForPremium, displayPremiumCategory: displayPremiumCategory, updated: { updatedPeerIds, enableForPremium in
|
||||||
updateState { state in
|
updateState { state in
|
||||||
if enable {
|
if enable {
|
||||||
switch target {
|
switch target {
|
||||||
|
|||||||
@ -764,6 +764,31 @@ private class AdMessagesHistoryContextImpl {
|
|||||||
}
|
}
|
||||||
let _ = signal.start()
|
let _ = signal.start()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func remove(opaqueId: Data) {
|
||||||
|
if var stateValue = self.stateValue {
|
||||||
|
if let index = stateValue.messages.firstIndex(where: { $0.adAttribute?.opaqueId == opaqueId }) {
|
||||||
|
stateValue.messages.remove(at: index)
|
||||||
|
self.stateValue = stateValue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let peerId = self.peerId
|
||||||
|
let _ = (self.account.postbox.transaction { transaction -> Void in
|
||||||
|
let key = ValueBoxKey(length: 8)
|
||||||
|
key.setInt64(0, value: peerId.toInt64())
|
||||||
|
let id = ItemCacheEntryId(collectionId: Namespaces.CachedItemCollection.cachedAdMessageStates, key: key)
|
||||||
|
guard var cachedState = transaction.retrieveItemCacheEntry(id: id)?.get(CachedState.self) else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if let index = cachedState.messages.firstIndex(where: { $0.opaqueId == opaqueId }) {
|
||||||
|
cachedState.messages.remove(at: index)
|
||||||
|
if let entry = CodableEntry(cachedState) {
|
||||||
|
transaction.putItemCacheEntry(id: id, entry: entry)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}).start()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public class AdMessagesHistoryContext {
|
public class AdMessagesHistoryContext {
|
||||||
@ -803,4 +828,10 @@ public class AdMessagesHistoryContext {
|
|||||||
impl.markAction(opaqueId: opaqueId)
|
impl.markAction(opaqueId: opaqueId)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public func remove(opaqueId: Data) {
|
||||||
|
self.impl.with { impl in
|
||||||
|
impl.remove(opaqueId: opaqueId)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -180,7 +180,7 @@ public final class ChatEmptyNodeGreetingChatContent: ASDisplayNode, ChatEmptyNod
|
|||||||
let previousCustomStickerFile = self.currentCustomStickerFile
|
let previousCustomStickerFile = self.currentCustomStickerFile
|
||||||
self.currentCustomStickerFile = customStickerFile
|
self.currentCustomStickerFile = customStickerFile
|
||||||
|
|
||||||
let stickerSize: CGSize
|
var stickerSize: CGSize
|
||||||
let inset: CGFloat
|
let inset: CGFloat
|
||||||
if size.width == 320.0 {
|
if size.width == 320.0 {
|
||||||
stickerSize = CGSize(width: 106.0, height: 106.0)
|
stickerSize = CGSize(width: 106.0, height: 106.0)
|
||||||
@ -189,6 +189,11 @@ public final class ChatEmptyNodeGreetingChatContent: ASDisplayNode, ChatEmptyNod
|
|||||||
stickerSize = CGSize(width: 160.0, height: 160.0)
|
stickerSize = CGSize(width: 160.0, height: 160.0)
|
||||||
inset = 15.0
|
inset = 15.0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if let customStickerFile, let dimensions = customStickerFile.dimensions?.cgSize {
|
||||||
|
stickerSize = dimensions.aspectFitted(stickerSize)
|
||||||
|
}
|
||||||
|
|
||||||
if let item = self.stickerItem, previousCustomStickerFile == customStickerFile {
|
if let item = self.stickerItem, previousCustomStickerFile == customStickerFile {
|
||||||
self.stickerNode.updateLayout(item: item, size: stickerSize, isVisible: true, synchronousLoads: true)
|
self.stickerNode.updateLayout(item: item, size: stickerSize, isVisible: true, synchronousLoads: true)
|
||||||
} else if !self.didSetupSticker || previousCustomStickerFile != customStickerFile {
|
} else if !self.didSetupSticker || previousCustomStickerFile != customStickerFile {
|
||||||
|
|||||||
@ -588,7 +588,8 @@ private final class PeerInfoScreenPersonalChannelItemNode: PeerInfoScreenItemNod
|
|||||||
searchQuery: nil,
|
searchQuery: nil,
|
||||||
messageCount: nil,
|
messageCount: nil,
|
||||||
hideSeparator: true,
|
hideSeparator: true,
|
||||||
hideDate: isLoading
|
hideDate: isLoading,
|
||||||
|
hidePeerStatus: false
|
||||||
)
|
)
|
||||||
)),
|
)),
|
||||||
editing: false,
|
editing: false,
|
||||||
|
|||||||
@ -242,7 +242,8 @@ final class GreetingMessageListItemComponent: Component {
|
|||||||
searchQuery: nil,
|
searchQuery: nil,
|
||||||
messageCount: component.count,
|
messageCount: component.count,
|
||||||
hideSeparator: true,
|
hideSeparator: true,
|
||||||
hideDate: true
|
hideDate: true,
|
||||||
|
hidePeerStatus: true
|
||||||
)
|
)
|
||||||
)),
|
)),
|
||||||
editing: false,
|
editing: false,
|
||||||
|
|||||||
@ -272,7 +272,8 @@ final class QuickReplySetupScreenComponent: Component {
|
|||||||
searchQuery: nil,
|
searchQuery: nil,
|
||||||
messageCount: item.totalCount,
|
messageCount: item.totalCount,
|
||||||
hideSeparator: false,
|
hideSeparator: false,
|
||||||
hideDate: true
|
hideDate: true,
|
||||||
|
hidePeerStatus: true
|
||||||
)
|
)
|
||||||
)),
|
)),
|
||||||
editing: isEditing,
|
editing: isEditing,
|
||||||
|
|||||||
@ -294,7 +294,7 @@ final class BusinessIntroSetupScreenComponent: Component {
|
|||||||
if !self.isUpdating {
|
if !self.isUpdating {
|
||||||
self.state?.updated(transition: .immediate)
|
self.state?.updated(transition: .immediate)
|
||||||
}
|
}
|
||||||
case let .text(rawQuery, _):
|
case let .text(rawQuery, languageCode):
|
||||||
let query = rawQuery.trimmingCharacters(in: .whitespacesAndNewlines)
|
let query = rawQuery.trimmingCharacters(in: .whitespacesAndNewlines)
|
||||||
|
|
||||||
if query.isEmpty {
|
if query.isEmpty {
|
||||||
@ -304,7 +304,7 @@ final class BusinessIntroSetupScreenComponent: Component {
|
|||||||
} else {
|
} else {
|
||||||
let context = component.context
|
let context = component.context
|
||||||
|
|
||||||
let localSets = context.engine.stickers.searchStickerSets(query: query)
|
/*let localSets = context.engine.stickers.searchStickerSets(query: query)
|
||||||
let remoteSets: Signal<FoundStickerSets?, NoError> = .single(nil) |> then(
|
let remoteSets: Signal<FoundStickerSets?, NoError> = .single(nil) |> then(
|
||||||
context.engine.stickers.searchStickerSetsRemotely(query: query)
|
context.engine.stickers.searchStickerSetsRemotely(query: query)
|
||||||
|> map(Optional.init)
|
|> map(Optional.init)
|
||||||
@ -349,6 +349,199 @@ final class BusinessIntroSetupScreenComponent: Component {
|
|||||||
items.append(item)
|
items.append(item)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return .single([EmojiPagerContentComponent.ItemGroup(
|
||||||
|
supergroupId: "search",
|
||||||
|
groupId: "search",
|
||||||
|
title: nil,
|
||||||
|
subtitle: nil,
|
||||||
|
badge: nil,
|
||||||
|
actionButtonTitle: nil,
|
||||||
|
isFeatured: false,
|
||||||
|
isPremiumLocked: false,
|
||||||
|
isEmbedded: false,
|
||||||
|
hasClear: false,
|
||||||
|
hasEdit: false,
|
||||||
|
collapsedLineCount: nil,
|
||||||
|
displayPremiumBadges: false,
|
||||||
|
headerItem: nil,
|
||||||
|
fillWithLoadingPlaceholders: false,
|
||||||
|
items: items
|
||||||
|
)])
|
||||||
|
}*/
|
||||||
|
|
||||||
|
let stickers: Signal<[(String?, FoundStickerItem)], NoError> = Signal { subscriber in
|
||||||
|
var signals: Signal<[Signal<(String?, [FoundStickerItem]), NoError>], NoError> = .single([])
|
||||||
|
|
||||||
|
if query.isSingleEmoji {
|
||||||
|
signals = .single([context.engine.stickers.searchStickers(query: [query.basicEmoji.0])
|
||||||
|
|> map { (nil, $0.items) }])
|
||||||
|
} else if query.count > 1, !languageCode.isEmpty && languageCode != "emoji" {
|
||||||
|
var signal = context.engine.stickers.searchEmojiKeywords(inputLanguageCode: languageCode, query: query.lowercased(), completeMatch: query.count < 3)
|
||||||
|
if !languageCode.lowercased().hasPrefix("en") {
|
||||||
|
signal = signal
|
||||||
|
|> mapToSignal { keywords in
|
||||||
|
return .single(keywords)
|
||||||
|
|> then(
|
||||||
|
context.engine.stickers.searchEmojiKeywords(inputLanguageCode: "en-US", query: query.lowercased(), completeMatch: query.count < 3)
|
||||||
|
|> map { englishKeywords in
|
||||||
|
return keywords + englishKeywords
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
signals = signal
|
||||||
|
|> map { keywords -> [Signal<(String?, [FoundStickerItem]), NoError>] in
|
||||||
|
var signals: [Signal<(String?, [FoundStickerItem]), NoError>] = []
|
||||||
|
let emoticons = keywords.flatMap { $0.emoticons }
|
||||||
|
for emoji in emoticons {
|
||||||
|
signals.append(context.engine.stickers.searchStickers(query: [emoji.basicEmoji.0])
|
||||||
|
|> take(1)
|
||||||
|
|> map { (emoji, $0.items) })
|
||||||
|
}
|
||||||
|
return signals
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return (signals
|
||||||
|
|> mapToSignal { signals in
|
||||||
|
return combineLatest(signals)
|
||||||
|
}).start(next: { results in
|
||||||
|
var result: [(String?, FoundStickerItem)] = []
|
||||||
|
for (emoji, stickers) in results {
|
||||||
|
for sticker in stickers {
|
||||||
|
result.append((emoji, sticker))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
subscriber.putNext(result)
|
||||||
|
}, completed: {
|
||||||
|
subscriber.putCompletion()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
let currentRemotePacks = Atomic<FoundStickerSets?>(value: nil)
|
||||||
|
|
||||||
|
let local = context.engine.stickers.searchStickerSets(query: query)
|
||||||
|
let remote = context.engine.stickers.searchStickerSetsRemotely(query: query)
|
||||||
|
|> delay(0.2, queue: Queue.mainQueue())
|
||||||
|
let rawPacks = local
|
||||||
|
|> mapToSignal { result -> Signal<(FoundStickerSets, Bool, FoundStickerSets?), NoError> in
|
||||||
|
var localResult = result
|
||||||
|
if let currentRemote = currentRemotePacks.with ({ $0 }) {
|
||||||
|
localResult = localResult.merge(with: currentRemote)
|
||||||
|
}
|
||||||
|
return .single((localResult, false, nil))
|
||||||
|
|> then(
|
||||||
|
remote
|
||||||
|
|> map { remote -> (FoundStickerSets, Bool, FoundStickerSets?) in
|
||||||
|
return (result.merge(with: remote), true, remote)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
let installedPackIds = context.account.postbox.combinedView(keys: [.itemCollectionInfos(namespaces: [Namespaces.ItemCollection.CloudStickerPacks])])
|
||||||
|
|> map { view -> Set<ItemCollectionId> in
|
||||||
|
var installedPacks = Set<ItemCollectionId>()
|
||||||
|
if let stickerPacksView = view.views[.itemCollectionInfos(namespaces: [Namespaces.ItemCollection.CloudStickerPacks])] as? ItemCollectionInfosView {
|
||||||
|
if let packsEntries = stickerPacksView.entriesByNamespace[Namespaces.ItemCollection.CloudStickerPacks] {
|
||||||
|
for entry in packsEntries {
|
||||||
|
installedPacks.insert(entry.id)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return installedPacks
|
||||||
|
}
|
||||||
|
|> distinctUntilChanged
|
||||||
|
let packs = combineLatest(rawPacks, installedPackIds)
|
||||||
|
|> map { packs, installedPackIds -> (FoundStickerSets, Bool, FoundStickerSets?) in
|
||||||
|
var (localPacks, completed, remotePacks) = packs
|
||||||
|
|
||||||
|
for i in 0 ..< localPacks.infos.count {
|
||||||
|
let installed = installedPackIds.contains(localPacks.infos[i].0)
|
||||||
|
if installed != localPacks.infos[i].3 {
|
||||||
|
localPacks.infos[i].3 = installed
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if remotePacks != nil {
|
||||||
|
for i in 0 ..< remotePacks!.infos.count {
|
||||||
|
let installed = installedPackIds.contains(remotePacks!.infos[i].0)
|
||||||
|
if installed != remotePacks!.infos[i].3 {
|
||||||
|
remotePacks!.infos[i].3 = installed
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return (localPacks, completed, remotePacks)
|
||||||
|
}
|
||||||
|
|
||||||
|
let signal = combineLatest(stickers, packs)
|
||||||
|
|> map { stickers, packs -> ([(String?, FoundStickerItem)], FoundStickerSets, Bool, FoundStickerSets?)? in
|
||||||
|
return (stickers, packs.0, packs.1, packs.2)
|
||||||
|
}
|
||||||
|
|
||||||
|
let resultSignal: Signal<[EmojiPagerContentComponent.ItemGroup], NoError> = signal
|
||||||
|
|> mapToSignal { result in
|
||||||
|
guard let result else {
|
||||||
|
return .complete()
|
||||||
|
}
|
||||||
|
|
||||||
|
let (foundItems, localSets, complete, remoteSets) = result
|
||||||
|
|
||||||
|
var items: [EmojiPagerContentComponent.Item] = []
|
||||||
|
|
||||||
|
var existingIds = Set<MediaId>()
|
||||||
|
for (_, entry) in foundItems {
|
||||||
|
let itemFile = entry.file
|
||||||
|
|
||||||
|
if existingIds.contains(itemFile.fileId) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
existingIds.insert(itemFile.fileId)
|
||||||
|
|
||||||
|
let animationData = EntityKeyboardAnimationData(file: itemFile)
|
||||||
|
let item = EmojiPagerContentComponent.Item(
|
||||||
|
animationData: animationData,
|
||||||
|
content: .animation(animationData),
|
||||||
|
itemFile: itemFile,
|
||||||
|
subgroupId: nil,
|
||||||
|
icon: .none,
|
||||||
|
tintMode: animationData.isTemplate ? .primary : .none
|
||||||
|
)
|
||||||
|
items.append(item)
|
||||||
|
}
|
||||||
|
|
||||||
|
var mergedSets = localSets
|
||||||
|
if let remoteSets {
|
||||||
|
mergedSets = mergedSets.merge(with: remoteSets)
|
||||||
|
}
|
||||||
|
for entry in mergedSets.entries {
|
||||||
|
guard let stickerPackItem = entry.item as? StickerPackItem else {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
let itemFile = stickerPackItem.file
|
||||||
|
|
||||||
|
if existingIds.contains(itemFile.fileId) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
existingIds.insert(itemFile.fileId)
|
||||||
|
|
||||||
|
let animationData = EntityKeyboardAnimationData(file: itemFile)
|
||||||
|
let item = EmojiPagerContentComponent.Item(
|
||||||
|
animationData: animationData,
|
||||||
|
content: .animation(animationData),
|
||||||
|
itemFile: itemFile,
|
||||||
|
subgroupId: nil,
|
||||||
|
icon: .none,
|
||||||
|
tintMode: animationData.isTemplate ? .primary : .none
|
||||||
|
)
|
||||||
|
items.append(item)
|
||||||
|
}
|
||||||
|
|
||||||
|
if items.isEmpty && !complete {
|
||||||
|
return .complete()
|
||||||
|
}
|
||||||
|
|
||||||
return .single([EmojiPagerContentComponent.ItemGroup(
|
return .single([EmojiPagerContentComponent.ItemGroup(
|
||||||
supergroupId: "search",
|
supergroupId: "search",
|
||||||
groupId: "search",
|
groupId: "search",
|
||||||
@ -825,7 +1018,7 @@ final class BusinessIntroSetupScreenComponent: Component {
|
|||||||
var stickerSearchResults: EmojiPagerContentComponent.EmptySearchResults?
|
var stickerSearchResults: EmojiPagerContentComponent.EmptySearchResults?
|
||||||
if !stickerSearchResult.groups.contains(where: { !$0.items.isEmpty || $0.fillWithLoadingPlaceholders }) {
|
if !stickerSearchResult.groups.contains(where: { !$0.items.isEmpty || $0.fillWithLoadingPlaceholders }) {
|
||||||
stickerSearchResults = EmojiPagerContentComponent.EmptySearchResults(
|
stickerSearchResults = EmojiPagerContentComponent.EmptySearchResults(
|
||||||
text: environment.strings.EmojiSearch_SearchStickersEmptyResult,
|
text: "No stickers found",
|
||||||
iconFile: nil
|
iconFile: nil
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -8459,6 +8459,14 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
|||||||
customChatContents.enqueueMessages(messages: messages)
|
customChatContents.enqueueMessages(messages: messages)
|
||||||
strongSelf.chatDisplayNode.historyNode.scrollToEndOfHistory()
|
strongSelf.chatDisplayNode.historyNode.scrollToEndOfHistory()
|
||||||
case let .businessLinkSetup(link):
|
case let .businessLinkSetup(link):
|
||||||
|
if messages.count > 1 {
|
||||||
|
strongSelf.present(standardTextAlertController(theme: AlertControllerTheme(presentationData: strongSelf.presentationData), title: nil, text: "The message text limit is 4096 characters", actions: [
|
||||||
|
TextAlertAction(type: .defaultAction, title: strongSelf.presentationData.strings.Common_OK, action: {})
|
||||||
|
]), in: .window(.root))
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
var text: String = ""
|
var text: String = ""
|
||||||
var entities: [MessageTextEntity] = []
|
var entities: [MessageTextEntity] = []
|
||||||
if let message = messages.first {
|
if let message = messages.first {
|
||||||
|
|||||||
25
submodules/TelegramUI/Sources/ChatControllerRemoveAd.swift
Normal file
25
submodules/TelegramUI/Sources/ChatControllerRemoveAd.swift
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
import Foundation
|
||||||
|
import TelegramPresentationData
|
||||||
|
import AccountContext
|
||||||
|
import Postbox
|
||||||
|
import TelegramCore
|
||||||
|
import SwiftSignalKit
|
||||||
|
import Display
|
||||||
|
import TelegramPresentationData
|
||||||
|
import PresentationDataUtils
|
||||||
|
import ChatMessageItemView
|
||||||
|
|
||||||
|
extension ChatControllerImpl {
|
||||||
|
func removeAd(opaqueId: Data) {
|
||||||
|
var foundItemNode: ChatMessageItemView?
|
||||||
|
self.chatDisplayNode.historyNode.forEachItemNode { itemNode in
|
||||||
|
if let itemNode = itemNode as? ChatMessageItemView, let item = itemNode.item, let adAttribute = item.message.adAttribute, adAttribute.opaqueId == opaqueId {
|
||||||
|
foundItemNode = itemNode
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if let foundItemNode, let message = foundItemNode.item?.message {
|
||||||
|
self.chatDisplayNode.historyNode.setCurrentDeleteAnimationCorrelationIds(Set([message.stableId]))
|
||||||
|
}
|
||||||
|
self.chatDisplayNode.historyNode.adMessagesContext?.remove(opaqueId: opaqueId)
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -499,8 +499,14 @@ func contextMenuForChatPresentationInterfaceState(chatPresentationInterfaceState
|
|||||||
opaqueId: adAttribute.opaqueId,
|
opaqueId: adAttribute.opaqueId,
|
||||||
title: title,
|
title: title,
|
||||||
options: options,
|
options: options,
|
||||||
completed: {
|
completed: { [weak interfaceInteraction] in
|
||||||
|
guard let interfaceInteraction else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
guard let chatController = interfaceInteraction.chatController() as? ChatControllerImpl else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
chatController.removeAd(opaqueId: adAttribute.opaqueId)
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|||||||
@ -3321,7 +3321,16 @@ class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDelegate, Ch
|
|||||||
}
|
}
|
||||||
|
|
||||||
private func updateCounterTextNode(transition: ContainedViewLayoutTransition) {
|
private func updateCounterTextNode(transition: ContainedViewLayoutTransition) {
|
||||||
if let textInputNode = self.textInputNode, let presentationInterfaceState = self.presentationInterfaceState, let editMessage = presentationInterfaceState.interfaceState.editMessage, let inputTextMaxLength = editMessage.inputTextMaxLength {
|
var inputTextMaxLength: Int32?
|
||||||
|
if let presentationInterfaceState = self.presentationInterfaceState {
|
||||||
|
if let editMessage = presentationInterfaceState.interfaceState.editMessage, let inputTextMaxLengthValue = editMessage.inputTextMaxLength {
|
||||||
|
inputTextMaxLength = inputTextMaxLengthValue
|
||||||
|
} else if case let .customChatContents(customChatContents) = presentationInterfaceState.subject, case .businessLinkSetup = customChatContents.kind {
|
||||||
|
inputTextMaxLength = 4096
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if let presentationInterfaceState = self.presentationInterfaceState, let textInputNode = self.textInputNode, let inputTextMaxLength {
|
||||||
let textCount = Int32(textInputNode.textView.text.count)
|
let textCount = Int32(textInputNode.textView.text.count)
|
||||||
let counterColor: UIColor = textCount > inputTextMaxLength ? presentationInterfaceState.theme.chat.inputPanel.panelControlDestructiveColor : presentationInterfaceState.theme.chat.inputPanel.panelControlColor
|
let counterColor: UIColor = textCount > inputTextMaxLength ? presentationInterfaceState.theme.chat.inputPanel.panelControlDestructiveColor : presentationInterfaceState.theme.chat.inputPanel.panelControlColor
|
||||||
|
|
||||||
|
|||||||
@ -227,7 +227,8 @@ private struct CommandChatInputContextPanelEntry: Comparable, Identifiable {
|
|||||||
searchQuery: command.searchQuery.flatMap { "/\($0)"},
|
searchQuery: command.searchQuery.flatMap { "/\($0)"},
|
||||||
messageCount: shortcut.totalCount,
|
messageCount: shortcut.totalCount,
|
||||||
hideSeparator: false,
|
hideSeparator: false,
|
||||||
hideDate: true
|
hideDate: true,
|
||||||
|
hidePeerStatus: true
|
||||||
)
|
)
|
||||||
)),
|
)),
|
||||||
editing: false,
|
editing: false,
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user