Cherry pick more fixes

This commit is contained in:
Ilya Laktyushin 2023-04-26 18:49:13 +04:00
parent 5126be83b3
commit b8cd4b5b61
14 changed files with 435 additions and 377 deletions

View File

@ -523,6 +523,23 @@ private final class CachedChatListSearchResult {
} }
} }
private final class CachedCustomTextEntities {
let text: String
let textEntities: [MessageTextEntity]
init(text: String, textEntities: [MessageTextEntity]) {
self.text = text
self.textEntities = textEntities
}
func matches(text: String) -> Bool {
if self.text != text {
return false
}
return true
}
}
private let playIconImage = UIImage(bundleImageName: "Chat List/MiniThumbnailPlay")?.precomposed() private let playIconImage = UIImage(bundleImageName: "Chat List/MiniThumbnailPlay")?.precomposed()
private final class ChatListMediaPreviewNode: ASDisplayNode { private final class ChatListMediaPreviewNode: ASDisplayNode {
@ -611,6 +628,8 @@ private final class ChatListMediaPreviewNode: ASDisplayNode {
} }
} }
private let loginCodeRegex = try? NSRegularExpression(pattern: "[\\d\\-]{5,7}", options: [])
class ChatListItemNode: ItemListRevealOptionsItemNode { class ChatListItemNode: ItemListRevealOptionsItemNode {
final class TopicItemNode: ASDisplayNode { final class TopicItemNode: ASDisplayNode {
let topicTitleNode: TextNode let topicTitleNode: TextNode
@ -924,6 +943,7 @@ class ChatListItemNode: ItemListRevealOptionsItemNode {
private var cachedChatListText: (String, String)? private var cachedChatListText: (String, String)?
private var cachedChatListSearchResult: CachedChatListSearchResult? private var cachedChatListSearchResult: CachedChatListSearchResult?
private var cachedCustomTextEntities: CachedCustomTextEntities?
var layoutParams: (ChatListItem, first: Bool, last: Bool, firstWithHeader: Bool, nextIsPinned: Bool, ListViewItemLayoutParams, countersSize: CGFloat)? var layoutParams: (ChatListItem, first: Bool, last: Bool, firstWithHeader: Bool, nextIsPinned: Bool, ListViewItemLayoutParams, countersSize: CGFloat)?
@ -1492,6 +1512,7 @@ class ChatListItemNode: ItemListRevealOptionsItemNode {
let currentItem = self.layoutParams?.0 let currentItem = self.layoutParams?.0
let currentChatListText = self.cachedChatListText let currentChatListText = self.cachedChatListText
let currentChatListSearchResult = self.cachedChatListSearchResult let currentChatListSearchResult = self.cachedChatListSearchResult
let currentCustomTextEntities = self.cachedCustomTextEntities
return { item, params, first, last, firstWithHeader, nextIsPinned in return { item, params, first, last, firstWithHeader, nextIsPinned in
let titleFont = Font.medium(floor(item.presentationData.fontSize.itemListBaseFontSize * 16.0 / 17.0)) let titleFont = Font.medium(floor(item.presentationData.fontSize.itemListBaseFontSize * 16.0 / 17.0))
@ -1769,6 +1790,7 @@ class ChatListItemNode: ItemListRevealOptionsItemNode {
var chatListText: (String, String)? var chatListText: (String, String)?
var chatListSearchResult: CachedChatListSearchResult? var chatListSearchResult: CachedChatListSearchResult?
var customTextEntities: CachedCustomTextEntities?
let contentImageSide: CGFloat = max(10.0, min(20.0, floor(item.presentationData.fontSize.baseDisplaySize * 18.0 / 17.0))) let contentImageSide: CGFloat = max(10.0, min(20.0, floor(item.presentationData.fontSize.baseDisplaySize * 18.0 / 17.0)))
let contentImageSize = CGSize(width: contentImageSide, height: contentImageSide) let contentImageSize = CGSize(width: contentImageSide, height: contentImageSide)
@ -1841,7 +1863,7 @@ class ChatListItemNode: ItemListRevealOptionsItemNode {
authorAttributedString = NSAttributedString(string: peerText, font: textFont, textColor: theme.authorNameColor) authorAttributedString = NSAttributedString(string: peerText, font: textFont, textColor: theme.authorNameColor)
} }
let entities = (message._asMessage().textEntitiesAttribute?.entities ?? []).filter { entity in var entities = (message._asMessage().textEntitiesAttribute?.entities ?? []).filter { entity in
switch entity.type { switch entity.type {
case .Spoiler, .CustomEmoji: case .Spoiler, .CustomEmoji:
return true return true
@ -1851,6 +1873,23 @@ class ChatListItemNode: ItemListRevealOptionsItemNode {
return false return false
} }
} }
if message.id.peerId.namespace == Namespaces.Peer.CloudUser && message.id.peerId.id._internalGetInt64Value() == 777000 {
if let cached = currentCustomTextEntities, cached.matches(text: message.text) {
customTextEntities = cached
} else if let matches = loginCodeRegex?.matches(in: message.text, options: [], range: NSMakeRange(0, (message.text as NSString).length)) {
var entities: [MessageTextEntity] = []
if let first = matches.first {
entities.append(MessageTextEntity(range: first.range.location ..< first.range.location + first.range.length, type: .Spoiler))
}
customTextEntities = CachedCustomTextEntities(text: message.text, textEntities: entities)
}
}
if let customTextEntities, !customTextEntities.textEntities.isEmpty {
entities.append(contentsOf: customTextEntities.textEntities)
}
let messageString: NSAttributedString let messageString: NSAttributedString
if !message.text.isEmpty && entities.count > 0 { if !message.text.isEmpty && entities.count > 0 {
var messageText = message.text var messageText = message.text
@ -2560,6 +2599,7 @@ class ChatListItemNode: ItemListRevealOptionsItemNode {
strongSelf.currentItemHeight = itemHeight strongSelf.currentItemHeight = itemHeight
strongSelf.cachedChatListText = chatListText strongSelf.cachedChatListText = chatListText
strongSelf.cachedChatListSearchResult = chatListSearchResult strongSelf.cachedChatListSearchResult = chatListSearchResult
strongSelf.cachedCustomTextEntities = customTextEntities
strongSelf.onlineIsVoiceChat = onlineIsVoiceChat strongSelf.onlineIsVoiceChat = onlineIsVoiceChat
var animateOnline = animateOnline var animateOnline = animateOnline

View File

@ -476,9 +476,19 @@ public class CheckLayer: CALayer {
context.strokePath() context.strokePath()
case let .counter(number): case let .counter(number):
let text = NSAttributedString(string: "\(number)", font: Font.with(size: 16.0, design: .round, weight: .regular, traits: []), textColor: parameters.theme.strokeColor.withMultipliedAlpha(parameters.animationProgress)) let fontSize: CGFloat
let string = "\(number)"
switch string.count {
case 1:
fontSize = 16.0
case 2:
fontSize = 15.0
default:
fontSize = 13.0
}
let text = NSAttributedString(string: string, font: Font.with(size: fontSize, design: .round, weight: .medium, traits: []), textColor: parameters.theme.strokeColor.withMultipliedAlpha(parameters.animationProgress))
let textRect = text.boundingRect(with: CGSize(width: 100.0, height: 100.0), options: [.usesLineFragmentOrigin], context: nil) let textRect = text.boundingRect(with: CGSize(width: 100.0, height: 100.0), options: [.usesLineFragmentOrigin], context: nil)
text.draw(at: CGPoint(x: UIScreenPixel + textRect.minX + floor((size.width - textRect.width) * 0.5), y: textRect.minY + floor((size.height - textRect.height) * 0.5))) text.draw(at: CGPoint(x: textRect.minX + floorToScreenPixels((size.width - textRect.width) * 0.5), y: textRect.minY + floorToScreenPixels((size.height - textRect.height) * 0.5)))
} }
} }
} }

View File

@ -82,26 +82,27 @@ extension UIImage.Orientation {
} }
} }
private let fetchPhotoWorkers = ThreadPool(threadCount: 3, threadPriority: 0.2)
public func fetchPhotoLibraryResource(localIdentifier: String) -> Signal<MediaResourceDataFetchResult, MediaResourceDataFetchError> { public func fetchPhotoLibraryResource(localIdentifier: String) -> Signal<MediaResourceDataFetchResult, MediaResourceDataFetchError> {
return Signal { subscriber in return Signal { subscriber in
let queue = ThreadPoolQueue(threadPool: fetchPhotoWorkers)
let fetchResult = PHAsset.fetchAssets(withLocalIdentifiers: [localIdentifier], options: nil) let fetchResult = PHAsset.fetchAssets(withLocalIdentifiers: [localIdentifier], options: nil)
let requestId = Atomic<RequestId>(value: RequestId()) let requestId = Atomic<RequestId>(value: RequestId())
if fetchResult.count != 0 { if fetchResult.count != 0 {
let asset = fetchResult.object(at: 0) let asset = fetchResult.object(at: 0)
let option = PHImageRequestOptions() let option = PHImageRequestOptions()
option.deliveryMode = .opportunistic option.deliveryMode = .highQualityFormat
option.isNetworkAccessAllowed = true option.isNetworkAccessAllowed = true
option.isSynchronous = false option.isSynchronous = false
let madeProgress = Atomic<Bool>(value: false)
option.progressHandler = { progress, error, _, _ in
if !madeProgress.swap(true) {
//subscriber.putNext(.reset)
}
}
let size = CGSize(width: 1280.0, height: 1280.0) let size = CGSize(width: 1280.0, height: 1280.0)
queue.addTask(ThreadPoolTask({ _ in
let startTime = CACurrentMediaTime() let startTime = CACurrentMediaTime()
let semaphore = DispatchSemaphore(value: 0)
let requestIdValue = PHImageManager.default().requestImage(for: asset, targetSize: PHImageManagerMaximumSize, contentMode: .aspectFit, options: option, resultHandler: { (image, info) -> Void in let requestIdValue = PHImageManager.default().requestImage(for: asset, targetSize: PHImageManagerMaximumSize, contentMode: .aspectFit, options: option, resultHandler: { (image, info) -> Void in
Queue.concurrentDefaultQueue().async { Queue.concurrentDefaultQueue().async {
requestId.with { current -> Void in requestId.with { current -> Void in
@ -112,38 +113,33 @@ public func fetchPhotoLibraryResource(localIdentifier: String) -> Signal<MediaRe
} }
if let image = image { if let image = image {
if let info = info, let degraded = info[PHImageResultIsDegradedKey], (degraded as AnyObject).boolValue!{ if let info = info, let degraded = info[PHImageResultIsDegradedKey], (degraded as AnyObject).boolValue!{
if !madeProgress.swap(true) {
//subscriber.putNext(.reset)
}
} else {
#if DEBUG
print("load completion \((CACurrentMediaTime() - startTime) * 1000.0) ms")
#endif
_ = madeProgress.swap(true) } else {
#if DEBUG
print("load completion \((CACurrentMediaTime() - startTime) * 1000.0) ms")
#endif
let scale = min(1.0, min(size.width / max(1.0, image.size.width), size.height / max(1.0, image.size.height))) let scale = min(1.0, min(size.width / max(1.0, image.size.width), size.height / max(1.0, image.size.height)))
let scaledSize = CGSize(width: floor(image.size.width * scale), height: floor(image.size.height * scale)) let scaledSize = CGSize(width: floor(image.size.width * scale), height: floor(image.size.height * scale))
let scaledImage = resizedImage(image, for: scaledSize) let scaledImage = resizedImage(image, for: scaledSize)
#if DEBUG #if DEBUG
print("scaled completion \((CACurrentMediaTime() - startTime) * 1000.0) ms") print("scaled completion \((CACurrentMediaTime() - startTime) * 1000.0) ms")
#endif #endif
if let scaledImage = scaledImage, let data = compressImageToJPEG(scaledImage, quality: 0.6) { if let scaledImage = scaledImage, let data = compressImageToJPEG(scaledImage, quality: 0.6) {
#if DEBUG #if DEBUG
print("compression completion \((CACurrentMediaTime() - startTime) * 1000.0) ms") print("compression completion \((CACurrentMediaTime() - startTime) * 1000.0) ms")
#endif #endif
subscriber.putNext(.dataPart(resourceOffset: 0, data: data, range: 0 ..< Int64(data.count), complete: true)) subscriber.putNext(.dataPart(resourceOffset: 0, data: data, range: 0 ..< Int64(data.count), complete: true))
subscriber.putCompletion() subscriber.putCompletion()
} else { } else {
subscriber.putCompletion() subscriber.putCompletion()
} }
semaphore.signal()
} }
} else { } else {
if !madeProgress.swap(true) { semaphore.signal()
//subscriber.putNext(.reset)
}
} }
} }
}) })
@ -152,6 +148,8 @@ public func fetchPhotoLibraryResource(localIdentifier: String) -> Signal<MediaRe
current.id = requestIdValue current.id = requestIdValue
} }
} }
semaphore.wait()
}))
} else { } else {
subscriber.putNext(.reset) subscriber.putNext(.reset)
} }

View File

@ -25,6 +25,7 @@ func assetImage(asset: PHAsset, targetSize: CGSize, exact: Bool, deliveryMode: P
options.resizeMode = .exact options.resizeMode = .exact
} }
options.isSynchronous = synchronous options.isSynchronous = synchronous
options.isNetworkAccessAllowed = true
let token = imageManager.requestImage(for: asset, targetSize: targetSize, contentMode: .aspectFill, options: options) { (image, info) in let token = imageManager.requestImage(for: asset, targetSize: targetSize, contentMode: .aspectFill, options: options) { (image, info) in
var degraded = false var degraded = false

View File

@ -1452,13 +1452,13 @@ public final class MediaPickerScreen: ViewController, AttachmentContainable {
} }
} }
selectionState.setItem(item, selected: value) let success = selectionState.setItem(item, selected: value)
if showUndo { if showUndo {
self.showSelectionUndo(item: item) self.showSelectionUndo(item: item)
} }
return true return success
} else { } else {
return false return false
} }

