From 10c28d982eead73c717db2719e0b3a15b6b7da98 Mon Sep 17 00:00:00 2001 From: Isaac <> Date: Fri, 27 Jun 2025 12:45:19 +0200 Subject: [PATCH] Various improvements --- .../Sources/AccountContext.swift | 25 ++++++++++-- .../Sources/MediaPickerScreen.swift | 10 +++-- .../TelegramEngine/Payments/Stars.swift | 2 +- .../Payments/TelegramEnginePayments.swift | 4 ++ .../ChatMessageSuggestedPostInfoNode.swift | 20 ++++++---- .../PeerInfoScreen/Sources/PeerInfoData.swift | 6 ++- .../Sources/PeerInfoScreen.swift | 36 ++++++++++++------ .../PostSuggestionsSettingsScreen.swift | 12 +++--- .../Sources/StarsWithdrawalScreen.swift | 4 +- .../DeletePaid.imageset/Contents.json | 12 ++++++ .../DeletePaid.imageset/trash_24.pdf | Bin 0 -> 5476 bytes .../Sources/Chat/ChatControllerPaste.swift | 7 +++- .../TelegramUI/Sources/ChatController.swift | 14 +++++++ .../Sources/ChatControllerNode.swift | 1 + .../ChatControllerOpenAttachmentMenu.swift | 10 ++++- .../ChatInterfaceStateContextMenus.swift | 7 +++- 16 files changed, 132 insertions(+), 38 deletions(-) create mode 100644 submodules/TelegramUI/Images.xcassets/Chat/Context Menu/DeletePaid.imageset/Contents.json create mode 100644 submodules/TelegramUI/Images.xcassets/Chat/Context Menu/DeletePaid.imageset/trash_24.pdf 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/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/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..d064c79f9b 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( 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 0000000000000000000000000000000000000000..d6ed06acc043b9c5f7c4ae153f6877c9951e70ac GIT binary patch literal 5476 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 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)