From 29ecff37281340e0c9a03bf3770b80dd5b6f9a83 Mon Sep 17 00:00:00 2001 From: Ilya Laktyushin Date: Thu, 30 Apr 2026 12:43:12 +0200 Subject: [PATCH 1/5] Various fixes --- .../Sources/Node/ChatListItem.swift | 8 ++++-- .../Sources/QuickShareToastScreen.swift | 23 +++++++++------- .../WebUI/Sources/WebAppController.swift | 7 ++++- submodules/WebUI/Sources/WebAppWebView.swift | 27 +++++++++++++++++-- 4 files changed, 50 insertions(+), 15 deletions(-) diff --git a/submodules/ChatListUI/Sources/Node/ChatListItem.swift b/submodules/ChatListUI/Sources/Node/ChatListItem.swift index 2e76203112..abc01321fb 100644 --- a/submodules/ChatListUI/Sources/Node/ChatListItem.swift +++ b/submodules/ChatListUI/Sources/Node/ChatListItem.swift @@ -2589,6 +2589,10 @@ public class ChatListItemNode: ItemListRevealOptionsItemNode { if case .user = itemPeer.chatMainPeer { isUser = true } + var isGuestChatAuthor = false + if case let .user(user) = messages.last?.author, let botInfo = user.botInfo, botInfo.flags.contains(.isGuestChat) { + isGuestChatAuthor = true + } var peerText: String? if case .savedMessagesChats = item.chatListLocation { @@ -2606,14 +2610,14 @@ public class ChatListItemNode: ItemListRevealOptionsItemNode { if let message = messages.last, let forwardInfo = message.forwardInfo, let author = forwardInfo.author { peerText = EnginePeer(author).compactDisplayTitle } - } else if !isUser { + } else if !isUser || isGuestChatAuthor { if case let .channel(peer) = peer, case .broadcast = peer.info { } else if !displayAsMessage { if let forwardInfo = message.forwardInfo, forwardInfo.flags.contains(.isImported), let authorSignature = forwardInfo.authorSignature { peerText = authorSignature } else { peerText = author.id == account.peerId ? item.presentationData.strings.DialogList_You : EnginePeer(author).displayTitle(strings: item.presentationData.strings, displayOrder: item.presentationData.nameDisplayOrder) - authorIsCurrentChat = author.id == peer.id + authorIsCurrentChat = !isGuestChatAuthor && author.id == peer.id } } } diff --git a/submodules/TelegramUI/Components/Chat/QuickShareScreen/Sources/QuickShareToastScreen.swift b/submodules/TelegramUI/Components/Chat/QuickShareScreen/Sources/QuickShareToastScreen.swift index 723007aa78..baafd5d89b 100644 --- a/submodules/TelegramUI/Components/Chat/QuickShareScreen/Sources/QuickShareToastScreen.swift +++ b/submodules/TelegramUI/Components/Chat/QuickShareScreen/Sources/QuickShareToastScreen.swift @@ -254,16 +254,19 @@ private final class QuickShareToastScreenComponent: Component { let contentSize = self.content.update( transition: transition, - component: AnyComponent(MultilineTextComponent(text: .markdown( - text: tooltipText, - attributes: MarkdownAttributes( - body: MarkdownAttributeSet(font: Font.regular(14.0), textColor: .white), - bold: MarkdownAttributeSet(font: Font.semibold(14.0), textColor: environment.theme.list.itemAccentColor.withMultiplied(hue: 0.933, saturation: 0.61, brightness: 1.0)), - link: MarkdownAttributeSet(font: Font.regular(14.0), textColor: .white), - linkAttribute: { _ in return nil }) - ))), + component: AnyComponent(MultilineTextComponent( + text: .markdown( + text: tooltipText, + attributes: MarkdownAttributes( + body: MarkdownAttributeSet(font: Font.regular(14.0), textColor: .white), + bold: MarkdownAttributeSet(font: Font.semibold(14.0), textColor: environment.theme.list.itemAccentColor.withMultiplied(hue: 0.933, saturation: 0.61, brightness: 1.0)), + link: MarkdownAttributeSet(font: Font.regular(14.0), textColor: .white), + linkAttribute: { _ in return nil }) + ), + maximumNumberOfLines: 2 + )), environment: {}, - containerSize: CGSize(width: availableContentSize.width - contentInsets.left - contentInsets.right - spacing - iconSize.width - actionButtonSize.width - 16.0 - 4.0, height: availableContentSize.height) + containerSize: CGSize(width: availableContentSize.width - contentInsets.left - contentInsets.right - spacing - iconSize.width - actionButtonSize.width - 16.0 - 8.0, height: availableContentSize.height) ) var contentHeight: CGFloat = 0.0 @@ -313,7 +316,7 @@ private final class QuickShareToastScreenComponent: Component { self.backgroundView.updateColor(color: UIColor(white: 0.0, alpha: 0.7), transition: transition.containedViewLayoutTransition) - self.backgroundView.update(size: backgroundFrame.size, cornerRadius: 14.0, transition: transition.containedViewLayoutTransition) + self.backgroundView.update(size: backgroundFrame.size, cornerRadius: backgroundFrame.height * 0.5, transition: transition.containedViewLayoutTransition) transition.setFrame(view: self.backgroundView, frame: backgroundFrame) transition.setFrame(view: self.contentView, frame: CGRect(origin: .zero, size: backgroundFrame.size)) diff --git a/submodules/WebUI/Sources/WebAppController.swift b/submodules/WebUI/Sources/WebAppController.swift index 90202b3f4c..64616b7429 100644 --- a/submodules/WebUI/Sources/WebAppController.swift +++ b/submodules/WebUI/Sources/WebAppController.swift @@ -516,7 +516,12 @@ public final class WebAppController: ViewController, AttachmentContainable { return } #endif*/ - self.webView?.bindTrustedOrigin(from: url) + + if !"".isEmpty { + self.webView?.bindTrustedOrigin(from: url) + } else { + self.webView?.setupEventProxySource() + } self.webView?.load(URLRequest(url: url)) } diff --git a/submodules/WebUI/Sources/WebAppWebView.swift b/submodules/WebUI/Sources/WebAppWebView.swift index f722ace6e7..edf115e500 100644 --- a/submodules/WebUI/Sources/WebAppWebView.swift +++ b/submodules/WebUI/Sources/WebAppWebView.swift @@ -43,7 +43,19 @@ private func jsStringLiteral(_ value: String) -> String { return "\"\"" } -private func eventProxySource(trustedOrigin: String) -> String { +private func eventProxySource() -> String { + return """ + (function() { + var TelegramWebviewProxyProto = function() {}; + TelegramWebviewProxyProto.prototype.postEvent = function(eventName, eventData) { + window.webkit.messageHandlers.performAction.postMessage({'eventName': eventName, 'eventData': eventData}); + }; + window.TelegramWebviewProxy = new TelegramWebviewProxyProto(); + })(); + """ +} + +private func securedEventProxySource(trustedOrigin: String) -> String { return """ (function() { if (window.location.origin !== \(jsStringLiteral(trustedOrigin))) { @@ -202,6 +214,7 @@ final class WebAppWebView: WKWebView { print() } + var useSecuredEventProxy = true func bindTrustedOrigin(from url: URL) { guard self.trustedOrigin == nil else { return @@ -212,7 +225,14 @@ final class WebAppWebView: WKWebView { self.trustedOrigin = origin - let eventProxyScript = WKUserScript(source: eventProxySource(trustedOrigin: origin), injectionTime: .atDocumentStart, forMainFrameOnly: true) + let eventProxyScript = WKUserScript(source: securedEventProxySource(trustedOrigin: origin), injectionTime: .atDocumentStart, forMainFrameOnly: true) + self.configuration.userContentController.addUserScript(eventProxyScript) + } + + func setupEventProxySource() { + self.useSecuredEventProxy = false + + let eventProxyScript = WKUserScript(source: eventProxySource(), injectionTime: .atDocumentStart, forMainFrameOnly: true) self.configuration.userContentController.addUserScript(eventProxyScript) } @@ -220,6 +240,9 @@ final class WebAppWebView: WKWebView { guard message.frameInfo.isMainFrame else { return false } + if !self.useSecuredEventProxy { + return true + } guard let trustedOrigin = self.trustedOrigin else { return false } From 9c3cab27e148e9763bd7891fc3113100233d77b0 Mon Sep 17 00:00:00 2001 From: Ilya Laktyushin Date: Thu, 30 Apr 2026 13:14:56 +0200 Subject: [PATCH 2/5] Fix time-limited poll closing --- .../TelegramCore/Sources/TelegramEngine/Messages/Polls.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/submodules/TelegramCore/Sources/TelegramEngine/Messages/Polls.swift b/submodules/TelegramCore/Sources/TelegramEngine/Messages/Polls.swift index 355be9c09f..5ec6539f0e 100644 --- a/submodules/TelegramCore/Sources/TelegramEngine/Messages/Polls.swift +++ b/submodules/TelegramCore/Sources/TelegramEngine/Messages/Polls.swift @@ -266,7 +266,7 @@ func _internal_requestClosePoll(postbox: Postbox, network: Network, stateManager pollMediaFlags |= 1 << 1 } - return network.request(Api.functions.messages.editMessage(flags: flags, peer: inputPeer, id: messageId.id, message: nil, media: .inputMediaPoll(.init(flags: pollMediaFlags, poll: .poll(.init(id: poll.pollId.id, flags: pollFlags, question: .textWithEntities(.init(text: poll.text, entities: apiEntitiesFromMessageTextEntities(poll.textEntities, associatedPeers: SimpleDictionary()))), answers: poll.options.map({ $0.apiOption }), closePeriod: poll.deadlineTimeout, closeDate: nil, countriesIso2: poll.countries, hash: 0)), correctAnswers: correctAnswersIndices, attachedMedia: nil, solution: mappedSolution, solutionEntities: mappedSolutionEntities, solutionMedia: nil)), replyMarkup: nil, entities: nil, scheduleDate: nil, scheduleRepeatPeriod: nil, quickReplyShortcutId: nil)) + return network.request(Api.functions.messages.editMessage(flags: flags, peer: inputPeer, id: messageId.id, message: nil, media: .inputMediaPoll(.init(flags: pollMediaFlags, poll: .poll(.init(id: poll.pollId.id, flags: pollFlags, question: .textWithEntities(.init(text: poll.text, entities: apiEntitiesFromMessageTextEntities(poll.textEntities, associatedPeers: SimpleDictionary()))), answers: poll.options.map({ $0.apiOption }), closePeriod: poll.deadlineTimeout, closeDate: poll.deadlineDate, countriesIso2: poll.countries, hash: 0)), correctAnswers: correctAnswersIndices, attachedMedia: nil, solution: mappedSolution, solutionEntities: mappedSolutionEntities, solutionMedia: nil)), replyMarkup: nil, entities: nil, scheduleDate: nil, scheduleRepeatPeriod: nil, quickReplyShortcutId: nil)) |> map(Optional.init) |> `catch` { _ -> Signal in return .single(nil) From 0664197b5324367b6385b107b0da3c1692acd97b Mon Sep 17 00:00:00 2001 From: Ilya Laktyushin Date: Thu, 30 Apr 2026 15:43:05 +0200 Subject: [PATCH 3/5] Poll improvements --- .../Sources/BrowserBookmarksScreen.swift | 5 +- .../TelegramEngine/Messages/Polls.swift | 6 +- .../ChatMessagePollBubbleContentNode.swift | 44 +------------ .../ChatRecentActionsControllerNode.swift | 5 +- .../ChatSendAudioMessageContextPreview.swift | 5 +- .../Sources/ChatControllerInteraction.swift | 3 + .../Sources/PeerInfoScreen.swift | 5 +- .../Sources/Chat/ChatControllerToasts.swift | 66 +++++++++++++++++++ .../TelegramUI/Sources/ChatController.swift | 15 ++++- .../OverlayAudioPlayerControllerNode.swift | 5 +- .../Sources/SharedAccountContext.swift | 5 +- 11 files changed, 112 insertions(+), 52 deletions(-) diff --git a/submodules/BrowserUI/Sources/BrowserBookmarksScreen.swift b/submodules/BrowserUI/Sources/BrowserBookmarksScreen.swift index d72f35d457..05bdf6b4b2 100644 --- a/submodules/BrowserUI/Sources/BrowserBookmarksScreen.swift +++ b/submodules/BrowserUI/Sources/BrowserBookmarksScreen.swift @@ -189,7 +189,10 @@ public final class BrowserBookmarksScreen: ViewController { }, requestToggleTodoMessageItem: { _, _, _ in }, displayTodoToggleUnavailable: { _ in }, openStarsPurchase: { _ in - }, openRankInfo: { _, _, _ in }, openSetPeerAvatar: {}, automaticMediaDownloadSettings: MediaAutoDownloadSettings.defaultSettings, pollActionState: ChatInterfacePollActionState(), stickerSettings: ChatInterfaceStickerSettings(), presentationContext: ChatPresentationContext(context: context, backgroundNode: nil)) + }, openRankInfo: { _, _, _ in + }, openSetPeerAvatar: { + }, displayPollRestrictedToast: { _ in + }, automaticMediaDownloadSettings: MediaAutoDownloadSettings.defaultSettings, pollActionState: ChatInterfacePollActionState(), stickerSettings: ChatInterfaceStickerSettings(), presentationContext: ChatPresentationContext(context: context, backgroundNode: nil)) let tagMask: MessageTags = .webPage diff --git a/submodules/TelegramCore/Sources/TelegramEngine/Messages/Polls.swift b/submodules/TelegramCore/Sources/TelegramEngine/Messages/Polls.swift index 5ec6539f0e..a1a87ca53f 100644 --- a/submodules/TelegramCore/Sources/TelegramEngine/Messages/Polls.swift +++ b/submodules/TelegramCore/Sources/TelegramEngine/Messages/Polls.swift @@ -31,6 +31,7 @@ func pollCloudMediaToInputMedia(_ media: Media) -> Api.InputMedia? { public enum RequestMessageSelectPollOptionError { case generic + case restrictedToSubscribers } func _internal_requestMessageSelectPollOption(account: Account, messageId: MessageId, opaqueIdentifiers: [Data]) -> Signal { @@ -40,7 +41,10 @@ func _internal_requestMessageSelectPollOption(account: Account, messageId: Messa |> mapToSignal { peer in if let inputPeer = apiInputPeer(peer) { return account.network.request(Api.functions.messages.sendVote(peer: inputPeer, msgId: messageId.id, options: opaqueIdentifiers.map { Buffer(data: $0) })) - |> mapError { _ -> RequestMessageSelectPollOptionError in + |> mapError { error -> RequestMessageSelectPollOptionError in + if error.errorDescription == "POLL_MEMBER_RESTRICTED" { + return .restrictedToSubscribers + } return .generic } |> mapToSignal { result -> Signal in diff --git a/submodules/TelegramUI/Components/Chat/ChatMessagePollBubbleContentNode/Sources/ChatMessagePollBubbleContentNode.swift b/submodules/TelegramUI/Components/Chat/ChatMessagePollBubbleContentNode/Sources/ChatMessagePollBubbleContentNode.swift index 873a2a6dab..3ef4bd9cfc 100644 --- a/submodules/TelegramUI/Components/Chat/ChatMessagePollBubbleContentNode/Sources/ChatMessagePollBubbleContentNode.swift +++ b/submodules/TelegramUI/Components/Chat/ChatMessagePollBubbleContentNode/Sources/ChatMessagePollBubbleContentNode.swift @@ -2918,49 +2918,7 @@ public class ChatMessagePollBubbleContentNode: ChatMessageBubbleContentNode { if case .public = poll.publicity { item.controllerInteraction.openMessagePollResults(item.message.id, option.opaqueIdentifier) } else if isRestricted { - let text: String - - let peerName = item.message.peers[item.message.id.peerId].flatMap(EnginePeer.init)?.compactDisplayTitle ?? "" - if !poll.countries.isEmpty { - let locale = localeWithStrings(item.presentationData.strings) - let countryNames = poll.countries.map { id in - if id == "FT" { - return "Fragment" - } else if let countryName = locale.localizedString(forRegionCode: id) { - return countryName - } else { - return id - } - } - var countries: String = "" - if countryNames.count == 1, let country = countryNames.first { - countries = "**\(country)**" - } else { - for i in 0 ..< countryNames.count { - countries.append("**\(countryNames[i])**") - if i == countryNames.count - 2 { - countries.append(item.presentationData.strings.Chat_Poll_Restriction_Country_CountriesLastDelimiter) - } else if i < countryNames.count - 2 { - countries.append(item.presentationData.strings.Chat_Poll_Restriction_Country_CountriesDelimiter) - } - } - } - if poll.restrictToSubscribers { - text = item.presentationData.strings.Chat_Poll_Restriction_SubscribersCountry(peerName, countries).string - } else { - text = item.presentationData.strings.Chat_Poll_Restriction_Country(countries).string - } - } else { - text = item.presentationData.strings.Chat_Poll_Restriction_Subscribers(peerName).string - } - let controller = UndoOverlayController( - presentationData: item.context.sharedContext.currentPresentationData.with { $0 }, - content: .banned(text: text), - elevatedLayout: true, - position: .bottom, - action: { _ in return true } - ) - item.controllerInteraction.presentController(controller, nil) + item.controllerInteraction.displayPollRestrictedToast(item.message.id) } } } diff --git a/submodules/TelegramUI/Components/Chat/ChatRecentActionsController/Sources/ChatRecentActionsControllerNode.swift b/submodules/TelegramUI/Components/Chat/ChatRecentActionsController/Sources/ChatRecentActionsControllerNode.swift index fa8ecc35fb..604f741897 100644 --- a/submodules/TelegramUI/Components/Chat/ChatRecentActionsController/Sources/ChatRecentActionsControllerNode.swift +++ b/submodules/TelegramUI/Components/Chat/ChatRecentActionsController/Sources/ChatRecentActionsControllerNode.swift @@ -666,7 +666,10 @@ final class ChatRecentActionsControllerNode: ViewControllerTracingNode { }, requestToggleTodoMessageItem: { _, _, _ in }, displayTodoToggleUnavailable: { _ in }, openStarsPurchase: { _ in - }, openRankInfo: { _, _, _ in }, openSetPeerAvatar: {}, automaticMediaDownloadSettings: self.automaticMediaDownloadSettings, + }, openRankInfo: { _, _, _ in + }, openSetPeerAvatar: { + }, displayPollRestrictedToast: { _ in + }, automaticMediaDownloadSettings: self.automaticMediaDownloadSettings, pollActionState: ChatInterfacePollActionState(), stickerSettings: ChatInterfaceStickerSettings(), presentationContext: ChatPresentationContext(context: context, backgroundNode: self.backgroundNode)) self.controllerInteraction = controllerInteraction diff --git a/submodules/TelegramUI/Components/Chat/ChatSendAudioMessageContextPreview/Sources/ChatSendAudioMessageContextPreview.swift b/submodules/TelegramUI/Components/Chat/ChatSendAudioMessageContextPreview/Sources/ChatSendAudioMessageContextPreview.swift index 7253069a2e..1ebced67c2 100644 --- a/submodules/TelegramUI/Components/Chat/ChatSendAudioMessageContextPreview/Sources/ChatSendAudioMessageContextPreview.swift +++ b/submodules/TelegramUI/Components/Chat/ChatSendAudioMessageContextPreview/Sources/ChatSendAudioMessageContextPreview.swift @@ -513,7 +513,10 @@ public final class ChatSendGroupMediaMessageContextPreview: UIView, ChatSendMess }, requestToggleTodoMessageItem: { _, _, _ in }, displayTodoToggleUnavailable: { _ in }, openStarsPurchase: { _ in - }, openRankInfo: { _, _, _ in }, openSetPeerAvatar: {}, automaticMediaDownloadSettings: MediaAutoDownloadSettings.defaultSettings, + }, openRankInfo: { _, _, _ in + }, openSetPeerAvatar: { + }, displayPollRestrictedToast: { _ in + }, automaticMediaDownloadSettings: MediaAutoDownloadSettings.defaultSettings, pollActionState: ChatInterfacePollActionState(), stickerSettings: ChatInterfaceStickerSettings(), presentationContext: ChatPresentationContext(context: self.context, backgroundNode: self.wallpaperBackgroundNode)) let associatedData = ChatMessageItemAssociatedData( diff --git a/submodules/TelegramUI/Components/ChatControllerInteraction/Sources/ChatControllerInteraction.swift b/submodules/TelegramUI/Components/ChatControllerInteraction/Sources/ChatControllerInteraction.swift index 9477b10bf2..fc04218bf9 100644 --- a/submodules/TelegramUI/Components/ChatControllerInteraction/Sources/ChatControllerInteraction.swift +++ b/submodules/TelegramUI/Components/ChatControllerInteraction/Sources/ChatControllerInteraction.swift @@ -303,6 +303,7 @@ public final class ChatControllerInteraction: ChatControllerInteractionProtocol public let openStarsPurchase: (Int64?) -> Void public let openRankInfo: (EnginePeer, ChatRankInfoScreenRole, String) -> Void public let openSetPeerAvatar: () -> Void + public let displayPollRestrictedToast: (EngineMessage.Id) -> Void public var canPlayMedia: Bool = false public var hiddenMedia: [MessageId: [Media]] = [:] @@ -480,6 +481,7 @@ public final class ChatControllerInteraction: ChatControllerInteractionProtocol openStarsPurchase: @escaping (Int64?) -> Void, openRankInfo: @escaping (EnginePeer, ChatRankInfoScreenRole, String) -> Void, openSetPeerAvatar: @escaping () -> Void, + displayPollRestrictedToast: @escaping (EngineMessage.Id) -> Void, automaticMediaDownloadSettings: MediaAutoDownloadSettings, pollActionState: ChatInterfacePollActionState, stickerSettings: ChatInterfaceStickerSettings, @@ -610,6 +612,7 @@ public final class ChatControllerInteraction: ChatControllerInteractionProtocol self.openStarsPurchase = openStarsPurchase self.openRankInfo = openRankInfo self.openSetPeerAvatar = openSetPeerAvatar + self.displayPollRestrictedToast = displayPollRestrictedToast self.automaticMediaDownloadSettings = automaticMediaDownloadSettings diff --git a/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/PeerInfoScreen.swift b/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/PeerInfoScreen.swift index 2e441623ba..4dfd477063 100644 --- a/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/PeerInfoScreen.swift +++ b/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/PeerInfoScreen.swift @@ -1284,7 +1284,10 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, PeerInfoScreenNodePro }, requestToggleTodoMessageItem: { _, _, _ in }, displayTodoToggleUnavailable: { _ in }, openStarsPurchase: { _ in - }, openRankInfo: { _, _, _ in }, openSetPeerAvatar: {}, automaticMediaDownloadSettings: MediaAutoDownloadSettings.defaultSettings, + }, openRankInfo: { _, _, _ in + }, openSetPeerAvatar: { + }, displayPollRestrictedToast: { _ in + }, automaticMediaDownloadSettings: MediaAutoDownloadSettings.defaultSettings, pollActionState: ChatInterfacePollActionState(), stickerSettings: ChatInterfaceStickerSettings(), presentationContext: ChatPresentationContext(context: context, backgroundNode: nil)) self.hiddenMediaDisposable = context.sharedContext.mediaManager.galleryHiddenMediaManager.hiddenIds().startStrict(next: { [weak self] ids in guard let strongSelf = self else { diff --git a/submodules/TelegramUI/Sources/Chat/ChatControllerToasts.swift b/submodules/TelegramUI/Sources/Chat/ChatControllerToasts.swift index 754f6996c2..8e37932d93 100644 --- a/submodules/TelegramUI/Sources/Chat/ChatControllerToasts.swift +++ b/submodules/TelegramUI/Sources/Chat/ChatControllerToasts.swift @@ -8,6 +8,7 @@ import Display import UndoUI import AccountContext import ChatControllerInteraction +import TelegramStringFormatting extension ChatControllerImpl { func displaySendReactionRestrictedToast() { @@ -20,6 +21,71 @@ extension ChatControllerImpl { action: { _ in return true } ), nil) } + + func displayPollRestrictedToast(messageId: EngineMessage.Id) { + let _ = (self.context.engine.data.get( + TelegramEngine.EngineData.Item.Messages.Message(id: messageId), + TelegramEngine.EngineData.Item.Peer.Peer(id: messageId.peerId) + ) + |> deliverOnMainQueue).startStandalone(next: { [weak self] message, peer in + guard let self, let message, let peer else { + return + } + let peerName = peer.compactDisplayTitle + guard let poll = message.media.first(where: { $0 is TelegramMediaPoll }) as? TelegramMediaPoll else { + return + } + + var accountCountry = "" + if let data = self.context.currentAppConfiguration.with({ $0 }).data, let country = data["phone_country_iso2"] as? String { + accountCountry = (country) + } + var text = "" + if !poll.countries.isEmpty && !poll.countries.contains(accountCountry) { + let locale = localeWithStrings(self.presentationData.strings) + let countryNames = poll.countries.map { id in + if id == "FT" { + return "Fragment" + } else if let countryName = locale.localizedString(forRegionCode: id) { + return countryName + } else { + return id + } + } + var countries: String = "" + if countryNames.count == 1, let country = countryNames.first { + countries = "**\(country)**" + } else { + for i in 0 ..< countryNames.count { + countries.append("**\(countryNames[i])**") + if i == countryNames.count - 2 { + countries.append(self.presentationData.strings.Chat_Poll_Restriction_Country_CountriesLastDelimiter) + } else if i < countryNames.count - 2 { + countries.append(self.presentationData.strings.Chat_Poll_Restriction_Country_CountriesDelimiter) + } + } + } + if poll.restrictToSubscribers { + text = self.presentationData.strings.Chat_Poll_Restriction_SubscribersCountry(peerName, countries).string + } else { + text = self.presentationData.strings.Chat_Poll_Restriction_Country(countries).string + } + } else { + if case let .channel(channel) = peer, case .member = channel.participationStatus { + text = self.presentationData.strings.Chat_Poll_Restriction_Subscribers_TimeLimit + } else { + text = self.presentationData.strings.Chat_Poll_Restriction_Subscribers(peerName).string + } + } + let controller = UndoOverlayController( + presentationData: self.presentationData, + content: .banned(text: text), + position: .bottom, + action: { _ in return true } + ) + self.controllerInteraction?.presentControllerInCurrent(controller, nil) + }) + } func displayPostedScheduledMessagesToast(ids: [EngineMessage.Id]) { let timestamp = CFAbsoluteTimeGetCurrent() diff --git a/submodules/TelegramUI/Sources/ChatController.swift b/submodules/TelegramUI/Sources/ChatController.swift index f845e2024d..f48dc84ed4 100644 --- a/submodules/TelegramUI/Sources/ChatController.swift +++ b/submodules/TelegramUI/Sources/ChatController.swift @@ -3896,20 +3896,26 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G ) strongSelf.present(controller, in: .current) } - }, error: { _ in + }, error: { error in guard let strongSelf = self, let controllerInteraction = strongSelf.controllerInteraction else { return } if controllerInteraction.pollActionState.pollMessageIdsInProgress.removeValue(forKey: id) != nil { strongSelf.chatDisplayNode.historyNode.requestMessageUpdate(id) } + + switch error { + case .restrictedToSubscribers: + strongSelf.displayPollRestrictedToast(messageId: id) + default: + break + } }, completed: { guard let strongSelf = self, let controllerInteraction = strongSelf.controllerInteraction else { return } if controllerInteraction.pollActionState.pollMessageIdsInProgress.removeValue(forKey: id) != nil { Queue.mainQueue().after(1.0, { - strongSelf.chatDisplayNode.historyNode.requestMessageUpdate(id) }) } @@ -5664,6 +5670,11 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G return } self.interfaceInteraction?.openSetPeerAvatar() + }, displayPollRestrictedToast: { [weak self] messageId in + guard let self else { + return + } + self.displayPollRestrictedToast(messageId: messageId) }, automaticMediaDownloadSettings: self.automaticMediaDownloadSettings, pollActionState: ChatInterfacePollActionState(), stickerSettings: self.stickerSettings, presentationContext: ChatPresentationContext(context: context, backgroundNode: self.chatBackgroundNode)) controllerInteraction.enableFullTranslucency = context.sharedContext.energyUsageSettings.fullTranslucency diff --git a/submodules/TelegramUI/Sources/OverlayAudioPlayerControllerNode.swift b/submodules/TelegramUI/Sources/OverlayAudioPlayerControllerNode.swift index bb46df404b..fb2f379047 100644 --- a/submodules/TelegramUI/Sources/OverlayAudioPlayerControllerNode.swift +++ b/submodules/TelegramUI/Sources/OverlayAudioPlayerControllerNode.swift @@ -258,7 +258,10 @@ final class OverlayAudioPlayerControllerNode: ViewControllerTracingNode, ASGestu }, requestToggleTodoMessageItem: { _, _, _ in }, displayTodoToggleUnavailable: { _ in }, openStarsPurchase: { _ in - }, openRankInfo: { _, _, _ in }, openSetPeerAvatar: {}, automaticMediaDownloadSettings: MediaAutoDownloadSettings.defaultSettings, pollActionState: ChatInterfacePollActionState(), stickerSettings: ChatInterfaceStickerSettings(), presentationContext: ChatPresentationContext(context: context, backgroundNode: nil)) + }, openRankInfo: { _, _, _ in + }, openSetPeerAvatar: { + }, displayPollRestrictedToast: { _ in + }, automaticMediaDownloadSettings: MediaAutoDownloadSettings.defaultSettings, pollActionState: ChatInterfacePollActionState(), stickerSettings: ChatInterfaceStickerSettings(), presentationContext: ChatPresentationContext(context: context, backgroundNode: nil)) self.dimNode = ASDisplayNode() self.dimNode.backgroundColor = UIColor(white: 0.0, alpha: 0.5) diff --git a/submodules/TelegramUI/Sources/SharedAccountContext.swift b/submodules/TelegramUI/Sources/SharedAccountContext.swift index 2e9920d1fa..b960866103 100644 --- a/submodules/TelegramUI/Sources/SharedAccountContext.swift +++ b/submodules/TelegramUI/Sources/SharedAccountContext.swift @@ -2581,7 +2581,10 @@ public final class SharedAccountContextImpl: SharedAccountContext { openStarsPurchase: { _ in }, openRankInfo: { _, _, _ in - }, openSetPeerAvatar: { + }, + openSetPeerAvatar: { + }, + displayPollRestrictedToast: { _ in }, automaticMediaDownloadSettings: MediaAutoDownloadSettings.defaultSettings, pollActionState: ChatInterfacePollActionState(), From 9b8abdb5eec21dba628085e7409e0d1c56084958 Mon Sep 17 00:00:00 2001 From: Ilya Laktyushin Date: Thu, 30 Apr 2026 16:51:22 +0200 Subject: [PATCH 4/5] Fix --- submodules/WebUI/Sources/WebAppWebView.swift | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/submodules/WebUI/Sources/WebAppWebView.swift b/submodules/WebUI/Sources/WebAppWebView.swift index edf115e500..acebade7a2 100644 --- a/submodules/WebUI/Sources/WebAppWebView.swift +++ b/submodules/WebUI/Sources/WebAppWebView.swift @@ -291,8 +291,10 @@ final class WebAppWebView: WKWebView { } func sendEvent(name: String, data: String?) { - guard let trustedOrigin = self.trustedOrigin, self.origin == trustedOrigin else { - return + if self.useSecuredEventProxy { + guard let trustedOrigin = self.trustedOrigin, self.origin == trustedOrigin else { + return + } } let script = "window.TelegramGameProxy && window.TelegramGameProxy.receiveEvent && window.TelegramGameProxy.receiveEvent(\"\(name)\", \(data ?? "null"))" self.evaluateJavaScript(script, completionHandler: { _, _ in From ffd82647ee97c68e4da4802fe9717ccccd8105c9 Mon Sep 17 00:00:00 2001 From: Ilya Laktyushin Date: Fri, 1 May 2026 15:29:18 +0200 Subject: [PATCH 5/5] Various fixes --- .../AuthorizationSequencePaymentScreen.swift | 35 ++++++++++--------- .../Sources/InAppPurchaseManager.swift | 1 + .../CountriesMultiselectionScreen.swift | 3 +- 3 files changed, 21 insertions(+), 18 deletions(-) diff --git a/submodules/AuthorizationUI/Sources/AuthorizationSequencePaymentScreen.swift b/submodules/AuthorizationUI/Sources/AuthorizationSequencePaymentScreen.swift index 8658893b75..ddb76da69a 100644 --- a/submodules/AuthorizationUI/Sources/AuthorizationSequencePaymentScreen.swift +++ b/submodules/AuthorizationUI/Sources/AuthorizationSequencePaymentScreen.swift @@ -28,6 +28,7 @@ import PhoneNumberFormat import PlainButtonComponent import StoreKit import DeviceModel +import GlassBarButtonComponent final class AuthorizationSequencePaymentScreenComponent: Component { typealias EnvironmentType = ViewControllerComponentContainer.Environment @@ -254,25 +255,27 @@ final class AuthorizationSequencePaymentScreenComponent: Component { let helpButtonSize = self.helpButton.update( transition: transition, - component: AnyComponent(PlainButtonComponent( - content: AnyComponent(MultilineTextComponent( - text: .plain(NSAttributedString(string: environment.strings.Login_PhoneNumberHelp, font: Font.regular(17.0), textColor: environment.theme.list.itemAccentColor)) - )), - minSize: CGSize(width: 0.0, height: 44.0), - contentInsets: UIEdgeInsets(top: 0.0, left: 8.0, bottom: 0.0, right: 8.0), - action: { [weak self] in - guard let self else { - return + component: AnyComponent( + GlassBarButtonComponent( + size: nil, + backgroundColor: nil, + isDark: environment.theme.overallDarkAppearance, + state: .glass, + component: AnyComponentWithIdentity(id: "label", component: AnyComponent(MultilineTextComponent( + text: .plain(NSAttributedString(string: environment.strings.Login_PhoneNumberHelp, font: Font.regular(17.0), textColor: environment.theme.chat.inputPanel.panelControlColor)) + ))), + action: { [weak self] _ in + guard let self else { + return + } + self.displaySendEmail(error: nil, errorCode: nil) } - self.displaySendEmail(error: nil, errorCode: nil) - }, - animateScale: false, - animateContents: false - )), + ) + ), environment: {}, - containerSize: CGSize(width: 200.0, height: 100.0) + containerSize: CGSize(width: 200.0, height: 44.0) ) - let helpButtonFrame = CGRect(origin: CGPoint(x: availableSize.width - 8.0 - helpButtonSize.width, y: environment.statusBarHeight), size: helpButtonSize) + let helpButtonFrame = CGRect(origin: CGPoint(x: availableSize.width - 16.0 - helpButtonSize.width, y: environment.navigationHeight - helpButtonSize.height - 6.0), size: helpButtonSize) if let helpButtonView = self.helpButton.view { if helpButtonView.superview == nil { self.addSubview(helpButtonView) diff --git a/submodules/InAppPurchaseManager/Sources/InAppPurchaseManager.swift b/submodules/InAppPurchaseManager/Sources/InAppPurchaseManager.swift index 74f3824243..23ea3eb290 100644 --- a/submodules/InAppPurchaseManager/Sources/InAppPurchaseManager.swift +++ b/submodules/InAppPurchaseManager/Sources/InAppPurchaseManager.swift @@ -28,6 +28,7 @@ private let productIdentifiers = [ "org.telegram.telegramPremium.twelveMonths.code_x10", "org.telegram.telegramPremium.oneWeek.auth", + "org.telegram.telegramPremium.threeDays.auth", "org.telegram.telegramStars.topup.x15", "org.telegram.telegramStars.topup.x25", diff --git a/submodules/TelegramUI/Components/ShareWithPeersScreen/Sources/CountriesMultiselectionScreen.swift b/submodules/TelegramUI/Components/ShareWithPeersScreen/Sources/CountriesMultiselectionScreen.swift index 3c3ad2573a..20f40edbe2 100644 --- a/submodules/TelegramUI/Components/ShareWithPeersScreen/Sources/CountriesMultiselectionScreen.swift +++ b/submodules/TelegramUI/Components/ShareWithPeersScreen/Sources/CountriesMultiselectionScreen.swift @@ -464,8 +464,7 @@ final class CountriesMultiselectionScreenComponent: Component { update() } - let limit = component.context.userLimits.maxGiveawayCountriesCount - if self.selectedCountries.count >= limit, index == nil { + if let limit = component.stateContext.maxCount, self.selectedCountries.count >= limit, index == nil { self.hapticFeedback.error() let presentationData = component.context.sharedContext.currentPresentationData.with { $0 }