mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-06-15 13:35:19 +00:00
Various fixes
This commit is contained in:
parent
1a89986990
commit
b2351194d4
@ -13819,12 +13819,12 @@ Sorry for the inconvenience.";
|
||||
"GroupInfo.Permissions.ChargeForMessages" = "Charge for Messages";
|
||||
"GroupInfo.Permissions.ChargeForMessagesInfo" = "If you turn this on, regular members of the group will have to pay Stars to send messages.";
|
||||
"GroupInfo.Permissions.MessagePrice" = "SET YOUR PRICE PER MESSAGE";
|
||||
"GroupInfo.Permissions.MessagePriceInfo" = "Your group will receive 85% of the selected fee (%1$@) for each incoming message.";
|
||||
"GroupInfo.Permissions.MessagePriceInfo" = "Your group will receive %1$@% of the selected fee (%2$@) for each incoming message.";
|
||||
|
||||
"Privacy.Messages.ChargeForMessages" = "Charge for Messages";
|
||||
"Privacy.Messages.ChargeForMessagesInfo" = "Charge a fee for messages from people outide your contacts or those you haven't messaged first.";
|
||||
"Privacy.Messages.MessagePrice" = "SET YOUR PRICE PER MESSAGE";
|
||||
"Privacy.Messages.MessagePriceInfo" = "Your will receive 85% of the selected fee (%1$@) for each incoming message.";
|
||||
"Privacy.Messages.MessagePriceInfo" = "Your will receive %1$@% of the selected fee (%2$@) for each incoming message.";
|
||||
|
||||
"Privacy.Messages.RemoveFeeHeader" = "EXCEPTIONS";
|
||||
"Privacy.Messages.RemoveFee" = "Remove Fee";
|
||||
@ -13874,3 +13874,5 @@ Sorry for the inconvenience.";
|
||||
"Gift.Send.PayWithStars.Info" = "Your balance is **%@**. [Get More Stars >]()";
|
||||
|
||||
"Chat.PanelCustomStatusShortInfo" = "%@ is a mark for [Premium subscribers >]()";
|
||||
|
||||
"Chat.InputTextPaidMessagePlaceholder" = "Message for %@";
|
||||
|
@ -1353,20 +1353,43 @@ public struct StickersSearchConfiguration {
|
||||
|
||||
public struct StarsSubscriptionConfiguration {
|
||||
static var defaultValue: StarsSubscriptionConfiguration {
|
||||
return StarsSubscriptionConfiguration(maxFee: 2500, usdWithdrawRate: 1200)
|
||||
return StarsSubscriptionConfiguration(
|
||||
maxFee: 2500,
|
||||
usdWithdrawRate: 1200,
|
||||
paidMessageMaxAmount: 10000,
|
||||
paidMessageCommissionPermille: 850
|
||||
)
|
||||
}
|
||||
|
||||
public let maxFee: Int64?
|
||||
public let usdWithdrawRate: Int64?
|
||||
public let maxFee: Int64
|
||||
public let usdWithdrawRate: Int64
|
||||
public let paidMessageMaxAmount: Int64
|
||||
public let paidMessageCommissionPermille: Int32
|
||||
|
||||
fileprivate init(maxFee: Int64?, usdWithdrawRate: Int64?) {
|
||||
fileprivate init(
|
||||
maxFee: Int64,
|
||||
usdWithdrawRate: Int64,
|
||||
paidMessageMaxAmount: Int64,
|
||||
paidMessageCommissionPermille: Int32
|
||||
) {
|
||||
self.maxFee = maxFee
|
||||
self.usdWithdrawRate = usdWithdrawRate
|
||||
self.paidMessageMaxAmount = paidMessageMaxAmount
|
||||
self.paidMessageCommissionPermille = paidMessageCommissionPermille
|
||||
}
|
||||
|
||||
public static func with(appConfiguration: AppConfiguration) -> StarsSubscriptionConfiguration {
|
||||
if let data = appConfiguration.data, let value = data["stars_subscription_amount_max"] as? Double, let usdRate = data["stars_usd_withdraw_rate_x1000"] as? Double {
|
||||
return StarsSubscriptionConfiguration(maxFee: Int64(value), usdWithdrawRate: Int64(usdRate))
|
||||
if let data = appConfiguration.data {
|
||||
let maxFee = (data["stars_subscription_amount_max"] as? Double).flatMap(Int64.init) ?? StarsSubscriptionConfiguration.defaultValue.maxFee
|
||||
let usdWithdrawRate = (data["stars_usd_withdraw_rate_x1000"] as? Double).flatMap(Int64.init) ?? StarsSubscriptionConfiguration.defaultValue.usdWithdrawRate
|
||||
let paidMessageMaxAmount = (data["stars_paid_message_amount_max"] as? Double).flatMap(Int64.init) ?? StarsSubscriptionConfiguration.defaultValue.paidMessageMaxAmount
|
||||
let paidMessageCommissionPermille = (data["stars_paid_message_commission_permille"] as? Double).flatMap(Int32.init) ?? StarsSubscriptionConfiguration.defaultValue.paidMessageCommissionPermille
|
||||
return StarsSubscriptionConfiguration(
|
||||
maxFee: maxFee,
|
||||
usdWithdrawRate: usdWithdrawRate,
|
||||
paidMessageMaxAmount: paidMessageMaxAmount,
|
||||
paidMessageCommissionPermille: paidMessageCommissionPermille
|
||||
)
|
||||
} else {
|
||||
return .defaultValue
|
||||
}
|
||||
|
@ -76,5 +76,5 @@ public enum ShareControllerSubject {
|
||||
case image([ImageRepresentationWithReference])
|
||||
case media(AnyMediaReference, MediaParameters?)
|
||||
case mapMedia(TelegramMediaMap)
|
||||
case fromExternal(([PeerId], [PeerId: Int64], String, ShareControllerAccountContext, Bool) -> Signal<ShareControllerExternalStatus, ShareControllerError>)
|
||||
case fromExternal(Int, ([PeerId], [PeerId: Int64], [PeerId: StarsAmount], String, ShareControllerAccountContext, Bool) -> Signal<ShareControllerExternalStatus, ShareControllerError>)
|
||||
}
|
||||
|
@ -144,7 +144,7 @@ final class GameControllerNode: ViewControllerTracingNode {
|
||||
if eventName == "share_game" || eventName == "share_score" {
|
||||
if let (botPeer, gameName) = self.shareData(), let addressName = botPeer.addressName, !addressName.isEmpty, !gameName.isEmpty {
|
||||
if eventName == "share_score" {
|
||||
self.present(ShareController(context: self.context, subject: .fromExternal({ [weak self] peerIds, threadIds, text, account, _ in
|
||||
self.present(ShareController(context: self.context, subject: .fromExternal(1, { [weak self] peerIds, threadIds, requireStars, text, account, _ in
|
||||
if let strongSelf = self, let message = strongSelf.message, let account = account as? ShareControllerAppAccountContext {
|
||||
let signals = peerIds.map { TelegramEngine(account: account.context.account).messages.forwardGameWithScore(messageId: message.id, to: $0, threadId: threadIds[$0], as: nil) }
|
||||
return .single(.preparing(false))
|
||||
|
@ -493,13 +493,10 @@ private func inviteLinkEditControllerEntries(invite: ExportedInvitation?, state:
|
||||
if state.subscriptionEnabled {
|
||||
var label: String = ""
|
||||
if let subscriptionFee = state.subscriptionFee, subscriptionFee > StarsAmount.zero {
|
||||
var usdRate = 0.012
|
||||
if let usdWithdrawRate = configuration.usdWithdrawRate {
|
||||
usdRate = Double(usdWithdrawRate) / 1000.0 / 100.0
|
||||
}
|
||||
let usdRate = Double(configuration.usdWithdrawRate) / 1000.0 / 100.0
|
||||
label = presentationData.strings.InviteLink_Create_FeePerMonth("≈\(formatTonUsdValue(subscriptionFee.value, divide: false, rate: usdRate, dateTimeFormat: presentationData.dateTimeFormat))").string
|
||||
}
|
||||
entries.append(.subscriptionFee(presentationData.theme, presentationData.strings.InviteLink_Create_FeePlaceholder, isEditingEnabled, state.subscriptionFee, label, configuration.maxFee.flatMap({ StarsAmount(value: $0, nanos: 0) })))
|
||||
entries.append(.subscriptionFee(presentationData.theme, presentationData.strings.InviteLink_Create_FeePlaceholder, isEditingEnabled, state.subscriptionFee, label, StarsAmount(value: configuration.maxFee, nanos: 0)))
|
||||
}
|
||||
let infoText: String
|
||||
if let _ = invite, state.subscriptionEnabled {
|
||||
|
@ -594,10 +594,7 @@ public final class InviteLinkViewController: ViewController {
|
||||
guard let peer else {
|
||||
return
|
||||
}
|
||||
var usdRate = 0.012
|
||||
if let usdWithdrawRate = configuration.usdWithdrawRate {
|
||||
usdRate = Double(usdWithdrawRate) / 1000.0 / 100.0
|
||||
}
|
||||
let usdRate = Double(configuration.usdWithdrawRate) / 1000.0 / 100.0
|
||||
let subscriptionController = context.sharedContext.makeStarsSubscriptionScreen(context: context, peer: peer, pricing: pricing, importer: importer, usdRate: usdRate)
|
||||
self?.controller?.push(subscriptionController)
|
||||
})
|
||||
@ -834,11 +831,8 @@ public final class InviteLinkViewController: ViewController {
|
||||
context.account.postbox.loadedPeerWithId(adminId)
|
||||
) |> deliverOnMainQueue).start(next: { [weak self] presentationData, state, requestsState, creatorPeer in
|
||||
if let strongSelf = self {
|
||||
var usdRate = 0.012
|
||||
if let usdWithdrawRate = configuration.usdWithdrawRate {
|
||||
usdRate = Double(usdWithdrawRate) / 1000.0 / 100.0
|
||||
}
|
||||
|
||||
let usdRate = Double(configuration.usdWithdrawRate) / 1000.0 / 100.0
|
||||
|
||||
var entries: [InviteLinkViewEntry] = []
|
||||
|
||||
entries.append(.link(presentationData.theme, invite))
|
||||
|
@ -720,7 +720,7 @@ private func channelPermissionsControllerEntries(context: AccountContext, presen
|
||||
entries.append(.conversionInfo(presentationData.theme, presentationData.strings.GroupInfo_Permissions_BroadcastConvertInfo(presentationStringsFormattedNumber(participantsLimit, presentationData.dateTimeFormat.groupingSeparator)).string))
|
||||
}
|
||||
|
||||
if channel.hasPermission(.banMembers) {
|
||||
if cachedData.flags.contains(.paidMessagesAvailable) && channel.hasPermission(.banMembers) {
|
||||
let sendPaidMessageStars = state.modifiedStarsAmount?.value ?? (cachedData.sendPaidMessageStars?.value ?? 0)
|
||||
let chargeEnabled = sendPaidMessageStars > 0
|
||||
entries.append(.chargeForMessages(presentationData.theme, presentationData.strings.GroupInfo_Permissions_ChargeForMessages, chargeEnabled))
|
||||
@ -728,15 +728,13 @@ private func channelPermissionsControllerEntries(context: AccountContext, presen
|
||||
|
||||
if chargeEnabled {
|
||||
var price: String = ""
|
||||
var usdRate = 0.012
|
||||
if let usdWithdrawRate = configuration.usdWithdrawRate {
|
||||
usdRate = Double(usdWithdrawRate) / 1000.0 / 100.0
|
||||
}
|
||||
let usdRate = Double(configuration.usdWithdrawRate) / 1000.0 / 100.0
|
||||
|
||||
price = "≈\(formatTonUsdValue(sendPaidMessageStars, divide: false, rate: usdRate, dateTimeFormat: presentationData.dateTimeFormat))"
|
||||
|
||||
entries.append(.messagePriceHeader(presentationData.theme, presentationData.strings.GroupInfo_Permissions_MessagePrice))
|
||||
entries.append(.messagePrice(presentationData.theme, sendPaidMessageStars, price))
|
||||
entries.append(.messagePriceInfo(presentationData.theme, presentationData.strings.GroupInfo_Permissions_MessagePriceInfo(price).string))
|
||||
entries.append(.messagePriceInfo(presentationData.theme, presentationData.strings.GroupInfo_Permissions_MessagePriceInfo("\(configuration.paidMessageCommissionPermille / 10)", price).string))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -50,7 +50,7 @@ private enum GlobalAutoremoveEntry: ItemListNodeEntry {
|
||||
case footer(value: GlobalPrivacySettings.NonContactChatsPrivacy)
|
||||
case priceHeader
|
||||
case price(value: Int64, price: String)
|
||||
case priceInfo(value: String)
|
||||
case priceInfo(commission: Int32, value: String)
|
||||
case exceptionsHeader
|
||||
case exceptions(count: Int)
|
||||
case exceptionsInfo
|
||||
@ -153,8 +153,8 @@ private enum GlobalAutoremoveEntry: ItemListNodeEntry {
|
||||
return MessagePriceItem(theme: presentationData.theme, strings: presentationData.strings, minValue: 1, maxValue: 10000, value: value, price: price, sectionId: self.section, updated: { value in
|
||||
arguments.updateValue(.paidMessages(StarsAmount(value: value, nanos: 0)))
|
||||
})
|
||||
case let .priceInfo(value):
|
||||
return ItemListTextItem(presentationData: presentationData, text: .markdown(presentationData.strings.Privacy_Messages_MessagePriceInfo(value).string), sectionId: self.section)
|
||||
case let .priceInfo(commission, value):
|
||||
return ItemListTextItem(presentationData: presentationData, text: .markdown(presentationData.strings.Privacy_Messages_MessagePriceInfo("\(commission)", value).string), sectionId: self.section)
|
||||
case .exceptionsHeader:
|
||||
return ItemListSectionHeaderItem(presentationData: presentationData, text: presentationData.strings.Privacy_Messages_RemoveFeeHeader, sectionId: self.section)
|
||||
case let .exceptions(count):
|
||||
@ -184,14 +184,12 @@ private func incomingMessagePrivacyScreenEntries(presentationData: PresentationD
|
||||
entries.append(.footer(value: state.updatedValue))
|
||||
entries.append(.priceHeader)
|
||||
|
||||
var usdRate = 0.012
|
||||
if let usdWithdrawRate = configuration.usdWithdrawRate {
|
||||
usdRate = Double(usdWithdrawRate) / 1000.0 / 100.0
|
||||
}
|
||||
let usdRate = Double(configuration.usdWithdrawRate) / 1000.0 / 100.0
|
||||
|
||||
let price = "≈\(formatTonUsdValue(amount.value, divide: false, rate: usdRate, dateTimeFormat: presentationData.dateTimeFormat))"
|
||||
|
||||
entries.append(.price(value: amount.value, price: price))
|
||||
entries.append(.priceInfo(value: price))
|
||||
entries.append(.priceInfo(commission: configuration.paidMessageCommissionPermille / 10, value: price))
|
||||
entries.append(.exceptionsHeader)
|
||||
entries.append(.exceptions(count: state.disableFor.count))
|
||||
entries.append(.exceptionsInfo)
|
||||
|
@ -676,6 +676,8 @@ public final class ShareController: ViewController {
|
||||
messageCount = messages.count
|
||||
} else if case let .image(images) = self.subject {
|
||||
messageCount = images.count
|
||||
} else if case let .fromExternal(count, _) = self.subject {
|
||||
messageCount = count
|
||||
}
|
||||
|
||||
var mediaParameters: ShareControllerSubject.MediaParameters?
|
||||
@ -1253,18 +1255,18 @@ public final class ShareController: ViewController {
|
||||
}
|
||||
)
|
||||
|> take(1)
|
||||
|> map { views -> ([EnginePeer.Id: EnginePeer?], [EnginePeer.Id: Int64]) in
|
||||
|> map { views -> ([EnginePeer.Id: EnginePeer?], [EnginePeer.Id: StarsAmount]) in
|
||||
var result: [EnginePeer.Id: EnginePeer?] = [:]
|
||||
var requiresStars: [EnginePeer.Id: Int64] = [:]
|
||||
var requiresStars: [EnginePeer.Id: StarsAmount] = [:]
|
||||
for peerId in peerIds {
|
||||
if let view = views.views[PostboxViewKey.basicPeer(peerId)] as? BasicPeerView, let peer = view.peer {
|
||||
result[peerId] = EnginePeer(peer)
|
||||
if peer is TelegramUser, let cachedPeerDataView = views.views[PostboxViewKey.cachedPeerData(peerId: peerId)] as? CachedPeerDataView {
|
||||
if let cachedData = cachedPeerDataView.cachedPeerData as? CachedUserData {
|
||||
requiresStars[peerId] = cachedData.sendPaidMessageStars?.value
|
||||
requiresStars[peerId] = cachedData.sendPaidMessageStars
|
||||
}
|
||||
} else if let channel = peer as? TelegramChannel {
|
||||
requiresStars[peerId] = channel.sendPaidMessageStars?.value
|
||||
requiresStars[peerId] = channel.sendPaidMessageStars
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1284,7 +1286,7 @@ public final class ShareController: ViewController {
|
||||
subject = selectedValue.subject
|
||||
}
|
||||
|
||||
func transformMessages(_ messages: [StandaloneSendEnqueueMessage], showNames: Bool, silently: Bool, sendPaidMessageStars: Int64?) -> [StandaloneSendEnqueueMessage] {
|
||||
func transformMessages(_ messages: [StandaloneSendEnqueueMessage], showNames: Bool, silently: Bool, sendPaidMessageStars: StarsAmount?) -> [StandaloneSendEnqueueMessage] {
|
||||
return messages.map { message in
|
||||
var message = message
|
||||
if !showNames {
|
||||
@ -1296,7 +1298,7 @@ public final class ShareController: ViewController {
|
||||
if silently {
|
||||
message.isSilent = true
|
||||
}
|
||||
message.sendPaidMessageStars = sendPaidMessageStars.flatMap { StarsAmount(value: $0, nanos: 0) }
|
||||
message.sendPaidMessageStars = sendPaidMessageStars
|
||||
return message
|
||||
}
|
||||
}
|
||||
@ -1839,8 +1841,8 @@ public final class ShareController: ViewController {
|
||||
messages: messagesToEnqueue
|
||||
))
|
||||
}
|
||||
case let .fromExternal(f):
|
||||
return f(peerIds, topicIds, text, strongSelf.currentContext, silently)
|
||||
case let .fromExternal(_, f):
|
||||
return f(peerIds, topicIds, requiresStars, text, strongSelf.currentContext, silently)
|
||||
|> map { state -> ShareState in
|
||||
switch state {
|
||||
case let .preparing(long):
|
||||
@ -1907,18 +1909,18 @@ public final class ShareController: ViewController {
|
||||
}
|
||||
)
|
||||
|> take(1)
|
||||
|> map { views -> ([EnginePeer.Id: EnginePeer?], [EnginePeer.Id: Int64]) in
|
||||
|> map { views -> ([EnginePeer.Id: EnginePeer?], [EnginePeer.Id: StarsAmount]) in
|
||||
var result: [EnginePeer.Id: EnginePeer?] = [:]
|
||||
var requiresStars: [EnginePeer.Id: Int64] = [:]
|
||||
var requiresStars: [EnginePeer.Id: StarsAmount] = [:]
|
||||
for peerId in peerIds {
|
||||
if let view = views.views[PostboxViewKey.basicPeer(peerId)] as? BasicPeerView, let peer = view.peer {
|
||||
result[peerId] = EnginePeer(peer)
|
||||
if peer is TelegramUser, let cachedPeerDataView = views.views[PostboxViewKey.cachedPeerData(peerId: peerId)] as? CachedPeerDataView {
|
||||
if let cachedData = cachedPeerDataView.cachedPeerData as? CachedUserData {
|
||||
requiresStars[peerId] = cachedData.sendPaidMessageStars?.value
|
||||
requiresStars[peerId] = cachedData.sendPaidMessageStars
|
||||
}
|
||||
} else if let channel = peer as? TelegramChannel {
|
||||
requiresStars[peerId] = channel.sendPaidMessageStars?.value
|
||||
requiresStars[peerId] = channel.sendPaidMessageStars
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1938,7 +1940,7 @@ public final class ShareController: ViewController {
|
||||
subject = selectedValue.subject
|
||||
}
|
||||
|
||||
func transformMessages(_ messages: [EnqueueMessage], showNames: Bool, silently: Bool, sendPaidMessageStars: Int64?) -> [EnqueueMessage] {
|
||||
func transformMessages(_ messages: [EnqueueMessage], showNames: Bool, silently: Bool, sendPaidMessageStars: StarsAmount?) -> [EnqueueMessage] {
|
||||
return messages.map { message in
|
||||
return message.withUpdatedAttributes({ attributes in
|
||||
var attributes = attributes
|
||||
@ -1949,7 +1951,7 @@ public final class ShareController: ViewController {
|
||||
attributes.append(NotificationInfoMessageAttribute(flags: .muted))
|
||||
}
|
||||
if let sendPaidMessageStars {
|
||||
attributes.append(PaidStarsMessageAttribute(stars: StarsAmount(value: sendPaidMessageStars, nanos: 0), postponeSending: false))
|
||||
attributes.append(PaidStarsMessageAttribute(stars: sendPaidMessageStars, postponeSending: false))
|
||||
}
|
||||
return attributes
|
||||
})
|
||||
@ -2321,8 +2323,8 @@ public final class ShareController: ViewController {
|
||||
messagesToEnqueue = transformMessages(messagesToEnqueue, showNames: showNames, silently: silently, sendPaidMessageStars: requiresStars[peerId])
|
||||
shareSignals.append(enqueueMessages(account: currentContext.context.account, peerId: peerId, messages: messagesToEnqueue))
|
||||
}
|
||||
case let .fromExternal(f):
|
||||
return f(peerIds, topicIds, text, currentContext, silently)
|
||||
case let .fromExternal(_, f):
|
||||
return f(peerIds, topicIds, requiresStars, text, currentContext, silently)
|
||||
|> map { state -> ShareState in
|
||||
switch state {
|
||||
case let .preparing(long):
|
||||
|
@ -409,7 +409,7 @@ public func preparedShareItems(postbox: Postbox, network: Network, to peerId: Pe
|
||||
})
|
||||
}
|
||||
|
||||
public func sentShareItems(accountPeerId: PeerId, postbox: Postbox, network: Network, stateManager: AccountStateManager, auxiliaryMethods: AccountAuxiliaryMethods, to peerIds: [PeerId], threadIds: [PeerId: Int64], items: [PreparedShareItemContent], silently: Bool, additionalText: String) -> Signal<Float, Void> {
|
||||
public func sentShareItems(accountPeerId: PeerId, postbox: Postbox, network: Network, stateManager: AccountStateManager, auxiliaryMethods: AccountAuxiliaryMethods, to peerIds: [PeerId], threadIds: [PeerId: Int64], requireStars: [PeerId: StarsAmount], items: [PreparedShareItemContent], silently: Bool, additionalText: String) -> Signal<Float, Void> {
|
||||
var messages: [StandaloneSendEnqueueMessage] = []
|
||||
var groupingKey: Int64?
|
||||
var mediaTypes: (photo: Int, video: Int, music: Int, other: Int) = (0, 0, 0, 0)
|
||||
@ -498,6 +498,16 @@ public func sentShareItems(accountPeerId: PeerId, postbox: Postbox, network: Net
|
||||
|
||||
var peerSignals: Signal<Float, StandaloneSendMessagesError> = .single(0.0)
|
||||
for peerId in peerIds {
|
||||
var peerMessages = messages
|
||||
if let amount = requireStars[peerId] {
|
||||
var updatedMessages: [StandaloneSendEnqueueMessage] = []
|
||||
for message in peerMessages {
|
||||
var message = message
|
||||
message.sendPaidMessageStars = amount
|
||||
updatedMessages.append(message)
|
||||
}
|
||||
peerMessages = updatedMessages
|
||||
}
|
||||
peerSignals = peerSignals |> then(standaloneSendEnqueueMessages(
|
||||
accountPeerId: accountPeerId,
|
||||
postbox: postbox,
|
||||
@ -506,7 +516,7 @@ public func sentShareItems(accountPeerId: PeerId, postbox: Postbox, network: Net
|
||||
auxiliaryMethods: auxiliaryMethods,
|
||||
peerId: peerId,
|
||||
threadId: threadIds[peerId],
|
||||
messages: messages
|
||||
messages: peerMessages
|
||||
)
|
||||
|> mapToSignal { status -> Signal<Float, StandaloneSendMessagesError> in
|
||||
switch status {
|
||||
|
@ -1390,7 +1390,7 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = {
|
||||
dict[1314881805] = { return Api.payments.PaymentResult.parse_paymentResult($0) }
|
||||
dict[-666824391] = { return Api.payments.PaymentResult.parse_paymentVerificationNeeded($0) }
|
||||
dict[-74456004] = { return Api.payments.SavedInfo.parse_savedInfo($0) }
|
||||
dict[-1779201615] = { return Api.payments.SavedStarGifts.parse_savedStarGifts($0) }
|
||||
dict[-418915641] = { return Api.payments.SavedStarGifts.parse_savedStarGifts($0) }
|
||||
dict[377215243] = { return Api.payments.StarGiftUpgradePreview.parse_starGiftUpgradePreview($0) }
|
||||
dict[-2069218660] = { return Api.payments.StarGiftWithdrawalUrl.parse_starGiftWithdrawalUrl($0) }
|
||||
dict[-1877571094] = { return Api.payments.StarGifts.parse_starGifts($0) }
|
||||
|
@ -1,16 +1,21 @@
|
||||
public extension Api.payments {
|
||||
enum SavedStarGifts: TypeConstructorDescription {
|
||||
case savedStarGifts(flags: Int32, count: Int32, chatNotificationsEnabled: Api.Bool?, gifts: [Api.SavedStarGift], nextOffset: String?, chats: [Api.Chat], users: [Api.User])
|
||||
case savedStarGifts(flags: Int32, count: Int32, chatNotificationsEnabled: Api.Bool?, pinnedToTop: [Int64]?, gifts: [Api.SavedStarGift], nextOffset: String?, chats: [Api.Chat], users: [Api.User])
|
||||
|
||||
public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) {
|
||||
switch self {
|
||||
case .savedStarGifts(let flags, let count, let chatNotificationsEnabled, let gifts, let nextOffset, let chats, let users):
|
||||
case .savedStarGifts(let flags, let count, let chatNotificationsEnabled, let pinnedToTop, let gifts, let nextOffset, let chats, let users):
|
||||
if boxed {
|
||||
buffer.appendInt32(-1779201615)
|
||||
buffer.appendInt32(-418915641)
|
||||
}
|
||||
serializeInt32(flags, buffer: buffer, boxed: false)
|
||||
serializeInt32(count, buffer: buffer, boxed: false)
|
||||
if Int(flags) & Int(1 << 1) != 0 {chatNotificationsEnabled!.serialize(buffer, true)}
|
||||
if Int(flags) & Int(1 << 2) != 0 {buffer.appendInt32(481674261)
|
||||
buffer.appendInt32(Int32(pinnedToTop!.count))
|
||||
for item in pinnedToTop! {
|
||||
serializeInt64(item, buffer: buffer, boxed: false)
|
||||
}}
|
||||
buffer.appendInt32(481674261)
|
||||
buffer.appendInt32(Int32(gifts.count))
|
||||
for item in gifts {
|
||||
@ -33,8 +38,8 @@ public extension Api.payments {
|
||||
|
||||
public func descriptionFields() -> (String, [(String, Any)]) {
|
||||
switch self {
|
||||
case .savedStarGifts(let flags, let count, let chatNotificationsEnabled, let gifts, let nextOffset, let chats, let users):
|
||||
return ("savedStarGifts", [("flags", flags as Any), ("count", count as Any), ("chatNotificationsEnabled", chatNotificationsEnabled as Any), ("gifts", gifts as Any), ("nextOffset", nextOffset as Any), ("chats", chats as Any), ("users", users as Any)])
|
||||
case .savedStarGifts(let flags, let count, let chatNotificationsEnabled, let pinnedToTop, let gifts, let nextOffset, let chats, let users):
|
||||
return ("savedStarGifts", [("flags", flags as Any), ("count", count as Any), ("chatNotificationsEnabled", chatNotificationsEnabled as Any), ("pinnedToTop", pinnedToTop as Any), ("gifts", gifts as Any), ("nextOffset", nextOffset as Any), ("chats", chats as Any), ("users", users as Any)])
|
||||
}
|
||||
}
|
||||
|
||||
@ -47,29 +52,34 @@ public extension Api.payments {
|
||||
if Int(_1!) & Int(1 << 1) != 0 {if let signature = reader.readInt32() {
|
||||
_3 = Api.parse(reader, signature: signature) as? Api.Bool
|
||||
} }
|
||||
var _4: [Api.SavedStarGift]?
|
||||
var _4: [Int64]?
|
||||
if Int(_1!) & Int(1 << 2) != 0 {if let _ = reader.readInt32() {
|
||||
_4 = Api.parseVector(reader, elementSignature: 570911930, elementType: Int64.self)
|
||||
} }
|
||||
var _5: [Api.SavedStarGift]?
|
||||
if let _ = reader.readInt32() {
|
||||
_4 = Api.parseVector(reader, elementSignature: 0, elementType: Api.SavedStarGift.self)
|
||||
_5 = Api.parseVector(reader, elementSignature: 0, elementType: Api.SavedStarGift.self)
|
||||
}
|
||||
var _5: String?
|
||||
if Int(_1!) & Int(1 << 0) != 0 {_5 = parseString(reader) }
|
||||
var _6: [Api.Chat]?
|
||||
var _6: String?
|
||||
if Int(_1!) & Int(1 << 0) != 0 {_6 = parseString(reader) }
|
||||
var _7: [Api.Chat]?
|
||||
if let _ = reader.readInt32() {
|
||||
_6 = Api.parseVector(reader, elementSignature: 0, elementType: Api.Chat.self)
|
||||
_7 = Api.parseVector(reader, elementSignature: 0, elementType: Api.Chat.self)
|
||||
}
|
||||
var _7: [Api.User]?
|
||||
var _8: [Api.User]?
|
||||
if let _ = reader.readInt32() {
|
||||
_7 = Api.parseVector(reader, elementSignature: 0, elementType: Api.User.self)
|
||||
_8 = Api.parseVector(reader, elementSignature: 0, elementType: Api.User.self)
|
||||
}
|
||||
let _c1 = _1 != nil
|
||||
let _c2 = _2 != nil
|
||||
let _c3 = (Int(_1!) & Int(1 << 1) == 0) || _3 != nil
|
||||
let _c4 = _4 != nil
|
||||
let _c5 = (Int(_1!) & Int(1 << 0) == 0) || _5 != nil
|
||||
let _c6 = _6 != nil
|
||||
let _c4 = (Int(_1!) & Int(1 << 2) == 0) || _4 != nil
|
||||
let _c5 = _5 != nil
|
||||
let _c6 = (Int(_1!) & Int(1 << 0) == 0) || _6 != nil
|
||||
let _c7 = _7 != nil
|
||||
if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 {
|
||||
return Api.payments.SavedStarGifts.savedStarGifts(flags: _1!, count: _2!, chatNotificationsEnabled: _3, gifts: _4!, nextOffset: _5, chats: _6!, users: _7!)
|
||||
let _c8 = _8 != nil
|
||||
if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 && _c8 {
|
||||
return Api.payments.SavedStarGifts.savedStarGifts(flags: _1!, count: _2!, chatNotificationsEnabled: _3, pinnedToTop: _4, gifts: _5!, nextOffset: _6, chats: _7!, users: _8!)
|
||||
}
|
||||
else {
|
||||
return nil
|
||||
|
@ -9717,6 +9717,26 @@ public extension Api.functions.payments {
|
||||
})
|
||||
}
|
||||
}
|
||||
public extension Api.functions.payments {
|
||||
static func toggleStarGiftsPinnedToTop(peer: Api.InputPeer, stargift: [Api.InputSavedStarGift]) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.Bool>) {
|
||||
let buffer = Buffer()
|
||||
buffer.appendInt32(353626032)
|
||||
peer.serialize(buffer, true)
|
||||
buffer.appendInt32(481674261)
|
||||
buffer.appendInt32(Int32(stargift.count))
|
||||
for item in stargift {
|
||||
item.serialize(buffer, true)
|
||||
}
|
||||
return (FunctionDescription(name: "payments.toggleStarGiftsPinnedToTop", parameters: [("peer", String(describing: peer)), ("stargift", String(describing: stargift))]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.Bool? in
|
||||
let reader = BufferReader(buffer)
|
||||
var result: Api.Bool?
|
||||
if let signature = reader.readInt32() {
|
||||
result = Api.parse(reader, signature: signature) as? Api.Bool
|
||||
}
|
||||
return result
|
||||
})
|
||||
}
|
||||
}
|
||||
public extension Api.functions.payments {
|
||||
static func transferStarGift(stargift: Api.InputSavedStarGift, toId: Api.InputPeer) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.Updates>) {
|
||||
let buffer = Buffer()
|
||||
|
@ -129,6 +129,7 @@ public func standaloneSendEnqueueMessages(
|
||||
struct MessageResult {
|
||||
var result: PendingMessageUploadedContentResult
|
||||
var media: [Media]
|
||||
var attributes: [MessageAttribute]
|
||||
}
|
||||
|
||||
let signals: [Signal<MessageResult, PendingMessageUploadError>] = messages.map { message in
|
||||
@ -178,7 +179,10 @@ public func standaloneSendEnqueueMessages(
|
||||
if message.isSilent {
|
||||
attributes.append(NotificationInfoMessageAttribute(flags: .muted))
|
||||
}
|
||||
|
||||
if let sendPaidMessageStars = message.sendPaidMessageStars {
|
||||
attributes.append(PaidStarsMessageAttribute(stars: sendPaidMessageStars, postponeSending: false))
|
||||
}
|
||||
|
||||
let content = messageContentToUpload(accountPeerId: accountPeerId, network: network, postbox: postbox, auxiliaryMethods: auxiliaryMethods, transformOutgoingMessageMedia: { _, _, _, _ in
|
||||
return .single(nil)
|
||||
}, messageMediaPreuploadManager: MessageMediaPreuploadManager(), revalidationContext: MediaReferenceRevalidationContext(), forceReupload: false, isGrouped: false, passFetchProgress: true, forceNoBigParts: false, peerId: peerId, messageId: nil, attributes: attributes, text: text, media: media)
|
||||
@ -191,7 +195,7 @@ public func standaloneSendEnqueueMessages(
|
||||
}
|
||||
return contentResult
|
||||
|> map { contentResult in
|
||||
return MessageResult(result: contentResult, media: media)
|
||||
return MessageResult(result: contentResult, media: media, attributes: attributes)
|
||||
}
|
||||
}
|
||||
|
||||
@ -201,7 +205,7 @@ public func standaloneSendEnqueueMessages(
|
||||
}
|
||||
|> mapToSignal { contentResults -> Signal<StandaloneSendMessageStatus, StandaloneSendMessagesError> in
|
||||
var progressSum: Float = 0.0
|
||||
var allResults: [(result: PendingMessageUploadedContentAndReuploadInfo, media: [Media])] = []
|
||||
var allResults: [(result: PendingMessageUploadedContentAndReuploadInfo, media: [Media], attributes: [MessageAttribute])] = []
|
||||
var allDone = true
|
||||
for result in contentResults {
|
||||
switch result.result {
|
||||
@ -209,13 +213,13 @@ public func standaloneSendEnqueueMessages(
|
||||
allDone = false
|
||||
progressSum += value.progress
|
||||
case let .content(content):
|
||||
allResults.append((content, result.media))
|
||||
allResults.append((content, result.media, result.attributes))
|
||||
}
|
||||
}
|
||||
if allDone {
|
||||
var sendSignals: [Signal<Never, StandaloneSendMessagesError>] = []
|
||||
|
||||
for (content, media) in allResults {
|
||||
for (content, media, attributes) in allResults {
|
||||
var text: String = ""
|
||||
switch content.content {
|
||||
case let .text(textValue):
|
||||
@ -235,7 +239,7 @@ public func standaloneSendEnqueueMessages(
|
||||
peerId: peerId,
|
||||
content: content,
|
||||
text: text,
|
||||
attributes: [],
|
||||
attributes: attributes,
|
||||
media: media,
|
||||
threadId: threadId
|
||||
))
|
||||
@ -328,6 +332,7 @@ private func sendUploadedMessageContent(
|
||||
var videoTimestamp: Int32?
|
||||
var sendAsPeerId: PeerId?
|
||||
var bubbleUpEmojiOrStickersets = false
|
||||
var allowPaidStars: Int64?
|
||||
|
||||
var flags: Int32 = 0
|
||||
|
||||
@ -365,6 +370,8 @@ private func sendUploadedMessageContent(
|
||||
} else if let attribute = attribute as? ForwardVideoTimestampAttribute {
|
||||
flags |= Int32(1 << 20)
|
||||
videoTimestamp = attribute.timestamp
|
||||
} else if let attribute = attribute as? PaidStarsMessageAttribute {
|
||||
allowPaidStars = attribute.stars.value
|
||||
}
|
||||
}
|
||||
|
||||
@ -390,6 +397,11 @@ private func sendUploadedMessageContent(
|
||||
flags |= (1 << 13)
|
||||
}
|
||||
|
||||
if let _ = allowPaidStars {
|
||||
flags |= 1 << 21
|
||||
}
|
||||
|
||||
|
||||
let dependencyTag: PendingMessageRequestDependencyTag? = nil//(messageId: messageId)
|
||||
|
||||
let sendMessageRequest: Signal<NetworkRequestResult<Api.Updates>, MTRpcError>
|
||||
@ -415,7 +427,7 @@ private func sendUploadedMessageContent(
|
||||
}
|
||||
}
|
||||
|
||||
sendMessageRequest = network.requestWithAdditionalInfo(Api.functions.messages.sendMessage(flags: flags, peer: inputPeer, replyTo: replyTo, message: text, randomId: uniqueId, replyMarkup: nil, entities: messageEntities, scheduleDate: scheduleTime, sendAs: sendAsInputPeer, quickReplyShortcut: nil, effect: nil, allowPaidStars: nil), info: .acknowledgement, tag: dependencyTag)
|
||||
sendMessageRequest = network.requestWithAdditionalInfo(Api.functions.messages.sendMessage(flags: flags, peer: inputPeer, replyTo: replyTo, message: text, randomId: uniqueId, replyMarkup: nil, entities: messageEntities, scheduleDate: scheduleTime, sendAs: sendAsInputPeer, quickReplyShortcut: nil, effect: nil, allowPaidStars: allowPaidStars), info: .acknowledgement, tag: dependencyTag)
|
||||
case let .media(inputMedia, text):
|
||||
if bubbleUpEmojiOrStickersets {
|
||||
flags |= Int32(1 << 15)
|
||||
@ -437,7 +449,7 @@ private func sendUploadedMessageContent(
|
||||
}
|
||||
}
|
||||
|
||||
sendMessageRequest = network.request(Api.functions.messages.sendMedia(flags: flags, peer: inputPeer, replyTo: replyTo, media: inputMedia, message: text, randomId: uniqueId, replyMarkup: nil, entities: messageEntities, scheduleDate: scheduleTime, sendAs: sendAsInputPeer, quickReplyShortcut: nil, effect: nil, allowPaidStars: nil), tag: dependencyTag)
|
||||
sendMessageRequest = network.request(Api.functions.messages.sendMedia(flags: flags, peer: inputPeer, replyTo: replyTo, media: inputMedia, message: text, randomId: uniqueId, replyMarkup: nil, entities: messageEntities, scheduleDate: scheduleTime, sendAs: sendAsInputPeer, quickReplyShortcut: nil, effect: nil, allowPaidStars: allowPaidStars), tag: dependencyTag)
|
||||
|> map(NetworkRequestResult.result)
|
||||
case let .forward(sourceInfo):
|
||||
var topMsgId: Int32?
|
||||
@ -447,7 +459,7 @@ private func sendUploadedMessageContent(
|
||||
}
|
||||
|
||||
if let forwardSourceInfoAttribute = forwardSourceInfoAttribute, let sourcePeer = transaction.getPeer(forwardSourceInfoAttribute.messageId.peerId), let sourceInputPeer = apiInputPeer(sourcePeer) {
|
||||
sendMessageRequest = network.request(Api.functions.messages.forwardMessages(flags: flags, fromPeer: sourceInputPeer, id: [sourceInfo.messageId.id], randomId: [uniqueId], toPeer: inputPeer, topMsgId: topMsgId, scheduleDate: scheduleTime, sendAs: sendAsInputPeer, quickReplyShortcut: nil, videoTimestamp: videoTimestamp, allowPaidStars: nil), tag: dependencyTag)
|
||||
sendMessageRequest = network.request(Api.functions.messages.forwardMessages(flags: flags, fromPeer: sourceInputPeer, id: [sourceInfo.messageId.id], randomId: [uniqueId], toPeer: inputPeer, topMsgId: topMsgId, scheduleDate: scheduleTime, sendAs: sendAsInputPeer, quickReplyShortcut: nil, videoTimestamp: videoTimestamp, allowPaidStars: allowPaidStars), tag: dependencyTag)
|
||||
|> map(NetworkRequestResult.result)
|
||||
} else {
|
||||
sendMessageRequest = .fail(MTRpcError(errorCode: 400, errorDescription: "internal"))
|
||||
@ -473,7 +485,7 @@ private func sendUploadedMessageContent(
|
||||
}
|
||||
}
|
||||
|
||||
sendMessageRequest = network.request(Api.functions.messages.sendInlineBotResult(flags: flags, peer: inputPeer, replyTo: replyTo, randomId: uniqueId, queryId: chatContextResult.queryId, id: chatContextResult.id, scheduleDate: scheduleTime, sendAs: sendAsInputPeer, quickReplyShortcut: nil, allowPaidStars: nil))
|
||||
sendMessageRequest = network.request(Api.functions.messages.sendInlineBotResult(flags: flags, peer: inputPeer, replyTo: replyTo, randomId: uniqueId, queryId: chatContextResult.queryId, id: chatContextResult.id, scheduleDate: scheduleTime, sendAs: sendAsInputPeer, quickReplyShortcut: nil, allowPaidStars: allowPaidStars))
|
||||
|> map(NetworkRequestResult.result)
|
||||
case .messageScreenshot:
|
||||
let replyTo: Api.InputReplyTo
|
||||
@ -585,6 +597,7 @@ private func sendMessageContent(account: Account, peerId: PeerId, attributes: [M
|
||||
var replyToStoryId: StoryId?
|
||||
var scheduleTime: Int32?
|
||||
var sendAsPeerId: PeerId?
|
||||
var allowPaidStars: Int64?
|
||||
|
||||
var flags: Int32 = 0
|
||||
flags |= (1 << 7)
|
||||
@ -609,6 +622,8 @@ private func sendMessageContent(account: Account, peerId: PeerId, attributes: [M
|
||||
scheduleTime = attribute.scheduleTime
|
||||
} else if let attribute = attribute as? SendAsMessageAttribute {
|
||||
sendAsPeerId = attribute.peerId
|
||||
} else if let attribute = attribute as? PaidStarsMessageAttribute {
|
||||
allowPaidStars = attribute.stars.value
|
||||
}
|
||||
}
|
||||
|
||||
@ -622,6 +637,11 @@ private func sendMessageContent(account: Account, peerId: PeerId, attributes: [M
|
||||
flags |= (1 << 13)
|
||||
}
|
||||
|
||||
if let _ = allowPaidStars {
|
||||
flags |= 1 << 21
|
||||
}
|
||||
|
||||
|
||||
let sendMessageRequest: Signal<Api.Updates, NoError>
|
||||
switch content {
|
||||
case let .text(text):
|
||||
@ -641,7 +661,7 @@ private func sendMessageContent(account: Account, peerId: PeerId, attributes: [M
|
||||
replyTo = .inputReplyToMessage(flags: flags, replyToMsgId: threadId, topMsgId: threadId, replyToPeerId: nil, quoteText: nil, quoteEntities: nil, quoteOffset: nil)
|
||||
}
|
||||
|
||||
sendMessageRequest = account.network.request(Api.functions.messages.sendMessage(flags: flags, peer: inputPeer, replyTo: replyTo, message: text, randomId: uniqueId, replyMarkup: nil, entities: messageEntities, scheduleDate: scheduleTime, sendAs: sendAsInputPeer, quickReplyShortcut: nil, effect: nil, allowPaidStars: nil))
|
||||
sendMessageRequest = account.network.request(Api.functions.messages.sendMessage(flags: flags, peer: inputPeer, replyTo: replyTo, message: text, randomId: uniqueId, replyMarkup: nil, entities: messageEntities, scheduleDate: scheduleTime, sendAs: sendAsInputPeer, quickReplyShortcut: nil, effect: nil, allowPaidStars: allowPaidStars))
|
||||
|> `catch` { _ -> Signal<Api.Updates, NoError> in
|
||||
return .complete()
|
||||
}
|
||||
@ -662,7 +682,7 @@ private func sendMessageContent(account: Account, peerId: PeerId, attributes: [M
|
||||
replyTo = .inputReplyToMessage(flags: flags, replyToMsgId: threadId, topMsgId: threadId, replyToPeerId: nil, quoteText: nil, quoteEntities: nil, quoteOffset: nil)
|
||||
}
|
||||
|
||||
sendMessageRequest = account.network.request(Api.functions.messages.sendMedia(flags: flags, peer: inputPeer, replyTo: replyTo, media: inputMedia, message: text, randomId: uniqueId, replyMarkup: nil, entities: messageEntities, scheduleDate: scheduleTime, sendAs: sendAsInputPeer, quickReplyShortcut: nil, effect: nil, allowPaidStars: nil))
|
||||
sendMessageRequest = account.network.request(Api.functions.messages.sendMedia(flags: flags, peer: inputPeer, replyTo: replyTo, media: inputMedia, message: text, randomId: uniqueId, replyMarkup: nil, entities: messageEntities, scheduleDate: scheduleTime, sendAs: sendAsInputPeer, quickReplyShortcut: nil, effect: nil, allowPaidStars: allowPaidStars))
|
||||
|> `catch` { _ -> Signal<Api.Updates, NoError> in
|
||||
return .complete()
|
||||
}
|
||||
|
@ -25,6 +25,7 @@ public struct CachedChannelFlags: OptionSet {
|
||||
public static let paidMediaAllowed = CachedChannelFlags(rawValue: 1 << 11)
|
||||
public static let canViewStarsRevenue = CachedChannelFlags(rawValue: 1 << 12)
|
||||
public static let starGiftsAvailable = CachedChannelFlags(rawValue: 1 << 13)
|
||||
public static let paidMessagesAvailable = CachedChannelFlags(rawValue: 1 << 14)
|
||||
}
|
||||
|
||||
public struct CachedChannelParticipantsSummary: PostboxCoding, Equatable {
|
||||
|
@ -375,22 +375,18 @@ public extension TelegramEngine.EngineData.Item {
|
||||
}
|
||||
|
||||
var key: PostboxViewKey {
|
||||
return .cachedPeerData(peerId: self.id)
|
||||
return .peer(peerId: self.id, components: [.cachedData])
|
||||
}
|
||||
|
||||
func extract(view: PostboxView) -> Result {
|
||||
guard let view = view as? CachedPeerDataView else {
|
||||
guard let view = view as? PeerView else {
|
||||
preconditionFailure()
|
||||
}
|
||||
guard let cachedPeerData = view.cachedPeerData else {
|
||||
return nil
|
||||
}
|
||||
switch cachedPeerData {
|
||||
case let user as CachedUserData:
|
||||
return user.sendPaidMessageStars
|
||||
case let channel as CachedChannelData:
|
||||
if let cachedPeerData = view.cachedData as? CachedUserData {
|
||||
return cachedPeerData.sendPaidMessageStars
|
||||
} else if let channel = peerViewMainPeer(view) as? TelegramChannel {
|
||||
return channel.sendPaidMessageStars
|
||||
default:
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
@ -2,15 +2,15 @@ import Foundation
|
||||
import Postbox
|
||||
import SwiftSignalKit
|
||||
|
||||
func _internal_enqueueOutgoingMessageWithChatContextResult(account: Account, to peerId: PeerId, threadId: Int64?, botId: PeerId, result: ChatContextResult, replyToMessageId: EngineMessageReplySubject?, replyToStoryId: StoryId?, hideVia: Bool, silentPosting: Bool, scheduleTime: Int32?, correlationId: Int64?) -> Bool {
|
||||
guard let message = _internal_outgoingMessageWithChatContextResult(to: peerId, threadId: threadId, botId: botId, result: result, replyToMessageId: replyToMessageId, replyToStoryId: replyToStoryId, hideVia: hideVia, silentPosting: silentPosting, scheduleTime: scheduleTime, correlationId: correlationId) else {
|
||||
func _internal_enqueueOutgoingMessageWithChatContextResult(account: Account, to peerId: PeerId, threadId: Int64?, botId: PeerId, result: ChatContextResult, replyToMessageId: EngineMessageReplySubject?, replyToStoryId: StoryId?, hideVia: Bool, silentPosting: Bool, scheduleTime: Int32?, sendPaidMessageStars: StarsAmount?, postpone: Bool, correlationId: Int64?) -> Bool {
|
||||
guard let message = _internal_outgoingMessageWithChatContextResult(to: peerId, threadId: threadId, botId: botId, result: result, replyToMessageId: replyToMessageId, replyToStoryId: replyToStoryId, hideVia: hideVia, silentPosting: silentPosting, scheduleTime: scheduleTime, sendPaidMessageStars: sendPaidMessageStars, postpone: postpone, correlationId: correlationId) else {
|
||||
return false
|
||||
}
|
||||
let _ = enqueueMessages(account: account, peerId: peerId, messages: [message]).start()
|
||||
return true
|
||||
}
|
||||
|
||||
func _internal_outgoingMessageWithChatContextResult(to peerId: PeerId, threadId: Int64?, botId: PeerId, result: ChatContextResult, replyToMessageId: EngineMessageReplySubject?, replyToStoryId: StoryId?, hideVia: Bool, silentPosting: Bool, scheduleTime: Int32?, correlationId: Int64?) -> EnqueueMessage? {
|
||||
func _internal_outgoingMessageWithChatContextResult(to peerId: PeerId, threadId: Int64?, botId: PeerId, result: ChatContextResult, replyToMessageId: EngineMessageReplySubject?, replyToStoryId: StoryId?, hideVia: Bool, silentPosting: Bool, scheduleTime: Int32?, sendPaidMessageStars: StarsAmount?, postpone: Bool, correlationId: Int64?) -> EnqueueMessage? {
|
||||
var replyToMessageId = replyToMessageId
|
||||
if replyToMessageId == nil, let threadId = threadId {
|
||||
replyToMessageId = EngineMessageReplySubject(messageId: MessageId(peerId: peerId, namespace: Namespaces.Message.Cloud, id: MessageId.Id(clamping: threadId)), quote: nil)
|
||||
@ -32,6 +32,9 @@ func _internal_outgoingMessageWithChatContextResult(to peerId: PeerId, threadId:
|
||||
if silentPosting {
|
||||
attributes.append(NotificationInfoMessageAttribute(flags: .muted))
|
||||
}
|
||||
if let sendPaidMessageStars {
|
||||
attributes.append(PaidStarsMessageAttribute(stars: sendPaidMessageStars, postponeSending: postpone))
|
||||
}
|
||||
switch result.message {
|
||||
case let .auto(caption, entities, replyMarkup):
|
||||
if let entities = entities {
|
||||
|
@ -247,13 +247,14 @@ public extension TelegramEngine {
|
||||
storyId: StoryId? = nil,
|
||||
content: EngineOutgoingMessageContent,
|
||||
silentPosting: Bool = false,
|
||||
scheduleTime: Int32? = nil
|
||||
scheduleTime: Int32? = nil,
|
||||
sendPaidMessageStars: StarsAmount? = nil
|
||||
) -> Signal<[MessageId?], NoError> {
|
||||
var message: EnqueueMessage?
|
||||
if case let .preparedInlineMessage(preparedInlineMessage) = content {
|
||||
message = self.outgoingMessageWithChatContextResult(to: peerId, threadId: nil, botId: preparedInlineMessage.botId, result: preparedInlineMessage.result, replyToMessageId: replyToMessageId, replyToStoryId: storyId, hideVia: true, silentPosting: silentPosting, scheduleTime: scheduleTime, correlationId: nil)
|
||||
message = self.outgoingMessageWithChatContextResult(to: peerId, threadId: nil, botId: preparedInlineMessage.botId, result: preparedInlineMessage.result, replyToMessageId: replyToMessageId, replyToStoryId: storyId, hideVia: true, silentPosting: silentPosting, scheduleTime: scheduleTime, sendPaidMessageStars: sendPaidMessageStars, postpone: false, correlationId: nil)
|
||||
} else if case let .contextResult(results, result) = content {
|
||||
message = self.outgoingMessageWithChatContextResult(to: peerId, threadId: nil, botId: results.botId, result: result, replyToMessageId: replyToMessageId, replyToStoryId: storyId, hideVia: true, silentPosting: silentPosting, scheduleTime: scheduleTime, correlationId: nil)
|
||||
message = self.outgoingMessageWithChatContextResult(to: peerId, threadId: nil, botId: results.botId, result: result, replyToMessageId: replyToMessageId, replyToStoryId: storyId, hideVia: true, silentPosting: silentPosting, scheduleTime: scheduleTime, sendPaidMessageStars: sendPaidMessageStars, postpone: false, correlationId: nil)
|
||||
} else {
|
||||
var attributes: [MessageAttribute] = []
|
||||
if silentPosting {
|
||||
@ -262,6 +263,9 @@ public extension TelegramEngine {
|
||||
if let scheduleTime = scheduleTime {
|
||||
attributes.append(OutgoingScheduleInfoMessageAttribute(scheduleTime: scheduleTime))
|
||||
}
|
||||
if let sendPaidMessageStars {
|
||||
attributes.append(PaidStarsMessageAttribute(stars: sendPaidMessageStars, postponeSending: false))
|
||||
}
|
||||
|
||||
var text: String = ""
|
||||
var mediaReference: AnyMediaReference?
|
||||
@ -301,12 +305,12 @@ public extension TelegramEngine {
|
||||
)
|
||||
}
|
||||
|
||||
public func enqueueOutgoingMessageWithChatContextResult(to peerId: PeerId, threadId: Int64?, botId: PeerId, result: ChatContextResult, replyToMessageId: EngineMessageReplySubject? = nil, replyToStoryId: StoryId? = nil, hideVia: Bool = false, silentPosting: Bool = false, scheduleTime: Int32? = nil, correlationId: Int64? = nil) -> Bool {
|
||||
return _internal_enqueueOutgoingMessageWithChatContextResult(account: self.account, to: peerId, threadId: threadId, botId: botId, result: result, replyToMessageId: replyToMessageId, replyToStoryId: replyToStoryId, hideVia: hideVia, silentPosting: silentPosting, scheduleTime: scheduleTime, correlationId: correlationId)
|
||||
public func enqueueOutgoingMessageWithChatContextResult(to peerId: PeerId, threadId: Int64?, botId: PeerId, result: ChatContextResult, replyToMessageId: EngineMessageReplySubject? = nil, replyToStoryId: StoryId? = nil, hideVia: Bool = false, silentPosting: Bool = false, scheduleTime: Int32? = nil, sendPaidMessageStars: StarsAmount?, postpone: Bool = false, correlationId: Int64? = nil) -> Bool {
|
||||
return _internal_enqueueOutgoingMessageWithChatContextResult(account: self.account, to: peerId, threadId: threadId, botId: botId, result: result, replyToMessageId: replyToMessageId, replyToStoryId: replyToStoryId, hideVia: hideVia, silentPosting: silentPosting, scheduleTime: scheduleTime, sendPaidMessageStars: sendPaidMessageStars, postpone: postpone, correlationId: correlationId)
|
||||
}
|
||||
|
||||
public func outgoingMessageWithChatContextResult(to peerId: PeerId, threadId: Int64?, botId: PeerId, result: ChatContextResult, replyToMessageId: EngineMessageReplySubject?, replyToStoryId: StoryId?, hideVia: Bool, silentPosting: Bool, scheduleTime: Int32?, correlationId: Int64?) -> EnqueueMessage? {
|
||||
return _internal_outgoingMessageWithChatContextResult(to: peerId, threadId: threadId, botId: botId, result: result, replyToMessageId: replyToMessageId, replyToStoryId: replyToStoryId, hideVia: hideVia, silentPosting: silentPosting, scheduleTime: scheduleTime, correlationId: correlationId)
|
||||
public func outgoingMessageWithChatContextResult(to peerId: PeerId, threadId: Int64?, botId: PeerId, result: ChatContextResult, replyToMessageId: EngineMessageReplySubject?, replyToStoryId: StoryId?, hideVia: Bool, silentPosting: Bool, scheduleTime: Int32?, sendPaidMessageStars: StarsAmount?, postpone: Bool, correlationId: Int64?) -> EnqueueMessage? {
|
||||
return _internal_outgoingMessageWithChatContextResult(to: peerId, threadId: threadId, botId: botId, result: result, replyToMessageId: replyToMessageId, replyToStoryId: replyToStoryId, hideVia: hideVia, silentPosting: silentPosting, scheduleTime: scheduleTime, sendPaidMessageStars: sendPaidMessageStars, postpone: postpone, correlationId: correlationId)
|
||||
}
|
||||
|
||||
public func setMessageReactions(
|
||||
|
@ -1064,7 +1064,8 @@ private final class ProfileGiftsContextImpl {
|
||||
}
|
||||
return postbox.transaction { transaction -> ([ProfileGiftsContext.State.StarGift], Int32, String?, Bool?) in
|
||||
switch result {
|
||||
case let .savedStarGifts(_, count, apiNotificationsEnabled, apiGifts, nextOffset, chats, users):
|
||||
case let .savedStarGifts(_, count, apiNotificationsEnabled, pinnedToTop, apiGifts, nextOffset, chats, users):
|
||||
let _ = pinnedToTop
|
||||
let parsedPeers = AccumulatedPeers(transaction: transaction, chats: chats, users: users)
|
||||
updatePeers(transaction: transaction, accountPeerId: accountPeerId, peers: parsedPeers)
|
||||
|
||||
|
@ -99,8 +99,8 @@ func _internal_addGroupMember(account: Account, peerId: PeerId, memberId: PeerId
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
return TelegramInvitePeersResult(forbiddenPeers: missingInviteesValue.compactMap { invitee -> TelegramForbiddenInvitePeer? in
|
||||
|
||||
let result = TelegramInvitePeersResult(forbiddenPeers: missingInviteesValue.compactMap { invitee -> TelegramForbiddenInvitePeer? in
|
||||
switch invitee {
|
||||
case let .missingInvitee(flags, userId):
|
||||
guard let peer = transaction.getPeer(PeerId(namespace: Namespaces.Peer.CloudUser, id: PeerId.Id._internalFromInt64Value(userId))) else {
|
||||
@ -113,6 +113,10 @@ func _internal_addGroupMember(account: Account, peerId: PeerId, memberId: PeerId
|
||||
)
|
||||
}
|
||||
})
|
||||
|
||||
let _ = _internal_updateIsPremiumRequiredToContact(account: account, peerIds: result.forbiddenPeers.map { $0.peer.id }).startStandalone()
|
||||
|
||||
return result
|
||||
}
|
||||
|> mapError { _ -> AddGroupMemberError in }
|
||||
|> mapToSignal { result -> Signal<Void, AddGroupMemberError> in
|
||||
@ -186,6 +190,8 @@ func _internal_addChannelMember(account: Account, peerId: PeerId, memberId: Peer
|
||||
switch result {
|
||||
case let .invitedUsers(updates, missingInvitees):
|
||||
if case let .missingInvitee(flags, _) = missingInvitees.first {
|
||||
let _ = _internal_updateIsPremiumRequiredToContact(account: account, peerIds: [memberPeer.id]).startStandalone()
|
||||
|
||||
return .fail(.restricted(TelegramForbiddenInvitePeer(
|
||||
peer: EnginePeer(memberPeer),
|
||||
canInviteWithPremium: (flags & (1 << 0)) != 0,
|
||||
@ -302,7 +308,7 @@ func _internal_addChannelMembers(account: Account, peerId: PeerId, memberIds: [P
|
||||
account.viewTracker.forceUpdateCachedPeerData(peerId: peerId)
|
||||
|
||||
return account.postbox.transaction { transaction -> TelegramInvitePeersResult in
|
||||
return TelegramInvitePeersResult(forbiddenPeers: missingInviteesValue.compactMap { invitee -> TelegramForbiddenInvitePeer? in
|
||||
let result = TelegramInvitePeersResult(forbiddenPeers: missingInviteesValue.compactMap { invitee -> TelegramForbiddenInvitePeer? in
|
||||
switch invitee {
|
||||
case let .missingInvitee(flags, userId):
|
||||
guard let peer = transaction.getPeer(PeerId(namespace: Namespaces.Peer.CloudUser, id: PeerId.Id._internalFromInt64Value(userId))) else {
|
||||
@ -315,6 +321,8 @@ func _internal_addChannelMembers(account: Account, peerId: PeerId, memberIds: [P
|
||||
)
|
||||
}
|
||||
})
|
||||
let _ = _internal_updateIsPremiumRequiredToContact(account: account, peerIds: result.forbiddenPeers.map { $0.peer.id }).startStandalone()
|
||||
return result
|
||||
}
|
||||
|> castError(AddChannelMemberError.self)
|
||||
}
|
||||
|
@ -620,6 +620,10 @@ func _internal_fetchAndUpdateCachedPeerData(accountPeerId: PeerId, peerId rawPee
|
||||
if (flags2 & Int32(1 << 19)) != 0 {
|
||||
channelFlags.insert(.starGiftsAvailable)
|
||||
}
|
||||
if (flags2 & Int32(1 << 20)) != 0 {
|
||||
channelFlags.insert(.paidMessagesAvailable)
|
||||
}
|
||||
|
||||
let sendAsPeerId = defaultSendAs?.peerId
|
||||
|
||||
let linkedDiscussionPeerId: PeerId?
|
||||
|
@ -2877,7 +2877,7 @@ public class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePreviewI
|
||||
bottomBubbleAttributes = contentPropertiesAndLayouts[i + 1].3
|
||||
}
|
||||
|
||||
if i == 0 {
|
||||
if i == 0 || (i == 1 && contentPropertiesAndLayouts[0].1.isDetached) {
|
||||
topPosition = firstNodeTopPosition
|
||||
} else {
|
||||
topPosition = .Neighbour(topBubbleAttributes.isAttachment, topBubbleAttributes.neighborType, topBubbleAttributes.neighborSpacing)
|
||||
@ -3002,11 +3002,7 @@ public class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePreviewI
|
||||
}
|
||||
|
||||
let (size, apply) = finalize(maxContentWidth)
|
||||
var containerFrame = CGRect(origin: CGPoint(x: 0.0, y: contentNodeOriginY), size: size)
|
||||
if size.height == 33.0 && detachedContentNodesHeight > 0.0 {
|
||||
//TODO:unmock
|
||||
containerFrame = containerFrame.offsetBy(dx: 0.0, dy: 2.0)
|
||||
}
|
||||
let containerFrame = CGRect(origin: CGPoint(x: 0.0, y: contentNodeOriginY), size: size)
|
||||
contentNodeFramesPropertiesAndApply.append((containerFrame, properties, contentGroupId == nil, apply))
|
||||
|
||||
if contentProperties.neighborType == .media && unlockButtonPosition == nil {
|
||||
|
@ -328,23 +328,34 @@ private class ChatMessagePaymentAlertController: AlertController {
|
||||
self.context = context
|
||||
self.presentationData = presentationData
|
||||
self.parentNavigationController = navigationController
|
||||
|
||||
|
||||
super.init(theme: AlertControllerTheme(presentationData: presentationData), contentNode: contentNode)
|
||||
|
||||
self.willDismiss = { [weak self] in
|
||||
guard let self else {
|
||||
return
|
||||
}
|
||||
self.animateOut()
|
||||
}
|
||||
}
|
||||
|
||||
required public init(coder aDecoder: NSCoder) {
|
||||
preconditionFailure()
|
||||
}
|
||||
|
||||
override func dismissAnimated() {
|
||||
super.dismissAnimated()
|
||||
|
||||
private func animateOut() {
|
||||
if let view = self.balance.view {
|
||||
view.layer.animateScale(from: 1.0, to: 0.8, duration: 0.4, removeOnCompletion: false)
|
||||
view.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.3, removeOnCompletion: false)
|
||||
}
|
||||
}
|
||||
|
||||
override func dismissAnimated() {
|
||||
super.dismissAnimated()
|
||||
|
||||
self.animateOut()
|
||||
}
|
||||
|
||||
override func containerLayoutUpdated(_ layout: ContainerViewLayout, transition: ContainedViewLayoutTransition) {
|
||||
super.containerLayoutUpdated(layout, transition: transition)
|
||||
|
||||
|
@ -251,6 +251,9 @@ public final class ChatUserInfoItemNode: ListViewItemNode {
|
||||
|
||||
let infoConstrainedSize = CGSize(width: constrainedWidth * 0.7, height: CGFloat.greatestFiniteMagnitude)
|
||||
|
||||
var maxTitleWidth: CGFloat = 0.0
|
||||
var maxValueWidth: CGFloat = 0.0
|
||||
|
||||
var registrationDateText: String?
|
||||
let registrationDateTitleLayoutAndApply: (TextNodeLayout, () -> TextNode)?
|
||||
let registrationDateValueLayoutAndApply: (TextNodeLayout, () -> TextNode)?
|
||||
@ -272,7 +275,8 @@ public final class ChatUserInfoItemNode: ListViewItemNode {
|
||||
backgroundSize.height += verticalSpacing
|
||||
backgroundSize.height += registrationDateValueLayoutAndApply?.0.size.height ?? 0
|
||||
|
||||
backgroundSize.width = max(backgroundSize.width, horizontalContentInset * 2.0 + (registrationDateTitleLayoutAndApply?.0.size.width ?? 0) + attributeSpacing + (registrationDateValueLayoutAndApply?.0.size.width ?? 0))
|
||||
maxTitleWidth = max(maxTitleWidth, (registrationDateTitleLayoutAndApply?.0.size.width ?? 0))
|
||||
maxValueWidth = max(maxValueWidth, (registrationDateValueLayoutAndApply?.0.size.width ?? 0))
|
||||
} else {
|
||||
registrationDateTitleLayoutAndApply = nil
|
||||
registrationDateValueLayoutAndApply = nil
|
||||
@ -297,7 +301,8 @@ public final class ChatUserInfoItemNode: ListViewItemNode {
|
||||
backgroundSize.height += verticalSpacing
|
||||
backgroundSize.height += phoneCountryValueLayoutAndApply?.0.size.height ?? 0
|
||||
|
||||
backgroundSize.width = max(backgroundSize.width, horizontalContentInset * 2.0 + (phoneCountryTitleLayoutAndApply?.0.size.width ?? 0) + attributeSpacing + (phoneCountryValueLayoutAndApply?.0.size.width ?? 0))
|
||||
maxTitleWidth = max(maxTitleWidth, (phoneCountryTitleLayoutAndApply?.0.size.width ?? 0))
|
||||
maxValueWidth = max(maxValueWidth, (phoneCountryValueLayoutAndApply?.0.size.width ?? 0))
|
||||
} else {
|
||||
phoneCountryTitleLayoutAndApply = nil
|
||||
phoneCountryValueLayoutAndApply = nil
|
||||
@ -322,12 +327,15 @@ public final class ChatUserInfoItemNode: ListViewItemNode {
|
||||
backgroundSize.height += verticalSpacing
|
||||
backgroundSize.height += locationCountryValueLayoutAndApply?.0.size.height ?? 0
|
||||
|
||||
backgroundSize.width = max(backgroundSize.width, horizontalContentInset * 2.0 + (locationCountryTitleLayoutAndApply?.0.size.width ?? 0) + attributeSpacing + (locationCountryValueLayoutAndApply?.0.size.width ?? 0))
|
||||
maxTitleWidth = max(maxTitleWidth, (locationCountryTitleLayoutAndApply?.0.size.width ?? 0))
|
||||
maxValueWidth = max(maxValueWidth, (locationCountryValueLayoutAndApply?.0.size.width ?? 0))
|
||||
} else {
|
||||
locationCountryTitleLayoutAndApply = nil
|
||||
locationCountryValueLayoutAndApply = nil
|
||||
}
|
||||
|
||||
backgroundSize.width = horizontalContentInset * 3.0 + maxTitleWidth + attributeSpacing + maxValueWidth
|
||||
|
||||
let (groupsLayout, groupsApply) = makeGroupsLayout(TextNodeLayoutArguments(attributedString: NSAttributedString(string: "No groups in common", font: Font.regular(13.0), textColor: subtitleColor), backgroundColor: nil, maximumNumberOfLines: 0, truncationType: .end, constrainedSize: CGSize(width: constrainedWidth, height: CGFloat.greatestFiniteMagnitude), alignment: .natural, cutout: nil, insets: UIEdgeInsets()))
|
||||
backgroundSize.height += verticalSpacing * 2.0 + paragraphSpacing
|
||||
backgroundSize.height += groupsLayout.size.height
|
||||
|
@ -502,9 +502,7 @@ final class GiftOptionsScreenComponent: Component {
|
||||
return
|
||||
}
|
||||
|
||||
//TODO:unmock
|
||||
let context = component.context
|
||||
|
||||
let alertController = giftTransferAlertController(
|
||||
context: context,
|
||||
gift: transferGift,
|
||||
@ -517,36 +515,53 @@ final class GiftOptionsScreenComponent: Component {
|
||||
guard let controller, let navigationController = controller.navigationController as? NavigationController else {
|
||||
return
|
||||
}
|
||||
var controllers = navigationController.viewControllers
|
||||
controllers = controllers.filter { !($0 is ContactSelectionController) && !($0 is GiftOptionsScreen) }
|
||||
|
||||
if peer.id.namespace == Namespaces.Peer.CloudChannel {
|
||||
if let controller = context.sharedContext.makePeerInfoController(
|
||||
context: context,
|
||||
updatedPresentationData: nil,
|
||||
peer: peer._asPeer(),
|
||||
mode: .gifts,
|
||||
avatarInitiallyExpanded: false,
|
||||
fromChat: false,
|
||||
requestsContext: nil
|
||||
) {
|
||||
controllers.append(controller)
|
||||
}
|
||||
} else {
|
||||
var controllers = navigationController.viewControllers
|
||||
controllers = controllers.filter { !($0 is GiftSetupScreen) && !($0 is GiftOptionsScreenProtocol) }
|
||||
var foundController = false
|
||||
for controller in controllers.reversed() {
|
||||
if let chatController = controller as? ChatController, case .peer(id: peer.id) = chatController.chatLocation {
|
||||
if let controller = controller as? PeerInfoScreen, controller.peerId == component.peerId {
|
||||
foundController = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !foundController {
|
||||
if let controller = context.sharedContext.makePeerInfoController(
|
||||
context: context,
|
||||
updatedPresentationData: nil,
|
||||
peer: peer._asPeer(),
|
||||
mode: .gifts,
|
||||
avatarInitiallyExpanded: false,
|
||||
fromChat: false,
|
||||
requestsContext: nil
|
||||
) {
|
||||
controllers.append(controller)
|
||||
}
|
||||
}
|
||||
navigationController.setViewControllers(controllers, animated: true)
|
||||
} else {
|
||||
var controllers = navigationController.viewControllers
|
||||
controllers = controllers.filter { !($0 is GiftSetupScreen) && !($0 is GiftOptionsScreenProtocol) && !($0 is PeerInfoScreen) && !($0 is ContactSelectionController) }
|
||||
var foundController = false
|
||||
for controller in controllers.reversed() {
|
||||
if let chatController = controller as? ChatController, case .peer(id: component.peerId) = chatController.chatLocation {
|
||||
chatController.hintPlayNextOutgoingGift()
|
||||
foundController = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !foundController {
|
||||
let chatController = context.sharedContext.makeChatController(context: context, chatLocation: .peer(id: peer.id), subject: nil, botStart: nil, mode: .standard(.default), params: nil)
|
||||
let chatController = component.context.sharedContext.makeChatController(context: component.context, chatLocation: .peer(id: component.peerId), subject: nil, botStart: nil, mode: .standard(.default), params: nil)
|
||||
chatController.hintPlayNextOutgoingGift()
|
||||
controllers.append(chatController)
|
||||
}
|
||||
navigationController.setViewControllers(controllers, animated: true)
|
||||
}
|
||||
|
||||
if let completion = component.completion {
|
||||
completion()
|
||||
}
|
||||
navigationController.setViewControllers(controllers, animated: true)
|
||||
}
|
||||
)
|
||||
controller.present(alertController, in: .window(.root))
|
||||
|
@ -253,7 +253,7 @@ public func presentedLegacyShortcutCamera(context: AccountContext, saveCapturedM
|
||||
nativeGenerator(_1, _2, _3, nil)
|
||||
})
|
||||
if let parentController = parentController {
|
||||
parentController.present(ShareController(context: context, subject: .fromExternal({ peerIds, _, text, account, silently in
|
||||
parentController.present(ShareController(context: context, subject: .fromExternal(1, { peerIds, _, _, text, account, silently in
|
||||
guard let account = account as? ShareControllerAppAccountContext else {
|
||||
return .single(.done)
|
||||
}
|
||||
|
@ -214,6 +214,7 @@ public class LegacyMessageInputPanelNode: ASDisplayNode, TGCaptionPanelView {
|
||||
strings: presentationData.strings,
|
||||
style: .media,
|
||||
placeholder: .plain(presentationData.strings.MediaPicker_AddCaption),
|
||||
sendPaidMessageStars: nil,
|
||||
maxLength: Int(self.context.userLimits.maxCaptionLength),
|
||||
queryTypes: [.mention, .hashtag],
|
||||
alwaysDarkWhenHasText: false,
|
||||
|
@ -1365,6 +1365,7 @@ final class MediaEditorScreenComponent: Component {
|
||||
strings: environment.strings,
|
||||
style: .editor,
|
||||
placeholder: .plain(environment.strings.Story_Editor_InputPlaceholderAddCaption),
|
||||
sendPaidMessageStars: nil,
|
||||
maxLength: Int(component.context.userLimits.maxStoryCaptionLength),
|
||||
queryTypes: [.mention, .hashtag],
|
||||
alwaysDarkWhenHasText: false,
|
||||
|
@ -251,6 +251,7 @@ final class StoryPreviewComponent: Component {
|
||||
strings: presentationData.strings,
|
||||
style: .story,
|
||||
placeholder: .plain(presentationData.strings.Story_InputPlaceholderReplyPrivately),
|
||||
sendPaidMessageStars: nil,
|
||||
maxLength: nil,
|
||||
queryTypes: [],
|
||||
alwaysDarkWhenHasText: false,
|
||||
|
@ -160,6 +160,7 @@ public final class MessageInputPanelComponent: Component {
|
||||
public let strings: PresentationStrings
|
||||
public let style: Style
|
||||
public let placeholder: Placeholder
|
||||
public let sendPaidMessageStars: StarsAmount?
|
||||
public let maxLength: Int?
|
||||
public let queryTypes: ContextQueryTypes
|
||||
public let alwaysDarkWhenHasText: Bool
|
||||
@ -218,6 +219,7 @@ public final class MessageInputPanelComponent: Component {
|
||||
strings: PresentationStrings,
|
||||
style: Style,
|
||||
placeholder: Placeholder,
|
||||
sendPaidMessageStars: StarsAmount?,
|
||||
maxLength: Int?,
|
||||
queryTypes: ContextQueryTypes,
|
||||
alwaysDarkWhenHasText: Bool,
|
||||
@ -276,6 +278,7 @@ public final class MessageInputPanelComponent: Component {
|
||||
self.style = style
|
||||
self.nextInputMode = nextInputMode
|
||||
self.placeholder = placeholder
|
||||
self.sendPaidMessageStars = sendPaidMessageStars
|
||||
self.maxLength = maxLength
|
||||
self.queryTypes = queryTypes
|
||||
self.alwaysDarkWhenHasText = alwaysDarkWhenHasText
|
||||
@ -346,6 +349,9 @@ public final class MessageInputPanelComponent: Component {
|
||||
if lhs.placeholder != rhs.placeholder {
|
||||
return false
|
||||
}
|
||||
if lhs.sendPaidMessageStars != rhs.sendPaidMessageStars {
|
||||
return false
|
||||
}
|
||||
if lhs.maxLength != rhs.maxLength {
|
||||
return false
|
||||
}
|
||||
@ -849,43 +855,75 @@ public final class MessageInputPanelComponent: Component {
|
||||
)
|
||||
let isEditing = self.textFieldExternalState.isEditing || component.forceIsEditing
|
||||
|
||||
var placeholderItems: [AnimatedTextComponent.Item] = []
|
||||
switch component.placeholder {
|
||||
case let .plain(string):
|
||||
placeholderItems.append(AnimatedTextComponent.Item(id: AnyHashable(0 as Int), content: .text(string)))
|
||||
case let .counter(items):
|
||||
for item in items {
|
||||
switch item.content {
|
||||
case let .text(string):
|
||||
placeholderItems.append(AnimatedTextComponent.Item(id: AnyHashable(item.id), content: .text(string)))
|
||||
case let .number(value, minDigits):
|
||||
placeholderItems.append(AnimatedTextComponent.Item(id: AnyHashable(item.id), content: .number(value, minDigits: minDigits)))
|
||||
let placeholderTransition: ComponentTransition = (previousPlaceholder != nil && previousPlaceholder != component.placeholder) ? ComponentTransition(animation: .curve(duration: 0.3, curve: .spring)) : .immediate
|
||||
let placeholderSize: CGSize
|
||||
if case let .plain(string) = component.placeholder, string.contains("#") {
|
||||
let attributedPlaceholder = NSMutableAttributedString(string: string, font:Font.regular(17.0), textColor: UIColor(rgb: 0xffffff, alpha: 0.3))
|
||||
if let range = attributedPlaceholder.string.range(of: "#") {
|
||||
attributedPlaceholder.addAttribute(.attachment, value: PresentationResourcesChat.chatPlaceholderStarIcon(component.theme)!, range: NSRange(range, in: attributedPlaceholder.string))
|
||||
attributedPlaceholder.addAttribute(.foregroundColor, value: UIColor(rgb: 0xffffff, alpha: 0.3), range: NSRange(range, in: attributedPlaceholder.string))
|
||||
attributedPlaceholder.addAttribute(.baselineOffset, value: 1.0, range: NSRange(range, in: attributedPlaceholder.string))
|
||||
}
|
||||
|
||||
placeholderSize = self.placeholder.update(
|
||||
transition: placeholderTransition,
|
||||
component: AnyComponent(MultilineTextComponent(text: .plain(attributedPlaceholder))),
|
||||
environment: {},
|
||||
containerSize: availableTextFieldSize
|
||||
)
|
||||
|
||||
let vibrancyAttributedPlaceholder = NSMutableAttributedString(string: string, font:Font.regular(17.0), textColor: UIColor.black)
|
||||
if let range = vibrancyAttributedPlaceholder.string.range(of: "#") {
|
||||
vibrancyAttributedPlaceholder.addAttribute(.attachment, value: PresentationResourcesChat.chatPlaceholderStarIcon(component.theme)!, range: NSRange(range, in: vibrancyAttributedPlaceholder.string))
|
||||
vibrancyAttributedPlaceholder.addAttribute(.foregroundColor, value: UIColor.black, range: NSRange(range, in: vibrancyAttributedPlaceholder.string))
|
||||
vibrancyAttributedPlaceholder.addAttribute(.baselineOffset, value: 1.0, range: NSRange(range, in: vibrancyAttributedPlaceholder.string))
|
||||
}
|
||||
|
||||
let _ = self.vibrancyPlaceholder.update(
|
||||
transition: placeholderTransition,
|
||||
component: AnyComponent(MultilineTextComponent(text: .plain(attributedPlaceholder))),
|
||||
environment: {},
|
||||
containerSize: availableTextFieldSize
|
||||
)
|
||||
} else {
|
||||
var placeholderItems: [AnimatedTextComponent.Item] = []
|
||||
switch component.placeholder {
|
||||
case let .plain(string):
|
||||
placeholderItems.append(AnimatedTextComponent.Item(id: AnyHashable(0 as Int), content: .text(string)))
|
||||
case let .counter(items):
|
||||
for item in items {
|
||||
switch item.content {
|
||||
case let .text(string):
|
||||
placeholderItems.append(AnimatedTextComponent.Item(id: AnyHashable(item.id), content: .text(string)))
|
||||
case let .number(value, minDigits):
|
||||
placeholderItems.append(AnimatedTextComponent.Item(id: AnyHashable(item.id), content: .number(value, minDigits: minDigits)))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
placeholderSize = self.placeholder.update(
|
||||
transition: placeholderTransition,
|
||||
component: AnyComponent(AnimatedTextComponent(
|
||||
font: Font.regular(17.0),
|
||||
color: UIColor(rgb: 0xffffff, alpha: 0.3),
|
||||
items: placeholderItems
|
||||
)),
|
||||
environment: {},
|
||||
containerSize: availableTextFieldSize
|
||||
)
|
||||
|
||||
let _ = self.vibrancyPlaceholder.update(
|
||||
transition: placeholderTransition,
|
||||
component: AnyComponent(AnimatedTextComponent(
|
||||
font: Font.regular(17.0),
|
||||
color: .black,
|
||||
items: placeholderItems
|
||||
)),
|
||||
environment: {},
|
||||
containerSize: availableTextFieldSize
|
||||
)
|
||||
}
|
||||
|
||||
let placeholderTransition: ComponentTransition = (previousPlaceholder != nil && previousPlaceholder != component.placeholder) ? ComponentTransition(animation: .curve(duration: 0.3, curve: .spring)) : .immediate
|
||||
let placeholderSize = self.placeholder.update(
|
||||
transition: placeholderTransition,
|
||||
component: AnyComponent(AnimatedTextComponent(
|
||||
font: Font.regular(17.0),
|
||||
color: UIColor(rgb: 0xffffff, alpha: 0.3),
|
||||
items: placeholderItems
|
||||
)),
|
||||
environment: {},
|
||||
containerSize: availableTextFieldSize
|
||||
)
|
||||
|
||||
let _ = self.vibrancyPlaceholder.update(
|
||||
transition: placeholderTransition,
|
||||
component: AnyComponent(AnimatedTextComponent(
|
||||
font: Font.regular(17.0),
|
||||
color: .black,
|
||||
items: placeholderItems
|
||||
)),
|
||||
environment: {},
|
||||
containerSize: availableTextFieldSize
|
||||
)
|
||||
if !isEditing && component.setMediaRecordingActive == nil {
|
||||
insets.right = defaultInsets.left
|
||||
}
|
||||
|
@ -31,6 +31,7 @@ swift_library(
|
||||
"//submodules/PeerPresenceStatusManager",
|
||||
"//submodules/UndoUI",
|
||||
"//submodules/AnimatedAvatarSetNode",
|
||||
"//submodules/TelegramUI/Components/Chat/ChatMessagePaymentAlertController",
|
||||
],
|
||||
visibility = [
|
||||
"//visibility:public",
|
||||
|
@ -17,6 +17,7 @@ import UndoUI
|
||||
import AnimatedAvatarSetNode
|
||||
import AvatarNode
|
||||
import TelegramStringFormatting
|
||||
import ChatMessagePaymentAlertController
|
||||
|
||||
private final class SendInviteLinkScreenComponent: Component {
|
||||
typealias EnvironmentType = ViewControllerComponentContainer.Environment
|
||||
@ -26,19 +27,22 @@ private final class SendInviteLinkScreenComponent: Component {
|
||||
let link: String?
|
||||
let peers: [TelegramForbiddenInvitePeer]
|
||||
let peerPresences: [EnginePeer.Id: EnginePeer.Presence]
|
||||
let sendPaidMessageStars: [EnginePeer.Id: StarsAmount]
|
||||
|
||||
init(
|
||||
context: AccountContext,
|
||||
peer: EnginePeer,
|
||||
link: String?,
|
||||
peers: [TelegramForbiddenInvitePeer],
|
||||
peerPresences: [EnginePeer.Id: EnginePeer.Presence]
|
||||
peerPresences: [EnginePeer.Id: EnginePeer.Presence],
|
||||
sendPaidMessageStars: [EnginePeer.Id: StarsAmount]
|
||||
) {
|
||||
self.context = context
|
||||
self.peer = peer
|
||||
self.link = link
|
||||
self.peers = peers
|
||||
self.peerPresences = peerPresences
|
||||
self.sendPaidMessageStars = sendPaidMessageStars
|
||||
}
|
||||
|
||||
static func ==(lhs: SendInviteLinkScreenComponent, rhs: SendInviteLinkScreenComponent) -> Bool {
|
||||
@ -54,6 +58,9 @@ private final class SendInviteLinkScreenComponent: Component {
|
||||
if lhs.peerPresences != rhs.peerPresences {
|
||||
return false
|
||||
}
|
||||
if lhs.sendPaidMessageStars != rhs.sendPaidMessageStars {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
@ -266,6 +273,38 @@ private final class SendInviteLinkScreenComponent: Component {
|
||||
}
|
||||
}
|
||||
|
||||
private func presentPaidMessageAlertIfNeeded(peers: [EnginePeer], requiresStars: [EnginePeer.Id: StarsAmount], completion: @escaping () -> Void) {
|
||||
guard let component = self.component else {
|
||||
completion()
|
||||
return
|
||||
}
|
||||
var totalAmount: StarsAmount = .zero
|
||||
for peer in peers {
|
||||
if let amount = requiresStars[peer.id] {
|
||||
totalAmount = totalAmount + amount
|
||||
}
|
||||
}
|
||||
if totalAmount.value > 0 {
|
||||
let controller = chatMessagePaymentAlertController(
|
||||
context: component.context,
|
||||
presentationData: component.context.sharedContext.currentPresentationData.with { $0 },
|
||||
updatedPresentationData: nil,
|
||||
peers: peers,
|
||||
count: 1,
|
||||
amount: totalAmount,
|
||||
totalAmount: totalAmount,
|
||||
hasCheck: false,
|
||||
navigationController: self.environment?.controller()?.navigationController as? NavigationController,
|
||||
completion: { _ in
|
||||
completion()
|
||||
}
|
||||
)
|
||||
self.environment?.controller()?.present(controller, in: .window(.root))
|
||||
} else {
|
||||
completion()
|
||||
}
|
||||
}
|
||||
|
||||
func update(component: SendInviteLinkScreenComponent, availableSize: CGSize, state: EmptyComponentState, environment: Environment<ViewControllerComponentContainer.Environment>, transition: ComponentTransition) -> CGSize {
|
||||
let environment = environment[ViewControllerComponentContainer.Environment.self].value
|
||||
let themeUpdated = self.environment?.theme !== environment.theme
|
||||
@ -851,20 +890,37 @@ private final class SendInviteLinkScreenComponent: Component {
|
||||
} else if let link = component.link {
|
||||
let selectedPeers = component.peers.filter { self.selectedItems.contains($0.peer.id) }
|
||||
|
||||
let _ = enqueueMessagesToMultiplePeers(account: component.context.account, peerIds: Array(self.selectedItems), threadIds: [:], messages: [.message(text: link, attributes: [], inlineStickers: [:], mediaReference: nil, threadId: nil, replyToMessageId: nil, replyToStoryId: nil, localGroupingKey: nil, correlationId: nil, bubbleUpEmojiOrStickersets: [])]).start()
|
||||
let text: String
|
||||
if selectedPeers.count == 1 {
|
||||
text = environment.strings.Conversation_ShareLinkTooltip_Chat_One(selectedPeers[0].peer.displayTitle(strings: environment.strings, displayOrder: .firstLast).replacingOccurrences(of: "*", with: "")).string
|
||||
} else if selectedPeers.count == 2 {
|
||||
text = environment.strings.Conversation_ShareLinkTooltip_TwoChats_One(selectedPeers[0].peer.displayTitle(strings: environment.strings, displayOrder: .firstLast).replacingOccurrences(of: "*", with: ""), selectedPeers[1].peer.displayTitle(strings: environment.strings, displayOrder: .firstLast).replacingOccurrences(of: "*", with: "")).string
|
||||
} else {
|
||||
text = environment.strings.Conversation_ShareLinkTooltip_ManyChats_One(selectedPeers[0].peer.displayTitle(strings: environment.strings, displayOrder: .firstLast).replacingOccurrences(of: "*", with: ""), "\(selectedPeers.count - 1)").string
|
||||
}
|
||||
|
||||
let presentationData = component.context.sharedContext.currentPresentationData.with { $0 }
|
||||
controller.present(UndoOverlayController(presentationData: presentationData, content: .forward(savedMessages: false, text: text), elevatedLayout: false, action: { _ in return false }), in: .window(.root))
|
||||
|
||||
controller.dismiss()
|
||||
self.presentPaidMessageAlertIfNeeded(
|
||||
peers: selectedPeers.map { $0.peer },
|
||||
requiresStars: component.sendPaidMessageStars,
|
||||
completion: { [weak self] in
|
||||
guard let self, let component = self.component, let controller = self.environment?.controller() else {
|
||||
return
|
||||
}
|
||||
|
||||
for peerId in Array(self.selectedItems) {
|
||||
var messageAttributes: [EngineMessage.Attribute] = []
|
||||
if let sendPaidMessageStars = component.sendPaidMessageStars[peerId] {
|
||||
messageAttributes.append(PaidStarsMessageAttribute(stars: sendPaidMessageStars, postponeSending: false))
|
||||
}
|
||||
let _ = enqueueMessages(account: component.context.account, peerId: peerId, messages: [.message(text: link, attributes: messageAttributes, inlineStickers: [:], mediaReference: nil, threadId: nil, replyToMessageId: nil, replyToStoryId: nil, localGroupingKey: nil, correlationId: nil, bubbleUpEmojiOrStickersets: [])]).startStandalone()
|
||||
}
|
||||
|
||||
let text: String
|
||||
if selectedPeers.count == 1 {
|
||||
text = environment.strings.Conversation_ShareLinkTooltip_Chat_One(selectedPeers[0].peer.displayTitle(strings: environment.strings, displayOrder: .firstLast).replacingOccurrences(of: "*", with: "")).string
|
||||
} else if selectedPeers.count == 2 {
|
||||
text = environment.strings.Conversation_ShareLinkTooltip_TwoChats_One(selectedPeers[0].peer.displayTitle(strings: environment.strings, displayOrder: .firstLast).replacingOccurrences(of: "*", with: ""), selectedPeers[1].peer.displayTitle(strings: environment.strings, displayOrder: .firstLast).replacingOccurrences(of: "*", with: "")).string
|
||||
} else {
|
||||
text = environment.strings.Conversation_ShareLinkTooltip_ManyChats_One(selectedPeers[0].peer.displayTitle(strings: environment.strings, displayOrder: .firstLast).replacingOccurrences(of: "*", with: ""), "\(selectedPeers.count - 1)").string
|
||||
}
|
||||
|
||||
let presentationData = component.context.sharedContext.currentPresentationData.with { $0 }
|
||||
controller.present(UndoOverlayController(presentationData: presentationData, content: .forward(savedMessages: false, text: text), elevatedLayout: false, action: { _ in return false }), in: .window(.root))
|
||||
|
||||
controller.dismiss()
|
||||
}
|
||||
)
|
||||
} else {
|
||||
controller.dismiss()
|
||||
}
|
||||
@ -1083,16 +1139,21 @@ public class SendInviteLinkScreen: ViewControllerComponentContainer {
|
||||
self.link = link
|
||||
self.peers = peers
|
||||
|
||||
super.init(context: context, component: SendInviteLinkScreenComponent(context: context, peer: peer, link: link, peers: peers, peerPresences: [:]), navigationBarAppearance: .none)
|
||||
super.init(context: context, component: SendInviteLinkScreenComponent(context: context, peer: peer, link: link, peers: peers, peerPresences: [:], sendPaidMessageStars: [:]), navigationBarAppearance: .none)
|
||||
|
||||
self.statusBar.statusBarStyle = .Ignore
|
||||
self.navigationPresentation = .flatModal
|
||||
self.blocksBackgroundWhenInOverlay = true
|
||||
|
||||
self.presenceDisposable = (context.engine.data.subscribe(EngineDataMap(
|
||||
peers.map(\.peer.id).map(TelegramEngine.EngineData.Item.Peer.Presence.init(id:))
|
||||
))
|
||||
|> deliverOnMainQueue).start(next: { [weak self] presences in
|
||||
self.presenceDisposable = (context.engine.data.subscribe(
|
||||
EngineDataMap(
|
||||
peers.map(\.peer.id).map(TelegramEngine.EngineData.Item.Peer.Presence.init(id:))
|
||||
),
|
||||
EngineDataMap(
|
||||
peers.map(\.peer.id).map(TelegramEngine.EngineData.Item.Peer.SendPaidMessageStars.init(id:))
|
||||
)
|
||||
)
|
||||
|> deliverOnMainQueue).start(next: { [weak self] presences, sendPaidMessageStars in
|
||||
guard let self else {
|
||||
return
|
||||
}
|
||||
@ -1102,7 +1163,13 @@ public class SendInviteLinkScreen: ViewControllerComponentContainer {
|
||||
parsedPresences[id] = presence
|
||||
}
|
||||
}
|
||||
self.updateComponent(component: AnyComponent(SendInviteLinkScreenComponent(context: context, peer: peer, link: link, peers: peers, peerPresences: parsedPresences)), transition: .immediate)
|
||||
var parsedSendPaidMessageStars: [EnginePeer.Id: StarsAmount] = [:]
|
||||
for (id, sendPaidMessageStars) in sendPaidMessageStars {
|
||||
if let sendPaidMessageStars {
|
||||
parsedSendPaidMessageStars[id] = sendPaidMessageStars
|
||||
}
|
||||
}
|
||||
self.updateComponent(component: AnyComponent(SendInviteLinkScreenComponent(context: context, peer: peer, link: link, peers: peers, peerPresences: parsedPresences, sendPaidMessageStars: parsedSendPaidMessageStars)), transition: .immediate)
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -525,8 +525,8 @@ public class ShareRootControllerImpl {
|
||||
} |> runOn(Queue.mainQueue())
|
||||
}
|
||||
|
||||
let sentItems: ([PeerId], [PeerId: Int64], [PreparedShareItemContent], ShareControllerAccountContext, Bool, String) -> Signal<ShareControllerExternalStatus, NoError> = { peerIds, threadIds, contents, account, silently, additionalText in
|
||||
let sentItems = sentShareItems(accountPeerId: account.accountPeerId, postbox: account.stateManager.postbox, network: account.stateManager.network, stateManager: account.stateManager, auxiliaryMethods: makeTelegramAccountAuxiliaryMethods(uploadInBackground: nil), to: peerIds, threadIds: threadIds, items: contents, silently: silently, additionalText: additionalText)
|
||||
let sentItems: ([PeerId], [PeerId: Int64], [PeerId: StarsAmount], [PreparedShareItemContent], ShareControllerAccountContext, Bool, String) -> Signal<ShareControllerExternalStatus, NoError> = { peerIds, threadIds, requireStars, contents, account, silently, additionalText in
|
||||
let sentItems = sentShareItems(accountPeerId: account.accountPeerId, postbox: account.stateManager.postbox, network: account.stateManager.network, stateManager: account.stateManager, auxiliaryMethods: makeTelegramAccountAuxiliaryMethods(uploadInBackground: nil), to: peerIds, threadIds: threadIds, requireStars: requireStars, items: contents, silently: silently, additionalText: additionalText)
|
||||
|> `catch` { _ -> Signal<
|
||||
Float, NoError> in
|
||||
return .complete()
|
||||
@ -537,8 +537,20 @@ public class ShareRootControllerImpl {
|
||||
}
|
||||
|> then(.single(.done))
|
||||
}
|
||||
|
||||
let shareController = ShareController(environment: environment, currentContext: context, subject: .fromExternal({ peerIds, threadIds, additionalText, account, silently in
|
||||
|
||||
var itemCount = 1
|
||||
|
||||
if let extensionItems = self?.getExtensionContext()?.inputItems as? [NSExtensionItem] {
|
||||
for item in extensionItems {
|
||||
if let attachments = item.attachments {
|
||||
itemCount = 0
|
||||
for _ in attachments {
|
||||
itemCount += 1
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
let shareController = ShareController(environment: environment, currentContext: context, subject: .fromExternal(itemCount, { peerIds, threadIds, requireStars, additionalText, account, silently in
|
||||
if let strongSelf = self, let inputItems = strongSelf.getExtensionContext()?.inputItems, !inputItems.isEmpty, !peerIds.isEmpty {
|
||||
let rawSignals = TGItemProviderSignals.itemSignals(forInputItems: inputItems)!
|
||||
return preparedShareItems(postbox: account.stateManager.postbox, network: account.stateManager.network, to: peerIds[0], dataItems: rawSignals)
|
||||
@ -564,11 +576,11 @@ public class ShareRootControllerImpl {
|
||||
return requestUserInteraction(value)
|
||||
|> castError(ShareControllerError.self)
|
||||
|> mapToSignal { contents -> Signal<ShareControllerExternalStatus, ShareControllerError> in
|
||||
return sentItems(peerIds, threadIds, contents, account, silently, additionalText)
|
||||
return sentItems(peerIds, threadIds, requireStars, contents, account, silently, additionalText)
|
||||
|> castError(ShareControllerError.self)
|
||||
}
|
||||
case let .done(contents):
|
||||
return sentItems(peerIds, threadIds, contents, account, silently, additionalText)
|
||||
return sentItems(peerIds, threadIds, requireStars, contents, account, silently, additionalText)
|
||||
|> castError(ShareControllerError.self)
|
||||
}
|
||||
}
|
||||
|
@ -124,9 +124,9 @@ private final class SheetContent: CombinedComponent {
|
||||
minAmount = StarsAmount(value: 1, nanos: 0)
|
||||
maxAmount = configuration.maxPaidMediaAmount.flatMap { StarsAmount(value: $0, nanos: 0) }
|
||||
|
||||
var usdRate = 0.012
|
||||
|
||||
if let usdWithdrawRate = configuration.usdWithdrawRate, let amount = state.amount, amount > StarsAmount.zero {
|
||||
usdRate = Double(usdWithdrawRate) / 1000.0 / 100.0
|
||||
let usdRate = Double(usdWithdrawRate) / 1000.0 / 100.0
|
||||
amountLabel = "≈\(formatTonUsdValue(amount.value, divide: false, rate: usdRate, dateTimeFormat: environment.dateTimeFormat))"
|
||||
} else {
|
||||
amountLabel = nil
|
||||
|
@ -98,6 +98,7 @@ swift_library(
|
||||
"//submodules/TelegramUI/Components/SliderContextItem",
|
||||
"//submodules/TelegramUI/Components/InteractiveTextComponent",
|
||||
"//submodules/TelegramUI/Components/SaveProgressScreen",
|
||||
"//submodules/TelegramUI/Components/Chat/ChatMessagePaymentAlertController",
|
||||
],
|
||||
visibility = [
|
||||
"//visibility:public",
|
||||
|
@ -219,7 +219,8 @@ public final class StoryContentContextImpl: StoryContentContext {
|
||||
isPremiumRequiredForMessaging: isPremiumRequiredForMessaging,
|
||||
preferHighQualityStories: preferHighQualityStories,
|
||||
boostsToUnrestrict: nil,
|
||||
appliedBoosts: nil
|
||||
appliedBoosts: nil,
|
||||
sendPaidMessageStars: cachedUserData.sendPaidMessageStars
|
||||
)
|
||||
} else if let cachedChannelData = cachedPeerDataView.cachedPeerData as? CachedChannelData {
|
||||
additionalPeerData = StoryContentContextState.AdditionalPeerData(
|
||||
@ -230,7 +231,8 @@ public final class StoryContentContextImpl: StoryContentContext {
|
||||
isPremiumRequiredForMessaging: isPremiumRequiredForMessaging,
|
||||
preferHighQualityStories: preferHighQualityStories,
|
||||
boostsToUnrestrict: cachedChannelData.boostsToUnrestrict,
|
||||
appliedBoosts: cachedChannelData.appliedBoosts
|
||||
appliedBoosts: cachedChannelData.appliedBoosts,
|
||||
sendPaidMessageStars: cachedChannelData.sendPaidMessageStars
|
||||
)
|
||||
} else {
|
||||
additionalPeerData = StoryContentContextState.AdditionalPeerData(
|
||||
@ -241,7 +243,8 @@ public final class StoryContentContextImpl: StoryContentContext {
|
||||
isPremiumRequiredForMessaging: isPremiumRequiredForMessaging,
|
||||
preferHighQualityStories: preferHighQualityStories,
|
||||
boostsToUnrestrict: nil,
|
||||
appliedBoosts: nil
|
||||
appliedBoosts: nil,
|
||||
sendPaidMessageStars: nil
|
||||
)
|
||||
}
|
||||
} else {
|
||||
@ -253,7 +256,8 @@ public final class StoryContentContextImpl: StoryContentContext {
|
||||
isPremiumRequiredForMessaging: isPremiumRequiredForMessaging,
|
||||
preferHighQualityStories: preferHighQualityStories,
|
||||
boostsToUnrestrict: nil,
|
||||
appliedBoosts: nil
|
||||
appliedBoosts: nil,
|
||||
sendPaidMessageStars: nil
|
||||
)
|
||||
}
|
||||
let state = stateView.value?.get(Stories.PeerState.self)
|
||||
@ -1182,7 +1186,8 @@ public final class SingleStoryContentContextImpl: StoryContentContext {
|
||||
TelegramEngine.EngineData.Item.NotificationSettings.Global(),
|
||||
TelegramEngine.EngineData.Item.Peer.IsPremiumRequiredForMessaging(id: storyId.peerId),
|
||||
TelegramEngine.EngineData.Item.Peer.BoostsToUnrestrict(id: storyId.peerId),
|
||||
TelegramEngine.EngineData.Item.Peer.AppliedBoosts(id: storyId.peerId)
|
||||
TelegramEngine.EngineData.Item.Peer.AppliedBoosts(id: storyId.peerId),
|
||||
TelegramEngine.EngineData.Item.Peer.SendPaidMessageStars(id: storyId.peerId)
|
||||
),
|
||||
item |> mapToSignal { item -> Signal<(Stories.StoredItem?, [PeerId: Peer], [MediaId: TelegramMediaFile], [StoryId: EngineStoryItem?]), NoError> in
|
||||
return context.account.postbox.transaction { transaction -> (Stories.StoredItem?, [PeerId: Peer], [MediaId: TelegramMediaFile], [StoryId: EngineStoryItem?]) in
|
||||
@ -1253,7 +1258,7 @@ public final class SingleStoryContentContextImpl: StoryContentContext {
|
||||
return
|
||||
}
|
||||
|
||||
let (peer, presence, areVoiceMessagesAvailable, canViewStats, notificationSettings, globalNotificationSettings, isPremiumRequiredForMessaging, boostsToUnrestrict, appliedBoosts) = data
|
||||
let (peer, presence, areVoiceMessagesAvailable, canViewStats, notificationSettings, globalNotificationSettings, isPremiumRequiredForMessaging, boostsToUnrestrict, appliedBoosts, sendPaidMessageStars) = data
|
||||
let (item, peers, allEntityFiles, forwardInfoStories) = itemAndPeers
|
||||
|
||||
guard let peer else {
|
||||
@ -1270,7 +1275,8 @@ public final class SingleStoryContentContextImpl: StoryContentContext {
|
||||
isPremiumRequiredForMessaging: isPremiumRequiredForMessaging,
|
||||
preferHighQualityStories: preferHighQualityStories,
|
||||
boostsToUnrestrict: boostsToUnrestrict,
|
||||
appliedBoosts: appliedBoosts
|
||||
appliedBoosts: appliedBoosts,
|
||||
sendPaidMessageStars: sendPaidMessageStars
|
||||
)
|
||||
|
||||
for (storyId, story) in forwardInfoStories {
|
||||
@ -1436,9 +1442,11 @@ public final class PeerStoryListContentContextImpl: StoryContentContext {
|
||||
TelegramEngine.EngineData.Item.NotificationSettings.Global.Result,
|
||||
TelegramEngine.EngineData.Item.Peer.IsPremiumRequiredForMessaging.Result,
|
||||
TelegramEngine.EngineData.Item.Peer.BoostsToUnrestrict.Result,
|
||||
TelegramEngine.EngineData.Item.Peer.AppliedBoosts.Result)
|
||||
TelegramEngine.EngineData.Item.Peer.AppliedBoosts.Result,
|
||||
TelegramEngine.EngineData.Item.Peer.SendPaidMessageStars.Result
|
||||
)
|
||||
|
||||
init(data: (TelegramEngine.EngineData.Item.Peer.Peer.Result, TelegramEngine.EngineData.Item.Peer.Presence.Result, TelegramEngine.EngineData.Item.Peer.AreVoiceMessagesAvailable.Result, TelegramEngine.EngineData.Item.Peer.CanViewStats.Result, TelegramEngine.EngineData.Item.Peer.NotificationSettings.Result, TelegramEngine.EngineData.Item.NotificationSettings.Global.Result, TelegramEngine.EngineData.Item.Peer.IsPremiumRequiredForMessaging.Result, TelegramEngine.EngineData.Item.Peer.BoostsToUnrestrict.Result, TelegramEngine.EngineData.Item.Peer.AppliedBoosts.Result)) {
|
||||
init(data: (TelegramEngine.EngineData.Item.Peer.Peer.Result, TelegramEngine.EngineData.Item.Peer.Presence.Result, TelegramEngine.EngineData.Item.Peer.AreVoiceMessagesAvailable.Result, TelegramEngine.EngineData.Item.Peer.CanViewStats.Result, TelegramEngine.EngineData.Item.Peer.NotificationSettings.Result, TelegramEngine.EngineData.Item.NotificationSettings.Global.Result, TelegramEngine.EngineData.Item.Peer.IsPremiumRequiredForMessaging.Result, TelegramEngine.EngineData.Item.Peer.BoostsToUnrestrict.Result, TelegramEngine.EngineData.Item.Peer.AppliedBoosts.Result, TelegramEngine.EngineData.Item.Peer.SendPaidMessageStars.Result)) {
|
||||
self.data = data
|
||||
}
|
||||
}
|
||||
@ -1544,7 +1552,8 @@ public final class PeerStoryListContentContextImpl: StoryContentContext {
|
||||
TelegramEngine.EngineData.Item.NotificationSettings.Global(),
|
||||
TelegramEngine.EngineData.Item.Peer.IsPremiumRequiredForMessaging(id: peerId),
|
||||
TelegramEngine.EngineData.Item.Peer.BoostsToUnrestrict(id: peerId),
|
||||
TelegramEngine.EngineData.Item.Peer.AppliedBoosts(id: peerId)
|
||||
TelegramEngine.EngineData.Item.Peer.AppliedBoosts(id: peerId),
|
||||
TelegramEngine.EngineData.Item.Peer.SendPaidMessageStars(id: peerId)
|
||||
) |> map { PeerData(data: $0) })
|
||||
self.currentPeerData = currentPeerData
|
||||
|
||||
@ -1563,7 +1572,7 @@ public final class PeerStoryListContentContextImpl: StoryContentContext {
|
||||
self.listState = state
|
||||
|
||||
let stateValue: StoryContentContextState
|
||||
if let focusedIndex, let (peer, presence, areVoiceMessagesAvailable, canViewStats, notificationSettings, globalNotificationSettings, isPremiumRequiredForMessaging, boostsToUnrestrict, appliedBoosts) = data?.data, let peer {
|
||||
if let focusedIndex, let (peer, presence, areVoiceMessagesAvailable, canViewStats, notificationSettings, globalNotificationSettings, isPremiumRequiredForMessaging, boostsToUnrestrict, appliedBoosts, sendPaidMessageStars) = data?.data, let peer {
|
||||
let isMuted = resolvedAreStoriesMuted(globalSettings: globalNotificationSettings._asGlobalNotificationSettings(), peer: peer._asPeer(), peerSettings: notificationSettings._asNotificationSettings(), topSearchPeers: [])
|
||||
let additionalPeerData = StoryContentContextState.AdditionalPeerData(
|
||||
isMuted: isMuted,
|
||||
@ -1573,7 +1582,8 @@ public final class PeerStoryListContentContextImpl: StoryContentContext {
|
||||
isPremiumRequiredForMessaging: isPremiumRequiredForMessaging,
|
||||
preferHighQualityStories: preferHighQualityStories,
|
||||
boostsToUnrestrict: boostsToUnrestrict,
|
||||
appliedBoosts: appliedBoosts
|
||||
appliedBoosts: appliedBoosts,
|
||||
sendPaidMessageStars: sendPaidMessageStars
|
||||
)
|
||||
|
||||
let item = state.items[focusedIndex]
|
||||
@ -2462,7 +2472,8 @@ public final class RepostStoriesContentContextImpl: StoryContentContext {
|
||||
isPremiumRequiredForMessaging: isPremiumRequiredForMessaging,
|
||||
preferHighQualityStories: preferHighQualityStories,
|
||||
boostsToUnrestrict: nil,
|
||||
appliedBoosts: nil
|
||||
appliedBoosts: nil,
|
||||
sendPaidMessageStars: cachedUserData.sendPaidMessageStars
|
||||
)
|
||||
} else if let cachedChannelData = cachedPeerDataView.cachedPeerData as? CachedChannelData {
|
||||
additionalPeerData = StoryContentContextState.AdditionalPeerData(
|
||||
@ -2473,7 +2484,8 @@ public final class RepostStoriesContentContextImpl: StoryContentContext {
|
||||
isPremiumRequiredForMessaging: isPremiumRequiredForMessaging,
|
||||
preferHighQualityStories: preferHighQualityStories,
|
||||
boostsToUnrestrict: cachedChannelData.boostsToUnrestrict,
|
||||
appliedBoosts: cachedChannelData.appliedBoosts
|
||||
appliedBoosts: cachedChannelData.appliedBoosts,
|
||||
sendPaidMessageStars: cachedChannelData.sendPaidMessageStars
|
||||
)
|
||||
} else {
|
||||
additionalPeerData = StoryContentContextState.AdditionalPeerData(
|
||||
@ -2484,7 +2496,8 @@ public final class RepostStoriesContentContextImpl: StoryContentContext {
|
||||
isPremiumRequiredForMessaging: isPremiumRequiredForMessaging,
|
||||
preferHighQualityStories: preferHighQualityStories,
|
||||
boostsToUnrestrict: nil,
|
||||
appliedBoosts: nil
|
||||
appliedBoosts: nil,
|
||||
sendPaidMessageStars: nil
|
||||
)
|
||||
}
|
||||
}
|
||||
@ -2497,7 +2510,8 @@ public final class RepostStoriesContentContextImpl: StoryContentContext {
|
||||
isPremiumRequiredForMessaging: isPremiumRequiredForMessaging,
|
||||
preferHighQualityStories: preferHighQualityStories,
|
||||
boostsToUnrestrict: nil,
|
||||
appliedBoosts: nil
|
||||
appliedBoosts: nil,
|
||||
sendPaidMessageStars: nil
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -161,6 +161,7 @@ public final class StoryContentContextState {
|
||||
public let preferHighQualityStories: Bool
|
||||
public let boostsToUnrestrict: Int32?
|
||||
public let appliedBoosts: Int32?
|
||||
public let sendPaidMessageStars: StarsAmount?
|
||||
|
||||
public init(
|
||||
isMuted: Bool,
|
||||
@ -170,7 +171,8 @@ public final class StoryContentContextState {
|
||||
isPremiumRequiredForMessaging: Bool,
|
||||
preferHighQualityStories: Bool,
|
||||
boostsToUnrestrict: Int32?,
|
||||
appliedBoosts: Int32?
|
||||
appliedBoosts: Int32?,
|
||||
sendPaidMessageStars: StarsAmount?
|
||||
) {
|
||||
self.isMuted = isMuted
|
||||
self.areVoiceMessagesAvailable = areVoiceMessagesAvailable
|
||||
@ -180,6 +182,7 @@ public final class StoryContentContextState {
|
||||
self.preferHighQualityStories = preferHighQualityStories
|
||||
self.boostsToUnrestrict = boostsToUnrestrict
|
||||
self.appliedBoosts = appliedBoosts
|
||||
self.sendPaidMessageStars = sendPaidMessageStars
|
||||
}
|
||||
|
||||
public static func == (lhs: StoryContentContextState.AdditionalPeerData, rhs: StoryContentContextState.AdditionalPeerData) -> Bool {
|
||||
@ -207,6 +210,9 @@ public final class StoryContentContextState {
|
||||
if lhs.appliedBoosts != rhs.appliedBoosts {
|
||||
return false
|
||||
}
|
||||
if lhs.sendPaidMessageStars != rhs.sendPaidMessageStars {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
@ -2823,7 +2823,12 @@ public final class StoryItemSetContainerComponent: Component {
|
||||
|
||||
inputPlaceholder = .counter(items)
|
||||
} else {
|
||||
inputPlaceholder = .plain(isGroup ? component.strings.Story_InputPlaceholderReplyInGroup : component.strings.Story_InputPlaceholderReplyPrivately)
|
||||
if let sendPaidMessageStars = component.slice.additionalPeerData.sendPaidMessageStars {
|
||||
let dateTimeFormat = component.context.sharedContext.currentPresentationData.with { $0 }.dateTimeFormat
|
||||
inputPlaceholder = .plain(component.strings.Chat_InputTextPaidMessagePlaceholder(" # \(presentationStringsFormattedNumber(Int32(sendPaidMessageStars.value), dateTimeFormat.groupingSeparator))").string)
|
||||
} else {
|
||||
inputPlaceholder = .plain(isGroup ? component.strings.Story_InputPlaceholderReplyInGroup : component.strings.Story_InputPlaceholderReplyPrivately)
|
||||
}
|
||||
}
|
||||
|
||||
let startTime22 = CFAbsoluteTimeGetCurrent()
|
||||
@ -2867,6 +2872,7 @@ public final class StoryItemSetContainerComponent: Component {
|
||||
strings: component.strings,
|
||||
style: .story,
|
||||
placeholder: inputPlaceholder,
|
||||
sendPaidMessageStars: component.slice.additionalPeerData.sendPaidMessageStars,
|
||||
maxLength: 4096,
|
||||
queryTypes: [.mention, .hashtag, .emoji],
|
||||
alwaysDarkWhenHasText: component.metrics.widthClass == .regular,
|
||||
@ -4647,6 +4653,10 @@ public final class StoryItemSetContainerComponent: Component {
|
||||
case .stars:
|
||||
break
|
||||
}
|
||||
|
||||
if let sendPaidMessageStars = component.slice.additionalPeerData.sendPaidMessageStars {
|
||||
messageAttributes.append(PaidStarsMessageAttribute(stars: sendPaidMessageStars, postponeSending: false))
|
||||
}
|
||||
|
||||
let message: EnqueueMessage = .message(
|
||||
text: text,
|
||||
@ -4693,7 +4703,6 @@ public final class StoryItemSetContainerComponent: Component {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
if self.displayLikeReactions {
|
||||
if component.slice.item.storyItem.myReaction == updateReaction.reaction {
|
||||
action()
|
||||
@ -4704,7 +4713,9 @@ public final class StoryItemSetContainerComponent: Component {
|
||||
}
|
||||
} else {
|
||||
self.sendMessageContext.performWithPossibleStealthModeConfirmation(view: self, action: {
|
||||
action()
|
||||
self.sendMessageContext.presentPaidMessageAlertIfNeeded(view: self, completion: {
|
||||
action()
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -50,6 +50,7 @@ import LocationUI
|
||||
import ReactionSelectionNode
|
||||
import StoryQualityUpgradeSheetScreen
|
||||
import AudioWaveform
|
||||
import ChatMessagePaymentAlertController
|
||||
|
||||
private var ObjCKey_DeinitWatcher: Int?
|
||||
|
||||
@ -491,6 +492,30 @@ final class StoryItemSetContainerSendMessage {
|
||||
view.updateIsProgressPaused()
|
||||
}
|
||||
|
||||
func presentPaidMessageAlertIfNeeded(view: StoryItemSetContainerComponent.View, completion: @escaping () -> Void) {
|
||||
guard let component = view.component, let sendPaidMessageStars = component.slice.additionalPeerData.sendPaidMessageStars else {
|
||||
completion()
|
||||
return
|
||||
}
|
||||
let presentationData = component.context.sharedContext.currentPresentationData.with({ $0 }).withUpdated(theme: defaultDarkColorPresentationTheme)
|
||||
|
||||
let controller = chatMessagePaymentAlertController(
|
||||
context: component.context,
|
||||
presentationData: presentationData,
|
||||
updatedPresentationData: nil,
|
||||
peers: [component.slice.effectivePeer],
|
||||
count: 1,
|
||||
amount: sendPaidMessageStars,
|
||||
totalAmount: nil,
|
||||
hasCheck: false,
|
||||
navigationController: component.controller()?.navigationController as? NavigationController,
|
||||
completion: { _ in
|
||||
completion()
|
||||
}
|
||||
)
|
||||
component.controller()?.present(controller, in: .window(.root))
|
||||
}
|
||||
|
||||
func performWithPossibleStealthModeConfirmation(view: StoryItemSetContainerComponent.View, action: @escaping () -> Void) {
|
||||
guard let component = view.component, component.stealthModeTimeout != nil else {
|
||||
action()
|
||||
@ -512,7 +537,6 @@ final class StoryItemSetContainerSendMessage {
|
||||
|
||||
let timestamp = Int32(Date().timeIntervalSince1970)
|
||||
if noticeCount < 1, let activeUntilTimestamp = config.stealthModeState.actualizedNow().activeUntilTimestamp, activeUntilTimestamp > timestamp {
|
||||
|
||||
let theme = component.theme
|
||||
let updatedPresentationData: (initial: PresentationData, signal: Signal<PresentationData, NoError>) = (component.context.sharedContext.currentPresentationData.with({ $0 }).withUpdated(theme: theme), component.context.sharedContext.presentationData |> map { $0.withUpdated(theme: theme) })
|
||||
|
||||
@ -575,53 +599,64 @@ final class StoryItemSetContainerSendMessage {
|
||||
|
||||
let controller = component.controller() as? StoryContainerScreen
|
||||
|
||||
if let recordedAudioPreview = self.recordedAudioPreview, case let .audio(audio) = recordedAudioPreview {
|
||||
self.recordedAudioPreview = nil
|
||||
|
||||
let waveformBuffer = audio.waveform.makeBitstream()
|
||||
|
||||
let messages: [EnqueueMessage] = [.message(text: "", attributes: [], inlineStickers: [:], mediaReference: .standalone(media: TelegramMediaFile(fileId: EngineMedia.Id(namespace: Namespaces.Media.LocalFile, id: Int64.random(in: Int64.min ... Int64.max)), partialReference: nil, resource: audio.resource, previewRepresentations: [], videoThumbnails: [], immediateThumbnailData: nil, mimeType: "audio/ogg", size: Int64(audio.fileSize), attributes: [.Audio(isVoice: true, duration: Int(audio.duration), title: nil, performer: nil, waveform: waveformBuffer)], alternativeRepresentations: [])), threadId: nil, replyToMessageId: nil, replyToStoryId: focusedStoryId, localGroupingKey: nil, correlationId: nil, bubbleUpEmojiOrStickersets: [])]
|
||||
|
||||
let _ = enqueueMessages(account: component.context.account, peerId: peerId, messages: messages).start()
|
||||
|
||||
view.state?.updated(transition: ComponentTransition(animation: .curve(duration: 0.3, curve: .spring)))
|
||||
} else if self.hasRecordedVideoPreview, let videoRecorderValue = self.videoRecorderValue {
|
||||
videoRecorderValue.send()
|
||||
self.hasRecordedVideoPreview = false
|
||||
self.videoRecorder.set(.single(nil))
|
||||
view.state?.updated(transition: ComponentTransition(animation: .curve(duration: 0.3, curve: .spring)))
|
||||
} else {
|
||||
switch inputPanelView.getSendMessageInput() {
|
||||
case let .text(text):
|
||||
if !text.string.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty {
|
||||
let entities = generateChatInputTextEntities(text)
|
||||
let _ = (component.context.engine.messages.enqueueOutgoingMessage(
|
||||
to: peerId,
|
||||
replyTo: nil,
|
||||
storyId: focusedStoryId,
|
||||
content: .text(text.string, entities),
|
||||
silentPosting: silentPosting,
|
||||
scheduleTime: scheduleTime
|
||||
) |> deliverOnMainQueue).start(next: { [weak self, weak view] messageIds in
|
||||
Queue.mainQueue().after(0.3) {
|
||||
if let self, let view {
|
||||
self.presentMessageSentTooltip(view: view, peer: peer, messageId: messageIds.first.flatMap { $0 }, isScheduled: scheduleTime != nil)
|
||||
self.presentPaidMessageAlertIfNeeded(view: view, completion: { [weak self, weak view] in
|
||||
guard let self, let view else {
|
||||
return
|
||||
}
|
||||
if let recordedAudioPreview = self.recordedAudioPreview, case let .audio(audio) = recordedAudioPreview {
|
||||
self.recordedAudioPreview = nil
|
||||
|
||||
let waveformBuffer = audio.waveform.makeBitstream()
|
||||
|
||||
var messageAttributes: [MessageAttribute] = []
|
||||
if let sendPaidMessageStars = component.slice.additionalPeerData.sendPaidMessageStars {
|
||||
messageAttributes.append(PaidStarsMessageAttribute(stars: sendPaidMessageStars, postponeSending: false))
|
||||
}
|
||||
|
||||
let messages: [EnqueueMessage] = [.message(text: "", attributes: messageAttributes, inlineStickers: [:], mediaReference: .standalone(media: TelegramMediaFile(fileId: EngineMedia.Id(namespace: Namespaces.Media.LocalFile, id: Int64.random(in: Int64.min ... Int64.max)), partialReference: nil, resource: audio.resource, previewRepresentations: [], videoThumbnails: [], immediateThumbnailData: nil, mimeType: "audio/ogg", size: Int64(audio.fileSize), attributes: [.Audio(isVoice: true, duration: Int(audio.duration), title: nil, performer: nil, waveform: waveformBuffer)], alternativeRepresentations: [])), threadId: nil, replyToMessageId: nil, replyToStoryId: focusedStoryId, localGroupingKey: nil, correlationId: nil, bubbleUpEmojiOrStickersets: [])]
|
||||
|
||||
let _ = enqueueMessages(account: component.context.account, peerId: peerId, messages: messages).start()
|
||||
|
||||
view.state?.updated(transition: ComponentTransition(animation: .curve(duration: 0.3, curve: .spring)))
|
||||
} else if self.hasRecordedVideoPreview, let videoRecorderValue = self.videoRecorderValue {
|
||||
videoRecorderValue.send()
|
||||
self.hasRecordedVideoPreview = false
|
||||
self.videoRecorder.set(.single(nil))
|
||||
view.state?.updated(transition: ComponentTransition(animation: .curve(duration: 0.3, curve: .spring)))
|
||||
} else {
|
||||
switch inputPanelView.getSendMessageInput() {
|
||||
case let .text(text):
|
||||
if !text.string.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty {
|
||||
let entities = generateChatInputTextEntities(text)
|
||||
let _ = (component.context.engine.messages.enqueueOutgoingMessage(
|
||||
to: peerId,
|
||||
replyTo: nil,
|
||||
storyId: focusedStoryId,
|
||||
content: .text(text.string, entities),
|
||||
silentPosting: silentPosting,
|
||||
scheduleTime: scheduleTime,
|
||||
sendPaidMessageStars: component.slice.additionalPeerData.sendPaidMessageStars
|
||||
) |> deliverOnMainQueue).start(next: { [weak self, weak view] messageIds in
|
||||
Queue.mainQueue().after(0.3) {
|
||||
if let self, let view {
|
||||
self.presentMessageSentTooltip(view: view, peer: peer, messageId: messageIds.first.flatMap { $0 }, isScheduled: scheduleTime != nil)
|
||||
}
|
||||
}
|
||||
})
|
||||
component.storyItemSharedState.replyDrafts.removeValue(forKey: StoryId(peerId: peerId, id: focusedItem.storyItem.id))
|
||||
inputPanelView.clearSendMessageInput(updateState: true)
|
||||
|
||||
self.currentInputMode = .text
|
||||
if hasFirstResponder(view) {
|
||||
view.endEditing(true)
|
||||
} else {
|
||||
view.state?.updated(transition: .spring(duration: 0.3))
|
||||
}
|
||||
})
|
||||
component.storyItemSharedState.replyDrafts.removeValue(forKey: StoryId(peerId: peerId, id: focusedItem.storyItem.id))
|
||||
inputPanelView.clearSendMessageInput(updateState: true)
|
||||
|
||||
self.currentInputMode = .text
|
||||
if hasFirstResponder(view) {
|
||||
view.endEditing(true)
|
||||
} else {
|
||||
view.state?.updated(transition: .spring(duration: 0.3))
|
||||
controller?.requestLayout(forceUpdate: true, transition: .animated(duration: 0.3, curve: .spring))
|
||||
}
|
||||
controller?.requestLayout(forceUpdate: true, transition: .animated(duration: 0.3, curve: .spring))
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
@ -660,26 +695,32 @@ final class StoryItemSetContainerSendMessage {
|
||||
})
|
||||
}
|
||||
|
||||
let _ = (component.context.engine.messages.enqueueOutgoingMessage(
|
||||
to: peerId,
|
||||
replyTo: nil,
|
||||
storyId: focusedStoryId,
|
||||
content: .file(fileReference)
|
||||
) |> deliverOnMainQueue).start(next: { [weak self, weak view] messageIds in
|
||||
Queue.mainQueue().after(0.3) {
|
||||
if let self, let view {
|
||||
self.presentMessageSentTooltip(view: view, peer: peer, messageId: messageIds.first.flatMap { $0 })
|
||||
}
|
||||
self.presentPaidMessageAlertIfNeeded(view: view, completion: { [weak self, weak view] in
|
||||
guard let self, let view else {
|
||||
return
|
||||
}
|
||||
let _ = (component.context.engine.messages.enqueueOutgoingMessage(
|
||||
to: peerId,
|
||||
replyTo: nil,
|
||||
storyId: focusedStoryId,
|
||||
content: .file(fileReference),
|
||||
sendPaidMessageStars: component.slice.additionalPeerData.sendPaidMessageStars
|
||||
) |> deliverOnMainQueue).start(next: { [weak self, weak view] messageIds in
|
||||
Queue.mainQueue().after(0.3) {
|
||||
if let self, let view {
|
||||
self.presentMessageSentTooltip(view: view, peer: peer, messageId: messageIds.first.flatMap { $0 })
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
self.currentInputMode = .text
|
||||
if hasFirstResponder(view) {
|
||||
view.endEditing(true)
|
||||
} else {
|
||||
view.state?.updated(transition: .spring(duration: 0.3))
|
||||
}
|
||||
controller?.requestLayout(forceUpdate: true, transition: .animated(duration: 0.3, curve: .spring))
|
||||
})
|
||||
|
||||
self.currentInputMode = .text
|
||||
if hasFirstResponder(view) {
|
||||
view.endEditing(true)
|
||||
} else {
|
||||
view.state?.updated(transition: .spring(duration: 0.3))
|
||||
}
|
||||
controller?.requestLayout(forceUpdate: true, transition: .animated(duration: 0.3, curve: .spring))
|
||||
})
|
||||
}
|
||||
|
||||
@ -714,37 +755,48 @@ final class StoryItemSetContainerSendMessage {
|
||||
})
|
||||
}
|
||||
|
||||
let _ = (component.context.engine.messages.enqueueOutgoingMessage(
|
||||
to: peerId,
|
||||
replyTo: nil,
|
||||
storyId: focusedStoryId,
|
||||
content: .contextResult(results, result)
|
||||
) |> deliverOnMainQueue).start(next: { [weak self, weak view] messageIds in
|
||||
Queue.mainQueue().after(0.3) {
|
||||
if let self, let view {
|
||||
self.presentMessageSentTooltip(view: view, peer: peer, messageId: messageIds.first.flatMap { $0 })
|
||||
}
|
||||
self.presentPaidMessageAlertIfNeeded(view: view, completion: { [weak self, weak view] in
|
||||
guard let self, let view else {
|
||||
return
|
||||
}
|
||||
let _ = (component.context.engine.messages.enqueueOutgoingMessage(
|
||||
to: peerId,
|
||||
replyTo: nil,
|
||||
storyId: focusedStoryId,
|
||||
content: .contextResult(results, result),
|
||||
sendPaidMessageStars: component.slice.additionalPeerData.sendPaidMessageStars
|
||||
) |> deliverOnMainQueue).start(next: { [weak self, weak view] messageIds in
|
||||
Queue.mainQueue().after(0.3) {
|
||||
if let self, let view {
|
||||
self.presentMessageSentTooltip(view: view, peer: peer, messageId: messageIds.first.flatMap { $0 })
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
self.currentInputMode = .text
|
||||
if hasFirstResponder(view) {
|
||||
view.endEditing(true)
|
||||
} else {
|
||||
view.state?.updated(transition: .spring(duration: 0.3))
|
||||
}
|
||||
controller?.requestLayout(forceUpdate: true, transition: .animated(duration: 0.3, curve: .spring))
|
||||
})
|
||||
|
||||
self.currentInputMode = .text
|
||||
if hasFirstResponder(view) {
|
||||
view.endEditing(true)
|
||||
} else {
|
||||
view.state?.updated(transition: .spring(duration: 0.3))
|
||||
}
|
||||
controller?.requestLayout(forceUpdate: true, transition: .animated(duration: 0.3, curve: .spring))
|
||||
}
|
||||
|
||||
func enqueueGifData(view: StoryItemSetContainerComponent.View, data: Data) {
|
||||
guard let component = view.component else {
|
||||
return
|
||||
}
|
||||
let peer = component.slice.effectivePeer
|
||||
let _ = (legacyEnqueueGifMessage(account: component.context.account, data: data) |> deliverOnMainQueue).start(next: { [weak self, weak view] message in
|
||||
if let self, let view {
|
||||
self.sendMessages(view: view, peer: peer, messages: [message])
|
||||
self.presentPaidMessageAlertIfNeeded(view: view, completion: { [weak self] in
|
||||
guard let self else {
|
||||
return
|
||||
}
|
||||
let peer = component.slice.effectivePeer
|
||||
let _ = (legacyEnqueueGifMessage(account: component.context.account, data: data) |> deliverOnMainQueue).start(next: { [weak self, weak view] message in
|
||||
if let self, let view {
|
||||
self.sendMessages(view: view, peer: peer, messages: [message])
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
@ -794,7 +846,12 @@ final class StoryItemSetContainerSendMessage {
|
||||
let media = TelegramMediaFile(fileId: MediaId(namespace: Namespaces.Media.LocalFile, id: Int64.random(in: Int64.min ... Int64.max)), partialReference: nil, resource: resource, previewRepresentations: [], videoThumbnails: [], immediateThumbnailData: nil, mimeType: "image/webp", size: Int64(data.count), attributes: fileAttributes, alternativeRepresentations: [])
|
||||
let message = EnqueueMessage.message(text: "", attributes: [], inlineStickers: [:], mediaReference: .standalone(media: media), threadId: nil, replyToMessageId: nil, replyToStoryId: nil, localGroupingKey: nil, correlationId: nil, bubbleUpEmojiOrStickersets: [])
|
||||
|
||||
self.sendMessages(view: view, peer: peer, messages: [message], silentPosting: false)
|
||||
self.presentPaidMessageAlertIfNeeded(view: view, completion: { [weak self] in
|
||||
guard let self else {
|
||||
return
|
||||
}
|
||||
self.sendMessages(view: view, peer: peer, messages: [message], silentPosting: false)
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
@ -846,7 +903,12 @@ final class StoryItemSetContainerSendMessage {
|
||||
guard let self, let view else {
|
||||
return
|
||||
}
|
||||
self.sendMessages(view: view, peer: peer, messages: [updatedMessage])
|
||||
self.presentPaidMessageAlertIfNeeded(view: view, completion: { [weak self, weak view] in
|
||||
guard let self, let view else {
|
||||
return
|
||||
}
|
||||
self.sendMessages(view: view, peer: peer, messages: [updatedMessage])
|
||||
})
|
||||
})
|
||||
}, displaySlowmodeTooltip: { [weak self] view, rect in
|
||||
//self?.interfaceInteraction?.displaySlowmodeTooltip(view, rect)
|
||||
@ -896,9 +958,14 @@ final class StoryItemSetContainerSendMessage {
|
||||
guard let self, let view else {
|
||||
return
|
||||
}
|
||||
self.sendMessages(view: view, peer: peer, messages: [.message(text: "", attributes: [], inlineStickers: [:], mediaReference: .standalone(media: TelegramMediaFile(fileId: EngineMedia.Id(namespace: Namespaces.Media.LocalFile, id: randomId), partialReference: nil, resource: resource, previewRepresentations: [], videoThumbnails: [], immediateThumbnailData: nil, mimeType: "audio/ogg", size: Int64(data.compressedData.count), attributes: [.Audio(isVoice: true, duration: Int(data.duration), title: nil, performer: nil, waveform: waveformBuffer)], alternativeRepresentations: [])), threadId: nil, replyToMessageId: nil, replyToStoryId: focusedStoryId, localGroupingKey: nil, correlationId: nil, bubbleUpEmojiOrStickersets: [])])
|
||||
|
||||
HapticFeedback().tap()
|
||||
self.presentPaidMessageAlertIfNeeded(view: view, completion: { [weak self, weak view] in
|
||||
guard let self, let view else {
|
||||
return
|
||||
}
|
||||
self.sendMessages(view: view, peer: peer, messages: [.message(text: "", attributes: [], inlineStickers: [:], mediaReference: .standalone(media: TelegramMediaFile(fileId: EngineMedia.Id(namespace: Namespaces.Media.LocalFile, id: randomId), partialReference: nil, resource: resource, previewRepresentations: [], videoThumbnails: [], immediateThumbnailData: nil, mimeType: "audio/ogg", size: Int64(data.compressedData.count), attributes: [.Audio(isVoice: true, duration: Int(data.duration), title: nil, performer: nil, waveform: waveformBuffer)], alternativeRepresentations: [])), threadId: nil, replyToMessageId: nil, replyToStoryId: focusedStoryId, localGroupingKey: nil, correlationId: nil, bubbleUpEmojiOrStickersets: [])])
|
||||
|
||||
HapticFeedback().tap()
|
||||
})
|
||||
})
|
||||
}
|
||||
})
|
||||
@ -1593,7 +1660,11 @@ final class StoryItemSetContainerSendMessage {
|
||||
guard let view, let component = view.component else {
|
||||
return
|
||||
}
|
||||
let message: EnqueueMessage = .message(text: "", attributes: [], inlineStickers: [:], mediaReference: mediaReference, threadId: nil, replyToMessageId: nil, replyToStoryId: focusedStoryId, localGroupingKey: nil, correlationId: nil, bubbleUpEmojiOrStickersets: [])
|
||||
var messageAttributes: [MessageAttribute] = []
|
||||
if let sendPaidMessageStars = component.slice.additionalPeerData.sendPaidMessageStars {
|
||||
messageAttributes.append(PaidStarsMessageAttribute(stars: sendPaidMessageStars, postponeSending: false))
|
||||
}
|
||||
let message: EnqueueMessage = .message(text: "", attributes: messageAttributes, inlineStickers: [:], mediaReference: mediaReference, threadId: nil, replyToMessageId: nil, replyToStoryId: focusedStoryId, localGroupingKey: nil, correlationId: nil, bubbleUpEmojiOrStickersets: [])
|
||||
let _ = (enqueueMessages(account: component.context.account, peerId: peer.id, messages: [message.withUpdatedReplyToMessageId(nil)])
|
||||
|> deliverOnMainQueue).start(next: { [weak self, weak view] messageIds in
|
||||
if let self, let view {
|
||||
@ -1636,7 +1707,12 @@ final class StoryItemSetContainerSendMessage {
|
||||
return
|
||||
}
|
||||
let message: EnqueueMessage = .message(text: "", attributes: [], inlineStickers: [:], mediaReference: .standalone(media: location), threadId: nil, replyToMessageId: nil, replyToStoryId: focusedStoryId, localGroupingKey: nil, correlationId: nil, bubbleUpEmojiOrStickersets: [])
|
||||
self.sendMessages(view: view, peer: peer, messages: [message])
|
||||
self.presentPaidMessageAlertIfNeeded(view: view, completion: { [weak self] in
|
||||
guard let self else {
|
||||
return
|
||||
}
|
||||
self.sendMessages(view: view, peer: peer, messages: [message])
|
||||
})
|
||||
})
|
||||
completion(controller, controller.mediaPickerContext)
|
||||
|
||||
@ -1705,7 +1781,12 @@ final class StoryItemSetContainerSendMessage {
|
||||
}
|
||||
}
|
||||
|
||||
self.sendMessages(view: view, peer: peer, messages: enqueueMessages, silentPosting: silent, scheduleTime: scheduleTime)
|
||||
self.presentPaidMessageAlertIfNeeded(view: view, completion: { [weak self] in
|
||||
guard let self else {
|
||||
return
|
||||
}
|
||||
self.sendMessages(view: view, peer: peer, messages: enqueueMessages, silentPosting: silent, scheduleTime: scheduleTime)
|
||||
})
|
||||
} else if let peer = peers.first {
|
||||
let dataSignal: Signal<(EnginePeer?, DeviceContactExtendedData?), NoError>
|
||||
switch peer {
|
||||
@ -1760,7 +1841,12 @@ final class StoryItemSetContainerSendMessage {
|
||||
}
|
||||
enqueueMessages.append(.message(text: "", attributes: [], inlineStickers: [:], mediaReference: .standalone(media: media), threadId: nil, replyToMessageId: nil, replyToStoryId: focusedStoryId, localGroupingKey: nil, correlationId: nil, bubbleUpEmojiOrStickersets: []))
|
||||
|
||||
self.sendMessages(view: view, peer: targetPeer, messages: enqueueMessages, silentPosting: silent, scheduleTime: scheduleTime)
|
||||
self.presentPaidMessageAlertIfNeeded(view: view, completion: { [weak self] in
|
||||
guard let self else {
|
||||
return
|
||||
}
|
||||
self.sendMessages(view: view, peer: targetPeer, messages: enqueueMessages, silentPosting: silent, scheduleTime: scheduleTime)
|
||||
})
|
||||
} else {
|
||||
let contactController = component.context.sharedContext.makeDeviceContactInfoController(context: ShareControllerAppAccountContext(context: component.context), environment: ShareControllerAppEnvironment(sharedContext: component.context.sharedContext), subject: .filter(peer: peerAndContactData.0?._asPeer(), contactId: nil, contactData: contactData, completion: { [weak self, weak view] peer, contactData in
|
||||
guard let self, let view else {
|
||||
@ -1779,7 +1865,12 @@ final class StoryItemSetContainerSendMessage {
|
||||
}
|
||||
enqueueMessages.append(.message(text: "", attributes: [], inlineStickers: [:], mediaReference: .standalone(media: media), threadId: nil, replyToMessageId: nil, replyToStoryId: focusedStoryId, localGroupingKey: nil, correlationId: nil, bubbleUpEmojiOrStickersets: []))
|
||||
|
||||
self.sendMessages(view: view, peer: targetPeer, messages: enqueueMessages, silentPosting: silent, scheduleTime: scheduleTime)
|
||||
self.presentPaidMessageAlertIfNeeded(view: view, completion: { [weak self] in
|
||||
guard let self else {
|
||||
return
|
||||
}
|
||||
self.sendMessages(view: view, peer: targetPeer, messages: enqueueMessages, silentPosting: silent, scheduleTime: scheduleTime)
|
||||
})
|
||||
}
|
||||
}), completed: nil, cancelled: nil)
|
||||
component.controller()?.push(contactController)
|
||||
@ -2187,7 +2278,12 @@ final class StoryItemSetContainerSendMessage {
|
||||
}
|
||||
|
||||
if !messages.isEmpty {
|
||||
strongSelf.sendMessages(view: view, peer: peer, messages: messages)
|
||||
strongSelf.presentPaidMessageAlertIfNeeded(view: view, completion: { [weak self] in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
strongSelf.sendMessages(view: view, peer: peer, messages: messages)
|
||||
})
|
||||
}
|
||||
}
|
||||
}))
|
||||
@ -2248,7 +2344,12 @@ final class StoryItemSetContainerSendMessage {
|
||||
if !inputText.string.isEmpty {
|
||||
self.clearInputText(view: view)
|
||||
}
|
||||
self.enqueueMediaMessages(view: view, peer: peer, replyToMessageId: nil, replyToStoryId: focusedStoryId, signals: signals, silentPosting: silentPosting, scheduleTime: scheduleTime, parameters: parameters, getAnimatedTransitionSource: getAnimatedTransitionSource, completion: completion)
|
||||
self.presentPaidMessageAlertIfNeeded(view: view, completion: { [weak self] in
|
||||
guard let self else {
|
||||
return
|
||||
}
|
||||
self.enqueueMediaMessages(view: view, peer: peer, replyToMessageId: nil, replyToStoryId: focusedStoryId, signals: signals, silentPosting: silentPosting, scheduleTime: scheduleTime, parameters: parameters, getAnimatedTransitionSource: getAnimatedTransitionSource, completion: completion)
|
||||
})
|
||||
}
|
||||
)
|
||||
}
|
||||
@ -2268,7 +2369,19 @@ final class StoryItemSetContainerSendMessage {
|
||||
guard let self, let view, let component = view.component else {
|
||||
return
|
||||
}
|
||||
if component.context.engine.messages.enqueueOutgoingMessageWithChatContextResult(to: peer.id, threadId: nil, botId: results.botId, result: result, replyToMessageId: replyMessageId.flatMap { EngineMessageReplySubject(messageId: $0, quote: nil) }, replyToStoryId: storyId, hideVia: hideVia, silentPosting: silentPosting, scheduleTime: scheduleTime) {
|
||||
if component.context.engine.messages.enqueueOutgoingMessageWithChatContextResult(
|
||||
to: peer.id,
|
||||
threadId: nil,
|
||||
botId: results.botId,
|
||||
result: result,
|
||||
replyToMessageId: replyMessageId.flatMap { EngineMessageReplySubject(messageId: $0, quote: nil) },
|
||||
replyToStoryId: storyId,
|
||||
hideVia: hideVia,
|
||||
silentPosting: silentPosting,
|
||||
scheduleTime: scheduleTime,
|
||||
sendPaidMessageStars: component.slice.additionalPeerData.sendPaidMessageStars,
|
||||
postpone: false
|
||||
) {
|
||||
}
|
||||
|
||||
if let attachmentController = self.attachmentController {
|
||||
@ -2416,10 +2529,15 @@ final class StoryItemSetContainerSendMessage {
|
||||
guard let self, let view else {
|
||||
return
|
||||
}
|
||||
self.enqueueMediaMessages(view: view, peer: peer, replyToMessageId: replyToMessageId, replyToStoryId: replyToStoryId, signals: signals, silentPosting: silentPosting, scheduleTime: scheduleTime > 0 ? scheduleTime : nil, parameters: parameters)
|
||||
if !inputText.string.isEmpty {
|
||||
self.clearInputText(view: view)
|
||||
}
|
||||
self.presentPaidMessageAlertIfNeeded(view: view, completion: { [weak self, weak view] in
|
||||
guard let self, let view else {
|
||||
return
|
||||
}
|
||||
self.enqueueMediaMessages(view: view, peer: peer, replyToMessageId: replyToMessageId, replyToStoryId: replyToStoryId, signals: signals, silentPosting: silentPosting, scheduleTime: scheduleTime > 0 ? scheduleTime : nil, parameters: parameters)
|
||||
if !inputText.string.isEmpty {
|
||||
self.clearInputText(view: view)
|
||||
}
|
||||
})
|
||||
}, recognizedQRCode: { _ in
|
||||
}, presentSchedulePicker: { [weak self, weak view] _, done in
|
||||
guard let self, let view else {
|
||||
@ -2545,6 +2663,10 @@ final class StoryItemSetContainerSendMessage {
|
||||
attributes.append(OutgoingScheduleInfoMessageAttribute(scheduleTime: scheduleTime))
|
||||
}
|
||||
}
|
||||
var messageAttributes: [MessageAttribute] = []
|
||||
if let component = view.component, let sendPaidMessageStars = component.slice.additionalPeerData.sendPaidMessageStars {
|
||||
messageAttributes.append(PaidStarsMessageAttribute(stars: sendPaidMessageStars, postponeSending: false))
|
||||
}
|
||||
return attributes
|
||||
}
|
||||
}
|
||||
|
@ -2604,8 +2604,12 @@ extension ChatControllerImpl {
|
||||
strongSelf.interfaceInteraction?.displaySlowmodeTooltip(node.view, rect)
|
||||
return false
|
||||
}
|
||||
|
||||
strongSelf.enqueueChatContextResult(results, result)
|
||||
strongSelf.presentPaidMessageAlertIfNeeded(completion: { [weak self] postpone in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
strongSelf.enqueueChatContextResult(results, result, postpone: postpone)
|
||||
})
|
||||
return true
|
||||
}, sendBotCommand: { [weak self] botPeer, command in
|
||||
if let strongSelf = self, canSendMessagesToChat(strongSelf.presentationInterfaceState) {
|
||||
|
@ -250,10 +250,8 @@ extension ChatControllerImpl {
|
||||
}
|
||||
|
||||
var sendImmediately = false
|
||||
if let _ = self.presentationInterfaceState.sendPaidMessageStars {
|
||||
if case .send = action {
|
||||
updatedAction = .preview
|
||||
}
|
||||
if let _ = self.presentationInterfaceState.sendPaidMessageStars, case .send = action {
|
||||
updatedAction = .preview
|
||||
sendImmediately = true
|
||||
}
|
||||
|
||||
|
@ -23,10 +23,10 @@ extension ChatControllerImpl {
|
||||
if let sendPaidMessageStars = self.presentationInterfaceState.sendPaidMessageStars {
|
||||
let _ = (ApplicationSpecificNotice.dismissedPaidMessageWarningNamespace(accountManager: self.context.sharedContext.accountManager, peerId: peer.id)
|
||||
|> deliverOnMainQueue).start(next: { [weak self] dismissedAmount in
|
||||
guard let self else {
|
||||
guard let self, let starsContext = self.context.starsContext else {
|
||||
return
|
||||
}
|
||||
if let dismissedAmount, dismissedAmount == sendPaidMessageStars.value {
|
||||
if let dismissedAmount, dismissedAmount == sendPaidMessageStars.value, let currentState = starsContext.currentState, currentState.balance > sendPaidMessageStars {
|
||||
completion(true)
|
||||
self.displayPaidMessageUndo(count: count, amount: sendPaidMessageStars)
|
||||
} else {
|
||||
@ -37,14 +37,14 @@ extension ChatControllerImpl {
|
||||
let controller = chatMessagePaymentAlertController(
|
||||
context: self.context,
|
||||
presentationData: presentationData,
|
||||
updatedPresentationData: nil,//self.updatedPresentationData,
|
||||
updatedPresentationData: nil,
|
||||
peers: [peer],
|
||||
count: count,
|
||||
amount: sendPaidMessageStars,
|
||||
totalAmount: nil,
|
||||
navigationController: self.navigationController as? NavigationController,
|
||||
completion: { [weak self] dontAskAgain in
|
||||
guard let self, let starsContext = self.context.starsContext else {
|
||||
guard let self else {
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -9515,7 +9515,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
}))
|
||||
}
|
||||
|
||||
func enqueueChatContextResult(_ results: ChatContextResultCollection, _ result: ChatContextResult, hideVia: Bool = false, closeMediaInput: Bool = false, silentPosting: Bool = false, resetTextInputState: Bool = true) {
|
||||
func enqueueChatContextResult(_ results: ChatContextResultCollection, _ result: ChatContextResult, hideVia: Bool = false, closeMediaInput: Bool = false, silentPosting: Bool = false, resetTextInputState: Bool = true, postpone: Bool = false) {
|
||||
if !canSendMessagesToChat(self.presentationInterfaceState) {
|
||||
return
|
||||
}
|
||||
@ -9534,7 +9534,9 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
|
||||
return
|
||||
}
|
||||
let replyMessageSubject = self.presentationInterfaceState.interfaceState.replyMessageSubject
|
||||
if self.context.engine.messages.enqueueOutgoingMessageWithChatContextResult(to: peerId, threadId: self.chatLocation.threadId, botId: results.botId, result: result, replyToMessageId: replyMessageSubject?.subjectModel, hideVia: hideVia, silentPosting: silentPosting, scheduleTime: scheduleTime) {
|
||||
|
||||
let sendPaidMessageStars = self.presentationInterfaceState.sendPaidMessageStars
|
||||
if self.context.engine.messages.enqueueOutgoingMessageWithChatContextResult(to: peerId, threadId: self.chatLocation.threadId, botId: results.botId, result: result, replyToMessageId: replyMessageSubject?.subjectModel, hideVia: hideVia, silentPosting: silentPosting, scheduleTime: scheduleTime, sendPaidMessageStars: sendPaidMessageStars, postpone: postpone) {
|
||||
self.chatDisplayNode.setupSendActionOnViewUpdate({ [weak self] in
|
||||
if let strongSelf = self {
|
||||
strongSelf.chatDisplayNode.collapseInput()
|
||||
|
@ -13,8 +13,9 @@ import ChatInterfaceState
|
||||
import PremiumUI
|
||||
import ReactionSelectionNode
|
||||
import TopMessageReactions
|
||||
import ChatMessagePaymentAlertController
|
||||
|
||||
extension ChatControllerImpl {
|
||||
extension ChatControllerImpl {
|
||||
func forwardMessages(messageIds: [MessageId], options: ChatInterfaceForwardOptionsState? = nil, resetCurrent: Bool = false) {
|
||||
let _ = (self.context.engine.data.get(EngineDataMap(
|
||||
messageIds.map(TelegramEngine.EngineData.Item.Messages.Message.init)
|
||||
@ -94,190 +95,246 @@ extension ChatControllerImpl {
|
||||
}
|
||||
}
|
||||
controller.multiplePeersSelected = { [weak self, weak controller] peers, peerMap, messageText, mode, forwardOptions, _ in
|
||||
guard let strongSelf = self, let strongController = controller else {
|
||||
return
|
||||
}
|
||||
strongController.dismiss()
|
||||
let peerIds = peers.map { $0.id }
|
||||
|
||||
var result: [EnqueueMessage] = []
|
||||
if messageText.string.count > 0 {
|
||||
let inputText = convertMarkdownToAttributes(messageText)
|
||||
for text in breakChatInputText(trimChatInputText(inputText)) {
|
||||
if text.length != 0 {
|
||||
var attributes: [MessageAttribute] = []
|
||||
let entities = generateTextEntities(text.string, enabledTypes: .all, currentEntities: generateChatInputTextEntities(text))
|
||||
if !entities.isEmpty {
|
||||
attributes.append(TextEntitiesMessageAttribute(entities: entities))
|
||||
}
|
||||
result.append(.message(text: text.string, attributes: attributes, inlineStickers: [:], mediaReference: nil, threadId: strongSelf.chatLocation.threadId, replyToMessageId: nil, replyToStoryId: nil, localGroupingKey: nil, correlationId: nil, bubbleUpEmojiOrStickersets: []))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var attributes: [MessageAttribute] = []
|
||||
attributes.append(ForwardOptionsMessageAttribute(hideNames: forwardOptions?.hideNames == true, hideCaptions: forwardOptions?.hideCaptions == true))
|
||||
|
||||
result.append(contentsOf: messages.map { message -> EnqueueMessage in
|
||||
return .forward(source: message.id, threadId: nil, grouping: .auto, attributes: attributes, correlationId: nil)
|
||||
})
|
||||
|
||||
let commit: ([EnqueueMessage]) -> Void = { result in
|
||||
let _ = (context.engine.data.get(
|
||||
EngineDataMap(
|
||||
peerIds.map(TelegramEngine.EngineData.Item.Peer.SendPaidMessageStars.init(id:))
|
||||
)
|
||||
)
|
||||
|> deliverOnMainQueue).start(next: { [weak self, weak controller] sendPaidMessageStars in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
var result = result
|
||||
|
||||
strongSelf.updateChatPresentationInterfaceState(animated: false, interactive: true, { $0.updatedInterfaceState({ $0.withoutSelectionState() }).updatedSearch(nil) })
|
||||
|
||||
var correlationIds: [Int64] = []
|
||||
for i in 0 ..< result.count {
|
||||
let correlationId = Int64.random(in: Int64.min ... Int64.max)
|
||||
correlationIds.append(correlationId)
|
||||
result[i] = result[i].withUpdatedCorrelationId(correlationId)
|
||||
var count: Int32 = Int32(messages.count)
|
||||
if messageText.string.count > 0 {
|
||||
count += 1
|
||||
}
|
||||
|
||||
let targetPeersShouldDivertSignals: [Signal<(EnginePeer, Bool), NoError>] = peers.map { peer -> Signal<(EnginePeer, Bool), NoError> in
|
||||
return strongSelf.shouldDivertMessagesToScheduled(targetPeer: peer, messages: result)
|
||||
|> map { shouldDivert -> (EnginePeer, Bool) in
|
||||
return (peer, shouldDivert)
|
||||
var totalAmount: StarsAmount = .zero
|
||||
for peer in peers {
|
||||
if let maybeAmount = sendPaidMessageStars[peer.id], let amount = maybeAmount {
|
||||
totalAmount = totalAmount + amount
|
||||
}
|
||||
}
|
||||
let targetPeersShouldDivert: Signal<[(EnginePeer, Bool)], NoError> = combineLatest(targetPeersShouldDivertSignals)
|
||||
let _ = (targetPeersShouldDivert
|
||||
|> deliverOnMainQueue).startStandalone(next: { targetPeersShouldDivert in
|
||||
guard let strongSelf = self else {
|
||||
|
||||
let proceed = { [weak self, weak controller] in
|
||||
guard let strongSelf = self, let strongController = controller else {
|
||||
return
|
||||
}
|
||||
|
||||
var displayConvertingTooltip = false
|
||||
strongController.dismiss()
|
||||
|
||||
var displayPeers: [EnginePeer] = []
|
||||
for (peer, shouldDivert) in targetPeersShouldDivert {
|
||||
var peerMessages = result
|
||||
if shouldDivert {
|
||||
displayConvertingTooltip = true
|
||||
peerMessages = peerMessages.map { message -> EnqueueMessage in
|
||||
return message.withUpdatedAttributes { attributes in
|
||||
var attributes = attributes
|
||||
attributes.removeAll(where: { $0 is OutgoingScheduleInfoMessageAttribute })
|
||||
attributes.append(OutgoingScheduleInfoMessageAttribute(scheduleTime: Int32(Date().timeIntervalSince1970) + 10 * 24 * 60 * 60))
|
||||
return attributes
|
||||
var result: [EnqueueMessage] = []
|
||||
if messageText.string.count > 0 {
|
||||
let inputText = convertMarkdownToAttributes(messageText)
|
||||
for text in breakChatInputText(trimChatInputText(inputText)) {
|
||||
if text.length != 0 {
|
||||
var attributes: [MessageAttribute] = []
|
||||
let entities = generateTextEntities(text.string, enabledTypes: .all, currentEntities: generateChatInputTextEntities(text))
|
||||
if !entities.isEmpty {
|
||||
attributes.append(TextEntitiesMessageAttribute(entities: entities))
|
||||
}
|
||||
result.append(.message(text: text.string, attributes: attributes, inlineStickers: [:], mediaReference: nil, threadId: strongSelf.chatLocation.threadId, replyToMessageId: nil, replyToStoryId: nil, localGroupingKey: nil, correlationId: nil, bubbleUpEmojiOrStickersets: []))
|
||||
}
|
||||
}
|
||||
|
||||
let _ = (enqueueMessages(account: strongSelf.context.account, peerId: peer.id, messages: peerMessages)
|
||||
|> deliverOnMainQueue).startStandalone(next: { messageIds in
|
||||
if let strongSelf = self {
|
||||
let signals: [Signal<Bool, NoError>] = messageIds.compactMap({ id -> Signal<Bool, NoError>? in
|
||||
guard let id = id else {
|
||||
return nil
|
||||
}
|
||||
return strongSelf.context.account.pendingMessageManager.pendingMessageStatus(id)
|
||||
|> mapToSignal { status, _ -> Signal<Bool, NoError> in
|
||||
if status != nil {
|
||||
return .never()
|
||||
} else {
|
||||
return .single(true)
|
||||
}
|
||||
}
|
||||
|> take(1)
|
||||
})
|
||||
if strongSelf.shareStatusDisposable == nil {
|
||||
strongSelf.shareStatusDisposable = MetaDisposable()
|
||||
}
|
||||
strongSelf.shareStatusDisposable?.set((combineLatest(signals)
|
||||
|> deliverOnMainQueue).startStrict())
|
||||
}
|
||||
})
|
||||
|
||||
if case let .secretChat(secretPeer) = peer {
|
||||
if let peer = peerMap[secretPeer.regularPeerId] {
|
||||
displayPeers.append(peer)
|
||||
}
|
||||
} else {
|
||||
displayPeers.append(peer)
|
||||
}
|
||||
}
|
||||
|
||||
let presentationData = strongSelf.context.sharedContext.currentPresentationData.with { $0 }
|
||||
let text: String
|
||||
var savedMessages = false
|
||||
if displayPeers.count == 1, let peerId = displayPeers.first?.id, peerId == strongSelf.context.account.peerId {
|
||||
text = messages.count == 1 ? presentationData.strings.Conversation_ForwardTooltip_SavedMessages_One : presentationData.strings.Conversation_ForwardTooltip_SavedMessages_Many
|
||||
savedMessages = true
|
||||
} else {
|
||||
if displayPeers.count == 1, let peer = displayPeers.first {
|
||||
var peerName = peer.id == strongSelf.context.account.peerId ? presentationData.strings.DialogList_SavedMessages : peer.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder)
|
||||
peerName = peerName.replacingOccurrences(of: "**", with: "")
|
||||
text = messages.count == 1 ? presentationData.strings.Conversation_ForwardTooltip_Chat_One(peerName).string : presentationData.strings.Conversation_ForwardTooltip_Chat_Many(peerName).string
|
||||
} else if displayPeers.count == 2, let firstPeer = displayPeers.first, let secondPeer = displayPeers.last {
|
||||
var firstPeerName = firstPeer.id == strongSelf.context.account.peerId ? presentationData.strings.DialogList_SavedMessages : firstPeer.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder)
|
||||
firstPeerName = firstPeerName.replacingOccurrences(of: "**", with: "")
|
||||
var secondPeerName = secondPeer.id == strongSelf.context.account.peerId ? presentationData.strings.DialogList_SavedMessages : secondPeer.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder)
|
||||
secondPeerName = secondPeerName.replacingOccurrences(of: "**", with: "")
|
||||
text = messages.count == 1 ? presentationData.strings.Conversation_ForwardTooltip_TwoChats_One(firstPeerName, secondPeerName).string : presentationData.strings.Conversation_ForwardTooltip_TwoChats_Many(firstPeerName, secondPeerName).string
|
||||
} else if let peer = displayPeers.first {
|
||||
var peerName = peer.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder)
|
||||
peerName = peerName.replacingOccurrences(of: "**", with: "")
|
||||
text = messages.count == 1 ? presentationData.strings.Conversation_ForwardTooltip_ManyChats_One(peerName, "\(displayPeers.count - 1)").string : presentationData.strings.Conversation_ForwardTooltip_ManyChats_Many(peerName, "\(displayPeers.count - 1)").string
|
||||
} else {
|
||||
text = ""
|
||||
}
|
||||
}
|
||||
|
||||
let reactionItems: Signal<[ReactionItem], NoError>
|
||||
if savedMessages && messages.count > 0 {
|
||||
reactionItems = tagMessageReactions(context: strongSelf.context, subPeerId: nil)
|
||||
} else {
|
||||
reactionItems = .single([])
|
||||
}
|
||||
var attributes: [MessageAttribute] = []
|
||||
attributes.append(ForwardOptionsMessageAttribute(hideNames: forwardOptions?.hideNames == true, hideCaptions: forwardOptions?.hideCaptions == true))
|
||||
|
||||
let _ = (reactionItems
|
||||
|> deliverOnMainQueue).startStandalone(next: { [weak strongSelf] reactionItems in
|
||||
guard let strongSelf else {
|
||||
return
|
||||
}
|
||||
|
||||
strongSelf.present(UndoOverlayController(presentationData: presentationData, content: .forward(savedMessages: savedMessages, text: text), elevatedLayout: false, position: savedMessages && messages.count > 0 ? .top : .bottom, animateInAsReplacement: true, action: { action in
|
||||
if savedMessages, let self, action == .info {
|
||||
let _ = (self.context.engine.data.get(TelegramEngine.EngineData.Item.Peer.Peer(id: self.context.account.peerId))
|
||||
|> deliverOnMainQueue).start(next: { [weak self] peer in
|
||||
guard let self, let peer else {
|
||||
return
|
||||
}
|
||||
guard let navigationController = self.navigationController as? NavigationController else {
|
||||
return
|
||||
}
|
||||
self.context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: self.context, chatLocation: .peer(peer), forceOpenChat: true))
|
||||
})
|
||||
}
|
||||
return false
|
||||
}, additionalView: (savedMessages && messages.count > 0) ? chatShareToSavedMessagesAdditionalView(strongSelf, reactionItems: reactionItems, correlationIds: correlationIds) : nil), in: .current)
|
||||
result.append(contentsOf: messages.map { message -> EnqueueMessage in
|
||||
return .forward(source: message.id, threadId: nil, grouping: .auto, attributes: attributes, correlationId: nil)
|
||||
})
|
||||
|
||||
if displayConvertingTooltip {
|
||||
let commit: ([EnqueueMessage]) -> Void = { result in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
var result = result
|
||||
|
||||
strongSelf.updateChatPresentationInterfaceState(animated: false, interactive: true, { $0.updatedInterfaceState({ $0.withoutSelectionState() }).updatedSearch(nil) })
|
||||
|
||||
var correlationIds: [Int64] = []
|
||||
for i in 0 ..< result.count {
|
||||
let correlationId = Int64.random(in: Int64.min ... Int64.max)
|
||||
correlationIds.append(correlationId)
|
||||
result[i] = result[i].withUpdatedCorrelationId(correlationId)
|
||||
}
|
||||
|
||||
let targetPeersShouldDivertSignals: [Signal<(EnginePeer, Bool), NoError>] = peers.map { peer -> Signal<(EnginePeer, Bool), NoError> in
|
||||
return strongSelf.shouldDivertMessagesToScheduled(targetPeer: peer, messages: result)
|
||||
|> map { shouldDivert -> (EnginePeer, Bool) in
|
||||
return (peer, shouldDivert)
|
||||
}
|
||||
}
|
||||
let targetPeersShouldDivert: Signal<[(EnginePeer, Bool)], NoError> = combineLatest(targetPeersShouldDivertSignals)
|
||||
let _ = (targetPeersShouldDivert
|
||||
|> deliverOnMainQueue).startStandalone(next: { targetPeersShouldDivert in
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
|
||||
var displayConvertingTooltip = false
|
||||
|
||||
var displayPeers: [EnginePeer] = []
|
||||
for (peer, shouldDivert) in targetPeersShouldDivert {
|
||||
var peerMessages = result
|
||||
if shouldDivert {
|
||||
displayConvertingTooltip = true
|
||||
peerMessages = peerMessages.map { message -> EnqueueMessage in
|
||||
return message.withUpdatedAttributes { attributes in
|
||||
var attributes = attributes
|
||||
attributes.removeAll(where: { $0 is OutgoingScheduleInfoMessageAttribute })
|
||||
attributes.append(OutgoingScheduleInfoMessageAttribute(scheduleTime: Int32(Date().timeIntervalSince1970) + 10 * 24 * 60 * 60))
|
||||
return attributes
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if let maybeAmount = sendPaidMessageStars[peer.id], let amount = maybeAmount {
|
||||
peerMessages = peerMessages.map { message -> EnqueueMessage in
|
||||
return message.withUpdatedAttributes { attributes in
|
||||
var attributes = attributes
|
||||
attributes.append(PaidStarsMessageAttribute(stars: amount, postponeSending: false))
|
||||
return attributes
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let _ = (enqueueMessages(account: strongSelf.context.account, peerId: peer.id, messages: peerMessages)
|
||||
|> deliverOnMainQueue).startStandalone(next: { messageIds in
|
||||
if let strongSelf = self {
|
||||
let signals: [Signal<Bool, NoError>] = messageIds.compactMap({ id -> Signal<Bool, NoError>? in
|
||||
guard let id = id else {
|
||||
return nil
|
||||
}
|
||||
return strongSelf.context.account.pendingMessageManager.pendingMessageStatus(id)
|
||||
|> mapToSignal { status, _ -> Signal<Bool, NoError> in
|
||||
if status != nil {
|
||||
return .never()
|
||||
} else {
|
||||
return .single(true)
|
||||
}
|
||||
}
|
||||
|> take(1)
|
||||
})
|
||||
if strongSelf.shareStatusDisposable == nil {
|
||||
strongSelf.shareStatusDisposable = MetaDisposable()
|
||||
}
|
||||
strongSelf.shareStatusDisposable?.set((combineLatest(signals)
|
||||
|> deliverOnMainQueue).startStrict())
|
||||
}
|
||||
})
|
||||
|
||||
if case let .secretChat(secretPeer) = peer {
|
||||
if let peer = peerMap[secretPeer.regularPeerId] {
|
||||
displayPeers.append(peer)
|
||||
}
|
||||
} else {
|
||||
displayPeers.append(peer)
|
||||
}
|
||||
}
|
||||
|
||||
let presentationData = strongSelf.context.sharedContext.currentPresentationData.with { $0 }
|
||||
let text: String
|
||||
var savedMessages = false
|
||||
if displayPeers.count == 1, let peerId = displayPeers.first?.id, peerId == strongSelf.context.account.peerId {
|
||||
text = messages.count == 1 ? presentationData.strings.Conversation_ForwardTooltip_SavedMessages_One : presentationData.strings.Conversation_ForwardTooltip_SavedMessages_Many
|
||||
savedMessages = true
|
||||
} else {
|
||||
if displayPeers.count == 1, let peer = displayPeers.first {
|
||||
var peerName = peer.id == strongSelf.context.account.peerId ? presentationData.strings.DialogList_SavedMessages : peer.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder)
|
||||
peerName = peerName.replacingOccurrences(of: "**", with: "")
|
||||
text = messages.count == 1 ? presentationData.strings.Conversation_ForwardTooltip_Chat_One(peerName).string : presentationData.strings.Conversation_ForwardTooltip_Chat_Many(peerName).string
|
||||
} else if displayPeers.count == 2, let firstPeer = displayPeers.first, let secondPeer = displayPeers.last {
|
||||
var firstPeerName = firstPeer.id == strongSelf.context.account.peerId ? presentationData.strings.DialogList_SavedMessages : firstPeer.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder)
|
||||
firstPeerName = firstPeerName.replacingOccurrences(of: "**", with: "")
|
||||
var secondPeerName = secondPeer.id == strongSelf.context.account.peerId ? presentationData.strings.DialogList_SavedMessages : secondPeer.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder)
|
||||
secondPeerName = secondPeerName.replacingOccurrences(of: "**", with: "")
|
||||
text = messages.count == 1 ? presentationData.strings.Conversation_ForwardTooltip_TwoChats_One(firstPeerName, secondPeerName).string : presentationData.strings.Conversation_ForwardTooltip_TwoChats_Many(firstPeerName, secondPeerName).string
|
||||
} else if let peer = displayPeers.first {
|
||||
var peerName = peer.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder)
|
||||
peerName = peerName.replacingOccurrences(of: "**", with: "")
|
||||
text = messages.count == 1 ? presentationData.strings.Conversation_ForwardTooltip_ManyChats_One(peerName, "\(displayPeers.count - 1)").string : presentationData.strings.Conversation_ForwardTooltip_ManyChats_Many(peerName, "\(displayPeers.count - 1)").string
|
||||
} else {
|
||||
text = ""
|
||||
}
|
||||
}
|
||||
|
||||
let reactionItems: Signal<[ReactionItem], NoError>
|
||||
if savedMessages && messages.count > 0 {
|
||||
reactionItems = tagMessageReactions(context: strongSelf.context, subPeerId: nil)
|
||||
} else {
|
||||
reactionItems = .single([])
|
||||
}
|
||||
|
||||
let _ = (reactionItems
|
||||
|> deliverOnMainQueue).startStandalone(next: { [weak strongSelf] reactionItems in
|
||||
guard let strongSelf else {
|
||||
return
|
||||
}
|
||||
|
||||
strongSelf.present(UndoOverlayController(presentationData: presentationData, content: .forward(savedMessages: savedMessages, text: text), elevatedLayout: false, position: savedMessages && messages.count > 0 ? .top : .bottom, animateInAsReplacement: true, action: { action in
|
||||
if savedMessages, let self, action == .info {
|
||||
let _ = (self.context.engine.data.get(TelegramEngine.EngineData.Item.Peer.Peer(id: self.context.account.peerId))
|
||||
|> deliverOnMainQueue).start(next: { [weak self] peer in
|
||||
guard let self, let peer else {
|
||||
return
|
||||
}
|
||||
guard let navigationController = self.navigationController as? NavigationController else {
|
||||
return
|
||||
}
|
||||
self.context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: self.context, chatLocation: .peer(peer), forceOpenChat: true))
|
||||
})
|
||||
}
|
||||
return false
|
||||
}, additionalView: (savedMessages && messages.count > 0) ? chatShareToSavedMessagesAdditionalView(strongSelf, reactionItems: reactionItems, correlationIds: correlationIds) : nil), in: .current)
|
||||
})
|
||||
|
||||
if displayConvertingTooltip {
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
switch mode {
|
||||
case .generic:
|
||||
commit(result)
|
||||
case .silent:
|
||||
let transformedMessages = strongSelf.transformEnqueueMessages(result, silentPosting: true)
|
||||
commit(transformedMessages)
|
||||
case .schedule:
|
||||
strongSelf.presentScheduleTimePicker(completion: { [weak self] scheduleTime in
|
||||
if let strongSelf = self {
|
||||
let transformedMessages = strongSelf.transformEnqueueMessages(result, silentPosting: false, scheduleTime: scheduleTime)
|
||||
|
||||
switch mode {
|
||||
case .generic:
|
||||
commit(result)
|
||||
case .silent:
|
||||
let transformedMessages = strongSelf.transformEnqueueMessages(result, silentPosting: true)
|
||||
commit(transformedMessages)
|
||||
case .schedule:
|
||||
strongSelf.presentScheduleTimePicker(completion: { [weak self] scheduleTime in
|
||||
if let strongSelf = self {
|
||||
let transformedMessages = strongSelf.transformEnqueueMessages(result, silentPosting: false, scheduleTime: scheduleTime)
|
||||
commit(transformedMessages)
|
||||
}
|
||||
})
|
||||
case .whenOnline:
|
||||
let transformedMessages = strongSelf.transformEnqueueMessages(result, silentPosting: false, scheduleTime: scheduleWhenOnlineTimestamp)
|
||||
commit(transformedMessages)
|
||||
}
|
||||
})
|
||||
case .whenOnline:
|
||||
let transformedMessages = strongSelf.transformEnqueueMessages(result, silentPosting: false, scheduleTime: scheduleWhenOnlineTimestamp)
|
||||
commit(transformedMessages)
|
||||
}
|
||||
}
|
||||
|
||||
if totalAmount.value > 0 {
|
||||
let controller = chatMessagePaymentAlertController(
|
||||
context: nil,
|
||||
presentationData: strongSelf.presentationData,
|
||||
updatedPresentationData: nil,
|
||||
peers: peers,
|
||||
count: count,
|
||||
amount: totalAmount,
|
||||
totalAmount: totalAmount,
|
||||
hasCheck: false,
|
||||
navigationController: strongSelf.navigationController as? NavigationController,
|
||||
completion: { _ in
|
||||
proceed()
|
||||
}
|
||||
)
|
||||
strongSelf.present(controller, in: .window(.root))
|
||||
} else {
|
||||
proceed()
|
||||
}
|
||||
})
|
||||
}
|
||||
controller.peerSelected = { [weak self, weak controller] peer, threadId in
|
||||
guard let strongSelf = self, let strongController = controller else {
|
||||
|
@ -1927,8 +1927,7 @@ class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDelegate, Ch
|
||||
}
|
||||
} else {
|
||||
if let sendPaidMessageStars = interfaceState.sendPaidMessageStars {
|
||||
//TODO:localize
|
||||
placeholder = "Message for # \(presentationStringsFormattedNumber(Int32(sendPaidMessageStars.value), interfaceState.dateTimeFormat.groupingSeparator))"
|
||||
placeholder = interfaceState.strings.Chat_InputTextPaidMessagePlaceholder(" # \(presentationStringsFormattedNumber(Int32(sendPaidMessageStars.value), interfaceState.dateTimeFormat.groupingSeparator))").string
|
||||
placeholderHasStar = true
|
||||
} else {
|
||||
placeholder = interfaceState.strings.Conversation_InputTextPlaceholder
|
||||
|
Loading…
x
Reference in New Issue
Block a user