From eb3f95ea63267956addd5d524027e6f48655652c Mon Sep 17 00:00:00 2001 From: Isaac <> Date: Thu, 29 May 2025 02:05:13 +0800 Subject: [PATCH] Monoforums --- .../Telegram-iOS/en.lproj/Localizable.strings | 19 +++-- .../AvatarNode/Sources/AvatarNode.swift | 29 ++++---- .../Sources/ChatListController.swift | 27 ++++--- .../Sources/Node/ChatListItem.swift | 6 +- .../DeleteChatPeerActionSheetItem.swift | 4 +- submodules/Postbox/Sources/Peer.swift | 2 + submodules/Postbox/Sources/PeerView.swift | 43 ++++++++--- .../Sources/ShareControllerNode.swift | 20 +++--- .../SyncCore/SyncCore_TelegramChannel.swift | 4 ++ .../ChatMessagePaymentAlertController.swift | 8 +-- .../PeerInfoScreenPersonalChannelItem.swift | 6 +- .../PeerInfoScreen/Sources/PeerInfoData.swift | 65 +++++++++++++---- .../Sources/PeerInfoScreen.swift | 71 ++++++++++++++++--- .../Sources/SendInviteLinkScreen.swift | 6 +- .../Sources/StarsWithdrawalScreen.swift | 22 +++--- ...StoryItemSetContainerViewSendMessage.swift | 2 +- .../Chat/ChatControllerPaidMessage.swift | 7 +- .../ChatControllerForwardMessages.swift | 13 ++-- .../Sources/ChatControllerNode.swift | 3 +- .../Sources/ChatTranslationPanelNode.swift | 4 +- .../Sources/WebAppMessagePreviewScreen.swift | 12 ++-- 21 files changed, 264 insertions(+), 109 deletions(-) diff --git a/Telegram/Telegram-iOS/en.lproj/Localizable.strings b/Telegram/Telegram-iOS/en.lproj/Localizable.strings index f60d7511e2..dc8c198c7e 100644 --- a/Telegram/Telegram-iOS/en.lproj/Localizable.strings +++ b/Telegram/Telegram-iOS/en.lproj/Localizable.strings @@ -14377,7 +14377,7 @@ Sorry for the inconvenience."; "PeerInfo.OptionTopics.Enabled" = "Enabled"; "PeerInfo.OptionTopics.Disabled" = "Disabled"; -"ChannelMessages.Title" = "Allow Channel Messages"; +"ChannelMessages.Title" = "Direct Messages"; "ChannelMessages.Info" = "Allow users to send messages to your channel, with the option to charge a fee for each message."; "ChannelMessages.SwitchTitle" = "Allow Channel Messages"; "ChannelMessages.PriceSectionTitle" = "PRICE FOR EACH MESSAGE"; @@ -14391,10 +14391,21 @@ Sorry for the inconvenience."; "Chat.InlineTopicMenu.AllTab" = "All"; "Chat.ChannelMessagesHint" = "Send a message to the channel's admin"; "Chat.ChannelMessagesHintBadge" = "NEW"; +"Chat.ContextMenu.AuthorInfo" = "Sent by %@"; -"PeerInfo.AllowChannelMessages" = "Allow Channel Messages"; -"PeerInfo.AllowChannelMessages.On" = "On"; +"PeerInfo.AllowChannelMessages" = "Direct Messages"; +"PeerInfo.AllowChannelMessages.Free" = "Free"; "PeerInfo.AllowChannelMessages.Off" = "Off"; -"PeerInfo.ChannelMessages" = "Channel Messages"; +"PeerInfo.ChannelMessages" = "Direct Messages"; "Chat.EmptyStateMonoforum.Text" = "Send a direct message to the administrator of **%@**."; +"Chat.EmptyStateMonoforumPaid.Text" = "**%1$@** charges **%2$@**\nper message to its admin."; + +"Monoforum.NameFormat" = "%@ Messages"; + +"Stars.SendMessage.AdjustmentTitle" = "Price for each Message"; +"Stars.SendMessage.AdjustmentPlaceholder" = "Price for each Message"; +"Stars.SendMessage.AdjustmentSectionHeader" = "PRICE IN STARS"; +"Stars.SendMessage.AdjustmentSectionFooterValue" = "You will receive **%@ Stars**."; +"Stars.SendMessage.AdjustmentSectionFooterEmpty" = "You will receive **80%**."; +"Stars.SendMessage.AdjustmentAction" = "OK"; diff --git a/submodules/AvatarNode/Sources/AvatarNode.swift b/submodules/AvatarNode/Sources/AvatarNode.swift index 31113827f4..371a11518a 100644 --- a/submodules/AvatarNode/Sources/AvatarNode.swift +++ b/submodules/AvatarNode/Sources/AvatarNode.swift @@ -272,6 +272,10 @@ public final class AvatarEditOverlayNode: ASDisplayNode { } } +private func generateAvatarBubblePath() -> CGPath { + return try! convertSvgPath("M60,30.274903 C60,46.843446 46.568544,60.274904 30,60.274904 C13.431458,60.274904 0,46.843446 0,30.274903 C0,23.634797 2.158635,17.499547 5.810547,12.529785 L6.036133,12.226074 C6.921364,10.896042 7.367402,8.104698 5.548828,5.316895 C3.606939,2.340088 1.186019,0.979668 2.399414,0.470215 C3.148032,0.156204 7.572027,0.000065 10.764648,1.790527 C12.148517,2.56662 13.2296,3.342422 14.09224,4.039734 C14.42622,4.309704 14.892063,4.349773 15.265962,4.138523 C19.618079,1.679604 24.644722,0.274902 30,0.274902 C46.568544,0.274902 60,13.70636 60,30.274903 Z ") +} + public final class AvatarNode: ASDisplayNode { public static func avatarBubbleMask(size: CGSize) -> UIImage! { return generateImage(size, rotatedContext: { size, context in @@ -282,19 +286,20 @@ public final class AvatarNode: ASDisplayNode { }) } + public static let avatarBubblePath: CGPath = generateAvatarBubblePath() + public static func addAvatarBubblePath(context: CGContext, rect: CGRect) { - if let path = try? convertSvgPath("M60,30.274903 C60,46.843446 46.568544,60.274904 30,60.274904 C13.431458,60.274904 0,46.843446 0,30.274903 C0,23.634797 2.158635,17.499547 5.810547,12.529785 L6.036133,12.226074 C6.921364,10.896042 7.367402,8.104698 5.548828,5.316895 C3.606939,2.340088 1.186019,0.979668 2.399414,0.470215 C3.148032,0.156204 7.572027,0.000065 10.764648,1.790527 C12.148517,2.56662 13.2296,3.342422 14.09224,4.039734 C14.42622,4.309704 14.892063,4.349773 15.265962,4.138523 C19.618079,1.679604 24.644722,0.274902 30,0.274902 C46.568544,0.274902 60,13.70636 60,30.274903 Z ") { - let sx = rect.width / 60.0 - let sy = rect.height / 60.0 - var transform = CGAffineTransform( - a: sx, b: 0.0, - c: 0.0, d: -sy, - tx: rect.minX, - ty: rect.minY + rect.height - ) - let transformedPath = path.copy(using: &transform)! - context.addPath(transformedPath) - } + let path = AvatarNode.avatarBubblePath + let sx = rect.width / 60.0 + let sy = rect.height / 60.274904 + var transform = CGAffineTransform( + a: sx, b: 0.0, + c: 0.0, d: -sy, + tx: rect.minX, + ty: rect.minY + rect.height + ) + let transformedPath = path.copy(using: &transform)! + context.addPath(transformedPath) } public static let gradientColors: [[UIColor]] = [ diff --git a/submodules/ChatListUI/Sources/ChatListController.swift b/submodules/ChatListUI/Sources/ChatListController.swift index 3367102c6b..08e7ef5261 100644 --- a/submodules/ChatListUI/Sources/ChatListController.swift +++ b/submodules/ChatListUI/Sources/ChatListController.swift @@ -5316,20 +5316,25 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController var deleteTitle = strongSelf.presentationData.strings.Common_Delete if case let .channel(channel) = chatPeer { - if case .broadcast = channel.info { + if channel.isMonoForum { canClear = false - deleteTitle = strongSelf.presentationData.strings.Channel_LeaveChannel - if channel.flags.contains(.isCreator) { - canRemoveGlobally = true - } + canRemoveGlobally = false } else { - deleteTitle = strongSelf.presentationData.strings.Group_DeleteGroup - if channel.flags.contains(.isCreator) { - canRemoveGlobally = true + if case .broadcast = channel.info { + canClear = false + deleteTitle = strongSelf.presentationData.strings.Channel_LeaveChannel + if channel.flags.contains(.isCreator) { + canRemoveGlobally = true + } + } else { + deleteTitle = strongSelf.presentationData.strings.Group_DeleteGroup + if channel.flags.contains(.isCreator) { + canRemoveGlobally = true + } + } + if let addressName = channel.addressName, !addressName.isEmpty { + canClear = false } - } - if let addressName = channel.addressName, !addressName.isEmpty { - canClear = false } } else if case let .legacyGroup(group) = chatPeer { if case .creator = group.role { diff --git a/submodules/ChatListUI/Sources/Node/ChatListItem.swift b/submodules/ChatListUI/Sources/Node/ChatListItem.swift index cad55bfac3..25e7fce3b7 100644 --- a/submodules/ChatListUI/Sources/Node/ChatListItem.swift +++ b/submodules/ChatListUI/Sources/Node/ChatListItem.swift @@ -2980,7 +2980,7 @@ public class ChatListItemNode: ItemListRevealOptionsItemNode { if customMessageListData.commandPrefix != nil { titleAttributedString = nil } else { - if let displayTitle = itemPeer.chatMainPeer?.displayTitle(strings: item.presentationData.strings, displayOrder: item.presentationData.nameDisplayOrder) { + if let displayTitle = itemPeer.chatOrMonoforumMainPeer?.displayTitle(strings: item.presentationData.strings, displayOrder: item.presentationData.nameDisplayOrder) { let textColor: UIColor if case let .chatList(index) = item.index, index.messageIndex.id.peerId.namespace == Namespaces.Peer.SecretChat { textColor = theme.secretTitleColor @@ -2988,6 +2988,10 @@ public class ChatListItemNode: ItemListRevealOptionsItemNode { textColor = theme.titleColor } titleAttributedString = NSAttributedString(string: displayTitle, font: titleFont, textColor: textColor) + + if case let .channel(channel) = itemPeer.peer, channel.flags.contains(.isMonoforum) { + titleBadgeText = item.presentationData.strings.ChatList_MonoforumLabel + } } } } else if let threadInfo = threadInfo { diff --git a/submodules/DeleteChatPeerActionSheetItem/Sources/DeleteChatPeerActionSheetItem.swift b/submodules/DeleteChatPeerActionSheetItem/Sources/DeleteChatPeerActionSheetItem.swift index e1d5e197cc..c7b1601538 100644 --- a/submodules/DeleteChatPeerActionSheetItem/Sources/DeleteChatPeerActionSheetItem.swift +++ b/submodules/DeleteChatPeerActionSheetItem/Sources/DeleteChatPeerActionSheetItem.swift @@ -130,8 +130,8 @@ private final class DeleteChatPeerActionSheetItemNode: ActionSheetItemNode { text = PresentationStrings.FormattedString(string: strings.ChatList_DeleteSavedMessagesConfirmation, ranges: []) } else if case let .legacyGroup(chatPeer) = chatPeer { text = strings.ChatList_DeleteAndLeaveGroupConfirmation(chatPeer.title) - } else if case let .channel(chatPeer) = chatPeer { - text = strings.ChatList_DeleteAndLeaveGroupConfirmation(chatPeer.title) + } else if case .channel = chatPeer { + text = strings.ChatList_DeleteAndLeaveGroupConfirmation(peer.compactDisplayTitle) } else if case .secretChat = chatPeer { text = strings.ChatList_DeleteSecretChatConfirmation(peer.displayTitle(strings: strings, displayOrder: nameOrder)) } else { diff --git a/submodules/Postbox/Sources/Peer.swift b/submodules/Postbox/Sources/Peer.swift index e4aed39cd0..827f98891a 100644 --- a/submodules/Postbox/Sources/Peer.swift +++ b/submodules/Postbox/Sources/Peer.swift @@ -298,6 +298,7 @@ public protocol Peer: AnyObject, PostboxCoding { var id: PeerId { get } var indexName: PeerIndexNameRepresentation { get } var associatedPeerId: PeerId? { get } + var additionalAssociatedPeerId: PeerId? { get } var associatedPeerOverridesIdentity: Bool { get } var notificationSettingsPeerId: PeerId? { get } var associatedMediaIds: [MediaId]? { get } @@ -307,6 +308,7 @@ public protocol Peer: AnyObject, PostboxCoding { } public extension Peer { + var additionalAssociatedPeerId: PeerId? { return nil } var associatedPeerOverridesIdentity: Bool { return false } } diff --git a/submodules/Postbox/Sources/PeerView.swift b/submodules/Postbox/Sources/PeerView.swift index 3f907ca142..20523451c9 100644 --- a/submodules/Postbox/Sources/PeerView.swift +++ b/submodules/Postbox/Sources/PeerView.swift @@ -48,15 +48,23 @@ final class MutablePeerView: MutablePostboxView { var messageIds = Set() peerIds.insert(peerId) - if let peer = getPeer(peerId), let associatedPeerId = peer.associatedPeerId { - peerIds.insert(associatedPeerId) - - if peer.associatedPeerOverridesIdentity { - self.contactPeerId = associatedPeerId - self.peerIsContact = postbox.contactsTable.isContact(peerId: associatedPeerId) + if let peer = getPeer(peerId) { + if let associatedPeerId = peer.associatedPeerId { + peerIds.insert(associatedPeerId) + + if peer.associatedPeerOverridesIdentity { + self.contactPeerId = associatedPeerId + self.peerIsContact = postbox.contactsTable.isContact(peerId: associatedPeerId) + } else { + self.contactPeerId = peerId + } } else { self.contactPeerId = peerId } + + if let additionalAssociatedPeerId = peer.additionalAssociatedPeerId { + peerIds.insert(additionalAssociatedPeerId) + } } else { self.contactPeerId = peerId } @@ -96,6 +104,11 @@ final class MutablePeerView: MutablePostboxView { } else { self.notificationSettings = postbox.peerNotificationSettingsTable.getEffective(peerId) } + if let peer = self.peers[peerId], let additionalAssociatedPeerId = peer.additionalAssociatedPeerId { + if let peer = getPeer(additionalAssociatedPeerId) { + self.peers[additionalAssociatedPeerId] = peer + } + } for id in messageIds { if let message = postbox.getMessage(id) { self.messages[id] = message @@ -141,8 +154,13 @@ final class MutablePeerView: MutablePostboxView { var peerIds = Set() peerIds.insert(self.peerId) - if let peer = getPeer(self.peerId), let associatedPeerId = peer.associatedPeerId { - peerIds.insert(associatedPeerId) + if let peer = getPeer(self.peerId) { + if let associatedPeerId = peer.associatedPeerId { + peerIds.insert(associatedPeerId) + } + if let additionalAssociatedPeerId = peer.additionalAssociatedPeerId { + peerIds.insert(additionalAssociatedPeerId) + } } peerIds.formUnion(cachedData.peerIds) @@ -186,8 +204,13 @@ final class MutablePeerView: MutablePostboxView { } else { var peerIds = Set() peerIds.insert(self.peerId) - if let peer = getPeer(self.peerId), let associatedPeerId = peer.associatedPeerId { - peerIds.insert(associatedPeerId) + if let peer = getPeer(self.peerId) { + if let associatedPeerId = peer.associatedPeerId { + peerIds.insert(associatedPeerId) + } + if let additionalAssociatedPeerId = peer.additionalAssociatedPeerId { + peerIds.insert(additionalAssociatedPeerId) + } } if let cachedData = self.cachedData { peerIds.formUnion(cachedData.peerIds) diff --git a/submodules/ShareController/Sources/ShareControllerNode.swift b/submodules/ShareController/Sources/ShareControllerNode.swift index ac5ac7f677..7090a6c7f2 100644 --- a/submodules/ShareController/Sources/ShareControllerNode.swift +++ b/submodules/ShareController/Sources/ShareControllerNode.swift @@ -1285,12 +1285,16 @@ final class ShareControllerNode: ViewControllerTracingNode, ASScrollViewDelegate } ) |> take(1) - |> map { views -> ([EnginePeer.Id: EnginePeer?], [EnginePeer.Id: Int64]) in - var result: [EnginePeer.Id: EnginePeer?] = [:] + |> map { views -> ([EnginePeer.Id: EngineRenderedPeer?], [EnginePeer.Id: Int64]) in + var result: [EnginePeer.Id: EngineRenderedPeer?] = [:] var requiresStars: [EnginePeer.Id: Int64] = [:] for peerId in peerIds { if let view = views.views[PostboxViewKey.basicPeer(peerId)] as? PeerView, let peer = peerViewMainPeer(view) { - result[peerId] = EnginePeer(peer) + var peers: [EnginePeer.Id: EnginePeer] = [peer.id: EnginePeer(peer)] + if let channel = peer as? TelegramChannel, channel.isMonoForum, let linkedMonoforumId = channel.linkedMonoforumId, let mainChannel = view.peers[linkedMonoforumId] { + peers[mainChannel.id] = EnginePeer(mainChannel) + } + result[peerId] = EngineRenderedPeer(peerId: peer.id, peers: peers, associatedMedia: [:]) if peer is TelegramUser, let cachedPeerDataView = views.views[PostboxViewKey.cachedPeerData(peerId: peerId)] as? CachedPeerDataView { if let cachedData = cachedPeerDataView.cachedPeerData as? CachedUserData { requiresStars[peerId] = cachedData.sendPaidMessageStars?.value @@ -1307,14 +1311,14 @@ final class ShareControllerNode: ViewControllerTracingNode, ASScrollViewDelegate return } - var mappedPeers: [EnginePeer] = [] + var mappedPeers: [EngineRenderedPeer] = [] for peerId in peerIds { if let maybePeer = peers[peerId], let peer = maybePeer { mappedPeers.append(peer) } } - if !tryShare(self.inputFieldNode.text, mappedPeers) { + if !tryShare(self.inputFieldNode.text, mappedPeers.compactMap(\.peer)) { return } @@ -1328,15 +1332,15 @@ final class ShareControllerNode: ViewControllerTracingNode, ASScrollViewDelegate } } - private func presentPaidMessageAlertIfNeeded(peers: [EnginePeer], requiresStars: [EnginePeer.Id: Int64], completion: @escaping () -> Void) { + private func presentPaidMessageAlertIfNeeded(peers: [EngineRenderedPeer], requiresStars: [EnginePeer.Id: Int64], completion: @escaping () -> Void) { var count: Int32 = Int32(self.messageCount) if !self.inputFieldNode.text.isEmpty { count += 1 } - var chargingPeers: [EnginePeer] = [] + var chargingPeers: [EngineRenderedPeer] = [] var totalAmount: StarsAmount = .zero for peer in peers { - if let stars = requiresStars[peer.id] { + if let stars = requiresStars[peer.peerId] { chargingPeers.append(peer) totalAmount = totalAmount + StarsAmount(value: stars, nanos: 0) } diff --git a/submodules/TelegramCore/Sources/SyncCore/SyncCore_TelegramChannel.swift b/submodules/TelegramCore/Sources/SyncCore/SyncCore_TelegramChannel.swift index 8c82a0cee4..68e9ac0cc8 100644 --- a/submodules/TelegramCore/Sources/SyncCore/SyncCore_TelegramChannel.swift +++ b/submodules/TelegramCore/Sources/SyncCore/SyncCore_TelegramChannel.swift @@ -223,6 +223,10 @@ public final class TelegramChannel: Peer, Equatable { } } + public var additionalAssociatedPeerId: PeerId? { + self.linkedMonoforumId + } + public var indexName: PeerIndexNameRepresentation { var addressNames = self.usernames.map { $0.username } if addressNames.isEmpty, let username = self.username, !username.isEmpty { diff --git a/submodules/TelegramUI/Components/Chat/ChatMessagePaymentAlertController/Sources/ChatMessagePaymentAlertController.swift b/submodules/TelegramUI/Components/Chat/ChatMessagePaymentAlertController/Sources/ChatMessagePaymentAlertController.swift index d78bb08410..9199fef551 100644 --- a/submodules/TelegramUI/Components/Chat/ChatMessagePaymentAlertController/Sources/ChatMessagePaymentAlertController.swift +++ b/submodules/TelegramUI/Components/Chat/ChatMessagePaymentAlertController/Sources/ChatMessagePaymentAlertController.swift @@ -422,7 +422,7 @@ public func chatMessagePaymentAlertController( context: AccountContext?, presentationData: PresentationData, updatedPresentationData: (initial: PresentationData, signal: Signal)?, - peers: [EnginePeer], + peers: [EngineRenderedPeer], count: Int32, amount: StarsAmount, totalAmount: StarsAmount?, @@ -452,10 +452,10 @@ public func chatMessagePaymentAlertController( if peers.count == 1, let peer = peers.first { let amountString = presentationData.strings.Chat_PaidMessage_Confirm_Text_Stars(Int32(amount.value)) let totalString = presentationData.strings.Chat_PaidMessage_Confirm_Text_Stars(Int32(amount.value * Int64(count))) - if case let .channel(channel) = peer, case .broadcast = channel.info { - text = presentationData.strings.Chat_PaidMessage_Confirm_SingleComment_Text(peer.compactDisplayTitle, amountString, totalString, messagesString).string + if case let .channel(channel) = peer.chatOrMonoforumMainPeer, case .broadcast = channel.info { + text = presentationData.strings.Chat_PaidMessage_Confirm_SingleComment_Text(EnginePeer(channel).compactDisplayTitle, amountString, totalString, messagesString).string } else { - text = presentationData.strings.Chat_PaidMessage_Confirm_Single_Text(peer.compactDisplayTitle, amountString, totalString, messagesString).string + text = presentationData.strings.Chat_PaidMessage_Confirm_Single_Text(peer.chatOrMonoforumMainPeer?.compactDisplayTitle ?? " ", amountString, totalString, messagesString).string } } else { let amount = totalAmount ?? amount diff --git a/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/ListItems/PeerInfoScreenPersonalChannelItem.swift b/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/ListItems/PeerInfoScreenPersonalChannelItem.swift index 55abf78cd1..edad6bc318 100644 --- a/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/ListItems/PeerInfoScreenPersonalChannelItem.swift +++ b/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/ListItems/PeerInfoScreenPersonalChannelItem.swift @@ -537,7 +537,7 @@ private final class PeerInfoScreenPersonalChannelItemNode: PeerInfoScreenItemNod return } - StoryContainerScreen.openPeerStories(context: item.context, peerId: item.data.peer.id, parentController: controller, avatarNode: itemNode.avatarNode) + StoryContainerScreen.openPeerStories(context: item.context, peerId: item.data.peer.peerId, parentController: controller, avatarNode: itemNode.avatarNode) }, openStarsTopup: { _ in }, @@ -565,7 +565,7 @@ private final class PeerInfoScreenPersonalChannelItemNode: PeerInfoScreenItemNod index = EngineChatList.Item.Index.chatList(ChatListIndex(pinningIndex: nil, messageIndex: item.data.topMessages[0].index)) messages = item.data.topMessages } else { - index = EngineChatList.Item.Index.chatList(ChatListIndex(pinningIndex: nil, messageIndex: MessageIndex(id: MessageId(peerId: item.data.peer.id, namespace: Namespaces.Message.Cloud, id: 1), timestamp: 0))) + index = EngineChatList.Item.Index.chatList(ChatListIndex(pinningIndex: nil, messageIndex: MessageIndex(id: MessageId(peerId: item.data.peer.peerId, namespace: Namespaces.Message.Cloud, id: 1), timestamp: 0))) messages = [] } @@ -577,7 +577,7 @@ private final class PeerInfoScreenPersonalChannelItemNode: PeerInfoScreenItemNod index: index, content: .peer(ChatListItemContent.PeerData( messages: messages, - peer: EngineRenderedPeer(peer: item.data.peer), + peer: item.data.peer, threadInfo: nil, combinedReadState: nil, isRemovedFromTotalUnreadCount: false, diff --git a/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/PeerInfoData.swift b/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/PeerInfoData.swift index 6d9d74eea6..60a59f702f 100644 --- a/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/PeerInfoData.swift +++ b/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/PeerInfoData.swift @@ -314,13 +314,13 @@ final class TelegramGlobalSettings { } final class PeerInfoPersonalChannelData: Equatable { - let peer: EnginePeer + let peer: EngineRenderedPeer let subscriberCount: Int? let topMessages: [EngineMessage] let storyStats: PeerStoryStats? let isLoading: Bool - init(peer: EnginePeer, subscriberCount: Int?, topMessages: [EngineMessage], storyStats: PeerStoryStats?, isLoading: Bool) { + init(peer: EngineRenderedPeer, subscriberCount: Int?, topMessages: [EngineMessage], storyStats: PeerStoryStats?, isLoading: Bool) { self.peer = peer self.subscriberCount = subscriberCount self.topMessages = topMessages @@ -363,6 +363,7 @@ final class PeerInfoScreenData { let availablePanes: [PeerInfoPaneKey] let groupsInCommon: GroupsInCommonContext? let linkedDiscussionPeer: Peer? + let linkedMonoforumPeer: Peer? let members: PeerInfoMembersData? let storyListContext: StoryListContext? let storyArchiveListContext: StoryListContext? @@ -413,6 +414,7 @@ final class PeerInfoScreenData { availablePanes: [PeerInfoPaneKey], groupsInCommon: GroupsInCommonContext?, linkedDiscussionPeer: Peer?, + linkedMonoforumPeer: Peer?, members: PeerInfoMembersData?, storyListContext: StoryListContext?, storyArchiveListContext: StoryListContext?, @@ -451,6 +453,7 @@ final class PeerInfoScreenData { self.availablePanes = availablePanes self.groupsInCommon = groupsInCommon self.linkedDiscussionPeer = linkedDiscussionPeer + self.linkedMonoforumPeer = linkedMonoforumPeer self.members = members self.storyListContext = storyListContext self.storyArchiveListContext = storyArchiveListContext @@ -663,10 +666,25 @@ public func keepPeerInfoScreenDataHot(context: AccountContext, peerId: PeerId, c } } -private func peerInfoPersonalChannel(context: AccountContext, peerId: EnginePeer.Id, isSettings: Bool) -> Signal { - return context.engine.data.subscribe( - TelegramEngine.EngineData.Item.Peer.PersonalChannel(id: peerId) +private func peerInfoPersonalOrLinkedChannel(context: AccountContext, peerId: EnginePeer.Id, isSettings: Bool) -> Signal { + let personalChannel: Signal = context.engine.data.subscribe( + TelegramEngine.EngineData.Item.Peer.Peer(id: peerId) ) + |> mapToSignal { peer -> Signal in + guard let peer else { + return .single(.known(nil)) + } + if case .user = peer { + return context.engine.data.subscribe( + TelegramEngine.EngineData.Item.Peer.PersonalChannel(id: peerId) + ) + } else if case let .channel(channel) = peer, case let .broadcast(info) = channel.info, info.flags.contains(.hasMonoforum), let linkedMonoforumId = channel.linkedMonoforumId { + return .single(CachedTelegramPersonalChannel.known(TelegramPersonalChannel(peerId: linkedMonoforumId, subscriberCount: nil, topMessageId: nil))) + } + return .single(.known(nil)) + } + + return personalChannel |> distinctUntilChanged |> mapToSignal { personalChannel -> Signal in guard case let .known(personalChannelValue) = personalChannel, let personalChannelValue else { @@ -674,15 +692,14 @@ private func peerInfoPersonalChannel(context: AccountContext, peerId: EnginePeer } return context.engine.data.subscribe( - TelegramEngine.EngineData.Item.Peer.Peer(id: personalChannelValue.peerId), + TelegramEngine.EngineData.Item.Peer.RenderedPeer(id: personalChannelValue.peerId), TelegramEngine.EngineData.Item.Peer.ParticipantCount(id: personalChannelValue.peerId) ) - |> mapToSignal { channelPeer, participantCount -> Signal in - guard let channelPeer else { + |> mapToSignal { channelRenderedPeer, participantCount -> Signal in + guard let channelRenderedPeer, let channelPeer = channelRenderedPeer.peer else { return .single(nil) } - let polledChannel: Signal = Signal.single(Void()) |> then( context.account.viewTracker.polledChannel(peerId: channelPeer.id) @@ -723,7 +740,7 @@ private func peerInfoPersonalChannel(context: AccountContext, peerId: EnginePeer } return PeerInfoPersonalChannelData( - peer: channelPeer, + peer: channelRenderedPeer, subscriberCount: mappedParticipantCount, topMessages: messages, storyStats: storyStats, @@ -862,7 +879,7 @@ func peerInfoScreenSettingsData(context: AccountContext, peerId: EnginePeer.Id, |> distinctUntilChanged, hasStories, bots, - peerInfoPersonalChannel(context: context, peerId: peerId, isSettings: true), + peerInfoPersonalOrLinkedChannel(context: context, peerId: peerId, isSettings: true), starsState ) |> map { peerView, accountsAndPeers, accountSessions, privacySettings, sharedPreferences, notifications, stickerPacks, hasPassport, hasWatchApp, accountPreferences, suggestions, limits, hasPassword, isPowerSavingEnabled, hasStories, bots, personalChannel, starsState -> PeerInfoScreenData in @@ -925,6 +942,7 @@ func peerInfoScreenSettingsData(context: AccountContext, peerId: EnginePeer.Id, availablePanes: [], groupsInCommon: nil, linkedDiscussionPeer: nil, + linkedMonoforumPeer: nil, members: nil, storyListContext: hasStories == true ? storyListContext : nil, storyArchiveListContext: nil, @@ -974,6 +992,7 @@ func peerInfoScreenData(context: AccountContext, peerId: PeerId, strings: Presen availablePanes: [], groupsInCommon: nil, linkedDiscussionPeer: nil, + linkedMonoforumPeer: nil, members: nil, storyListContext: nil, storyArchiveListContext: nil, @@ -1325,7 +1344,7 @@ func peerInfoScreenData(context: AccountContext, peerId: PeerId, strings: Presen hasSavedMessages, hasSavedMessageTags, hasBotPreviewItems, - peerInfoPersonalChannel(context: context, peerId: peerId, isSettings: false), + peerInfoPersonalOrLinkedChannel(context: context, peerId: peerId, isSettings: false), privacySettings, starsRevenueContextAndState, revenueContextAndState, @@ -1432,6 +1451,7 @@ func peerInfoScreenData(context: AccountContext, peerId: PeerId, strings: Presen availablePanes: availablePanes ?? [], groupsInCommon: groupsInCommon, linkedDiscussionPeer: nil, + linkedMonoforumPeer: nil, members: nil, storyListContext: storyListContext, storyArchiveListContext: storyArchiveListContext, @@ -1564,6 +1584,8 @@ func peerInfoScreenData(context: AccountContext, peerId: PeerId, strings: Presen let profileGiftsContext = ProfileGiftsContext(account: context.account, peerId: peerId) + let personalChannel = peerInfoPersonalOrLinkedChannel(context: context, peerId: peerId, isSettings: false) + return combineLatest( context.account.viewTracker.peerView(peerId, updateData: true), peerInfoAvailableMediaPanes(context: context, peerId: peerId, chatLocation: chatLocation, isMyProfile: false, chatLocationContextHolder: chatLocationContextHolder), @@ -1582,9 +1604,10 @@ func peerInfoScreenData(context: AccountContext, peerId: PeerId, strings: Presen isPremiumRequiredForStoryPosting, starsRevenueContextAndState, revenueContextAndState, - profileGiftsContext.state + profileGiftsContext.state, + personalChannel ) - |> map { peerView, availablePanes, globalNotificationSettings, status, currentInvitationsContext, invitations, currentRequestsContext, requests, hasStories, accountIsPremium, recommendedChannels, hasSavedMessages, hasSavedMessagesChats, hasSavedMessageTags, isPremiumRequiredForStoryPosting, starsRevenueContextAndState, revenueContextAndState, profileGiftsState -> PeerInfoScreenData in + |> map { peerView, availablePanes, globalNotificationSettings, status, currentInvitationsContext, invitations, currentRequestsContext, requests, hasStories, accountIsPremium, recommendedChannels, hasSavedMessages, hasSavedMessagesChats, hasSavedMessageTags, isPremiumRequiredForStoryPosting, starsRevenueContextAndState, revenueContextAndState, profileGiftsState, personalChannel -> PeerInfoScreenData in var availablePanes = availablePanes if let hasStories { if hasStories { @@ -1621,6 +1644,11 @@ func peerInfoScreenData(context: AccountContext, peerId: PeerId, strings: Presen discussionPeer = peer } + var monoforumPeer: Peer? + if let channel = peerViewMainPeer(peerView) as? TelegramChannel, case let .broadcast(info) = channel.info, info.flags.contains(.hasMonoforum), let linkedMonoforumId = channel.linkedMonoforumId { + monoforumPeer = peerView.peers[linkedMonoforumId] + } + var canManageInvitations = false if let channel = peerViewMainPeer(peerView) as? TelegramChannel, let _ = peerView.cachedData as? CachedChannelData, channel.flags.contains(.isCreator) || (channel.adminRights?.rights.contains(.canInviteUsers) == true) { canManageInvitations = true @@ -1654,6 +1682,7 @@ func peerInfoScreenData(context: AccountContext, peerId: PeerId, strings: Presen availablePanes: availablePanes ?? [], groupsInCommon: nil, linkedDiscussionPeer: discussionPeer, + linkedMonoforumPeer: monoforumPeer, members: nil, storyListContext: storyListContext, storyArchiveListContext: nil, @@ -1670,7 +1699,7 @@ func peerInfoScreenData(context: AccountContext, peerId: PeerId, strings: Presen hasSavedMessageTags: hasSavedMessageTags, hasBotPreviewItems: false, isPremiumRequiredForStoryPosting: isPremiumRequiredForStoryPosting, - personalChannel: nil, + personalChannel: personalChannel, starsState: nil, starsRevenueStatsState: starsRevenueContextAndState.1, starsRevenueStatsContext: starsRevenueContextAndState.0, @@ -1903,6 +1932,11 @@ func peerInfoScreenData(context: AccountContext, peerId: PeerId, strings: Presen if case let .known(maybeLinkedDiscussionPeerId) = (peerView.cachedData as? CachedChannelData)?.linkedDiscussionPeerId, let linkedDiscussionPeerId = maybeLinkedDiscussionPeerId, let peer = peerView.peers[linkedDiscussionPeerId] { discussionPeer = peer } + + var monoforumPeer: Peer? + if let channel = peerViewMainPeer(peerView) as? TelegramChannel, case let .broadcast(info) = channel.info, info.flags.contains(.hasMonoforum), let linkedMonoforumId = channel.linkedMonoforumId { + monoforumPeer = peerView.peers[linkedMonoforumId] + } var availablePanes = availablePanes if let membersData = membersData, case .longList = membersData { @@ -1980,6 +2014,7 @@ func peerInfoScreenData(context: AccountContext, peerId: PeerId, strings: Presen availablePanes: availablePanes ?? [], groupsInCommon: nil, linkedDiscussionPeer: discussionPeer, + linkedMonoforumPeer: monoforumPeer, members: membersData, storyListContext: storyListContext, storyArchiveListContext: nil, diff --git a/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/PeerInfoScreen.swift b/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/PeerInfoScreen.swift index 606d5edcdc..a6b28d8ba4 100644 --- a/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/PeerInfoScreen.swift +++ b/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/PeerInfoScreen.swift @@ -1197,8 +1197,8 @@ private func settingsEditingItems(data: PeerInfoScreenData?, state: PeerInfoStat } if displayPersonalChannel { var personalChannelTitle: String? - if let personalChannel = data.personalChannel { - personalChannelTitle = personalChannel.peer.compactDisplayTitle + if let personalChannel = data.personalChannel, let peer = personalChannel.peer.chatOrMonoforumMainPeer { + personalChannelTitle = peer.compactDisplayTitle } items[.info]!.append(PeerInfoScreenDisclosureItem(id: ItemPeerPersonalChannel, label: .text(personalChannelTitle ?? presentationData.strings.Settings_PersonalChannelEmptyValue), text: presentationData.strings.Settings_PersonalChannelItem, icon: nil, action: { @@ -1288,7 +1288,7 @@ private func infoItems(data: PeerInfoScreenData?, context: AccountContext, prese } if let personalChannel = data.personalChannel { - let peerId = personalChannel.peer.id + let peerId = personalChannel.peer.peerId var label: String? if let subscriberCount = personalChannel.subscriberCount { label = presentationData.strings.Conversation_StatusSubscribers(Int32(subscriberCount)) @@ -2024,6 +2024,7 @@ private func editingItems(data: PeerInfoScreenData?, boostStatus: ChannelBoostSt case peerDataSettings case peerVerifySettings case peerSettings + case linkedMonoforum case peerAdditionalSettings case peerActions } @@ -2218,10 +2219,6 @@ private func editingItems(data: PeerInfoScreenData?, boostStatus: ChannelBoostSt items[.peerSettings]!.append(PeerInfoScreenDisclosureItem(id: ItemDiscussionGroup, label: .text(discussionGroupTitle), text: presentationData.strings.Channel_DiscussionGroup, icon: UIImage(bundleImageName: "Chat/Info/GroupDiscussionIcon"), action: { interaction.editingOpenDiscussionGroupSetup() })) - - items[.peerSettings]!.append(PeerInfoScreenDisclosureItem(id: ItemPostSuggestionsSettings, label: .text(channel.linkedMonoforumId == nil ? presentationData.strings.PeerInfo_AllowChannelMessages_Off : presentationData.strings.PeerInfo_AllowChannelMessages_On), additionalBadgeLabel: presentationData.strings.Settings_New, text: presentationData.strings.PeerInfo_AllowChannelMessages, icon: PresentationResourcesSettings.channelMessages, action: { - interaction.editingOpenPostSuggestionsSetup() - })) } if isCreator || (channel.adminRights?.rights.contains(.canChangeInfo) == true) { @@ -2266,7 +2263,7 @@ private func editingItems(data: PeerInfoScreenData?, boostStatus: ChannelBoostSt if let approximateBoostLevel = channel.approximateBoostLevel, approximateBoostLevel < 1 { boostIcon = generateDisclosureActionBoostLevelBadgeImage(text: presentationData.strings.Channel_Info_BoostLevelPlusBadge("1").string) } else { - let labelText = NSAttributedString(string: presentationData.strings.Settings_New, font: Font.medium(11.0), textColor: presentationData.theme.list.itemCheckColors.foregroundColor) + /*let labelText = NSAttributedString(string: presentationData.strings.Settings_New, font: Font.medium(11.0), textColor: presentationData.theme.list.itemCheckColors.foregroundColor) let labelBounds = labelText.boundingRect(with: CGSize(width: 100.0, height: 100.0), options: [.usesLineFragmentOrigin], context: nil) let labelSize = CGSize(width: ceil(labelBounds.width), height: ceil(labelBounds.height)) let badgeSize = CGSize(width: labelSize.width + 8.0, height: labelSize.height + 2.0 + 1.0) @@ -2282,7 +2279,7 @@ private func editingItems(data: PeerInfoScreenData?, boostStatus: ChannelBoostSt UIGraphicsPushContext(context) labelText.draw(at: CGPoint(x: 4.0, y: 1.0 + UIScreenPixel)) UIGraphicsPopContext() - }) + })*/ } items[.peerSettings]!.append(PeerInfoScreenDisclosureItem(id: ItemPeerColor, label: .image(colorImage, colorImage.size), additionalBadgeIcon: boostIcon, text: presentationData.strings.Channel_Info_AppearanceItem, icon: UIImage(bundleImageName: "Chat/Info/NameColorIcon"), action: { interaction.editingOpenNameColorSetup() @@ -2302,6 +2299,62 @@ private func editingItems(data: PeerInfoScreenData?, boostStatus: ChannelBoostSt })) } + if isCreator || (channel.adminRights?.rights.contains(.canChangeInfo) == true) { + let labelString: NSAttributedString + if channel.linkedMonoforumId != nil { + if let monoforumPeer = data.linkedMonoforumPeer as? TelegramChannel { + if let sendPaidMessageStars = monoforumPeer.sendPaidMessageStars { + let formattedLabel = formatStarsAmountText(sendPaidMessageStars, dateTimeFormat: presentationData.dateTimeFormat) + let smallLabelFont = Font.regular(floor(presentationData.listsFontSize.itemListBaseFontSize / 17.0 * 13.0)) + let labelFont = Font.regular(presentationData.listsFontSize.itemListBaseFontSize) + let labelColor = presentationData.theme.list.itemSecondaryTextColor + let attributedString = tonAmountAttributedString(formattedLabel, integralFont: labelFont, fractionalFont: smallLabelFont, color: labelColor, decimalSeparator: presentationData.dateTimeFormat.decimalSeparator).mutableCopy() as! NSMutableAttributedString + attributedString.insert(NSAttributedString(string: "*", font: labelFont, textColor: labelColor), at: 0) + + if let range = attributedString.string.range(of: "*") { + attributedString.addAttribute(ChatTextInputAttributes.customEmoji, value: ChatTextInputTextCustomEmojiAttribute(interactivelySelectedFromPackId: nil, fileId: 0, file: nil, custom: .stars(tinted: false)), range: NSRange(range, in: attributedString.string)) + attributedString.addAttribute(.baselineOffset, value: 1.5, range: NSRange(range, in: attributedString.string)) + } + labelString = attributedString + } else { + let labelFont = Font.regular(presentationData.listsFontSize.itemListBaseFontSize) + let labelColor = presentationData.theme.list.itemSecondaryTextColor + + labelString = NSAttributedString(string: presentationData.strings.PeerInfo_AllowChannelMessages_Free, font: labelFont, textColor: labelColor) + } + } else { + let labelFont = Font.regular(presentationData.listsFontSize.itemListBaseFontSize) + let labelColor = presentationData.theme.list.itemSecondaryTextColor + + labelString = NSAttributedString(string: " ", font: labelFont, textColor: labelColor) + } + } else { + let labelFont = Font.regular(presentationData.listsFontSize.itemListBaseFontSize) + let labelColor = presentationData.theme.list.itemSecondaryTextColor + + labelString = NSAttributedString(string: presentationData.strings.PeerInfo_AllowChannelMessages_Off, font: labelFont, textColor: labelColor) + } + + items[.peerSettings]!.append(PeerInfoScreenDisclosureItem(id: ItemPostSuggestionsSettings, label: .attributedText(labelString), additionalBadgeLabel: presentationData.strings.Settings_New, text: presentationData.strings.PeerInfo_AllowChannelMessages, icon: PresentationResourcesSettings.channelMessages, action: { + interaction.editingOpenPostSuggestionsSetup() + })) + + if let personalChannel = data.personalChannel { + let peerId = personalChannel.peer.peerId + items[.linkedMonoforum]?.append(PeerInfoScreenPersonalChannelItem(id: 1, context: context, data: personalChannel, controller: { [weak interaction] in + guard let interaction else { + return nil + } + return interaction.getController() + }, action: { [weak interaction] in + guard let interaction else { + return + } + interaction.openChat(peerId) + })) + } + } + var canEditMembers = false if channel.hasPermission(.banMembers) && (channel.adminRights != nil || channel.flags.contains(.isCreator)) { canEditMembers = true diff --git a/submodules/TelegramUI/Components/SendInviteLinkScreen/Sources/SendInviteLinkScreen.swift b/submodules/TelegramUI/Components/SendInviteLinkScreen/Sources/SendInviteLinkScreen.swift index 5c0dea7506..52d93e4eb3 100644 --- a/submodules/TelegramUI/Components/SendInviteLinkScreen/Sources/SendInviteLinkScreen.swift +++ b/submodules/TelegramUI/Components/SendInviteLinkScreen/Sources/SendInviteLinkScreen.swift @@ -267,14 +267,14 @@ private final class SendInviteLinkScreenComponent: Component { } } - private func presentPaidMessageAlertIfNeeded(peers: [EnginePeer], requiresStars: [EnginePeer.Id: StarsAmount], completion: @escaping () -> Void) { + private func presentPaidMessageAlertIfNeeded(peers: [EngineRenderedPeer], requiresStars: [EnginePeer.Id: StarsAmount], completion: @escaping () -> Void) { guard let component = self.component else { completion() return } var totalAmount: StarsAmount = .zero for peer in peers { - if let amount = requiresStars[peer.id] { + if let amount = requiresStars[peer.peerId] { totalAmount = totalAmount + amount } } @@ -968,7 +968,7 @@ private final class SendInviteLinkScreenComponent: Component { let selectedPeers = component.peers.filter { self.selectedItems.contains($0.peer.id) } self.presentPaidMessageAlertIfNeeded( - peers: selectedPeers.map { $0.peer }, + peers: selectedPeers.map { EngineRenderedPeer(peer: $0.peer) }, requiresStars: component.sendPaidMessageStars, completion: { [weak self] in guard let self, let component = self.component, let controller = self.environment?.controller() else { diff --git a/submodules/TelegramUI/Components/Stars/StarsWithdrawalScreen/Sources/StarsWithdrawalScreen.swift b/submodules/TelegramUI/Components/Stars/StarsWithdrawalScreen/Sources/StarsWithdrawalScreen.swift index dec8eb1805..4a0d292bb4 100644 --- a/submodules/TelegramUI/Components/Stars/StarsWithdrawalScreen/Sources/StarsWithdrawalScreen.swift +++ b/submodules/TelegramUI/Components/Stars/StarsWithdrawalScreen/Sources/StarsWithdrawalScreen.swift @@ -151,16 +151,10 @@ private final class SheetContent: CombinedComponent { minAmount = StarsAmount(value: resaleConfiguration.starGiftResaleMinAmount, nanos: 0) maxAmount = StarsAmount(value: resaleConfiguration.starGiftResaleMaxAmount, nanos: 0) - case let .paidMessages(_, minAmountValue, _, kind): - //TODO:localize - switch kind { - case .privacy: - titleString = "Price per Message" - case .postSuggestion: - titleString = "Price for each Suggestion" - } - amountTitle = "PRICE IN STARS" - amountPlaceholder = "Enter Price" + case let .paidMessages(_, minAmountValue, _, _): + titleString = environment.strings.Stars_SendMessage_AdjustmentTitle + amountTitle = environment.strings.Stars_SendMessage_AdjustmentSectionHeader + amountPlaceholder = environment.strings.Stars_SendMessage_AdjustmentPlaceholder minAmount = StarsAmount(value: minAmountValue, nanos: 0) maxAmount = StarsAmount(value: resaleConfiguration.paidMessageMaxAmount, nanos: 0) @@ -299,9 +293,9 @@ private final class SheetContent: CombinedComponent { if let value = state.amount?.value, value > 0 { let fullValue: Int64 = Int64(value) * 1_000_000_000 * Int64(fractionAfterCommission) / 100 let amountValue = StarsAmount(value: fullValue / 1_000_000_000, nanos: Int32(fullValue % 1_000_000_000)) - amountInfoString = NSAttributedString(attributedString: parseMarkdownIntoAttributedString("You will receive **\(amountValue) Stars**.", attributes: amountMarkdownAttributes, textAlignment: .natural)) + amountInfoString = NSAttributedString(attributedString: parseMarkdownIntoAttributedString(environment.strings.Stars_SendMessage_AdjustmentSectionFooterValue("\(amountValue)").string, attributes: amountMarkdownAttributes, textAlignment: .natural)) } else { - amountInfoString = NSAttributedString(attributedString: parseMarkdownIntoAttributedString("You will receive **80%**.", attributes: amountMarkdownAttributes, textAlignment: .natural)) + amountInfoString = NSAttributedString(attributedString: parseMarkdownIntoAttributedString(environment.strings.Stars_SendMessage_AdjustmentSectionFooterEmpty, attributes: amountMarkdownAttributes, textAlignment: .natural)) } amountFooter = AnyComponent(MultilineTextComponent( text: .plain(amountInfoString), @@ -376,8 +370,7 @@ private final class SheetContent: CombinedComponent { buttonString = environment.strings.Stars_SellGift_Sell } } else if case .paidMessages = component.mode { - //TODO:localize - buttonString = "OK" + buttonString = environment.strings.Stars_SendMessage_AdjustmentAction } else if let amount = state.amount { buttonString = "\(environment.strings.Stars_Withdraw_Withdraw) # \(presentationStringsFormattedNumber(amount, environment.dateTimeFormat.groupingSeparator))" } else { @@ -672,6 +665,7 @@ public final class StarsWithdrawScreen: ViewControllerComponentContainer { let presentationData = self.context.sharedContext.currentPresentationData.with { $0 } var text = presentationData.strings.Stars_Withdraw_Withdraw_ErrorMinimum(presentationData.strings.Stars_Withdraw_Withdraw_ErrorMinimum_Stars(Int32(minAmount))).string if case .starGiftResell = self.mode { + //TODO:localize text = "You cannot sell gift for less than \(presentationData.strings.Stars_Withdraw_Withdraw_ErrorMinimum_Stars(Int32(minAmount)))." } diff --git a/submodules/TelegramUI/Components/Stories/StoryContainerScreen/Sources/StoryItemSetContainerViewSendMessage.swift b/submodules/TelegramUI/Components/Stories/StoryContainerScreen/Sources/StoryItemSetContainerViewSendMessage.swift index a40d162780..14f1e8d9f2 100644 --- a/submodules/TelegramUI/Components/Stories/StoryContainerScreen/Sources/StoryItemSetContainerViewSendMessage.swift +++ b/submodules/TelegramUI/Components/Stories/StoryContainerScreen/Sources/StoryItemSetContainerViewSendMessage.swift @@ -504,7 +504,7 @@ final class StoryItemSetContainerSendMessage { context: component.context, presentationData: presentationData, updatedPresentationData: nil, - peers: [component.slice.effectivePeer], + peers: [EngineRenderedPeer(peer: component.slice.effectivePeer)], count: 1, amount: sendPaidMessageStars, totalAmount: nil, diff --git a/submodules/TelegramUI/Sources/Chat/ChatControllerPaidMessage.swift b/submodules/TelegramUI/Sources/Chat/ChatControllerPaidMessage.swift index 0a0859db68..30ba8684d0 100644 --- a/submodules/TelegramUI/Sources/Chat/ChatControllerPaidMessage.swift +++ b/submodules/TelegramUI/Sources/Chat/ChatControllerPaidMessage.swift @@ -20,6 +20,9 @@ extension ChatControllerImpl { completion(false) return } + guard let renderedPeer = self.presentationInterfaceState.renderedPeer.flatMap(EngineRenderedPeer.init) else { + return + } if let sendPaidMessageStars = self.presentationInterfaceState.sendPaidMessageStars, self.presentationInterfaceState.interfaceState.editMessage == nil { let totalAmount = sendPaidMessageStars.value * Int64(count) @@ -42,14 +45,16 @@ extension ChatControllerImpl { presentationData = presentationData.withUpdated(theme: defaultDarkColorPresentationTheme) } var peer = peer + var renderedPeer = renderedPeer if let peerDiscussionId = self.presentationInterfaceState.peerDiscussionId, let channel = self.contentData?.state.peerView?.peers[peerDiscussionId] { peer = EnginePeer(channel) + renderedPeer = EngineRenderedPeer(peer: peer) } let controller = chatMessagePaymentAlertController( context: self.context, presentationData: presentationData, updatedPresentationData: nil, - peers: [peer], + peers: [renderedPeer], count: count, amount: sendPaidMessageStars, totalAmount: nil, diff --git a/submodules/TelegramUI/Sources/ChatControllerForwardMessages.swift b/submodules/TelegramUI/Sources/ChatControllerForwardMessages.swift index b856b26bbc..76d96bd35c 100644 --- a/submodules/TelegramUI/Sources/ChatControllerForwardMessages.swift +++ b/submodules/TelegramUI/Sources/ChatControllerForwardMessages.swift @@ -100,20 +100,25 @@ extension ChatControllerImpl { let _ = (context.engine.data.get( EngineDataMap( peerIds.map(TelegramEngine.EngineData.Item.Peer.SendPaidMessageStars.init(id:)) + ), + EngineDataList( + peerIds.map(TelegramEngine.EngineData.Item.Peer.RenderedPeer.init(id:)) ) ) - |> deliverOnMainQueue).start(next: { [weak self, weak controller] sendPaidMessageStars in + |> deliverOnMainQueue).start(next: { [weak self, weak controller] sendPaidMessageStars, renderedPeers in guard let strongSelf = self else { return } + let renderedPeers = renderedPeers.compactMap({ $0 }) + var count: Int32 = Int32(messages.count) if messageText.string.count > 0 { count += 1 } var totalAmount: StarsAmount = .zero - var chargingPeers: [EnginePeer] = [] - for peer in peers { - if let maybeAmount = sendPaidMessageStars[peer.id], let amount = maybeAmount { + var chargingPeers: [EngineRenderedPeer] = [] + for peer in renderedPeers { + if let maybeAmount = sendPaidMessageStars[peer.peerId], let amount = maybeAmount { totalAmount = totalAmount + amount chargingPeers.append(peer) } diff --git a/submodules/TelegramUI/Sources/ChatControllerNode.swift b/submodules/TelegramUI/Sources/ChatControllerNode.swift index c65d45c690..0769d003c6 100644 --- a/submodules/TelegramUI/Sources/ChatControllerNode.swift +++ b/submodules/TelegramUI/Sources/ChatControllerNode.swift @@ -398,6 +398,7 @@ class ChatControllerNode: ASDisplayNode, ASScrollViewDelegate { } else { self.loadingPlaceholderNode = nil loadingPlaceholderNode.removeFromSupernode() + self.backgroundNode.updateIsLooping(false) } } } else { @@ -1433,7 +1434,7 @@ class ChatControllerNode: ASDisplayNode, ASScrollViewDelegate { translationPanelNode.clipsToBounds = true } - let height = translationPanelNode.updateLayout(width: layout.size.width, leftInset: leftPanelSize?.width ?? layout.safeInsets.left, rightInset: layout.safeInsets.right, transition: immediatelyLayoutTitleAccessoryPanelNodeAndAnimateAppearance ? .immediate : transition, interfaceState: self.chatPresentationInterfaceState) + let height = translationPanelNode.updateLayout(width: layout.size.width, leftInset: leftPanelSize?.width ?? layout.safeInsets.left, rightInset: layout.safeInsets.right, leftDisplayInset: leftPanelSize?.width ?? 0.0, transition: immediatelyLayoutTitleAccessoryPanelNodeAndAnimateAppearance ? .immediate : transition, interfaceState: self.chatPresentationInterfaceState) translationPanelHeight = height if immediatelyLayoutTranslationPanelNodeAndAnimateAppearance { translationPanelNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.2) diff --git a/submodules/TelegramUI/Sources/ChatTranslationPanelNode.swift b/submodules/TelegramUI/Sources/ChatTranslationPanelNode.swift index 5a76c30635..1f4ea934d3 100644 --- a/submodules/TelegramUI/Sources/ChatTranslationPanelNode.swift +++ b/submodules/TelegramUI/Sources/ChatTranslationPanelNode.swift @@ -82,7 +82,7 @@ final class ChatTranslationPanelNode: ASDisplayNode { self.layer.animateBounds(from: self.bounds, to: self.bounds.offsetBy(dx: 0.0, dy: self.bounds.size.height), duration: 0.4, timingFunction: kCAMediaTimingFunctionSpring, removeOnCompletion: false) } - func updateLayout(width: CGFloat, leftInset: CGFloat, rightInset: CGFloat, transition: ContainedViewLayoutTransition, interfaceState: ChatPresentationInterfaceState) -> CGFloat { + func updateLayout(width: CGFloat, leftInset: CGFloat, rightInset: CGFloat, leftDisplayInset: CGFloat, transition: ContainedViewLayoutTransition, interfaceState: ChatPresentationInterfaceState) -> CGFloat { let previousIsEnabled = self.chatInterfaceState?.translationState?.isEnabled self.chatInterfaceState = interfaceState @@ -176,7 +176,7 @@ final class ChatTranslationPanelNode: ASDisplayNode { self.buttonTextNode.bounds = CGRect(origin: CGPoint(), size: buttonTextFrame.size) } - transition.updateFrame(node: self.separatorNode, frame: CGRect(origin: CGPoint(x: 0.0, y: 0.0), size: CGSize(width: width, height: UIScreenPixel))) + transition.updateFrame(node: self.separatorNode, frame: CGRect(origin: CGPoint(x: leftDisplayInset, y: 0.0), size: CGSize(width: width - leftDisplayInset, height: UIScreenPixel))) return panelHeight } diff --git a/submodules/WebUI/Sources/WebAppMessagePreviewScreen.swift b/submodules/WebUI/Sources/WebAppMessagePreviewScreen.swift index b41f39b0db..a9090e04e4 100644 --- a/submodules/WebUI/Sources/WebAppMessagePreviewScreen.swift +++ b/submodules/WebUI/Sources/WebAppMessagePreviewScreen.swift @@ -431,16 +431,20 @@ public final class WebAppMessagePreviewScreen: ViewControllerComponentContainer let _ = (self.context.engine.data.get( EngineDataMap( peers.map { TelegramEngine.EngineData.Item.Peer.SendPaidMessageStars.init(id: $0.id) } + ), + EngineDataList( + peers.map { TelegramEngine.EngineData.Item.Peer.RenderedPeer.init(id: $0.id) } ) ) - |> deliverOnMainQueue).start(next: { [weak self] sendPaidMessageStars in + |> deliverOnMainQueue).start(next: { [weak self] sendPaidMessageStars, renderedPeers in guard let self else { return } + let renderedPeers = renderedPeers.compactMap({ $0 }) var totalAmount: StarsAmount = .zero - var chargingPeers: [EnginePeer] = [] - for peer in peers { - if let maybeAmount = sendPaidMessageStars[peer.id], let amount = maybeAmount { + var chargingPeers: [EngineRenderedPeer] = [] + for peer in renderedPeers { + if let maybeAmount = sendPaidMessageStars[peer.peerId], let amount = maybeAmount { totalAmount = totalAmount + amount chargingPeers.append(peer) }