Various improvements

This commit is contained in:
Isaac 2025-06-27 12:45:19 +02:00
parent fd324106e3
commit 10c28d982e
16 changed files with 132 additions and 38 deletions

View File

@ -1506,7 +1506,10 @@ public struct StarsSubscriptionConfiguration {
paidMessagesAvailable: false, paidMessagesAvailable: false,
starGiftResaleMinAmount: 125, starGiftResaleMinAmount: 125,
starGiftResaleMaxAmount: 3500, 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 starGiftResaleMinAmount: Int64
public let starGiftResaleMaxAmount: Int64 public let starGiftResaleMaxAmount: Int64
public let starGiftCommissionPermille: Int32 public let starGiftCommissionPermille: Int32
public let channelMessageSuggestionCommissionPermille: Int32
public let channelMessageSuggestionMaxStarsAmount: Int64
public let channelMessageSuggestionMaxTonAmount: Int64
fileprivate init( fileprivate init(
maxFee: Int64, maxFee: Int64,
@ -1527,7 +1533,10 @@ public struct StarsSubscriptionConfiguration {
paidMessagesAvailable: Bool, paidMessagesAvailable: Bool,
starGiftResaleMinAmount: Int64, starGiftResaleMinAmount: Int64,
starGiftResaleMaxAmount: Int64, starGiftResaleMaxAmount: Int64,
starGiftCommissionPermille: Int32 starGiftCommissionPermille: Int32,
channelMessageSuggestionCommissionPermille: Int32,
channelMessageSuggestionMaxStarsAmount: Int64,
channelMessageSuggestionMaxTonAmount: Int64
) { ) {
self.maxFee = maxFee self.maxFee = maxFee
self.usdWithdrawRate = usdWithdrawRate self.usdWithdrawRate = usdWithdrawRate
@ -1537,6 +1546,9 @@ public struct StarsSubscriptionConfiguration {
self.starGiftResaleMinAmount = starGiftResaleMinAmount self.starGiftResaleMinAmount = starGiftResaleMinAmount
self.starGiftResaleMaxAmount = starGiftResaleMaxAmount self.starGiftResaleMaxAmount = starGiftResaleMaxAmount
self.starGiftCommissionPermille = starGiftCommissionPermille self.starGiftCommissionPermille = starGiftCommissionPermille
self.channelMessageSuggestionCommissionPermille = channelMessageSuggestionCommissionPermille
self.channelMessageSuggestionMaxStarsAmount = channelMessageSuggestionMaxStarsAmount
self.channelMessageSuggestionMaxTonAmount = channelMessageSuggestionMaxTonAmount
} }
public static func with(appConfiguration: AppConfiguration) -> StarsSubscriptionConfiguration { 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 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 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( return StarsSubscriptionConfiguration(
maxFee: maxFee, maxFee: maxFee,
usdWithdrawRate: usdWithdrawRate, usdWithdrawRate: usdWithdrawRate,
@ -1558,7 +1574,10 @@ public struct StarsSubscriptionConfiguration {
paidMessagesAvailable: paidMessagesAvailable, paidMessagesAvailable: paidMessagesAvailable,
starGiftResaleMinAmount: starGiftResaleMinAmount, starGiftResaleMinAmount: starGiftResaleMinAmount,
starGiftResaleMaxAmount: starGiftResaleMaxAmount, starGiftResaleMaxAmount: starGiftResaleMaxAmount,
starGiftCommissionPermille: starGiftCommissionPermille starGiftCommissionPermille: starGiftCommissionPermille,
channelMessageSuggestionCommissionPermille: channelMessageSuggestionCommissionPermille,
channelMessageSuggestionMaxStarsAmount: channelMessageSuggestionMaxStarsAmount,
channelMessageSuggestionMaxTonAmount: channelMessageSuggestionMaxTonAmount
) )
} else { } else {
return .defaultValue return .defaultValue

View File

@ -182,6 +182,7 @@ public final class MediaPickerScreenImpl: ViewController, MediaPickerScreen, Att
private let chatLocation: ChatLocation? private let chatLocation: ChatLocation?
private let bannedSendPhotos: (Int32, Bool)? private let bannedSendPhotos: (Int32, Bool)?
private let bannedSendVideos: (Int32, Bool)? private let bannedSendVideos: (Int32, Bool)?
private let enableMultiselection: Bool
private let canBoostToUnrestrict: Bool private let canBoostToUnrestrict: Bool
fileprivate let paidMediaAllowed: Bool fileprivate let paidMediaAllowed: Bool
fileprivate let subject: Subject fileprivate let subject: Subject
@ -1845,6 +1846,7 @@ public final class MediaPickerScreenImpl: ViewController, MediaPickerScreen, Att
isScheduledMessages: Bool = false, isScheduledMessages: Bool = false,
bannedSendPhotos: (Int32, Bool)? = nil, bannedSendPhotos: (Int32, Bool)? = nil,
bannedSendVideos: (Int32, Bool)? = nil, bannedSendVideos: (Int32, Bool)? = nil,
enableMultiselection: Bool = true,
canBoostToUnrestrict: Bool = false, canBoostToUnrestrict: Bool = false,
paidMediaAllowed: Bool = false, paidMediaAllowed: Bool = false,
subject: Subject, subject: Subject,
@ -1868,6 +1870,7 @@ public final class MediaPickerScreenImpl: ViewController, MediaPickerScreen, Att
self.isScheduledMessages = isScheduledMessages self.isScheduledMessages = isScheduledMessages
self.bannedSendPhotos = bannedSendPhotos self.bannedSendPhotos = bannedSendPhotos
self.bannedSendVideos = bannedSendVideos self.bannedSendVideos = bannedSendVideos
self.enableMultiselection = enableMultiselection
self.canBoostToUnrestrict = canBoostToUnrestrict self.canBoostToUnrestrict = canBoostToUnrestrict
self.paidMediaAllowed = paidMediaAllowed self.paidMediaAllowed = paidMediaAllowed
self.subject = subject self.subject = subject
@ -1877,7 +1880,7 @@ public final class MediaPickerScreenImpl: ViewController, MediaPickerScreen, Att
self.mainButtonAction = mainButtonAction self.mainButtonAction = mainButtonAction
self.secondaryButtonAction = secondaryButtonAction 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) 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)) super.init(navigationBarPresentationData: NavigationBarPresentationData(presentationData: presentationData))
self.statusBar.statusBarStyle = .Ignore self.statusBar.statusBarStyle = .Ignore
selectionContext.attemptSelectingItem = { [weak self] item in selectionContext.attemptSelectingItem = { [weak self] item in
guard let self else { guard let self else {
return false return false
} }
if let _ = item as? TGMediaPickerGalleryPhotoItem { if let _ = item as? TGMediaPickerGalleryPhotoItem {
if self.bannedSendPhotos != nil { 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)) 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 return
} }
if let selectionContext = self.interaction?.selectionState, let editingContext = self.interaction?.editingState { 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() { for case let item as TGMediaEditableItem in selectionContext.selectedItems() {
editingContext.setPrice(NSNumber(value: amount), for: item) editingContext.setPrice(NSNumber(value: amount), for: item)
} }

View File

@ -1666,7 +1666,7 @@ public struct StarsTransactionReference: PostboxCoding, Hashable, Equatable {
public let id: String public let id: String
public let isRefund: Bool 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.peerId = peerId
self.id = id self.id = id
self.isRefund = isRefund self.isRefund = isRefund

View File

@ -160,6 +160,10 @@ public extension TelegramEngine {
public func updateStarGiftResalePrice(reference: StarGiftReference, price: Int64?) -> Signal<Never, UpdateStarGiftPriceError> { public func updateStarGiftResalePrice(reference: StarGiftReference, price: Int64?) -> Signal<Never, UpdateStarGiftPriceError> {
return _internal_updateStarGiftResalePrice(account: self.account, reference: reference, price: price) return _internal_updateStarGiftResalePrice(account: self.account, reference: reference, price: price)
} }
public func getStarsTransaction(reference: StarsTransactionReference) -> Signal<StarsContext.State.Transaction?, NoError> {
return _internal_getStarsTransaction(accountPeerId: self.account.peerId, postbox: self.account.postbox, network: self.account.network, transactionReference: reference)
}
} }
} }

View File

@ -199,10 +199,14 @@ public final class ChatMessageSuggestedPostInfoNode: ASDisplayNode {
contentHeight += titleLayout.0.size.height contentHeight += titleLayout.0.size.height
contentHeight += titleSpacing contentHeight += titleSpacing
maxContentWidth = max(maxContentWidth, priceLabelLayout.0.size.width + labelSpacing + priceValueLayout.0.size.width) var tableContentWidth: CGFloat = 0.0
contentHeight += priceLabelLayout.0.size.height + valuesVerticalSpacing 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 contentHeight += timeLabelLayout.0.size.height
let size = CGSize(width: insets.left + insets.right + maxContentWidth, height: insets.top + insets.bottom + contentHeight) 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) 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 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 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 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 return node
}) })