View File

@ -47,7 +47,7 @@ public final class QrCodeScreen: ViewController {
case let .invite(invite, _): case let .invite(invite, _):
return invite.link ?? "" return invite.link ?? ""
case let .chatFolder(slug): case let .chatFolder(slug):
return "https://t.me/list/\(slug)" return slug
} }
} }

View File

@ -95,6 +95,7 @@ public func universalServiceMessageString(presentationData: (PresentationTheme,
for media in message.media { for media in message.media {
if let action = media as? TelegramMediaAction { if let action = media as? TelegramMediaAction {
let authorName = message.author?.displayTitle(strings: strings, displayOrder: nameDisplayOrder) ?? "" let authorName = message.author?.displayTitle(strings: strings, displayOrder: nameDisplayOrder) ?? ""
let compactAuthorName = message.author?.compactDisplayTitle ?? ""
var isChannel = false var isChannel = false
if message.id.peerId.namespace == Namespaces.Peer.CloudChannel, let peer = message.peers[message.id.peerId] as? TelegramChannel, case .broadcast = peer.info { if message.id.peerId.namespace == Namespaces.Peer.CloudChannel, let peer = message.peers[message.id.peerId] as? TelegramChannel, case .broadcast = peer.info {
@ -695,7 +696,7 @@ public func universalServiceMessageString(presentationData: (PresentationTheme,
attributedString = NSAttributedString(string: strings.Notification_YouDisabledTheme, font: titleFont, textColor: primaryTextColor) attributedString = NSAttributedString(string: strings.Notification_YouDisabledTheme, font: titleFont, textColor: primaryTextColor)
} else { } else {
let attributePeerIds: [(Int, EnginePeer.Id?)] = [(0, message.author?.id)] let attributePeerIds: [(Int, EnginePeer.Id?)] = [(0, message.author?.id)]
let resultTitleString = strings.Notification_DisabledTheme(authorName) let resultTitleString = strings.Notification_DisabledTheme(compactAuthorName)
attributedString = addAttributesToStringWithRanges(resultTitleString._tuple, body: bodyAttributes, argumentAttributes: peerMentionsAttributes(primaryTextColor: primaryTextColor, peerIds: attributePeerIds)) attributedString = addAttributesToStringWithRanges(resultTitleString._tuple, body: bodyAttributes, argumentAttributes: peerMentionsAttributes(primaryTextColor: primaryTextColor, peerIds: attributePeerIds))
} }
} else { } else {
@ -704,7 +705,7 @@ public func universalServiceMessageString(presentationData: (PresentationTheme,
} else if message.author?.id == accountPeerId { } else if message.author?.id == accountPeerId {
attributedString = NSAttributedString(string: strings.Notification_YouChangedTheme(emoji).string, font: titleFont, textColor: primaryTextColor) attributedString = NSAttributedString(string: strings.Notification_YouChangedTheme(emoji).string, font: titleFont, textColor: primaryTextColor)
} else { } else {
let resultTitleString = strings.Notification_ChangedTheme(authorName, emoji) let resultTitleString = strings.Notification_ChangedTheme(compactAuthorName, emoji)
attributedString = addAttributesToStringWithRanges(resultTitleString._tuple, body: bodyAttributes, argumentAttributes: [0: boldAttributes]) attributedString = addAttributesToStringWithRanges(resultTitleString._tuple, body: bodyAttributes, argumentAttributes: [0: boldAttributes])
} }
} }
@ -717,7 +718,7 @@ public func universalServiceMessageString(presentationData: (PresentationTheme,
} else { } else {
var attributes = peerMentionsAttributes(primaryTextColor: primaryTextColor, peerIds: [(0, message.author?.id)]) var attributes = peerMentionsAttributes(primaryTextColor: primaryTextColor, peerIds: [(0, message.author?.id)])
attributes[1] = boldAttributes attributes[1] = boldAttributes
attributedString = addAttributesToStringWithRanges(strings.Notification_PremiumGift_Sent(authorName, price)._tuple, body: bodyAttributes, argumentAttributes: attributes) attributedString = addAttributesToStringWithRanges(strings.Notification_PremiumGift_Sent(compactAuthorName, price)._tuple, body: bodyAttributes, argumentAttributes: attributes)
} }
case let .topicCreated(title, iconColor, iconFileId): case let .topicCreated(title, iconColor, iconFileId):
if forForumOverview { if forForumOverview {
@ -877,14 +878,14 @@ public func universalServiceMessageString(presentationData: (PresentationTheme,
if message.author?.id == accountPeerId { if message.author?.id == accountPeerId {
attributedString = NSAttributedString(string: strings.Notification_YouChangedWallpaper, font: titleFont, textColor: primaryTextColor) attributedString = NSAttributedString(string: strings.Notification_YouChangedWallpaper, font: titleFont, textColor: primaryTextColor)
} else { } else {
let resultTitleString = strings.Notification_ChangedWallpaper(authorName) let resultTitleString = strings.Notification_ChangedWallpaper(compactAuthorName)
attributedString = addAttributesToStringWithRanges(resultTitleString._tuple, body: bodyAttributes, argumentAttributes: [0: boldAttributes]) attributedString = addAttributesToStringWithRanges(resultTitleString._tuple, body: bodyAttributes, argumentAttributes: [0: boldAttributes])
} }
case .setSameChatWallpaper: case .setSameChatWallpaper:
if message.author?.id == accountPeerId { if message.author?.id == accountPeerId {
attributedString = NSAttributedString(string: strings.Notification_YouChangedToSameWallpaper, font: titleFont, textColor: primaryTextColor) attributedString = NSAttributedString(string: strings.Notification_YouChangedToSameWallpaper, font: titleFont, textColor: primaryTextColor)
} else { } else {
let resultTitleString = strings.Notification_ChangedToSameWallpaper(authorName) let resultTitleString = strings.Notification_ChangedToSameWallpaper(compactAuthorName)
attributedString = addAttributesToStringWithRanges(resultTitleString._tuple, body: bodyAttributes, argumentAttributes: [0: boldAttributes]) attributedString = addAttributesToStringWithRanges(resultTitleString._tuple, body: bodyAttributes, argumentAttributes: [0: boldAttributes])
} }
case .unknown: case .unknown:

View File

@ -705,12 +705,19 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
} }
isLocation = true isLocation = true
} }
if let file = media as? TelegramMediaFile, file.isInstantVideo { if let file = media as? TelegramMediaFile {
if file.isInstantVideo {
if strongSelf.chatDisplayNode.isInputViewFocused { if strongSelf.chatDisplayNode.isInputViewFocused {
strongSelf.returnInputViewFocus = true strongSelf.returnInputViewFocus = true
strongSelf.chatDisplayNode.dismissInput() strongSelf.chatDisplayNode.dismissInput()
} }
} }
if file.isMusic || file.isVoice || file.isInstantVideo {
if !displayVoiceMessageDiscardAlert() {
return false
}
}
}
if let invoice = media as? TelegramMediaInvoice, let extendedMedia = invoice.extendedMedia { if let invoice = media as? TelegramMediaInvoice, let extendedMedia = invoice.extendedMedia {
switch extendedMedia { switch extendedMedia {
case .preview: case .preview:
@ -4294,7 +4301,11 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
} }
} }
let _ = (ApplicationSpecificNotice.getBotGameNotice(accountManager: strongSelf.context.sharedContext.accountManager, peerId: peer.id) var botPeer = EnginePeer(peer)
if case let .inline(bot) = source {
botPeer = bot
}
let _ = (ApplicationSpecificNotice.getBotGameNotice(accountManager: strongSelf.context.sharedContext.accountManager, peerId: botPeer.id)
|> deliverOnMainQueue).start(next: { value in |> deliverOnMainQueue).start(next: { value in
guard let strongSelf = self else { guard let strongSelf = self else {
return return
@ -4303,8 +4314,8 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
if value { if value {
openWebView() openWebView()
} else { } else {
let controller = webAppLaunchConfirmationController(context: strongSelf.context, updatedPresentationData: strongSelf.updatedPresentationData, peer: EnginePeer(peer), commit: { let controller = webAppLaunchConfirmationController(context: strongSelf.context, updatedPresentationData: strongSelf.updatedPresentationData, peer: botPeer, commit: {
let _ = ApplicationSpecificNotice.setBotGameNotice(accountManager: strongSelf.context.sharedContext.accountManager, peerId: peer.id).start() let _ = ApplicationSpecificNotice.setBotGameNotice(accountManager: strongSelf.context.sharedContext.accountManager, peerId: botPeer.id).start()
openWebView() openWebView()
}, showMore: nil) }, showMore: nil)
strongSelf.present(controller, in: .window(.root)) strongSelf.present(controller, in: .window(.root))
@ -12857,13 +12868,17 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
self.presentAttachmentMenu(subject: .bot(id: botId, payload: payload, justInstalled: justInstalled)) self.presentAttachmentMenu(subject: .bot(id: botId, payload: payload, justInstalled: justInstalled))
} }
public func presentBotApp(botApp: BotApp, botPeer: EnginePeer, payload: String?) { public func presentBotApp(botApp: BotApp, botPeer: EnginePeer, payload: String?, concealed: Bool = false) {
guard let peerId = self.chatLocation.peerId else { guard let peerId = self.chatLocation.peerId else {
return return
} }
self.attachmentController?.dismiss(animated: true, completion: nil) self.attachmentController?.dismiss(animated: true, completion: nil)
self.updateChatPresentationInterfaceState(animated: true, interactive: true, { let openBotApp = { [weak self] allowWrite in
guard let strongSelf = self else {
return
}
strongSelf.updateChatPresentationInterfaceState(animated: true, interactive: true, {
return $0.updatedTitlePanelContext { return $0.updatedTitlePanelContext {
if !$0.contains(where: { if !$0.contains(where: {
switch $0 { switch $0 {
@ -12906,8 +12921,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
} }
let botAddress = botPeer.addressName ?? "" let botAddress = botPeer.addressName ?? ""
strongSelf.messageActionCallbackDisposable.set(((strongSelf.context.engine.messages.requestAppWebView(peerId: peerId, appReference: .id(id: botApp.id, accessHash: botApp.accessHash), payload: payload, themeParams: generateWebAppThemeParams(strongSelf.presentationData.theme), allowWrite: allowWrite)
self.messageActionCallbackDisposable.set(((self.context.engine.messages.requestAppWebView(peerId: peerId, appReference: .id(id: botApp.id, accessHash: botApp.accessHash), payload: payload, themeParams: generateWebAppThemeParams(self.presentationData.theme), allowWrite: false)
|> afterDisposed { |> afterDisposed {
updateProgress() updateProgress()
}) })
@ -12950,6 +12964,20 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
})) }))
} }
if concealed || botApp.flags.contains(.notActivated) {
let controller = webAppLaunchConfirmationController(context: self.context, updatedPresentationData: self.updatedPresentationData, peer: botPeer, commit: {
openBotApp(false)
}, showMore: { [weak self] in
if let strongSelf = self {
strongSelf.openResolved(result: .peer(botPeer._asPeer(), .info), sourceMessageId: nil)
}
})
self.present(controller, in: .window(.root))
} else {
openBotApp(false)
}
}
private func presentAttachmentPremiumGift() { private func presentAttachmentPremiumGift() {
self.presentAttachmentMenu(subject: .gift) self.presentAttachmentMenu(subject: .gift)
} }
@ -17329,9 +17357,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
})) }))
case let .withBotStartPayload(startPayload): case let .withBotStartPayload(startPayload):
if case .peer(peerId.id) = strongSelf.chatLocation { if case .peer(peerId.id) = strongSelf.chatLocation {
strongSelf.updateChatPresentationInterfaceState(animated: true, interactive: true, { strongSelf.startBot(startPayload.payload)
$0.updatedBotStartPayload(startPayload.payload)
})
} else if let navigationController = strongSelf.effectiveNavigationController { } else if let navigationController = strongSelf.effectiveNavigationController {
strongSelf.context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: strongSelf.context, chatLocation: .peer(peerId), botStart: startPayload, keepStack: .always)) strongSelf.context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: strongSelf.context, chatLocation: .peer(peerId), botStart: startPayload, keepStack: .always))
} }
@ -17343,23 +17369,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
let _ = (strongSelf.context.engine.data.get(TelegramEngine.EngineData.Item.Peer.Peer(id: peerId.id)) let _ = (strongSelf.context.engine.data.get(TelegramEngine.EngineData.Item.Peer.Peer(id: peerId.id))
|> deliverOnMainQueue).start(next: { [weak self] peer in |> deliverOnMainQueue).start(next: { [weak self] peer in
if let strongSelf = self, let peer { if let strongSelf = self, let peer {
let openBotApp = { [weak self] in strongSelf.presentBotApp(botApp: botAppStart.botApp, botPeer: peer, payload: botAppStart.payload, concealed: concealed)
if let strongSelf = self {
strongSelf.presentBotApp(botApp: botAppStart.botApp, botPeer: peerId, payload: botAppStart.payload)
}
}
if concealed {
let controller = webAppLaunchConfirmationController(context: strongSelf.context, updatedPresentationData: strongSelf.updatedPresentationData, peer: peer, commit: {
openBotApp()
}, showMore: { [weak self] in
if let strongSelf = self {
strongSelf.openResolved(result: .peer(peer._asPeer(), .info), sourceMessageId: nil)
}
})
strongSelf.present(controller, in: .window(.root))
} else {
openBotApp()
}
} }
}) })
default: default:

View File

@ -1,6 +1,7 @@
import Foundation import Foundation
import UIKit import UIKit
import AsyncDisplayKit import AsyncDisplayKit
import SwiftSignalKit
import Display import Display
import TelegramCore import TelegramCore
import TelegramPresentationData import TelegramPresentationData
@ -207,9 +208,13 @@ final class ChatLoadingPlaceholderNode: ASDisplayNode {
self.borderNode.view.mask = self.borderMaskNode.view self.borderNode.view.mask = self.borderMaskNode.view
if self.context.sharedContext.energyUsageSettings.fullTranslucency { if self.context.sharedContext.energyUsageSettings.fullTranslucency {
Queue.mainQueue().after(0.3) {
if !self.didAnimateOut {
self.backgroundNode?.updateIsLooping(true) self.backgroundNode?.updateIsLooping(true)
} }
} }
}
}
private var bottomInset: (Int, CGFloat)? private var bottomInset: (Int, CGFloat)?
func setup(_ historyNode: ChatHistoryNode, updating: Bool = false) { func setup(_ historyNode: ChatHistoryNode, updating: Bool = false) {
@ -279,11 +284,12 @@ final class ChatLoadingPlaceholderNode: ASDisplayNode {
self.borderMaskNode.bounds = self.borderMaskNode.bounds.offsetBy(dx: 0.0, dy: inset) self.borderMaskNode.bounds = self.borderMaskNode.bounds.offsetBy(dx: 0.0, dy: inset)
} }
private var didAnimateOut = false
func animateOut(_ historyNode: ChatHistoryNode, completion: @escaping () -> Void = {}) { func animateOut(_ historyNode: ChatHistoryNode, completion: @escaping () -> Void = {}) {
guard let listNode = historyNode as? ListView, let (size, _, _) = self.validLayout else { guard let listNode = historyNode as? ListView, let (size, _, _) = self.validLayout else {
return return
} }
self.didAnimateOut = true
self.backgroundNode?.updateIsLooping(false) self.backgroundNode?.updateIsLooping(false)
let transition = ContainedViewLayoutTransition.animated(duration: 0.3, curve: .spring) let transition = ContainedViewLayoutTransition.animated(duration: 0.3, curve: .spring)

View File

@ -1473,7 +1473,8 @@ class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDelegate {
transition.animatePosition(layer: self.startButton.layer, from: CGPoint(x: 0.0, y: 80.0), to: CGPoint(), additive: true) transition.animatePosition(layer: self.startButton.layer, from: CGPoint(x: 0.0, y: 80.0), to: CGPoint(), additive: true)
} }
if let context = self.context { if let context = self.context {
let absoluteFrame = self.startButton.view.convert(self.startButton.bounds, to: nil) let parentFrame = self.view.convert(self.bounds, to: nil)
let absoluteFrame = self.startButton.view.convert(self.startButton.bounds, to: nil).offsetBy(dx: -parentFrame.minX, dy: 0.0)
let location = CGRect(origin: CGPoint(x: absoluteFrame.midX, y: absoluteFrame.minY - 1.0), size: CGSize()) let location = CGRect(origin: CGPoint(x: absoluteFrame.midX, y: absoluteFrame.minY - 1.0), size: CGSize())
if let tooltipController = self.tooltipController { if let tooltipController = self.tooltipController {
@ -1494,7 +1495,8 @@ class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDelegate {
delay = 0.35 delay = 0.35
} }
Queue.mainQueue().after(delay, { Queue.mainQueue().after(delay, {
let absoluteFrame = self.startButton.view.convert(self.startButton.bounds, to: nil) let parentFrame = self.view.convert(self.bounds, to: nil)
let absoluteFrame = self.startButton.view.convert(self.startButton.bounds, to: nil).offsetBy(dx: -parentFrame.minX, dy: 0.0)
let location = CGRect(origin: CGPoint(x: absoluteFrame.midX, y: absoluteFrame.minY - 1.0), size: CGSize()) let location = CGRect(origin: CGPoint(x: absoluteFrame.midX, y: absoluteFrame.minY - 1.0), size: CGSize())
controller.location = .point(location, .bottom) controller.location = .point(location, .bottom)
self.interfaceInteraction?.presentControllerInCurrent(controller, nil) self.interfaceInteraction?.presentControllerInCurrent(controller, nil)

View File

@ -207,13 +207,6 @@ private final class FetchVideoLibraryMediaResourceContext {
private let throttlingContext = FetchVideoLibraryMediaResourceContext() private let throttlingContext = FetchVideoLibraryMediaResourceContext()
public func fetchVideoLibraryMediaResource(account: Account, resource: VideoLibraryMediaResource) -> Signal<MediaResourceDataFetchResult, MediaResourceDataFetchError> { public func fetchVideoLibraryMediaResource(account: Account, resource: VideoLibraryMediaResource) -> Signal<MediaResourceDataFetchResult, MediaResourceDataFetchError> {
return account.postbox.preferencesView(keys: [PreferencesKeys.appConfiguration])
|> take(1)
|> map { view in
return view.values[PreferencesKeys.appConfiguration]?.get(AppConfiguration.self) ?? .defaultValue
}
|> castError(MediaResourceDataFetchError.self)
|> mapToSignal { appConfiguration -> Signal<MediaResourceDataFetchResult, MediaResourceDataFetchError> in
let signal = Signal<MediaResourceDataFetchResult, MediaResourceDataFetchError> { subscriber in let signal = Signal<MediaResourceDataFetchResult, MediaResourceDataFetchError> { subscriber in
subscriber.putNext(.reset) subscriber.putNext(.reset)
let fetchResult = PHAsset.fetchAssets(withLocalIdentifiers: [resource.localIdentifier], options: nil) let fetchResult = PHAsset.fetchAssets(withLocalIdentifiers: [resource.localIdentifier], options: nil)
@ -319,17 +312,9 @@ public func fetchVideoLibraryMediaResource(account: Account, resource: VideoLibr
} }
} }
return throttlingContext.wrap(priority: .default, signal: signal) return throttlingContext.wrap(priority: .default, signal: signal)
}
} }
func fetchLocalFileVideoMediaResource(account: Account, resource: LocalFileVideoMediaResource) -> Signal<MediaResourceDataFetchResult, MediaResourceDataFetchError> { func fetchLocalFileVideoMediaResource(account: Account, resource: LocalFileVideoMediaResource) -> Signal<MediaResourceDataFetchResult, MediaResourceDataFetchError> {
return account.postbox.preferencesView(keys: [PreferencesKeys.appConfiguration])
|> take(1)
|> map { view in
return view.values[PreferencesKeys.appConfiguration]?.get(AppConfiguration.self) ?? .defaultValue
}
|> castError(MediaResourceDataFetchError.self)
|> mapToSignal { appConfiguration -> Signal<MediaResourceDataFetchResult, MediaResourceDataFetchError> in
let signal = Signal<MediaResourceDataFetchResult, MediaResourceDataFetchError> { subscriber in let signal = Signal<MediaResourceDataFetchResult, MediaResourceDataFetchError> { subscriber in
subscriber.putNext(.reset) subscriber.putNext(.reset)
@ -452,7 +437,6 @@ func fetchLocalFileVideoMediaResource(account: Account, resource: LocalFileVideo
} }
} }
return throttlingContext.wrap(priority: .default, signal: signal) return throttlingContext.wrap(priority: .default, signal: signal)
}
} }
public func fetchVideoLibraryMediaResourceHash(resource: VideoLibraryMediaResource) -> Signal<Data?, NoError> { public func fetchVideoLibraryMediaResourceHash(resource: VideoLibraryMediaResource) -> Signal<Data?, NoError> {

View File

@ -137,6 +137,10 @@ public func navigateToChatControllerImpl(_ params: NavigateToChatControllerParam
} }
} else { } else {
controller = ChatControllerImpl(context: params.context, chatLocation: params.chatLocation.asChatLocation, chatLocationContextHolder: params.chatLocationContextHolder, subject: params.subject, botStart: params.botStart, attachBotStart: params.attachBotStart, botAppStart: params.botAppStart, peekData: params.peekData, peerNearbyData: params.peerNearbyData, chatListFilter: params.chatListFilter, chatNavigationStack: params.chatNavigationStack) controller = ChatControllerImpl(context: params.context, chatLocation: params.chatLocation.asChatLocation, chatLocationContextHolder: params.chatLocationContextHolder, subject: params.subject, botStart: params.botStart, attachBotStart: params.attachBotStart, botAppStart: params.botAppStart, peekData: params.peekData, peerNearbyData: params.peerNearbyData, chatListFilter: params.chatListFilter, chatNavigationStack: params.chatNavigationStack)
if let botAppStart = params.botAppStart, case let .peer(peer) = params.chatLocation {
controller.presentBotApp(botApp: botAppStart.botApp, botPeer: peer, payload: botAppStart.payload)
}
} }
controller.purposefulAction = params.purposefulAction controller.purposefulAction = params.purposefulAction
if let search = params.activateMessageSearch { if let search = params.activateMessageSearch {

View File

@ -219,6 +219,11 @@ func openExternalUrlImpl(context: AccountContext, urlContext: OpenURLContext, ur
if let navigationController = navigationController { if let navigationController = navigationController {
context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: context, chatLocation: .peer(peer), attachBotStart: attachBotStart)) context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: context, chatLocation: .peer(peer), attachBotStart: attachBotStart))
} }
case let .withBotApp(botAppStart):
context.sharedContext.applicationBindings.dismissNativeController()
if let navigationController = navigationController {
context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: context, chatLocation: .peer(peer), botAppStart: botAppStart))
}
default: default:
break break
} }
@ -738,7 +743,7 @@ func openExternalUrlImpl(context: AccountContext, urlContext: OpenURLContext, ur
} else if let domain = domain { } else if let domain = domain {
var result = "https://t.me/\(domain)" var result = "https://t.me/\(domain)"
if let appName { if let appName {
result += "\(appName)" result += "/\(appName)"
} }
if let startApp { if let startApp {
result += "?startapp=\(startApp)" result += "?startapp=\(startApp)"

View File

@ -206,10 +206,7 @@ public func chatTranslationState(context: AccountContext, peerId: EnginePeer.Id)
var fromLangs: [String: Int] = [:] var fromLangs: [String: Int] = [:]
var count = 0 var count = 0
for message in messages { for message in messages {
if let _ = URL(string: message.text) { if message.effectivelyIncoming(context.account.peerId), message.text.count >= 10 {
continue
}
if message.text.count >= 10 {
var text = String(message.text.prefix(256)) var text = String(message.text.prefix(256))
if var entities = message.textEntitiesAttribute?.entities.filter({ [.Pre, .Code, .Url, .Email, .Mention, .Hashtag, .BotCommand].contains($0.type) }) { if var entities = message.textEntitiesAttribute?.entities.filter({ [.Pre, .Code, .Url, .Email, .Mention, .Hashtag, .BotCommand].contains($0.type) }) {
entities = entities.sorted(by: { $0.range.lowerBound > $1.range.lowerBound }) entities = entities.sorted(by: { $0.range.lowerBound > $1.range.lowerBound })