diff --git a/submodules/AccountContext/Sources/AccountContext.swift b/submodules/AccountContext/Sources/AccountContext.swift index 877ed5d1f5..4faa45e954 100644 --- a/submodules/AccountContext/Sources/AccountContext.swift +++ b/submodules/AccountContext/Sources/AccountContext.swift @@ -1506,7 +1506,10 @@ public struct StarsSubscriptionConfiguration { paidMessagesAvailable: false, starGiftResaleMinAmount: 125, starGiftResaleMaxAmount: 3500, - starGiftCommissionPermille: 80 + starGiftCommissionPermille: 80, + channelMessageSuggestionCommissionPermille: 850, + channelMessageSuggestionMaxStarsAmount: 10000, + channelMessageSuggestionMaxTonAmount: 10000000000000 ) } @@ -1518,6 +1521,9 @@ public struct StarsSubscriptionConfiguration { public let starGiftResaleMinAmount: Int64 public let starGiftResaleMaxAmount: Int64 public let starGiftCommissionPermille: Int32 + public let channelMessageSuggestionCommissionPermille: Int32 + public let channelMessageSuggestionMaxStarsAmount: Int64 + public let channelMessageSuggestionMaxTonAmount: Int64 fileprivate init( maxFee: Int64, @@ -1527,7 +1533,10 @@ public struct StarsSubscriptionConfiguration { paidMessagesAvailable: Bool, starGiftResaleMinAmount: Int64, starGiftResaleMaxAmount: Int64, - starGiftCommissionPermille: Int32 + starGiftCommissionPermille: Int32, + channelMessageSuggestionCommissionPermille: Int32, + channelMessageSuggestionMaxStarsAmount: Int64, + channelMessageSuggestionMaxTonAmount: Int64 ) { self.maxFee = maxFee self.usdWithdrawRate = usdWithdrawRate @@ -1537,6 +1546,9 @@ public struct StarsSubscriptionConfiguration { self.starGiftResaleMinAmount = starGiftResaleMinAmount self.starGiftResaleMaxAmount = starGiftResaleMaxAmount self.starGiftCommissionPermille = starGiftCommissionPermille + self.channelMessageSuggestionCommissionPermille = channelMessageSuggestionCommissionPermille + self.channelMessageSuggestionMaxStarsAmount = channelMessageSuggestionMaxStarsAmount + self.channelMessageSuggestionMaxTonAmount = channelMessageSuggestionMaxTonAmount } public static func with(appConfiguration: AppConfiguration) -> StarsSubscriptionConfiguration { @@ -1550,6 +1562,10 @@ public struct StarsSubscriptionConfiguration { let starGiftResaleMaxAmount = (data["stars_stargift_resale_amount_max"] as? Double).flatMap(Int64.init) ?? StarsSubscriptionConfiguration.defaultValue.starGiftResaleMaxAmount let starGiftCommissionPermille = (data["stars_stargift_resale_commission_permille"] as? Double).flatMap(Int32.init) ?? StarsSubscriptionConfiguration.defaultValue.starGiftCommissionPermille + let channelMessageSuggestionCommissionPermille = (data["stars_suggested_post_commission_permille"] as? Double).flatMap(Int32.init) ?? StarsSubscriptionConfiguration.defaultValue.channelMessageSuggestionCommissionPermille + let channelMessageSuggestionMaxStarsAmount = (data["stars_suggested_post_amount_max"] as? Double).flatMap(Int64.init) ?? StarsSubscriptionConfiguration.defaultValue.channelMessageSuggestionMaxStarsAmount + let channelMessageSuggestionMaxTonAmount = (data["ton_suggested_post_amount_max"] as? Double).flatMap(Int64.init) ?? StarsSubscriptionConfiguration.defaultValue.channelMessageSuggestionMaxTonAmount + return StarsSubscriptionConfiguration( maxFee: maxFee, usdWithdrawRate: usdWithdrawRate, @@ -1558,7 +1574,10 @@ public struct StarsSubscriptionConfiguration { paidMessagesAvailable: paidMessagesAvailable, starGiftResaleMinAmount: starGiftResaleMinAmount, starGiftResaleMaxAmount: starGiftResaleMaxAmount, - starGiftCommissionPermille: starGiftCommissionPermille + starGiftCommissionPermille: starGiftCommissionPermille, + channelMessageSuggestionCommissionPermille: channelMessageSuggestionCommissionPermille, + channelMessageSuggestionMaxStarsAmount: channelMessageSuggestionMaxStarsAmount, + channelMessageSuggestionMaxTonAmount: channelMessageSuggestionMaxTonAmount ) } else { return .defaultValue diff --git a/submodules/MediaPickerUI/Sources/MediaPickerScreen.swift b/submodules/MediaPickerUI/Sources/MediaPickerScreen.swift index f374dc79e3..3eeeb0943b 100644 --- a/submodules/MediaPickerUI/Sources/MediaPickerScreen.swift +++ b/submodules/MediaPickerUI/Sources/MediaPickerScreen.swift @@ -182,6 +182,7 @@ public final class MediaPickerScreenImpl: ViewController, MediaPickerScreen, Att private let chatLocation: ChatLocation? private let bannedSendPhotos: (Int32, Bool)? private let bannedSendVideos: (Int32, Bool)? + private let enableMultiselection: Bool private let canBoostToUnrestrict: Bool fileprivate let paidMediaAllowed: Bool fileprivate let subject: Subject @@ -1845,6 +1846,7 @@ public final class MediaPickerScreenImpl: ViewController, MediaPickerScreen, Att isScheduledMessages: Bool = false, bannedSendPhotos: (Int32, Bool)? = nil, bannedSendVideos: (Int32, Bool)? = nil, + enableMultiselection: Bool = true, canBoostToUnrestrict: Bool = false, paidMediaAllowed: Bool = false, subject: Subject, @@ -1868,6 +1870,7 @@ public final class MediaPickerScreenImpl: ViewController, MediaPickerScreen, Att self.isScheduledMessages = isScheduledMessages self.bannedSendPhotos = bannedSendPhotos self.bannedSendVideos = bannedSendVideos + self.enableMultiselection = enableMultiselection self.canBoostToUnrestrict = canBoostToUnrestrict self.paidMediaAllowed = paidMediaAllowed self.subject = subject @@ -1877,7 +1880,7 @@ public final class MediaPickerScreenImpl: ViewController, MediaPickerScreen, Att self.mainButtonAction = mainButtonAction self.secondaryButtonAction = secondaryButtonAction - let selectionContext = selectionContext ?? TGMediaSelectionContext() + let selectionContext = selectionContext ?? TGMediaSelectionContext(groupingAllowed: false, selectionLimit: enableMultiselection ? 100 : 1)! self.titleView = MediaPickerTitleView(theme: self.presentationData.theme, segments: [self.presentationData.strings.Attachment_AllMedia, self.presentationData.strings.Attachment_SelectedMedia(1)], selectedIndex: 0) @@ -1924,11 +1927,12 @@ public final class MediaPickerScreenImpl: ViewController, MediaPickerScreen, Att super.init(navigationBarPresentationData: NavigationBarPresentationData(presentationData: presentationData)) self.statusBar.statusBarStyle = .Ignore - + selectionContext.attemptSelectingItem = { [weak self] item in guard let self else { return false } + if let _ = item as? TGMediaPickerGalleryPhotoItem { if self.bannedSendPhotos != nil { self.present(standardTextAlertController(theme: AlertControllerTheme(presentationData: self.presentationData), title: nil, text: self.presentationData.strings.Chat_SendNotAllowedPhoto, actions: [TextAlertAction(type: .defaultAction, title: self.presentationData.strings.Common_OK, action: {})]), in: .window(.root)) @@ -2807,7 +2811,7 @@ public final class MediaPickerScreenImpl: ViewController, MediaPickerScreen, Att return } if let selectionContext = self.interaction?.selectionState, let editingContext = self.interaction?.editingState { - selectionContext.selectionLimit = 10 + selectionContext.selectionLimit = self.enableMultiselection ? 10 : 1 for case let item as TGMediaEditableItem in selectionContext.selectedItems() { editingContext.setPrice(NSNumber(value: amount), for: item) } diff --git a/submodules/TelegramCore/Sources/TelegramEngine/Payments/Stars.swift b/submodules/TelegramCore/Sources/TelegramEngine/Payments/Stars.swift index 7b947a4e7d..e5e7be5bfb 100644 --- a/submodules/TelegramCore/Sources/TelegramEngine/Payments/Stars.swift +++ b/submodules/TelegramCore/Sources/TelegramEngine/Payments/Stars.swift @@ -1666,7 +1666,7 @@ public struct StarsTransactionReference: PostboxCoding, Hashable, Equatable { public let id: String public let isRefund: Bool - public init(peerId: EnginePeer.Id, id: String, isRefund: Bool) { + public init(peerId: EnginePeer.Id, id: String, isRefund: Bool) { self.peerId = peerId self.id = id self.isRefund = isRefund diff --git a/submodules/TelegramCore/Sources/TelegramEngine/Payments/TelegramEnginePayments.swift b/submodules/TelegramCore/Sources/TelegramEngine/Payments/TelegramEnginePayments.swift index cb887658a1..7b564cf325 100644 --- a/submodules/TelegramCore/Sources/TelegramEngine/Payments/TelegramEnginePayments.swift +++ b/submodules/TelegramCore/Sources/TelegramEngine/Payments/TelegramEnginePayments.swift @@ -160,6 +160,10 @@ public extension TelegramEngine { public func updateStarGiftResalePrice(reference: StarGiftReference, price: Int64?) -> Signal { return _internal_updateStarGiftResalePrice(account: self.account, reference: reference, price: price) } + + public func getStarsTransaction(reference: StarsTransactionReference) -> Signal { + return _internal_getStarsTransaction(accountPeerId: self.account.peerId, postbox: self.account.postbox, network: self.account.network, transactionReference: reference) + } } } diff --git a/submodules/TelegramStringFormatting/Sources/ServiceMessageStrings.swift b/submodules/TelegramStringFormatting/Sources/ServiceMessageStrings.swift index 63de4331de..11111d9eb3 100644 --- a/submodules/TelegramStringFormatting/Sources/ServiceMessageStrings.swift +++ b/submodules/TelegramStringFormatting/Sources/ServiceMessageStrings.swift @@ -1259,8 +1259,24 @@ public func universalServiceMessageString(presentationData: (PresentationTheme, messagePeer = EnginePeer(messagePeerValue) } else if message.id.peerId.namespace == Namespaces.Peer.CloudChannel, let peer = message.peers[message.id.peerId] as? TelegramChannel, peer.isMonoForum { if let author = message.author, let threadId = message.threadId, let threadPeer = message.peers[PeerId(threadId)], author.id != threadPeer.id { - isOutgoing = true - messagePeer = EnginePeer(threadPeer) + if case .channel = author { + var isUser = true + if let peer = message.peers[message.id.peerId] as? TelegramChannel { + if peer.isMonoForum, let linkedMonoforumId = peer.linkedMonoforumId, let mainChannel = message.peers[linkedMonoforumId] as? TelegramChannel, mainChannel.hasPermission(.manageDirect) { + isUser = false + } + } + + if isUser { + messagePeer = author + } else { + messagePeer = EnginePeer(threadPeer) + isOutgoing = true + } + } else { + isOutgoing = true + messagePeer = EnginePeer(threadPeer) + } } } @@ -1450,12 +1466,51 @@ public func universalServiceMessageString(presentationData: (PresentationTheme, } } attributedString = NSAttributedString(string: string, font: titleFont, textColor: primaryTextColor) - case .suggestedPostSuccess: + case let .suggestedPostSuccess(amount): + var isUser = true + var channelName: String = "" + if let peer = message.peers[message.id.peerId] as? TelegramChannel { + channelName = peer.title + if peer.isMonoForum, let linkedMonoforumId = peer.linkedMonoforumId, let mainChannel = message.peers[linkedMonoforumId] as? TelegramChannel, mainChannel.hasPermission(.manageDirect) { + isUser = false + } + } + let _ = isUser + //TODO:localize - attributedString = NSAttributedString(string: "Suggested post was posted", font: titleFont, textColor: primaryTextColor) - case .suggestedPostRefund: + let amountString: String + switch amount.currency { + case .stars: + if amount.amount.value == 1 { + amountString = "1 Star" + } else { + amountString = "\(amount.amount.value) Stars" + } + case .ton: + amountString = "\(formatTonAmountText(amount.amount.value, dateTimeFormat: dateTimeFormat)) TON" + } + attributedString = parseMarkdownIntoAttributedString("**\(channelName)** received **\(amountString)** for publishing this post", attributes: MarkdownAttributes(body: bodyAttributes, bold: boldAttributes, link: bodyAttributes, linkAttribute: { _ in return nil })) + case let .suggestedPostRefund(info): + var isUser = true + var channelName: String = "" + if let peer = message.peers[message.id.peerId] as? TelegramChannel { + channelName = peer.title + if peer.isMonoForum, let linkedMonoforumId = peer.linkedMonoforumId, let mainChannel = message.peers[linkedMonoforumId] as? TelegramChannel, mainChannel.hasPermission(.manageDirect) { + isUser = false + } + } + let _ = channelName + //TODO:localize - attributedString = NSAttributedString(string: "Suggested post was refunded", font: titleFont, textColor: primaryTextColor) + if info.isUserInitiated { + if isUser { + attributedString = NSAttributedString(string: "Suggested post was refunded because you didn't have enough funds", font: titleFont, textColor: primaryTextColor) + } else { + attributedString = NSAttributedString(string: "Suggested post was refunded because the user didn't have enough funds", font: titleFont, textColor: primaryTextColor) + } + } else { + attributedString = NSAttributedString(string: "Suggested post was refunded because the message was deleted", font: titleFont, textColor: primaryTextColor) + } case let .giftTon(currency, amount, _, _, _): attributedString = nil if !forAdditionalServiceMessage { diff --git a/submodules/TelegramUI/Components/Chat/ChatMessageAnimatedStickerItemNode/Sources/ChatMessageAnimatedStickerItemNode.swift b/submodules/TelegramUI/Components/Chat/ChatMessageAnimatedStickerItemNode/Sources/ChatMessageAnimatedStickerItemNode.swift index 8053656588..2e54b862be 100644 --- a/submodules/TelegramUI/Components/Chat/ChatMessageAnimatedStickerItemNode/Sources/ChatMessageAnimatedStickerItemNode.swift +++ b/submodules/TelegramUI/Components/Chat/ChatMessageAnimatedStickerItemNode/Sources/ChatMessageAnimatedStickerItemNode.swift @@ -1408,7 +1408,7 @@ public class ChatMessageAnimatedStickerItemNode: ChatMessageItemView { layoutSize.height += additionalTopHeight imageFrame.origin.y += additionalTopHeight - var headersOffset: CGFloat = 0.0 + var headersOffset: CGFloat = additionalTopHeight if let (threadInfoSize, _) = threadInfoApply { headersOffset += threadInfoSize.height + 10.0 } @@ -1625,7 +1625,7 @@ public class ChatMessageAnimatedStickerItemNode: ChatMessageItemView { } } - var headersOffset: CGFloat = 0.0 + var headersOffset: CGFloat = additionalTopHeight if let (threadInfoSize, threadInfoApply) = threadInfoApply { let threadInfoNode = threadInfoApply(synchronousLoads) if strongSelf.threadInfoNode == nil { diff --git a/submodules/TelegramUI/Components/Chat/ChatMessageStickerItemNode/Sources/ChatMessageStickerItemNode.swift b/submodules/TelegramUI/Components/Chat/ChatMessageStickerItemNode/Sources/ChatMessageStickerItemNode.swift index 8e4d882243..55ad3cc6a7 100644 --- a/submodules/TelegramUI/Components/Chat/ChatMessageStickerItemNode/Sources/ChatMessageStickerItemNode.swift +++ b/submodules/TelegramUI/Components/Chat/ChatMessageStickerItemNode/Sources/ChatMessageStickerItemNode.swift @@ -991,7 +991,7 @@ public class ChatMessageStickerItemNode: ChatMessageItemView { baseShareButtonFrame.origin.x = dateAndStatusFrame.maxX + 8.0 } - var headersOffset: CGFloat = 0.0 + var headersOffset: CGFloat = additionalTopHeight if let (threadInfoSize, _) = threadInfoApply { headersOffset += threadInfoSize.height + 10.0 } @@ -1149,7 +1149,7 @@ public class ChatMessageStickerItemNode: ChatMessageItemView { } } - var headersOffset: CGFloat = 0.0 + var headersOffset: CGFloat = additionalTopHeight if let (threadInfoSize, threadInfoApply) = threadInfoApply { let threadInfoNode = threadInfoApply(synchronousLoads) if strongSelf.threadInfoNode == nil { diff --git a/submodules/TelegramUI/Components/Chat/ChatMessageSuggestedPostInfoNode/Sources/ChatMessageSuggestedPostInfoNode.swift b/submodules/TelegramUI/Components/Chat/ChatMessageSuggestedPostInfoNode/Sources/ChatMessageSuggestedPostInfoNode.swift index 8c9f2407a3..573baf3a9a 100644 --- a/submodules/TelegramUI/Components/Chat/ChatMessageSuggestedPostInfoNode/Sources/ChatMessageSuggestedPostInfoNode.swift +++ b/submodules/TelegramUI/Components/Chat/ChatMessageSuggestedPostInfoNode/Sources/ChatMessageSuggestedPostInfoNode.swift @@ -199,10 +199,14 @@ public final class ChatMessageSuggestedPostInfoNode: ASDisplayNode { contentHeight += titleLayout.0.size.height contentHeight += titleSpacing - maxContentWidth = max(maxContentWidth, priceLabelLayout.0.size.width + labelSpacing + priceValueLayout.0.size.width) - contentHeight += priceLabelLayout.0.size.height + valuesVerticalSpacing + var tableContentWidth: CGFloat = 0.0 + tableContentWidth = max(tableContentWidth, priceLabelLayout.0.size.width + labelSpacing + priceValueLayout.0.size.width) + tableContentWidth = max(tableContentWidth, timeLabelLayout.0.size.width + labelSpacing + timeValueLayout.0.size.width) - maxContentWidth = max(maxContentWidth, timeLabelLayout.0.size.width + labelSpacing + timeValueLayout.0.size.width) + let labelValueOffset = labelSpacing + max(priceLabelLayout.0.size.width, timeLabelLayout.0.size.width) + + maxContentWidth = max(maxContentWidth, tableContentWidth) + contentHeight += priceLabelLayout.0.size.height + valuesVerticalSpacing contentHeight += timeLabelLayout.0.size.height let size = CGSize(width: insets.left + insets.right + maxContentWidth, height: insets.top + insets.bottom + contentHeight) @@ -252,13 +256,15 @@ public final class ChatMessageSuggestedPostInfoNode: ASDisplayNode { let titleFrame = CGRect(origin: CGPoint(x: floor((size.width - titleLayout.0.size.width) * 0.5), y: insets.top), size: titleLayout.0.size) titleNode.frame = titleFrame - let priceLabelFrame = CGRect(origin: CGPoint(x: insets.left, y: titleFrame.maxY + titleSpacing), size: priceLabelLayout.0.size) + let tableX: CGFloat = floor((size.width - tableContentWidth) * 0.5) + + let priceLabelFrame = CGRect(origin: CGPoint(x: tableX, y: titleFrame.maxY + titleSpacing), size: priceLabelLayout.0.size) priceLabelNode.frame = priceLabelFrame - priceValueNode.frame = CGRect(origin: CGPoint(x: priceLabelFrame.maxX + labelSpacing, y: priceLabelFrame.minY), size: priceValueLayout.0.size) + priceValueNode.frame = CGRect(origin: CGPoint(x: tableX + labelValueOffset, y: priceLabelFrame.minY), size: priceValueLayout.0.size) - let timeLabelFrame = CGRect(origin: CGPoint(x: insets.left, y: priceLabelFrame.maxY + valuesVerticalSpacing), size: timeLabelLayout.0.size) + let timeLabelFrame = CGRect(origin: CGPoint(x: tableX, y: priceLabelFrame.maxY + valuesVerticalSpacing), size: timeLabelLayout.0.size) timeLabelNode.frame = timeLabelFrame - timeValueNode.frame = CGRect(origin: CGPoint(x: timeLabelFrame.maxX + labelSpacing, y: timeLabelFrame.minY), size: timeValueLayout.0.size) + timeValueNode.frame = CGRect(origin: CGPoint(x: tableX + labelValueOffset, y: timeLabelFrame.minY), size: timeValueLayout.0.size) return node }) diff --git a/submodules/TelegramUI/Components/ForumSettingsScreen/Sources/ForumSettingsScreen.swift b/submodules/TelegramUI/Components/ForumSettingsScreen/Sources/ForumSettingsScreen.swift index ce2e1c43ee..aec7e0f1e8 100644 --- a/submodules/TelegramUI/Components/ForumSettingsScreen/Sources/ForumSettingsScreen.swift +++ b/submodules/TelegramUI/Components/ForumSettingsScreen/Sources/ForumSettingsScreen.swift @@ -172,24 +172,27 @@ final class ForumSettingsScreenComponent: Component { if let controller = self.environment?.controller(), let navigationController = controller.navigationController as? NavigationController { var viewControllers = navigationController.viewControllers - if self.isOn && self.mode == .list { - for i in 0 ..< viewControllers.count { - if let chatController = viewControllers[i] as? ChatController, chatController.chatLocation.peerId == component.peerId { - let chatListController = component.context.sharedContext.makeChatListController(context: component.context, location: .forum(peerId: component.peerId), controlsHistoryPreload: false, hideNetworkActivityStatus: false, previewing: false, enableDebugActions: false) - viewControllers[i] = chatListController - } - } - navigationController.setViewControllers(viewControllers, animated: false) + if case .legacyGroup = peer { } else { - for i in (0 ..< viewControllers.count).reversed() { - if let chatListController = viewControllers[i] as? ChatListController, chatListController.location == .forum(peerId: component.peerId) { - viewControllers.remove(at: i) + if self.isOn && self.mode == .list { + for i in 0 ..< viewControllers.count { + if let chatController = viewControllers[i] as? ChatController, chatController.chatLocation.peerId == component.peerId { + let chatListController = component.context.sharedContext.makeChatListController(context: component.context, location: .forum(peerId: component.peerId), controlsHistoryPreload: false, hideNetworkActivityStatus: false, previewing: false, enableDebugActions: false) + viewControllers[i] = chatListController + } + } + navigationController.setViewControllers(viewControllers, animated: false) + } else { + for i in (0 ..< viewControllers.count).reversed() { + if let chatListController = viewControllers[i] as? ChatListController, chatListController.location == .forum(peerId: component.peerId) { + viewControllers.remove(at: i) + } + } + navigationController.setViewControllers(viewControllers, animated: false) + + if let baseController = navigationController as? TelegramRootControllerInterface, let chatListController = baseController.getChatsController() as? ChatListController { + chatListController.resetForumStackIfOpen() } - } - navigationController.setViewControllers(viewControllers, animated: false) - - if let baseController = navigationController as? TelegramRootControllerInterface, let chatListController = baseController.getChatsController() as? ChatListController { - chatListController.resetForumStackIfOpen() } } } @@ -232,6 +235,34 @@ final class ForumSettingsScreenComponent: Component { } if let resultPeerId { self.peerIdPromise.set(resultPeerId) + + let _ = component.context.engine.peers.setChannelForumMode(id: resultPeerId, isForum: true, displayForumAsTabs: self.mode == .tabs).startStandalone() + + if let controller = self.environment?.controller(), let navigationController = controller.navigationController as? NavigationController { + var viewControllers = navigationController.viewControllers + if self.mode == .list { + for i in 0 ..< viewControllers.count { + if let chatController = viewControllers[i] as? ChatController, chatController.chatLocation.peerId == component.peerId { + let chatListController = component.context.sharedContext.makeChatListController(context: component.context, location: .forum(peerId: resultPeerId), controlsHistoryPreload: false, hideNetworkActivityStatus: false, previewing: false, enableDebugActions: false) + viewControllers[i] = chatListController + } + } + navigationController.setViewControllers(viewControllers, animated: false) + } else { + for i in (0 ..< viewControllers.count).reversed() { + if let chatListController = viewControllers[i] as? ChatListController, chatListController.location == .forum(peerId: component.peerId) { + viewControllers.remove(at: i) + } else if let peerInfoScreen = viewControllers[i] as? PeerInfoScreen, peerInfoScreen.peerId == component.peerId { + viewControllers.remove(at: i) + } + } + navigationController.setViewControllers(viewControllers, animated: false) + + if let baseController = navigationController as? TelegramRootControllerInterface, let chatListController = baseController.getChatsController() as? ChatListController { + chatListController.resetForumStackIfOpen() + } + } + } } else { self.isOn = false self.state?.updated(transition: .easeInOut(duration: 0.2)) diff --git a/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/PeerInfoData.swift b/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/PeerInfoData.swift index fe4168a2ef..4e8eea21e7 100644 --- a/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/PeerInfoData.swift +++ b/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/PeerInfoData.swift @@ -2290,8 +2290,12 @@ func peerInfoHeaderButtons(peer: Peer?, cachedData: CachedPeerData?, isOpenedFro if hasVoiceChat || canStartVoiceChat { result.append(.voiceChat) } + if case let .broadcast(info) = channel.info, info.flags.contains(.hasMonoforum), !channel.hasPermission(.manageDirect) { + result.append(.message) + } result.append(.mute) - if hasDiscussion { + if case let .broadcast(info) = channel.info, info.flags.contains(.hasMonoforum), !channel.hasPermission(.manageDirect) { + } else if hasDiscussion { result.append(.discussion) } result.append(.search) diff --git a/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/PeerInfoScreen.swift b/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/PeerInfoScreen.swift index 0ade9c5412..0a9ee051f0 100644 --- a/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/PeerInfoScreen.swift +++ b/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/PeerInfoScreen.swift @@ -1959,7 +1959,7 @@ private func infoItems(data: PeerInfoScreenData?, context: AccountContext, prese })) } - if let personalChannel = data.personalChannel { + if channel.hasPermission(.manageDirect), let personalChannel = data.personalChannel { let peerId = personalChannel.peer.peerId items[.channelMonoforum]?.append(PeerInfoScreenPersonalChannelItem(id: ItemPeerPersonalChannel, context: context, data: personalChannel, controller: { [weak interaction] in guard let interaction else { @@ -5998,18 +5998,32 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, PeerInfoScreenNodePro switch key { case .message: if let navigationController = controller.navigationController as? NavigationController, let peer = self.data?.peer { - self.context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: self.context, chatLocation: .peer(EnginePeer(peer)), keepStack: self.nearbyPeerDistance != nil ? .always : .default, peerNearbyData: self.nearbyPeerDistance.flatMap({ ChatPeerNearbyData(distance: $0) }), completion: { [weak self] _ in - if let strongSelf = self, strongSelf.nearbyPeerDistance != nil { - var viewControllers = navigationController.viewControllers - viewControllers = viewControllers.filter { controller in - if controller is PeerInfoScreen { - return false - } - return true + if let channel = peer as? TelegramChannel, case let .broadcast(info) = channel.info, info.flags.contains(.hasMonoforum), let linkedMonoforumId = channel.linkedMonoforumId { + Task { @MainActor [weak self] in + guard let self else { + return } - navigationController.setViewControllers(viewControllers, animated: false) + + guard let peer = await self.context.engine.data.get(TelegramEngine.EngineData.Item.Peer.Peer(id: linkedMonoforumId)).get() else { + return + } + + self.context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: self.context, chatLocation: .peer(peer), keepStack: .default)) } - })) + } else { + self.context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: self.context, chatLocation: .peer(EnginePeer(peer)), keepStack: self.nearbyPeerDistance != nil ? .always : .default, peerNearbyData: self.nearbyPeerDistance.flatMap({ ChatPeerNearbyData(distance: $0) }), completion: { [weak self] _ in + if let strongSelf = self, strongSelf.nearbyPeerDistance != nil { + var viewControllers = navigationController.viewControllers + viewControllers = viewControllers.filter { controller in + if controller is PeerInfoScreen { + return false + } + return true + } + navigationController.setViewControllers(viewControllers, animated: false) + } + })) + } } case .discussion: if let cachedData = self.data?.cachedData as? CachedChannelData, case let .known(maybeLinkedDiscussionPeerId) = cachedData.linkedDiscussionPeerId, let linkedDiscussionPeerId = maybeLinkedDiscussionPeerId { diff --git a/submodules/TelegramUI/Components/PeerInfo/PostSuggestionsSettingsScreen/Sources/PostSuggestionsSettingsScreen.swift b/submodules/TelegramUI/Components/PeerInfo/PostSuggestionsSettingsScreen/Sources/PostSuggestionsSettingsScreen.swift index 12568056f3..947cb43f32 100644 --- a/submodules/TelegramUI/Components/PeerInfo/PostSuggestionsSettingsScreen/Sources/PostSuggestionsSettingsScreen.swift +++ b/submodules/TelegramUI/Components/PeerInfo/PostSuggestionsSettingsScreen/Sources/PostSuggestionsSettingsScreen.swift @@ -29,7 +29,7 @@ final class PostSuggestionsSettingsScreenComponent: Component { let context: AccountContext let usdWithdrawRate: Int64 - let paidMessageCommissionPermille: Int + let channelMessageSuggestionCommissionPermille: Int let peer: EnginePeer? let initialPrice: StarsAmount? let completion: () -> Void @@ -37,14 +37,14 @@ final class PostSuggestionsSettingsScreenComponent: Component { init( context: AccountContext, usdWithdrawRate: Int64, - paidMessageCommissionPermille: Int, + channelMessageSuggestionCommissionPermille: Int, peer: EnginePeer?, initialPrice: StarsAmount?, completion: @escaping () -> Void ) { self.context = context self.usdWithdrawRate = usdWithdrawRate - self.paidMessageCommissionPermille = paidMessageCommissionPermille + self.channelMessageSuggestionCommissionPermille = channelMessageSuggestionCommissionPermille self.peer = peer self.initialPrice = initialPrice self.completion = completion @@ -373,7 +373,7 @@ final class PostSuggestionsSettingsScreenComponent: Component { } let currentAmount: StarsAmount = StarsAmount(value: Int64(self.starCount), nanos: 0) - let starsScreen = component.context.sharedContext.makeStarsWithdrawalScreen(context: component.context, subject: .enterAmount(current: currentAmount, minValue: StarsAmount(value: 0, nanos: 0), fractionAfterCommission: component.paidMessageCommissionPermille / 10, kind: .postSuggestion, completion: { [weak self] amount in + let starsScreen = component.context.sharedContext.makeStarsWithdrawalScreen(context: component.context, subject: .enterAmount(current: currentAmount, minValue: StarsAmount(value: 0, nanos: 0), fractionAfterCommission: component.channelMessageSuggestionCommissionPermille / 10, kind: .postSuggestion, completion: { [weak self] amount in guard let self else { return } @@ -404,7 +404,7 @@ final class PostSuggestionsSettingsScreenComponent: Component { )), footer: AnyComponent(MultilineTextComponent( text: .plain(NSAttributedString( - string: environment.strings.ChannelMessages_PriceSectionFooterValue("\(component.paidMessageCommissionPermille / 10)").string, + string: environment.strings.ChannelMessages_PriceSectionFooterValue("\(component.channelMessageSuggestionCommissionPermille / 10)").string, font: Font.regular(13.0), textColor: self.starCount == 0 ? .clear : environment.theme.list.freeTextColor )), @@ -503,7 +503,7 @@ public final class PostSuggestionsSettingsScreen: ViewControllerComponentContain super.init(context: context, component: PostSuggestionsSettingsScreenComponent( context: context, usdWithdrawRate: configuration.usdWithdrawRate, - paidMessageCommissionPermille: Int(configuration.paidMessageCommissionPermille), + channelMessageSuggestionCommissionPermille: Int(configuration.channelMessageSuggestionCommissionPermille), peer: peer, initialPrice: initialPrice, completion: completion diff --git a/submodules/TelegramUI/Components/Stars/StarsWithdrawalScreen/Sources/StarsWithdrawalScreen.swift b/submodules/TelegramUI/Components/Stars/StarsWithdrawalScreen/Sources/StarsWithdrawalScreen.swift index 23c08659a0..7933167ced 100644 --- a/submodules/TelegramUI/Components/Stars/StarsWithdrawalScreen/Sources/StarsWithdrawalScreen.swift +++ b/submodules/TelegramUI/Components/Stars/StarsWithdrawalScreen/Sources/StarsWithdrawalScreen.swift @@ -220,14 +220,14 @@ private final class SheetContent: CombinedComponent { switch state.currency { case .stars: amountTitle = "ENTER A PRICE IN STARS" + maxAmount = StarsAmount(value: resaleConfiguration.channelMessageSuggestionMaxStarsAmount, nanos: 0) case .ton: amountTitle = "ENTER A PRICE IN TON" + maxAmount = StarsAmount(value: resaleConfiguration.channelMessageSuggestionMaxTonAmount, nanos: 0) } amountPlaceholder = "Price" minAmount = StarsAmount(value: 0, nanos: 0) - //TODO:release - maxAmount = StarsAmount(value: resaleConfiguration.paidMessageMaxAmount, nanos: 0) } let title = title.update( @@ -299,69 +299,86 @@ private final class SheetContent: CombinedComponent { if let tonBalance = state.tonBalance { tonBalanceValue = tonBalance } - if case let .suggestedPost(mode, _, _, _) = component.mode, (state.currency == .ton || tonBalanceValue > StarsAmount.zero) { - //TODO:localize - let selectedId: AnyHashable = state.currency == .stars ? AnyHashable(0 as Int) : AnyHashable(1 as Int) - let starsTitle: String - let tonTitle: String + + if case let .suggestedPost(mode, _, _, _) = component.mode { + var displayCurrencySelector = false switch mode { - case .sender: - starsTitle = "Offer Stars" - tonTitle = "Offer TON" + case let .sender(_, isFromAdmin): + if isFromAdmin { + displayCurrencySelector = true + } else { + if state.currency == .ton || tonBalanceValue > StarsAmount.zero { + displayCurrencySelector = true + } + } case .admin: - starsTitle = "Request Stars" - tonTitle = "Request TON" + displayCurrencySelector = true } - let currencyToggle = currencyToggle.update( - component: TabSelectorComponent( - colors: TabSelectorComponent.Colors( - foreground: theme.list.itemSecondaryTextColor, - selection: theme.list.itemSecondaryTextColor.withMultipliedAlpha(0.15), - simple: true - ), - customLayout: TabSelectorComponent.CustomLayout( - font: Font.medium(14.0), - spacing: 10.0 - ), - items: [ - TabSelectorComponent.Item( - id: AnyHashable(0), - content: .component(AnyComponent(CurrencyTabItemComponent(icon: .stars, title: starsTitle, theme: theme))) + if displayCurrencySelector { + //TODO:localize + let selectedId: AnyHashable = state.currency == .stars ? AnyHashable(0 as Int) : AnyHashable(1 as Int) + let starsTitle: String + let tonTitle: String + switch mode { + case .sender: + starsTitle = "Offer Stars" + tonTitle = "Offer TON" + case .admin: + starsTitle = "Request Stars" + tonTitle = "Request TON" + } + + let currencyToggle = currencyToggle.update( + component: TabSelectorComponent( + colors: TabSelectorComponent.Colors( + foreground: theme.list.itemSecondaryTextColor, + selection: theme.list.itemSecondaryTextColor.withMultipliedAlpha(0.15), + simple: true ), - TabSelectorComponent.Item( - id: AnyHashable(1), - content: .component(AnyComponent(CurrencyTabItemComponent(icon: .ton, title: tonTitle, theme: theme))) - ) - ], - selectedId: selectedId, - setSelectedId: { [weak state] id in - guard let state else { - return + customLayout: TabSelectorComponent.CustomLayout( + font: Font.medium(14.0), + spacing: 10.0 + ), + items: [ + TabSelectorComponent.Item( + id: AnyHashable(0), + content: .component(AnyComponent(CurrencyTabItemComponent(icon: .stars, title: starsTitle, theme: theme))) + ), + TabSelectorComponent.Item( + id: AnyHashable(1), + content: .component(AnyComponent(CurrencyTabItemComponent(icon: .ton, title: tonTitle, theme: theme))) + ) + ], + selectedId: selectedId, + setSelectedId: { [weak state] id in + guard let state else { + return + } + + let currency: CurrencyAmount.Currency + if id == AnyHashable(0) { + currency = .stars + } else { + currency = .ton + } + if state.currency != currency { + state.currency = currency + state.amount = nil + } + state.updated(transition: .spring(duration: 0.4)) } - - let currency: CurrencyAmount.Currency - if id == AnyHashable(0) { - currency = .stars - } else { - currency = .ton - } - if state.currency != currency { - state.currency = currency - state.amount = nil - } - state.updated(transition: .spring(duration: 0.4)) - } - ), - availableSize: CGSize(width: context.availableSize.width - sideInset * 2.0, height: 100.0), - transition: context.transition - ) - contentSize.height -= 17.0 - let currencyToggleFrame = CGRect(origin: CGPoint(x: floor((context.availableSize.width - currencyToggle.size.width) * 0.5), y: contentSize.height), size: currencyToggle.size) - context.add(currencyToggle - .position(currencyToggle.size.centered(in: currencyToggleFrame).center)) - - contentSize.height += currencyToggle.size.height + 29.0 + ), + availableSize: CGSize(width: context.availableSize.width - sideInset * 2.0, height: 100.0), + transition: context.transition + ) + contentSize.height -= 17.0 + let currencyToggleFrame = CGRect(origin: CGPoint(x: floor((context.availableSize.width - currencyToggle.size.width) * 0.5), y: contentSize.height), size: currencyToggle.size) + context.add(currencyToggle + .position(currencyToggle.size.centered(in: currencyToggleFrame).center)) + + contentSize.height += currencyToggle.size.height + 29.0 + } } let amountFont = Font.regular(13.0) @@ -506,7 +523,7 @@ private final class SheetContent: CombinedComponent { accentColor: theme.list.itemAccentColor, value: state.amount?.value, minValue: minAmount?.value, - maxValue: state.currency == .ton ? nil : maxAmount?.value, + maxValue: maxAmount?.value, placeholderText: amountPlaceholder, labelText: amountLabel, currency: state.currency, @@ -658,7 +675,7 @@ private final class SheetContent: CombinedComponent { //TODO:localize switch mode { case .sender: - if let amount = state.amount { + if let amount = state.amount, amount != .zero { let currencySymbol: String let currencyAmount: String switch state.currency { @@ -1164,9 +1181,14 @@ private final class AmountFieldStarsFormatter: NSObject, UITextFieldDelegate { // Convert and combine if let whole = Int64(wholeSlice), let frac = Int64(fractionStr) { + + let whole = min(whole, Int64.max / scale) + amount = whole * scale + frac } } else if let whole = Int64(text) { // string had no dot at all + let whole = min(whole, Int64.max / scale) + amount = whole * scale } } @@ -1241,7 +1263,7 @@ private final class AmountFieldStarsFormatter: NSObject, UITextFieldDelegate { case .stars: textField.text = "\(self.maxValue)" case .ton: - textField.text = "\(formatTonAmountText(self.maxValue, dateTimeFormat: self.dateTimeFormat))" + textField.text = "\(formatTonAmountText(self.maxValue, dateTimeFormat: PresentationDateTimeFormat(timeFormat: self.dateTimeFormat.timeFormat, dateFormat: self.dateTimeFormat.dateFormat, dateSeparator: "", dateSuffix: "", requiresFullYear: false, decimalSeparator: ".", groupingSeparator: "")))" } self.onTextChanged(text: self.textField.text ?? "") self.animateError() @@ -1396,13 +1418,13 @@ private final class AmountFieldComponent: Component { self.textField.textColor = component.textColor if self.component?.currency != component.currency { - if let value = component.value { + if let value = component.value, value != .zero { var text = "" switch component.currency { case .stars: text = "\(value)" case .ton: - text = "\(formatTonAmountText(value, dateTimeFormat: component.dateTimeFormat))" + text = "\(formatTonAmountText(value, dateTimeFormat: PresentationDateTimeFormat(timeFormat: component.dateTimeFormat.timeFormat, dateFormat: component.dateTimeFormat.dateFormat, dateSeparator: "", dateSuffix: "", requiresFullYear: false, decimalSeparator: ".", groupingSeparator: "")))" } self.textField.text = text } else { @@ -1461,7 +1483,7 @@ private final class AmountFieldComponent: Component { currency: component.currency, dateTimeFormat: component.dateTimeFormat, minValue: component.minValue ?? 0, - maxValue: component.maxValue ?? Int64.max, + maxValue: component.maxValue ?? 10000000, updated: { [weak self] value in guard let self, let component = self.component else { return diff --git a/submodules/TelegramUI/Images.xcassets/Chat/Context Menu/DeletePaid.imageset/Contents.json b/submodules/TelegramUI/Images.xcassets/Chat/Context Menu/DeletePaid.imageset/Contents.json new file mode 100644 index 0000000000..ee235a4085 --- /dev/null +++ b/submodules/TelegramUI/Images.xcassets/Chat/Context Menu/DeletePaid.imageset/Contents.json @@ -0,0 +1,12 @@ +{ + "images" : [ + { + "filename" : "trash_24.pdf", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/submodules/TelegramUI/Images.xcassets/Chat/Context Menu/DeletePaid.imageset/trash_24.pdf b/submodules/TelegramUI/Images.xcassets/Chat/Context Menu/DeletePaid.imageset/trash_24.pdf new file mode 100644 index 0000000000..d6ed06acc0 Binary files /dev/null and b/submodules/TelegramUI/Images.xcassets/Chat/Context Menu/DeletePaid.imageset/trash_24.pdf differ diff --git a/submodules/TelegramUI/Sources/Chat/ChatControllerPaste.swift b/submodules/TelegramUI/Sources/Chat/ChatControllerPaste.swift index 76b71ea164..346f2e6b8f 100644 --- a/submodules/TelegramUI/Sources/Chat/ChatControllerPaste.swift +++ b/submodules/TelegramUI/Sources/Chat/ChatControllerPaste.swift @@ -20,6 +20,11 @@ extension ChatControllerImpl { } |> deliverOnMainQueue).startStandalone(next: { [weak self] settings in if let strongSelf = self, let peer = strongSelf.presentationInterfaceState.renderedPeer?.peer { + var enableMultiselection = true + if strongSelf.presentationInterfaceState.interfaceState.postSuggestionState != nil { + enableMultiselection = false + } + strongSelf.chatDisplayNode.dismissInput() let controller = mediaPasteboardScreen( context: strongSelf.context, @@ -28,7 +33,7 @@ extension ChatControllerImpl { subjects: subjects, presentMediaPicker: { [weak self] subject, saveEditedPhotos, bannedSendPhotos, bannedSendVideos, present in if let strongSelf = self { - strongSelf.presentMediaPicker(subject: subject, saveEditedPhotos: saveEditedPhotos, bannedSendPhotos: bannedSendPhotos, bannedSendVideos: bannedSendVideos, present: present, updateMediaPickerContext: { _ in }, completion: { [weak self] fromGallery, signals, silentPosting, scheduleTime, parameters, getAnimatedTransitionSource, completion in + strongSelf.presentMediaPicker(subject: subject, saveEditedPhotos: saveEditedPhotos, bannedSendPhotos: bannedSendPhotos, bannedSendVideos: bannedSendVideos, enableMultiselection: enableMultiselection, present: present, updateMediaPickerContext: { _ in }, completion: { [weak self] fromGallery, signals, silentPosting, scheduleTime, parameters, getAnimatedTransitionSource, completion in self?.enqueueMediaMessages(fromGallery: fromGallery, signals: signals, silentPosting: silentPosting, scheduleTime: scheduleTime, parameters: parameters, getAnimatedTransitionSource: getAnimatedTransitionSource, completion: completion) }) } diff --git a/submodules/TelegramUI/Sources/ChatController.swift b/submodules/TelegramUI/Sources/ChatController.swift index bd1148b6d0..b15b0863ee 100644 --- a/submodules/TelegramUI/Sources/ChatController.swift +++ b/submodules/TelegramUI/Sources/ChatController.swift @@ -1173,6 +1173,20 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G let controller = self.context.sharedContext.makeStarsGiftScreen(context: self.context, message: EngineMessage(message)) self.push(controller) return true + case let .giftTon(_, _, _, _, transactionId): + Task { @MainActor [weak self] in + guard let self, let transactionId, let peerId = self.chatLocation.peerId else { + return + } + let transactionData = await self.context.engine.payments.getStarsTransaction(reference: StarsTransactionReference(peerId: self.context.account.peerId, id: transactionId, isRefund: false)).get() + let peer = await self.context.engine.data.get( + TelegramEngine.EngineData.Item.Peer.Peer(id: peerId) + ).get() + if let transactionData, let peer { + self.push(self.context.sharedContext.makeStarsTransactionScreen(context: self.context, transaction: transactionData, peer: peer)) + } + } + let _ = transactionId case let .giftCode(slug, _, _, _, _, _, _, _, _, _, _): self.openResolved(result: .premiumGiftCode(slug: slug), sourceMessageId: message.id, progress: params.progress) return true diff --git a/submodules/TelegramUI/Sources/ChatControllerNode.swift b/submodules/TelegramUI/Sources/ChatControllerNode.swift index b86ab95d31..62d5b14286 100644 --- a/submodules/TelegramUI/Sources/ChatControllerNode.swift +++ b/submodules/TelegramUI/Sources/ChatControllerNode.swift @@ -4472,6 +4472,7 @@ class ChatControllerNode: ASDisplayNode, ASScrollViewDelegate { } var effectivePresentationInterfaceState = self.chatPresentationInterfaceState + if let textInputPanelNode = self.textInputPanelNode { effectivePresentationInterfaceState = effectivePresentationInterfaceState.updatedInterfaceState { $0.withUpdatedEffectiveInputState(textInputPanelNode.inputTextState) } } diff --git a/submodules/TelegramUI/Sources/ChatControllerOpenAttachmentMenu.swift b/submodules/TelegramUI/Sources/ChatControllerOpenAttachmentMenu.swift index d001fdf81a..7b2614ba8f 100644 --- a/submodules/TelegramUI/Sources/ChatControllerOpenAttachmentMenu.swift +++ b/submodules/TelegramUI/Sources/ChatControllerOpenAttachmentMenu.swift @@ -61,6 +61,11 @@ extension ChatControllerImpl { var bannedSendVideos: (Int32, Bool)? var bannedSendFiles: (Int32, Bool)? + var enableMultiselection = true + if self.presentationInterfaceState.interfaceState.postSuggestionState != nil { + enableMultiselection = false + } + var canSendPolls = true var canSendTodos = true if let peer = self.presentationInterfaceState.renderedPeer?.peer { @@ -336,7 +341,7 @@ extension ChatControllerImpl { controller.prepareForReuse() return } - strongSelf.presentMediaPicker(saveEditedPhotos: dataSettings.storeEditedPhotos, bannedSendPhotos: bannedSendPhotos, bannedSendVideos: bannedSendVideos, present: { controller, mediaPickerContext in + strongSelf.presentMediaPicker(saveEditedPhotos: dataSettings.storeEditedPhotos, bannedSendPhotos: bannedSendPhotos, bannedSendVideos: bannedSendVideos, enableMultiselection: enableMultiselection, present: { controller, mediaPickerContext in let _ = currentMediaController.swap(controller) if !inputText.string.isEmpty { mediaPickerContext?.setCaption(inputText) @@ -1230,7 +1235,7 @@ extension ChatControllerImpl { self.present(actionSheet, in: .window(.root)) } - func presentMediaPicker(subject: MediaPickerScreenImpl.Subject = .assets(nil, .default), saveEditedPhotos: Bool, bannedSendPhotos: (Int32, Bool)?, bannedSendVideos: (Int32, Bool)?, present: @escaping (MediaPickerScreenImpl, AttachmentMediaPickerContext?) -> Void, updateMediaPickerContext: @escaping (AttachmentMediaPickerContext?) -> Void, completion: @escaping (Bool, [Any], Bool, Int32?, ChatSendMessageActionSheetController.SendParameters?, @escaping (String) -> UIView?, @escaping () -> Void) -> Void) { + func presentMediaPicker(subject: MediaPickerScreenImpl.Subject = .assets(nil, .default), saveEditedPhotos: Bool, bannedSendPhotos: (Int32, Bool)?, bannedSendVideos: (Int32, Bool)?, enableMultiselection: Bool, present: @escaping (MediaPickerScreenImpl, AttachmentMediaPickerContext?) -> Void, updateMediaPickerContext: @escaping (AttachmentMediaPickerContext?) -> Void, completion: @escaping (Bool, [Any], Bool, Int32?, ChatSendMessageActionSheetController.SendParameters?, @escaping (String) -> UIView?, @escaping () -> Void) -> Void) { var isScheduledMessages = false if case .scheduledMessages = self.presentationInterfaceState.subject { isScheduledMessages = true @@ -1248,6 +1253,7 @@ extension ChatControllerImpl { isScheduledMessages: isScheduledMessages, bannedSendPhotos: bannedSendPhotos, bannedSendVideos: bannedSendVideos, + enableMultiselection: enableMultiselection, canBoostToUnrestrict: (self.presentationInterfaceState.boostsToUnrestrict ?? 0) > 0 && bannedSendPhotos?.1 != true && bannedSendVideos?.1 != true, paidMediaAllowed: paidMediaAllowed, subject: subject, diff --git a/submodules/TelegramUI/Sources/ChatInterfaceStateContextMenus.swift b/submodules/TelegramUI/Sources/ChatInterfaceStateContextMenus.swift index 03277f6fa0..5423350bac 100644 --- a/submodules/TelegramUI/Sources/ChatInterfaceStateContextMenus.swift +++ b/submodules/TelegramUI/Sources/ChatInterfaceStateContextMenus.swift @@ -1924,8 +1924,13 @@ func contextMenuForChatPresentationInterfaceState(chatPresentationInterfaceState } }), false)) } else if !isUnremovableAction { + var iconName: String = isSending ? "Chat/Context Menu/Clear" : "Chat/Context Menu/Delete" + if message.attributes.contains(where: { $0 is PublishedSuggestedPostMessageAttribute }) { + iconName = "Chat/Context Menu/DeletePaid" + } + actions.append(.action(ContextMenuActionItem(text: title, textColor: .destructive, icon: { theme in - return generateTintedImage(image: UIImage(bundleImageName: isSending ? "Chat/Context Menu/Clear" : "Chat/Context Menu/Delete"), color: theme.actionSheet.destructiveActionTextColor) + return generateTintedImage(image: UIImage(bundleImageName: iconName), color: theme.actionSheet.destructiveActionTextColor) }, action: { controller, f in if isEditing { context.account.pendingUpdateMessageManager.cancel(messageId: message.id) diff --git a/submodules/TelegramUI/Sources/ChatTextInputPanelNode.swift b/submodules/TelegramUI/Sources/ChatTextInputPanelNode.swift index d2af18fb7d..a336b54b98 100644 --- a/submodules/TelegramUI/Sources/ChatTextInputPanelNode.swift +++ b/submodules/TelegramUI/Sources/ChatTextInputPanelNode.swift @@ -1523,6 +1523,13 @@ class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDelegate, Ch if case let .media(value) = editMessageState.content { isEditingMedia = !value.isEmpty isMediaEnabled = !value.isEmpty + + if interfaceState.interfaceState.postSuggestionState != nil { + if value.contains(.file) { + isEditingMedia = false + isMediaEnabled = false + } + } } else { isMediaEnabled = true }