From 6795603c4e1189d1b2a326eac36dfa9d34eeae3c Mon Sep 17 00:00:00 2001 From: Ilya Laktyushin Date: Thu, 21 Dec 2023 04:04:17 +0400 Subject: [PATCH] Add support for multiple users selection in bots peer requests --- .../Telegram-iOS/en.lproj/Localizable.strings | 6 + .../ContactMultiselectionController.swift | 1 + submodules/TelegramApi/Sources/Api0.swift | 7 +- submodules/TelegramApi/Sources/Api10.swift | 12 ++ submodules/TelegramApi/Sources/Api11.swift | 18 ++- submodules/TelegramApi/Sources/Api12.swift | 24 +-- submodules/TelegramApi/Sources/Api32.swift | 27 +++- .../ReplyMarkupMessageAttribute.swift | 4 +- .../ApiUtils/StoreMessage_Telegram.swift | 4 +- .../ApiUtils/TelegramMediaAction.swift | 4 +- .../Sources/ApiUtils/TelegramMediaFile.swift | 2 + .../Sources/State/Serialization.swift | 2 +- ...SyncCore_ReplyMarkupMessageAttribute.swift | 7 +- .../SyncCore_TelegramMediaAction.swift | 16 +- .../TelegramEngine/Peers/AddPeerMember.swift | 25 ++-- .../Peers/TelegramEnginePeers.swift | 4 +- .../Sources/ServiceMessageStrings.swift | 15 +- .../Sources/ChatButtonKeyboardInputNode.swift | 4 +- .../ChatRecentActionsControllerNode.swift | 2 +- .../Sources/ChatControllerInteraction.swift | 4 +- .../Sources/PeerInfoScreen.swift | 2 +- .../TelegramUI/Sources/ChatController.swift | 139 ++++++++++++------ .../ContactMultiselectionController.swift | 23 ++- .../ContactMultiselectionControllerNode.swift | 9 +- .../OverlayAudioPlayerControllerNode.swift | 2 +- .../Sources/SharedAccountContext.swift | 2 +- 26 files changed, 244 insertions(+), 121 deletions(-) diff --git a/Telegram/Telegram-iOS/en.lproj/Localizable.strings b/Telegram/Telegram-iOS/en.lproj/Localizable.strings index 8057a5b6517..d0b533baffc 100644 --- a/Telegram/Telegram-iOS/en.lproj/Localizable.strings +++ b/Telegram/Telegram-iOS/en.lproj/Localizable.strings @@ -8719,6 +8719,7 @@ Sorry for the inconvenience."; "CreateGroup.PublicLinkInfo" = "You can use **a-z**, **0-9** and underscores. Minimum length is **5** characters."; "Notification.RequestedPeer" = "You shared %1$@ with %2$@."; +"Notification.RequestedPeerMultiple" = "You shared %1$@ with %2$@."; "Conversation.ViewInChannel" = "View in Channel"; @@ -10829,3 +10830,8 @@ Sorry for the inconvenience."; "Channel.Info.BoostLevelPlusBadge" = "Level %@+"; "Channel.Info.AppearanceItem" = "Appearance"; + +"RequestPeer.SelectUsers" = "Choose Users"; +"RequestPeer.SelectUsers.SearchPlaceholder" = "Search"; +"RequestPeer.ReachedMaximum_1" = "You can select up to %@ user."; +"RequestPeer.ReachedMaximum_any" = "You can select up to %@ users."; diff --git a/submodules/AccountContext/Sources/ContactMultiselectionController.swift b/submodules/AccountContext/Sources/ContactMultiselectionController.swift index 84ac96014b7..28b68d96937 100644 --- a/submodules/AccountContext/Sources/ContactMultiselectionController.swift +++ b/submodules/AccountContext/Sources/ContactMultiselectionController.swift @@ -70,6 +70,7 @@ public enum ContactMultiselectionControllerMode { case channelCreation case chatSelection(ChatSelection) case premiumGifting + case requestedUsersSelection } public enum ContactListFilter { diff --git a/submodules/TelegramApi/Sources/Api0.swift b/submodules/TelegramApi/Sources/Api0.swift index 5366d566a0e..d3776d015d4 100644 --- a/submodules/TelegramApi/Sources/Api0.swift +++ b/submodules/TelegramApi/Sources/Api0.swift @@ -404,6 +404,7 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = { dict[42402760] = { return Api.InputStickerSet.parse_inputStickerSetAnimatedEmoji($0) } dict[215889721] = { return Api.InputStickerSet.parse_inputStickerSetAnimatedEmojiAnimations($0) } dict[-427863538] = { return Api.InputStickerSet.parse_inputStickerSetDice($0) } + dict[1232373075] = { return Api.InputStickerSet.parse_inputStickerSetEmojiChannelDefaultStatuses($0) } dict[701560302] = { return Api.InputStickerSet.parse_inputStickerSetEmojiDefaultStatuses($0) } dict[1153562857] = { return Api.InputStickerSet.parse_inputStickerSetEmojiDefaultTopicIcons($0) } dict[80008398] = { return Api.InputStickerSet.parse_inputStickerSetEmojiGenericAnimations($0) } @@ -447,7 +448,7 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = { dict[901503851] = { return Api.KeyboardButton.parse_keyboardButtonCallback($0) } dict[1358175439] = { return Api.KeyboardButton.parse_keyboardButtonGame($0) } dict[-59151553] = { return Api.KeyboardButton.parse_keyboardButtonRequestGeoLocation($0) } - dict[218842764] = { return Api.KeyboardButton.parse_keyboardButtonRequestPeer($0) } + dict[1406648280] = { return Api.KeyboardButton.parse_keyboardButtonRequestPeer($0) } dict[-1318425559] = { return Api.KeyboardButton.parse_keyboardButtonRequestPhone($0) } dict[-1144565411] = { return Api.KeyboardButton.parse_keyboardButtonRequestPoll($0) } dict[-1598009252] = { return Api.KeyboardButton.parse_keyboardButtonSimpleWebView($0) } @@ -503,7 +504,7 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = { dict[-1892568281] = { return Api.MessageAction.parse_messageActionPaymentSentMe($0) } dict[-2132731265] = { return Api.MessageAction.parse_messageActionPhoneCall($0) } dict[-1799538451] = { return Api.MessageAction.parse_messageActionPinMessage($0) } - dict[-25742243] = { return Api.MessageAction.parse_messageActionRequestedPeer($0) } + dict[827428507] = { return Api.MessageAction.parse_messageActionRequestedPeer($0) } dict[1200788123] = { return Api.MessageAction.parse_messageActionScreenshotTaken($0) } dict[-648257196] = { return Api.MessageAction.parse_messageActionSecureValuesSent($0) } dict[455635795] = { return Api.MessageAction.parse_messageActionSecureValuesSentMe($0) } @@ -1262,7 +1263,7 @@ public extension Api { return parser(reader) } else { - telegramApiLog("Type constructor \(String(UInt32(bitPattern: signature), radix: 16, uppercase: false)) not found") + telegramApiLog("Type constructor \(String(signature, radix: 16, uppercase: false)) not found") return nil } } diff --git a/submodules/TelegramApi/Sources/Api10.swift b/submodules/TelegramApi/Sources/Api10.swift index a118bfc4c2d..1335731228f 100644 --- a/submodules/TelegramApi/Sources/Api10.swift +++ b/submodules/TelegramApi/Sources/Api10.swift @@ -325,6 +325,7 @@ public extension Api { case inputStickerSetAnimatedEmoji case inputStickerSetAnimatedEmojiAnimations case inputStickerSetDice(emoticon: String) + case inputStickerSetEmojiChannelDefaultStatuses case inputStickerSetEmojiDefaultStatuses case inputStickerSetEmojiDefaultTopicIcons case inputStickerSetEmojiGenericAnimations @@ -352,6 +353,12 @@ public extension Api { buffer.appendInt32(-427863538) } serializeString(emoticon, buffer: buffer, boxed: false) + break + case .inputStickerSetEmojiChannelDefaultStatuses: + if boxed { + buffer.appendInt32(1232373075) + } + break case .inputStickerSetEmojiDefaultStatuses: if boxed { @@ -407,6 +414,8 @@ public extension Api { return ("inputStickerSetAnimatedEmojiAnimations", []) case .inputStickerSetDice(let emoticon): return ("inputStickerSetDice", [("emoticon", emoticon as Any)]) + case .inputStickerSetEmojiChannelDefaultStatuses: + return ("inputStickerSetEmojiChannelDefaultStatuses", []) case .inputStickerSetEmojiDefaultStatuses: return ("inputStickerSetEmojiDefaultStatuses", []) case .inputStickerSetEmojiDefaultTopicIcons: @@ -441,6 +450,9 @@ public extension Api { return nil } } + public static func parse_inputStickerSetEmojiChannelDefaultStatuses(_ reader: BufferReader) -> InputStickerSet? { + return Api.InputStickerSet.inputStickerSetEmojiChannelDefaultStatuses + } public static func parse_inputStickerSetEmojiDefaultStatuses(_ reader: BufferReader) -> InputStickerSet? { return Api.InputStickerSet.inputStickerSetEmojiDefaultStatuses } diff --git a/submodules/TelegramApi/Sources/Api11.swift b/submodules/TelegramApi/Sources/Api11.swift index daac038500f..666ea7ff21c 100644 --- a/submodules/TelegramApi/Sources/Api11.swift +++ b/submodules/TelegramApi/Sources/Api11.swift @@ -429,7 +429,7 @@ public extension Api { case keyboardButtonCallback(flags: Int32, text: String, data: Buffer) case keyboardButtonGame(text: String) case keyboardButtonRequestGeoLocation(text: String) - case keyboardButtonRequestPeer(text: String, buttonId: Int32, peerType: Api.RequestPeerType) + case keyboardButtonRequestPeer(text: String, buttonId: Int32, peerType: Api.RequestPeerType, maxQuantity: Int32) case keyboardButtonRequestPhone(text: String) case keyboardButtonRequestPoll(flags: Int32, quiz: Api.Bool?, text: String) case keyboardButtonSimpleWebView(text: String, url: String) @@ -490,13 +490,14 @@ public extension Api { } serializeString(text, buffer: buffer, boxed: false) break - case .keyboardButtonRequestPeer(let text, let buttonId, let peerType): + case .keyboardButtonRequestPeer(let text, let buttonId, let peerType, let maxQuantity): if boxed { - buffer.appendInt32(218842764) + buffer.appendInt32(1406648280) } serializeString(text, buffer: buffer, boxed: false) serializeInt32(buttonId, buffer: buffer, boxed: false) peerType.serialize(buffer, true) + serializeInt32(maxQuantity, buffer: buffer, boxed: false) break case .keyboardButtonRequestPhone(let text): if boxed { @@ -582,8 +583,8 @@ public extension Api { return ("keyboardButtonGame", [("text", text as Any)]) case .keyboardButtonRequestGeoLocation(let text): return ("keyboardButtonRequestGeoLocation", [("text", text as Any)]) - case .keyboardButtonRequestPeer(let text, let buttonId, let peerType): - return ("keyboardButtonRequestPeer", [("text", text as Any), ("buttonId", buttonId as Any), ("peerType", peerType as Any)]) + case .keyboardButtonRequestPeer(let text, let buttonId, let peerType, let maxQuantity): + return ("keyboardButtonRequestPeer", [("text", text as Any), ("buttonId", buttonId as Any), ("peerType", peerType as Any), ("maxQuantity", maxQuantity as Any)]) case .keyboardButtonRequestPhone(let text): return ("keyboardButtonRequestPhone", [("text", text as Any)]) case .keyboardButtonRequestPoll(let flags, let quiz, let text): @@ -714,11 +715,14 @@ public extension Api { if let signature = reader.readInt32() { _3 = Api.parse(reader, signature: signature) as? Api.RequestPeerType } + var _4: Int32? + _4 = reader.readInt32() let _c1 = _1 != nil let _c2 = _2 != nil let _c3 = _3 != nil - if _c1 && _c2 && _c3 { - return Api.KeyboardButton.keyboardButtonRequestPeer(text: _1!, buttonId: _2!, peerType: _3!) + let _c4 = _4 != nil + if _c1 && _c2 && _c3 && _c4 { + return Api.KeyboardButton.keyboardButtonRequestPeer(text: _1!, buttonId: _2!, peerType: _3!, maxQuantity: _4!) } else { return nil diff --git a/submodules/TelegramApi/Sources/Api12.swift b/submodules/TelegramApi/Sources/Api12.swift index 70197dfd31d..d5155f12fbf 100644 --- a/submodules/TelegramApi/Sources/Api12.swift +++ b/submodules/TelegramApi/Sources/Api12.swift @@ -683,7 +683,7 @@ public extension Api { case messageActionPaymentSentMe(flags: Int32, currency: String, totalAmount: Int64, payload: Buffer, info: Api.PaymentRequestedInfo?, shippingOptionId: String?, charge: Api.PaymentCharge) case messageActionPhoneCall(flags: Int32, callId: Int64, reason: Api.PhoneCallDiscardReason?, duration: Int32?) case messageActionPinMessage - case messageActionRequestedPeer(buttonId: Int32, peer: Api.Peer) + case messageActionRequestedPeer(buttonId: Int32, peers: [Api.Peer]) case messageActionScreenshotTaken case messageActionSecureValuesSent(types: [Api.SecureValueType]) case messageActionSecureValuesSentMe(values: [Api.SecureValue], credentials: Api.SecureCredentialsEncrypted) @@ -920,12 +920,16 @@ public extension Api { } break - case .messageActionRequestedPeer(let buttonId, let peer): + case .messageActionRequestedPeer(let buttonId, let peers): if boxed { - buffer.appendInt32(-25742243) + buffer.appendInt32(827428507) } serializeInt32(buttonId, buffer: buffer, boxed: false) - peer.serialize(buffer, true) + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(peers.count)) + for item in peers { + item.serialize(buffer, true) + } break case .messageActionScreenshotTaken: if boxed { @@ -1076,8 +1080,8 @@ public extension Api { return ("messageActionPhoneCall", [("flags", flags as Any), ("callId", callId as Any), ("reason", reason as Any), ("duration", duration as Any)]) case .messageActionPinMessage: return ("messageActionPinMessage", []) - case .messageActionRequestedPeer(let buttonId, let peer): - return ("messageActionRequestedPeer", [("buttonId", buttonId as Any), ("peer", peer as Any)]) + case .messageActionRequestedPeer(let buttonId, let peers): + return ("messageActionRequestedPeer", [("buttonId", buttonId as Any), ("peers", peers as Any)]) case .messageActionScreenshotTaken: return ("messageActionScreenshotTaken", []) case .messageActionSecureValuesSent(let types): @@ -1505,14 +1509,14 @@ public extension Api { public static func parse_messageActionRequestedPeer(_ reader: BufferReader) -> MessageAction? { var _1: Int32? _1 = reader.readInt32() - var _2: Api.Peer? - if let signature = reader.readInt32() { - _2 = Api.parse(reader, signature: signature) as? Api.Peer + var _2: [Api.Peer]? + if let _ = reader.readInt32() { + _2 = Api.parseVector(reader, elementSignature: 0, elementType: Api.Peer.self) } let _c1 = _1 != nil let _c2 = _2 != nil if _c1 && _c2 { - return Api.MessageAction.messageActionRequestedPeer(buttonId: _1!, peer: _2!) + return Api.MessageAction.messageActionRequestedPeer(buttonId: _1!, peers: _2!) } else { return nil diff --git a/submodules/TelegramApi/Sources/Api32.swift b/submodules/TelegramApi/Sources/Api32.swift index 9ce47f6456b..6e161a1f2bd 100644 --- a/submodules/TelegramApi/Sources/Api32.swift +++ b/submodules/TelegramApi/Sources/Api32.swift @@ -328,6 +328,21 @@ public extension Api.functions.account { }) } } +public extension Api.functions.account { + static func getChannelDefaultEmojiStatuses(hash: Int64) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(1999087573) + serializeInt64(hash, buffer: buffer, boxed: false) + return (FunctionDescription(name: "account.getChannelDefaultEmojiStatuses", parameters: [("hash", String(describing: hash))]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.account.EmojiStatuses? in + let reader = BufferReader(buffer) + var result: Api.account.EmojiStatuses? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.account.EmojiStatuses + } + return result + }) + } +} public extension Api.functions.account { static func getChannelRestrictedStatusEmojis(hash: Int64) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { let buffer = Buffer() @@ -6750,14 +6765,18 @@ public extension Api.functions.messages { } } public extension Api.functions.messages { - static func sendBotRequestedPeer(peer: Api.InputPeer, msgId: Int32, buttonId: Int32, requestedPeer: Api.InputPeer) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + static func sendBotRequestedPeer(peer: Api.InputPeer, msgId: Int32, buttonId: Int32, requestedPeers: [Api.InputPeer]) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { let buffer = Buffer() - buffer.appendInt32(-29831141) + buffer.appendInt32(-1850552224) peer.serialize(buffer, true) serializeInt32(msgId, buffer: buffer, boxed: false) serializeInt32(buttonId, buffer: buffer, boxed: false) - requestedPeer.serialize(buffer, true) - return (FunctionDescription(name: "messages.sendBotRequestedPeer", parameters: [("peer", String(describing: peer)), ("msgId", String(describing: msgId)), ("buttonId", String(describing: buttonId)), ("requestedPeer", String(describing: requestedPeer))]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.Updates? in + buffer.appendInt32(481674261) + buffer.appendInt32(Int32(requestedPeers.count)) + for item in requestedPeers { + item.serialize(buffer, true) + } + return (FunctionDescription(name: "messages.sendBotRequestedPeer", parameters: [("peer", String(describing: peer)), ("msgId", String(describing: msgId)), ("buttonId", String(describing: buttonId)), ("requestedPeers", String(describing: requestedPeers))]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.Updates? in let reader = BufferReader(buffer) var result: Api.Updates? if let signature = reader.readInt32() { diff --git a/submodules/TelegramCore/Sources/ApiUtils/ReplyMarkupMessageAttribute.swift b/submodules/TelegramCore/Sources/ApiUtils/ReplyMarkupMessageAttribute.swift index 00f0da59161..1b289cd0aa1 100644 --- a/submodules/TelegramCore/Sources/ApiUtils/ReplyMarkupMessageAttribute.swift +++ b/submodules/TelegramCore/Sources/ApiUtils/ReplyMarkupMessageAttribute.swift @@ -63,7 +63,7 @@ extension ReplyMarkupButton { self.init(title: text, titleWhenForwarded: nil, action: .openWebView(url: url, simple: false)) case let .keyboardButtonSimpleWebView(text, url): self.init(title: text, titleWhenForwarded: nil, action: .openWebView(url: url, simple: true)) - case let .keyboardButtonRequestPeer(text, buttonId, peerType): + case let .keyboardButtonRequestPeer(text, buttonId, peerType, maxQuantity): let mappedPeerType: ReplyMarkupButtonRequestPeerType switch peerType { case let .requestPeerTypeUser(_, bot, premium): @@ -88,7 +88,7 @@ extension ReplyMarkupButton { botAdminRights: botAdminRights.flatMap(TelegramChatAdminRights.init(apiAdminRights:)) )) } - self.init(title: text, titleWhenForwarded: nil, action: .requestPeer(peerType: mappedPeerType, buttonId: buttonId)) + self.init(title: text, titleWhenForwarded: nil, action: .requestPeer(peerType: mappedPeerType, buttonId: buttonId, maxQuantity: maxQuantity)) } } } diff --git a/submodules/TelegramCore/Sources/ApiUtils/StoreMessage_Telegram.swift b/submodules/TelegramCore/Sources/ApiUtils/StoreMessage_Telegram.swift index 7d18dc225ac..60e9e513044 100644 --- a/submodules/TelegramCore/Sources/ApiUtils/StoreMessage_Telegram.swift +++ b/submodules/TelegramCore/Sources/ApiUtils/StoreMessage_Telegram.swift @@ -242,8 +242,8 @@ func apiMessagePeerIds(_ message: Api.Message) -> [PeerId] { for id in userIds { result.append(PeerId(namespace: Namespaces.Peer.CloudUser, id: PeerId.Id._internalFromInt64Value(id))) } - case let .messageActionRequestedPeer(_, peer): - result.append(peer.peerId) + case let .messageActionRequestedPeer(_, peers): + result.append(contentsOf: peers.map(\.peerId)) case let .messageActionGiftCode(_, boostPeer, _, _, _, _, _, _): if let boostPeer = boostPeer { result.append(boostPeer.peerId) diff --git a/submodules/TelegramCore/Sources/ApiUtils/TelegramMediaAction.swift b/submodules/TelegramCore/Sources/ApiUtils/TelegramMediaAction.swift index d4a392eaee4..dda3010fa85 100644 --- a/submodules/TelegramCore/Sources/ApiUtils/TelegramMediaAction.swift +++ b/submodules/TelegramCore/Sources/ApiUtils/TelegramMediaAction.swift @@ -121,8 +121,8 @@ func telegramMediaActionFromApiAction(_ action: Api.MessageAction) -> TelegramMe return TelegramMediaAction(action: .topicEdited(components: components)) case let .messageActionSuggestProfilePhoto(photo): return TelegramMediaAction(action: .suggestedProfilePhoto(image: telegramMediaImageFromApiPhoto(photo))) - case let .messageActionRequestedPeer(buttonId, peer): - return TelegramMediaAction(action: .requestedPeer(buttonId: buttonId, peerId: peer.peerId)) + case let .messageActionRequestedPeer(buttonId, peers): + return TelegramMediaAction(action: .requestedPeer(buttonId: buttonId, peerIds: peers.map { $0.peerId })) case let .messageActionSetChatWallPaper(flags, wallpaper): if (flags & (1 << 0)) != 0 { return TelegramMediaAction(action: .setSameChatWallpaper(wallpaper: TelegramWallpaper(apiWallpaper: wallpaper))) diff --git a/submodules/TelegramCore/Sources/ApiUtils/TelegramMediaFile.swift b/submodules/TelegramCore/Sources/ApiUtils/TelegramMediaFile.swift index 7ffbcce9016..15899cf081d 100644 --- a/submodules/TelegramCore/Sources/ApiUtils/TelegramMediaFile.swift +++ b/submodules/TelegramCore/Sources/ApiUtils/TelegramMediaFile.swift @@ -70,6 +70,8 @@ extension StickerPackReference { self = .iconStatusEmoji case .inputStickerSetEmojiDefaultTopicIcons: self = .iconTopicEmoji + case .inputStickerSetEmojiChannelDefaultStatuses: + return nil } } } diff --git a/submodules/TelegramCore/Sources/State/Serialization.swift b/submodules/TelegramCore/Sources/State/Serialization.swift index eced7585d48..1db7e2bbec4 100644 --- a/submodules/TelegramCore/Sources/State/Serialization.swift +++ b/submodules/TelegramCore/Sources/State/Serialization.swift @@ -210,7 +210,7 @@ public class BoxedMessage: NSObject { public class Serialization: NSObject, MTSerialization { public func currentLayer() -> UInt { - return 168 + return 169 } public func parseMessage(_ data: Data!) -> Any! { diff --git a/submodules/TelegramCore/Sources/SyncCore/SyncCore_ReplyMarkupMessageAttribute.swift b/submodules/TelegramCore/Sources/SyncCore/SyncCore_ReplyMarkupMessageAttribute.swift index e07e11baed8..acd70cce706 100644 --- a/submodules/TelegramCore/Sources/SyncCore/SyncCore_ReplyMarkupMessageAttribute.swift +++ b/submodules/TelegramCore/Sources/SyncCore/SyncCore_ReplyMarkupMessageAttribute.swift @@ -231,7 +231,7 @@ public enum ReplyMarkupButtonAction: PostboxCoding, Equatable { case setupPoll(isQuiz: Bool?) case openUserProfile(peerId: PeerId) case openWebView(url: String, simple: Bool) - case requestPeer(peerType: ReplyMarkupButtonRequestPeerType, buttonId: Int32) + case requestPeer(peerType: ReplyMarkupButtonRequestPeerType, buttonId: Int32, maxQuantity: Int32) public init(decoder: PostboxDecoder) { switch decoder.decodeInt32ForKey("v", orElse: 0) { @@ -260,7 +260,7 @@ public enum ReplyMarkupButtonAction: PostboxCoding, Equatable { case 11: self = .openWebView(url: decoder.decodeStringForKey("u", orElse: ""), simple: decoder.decodeInt32ForKey("s", orElse: 0) != 0) case 12: - self = .requestPeer(peerType: decoder.decode(ReplyMarkupButtonRequestPeerType.self, forKey: "pt") ?? ReplyMarkupButtonRequestPeerType.user(ReplyMarkupButtonRequestPeerType.User(isBot: nil, isPremium: nil)), buttonId: decoder.decodeInt32ForKey("b", orElse: 0)) + self = .requestPeer(peerType: decoder.decode(ReplyMarkupButtonRequestPeerType.self, forKey: "pt") ?? ReplyMarkupButtonRequestPeerType.user(ReplyMarkupButtonRequestPeerType.User(isBot: nil, isPremium: nil)), buttonId: decoder.decodeInt32ForKey("b", orElse: 0), maxQuantity: decoder.decodeInt32ForKey("q", orElse: 1)) default: self = .text } @@ -308,10 +308,11 @@ public enum ReplyMarkupButtonAction: PostboxCoding, Equatable { encoder.encodeInt32(11, forKey: "v") encoder.encodeString(url, forKey: "u") encoder.encodeInt32(simple ? 1 : 0, forKey: "s") - case let .requestPeer(peerType, buttonId): + case let .requestPeer(peerType, buttonId, maxQuantity): encoder.encodeInt32(12, forKey: "v") encoder.encodeInt32(buttonId, forKey: "b") encoder.encode(peerType, forKey: "pt") + encoder.encodeInt32(maxQuantity, forKey: "q") } } } diff --git a/submodules/TelegramCore/Sources/SyncCore/SyncCore_TelegramMediaAction.swift b/submodules/TelegramCore/Sources/SyncCore/SyncCore_TelegramMediaAction.swift index fa1aec05d70..f0668d34e93 100644 --- a/submodules/TelegramCore/Sources/SyncCore/SyncCore_TelegramMediaAction.swift +++ b/submodules/TelegramCore/Sources/SyncCore/SyncCore_TelegramMediaAction.swift @@ -119,7 +119,7 @@ public enum TelegramMediaActionType: PostboxCoding, Equatable { case topicEdited(components: [ForumTopicEditComponent]) case suggestedProfilePhoto(image: TelegramMediaImage?) case attachMenuBotAllowed - case requestedPeer(buttonId: Int32, peerId: PeerId) + case requestedPeer(buttonId: Int32, peerIds: [PeerId]) case setChatWallpaper(wallpaper: TelegramWallpaper, forBoth: Bool) case setSameChatWallpaper(wallpaper: TelegramWallpaper) case giftCode(slug: String, fromGiveaway: Bool, isUnclaimed: Bool, boostPeerId: PeerId?, months: Int32, currency: String?, amount: Int64?, cryptoCurrency: String?, cryptoAmount: Int64?) @@ -205,7 +205,11 @@ public enum TelegramMediaActionType: PostboxCoding, Equatable { case 31: self = .attachMenuBotAllowed case 32: - self = .requestedPeer(buttonId: decoder.decodeInt32ForKey("b", orElse: 0), peerId: PeerId(decoder.decodeInt64ForKey("pi", orElse: 0))) + var peerIds = decoder.decodeInt64ArrayForKey("pis").map { PeerId($0) } + if peerIds.isEmpty { + peerIds = [PeerId(decoder.decodeInt64ForKey("pi", orElse: 0))] + } + self = .requestedPeer(buttonId: decoder.decodeInt32ForKey("b", orElse: 0), peerIds: peerIds) case 33: if let wallpaper = decoder.decode(TelegramWallpaperNativeCodable.self, forKey: "wallpaper")?.value { self = .setChatWallpaper(wallpaper: wallpaper, forBoth: decoder.decodeBoolForKey("both", orElse: false)) @@ -385,10 +389,10 @@ public enum TelegramMediaActionType: PostboxCoding, Equatable { } case .attachMenuBotAllowed: encoder.encodeInt32(31, forKey: "_rawValue") - case let .requestedPeer(buttonId, peerId): + case let .requestedPeer(buttonId, peerIds): encoder.encodeInt32(32, forKey: "_rawValue") encoder.encodeInt32(buttonId, forKey: "b") - encoder.encodeInt64(peerId.toInt64(), forKey: "pi") + encoder.encodeInt64Array(peerIds.map { $0.toInt64() }, forKey: "pis") case let .setChatWallpaper(wallpaper, forBoth): encoder.encodeInt32(33, forKey: "_rawValue") encoder.encode(TelegramWallpaperNativeCodable(wallpaper), forKey: "wallpaper") @@ -466,8 +470,8 @@ public enum TelegramMediaActionType: PostboxCoding, Equatable { return [from, to] case let .inviteToGroupPhoneCall(_, _, peerIds): return peerIds - case let .requestedPeer(_, peerId): - return [peerId] + case let .requestedPeer(_, peerIds): + return peerIds case let .giftCode(_, _, _, boostPeerId, _, _, _, _, _): return boostPeerId.flatMap { [$0] } ?? [] default: diff --git a/submodules/TelegramCore/Sources/TelegramEngine/Peers/AddPeerMember.swift b/submodules/TelegramCore/Sources/TelegramEngine/Peers/AddPeerMember.swift index f0b53701721..de47654b99a 100644 --- a/submodules/TelegramCore/Sources/TelegramEngine/Peers/AddPeerMember.swift +++ b/submodules/TelegramCore/Sources/TelegramEngine/Peers/AddPeerMember.swift @@ -235,17 +235,17 @@ public enum SendBotRequestedPeerError { case generic } -func _internal_sendBotRequestedPeer(account: Account, peerId: PeerId, messageId: MessageId, buttonId: Int32, requestedPeerId: PeerId) -> Signal { - let signal = account.postbox.transaction { transaction -> Signal in - - - if let peer = transaction.getPeer(peerId), let requestedPeer = transaction.getPeer(requestedPeerId) { - - let inputPeer = apiInputPeer(peer) - let inputRequestedPeer = apiInputPeer(requestedPeer) - - if let inputPeer = inputPeer, let inputRequestedPeer = inputRequestedPeer { - let signal = account.network.request(Api.functions.messages.sendBotRequestedPeer(peer: inputPeer, msgId: messageId.id, buttonId: buttonId, requestedPeer: inputRequestedPeer)) +func _internal_sendBotRequestedPeer(account: Account, peerId: PeerId, messageId: MessageId, buttonId: Int32, requestedPeerIds: [PeerId]) -> Signal { + return account.postbox.transaction { transaction -> Signal in + if let peer = transaction.getPeer(peerId) { + var inputRequestedPeers: [Api.InputPeer] = [] + for requestedPeerId in requestedPeerIds { + if let requestedPeer = transaction.getPeer(requestedPeerId), let inputRequestedPeer = apiInputPeer(requestedPeer) { + inputRequestedPeers.append(inputRequestedPeer) + } + } + if let inputPeer = apiInputPeer(peer), !inputRequestedPeers.isEmpty { + let signal = account.network.request(Api.functions.messages.sendBotRequestedPeer(peer: inputPeer, msgId: messageId.id, buttonId: buttonId, requestedPeers: inputRequestedPeers)) |> mapError { error -> SendBotRequestedPeerError in return .generic } @@ -254,12 +254,9 @@ func _internal_sendBotRequestedPeer(account: Account, peerId: PeerId, messageId: } return signal } - } return .single(Void()) } |> castError(SendBotRequestedPeerError.self) - - return signal |> switchToLatest } diff --git a/submodules/TelegramCore/Sources/TelegramEngine/Peers/TelegramEnginePeers.swift b/submodules/TelegramCore/Sources/TelegramEngine/Peers/TelegramEnginePeers.swift index 573637db614..1d684e538c5 100644 --- a/submodules/TelegramCore/Sources/TelegramEngine/Peers/TelegramEnginePeers.swift +++ b/submodules/TelegramCore/Sources/TelegramEngine/Peers/TelegramEnginePeers.swift @@ -504,8 +504,8 @@ public extension TelegramEngine { return _internal_addChannelMember(account: self.account, peerId: peerId, memberId: memberId) } - public func sendBotRequestedPeer(messageId: MessageId, buttonId: Int32, requestedPeerId: PeerId) -> Signal { - return _internal_sendBotRequestedPeer(account: self.account, peerId: messageId.peerId, messageId: messageId, buttonId: buttonId, requestedPeerId: requestedPeerId) + public func sendBotRequestedPeer(messageId: MessageId, buttonId: Int32, requestedPeerIds: [PeerId]) -> Signal { + return _internal_sendBotRequestedPeer(account: self.account, peerId: messageId.peerId, messageId: messageId, buttonId: buttonId, requestedPeerIds: requestedPeerIds) } public func addChannelMembers(peerId: PeerId, memberIds: [PeerId]) -> Signal { diff --git a/submodules/TelegramStringFormatting/Sources/ServiceMessageStrings.swift b/submodules/TelegramStringFormatting/Sources/ServiceMessageStrings.swift index 2e9ef94238a..7248c286e59 100644 --- a/submodules/TelegramStringFormatting/Sources/ServiceMessageStrings.swift +++ b/submodules/TelegramStringFormatting/Sources/ServiceMessageStrings.swift @@ -886,10 +886,19 @@ public func universalServiceMessageString(presentationData: (PresentationTheme, } case .attachMenuBotAllowed: attributedString = NSAttributedString(string: strings.Notification_BotWriteAllowed, font: titleFont, textColor: primaryTextColor) - case let .requestedPeer(_, peerId): + case let .requestedPeer(_, peerIds): let botName = message.peers[message.id.peerId].flatMap(EnginePeer.init)?.displayTitle(strings: strings, displayOrder: nameDisplayOrder) ?? "" - let peerName = message.peers[peerId].flatMap(EnginePeer.init)?.displayTitle(strings: strings, displayOrder: nameDisplayOrder) ?? "" - attributedString = addAttributesToStringWithRanges(strings.Notification_RequestedPeer(peerName, botName)._tuple, body: bodyAttributes, argumentAttributes: peerMentionsAttributes(primaryTextColor: primaryTextColor, peerIds: [(0, peerId), (1, message.id.peerId)])) + var attributePeerIds: [(Int, EnginePeer.Id?)] = [] + let resultTitleString: PresentationStrings.FormattedString + if peerIds.count == 1 { + attributePeerIds.append((0, peerIds.first)) + attributePeerIds.append((1, message.id.peerId)) + resultTitleString = strings.Notification_RequestedPeer(peerDisplayTitles(peerIds, message.peers, strings: strings, nameDisplayOrder: nameDisplayOrder), botName) + } else { + attributePeerIds.append((1, message.id.peerId)) + resultTitleString = strings.Notification_RequestedPeerMultiple(peerDisplayTitles(peerIds, message.peers, strings: strings, nameDisplayOrder: nameDisplayOrder), botName) + } + attributedString = addAttributesToStringWithRanges(resultTitleString._tuple, body: bodyAttributes, argumentAttributes: peerMentionsAttributes(primaryTextColor: primaryTextColor, peerIds: attributePeerIds)) case let .setChatWallpaper(_, forBoth): if message.author?.id == accountPeerId { if forBoth { diff --git a/submodules/TelegramUI/Components/Chat/ChatButtonKeyboardInputNode/Sources/ChatButtonKeyboardInputNode.swift b/submodules/TelegramUI/Components/Chat/ChatButtonKeyboardInputNode/Sources/ChatButtonKeyboardInputNode.swift index 348fc553ecc..269f0a80d29 100644 --- a/submodules/TelegramUI/Components/Chat/ChatButtonKeyboardInputNode/Sources/ChatButtonKeyboardInputNode.swift +++ b/submodules/TelegramUI/Components/Chat/ChatButtonKeyboardInputNode/Sources/ChatButtonKeyboardInputNode.swift @@ -434,9 +434,9 @@ public final class ChatButtonKeyboardInputNode: ChatInputNode { }) case let .openWebView(url, simple): self.controllerInteraction.openWebView(markupButton.title, url, simple, .generic) - case let .requestPeer(peerType, buttonId): + case let .requestPeer(peerType, buttonId, maxQuantity): if let message = self.message { - self.controllerInteraction.openRequestedPeerSelection(message.id, peerType, buttonId) + self.controllerInteraction.openRequestedPeerSelection(message.id, peerType, buttonId, maxQuantity) } } if dismissIfOnce { diff --git a/submodules/TelegramUI/Components/Chat/ChatRecentActionsController/Sources/ChatRecentActionsControllerNode.swift b/submodules/TelegramUI/Components/Chat/ChatRecentActionsController/Sources/ChatRecentActionsControllerNode.swift index daac53664ac..ed49c75dfb9 100644 --- a/submodules/TelegramUI/Components/Chat/ChatRecentActionsController/Sources/ChatRecentActionsControllerNode.swift +++ b/submodules/TelegramUI/Components/Chat/ChatRecentActionsController/Sources/ChatRecentActionsControllerNode.swift @@ -565,7 +565,7 @@ final class ChatRecentActionsControllerNode: ViewControllerTracingNode { }, openJoinLink: { _ in }, openWebView: { _, _, _, _ in }, activateAdAction: { _ in - }, openRequestedPeerSelection: { _, _, _ in + }, openRequestedPeerSelection: { _, _, _, _ in }, saveMediaToFiles: { _ in }, openNoAdsDemo: { }, displayGiveawayParticipationStatus: { _ in diff --git a/submodules/TelegramUI/Components/ChatControllerInteraction/Sources/ChatControllerInteraction.swift b/submodules/TelegramUI/Components/ChatControllerInteraction/Sources/ChatControllerInteraction.swift index a0d5530497e..1f8978e8f87 100644 --- a/submodules/TelegramUI/Components/ChatControllerInteraction/Sources/ChatControllerInteraction.swift +++ b/submodules/TelegramUI/Components/ChatControllerInteraction/Sources/ChatControllerInteraction.swift @@ -225,7 +225,7 @@ public final class ChatControllerInteraction: ChatControllerInteractionProtocol public let openJoinLink: (String) -> Void public let openWebView: (String, String, Bool, ChatOpenWebViewSource) -> Void public let activateAdAction: (EngineMessage.Id) -> Void - public let openRequestedPeerSelection: (EngineMessage.Id, ReplyMarkupButtonRequestPeerType, Int32) -> Void + public let openRequestedPeerSelection: (EngineMessage.Id, ReplyMarkupButtonRequestPeerType, Int32, Int32) -> Void public let saveMediaToFiles: (EngineMessage.Id) -> Void public let openNoAdsDemo: () -> Void public let displayGiveawayParticipationStatus: (EngineMessage.Id) -> Void @@ -346,7 +346,7 @@ public final class ChatControllerInteraction: ChatControllerInteractionProtocol openJoinLink: @escaping (String) -> Void, openWebView: @escaping (String, String, Bool, ChatOpenWebViewSource) -> Void, activateAdAction: @escaping (EngineMessage.Id) -> Void, - openRequestedPeerSelection: @escaping (EngineMessage.Id, ReplyMarkupButtonRequestPeerType, Int32) -> Void, + openRequestedPeerSelection: @escaping (EngineMessage.Id, ReplyMarkupButtonRequestPeerType, Int32, Int32) -> Void, saveMediaToFiles: @escaping (EngineMessage.Id) -> Void, openNoAdsDemo: @escaping () -> Void, displayGiveawayParticipationStatus: @escaping (EngineMessage.Id) -> Void, diff --git a/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/PeerInfoScreen.swift b/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/PeerInfoScreen.swift index ea9f3274e85..85f791d5f30 100644 --- a/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/PeerInfoScreen.swift +++ b/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/PeerInfoScreen.swift @@ -2996,7 +2996,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, PeerInfoScreenNodePro }, openJoinLink: { _ in }, openWebView: { _, _, _, _ in }, activateAdAction: { _ in - }, openRequestedPeerSelection: { _, _, _ in + }, openRequestedPeerSelection: { _, _, _, _ in }, saveMediaToFiles: { _ in }, openNoAdsDemo: { }, displayGiveawayParticipationStatus: { _ in diff --git a/submodules/TelegramUI/Sources/ChatController.swift b/submodules/TelegramUI/Sources/ChatController.swift index 447002557b7..bd936f0066b 100644 --- a/submodules/TelegramUI/Sources/ChatController.swift +++ b/submodules/TelegramUI/Sources/ChatController.swift @@ -4174,23 +4174,19 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G } }) } - }, openRequestedPeerSelection: { [weak self] messageId, peerType, buttonId in + }, openRequestedPeerSelection: { [weak self] messageId, peerType, buttonId, maxQuantity in guard let self else { return } let botName = self.presentationInterfaceState.renderedPeer?.peer.flatMap { EnginePeer($0) }?.compactDisplayTitle ?? "" let context = self.context let peerId = self.chatLocation.peerId - var createNewGroupImpl: (() -> Void)? - let controller = self.context.sharedContext.makePeerSelectionController(PeerSelectionControllerParams(context: self.context, filter: [.excludeRecent, .doNotSearchMessages], requestPeerType: [peerType], hasContactSelector: false, createNewGroup: { - createNewGroupImpl?() - }, hasCreation: true)) let presentConfirmation: (String, Bool, @escaping () -> Void) -> Void = { [weak self] peerName, isChannel, completion in guard let strongSelf = self else { return } - + var attributedTitle: NSAttributedString? let attributedText: NSAttributedString @@ -4240,62 +4236,109 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G } } } - + let controller = richTextAlertController(context: context, title: attributedTitle, text: attributedText, actions: [TextAlertAction(type: .genericAction, title: strongSelf.presentationData.strings.Common_Cancel, action: {}), TextAlertAction(type: .defaultAction, title: strongSelf.presentationData.strings.RequestPeer_SelectionConfirmationSend, action: { - completion() })]) strongSelf.present(controller, in: .window(.root)) } - controller.peerSelected = { [weak self, weak controller] peer, _ in - guard let strongSelf = self else { - return + if case .user = peerType, maxQuantity > 1 { + let presentationData = self.presentationData + var reachedLimitImpl: ((Int32) -> Void)? + let controller = context.sharedContext.makeContactMultiselectionController(ContactMultiselectionControllerParams(context: context, mode: .requestedUsersSelection, options: [], isPeerEnabled: { peer in + if case let .user(user) = peer, user.botInfo == nil { + return true + } else { + return false + } + }, limit: maxQuantity, reachedLimit: { limit in + reachedLimitImpl?(limit) + })) + controller.navigationPresentation = .modal + reachedLimitImpl = { [weak controller] limit in + guard let controller else { + return + } + HapticFeedback().error() + controller.present(UndoOverlayController(presentationData: presentationData, content: .info(title: nil, text: presentationData.strings.RequestPeer_ReachedMaximum(limit), timeout: nil, customUndoText: nil), elevatedLayout: true, position: .bottom, animateInAsReplacement: false, action: { _ in return false }), in: .current) } - if case .user = peerType { - let _ = context.engine.peers.sendBotRequestedPeer(messageId: messageId, buttonId: buttonId, requestedPeerId: peer.id).startStandalone() - controller?.dismiss() - } else { - var isChannel = false - if case let .channel(channel) = peer, case .broadcast = channel.info { - isChannel = true + + let _ = (controller.result + |> deliverOnMainQueue).startStandalone(next: { [weak controller] result in + guard let controller else { + return + } + var peerIds: [PeerId] = [] + if case let .result(peerIdsValue, _) = result { + peerIds = peerIdsValue.compactMap({ peerId in + if case let .peer(peerId) = peerId { + return peerId + } else { + return nil + } + }) + } + let _ = context.engine.peers.sendBotRequestedPeer(messageId: messageId, buttonId: buttonId, requestedPeerIds: peerIds).startStandalone() + controller.dismiss() + }) + + self.push(controller) + } else { + var createNewGroupImpl: (() -> Void)? + let controller = self.context.sharedContext.makePeerSelectionController(PeerSelectionControllerParams(context: self.context, filter: [.excludeRecent, .doNotSearchMessages], requestPeerType: [peerType], hasContactSelector: false, createNewGroup: { + createNewGroupImpl?() + }, hasCreation: true)) + + controller.peerSelected = { [weak self, weak controller] peer, _ in + guard let strongSelf = self else { + return } - let peerName = peer.displayTitle(strings: strongSelf.presentationData.strings, displayOrder: strongSelf.presentationData.nameDisplayOrder) - presentConfirmation(peerName, isChannel, { - let _ = context.engine.peers.sendBotRequestedPeer(messageId: messageId, buttonId: buttonId, requestedPeerId: peer.id).startStandalone() + if case .user = peerType { + let _ = context.engine.peers.sendBotRequestedPeer(messageId: messageId, buttonId: buttonId, requestedPeerIds: [peer.id]).startStandalone() controller?.dismiss() - }) + } else { + var isChannel = false + if case let .channel(channel) = peer, case .broadcast = channel.info { + isChannel = true + } + let peerName = peer.displayTitle(strings: strongSelf.presentationData.strings, displayOrder: strongSelf.presentationData.nameDisplayOrder) + presentConfirmation(peerName, isChannel, { + let _ = context.engine.peers.sendBotRequestedPeer(messageId: messageId, buttonId: buttonId, requestedPeerIds: [peer.id]).startStandalone() + controller?.dismiss() + }) + } } - } - createNewGroupImpl = { [weak controller] in - switch peerType { - case .user: - break - case let .group(group): - let createGroupController = createGroupControllerImpl(context: context, peerIds: group.botParticipant || group.botAdminRights != nil ? (peerId.flatMap { [$0] } ?? []) : [], mode: .requestPeer(group), willComplete: { peerName, complete in - presentConfirmation(peerName, false, { - complete() + createNewGroupImpl = { [weak controller] in + switch peerType { + case .user: + break + case let .group(group): + let createGroupController = createGroupControllerImpl(context: context, peerIds: group.botParticipant || group.botAdminRights != nil ? (peerId.flatMap { [$0] } ?? []) : [], mode: .requestPeer(group), willComplete: { peerName, complete in + presentConfirmation(peerName, false, { + complete() + }) + }, completion: { peerId, dismiss in + let _ = context.engine.peers.sendBotRequestedPeer(messageId: messageId, buttonId: buttonId, requestedPeerIds: [peerId]).startStandalone() + dismiss() }) - }, completion: { peerId, dismiss in - let _ = context.engine.peers.sendBotRequestedPeer(messageId: messageId, buttonId: buttonId, requestedPeerId: peerId).startStandalone() - dismiss() - }) - createGroupController.navigationPresentation = .modal - controller?.replace(with: createGroupController) - case let .channel(channel): - let createChannelController = createChannelController(context: context, mode: .requestPeer(channel), willComplete: { peerName, complete in - presentConfirmation(peerName, true, { - complete() + createGroupController.navigationPresentation = .modal + controller?.replace(with: createGroupController) + case let .channel(channel): + let createChannelController = createChannelController(context: context, mode: .requestPeer(channel), willComplete: { peerName, complete in + presentConfirmation(peerName, true, { + complete() + }) + }, completion: { peerId, dismiss in + let _ = context.engine.peers.sendBotRequestedPeer(messageId: messageId, buttonId: buttonId, requestedPeerIds: [peerId]).startStandalone() + dismiss() }) - }, completion: { peerId, dismiss in - let _ = context.engine.peers.sendBotRequestedPeer(messageId: messageId, buttonId: buttonId, requestedPeerId: peerId).startStandalone() - dismiss() - }) - createChannelController.navigationPresentation = .modal - controller?.replace(with: createChannelController) + createChannelController.navigationPresentation = .modal + controller?.replace(with: createChannelController) + } } + self.push(controller) } - self.push(controller) }, saveMediaToFiles: { [weak self] messageId in let _ = (context.engine.data.get(TelegramEngine.EngineData.Item.Messages.Message(id: messageId)) |> deliverOnMainQueue).startStandalone(next: { message in diff --git a/submodules/TelegramUI/Sources/ContactMultiselectionController.swift b/submodules/TelegramUI/Sources/ContactMultiselectionController.swift index 7f99fffb9db..d89f9bb1a6c 100644 --- a/submodules/TelegramUI/Sources/ContactMultiselectionController.swift +++ b/submodules/TelegramUI/Sources/ContactMultiselectionController.swift @@ -202,12 +202,19 @@ class ContactMultiselectionControllerImpl: ViewController, ContactMultiselection self.navigationItem.rightBarButtonItem = self.rightNavigationButton rightNavigationButton.isEnabled = true //count != 0 || self.params.alwaysEnabled case .premiumGifting: - let maxCount: Int32 = 10 + let maxCount: Int32 = self.limit ?? 10 var count = 0 if case let .contacts(contactsNode) = self.contactsNode.contentNode { count = contactsNode.selectionState?.selectedPeerIndices.count ?? 0 } self.titleView.title = CounterContollerTitle(title: self.presentationData.strings.Premium_Gift_ContactSelection_Title, counter: "\(count)/\(maxCount)") + case .requestedUsersSelection: + let maxCount: Int32 = self.limit ?? 10 + var count = 0 + if case let .contacts(contactsNode) = self.contactsNode.contentNode { + count = contactsNode.selectionState?.selectedPeerIndices.count ?? 0 + } + self.titleView.title = CounterContollerTitle(title: self.presentationData.strings.RequestPeer_SelectUsers, counter: "\(count)/\(maxCount)") case .channelCreation: self.titleView.title = CounterContollerTitle(title: self.presentationData.strings.GroupInfo_AddParticipantTitle, counter: "") let rightNavigationButton = UIBarButtonItem(title: self.presentationData.strings.Common_Next, style: .done, target: self, action: #selector(self.rightNavigationButtonPressed)) @@ -325,7 +332,7 @@ class ContactMultiselectionControllerImpl: ViewController, ContactMultiselection switch strongSelf.mode { case .groupCreation, .peerSelection, .chatSelection: strongSelf.rightNavigationButton?.isEnabled = updatedCount != 0 || strongSelf.params.alwaysEnabled - case .channelCreation, .premiumGifting: + case .channelCreation, .premiumGifting, .requestedUsersSelection: break } @@ -334,8 +341,11 @@ class ContactMultiselectionControllerImpl: ViewController, ContactMultiselection let maxCount: Int32 = strongSelf.limitsConfiguration?.maxSupergroupMemberCount ?? 5000 strongSelf.titleView.title = CounterContollerTitle(title: strongSelf.presentationData.strings.Compose_NewGroupTitle, counter: "\(updatedCount)/\(maxCount)") case .premiumGifting: - let maxCount: Int32 = 10 + let maxCount: Int32 = strongSelf.limit ?? 10 strongSelf.titleView.title = CounterContollerTitle(title: strongSelf.presentationData.strings.Premium_Gift_ContactSelection_Title, counter: "\(updatedCount)/\(maxCount)") + case .requestedUsersSelection: + let maxCount: Int32 = strongSelf.limit ?? 10 + strongSelf.titleView.title = CounterContollerTitle(title: strongSelf.presentationData.strings.RequestPeer_SelectUsers, counter: "\(updatedCount)/\(maxCount)") case .peerSelection, .channelCreation, .chatSelection: break } @@ -407,7 +417,7 @@ class ContactMultiselectionControllerImpl: ViewController, ContactMultiselection switch strongSelf.mode { case .groupCreation, .peerSelection, .chatSelection: strongSelf.rightNavigationButton?.isEnabled = updatedCount != 0 || strongSelf.params.alwaysEnabled - case .channelCreation, .premiumGifting: + case .channelCreation, .premiumGifting, .requestedUsersSelection: break } switch strongSelf.mode { @@ -415,8 +425,11 @@ class ContactMultiselectionControllerImpl: ViewController, ContactMultiselection let maxCount: Int32 = strongSelf.limitsConfiguration?.maxSupergroupMemberCount ?? 5000 strongSelf.titleView.title = CounterContollerTitle(title: strongSelf.presentationData.strings.Compose_NewGroupTitle, counter: "\(updatedCount)/\(maxCount)") case .premiumGifting: - let maxCount: Int32 = 10 + let maxCount: Int32 = strongSelf.limit ?? 10 strongSelf.titleView.title = CounterContollerTitle(title: strongSelf.presentationData.strings.Premium_Gift_ContactSelection_Title, counter: "\(updatedCount)/\(maxCount)") + case .requestedUsersSelection: + let maxCount: Int32 = strongSelf.limit ?? 10 + strongSelf.titleView.title = CounterContollerTitle(title: strongSelf.presentationData.strings.RequestPeer_SelectUsers, counter: "\(updatedCount)/\(maxCount)") case .peerSelection, .channelCreation, .chatSelection: break } diff --git a/submodules/TelegramUI/Sources/ContactMultiselectionControllerNode.swift b/submodules/TelegramUI/Sources/ContactMultiselectionControllerNode.swift index 2035932f483..e09805422fe 100644 --- a/submodules/TelegramUI/Sources/ContactMultiselectionControllerNode.swift +++ b/submodules/TelegramUI/Sources/ContactMultiselectionControllerNode.swift @@ -108,6 +108,11 @@ final class ContactMultiselectionControllerNode: ASDisplayNode { self.footerPanelNode = FooterPanelNode(theme: self.presentationData.theme, strings: self.presentationData.strings, action: { proceedImpl?() }) + case .requestedUsersSelection: + placeholder = self.presentationData.strings.RequestPeer_SelectUsers_SearchPlaceholder + self.footerPanelNode = FooterPanelNode(theme: self.presentationData.theme, strings: self.presentationData.strings, action: { + proceedImpl?() + }) default: placeholder = self.presentationData.strings.Compose_TokenListPlaceholder self.footerPanelNode = nil @@ -149,6 +154,8 @@ final class ContactMultiselectionControllerNode: ASDisplayNode { var displayTopPeers = false if case .premiumGifting = mode { displayTopPeers = true + } else if case .requestedUsersSelection = mode { + displayTopPeers = true } self.contentNode = .contacts(ContactListNode(context: context, presentation: .single(.natural(options: options, includeChatList: includeChatList, topPeers: displayTopPeers)), filters: filters, selectionState: ContactListNodeGroupSelectionState())) } @@ -233,7 +240,7 @@ final class ContactMultiselectionControllerNode: ASDisplayNode { searchGroups = true searchChannels = true globalSearch = false - case .premiumGifting: + case .premiumGifting, .requestedUsersSelection: searchChatList = true } let searchResultsNode = ContactListNode(context: context, presentation: .single(.search(signal: searchText.get(), searchChatList: searchChatList, searchDeviceContacts: false, searchGroups: searchGroups, searchChannels: searchChannels, globalSearch: globalSearch)), filters: filters, isPeerEnabled: strongSelf.isPeerEnabled, selectionState: selectionState, isSearch: true) diff --git a/submodules/TelegramUI/Sources/OverlayAudioPlayerControllerNode.swift b/submodules/TelegramUI/Sources/OverlayAudioPlayerControllerNode.swift index 61cddab88ee..a9982911069 100644 --- a/submodules/TelegramUI/Sources/OverlayAudioPlayerControllerNode.swift +++ b/submodules/TelegramUI/Sources/OverlayAudioPlayerControllerNode.swift @@ -166,7 +166,7 @@ final class OverlayAudioPlayerControllerNode: ViewControllerTracingNode, UIGestu }, openJoinLink: { _ in }, openWebView: { _, _, _, _ in }, activateAdAction: { _ in - }, openRequestedPeerSelection: { _, _, _ in + }, openRequestedPeerSelection: { _, _, _, _ in }, saveMediaToFiles: { _ in }, openNoAdsDemo: { }, displayGiveawayParticipationStatus: { _ in diff --git a/submodules/TelegramUI/Sources/SharedAccountContext.swift b/submodules/TelegramUI/Sources/SharedAccountContext.swift index cfba962d1dd..1a52e57dc49 100644 --- a/submodules/TelegramUI/Sources/SharedAccountContext.swift +++ b/submodules/TelegramUI/Sources/SharedAccountContext.swift @@ -1670,7 +1670,7 @@ public final class SharedAccountContextImpl: SharedAccountContext { }, openJoinLink: { _ in }, openWebView: { _, _, _, _ in }, activateAdAction: { _ in - }, openRequestedPeerSelection: { _, _, _ in + }, openRequestedPeerSelection: { _, _, _, _ in }, saveMediaToFiles: { _ in }, openNoAdsDemo: { }, displayGiveawayParticipationStatus: { _ in