Merge commit 'c751b2b790a37424fe946935dab950c9121cb975'

This commit is contained in:
Isaac 2024-05-24 15:52:04 +04:00
commit 16b6083b6e
19 changed files with 203 additions and 98 deletions

View File

@ -1045,6 +1045,7 @@ public protocol SharedAccountContext: AnyObject {
func makeStarsPurchaseScreen(context: AccountContext, starsContext: StarsContext, options: [StarsTopUpOption], peerId: EnginePeer.Id?, requiredStars: Int64?, completion: @escaping (Int64) -> Void) -> ViewController func makeStarsPurchaseScreen(context: AccountContext, starsContext: StarsContext, options: [StarsTopUpOption], peerId: EnginePeer.Id?, requiredStars: Int64?, completion: @escaping (Int64) -> Void) -> ViewController
func makeStarsTransferScreen(context: AccountContext, starsContext: StarsContext, invoice: TelegramMediaInvoice, source: BotPaymentInvoiceSource, inputData: Signal<(StarsContext.State, BotPaymentForm, EnginePeer?)?, NoError>) -> ViewController func makeStarsTransferScreen(context: AccountContext, starsContext: StarsContext, invoice: TelegramMediaInvoice, source: BotPaymentInvoiceSource, inputData: Signal<(StarsContext.State, BotPaymentForm, EnginePeer?)?, NoError>) -> ViewController
func makeStarsTransactionScreen(context: AccountContext, transaction: StarsContext.State.Transaction) -> ViewController func makeStarsTransactionScreen(context: AccountContext, transaction: StarsContext.State.Transaction) -> ViewController
func makeStarsReceiptScreen(context: AccountContext, receipt: BotPaymentReceipt, id: String?, date: Int32) -> ViewController
func makeDebugSettingsController(context: AccountContext?) -> ViewController? func makeDebugSettingsController(context: AccountContext?) -> ViewController?

View File

@ -102,7 +102,17 @@ final class HashtagSearchControllerNode: ASDisplayNode {
self.myController?.displayNode.isHidden = true self.myController?.displayNode.isHidden = true
self.globalController?.displayNode.isHidden = true self.globalController?.displayNode.isHidden = true
self.isSearching.set(self.currentController?.searching.get() ?? .single(false)) let isSearching: Signal<Bool, NoError>
if let currentController = self.currentController {
isSearching = .single(true)
|> then(
currentController.searching.get()
|> delay(0.5, queue: Queue.mainQueue())
)
} else {
isSearching = .single(false)
}
self.isSearching.set(isSearching)
} else { } else {
self.myController?.displayNode.isHidden = false self.myController?.displayNode.isHidden = false
self.globalController?.displayNode.isHidden = true self.globalController?.displayNode.isHidden = true

View File

@ -63,6 +63,8 @@ final class HashtagSearchNavigationContentNode: NavigationBarContentNode {
super.init() super.init()
self.searchBar.autocapitalization = .none
if hasCurrentChat { if hasCurrentChat {
self.addSubnode(self.searchBar) self.addSubnode(self.searchBar)
} }

View File

@ -949,6 +949,15 @@ public class SearchBarNode: ASDisplayNode, UITextFieldDelegate {
} }
} }
public var autocapitalization: UITextAutocapitalizationType {
get {
return self.textField.autocapitalizationType
}
set {
self.textField.autocapitalizationType = newValue
}
}
private var validLayout: (CGSize, CGFloat, CGFloat)? private var validLayout: (CGSize, CGFloat, CGFloat)?
private let fieldStyle: SearchBarStyle private let fieldStyle: SearchBarStyle

View File