View File

@ -2290,8 +2290,12 @@ func peerInfoHeaderButtons(peer: Peer?, cachedData: CachedPeerData?, isOpenedFro
if hasVoiceChat || canStartVoiceChat { if hasVoiceChat || canStartVoiceChat {
result.append(.voiceChat) result.append(.voiceChat)
} }
if case let .broadcast(info) = channel.info, info.flags.contains(.hasMonoforum), !channel.hasPermission(.manageDirect) {
result.append(.message)
}
result.append(.mute) 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(.discussion)
} }
result.append(.search) result.append(.search)

View File

@ -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 let peerId = personalChannel.peer.peerId
items[.channelMonoforum]?.append(PeerInfoScreenPersonalChannelItem(id: ItemPeerPersonalChannel, context: context, data: personalChannel, controller: { [weak interaction] in items[.channelMonoforum]?.append(PeerInfoScreenPersonalChannelItem(id: ItemPeerPersonalChannel, context: context, data: personalChannel, controller: { [weak interaction] in
guard let interaction else { guard let interaction else {
@ -5998,18 +5998,32 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, PeerInfoScreenNodePro
switch key { switch key {
case .message: case .message:
if let navigationController = controller.navigationController as? NavigationController, let peer = self.data?.peer { 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 channel = peer as? TelegramChannel, case let .broadcast(info) = channel.info, info.flags.contains(.hasMonoforum), let linkedMonoforumId = channel.linkedMonoforumId {
if let strongSelf = self, strongSelf.nearbyPeerDistance != nil { Task { @MainActor [weak self] in
var viewControllers = navigationController.viewControllers guard let self else {
viewControllers = viewControllers.filter { controller in return
if controller is PeerInfoScreen {
return false
}
return true
} }
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: case .discussion:
if let cachedData = self.data?.cachedData as? CachedChannelData, case let .known(maybeLinkedDiscussionPeerId) = cachedData.linkedDiscussionPeerId, let linkedDiscussionPeerId = maybeLinkedDiscussionPeerId { if let cachedData = self.data?.cachedData as? CachedChannelData, case let .known(maybeLinkedDiscussionPeerId) = cachedData.linkedDiscussionPeerId, let linkedDiscussionPeerId = maybeLinkedDiscussionPeerId {

View File

@ -29,7 +29,7 @@ final class PostSuggestionsSettingsScreenComponent: Component {
let context: AccountContext let context: AccountContext
let usdWithdrawRate: Int64 let usdWithdrawRate: Int64
let paidMessageCommissionPermille: Int let channelMessageSuggestionCommissionPermille: Int
let peer: EnginePeer? let peer: EnginePeer?
let initialPrice: StarsAmount? let initialPrice: StarsAmount?
let completion: () -> Void let completion: () -> Void
@ -37,14 +37,14 @@ final class PostSuggestionsSettingsScreenComponent: Component {
init( init(
context: AccountContext, context: AccountContext,
usdWithdrawRate: Int64, usdWithdrawRate: Int64,
paidMessageCommissionPermille: Int, channelMessageSuggestionCommissionPermille: Int,
peer: EnginePeer?, peer: EnginePeer?,
initialPrice: StarsAmount?, initialPrice: StarsAmount?,
completion: @escaping () -> Void completion: @escaping () -> Void
) { ) {
self.context = context self.context = context
self.usdWithdrawRate = usdWithdrawRate self.usdWithdrawRate = usdWithdrawRate
self.paidMessageCommissionPermille = paidMessageCommissionPermille self.channelMessageSuggestionCommissionPermille = channelMessageSuggestionCommissionPermille
self.peer = peer self.peer = peer
self.initialPrice = initialPrice self.initialPrice = initialPrice
self.completion = completion self.completion = completion
@ -373,7 +373,7 @@ final class PostSuggestionsSettingsScreenComponent: Component {
} }
let currentAmount: StarsAmount = StarsAmount(value: Int64(self.starCount), nanos: 0) 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 { guard let self else {
return return
} }
@ -404,7 +404,7 @@ final class PostSuggestionsSettingsScreenComponent: Component {
)), )),
footer: AnyComponent(MultilineTextComponent( footer: AnyComponent(MultilineTextComponent(
text: .plain(NSAttributedString( 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), font: Font.regular(13.0),
textColor: self.starCount == 0 ? .clear : environment.theme.list.freeTextColor textColor: self.starCount == 0 ? .clear : environment.theme.list.freeTextColor
)), )),
@ -503,7 +503,7 @@ public final class PostSuggestionsSettingsScreen: ViewControllerComponentContain
super.init(context: context, component: PostSuggestionsSettingsScreenComponent( super.init(context: context, component: PostSuggestionsSettingsScreenComponent(
context: context, context: context,
usdWithdrawRate: configuration.usdWithdrawRate, usdWithdrawRate: configuration.usdWithdrawRate,
paidMessageCommissionPermille: Int(configuration.paidMessageCommissionPermille), channelMessageSuggestionCommissionPermille: Int(configuration.channelMessageSuggestionCommissionPermille),
peer: peer, peer: peer,
initialPrice: initialPrice, initialPrice: initialPrice,
completion: completion completion: completion

View File

@ -220,14 +220,14 @@ private final class SheetContent: CombinedComponent {
switch state.currency { switch state.currency {
case .stars: case .stars:
amountTitle = "ENTER A PRICE IN STARS" amountTitle = "ENTER A PRICE IN STARS"
maxAmount = StarsAmount(value: resaleConfiguration.channelMessageSuggestionMaxStarsAmount, nanos: 0)
case .ton: case .ton:
amountTitle = "ENTER A PRICE IN TON" amountTitle = "ENTER A PRICE IN TON"
maxAmount = StarsAmount(value: resaleConfiguration.channelMessageSuggestionMaxTonAmount, nanos: 0)
} }
amountPlaceholder = "Price" amountPlaceholder = "Price"
minAmount = StarsAmount(value: 0, nanos: 0) minAmount = StarsAmount(value: 0, nanos: 0)
//TODO:release
maxAmount = StarsAmount(value: resaleConfiguration.paidMessageMaxAmount, nanos: 0)
} }
let title = title.update( let title = title.update(

View File

@ -0,0 +1,12 @@
{
"images" : [
{
"filename" : "trash_24.pdf",
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

View File

@ -20,6 +20,11 @@ extension ChatControllerImpl {
} }
|> deliverOnMainQueue).startStandalone(next: { [weak self] settings in |> deliverOnMainQueue).startStandalone(next: { [weak self] settings in
if let strongSelf = self, let peer = strongSelf.presentationInterfaceState.renderedPeer?.peer { if let strongSelf = self, let peer = strongSelf.presentationInterfaceState.renderedPeer?.peer {
var enableMultiselection = true
if strongSelf.presentationInterfaceState.interfaceState.postSuggestionState != nil {
enableMultiselection = false
}
strongSelf.chatDisplayNode.dismissInput() strongSelf.chatDisplayNode.dismissInput()
let controller = mediaPasteboardScreen( let controller = mediaPasteboardScreen(
context: strongSelf.context, context: strongSelf.context,
@ -28,7 +33,7 @@ extension ChatControllerImpl {
subjects: subjects, subjects: subjects,
presentMediaPicker: { [weak self] subject, saveEditedPhotos, bannedSendPhotos, bannedSendVideos, present in presentMediaPicker: { [weak self] subject, saveEditedPhotos, bannedSendPhotos, bannedSendVideos, present in
if let strongSelf = self { 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) self?.enqueueMediaMessages(fromGallery: fromGallery, signals: signals, silentPosting: silentPosting, scheduleTime: scheduleTime, parameters: parameters, getAnimatedTransitionSource: getAnimatedTransitionSource, completion: completion)
}) })
} }

View File

@ -1173,6 +1173,20 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
let controller = self.context.sharedContext.makeStarsGiftScreen(context: self.context, message: EngineMessage(message)) let controller = self.context.sharedContext.makeStarsGiftScreen(context: self.context, message: EngineMessage(message))
self.push(controller) self.push(controller)
return true 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, _, _, _, _, _, _, _, _, _, _): case let .giftCode(slug, _, _, _, _, _, _, _, _, _, _):
self.openResolved(result: .premiumGiftCode(slug: slug), sourceMessageId: message.id, progress: params.progress) self.openResolved(result: .premiumGiftCode(slug: slug), sourceMessageId: message.id, progress: params.progress)
return true return true

View File

@ -4472,6 +4472,7 @@ class ChatControllerNode: ASDisplayNode, ASScrollViewDelegate {
} }
var effectivePresentationInterfaceState = self.chatPresentationInterfaceState var effectivePresentationInterfaceState = self.chatPresentationInterfaceState
if let textInputPanelNode = self.textInputPanelNode { if let textInputPanelNode = self.textInputPanelNode {
effectivePresentationInterfaceState = effectivePresentationInterfaceState.updatedInterfaceState { $0.withUpdatedEffectiveInputState(textInputPanelNode.inputTextState) } effectivePresentationInterfaceState = effectivePresentationInterfaceState.updatedInterfaceState { $0.withUpdatedEffectiveInputState(textInputPanelNode.inputTextState) }
} }

View File

@ -61,6 +61,11 @@ extension ChatControllerImpl {
var bannedSendVideos: (Int32, Bool)? var bannedSendVideos: (Int32, Bool)?
var bannedSendFiles: (Int32, Bool)? var bannedSendFiles: (Int32, Bool)?
var enableMultiselection = true
if self.presentationInterfaceState.interfaceState.postSuggestionState != nil {
enableMultiselection = false
}
var canSendPolls = true var canSendPolls = true
var canSendTodos = true var canSendTodos = true
if let peer = self.presentationInterfaceState.renderedPeer?.peer { if let peer = self.presentationInterfaceState.renderedPeer?.peer {
@ -336,7 +341,7 @@ extension ChatControllerImpl {
controller.prepareForReuse() controller.prepareForReuse()
return 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) let _ = currentMediaController.swap(controller)
if !inputText.string.isEmpty { if !inputText.string.isEmpty {
mediaPickerContext?.setCaption(inputText) mediaPickerContext?.setCaption(inputText)
@ -1230,7 +1235,7 @@ extension ChatControllerImpl {
self.present(actionSheet, in: .window(.root)) 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 var isScheduledMessages = false
if case .scheduledMessages = self.presentationInterfaceState.subject { if case .scheduledMessages = self.presentationInterfaceState.subject {
isScheduledMessages = true isScheduledMessages = true
@ -1248,6 +1253,7 @@ extension ChatControllerImpl {
isScheduledMessages: isScheduledMessages, isScheduledMessages: isScheduledMessages,
bannedSendPhotos: bannedSendPhotos, bannedSendPhotos: bannedSendPhotos,
bannedSendVideos: bannedSendVideos, bannedSendVideos: bannedSendVideos,
enableMultiselection: enableMultiselection,
canBoostToUnrestrict: (self.presentationInterfaceState.boostsToUnrestrict ?? 0) > 0 && bannedSendPhotos?.1 != true && bannedSendVideos?.1 != true, canBoostToUnrestrict: (self.presentationInterfaceState.boostsToUnrestrict ?? 0) > 0 && bannedSendPhotos?.1 != true && bannedSendVideos?.1 != true,
paidMediaAllowed: paidMediaAllowed, paidMediaAllowed: paidMediaAllowed,
subject: subject, subject: subject,

View File

@ -1924,8 +1924,13 @@ func contextMenuForChatPresentationInterfaceState(chatPresentationInterfaceState
} }
}), false)) }), false))
} else if !isUnremovableAction { } 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 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 }, action: { controller, f in
if isEditing { if isEditing {
context.account.pendingUpdateMessageManager.cancel(messageId: message.id) context.account.pendingUpdateMessageManager.cancel(messageId: message.id)