@ -545,7 +545,7 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = {
dict[-1281329567] = { return Api.MessageAction.parse_messageActionGroupCallScheduled($0) } dict[-1281329567] = { return Api.MessageAction.parse_messageActionGroupCallScheduled($0) }
dict[-1615153660] = { return Api.MessageAction.parse_messageActionHistoryClear($0) } dict[-1615153660] = { return Api.MessageAction.parse_messageActionHistoryClear($0) }
dict[1345295095] = { return Api.MessageAction.parse_messageActionInviteToGroupCall($0) } dict[1345295095] = { return Api.MessageAction.parse_messageActionInviteToGroupCall($0) }
dict[-1776926890] = { return Api.MessageAction.parse_messageActionPaymentSent($0) } dict[-1482950556] = { return Api.MessageAction.parse_messageActionPaymentSent($0) }
dict[-1892568281] = { return Api.MessageAction.parse_messageActionPaymentSentMe($0) } dict[-1892568281] = { return Api.MessageAction.parse_messageActionPaymentSentMe($0) }
dict[-2132731265] = { return Api.MessageAction.parse_messageActionPhoneCall($0) } dict[-2132731265] = { return Api.MessageAction.parse_messageActionPhoneCall($0) }
dict[-1799538451] = { return Api.MessageAction.parse_messageActionPinMessage($0) } dict[-1799538451] = { return Api.MessageAction.parse_messageActionPinMessage($0) }

View File

@ -604,7 +604,7 @@ public extension Api {
case messageActionGroupCallScheduled(call: Api.InputGroupCall, scheduleDate: Int32) case messageActionGroupCallScheduled(call: Api.InputGroupCall, scheduleDate: Int32)
case messageActionHistoryClear case messageActionHistoryClear
case messageActionInviteToGroupCall(call: Api.InputGroupCall, users: [Int64]) case messageActionInviteToGroupCall(call: Api.InputGroupCall, users: [Int64])
case messageActionPaymentSent(flags: Int32, currency: String, totalAmount: Int64, invoiceSlug: String?) case messageActionPaymentSent(flags: Int32, currency: String, totalAmount: Int64, invoiceSlug: String?, charge: Api.PaymentCharge?)
case messageActionPaymentSentMe(flags: Int32, currency: String, totalAmount: Int64, payload: Buffer, info: Api.PaymentRequestedInfo?, shippingOptionId: String?, charge: Api.PaymentCharge) case messageActionPaymentSentMe(flags: Int32, currency: String, totalAmount: Int64, payload: Buffer, info: Api.PaymentRequestedInfo?, shippingOptionId: String?, charge: Api.PaymentCharge)
case messageActionPhoneCall(flags: Int32, callId: Int64, reason: Api.PhoneCallDiscardReason?, duration: Int32?) case messageActionPhoneCall(flags: Int32, callId: Int64, reason: Api.PhoneCallDiscardReason?, duration: Int32?)
case messageActionPinMessage case messageActionPinMessage
@ -816,14 +816,15 @@ public extension Api {
serializeInt64(item, buffer: buffer, boxed: false) serializeInt64(item, buffer: buffer, boxed: false)
} }
break break
case .messageActionPaymentSent(let flags, let currency, let totalAmount, let invoiceSlug): case .messageActionPaymentSent(let flags, let currency, let totalAmount, let invoiceSlug, let charge):
if boxed { if boxed {
buffer.appendInt32(-1776926890) buffer.appendInt32(-1482950556)
} }
serializeInt32(flags, buffer: buffer, boxed: false) serializeInt32(flags, buffer: buffer, boxed: false)
serializeString(currency, buffer: buffer, boxed: false) serializeString(currency, buffer: buffer, boxed: false)
serializeInt64(totalAmount, buffer: buffer, boxed: false) serializeInt64(totalAmount, buffer: buffer, boxed: false)
if Int(flags) & Int(1 << 0) != 0 {serializeString(invoiceSlug!, buffer: buffer, boxed: false)} if Int(flags) & Int(1 << 0) != 0 {serializeString(invoiceSlug!, buffer: buffer, boxed: false)}
if Int(flags) & Int(1 << 4) != 0 {charge!.serialize(buffer, true)}
break break
case .messageActionPaymentSentMe(let flags, let currency, let totalAmount, let payload, let info, let shippingOptionId, let charge): case .messageActionPaymentSentMe(let flags, let currency, let totalAmount, let payload, let info, let shippingOptionId, let charge):
if boxed { if boxed {
@ -1017,8 +1018,8 @@ public extension Api {
return ("messageActionHistoryClear", []) return ("messageActionHistoryClear", [])
case .messageActionInviteToGroupCall(let call, let users): case .messageActionInviteToGroupCall(let call, let users):
return ("messageActionInviteToGroupCall", [("call", call as Any), ("users", users as Any)]) return ("messageActionInviteToGroupCall", [("call", call as Any), ("users", users as Any)])
case .messageActionPaymentSent(let flags, let currency, let totalAmount, let invoiceSlug): case .messageActionPaymentSent(let flags, let currency, let totalAmount, let invoiceSlug, let charge):
return ("messageActionPaymentSent", [("flags", flags as Any), ("currency", currency as Any), ("totalAmount", totalAmount as Any), ("invoiceSlug", invoiceSlug as Any)]) return ("messageActionPaymentSent", [("flags", flags as Any), ("currency", currency as Any), ("totalAmount", totalAmount as Any), ("invoiceSlug", invoiceSlug as Any), ("charge", charge as Any)])
case .messageActionPaymentSentMe(let flags, let currency, let totalAmount, let payload, let info, let shippingOptionId, let charge): case .messageActionPaymentSentMe(let flags, let currency, let totalAmount, let payload, let info, let shippingOptionId, let charge):
return ("messageActionPaymentSentMe", [("flags", flags as Any), ("currency", currency as Any), ("totalAmount", totalAmount as Any), ("payload", payload as Any), ("info", info as Any), ("shippingOptionId", shippingOptionId as Any), ("charge", charge as Any)]) return ("messageActionPaymentSentMe", [("flags", flags as Any), ("currency", currency as Any), ("totalAmount", totalAmount as Any), ("payload", payload as Any), ("info", info as Any), ("shippingOptionId", shippingOptionId as Any), ("charge", charge as Any)])
case .messageActionPhoneCall(let flags, let callId, let reason, let duration): case .messageActionPhoneCall(let flags, let callId, let reason, let duration):
@ -1395,12 +1396,17 @@ public extension Api {
_3 = reader.readInt64() _3 = reader.readInt64()
var _4: String? var _4: String?
if Int(_1!) & Int(1 << 0) != 0 {_4 = parseString(reader) } if Int(_1!) & Int(1 << 0) != 0 {_4 = parseString(reader) }
var _5: Api.PaymentCharge?
if Int(_1!) & Int(1 << 4) != 0 {if let signature = reader.readInt32() {
_5 = Api.parse(reader, signature: signature) as? Api.PaymentCharge
} }
let _c1 = _1 != nil let _c1 = _1 != nil
let _c2 = _2 != nil let _c2 = _2 != nil
let _c3 = _3 != nil let _c3 = _3 != nil
let _c4 = (Int(_1!) & Int(1 << 0) == 0) || _4 != nil let _c4 = (Int(_1!) & Int(1 << 0) == 0) || _4 != nil
if _c1 && _c2 && _c3 && _c4 { let _c5 = (Int(_1!) & Int(1 << 4) == 0) || _5 != nil
return Api.MessageAction.messageActionPaymentSent(flags: _1!, currency: _2!, totalAmount: _3!, invoiceSlug: _4) if _c1 && _c2 && _c3 && _c4 && _c5 {
return Api.MessageAction.messageActionPaymentSent(flags: _1!, currency: _2!, totalAmount: _3!, invoiceSlug: _4, charge: _5)
} }
else { else {
return nil return nil

View File

@ -40,10 +40,18 @@ func telegramMediaActionFromApiAction(_ action: Api.MessageAction) -> TelegramMe
return TelegramMediaAction(action: .phoneCall(callId: callId, discardReason: discardReason, duration: duration, isVideo: isVideo)) return TelegramMediaAction(action: .phoneCall(callId: callId, discardReason: discardReason, duration: duration, isVideo: isVideo))
case .messageActionEmpty: case .messageActionEmpty:
return nil return nil
case let .messageActionPaymentSent(flags, currency, totalAmount, invoiceSlug): case let .messageActionPaymentSent(flags, currency, totalAmount, invoiceSlug, charge):
let isRecurringInit = (flags & (1 << 2)) != 0 let isRecurringInit = (flags & (1 << 2)) != 0
let isRecurringUsed = (flags & (1 << 3)) != 0 let isRecurringUsed = (flags & (1 << 3)) != 0
return TelegramMediaAction(action: .paymentSent(currency: currency, totalAmount: totalAmount, invoiceSlug: invoiceSlug, isRecurringInit: isRecurringInit, isRecurringUsed: isRecurringUsed))
let chargeId: String?
switch charge {
case let .paymentCharge(id, _):
chargeId = id
default:
chargeId = nil
}
return TelegramMediaAction(action: .paymentSent(currency: currency, totalAmount: totalAmount, invoiceSlug: invoiceSlug, isRecurringInit: isRecurringInit, isRecurringUsed: isRecurringUsed, chargeId: chargeId))
case .messageActionPaymentSentMe: case .messageActionPaymentSentMe:
return nil return nil
case .messageActionScreenshotTaken: case .messageActionScreenshotTaken:

View File

@ -101,7 +101,7 @@ public enum TelegramMediaActionType: PostboxCoding, Equatable {
case messageAutoremoveTimeoutUpdated(period: Int32, autoSettingSource: PeerId?) case messageAutoremoveTimeoutUpdated(period: Int32, autoSettingSource: PeerId?)
case gameScore(gameId: Int64, score: Int32) case gameScore(gameId: Int64, score: Int32)
case phoneCall(callId: Int64, discardReason: PhoneCallDiscardReason?, duration: Int32?, isVideo: Bool) case phoneCall(callId: Int64, discardReason: PhoneCallDiscardReason?, duration: Int32?, isVideo: Bool)
case paymentSent(currency: String, totalAmount: Int64, invoiceSlug: String?, isRecurringInit: Bool, isRecurringUsed: Bool) case paymentSent(currency: String, totalAmount: Int64, invoiceSlug: String?, isRecurringInit: Bool, isRecurringUsed: Bool, chargeId: String?)
case customText(text: String, entities: [MessageTextEntity], additionalAttributes: CustomTextAttributes?) case customText(text: String, entities: [MessageTextEntity], additionalAttributes: CustomTextAttributes?)
case botDomainAccessGranted(domain: String) case botDomainAccessGranted(domain: String)
case botAppAccessGranted(appName: String?, type: BotSendMessageAccessGrantedType?) case botAppAccessGranted(appName: String?, type: BotSendMessageAccessGrantedType?)
@ -164,7 +164,7 @@ public enum TelegramMediaActionType: PostboxCoding, Equatable {
} }
self = .phoneCall(callId: decoder.decodeInt64ForKey("i", orElse: 0), discardReason: discardReason, duration: decoder.decodeInt32ForKey("d", orElse: 0), isVideo: decoder.decodeInt32ForKey("vc", orElse: 0) != 0) self = .phoneCall(callId: decoder.decodeInt64ForKey("i", orElse: 0), discardReason: discardReason, duration: decoder.decodeInt32ForKey("d", orElse: 0), isVideo: decoder.decodeInt32ForKey("vc", orElse: 0) != 0)
case 15: case 15:
self = .paymentSent(currency: decoder.decodeStringForKey("currency", orElse: ""), totalAmount: decoder.decodeInt64ForKey("ta", orElse: 0), invoiceSlug: decoder.decodeOptionalStringForKey("invoiceSlug"), isRecurringInit: decoder.decodeBoolForKey("isRecurringInit", orElse: false), isRecurringUsed: decoder.decodeBoolForKey("isRecurringUsed", orElse: false)) self = .paymentSent(currency: decoder.decodeStringForKey("currency", orElse: ""), totalAmount: decoder.decodeInt64ForKey("ta", orElse: 0), invoiceSlug: decoder.decodeOptionalStringForKey("invoiceSlug"), isRecurringInit: decoder.decodeBoolForKey("isRecurringInit", orElse: false), isRecurringUsed: decoder.decodeBoolForKey("isRecurringUsed", orElse: false), chargeId: decoder.decodeOptionalStringForKey("chargeId"))
case 16: case 16:
self = .customText(text: decoder.decodeStringForKey("text", orElse: ""), entities: decoder.decodeObjectArrayWithDecoderForKey("ent"), additionalAttributes: nil) self = .customText(text: decoder.decodeStringForKey("text", orElse: ""), entities: decoder.decodeObjectArrayWithDecoderForKey("ent"), additionalAttributes: nil)
case 17: case 17:
@ -293,7 +293,7 @@ public enum TelegramMediaActionType: PostboxCoding, Equatable {
encoder.encodeInt32(13, forKey: "_rawValue") encoder.encodeInt32(13, forKey: "_rawValue")
encoder.encodeInt64(gameId, forKey: "i") encoder.encodeInt64(gameId, forKey: "i")
encoder.encodeInt32(score, forKey: "s") encoder.encodeInt32(score, forKey: "s")
case let .paymentSent(currency, totalAmount, invoiceSlug, isRecurringInit, isRecurringUsed): case let .paymentSent(currency, totalAmount, invoiceSlug, isRecurringInit, isRecurringUsed, chargeId):
encoder.encodeInt32(15, forKey: "_rawValue") encoder.encodeInt32(15, forKey: "_rawValue")
encoder.encodeString(currency, forKey: "currency") encoder.encodeString(currency, forKey: "currency")
encoder.encodeInt64(totalAmount, forKey: "ta") encoder.encodeInt64(totalAmount, forKey: "ta")
@ -304,6 +304,11 @@ public enum TelegramMediaActionType: PostboxCoding, Equatable {
} }
encoder.encodeBool(isRecurringInit, forKey: "isRecurringInit") encoder.encodeBool(isRecurringInit, forKey: "isRecurringInit")
encoder.encodeBool(isRecurringUsed, forKey: "isRecurringUsed") encoder.encodeBool(isRecurringUsed, forKey: "isRecurringUsed")
if let chargeId = chargeId {
encoder.encodeString(chargeId, forKey: "chargeId")
} else {
encoder.encodeNil(forKey: "chargeId")
}
case let .phoneCall(callId, discardReason, duration, isVideo): case let .phoneCall(callId, discardReason, duration, isVideo):
encoder.encodeInt32(14, forKey: "_rawValue") encoder.encodeInt32(14, forKey: "_rawValue")
encoder.encodeInt64(callId, forKey: "i") encoder.encodeInt64(callId, forKey: "i")

View File

@ -563,7 +563,7 @@ func _internal_sendBotPaymentForm(account: Account, formId: Int64, source: BotPa
switch source { switch source {
case let .slug(slug): case let .slug(slug):
for media in message.media { for media in message.media {
if let action = media as? TelegramMediaAction, case let .paymentSent(_, _, invoiceSlug?, _, _) = action.action, invoiceSlug == slug { if let action = media as? TelegramMediaAction, case let .paymentSent(_, _, invoiceSlug?, _, _, _) = action.action, invoiceSlug == slug {
if case let .Id(id) = message.id { if case let .Id(id) = message.id {
receiptMessageId = id receiptMessageId = id
} }

View File

@ -366,7 +366,7 @@ func _internal_sendStarsPaymentForm(account: Account, formId: Int64, source: Bot
switch source { switch source {
case let .slug(slug): case let .slug(slug):
for media in message.media { for media in message.media {
if let action = media as? TelegramMediaAction, case let .paymentSent(_, _, invoiceSlug?, _, _) = action.action, invoiceSlug == slug { if let action = media as? TelegramMediaAction, case let .paymentSent(_, _, invoiceSlug?, _, _, _) = action.action, invoiceSlug == slug {
if case let .Id(id) = message.id { if case let .Id(id) = message.id {
receiptMessageId = id receiptMessageId = id
} }

View File

@ -496,7 +496,7 @@ public func universalServiceMessageString(presentationData: (PresentationTheme,
var argumentAttributes = peerMentionsAttributes(primaryTextColor: primaryTextColor, peerIds: [(0, message.author?.id)]) var argumentAttributes = peerMentionsAttributes(primaryTextColor: primaryTextColor, peerIds: [(0, message.author?.id)])
argumentAttributes[1] = MarkdownAttributeSet(font: titleBoldFont, textColor: primaryTextColor, additionalAttributes: [:]) argumentAttributes[1] = MarkdownAttributeSet(font: titleBoldFont, textColor: primaryTextColor, additionalAttributes: [:])
attributedString = addAttributesToStringWithRanges(formatWithArgumentRanges(baseString, ranges, [authorName, gameTitle ?? ""]), body: bodyAttributes, argumentAttributes: argumentAttributes) attributedString = addAttributesToStringWithRanges(formatWithArgumentRanges(baseString, ranges, [authorName, gameTitle ?? ""]), body: bodyAttributes, argumentAttributes: argumentAttributes)
case let .paymentSent(currency, totalAmount, _, isRecurringInit, isRecurringUsed): case let .paymentSent(currency, totalAmount, _, isRecurringInit, isRecurringUsed, _):
var invoiceMessage: EngineMessage? var invoiceMessage: EngineMessage?
for attribute in message.attributes { for attribute in message.attributes {
if let attribute = attribute as? ReplyMessageAttribute, let message = message.associatedMessages[attribute.messageId] { if let attribute = attribute as? ReplyMessageAttribute, let message = message.associatedMessages[attribute.messageId] {
@ -548,13 +548,11 @@ public func universalServiceMessageString(presentationData: (PresentationTheme,
range = (mutableString.string as NSString).range(of: "{amount}") range = (mutableString.string as NSString).range(of: "{amount}")
if range.location != NSNotFound { if range.location != NSNotFound {
if currency == "XTR" { if currency == "XTR" {
let amountAttributedString = NSMutableAttributedString(string: " > \(totalAmount)", font: titleBoldFont, textColor: primaryTextColor) let amountAttributedString = NSMutableAttributedString(string: "#\(totalAmount)", font: titleBoldFont, textColor: primaryTextColor)
if let range = amountAttributedString.string.range(of: ">"), let starImage = generateScaledImage(image: UIImage(bundleImageName: "Premium/Stars/Star"), size: CGSize(width: 16.0, height: 16.0), opaque: false)?.withRenderingMode(.alwaysTemplate) { if let range = amountAttributedString.string.range(of: "#") {
amountAttributedString.addAttribute(.attachment, value: starImage, range: NSRange(range, in: amountAttributedString.string)) amountAttributedString.addAttribute(ChatTextInputAttributes.customEmoji, value: ChatTextInputTextCustomEmojiAttribute(interactivelySelectedFromPackId: nil, fileId: 0, file: nil, custom: .stars), range: NSRange(range, in: amountAttributedString.string))
amountAttributedString.addAttribute(.foregroundColor, value: primaryTextColor, range: NSRange(range, in: amountAttributedString.string))
amountAttributedString.addAttribute(.baselineOffset, value: 1.5, range: NSRange(range, in: amountAttributedString.string)) amountAttributedString.addAttribute(.baselineOffset, value: 1.5, range: NSRange(range, in: amountAttributedString.string))
} }
mutableString.replaceCharacters(in: range, with: amountAttributedString) mutableString.replaceCharacters(in: range, with: amountAttributedString)
} else { } else {
mutableString.replaceCharacters(in: range, with: NSAttributedString(string: formatCurrencyAmount(totalAmount, currency: currency), font: titleBoldFont, textColor: primaryTextColor)) mutableString.replaceCharacters(in: range, with: NSAttributedString(string: formatCurrencyAmount(totalAmount, currency: currency), font: titleBoldFont, textColor: primaryTextColor))

View File

@ -98,6 +98,7 @@ private func contentNodeMessagesAndClassesForItem(_ item: ChatMessageItem) -> ([
var result: [(Message, AnyClass, ChatMessageEntryAttributes, BubbleItemAttributes)] = [] var result: [(Message, AnyClass, ChatMessageEntryAttributes, BubbleItemAttributes)] = []
var skipText = false var skipText = false
var messageWithCaptionToAdd: (Message, ChatMessageEntryAttributes)? var messageWithCaptionToAdd: (Message, ChatMessageEntryAttributes)?
var messageWithFactCheckToAdd: (Message, ChatMessageEntryAttributes)?
var isUnsupportedMedia = false var isUnsupportedMedia = false
var isStoryWithText = false var isStoryWithText = false
var isAction = false var isAction = false
@ -263,6 +264,10 @@ private func contentNodeMessagesAndClassesForItem(_ item: ChatMessageItem) -> ([
} }
} }
if let attribute = message.factCheckAttribute, case .Loaded = attribute.content, messageWithFactCheckToAdd == nil {
messageWithFactCheckToAdd = (message, itemAttributes)
}
inner: for media in message.media { inner: for media in message.media {
if let webpage = media as? TelegramMediaWebpage { if let webpage = media as? TelegramMediaWebpage {
if case let .Loaded(content) = webpage.content { if case let .Loaded(content) = webpage.content {
@ -294,14 +299,6 @@ private func contentNodeMessagesAndClassesForItem(_ item: ChatMessageItem) -> ([
if isUnsupportedMedia { if isUnsupportedMedia {
result.append((message, ChatMessageUnsupportedBubbleContentNode.self, itemAttributes, BubbleItemAttributes(isAttachment: false, neighborType: .text, neighborSpacing: .default))) result.append((message, ChatMessageUnsupportedBubbleContentNode.self, itemAttributes, BubbleItemAttributes(isAttachment: false, neighborType: .text, neighborSpacing: .default)))
needReactions = false needReactions = false
} else {
for attribute in message.attributes {
if let attribute = attribute as? FactCheckMessageAttribute, case .Loaded = attribute.content {
result.append((message, ChatMessageFactCheckBubbleContentNode.self, itemAttributes, BubbleItemAttributes(isAttachment: false, neighborType: .text, neighborSpacing: .default)))
needReactions = false
break
}
}
} }
} }
@ -317,6 +314,11 @@ private func contentNodeMessagesAndClassesForItem(_ item: ChatMessageItem) -> ([
} }
} }
if let (messageWithFactCheckToAdd, itemAttributes) = messageWithFactCheckToAdd, !hasSeparateCommentsButton {
result.append((messageWithFactCheckToAdd, ChatMessageFactCheckBubbleContentNode.self, itemAttributes, BubbleItemAttributes(isAttachment: false, neighborType: .text, neighborSpacing: .default)))
needReactions = false
}
if let additionalContent = item.additionalContent { if let additionalContent = item.additionalContent {
switch additionalContent { switch additionalContent {
case let .eventLogPreviousMessage(previousMessage): case let .eventLogPreviousMessage(previousMessage):

View File

@ -395,6 +395,9 @@ public final class InlineStickerItemLayer: MultiAnimationRenderTarget {
self.updateTopicInfo(topicInfo: (id, info)) self.updateTopicInfo(topicInfo: (id, info))
case let .nameColors(colors): case let .nameColors(colors):
self.updateNameColors(colors: colors) self.updateNameColors(colors: colors)
case .stars:
self.updateStars()
self.updateTintColor()
} }
} else if let file = file { } else if let file = file {
self.updateFile(file: file, attemptSynchronousLoad: attemptSynchronousLoad) self.updateFile(file: file, attemptSynchronousLoad: attemptSynchronousLoad)
@ -480,6 +483,8 @@ public final class InlineStickerItemLayer: MultiAnimationRenderTarget {
if file.isCustomTemplateEmoji { if file.isCustomTemplateEmoji {
customColor = self.dynamicColor customColor = self.dynamicColor
} }
} else if let emoji = self.arguments?.emoji, let custom = emoji.custom, case .stars = custom {
customColor = self.dynamicColor
} }
if customColor != nil { if customColor != nil {
@ -574,6 +579,10 @@ public final class InlineStickerItemLayer: MultiAnimationRenderTarget {
self.contents = image?.cgImage self.contents = image?.cgImage
} }
private func updateStars() {
self.contents = starImage?.cgImage
}
private func updateFile(file: TelegramMediaFile, attemptSynchronousLoad: Bool) { private func updateFile(file: TelegramMediaFile, attemptSynchronousLoad: Bool) {
guard let arguments = self.arguments else { guard let arguments = self.arguments else {
return return
@ -833,3 +842,13 @@ public final class CustomEmojiContainerView: UIView {
} }
} }
} }
private let starImage: UIImage? = {
generateImage(CGSize(width: 32.0, height: 32.0), contextGenerator: { size, context in
context.clear(CGRect(origin: .zero, size: size))
if let image = generateTintedImage(image: UIImage(bundleImageName: "Premium/Stars/Star"), color: .white), let cgImage = image.cgImage {
context.draw(cgImage, in: CGRect(origin: .zero, size: size).insetBy(dx: 2.0, dy: 2.0), byTiling: false)
}
})?.withRenderingMode(.alwaysTemplate)
}()

View File

@ -79,6 +79,8 @@ private final class StarsTransactionSheetContent: CombinedComponent {
if case let .peer(peer) = transaction.peer { if case let .peer(peer) = transaction.peer {
peerIds.append(peer.id) peerIds.append(peer.id)
} }
case let .receipt(receipt, _, _):
peerIds.append(receipt.botPaymentId)
} }
self.disposable = (context.engine.data.get( self.disposable = (context.engine.data.get(
@ -159,18 +161,20 @@ private final class StarsTransactionSheetContent: CombinedComponent {
let additionalText: String let additionalText: String
let buttonText: String let buttonText: String
let transactionId: String let count: Int64
let transactionId: String?
let date: Int32 let date: Int32
let toPeer: EnginePeer? let toPeer: EnginePeer?
let photo: TelegramMediaWebFile?
let gloss = false let gloss = false
switch subject { switch subject {
case let .transaction(transaction): case let .transaction(transaction):
switch transaction.peer { switch transaction.peer {
case .peer: case let .peer(peer):
titleText = "Product Title" titleText = transaction.title ?? peer.compactDisplayTitle
case .appStore: case .appStore:
titleText = "In-app Purchase" titleText = "In-App Purchase"
case .playMarket: case .playMarket:
titleText = "Play Market" titleText = "Play Market"
case .premiumBot: case .premiumBot:
@ -181,14 +185,7 @@ private final class StarsTransactionSheetContent: CombinedComponent {
titleText = "Unsupported" titleText = "Unsupported"
} }
if transaction.count < 0 { count = transaction.count
descriptionText = "- \(transaction.count * -1) ⭐️"
} else {
descriptionText = "+ \(transaction.count) ⭐️"
}
additionalText = strings.Stars_Transaction_Terms
buttonText = strings.Common_OK
transactionId = transaction.id transactionId = transaction.id
date = transaction.date date = transaction.date
if case let .peer(peer) = transaction.peer { if case let .peer(peer) = transaction.peer {
@ -196,6 +193,27 @@ private final class StarsTransactionSheetContent: CombinedComponent {
} else { } else {
toPeer = nil toPeer = nil
} }
photo = transaction.photo
case let .receipt(receipt, id, dateValue):
titleText = receipt.invoiceMedia.title
count = (receipt.invoice.prices.first?.amount ?? receipt.invoiceMedia.totalAmount) * -1
transactionId = id
date = dateValue
if let peer = state.peerMap[receipt.botPaymentId] {
toPeer = peer
} else {
toPeer = nil
}
photo = receipt.invoiceMedia.photo
}
additionalText = strings.Stars_Transaction_Terms
buttonText = strings.Common_OK
if count < 0 {
descriptionText = "- \(count * -1) ⭐️"
} else {
descriptionText = "+ \(count) ⭐️"
} }
let title = title.update( let title = title.update(
@ -218,6 +236,7 @@ private final class StarsTransactionSheetContent: CombinedComponent {
context: component.context, context: component.context,
theme: theme, theme: theme,
peers: toPeer.flatMap { [$0] } ?? [], peers: toPeer.flatMap { [$0] } ?? [],
photo: photo,
isVisible: true, isVisible: true,
hasIdleAnimations: true, hasIdleAnimations: true,
hasScaleAnimation: false, hasScaleAnimation: false,
@ -247,7 +266,7 @@ private final class StarsTransactionSheetContent: CombinedComponent {
if let toPeer { if let toPeer {
tableItems.append(.init( tableItems.append(.init(
id: "to", id: "to",
title: strings.Stars_Transaction_Date, title: strings.Stars_Transaction_To,
component: AnyComponent( component: AnyComponent(
Button( Button(
content: AnyComponent( content: AnyComponent(
@ -270,6 +289,7 @@ private final class StarsTransactionSheetContent: CombinedComponent {
)) ))
} }
if let transactionId {
tableItems.append(.init( tableItems.append(.init(
id: "transaction", id: "transaction",
title: strings.Stars_Transaction_Id, title: strings.Stars_Transaction_Id,
@ -285,6 +305,7 @@ private final class StarsTransactionSheetContent: CombinedComponent {
), ),
insets: UIEdgeInsets(top: 0.0, left: 12.0, bottom: 0.0, right: 5.0) insets: UIEdgeInsets(top: 0.0, left: 12.0, bottom: 0.0, right: 5.0)
)) ))
}
tableItems.append(.init( tableItems.append(.init(
id: "date", id: "date",
@ -522,6 +543,7 @@ private final class StarsTransactionSheetComponent: CombinedComponent {
public class StarsTransactionScreen: ViewControllerComponentContainer { public class StarsTransactionScreen: ViewControllerComponentContainer {
public enum Subject: Equatable { public enum Subject: Equatable {
case transaction(StarsContext.State.Transaction) case transaction(StarsContext.State.Transaction)
case receipt(receipt: BotPaymentReceipt, id: String?, date: Int32)
} }
private let context: AccountContext private let context: AccountContext

View File

@ -1041,8 +1041,18 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
if canSetupAutoremoveTimeout { if canSetupAutoremoveTimeout {
strongSelf.presentAutoremoveSetup() strongSelf.presentAutoremoveSetup()
} }
case .paymentSent: case let .paymentSent(currency, _, _, _, _, id):
if currency == "XTR" {
let _ = (context.engine.payments.requestBotPaymentReceipt(messageId: message.id)
|> deliverOnMainQueue).start(next: { [weak self] receipt in
guard let self else {
return
}
self.push(self.context.sharedContext.makeStarsReceiptScreen(context: self.context, receipt: receipt, id: id, date: message.timestamp))
})
} else {
strongSelf.present(BotReceiptController(context: strongSelf.context, messageId: message.id), in: .window(.root), with: ViewControllerPresentationArguments(presentationAnimation: .modalSheet)) strongSelf.present(BotReceiptController(context: strongSelf.context, messageId: message.id), in: .window(.root), with: ViewControllerPresentationArguments(presentationAnimation: .modalSheet))
}
/*for attribute in message.attributes { /*for attribute in message.attributes {
if let attribute = attribute as? ReplyMessageAttribute { if let attribute = attribute as? ReplyMessageAttribute {
//strongSelf.navigateToMessage(from: message.id, to: .id(attribute.messageId)) //strongSelf.navigateToMessage(from: message.id, to: .id(attribute.messageId))
@ -2709,19 +2719,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
ActionSheetButtonItem(title: strongSelf.presentationData.strings.Conversation_LinkDialogOpen, color: .accent, action: { [weak actionSheet] in ActionSheetButtonItem(title: strongSelf.presentationData.strings.Conversation_LinkDialogOpen, color: .accent, action: { [weak actionSheet] in
actionSheet?.dismissAnimated() actionSheet?.dismissAnimated()
if let strongSelf = self { if let strongSelf = self {
let peerSignal: Signal<Peer?, NoError> strongSelf.openHashtag(hashtag, peerName: nil)
guard let peerId = strongSelf.chatLocation.peerId else {
return
}
peerSignal = strongSelf.context.account.postbox.loadedPeerWithId(peerId)
|> map(Optional.init)
let _ = (peerSignal
|> deliverOnMainQueue).startStandalone(next: { peer in
if let strongSelf = self {
let searchController = HashtagSearchController(context: strongSelf.context, peer: peer.flatMap(EnginePeer.init), query: hashtag)
strongSelf.effectiveNavigationController?.pushViewController(searchController)
}
})
} }
}), }),
ActionSheetButtonItem(title: strongSelf.presentationData.strings.Conversation_LinkDialogCopy, color: .accent, action: { [weak actionSheet] in ActionSheetButtonItem(title: strongSelf.presentationData.strings.Conversation_LinkDialogCopy, color: .accent, action: { [weak actionSheet] in
@ -2925,7 +2923,17 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
if let invoice = media as? TelegramMediaInvoice { if let invoice = media as? TelegramMediaInvoice {
strongSelf.chatDisplayNode.dismissInput() strongSelf.chatDisplayNode.dismissInput()
if let receiptMessageId = invoice.receiptMessageId { if let receiptMessageId = invoice.receiptMessageId {
if invoice.currency == "XTR" {
let _ = (strongSelf.context.engine.payments.requestBotPaymentReceipt(messageId: message.id)
|> deliverOnMainQueue).start(next: { [weak self] receipt in
guard let strongSelf = self else {
return
}
strongSelf.push(strongSelf.context.sharedContext.makeStarsReceiptScreen(context: strongSelf.context, receipt: receipt, id: nil, date: 0))
})
} else {
strongSelf.present(BotReceiptController(context: strongSelf.context, messageId: receiptMessageId), in: .window(.root), with: ViewControllerPresentationArguments(presentationAnimation: .modalSheet)) strongSelf.present(BotReceiptController(context: strongSelf.context, messageId: receiptMessageId), in: .window(.root), with: ViewControllerPresentationArguments(presentationAnimation: .modalSheet))
}
} else { } else {
let inputData = Promise<BotCheckoutController.InputData?>() let inputData = Promise<BotCheckoutController.InputData?>()
inputData.set(BotCheckoutController.InputData.fetch(context: strongSelf.context, source: .message(message.id)) inputData.set(BotCheckoutController.InputData.fetch(context: strongSelf.context, source: .message(message.id))
@ -9586,6 +9594,10 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
self.resolvePeerByNameDisposable?.set((resolveSignal self.resolvePeerByNameDisposable?.set((resolveSignal
|> deliverOnMainQueue).start(next: { [weak self] peer in |> deliverOnMainQueue).start(next: { [weak self] peer in
if let strongSelf = self, !hashtag.isEmpty { if let strongSelf = self, !hashtag.isEmpty {
// var peer = peer
// if peer?.id.isReplies == true {
// peer = nil
// }
let searchController = HashtagSearchController(context: strongSelf.context, peer: peer.flatMap(EnginePeer.init), query: hashtag) let searchController = HashtagSearchController(context: strongSelf.context, peer: peer.flatMap(EnginePeer.init), query: hashtag)
strongSelf.effectiveNavigationController?.pushViewController(searchController) strongSelf.effectiveNavigationController?.pushViewController(searchController)
} }

View File

@ -2816,8 +2816,12 @@ class ChatControllerNode: ASDisplayNode, ASScrollViewDelegate {
} }
self.skippedShowSearchResultsAsListAnimationOnce = true self.skippedShowSearchResultsAsListAnimationOnce = true
inlineSearchResultsView.layer.allowsGroupOpacity = true inlineSearchResultsView.layer.allowsGroupOpacity = true
if let inlineSearchResultsView = self.inlineSearchResults?.view {
self.contentContainerNode.view.insertSubview(inlineSearchResultsView, aboveSubview: inlineSearchResultsView)
} else {
self.contentContainerNode.view.insertSubview(inlineSearchResultsView, aboveSubview: self.historyNodeContainer.view) self.contentContainerNode.view.insertSubview(inlineSearchResultsView, aboveSubview: self.historyNodeContainer.view)
} }
}
inlineSearchResultsTransition.setFrame(view: inlineSearchResultsView, frame: CGRect(origin: CGPoint(), size: layout.size)) inlineSearchResultsTransition.setFrame(view: inlineSearchResultsView, frame: CGRect(origin: CGPoint(), size: layout.size))
if animateIn { if animateIn {

View File

@ -480,6 +480,10 @@ func contextMenuForChatPresentationInterfaceState(chatPresentationInterfaceState
isEmbeddedMode = true isEmbeddedMode = true
} }
if case let .customChatContents(customChatContents) = chatPresentationInterfaceState.subject, case .hashTagSearch = customChatContents.kind {
isEmbeddedMode = true
}
var hasExpandedAudioTranscription = false var hasExpandedAudioTranscription = false
if let messageNode = messageNode as? ChatMessageBubbleItemNode { if let messageNode = messageNode as? ChatMessageBubbleItemNode {
hasExpandedAudioTranscription = messageNode.hasExpandedAudioTranscription() hasExpandedAudioTranscription = messageNode.hasExpandedAudioTranscription()
@ -1703,16 +1707,14 @@ func contextMenuForChatPresentationInterfaceState(chatPresentationInterfaceState
clearCacheAsDelete = true clearCacheAsDelete = true
} }
if let channel = message.peers[message.id.peerId] as? TelegramChannel, case .broadcast = channel.info, canEditFactCheck(appConfig: appConfig) { if let channel = message.peers[message.id.peerId] as? TelegramChannel, case .broadcast = channel.info, canEditFactCheck(appConfig: appConfig) {
var hasFactCheck = false var canAddFactCheck = true
for attribute in message.attributes { if message.media.contains(where: { $0 is TelegramMediaAction || $0 is TelegramMediaGiveaway }) {
if let _ = attribute as? FactCheckMessageAttribute { canAddFactCheck = false
hasFactCheck = true
break
}
} }
if canAddFactCheck {
let hasFactCheck = message.factCheckAttribute != nil
let title: String let title: String
if hasFactCheck { if hasFactCheck {
title = chatPresentationInterfaceState.strings.Conversation_ContextMenuEditFactCheck title = chatPresentationInterfaceState.strings.Conversation_ContextMenuEditFactCheck
@ -1727,6 +1729,7 @@ func contextMenuForChatPresentationInterfaceState(chatPresentationInterfaceState
}) })
}))) })))
} }
}
// if message.id.peerId.isGroupOrChannel { // if message.id.peerId.isGroupOrChannel {
// //TODO:localize // //TODO:localize
// if message.isAgeRestricted() { // if message.isAgeRestricted() {
@ -1985,12 +1988,11 @@ func contextMenuForChatPresentationInterfaceState(chatPresentationInterfaceState
} }
if let message = messages.first, case let .customChatContents(customChatContents) = chatPresentationInterfaceState.subject { if let message = messages.first, case let .customChatContents(customChatContents) = chatPresentationInterfaceState.subject {
actions.removeAll()
switch customChatContents.kind { switch customChatContents.kind {
case .hashTagSearch: case .hashTagSearch:
break break
case .quickReplyMessageInput: case .quickReplyMessageInput:
actions.removeAll()
if !messageText.isEmpty || (resourceAvailable && isImage) || diceEmoji != nil { if !messageText.isEmpty || (resourceAvailable && isImage) || diceEmoji != nil {
actions.append(.action(ContextMenuActionItem(text: chatPresentationInterfaceState.strings.Conversation_ContextMenuCopy, icon: { theme in actions.append(.action(ContextMenuActionItem(text: chatPresentationInterfaceState.strings.Conversation_ContextMenuCopy, icon: { theme in
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Copy"), color: theme.actionSheet.primaryTextColor) return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Copy"), color: theme.actionSheet.primaryTextColor)
@ -2054,7 +2056,7 @@ func contextMenuForChatPresentationInterfaceState(chatPresentationInterfaceState
}))) })))
} }
case .businessLinkSetup: case .businessLinkSetup:
break actions.removeAll()
} }
} }

View File

@ -2634,6 +2634,10 @@ public final class SharedAccountContextImpl: SharedAccountContext {
public func makeStarsTransactionScreen(context: AccountContext, transaction: StarsContext.State.Transaction) -> ViewController { public func makeStarsTransactionScreen(context: AccountContext, transaction: StarsContext.State.Transaction) -> ViewController {
return StarsTransactionScreen(context: context, subject: .transaction(transaction), action: {}) return StarsTransactionScreen(context: context, subject: .transaction(transaction), action: {})
} }
public func makeStarsReceiptScreen(context: AccountContext, receipt: BotPaymentReceipt, id: String?, date: Int32) -> ViewController {
return StarsTransactionScreen(context: context, subject: .receipt(receipt: receipt, id: id, date: date), action: {})
}
} }
private func peerInfoControllerImpl(context: AccountContext, updatedPresentationData: (PresentationData, Signal<PresentationData, NoError>)?, peer: Peer, mode: PeerInfoControllerMode, avatarInitiallyExpanded: Bool, isOpenedFromChat: Bool, requestsContext: PeerInvitationImportersContext? = nil) -> ViewController? { private func peerInfoControllerImpl(context: AccountContext, updatedPresentationData: (PresentationData, Signal<PresentationData, NoError>)?, peer: Peer, mode: PeerInfoControllerMode, avatarInitiallyExpanded: Bool, isOpenedFromChat: Bool, requestsContext: PeerInvitationImportersContext? = nil) -> ViewController? {

View File

@ -407,6 +407,7 @@ public final class ChatTextInputTextCustomEmojiAttribute: NSObject, Codable {
public enum Custom: Codable { public enum Custom: Codable {
case topic(id: Int64, info: EngineMessageHistoryThread.Info) case topic(id: Int64, info: EngineMessageHistoryThread.Info)
case nameColors([UInt32]) case nameColors([UInt32])
case stars
} }
public let interactivelySelectedFromPackId: ItemCollectionId? public let interactivelySelectedFromPackId: ItemCollectionId?