diff --git a/Telegram/Telegram-iOS/Resources/Requests.tgs b/Telegram/Telegram-iOS/Resources/Requests.tgs new file mode 100644 index 0000000000..e698808678 Binary files /dev/null and b/Telegram/Telegram-iOS/Resources/Requests.tgs differ diff --git a/Telegram/Telegram-iOS/en.lproj/Localizable.strings b/Telegram/Telegram-iOS/en.lproj/Localizable.strings index f87ee06cf0..b995a98026 100644 --- a/Telegram/Telegram-iOS/en.lproj/Localizable.strings +++ b/Telegram/Telegram-iOS/en.lproj/Localizable.strings @@ -6783,13 +6783,7 @@ Sorry for the inconvenience."; "SponsoredMessageMenu.Info" = "What are sponsored\nmessages?"; "SponsoredMessageInfoScreen.Title" = "What are sponsored messages?"; -"SponsoredMessageInfoScreen.Text" = "Unlike other apps, Telegram never uses your private data to target ads. You are seeing this message only because someone chose this public one-to many channel as a space to promote their messages. This means that no user data is mined or analyzed to display ads, and every user viewing a channel on Telegram sees the same sponsored message. - -Unline other apps, Telegram doesn't track whether you tapped on a sponsored message and doesn't profile you based on your activity. We also prevent external links in sponsored messages to ensure that third parties can't spy on our users. We believe that everyone has the right to privacy, and technological platforms should respect that. - -Telegram offers free and unlimited service to hundreds of millions of users, which involves significant server and traffic costs. In order to remain independent and stay true to its values, Telegram developed a paid tool to promote messages with user privacy in mind. We welcome responsible adverticers at: -[url] -Ads should no longer be synonymous with abuse of user privacy. Let us redefine how a tech compony should operate — together."; +"SponsoredMessageInfoScreen.Text" = "Unlike other apps, Telegram never uses your private data to target ads. You are seeing this message only because someone chose this public one-to many channel as a space to promote their messages. This means that no user data is mined or analyzed to display ads, and every user viewing a channel on Telegram sees the same sponsored message.\n\nUnline other apps, Telegram doesn't track whether you tapped on a sponsored message and doesn't profile you based on your activity. We also prevent external links in sponsored messages to ensure that third parties can't spy on our users. We believe that everyone has the right to privacy, and technological platforms should respect that.\n\nTelegram offers free and unlimited service to hundreds of millions of users, which involves significant server and traffic costs. In order to remain independent and stay true to its values, Telegram developed a paid tool to promote messages with user privacy in mind. We welcome responsible adverticers at:\n[url]\nAds should no longer be synonymous with abuse of user privacy. Let us redefine how a tech compony should operate — together."; "SponsoredMessageInfo.Action" = "Learn More"; "SponsoredMessageInfo.Url" = "https://telegram.org/ads"; diff --git a/submodules/Display/Source/NavigationBar.swift b/submodules/Display/Source/NavigationBar.swift index 94fa74f893..d81aa4cac9 100644 --- a/submodules/Display/Source/NavigationBar.swift +++ b/submodules/Display/Source/NavigationBar.swift @@ -1,5 +1,6 @@ import UIKit import AsyncDisplayKit +import SwiftSignalKit private var backArrowImageCache: [Int32: UIImage] = [:] @@ -146,7 +147,23 @@ public final class NavigationBackgroundNode: ASDisplayNode { self.updateColor(color: color, transition: .immediate) } + + public override func didLoad() { + super.didLoad() + + if self.scheduledUpdate { + self.scheduledUpdate = false + self.updateBackgroundBlur(forceKeepBlur: false) + } + } + + private var scheduledUpdate = false + private func updateBackgroundBlur(forceKeepBlur: Bool) { + guard self.isNodeLoaded else { + self.scheduledUpdate = true + return + } if self.enableBlur && !sharedIsReduceTransparencyEnabled && ((self._color.alpha > .ulpOfOne && self._color.alpha < 0.95) || forceKeepBlur) { if self.effectView == nil { let effectView = UIVisualEffectView(effect: UIBlurEffect(style: .light)) diff --git a/submodules/GraphUI/Sources/ChartStackSection.swift b/submodules/GraphUI/Sources/ChartStackSection.swift index 7f885a31f2..7e35df4bcc 100644 --- a/submodules/GraphUI/Sources/ChartStackSection.swift +++ b/submodules/GraphUI/Sources/ChartStackSection.swift @@ -18,12 +18,15 @@ private class LeftAlignedIconButton: UIButton { override func titleRect(forContentRect contentRect: CGRect) -> CGRect { var titleRect = super.titleRect(forContentRect: contentRect) let imageSize = currentImage?.size ?? .zero - titleRect.origin.x = imageSize.width + 2.0 -// -// let availableWidth = contentRect.width - imageEdgeInsets.right - imageSize.width - titleRect.width -// return titleRect.offsetBy(dx: round(availableWidth / 2) - imageEdgeInsets.left, dy: 0) + titleRect.origin.x = imageSize.width return titleRect } + + override func imageRect(forContentRect contentRect: CGRect) -> CGRect { + var imageRect = super.imageRect(forContentRect: contentRect) + imageRect.origin.x = 0.0 + return imageRect + } } class ChartStackSection: UIView, ChartThemeContainer { @@ -72,6 +75,7 @@ class ChartStackSection: UIView, ChartThemeContainer { backButton.setImage(UIImage(bundleImageName: "Chart/arrow_left"), for: .normal) backButton.imageEdgeInsets = UIEdgeInsets(top: 0.0, left: 6.0, bottom: 0.0, right: 3.0) backButton.imageView?.tintColor = UIColor(rgb: 0x007aff) + backButton.adjustsImageWhenHighlighted = false backButton.setVisible(false, animated: false) } @@ -172,7 +176,7 @@ class ChartStackSection: UIView, ChartThemeContainer { self.rangeView.frame = CGRect(origin: CGPoint(x: 0.0, y: 310.0), size: CGSize(width: bounds.width, height: 42.0)) self.visibilityView.frame = CGRect(origin: CGPoint(x: 0.0, y: self.displayRange ? 368.0 : 326.0), size: CGSize(width: bounds.width, height: 350.0)) - self.backButton.frame = CGRect(x: 0.0, y: 0.0, width: 96.0, height: 38.0) + self.backButton.frame = CGRect(x: 8.0, y: 0.0, width: 96.0, height: 38.0) self.chartView.setNeedsDisplay() } diff --git a/submodules/InviteLinksUI/Sources/InviteLinkHeaderItem.swift b/submodules/InviteLinksUI/Sources/InviteLinkHeaderItem.swift index 0a4afeebad..b76c282401 100644 --- a/submodules/InviteLinksUI/Sources/InviteLinkHeaderItem.swift +++ b/submodules/InviteLinksUI/Sources/InviteLinkHeaderItem.swift @@ -16,13 +16,15 @@ class InviteLinkHeaderItem: ListViewItem, ItemListItem { let context: AccountContext let theme: PresentationTheme let text: String + let animationName: String let sectionId: ItemListSectionId let linkAction: ((ItemListTextItemLinkAction) -> Void)? - init(context: AccountContext, theme: PresentationTheme, text: String, sectionId: ItemListSectionId, linkAction: ((ItemListTextItemLinkAction) -> Void)? = nil) { + init(context: AccountContext, theme: PresentationTheme, text: String, animationName: String, sectionId: ItemListSectionId, linkAction: ((ItemListTextItemLinkAction) -> Void)? = nil) { self.context = context self.theme = theme self.text = text + self.animationName = animationName self.sectionId = sectionId self.linkAction = linkAction } @@ -117,7 +119,7 @@ class InviteLinkHeaderItemNode: ListViewItemNode { return (layout, { [weak self] in if let strongSelf = self { if strongSelf.item == nil { - strongSelf.animationNode.setup(source: AnimatedStickerNodeLocalFileSource(name: "Invite"), width: 192, height: 192, playbackMode: .loop, mode: .direct(cachePathPrefix: nil)) + strongSelf.animationNode.setup(source: AnimatedStickerNodeLocalFileSource(name: item.animationName), width: 192, height: 192, playbackMode: .loop, mode: .direct(cachePathPrefix: nil)) strongSelf.animationNode.visibility = true } strongSelf.item = item diff --git a/submodules/InviteLinksUI/Sources/InviteLinkListController.swift b/submodules/InviteLinksUI/Sources/InviteLinkListController.swift index 67a87faaf3..d67da60464 100644 --- a/submodules/InviteLinksUI/Sources/InviteLinkListController.swift +++ b/submodules/InviteLinksUI/Sources/InviteLinkListController.swift @@ -210,7 +210,7 @@ private enum InviteLinksListEntry: ItemListNodeEntry { let arguments = arguments as! InviteLinkListControllerArguments switch self { case let .header(theme, text): - return InviteLinkHeaderItem(context: arguments.context, theme: theme, text: text, sectionId: self.section) + return InviteLinkHeaderItem(context: arguments.context, theme: theme, text: text, animationName: "Invite", sectionId: self.section) case let .mainLinkHeader(_, text): return ItemListSectionHeaderItem(presentationData: presentationData, text: text, sectionId: self.section) case let .mainLink(_, invite, peers, importersCount, isPublic): @@ -283,7 +283,7 @@ private func inviteLinkListControllerEntries(presentationData: PresentationData, let mainInvite: ExportedInvitation? var isPublic = false if let peer = peer, let address = peer.addressName, !address.isEmpty && admin == nil { - mainInvite = ExportedInvitation(link: "t.me/\(address)", isPermanent: true, requestApproval: false, isRevoked: false, adminId: EnginePeer.Id(0), date: 0, startDate: nil, expireDate: nil, usageLimit: nil, count: nil, approvedDate: nil) + mainInvite = ExportedInvitation(link: "t.me/\(address)", isPermanent: true, requestApproval: false, isRevoked: false, adminId: EnginePeer.Id(0), date: 0, startDate: nil, expireDate: nil, usageLimit: nil, count: nil, requestedCount: nil) isPublic = true } else if let invites = invites, let invite = invites.first(where: { $0.isPermanent && !$0.isRevoked }) { mainInvite = invite @@ -756,7 +756,7 @@ public func inviteLinkListController(context: AccountContext, updatedPresentatio |> distinctUntilChanged |> deliverOnMainQueue |> map { invite -> PeerInvitationImportersContext? in - return invite.flatMap { context.engine.peers.peerInvitationImporters(peerId: peerId, invite: $0) } + return invite.flatMap { context.engine.peers.peerInvitationImporters(peerId: peerId, subject: .invite(invite: $0, requested: false)) } } |> afterNext { context in if let context = context { importersState.set(context.state |> map(Optional.init)) diff --git a/submodules/InviteLinksUI/Sources/InviteLinkViewController.swift b/submodules/InviteLinksUI/Sources/InviteLinkViewController.swift index fd3bac1755..488637cacb 100644 --- a/submodules/InviteLinksUI/Sources/InviteLinkViewController.swift +++ b/submodules/InviteLinksUI/Sources/InviteLinkViewController.swift @@ -341,6 +341,7 @@ public final class InviteLinkViewController: ViewController { private let invite: ExportedInvitation private let importersContext: PeerInvitationImportersContext + private let requestsContext: PeerInvitationImportersContext? private var interaction: InviteLinkViewInteraction? @@ -376,7 +377,12 @@ public final class InviteLinkViewController: ViewController { self.presentationDataPromise = Promise(self.presentationData) self.controller = controller - self.importersContext = importersContext ?? context.engine.peers.peerInvitationImporters(peerId: peerId, invite: invite) + self.importersContext = importersContext ?? context.engine.peers.peerInvitationImporters(peerId: peerId, subject: .invite(invite: invite, requested: false)) + if invite.requestApproval { + self.requestsContext = context.engine.peers.peerInvitationImporters(peerId: peerId, subject: .invite(invite: invite, requested: true)) + } else { + self.requestsContext = nil + } self.dimNode = ASDisplayNode() self.dimNode.backgroundColor = UIColor(white: 0.0, alpha: 0.5) @@ -572,36 +578,32 @@ public final class InviteLinkViewController: ViewController { let previousCount = Atomic(value: nil) let previousLoading = Atomic(value: nil) + let requestsState: Signal + if let requestsContext = self.requestsContext { + requestsState = requestsContext.state + } else { + requestsState = .single(PeerInvitationImportersState.Empty) + } + let creatorPeer = context.account.postbox.loadedPeerWithId(invite.adminId) - self.disposable = (combineLatest(self.presentationDataPromise.get(), self.importersContext.state, creatorPeer) - |> deliverOnMainQueue).start(next: { [weak self] presentationData, state, creatorPeer in + self.disposable = (combineLatest(self.presentationDataPromise.get(), self.importersContext.state, requestsState, creatorPeer) + |> deliverOnMainQueue).start(next: { [weak self] presentationData, state, requestsState, creatorPeer in if let strongSelf = self { var entries: [InviteLinkViewEntry] = [] entries.append(.link(presentationData.theme, invite)) entries.append(.creatorHeader(presentationData.theme, presentationData.strings.InviteLink_CreatedBy.uppercased())) entries.append(.creator(presentationData.theme, presentationData.dateTimeFormat, EnginePeer(creatorPeer), invite.date)) - - if !state.importers.isEmpty || (state.isLoadingMore && state.count > 0) { - let subtitle: String - let subtitleExpired: Bool - if let usageLimit = invite.usageLimit { - let remaining = max(0, usageLimit - state.count) - subtitle = presentationData.strings.InviteLink_PeopleRemaining(remaining).uppercased() - subtitleExpired = remaining <= 0 - } else { - subtitle = "" - subtitleExpired = false - } - - entries.append(.importerHeader(presentationData.theme, presentationData.strings.InviteLink_PeopleJoined(Int32(state.count)).uppercased(), subtitle, subtitleExpired)) + + if !requestsState.importers.isEmpty || (state.isLoadingMore && requestsState.count > 0) { + entries.append(.importerHeader(presentationData.theme, presentationData.strings.MemberRequests_PeopleRequested(Int32(requestsState.count)).uppercased(), "", false)) } let count: Int32 let loading: Bool var index: Int32 = 0 - if state.importers.isEmpty && state.isLoadingMore { + if requestsState.importers.isEmpty && requestsState.isLoadingMore { count = min(4, state.count) loading = true let fakeUser = TelegramUser(id: EnginePeer.Id(namespace: .max, id: EnginePeer.Id.Id._internalFromInt64Value(0)), accessHash: nil, firstName: "", lastName: "", username: nil, phone: nil, photo: [], botInfo: nil, restrictionInfo: nil, flags: []) @@ -609,9 +611,9 @@ public final class InviteLinkViewController: ViewController { entries.append(.importer(Int32(i), presentationData.theme, presentationData.dateTimeFormat, EnginePeer.user(fakeUser), 0, true)) } } else { - count = min(4, Int32(state.importers.count)) + count = min(4, Int32(requestsState.importers.count)) loading = false - for importer in state.importers { + for importer in requestsState.importers { if let peer = importer.peer.peer { entries.append(.importer(index, presentationData.theme, presentationData.dateTimeFormat, EnginePeer(peer), importer.date, false)) } @@ -619,6 +621,43 @@ public final class InviteLinkViewController: ViewController { } } + // if !state.importers.isEmpty || (state.isLoadingMore && state.count > 0) { + // let subtitle: String + // let subtitleExpired: Bool + // if let usageLimit = invite.usageLimit { + // let remaining = max(0, usageLimit - state.count) + // subtitle = presentationData.strings.InviteLink_PeopleRemaining(remaining).uppercased() + // subtitleExpired = remaining <= 0 + // } else { + // subtitle = "" + // subtitleExpired = false + // } + // + // entries.append(.importerHeader(presentationData.theme, presentationData.strings.InviteLink_PeopleJoined(Int32(state.count)).uppercased(), subtitle, subtitleExpired)) + // } + +// let count: Int32 +// let loading: Bool +// +// var index: Int32 = 0 +// if state.importers.isEmpty && state.isLoadingMore { +// count = min(4, state.count) +// loading = true +// let fakeUser = TelegramUser(id: EnginePeer.Id(namespace: .max, id: EnginePeer.Id.Id._internalFromInt64Value(0)), accessHash: nil, firstName: "", lastName: "", username: nil, phone: nil, photo: [], botInfo: nil, restrictionInfo: nil, flags: []) +// for i in 0 ..< count { +// entries.append(.importer(Int32(i), presentationData.theme, presentationData.dateTimeFormat, EnginePeer.user(fakeUser), 0, true)) +// } +// } else { +// count = min(4, Int32(state.importers.count)) +// loading = false +// for importer in state.importers { +// if let peer = importer.peer.peer { +// entries.append(.importer(index, presentationData.theme, presentationData.dateTimeFormat, EnginePeer(peer), importer.date, false)) +// } +// index += 1 +// } +// } + let previousCount = previousCount.swap(count) let previousLoading = previousLoading.swap(loading) diff --git a/submodules/InviteLinksUI/Sources/InviteRequestsController.swift b/submodules/InviteLinksUI/Sources/InviteRequestsController.swift index d156597672..e8c5b16980 100644 --- a/submodules/InviteLinksUI/Sources/InviteRequestsController.swift +++ b/submodules/InviteLinksUI/Sources/InviteRequestsController.swift @@ -100,7 +100,7 @@ private enum InviteRequestsEntry: ItemListNodeEntry { let arguments = arguments as! InviteRequestsControllerArguments switch self { case let .header(theme, text): - return InviteLinkHeaderItem(context: arguments.context, theme: theme, text: text, sectionId: self.section, linkAction: { _ in + return InviteLinkHeaderItem(context: arguments.context, theme: theme, text: text, animationName: "Requests", sectionId: self.section, linkAction: { _ in arguments.openLinks() }) case let .requestsHeader(_, text): @@ -166,7 +166,7 @@ public func inviteRequestsController(context: AccountContext, updatedPresentatio var getControllerImpl: (() -> ViewController?)? - let importersContext = existingContext ?? context.engine.peers.peerInvitationImporters(peerId: peerId, invite: nil) + let importersContext = existingContext ?? context.engine.peers.peerInvitationImporters(peerId: peerId, subject: .requests(query: nil)) let arguments = InviteRequestsControllerArguments(context: context, openLinks: { let controller = inviteLinkListController(context: context, updatedPresentationData: updatedPresentationData, peerId: peerId, admin: nil) diff --git a/submodules/InviteLinksUI/Sources/ItemListInviteLinkItem.swift b/submodules/InviteLinksUI/Sources/ItemListInviteLinkItem.swift index dbcd124664..f73bd7646f 100644 --- a/submodules/InviteLinksUI/Sources/ItemListInviteLinkItem.swift +++ b/submodules/InviteLinksUI/Sources/ItemListInviteLinkItem.swift @@ -338,25 +338,34 @@ public class ItemListInviteLinkItemNode: ListViewItemNode, ItemListItemNode { let inviteLink = item.invite?.link.replacingOccurrences(of: "https://", with: "") ?? "" var titleText = inviteLink - + var subtitleText: String = "" var timerValue: TimerNode.Value? if let invite = item.invite { let count = invite.count ?? 0 + let requestedCount = invite.requestedCount ?? 0 + if count > 0 { - if invite.requestApproval { - subtitleText = item.presentationData.strings.MemberRequests_PeopleRequestedShort(count) - } else { - subtitleText = item.presentationData.strings.InviteLink_PeopleJoinedShort(count) - } + subtitleText = item.presentationData.strings.InviteLink_PeopleJoinedShort(count) } else { if let usageLimit = invite.usageLimit, count == 0 && !availability.isZero { subtitleText = item.presentationData.strings.InviteLink_PeopleCanJoin(usageLimit) } else { - subtitleText = availability.isZero ? item.presentationData.strings.InviteLink_PeopleJoinedShortNoneExpired : item.presentationData.strings.InviteLink_PeopleJoinedShortNone + if availability.isZero { + subtitleText = item.presentationData.strings.InviteLink_PeopleJoinedShortNoneExpired + } else if requestedCount == 0 { + subtitleText = item.presentationData.strings.InviteLink_PeopleJoinedShortNone + } } } + if requestedCount > 0 { + if !subtitleText.isEmpty { + subtitleText += ", " + } + subtitleText += item.presentationData.strings.MemberRequests_PeopleRequestedShort(requestedCount) + } + if invite.isRevoked { if !subtitleText.isEmpty { subtitleText += " • " diff --git a/submodules/InviteLinksUI/Sources/ItemListInviteRequestItem.swift b/submodules/InviteLinksUI/Sources/ItemListInviteRequestItem.swift index 961a9fdc72..d8c4a917b1 100644 --- a/submodules/InviteLinksUI/Sources/ItemListInviteRequestItem.swift +++ b/submodules/InviteLinksUI/Sources/ItemListInviteRequestItem.swift @@ -277,11 +277,7 @@ public class ItemListInviteRequestItemNode: ListViewItemNode, ItemListItemNode { if let importer = item.importer, let peer = importer.peer.peer.flatMap({ EnginePeer($0) }) { titleText = peer.displayTitle(strings: item.presentationData.strings, displayOrder: item.nameDisplayOrder) - if case .user = peer { - subtitleText = " " - } else { - subtitleText = "" - } + subtitleText = importer.about ?? "" let timestamp = Int32(CFAbsoluteTimeGetCurrent() + NSTimeIntervalSince1970) dateText = stringForRelativeTimestamp(strings: item.presentationData.strings, relativeTimestamp: importer.date, relativeTo: timestamp, dateTimeFormat: item.dateTimeFormat) } else { @@ -305,8 +301,10 @@ public class ItemListInviteRequestItemNode: ListViewItemNode, ItemListItemNode { let titleSpacing: CGFloat = 1.0 let minHeight: CGFloat = titleLayout.size.height + verticalInset * 2.0 - let rawHeight: CGFloat = verticalInset * 2.0 + titleLayout.size.height + titleSpacing + subtitleLayout.size.height + 24.0 - + var rawHeight: CGFloat = verticalInset * 2.0 + titleLayout.size.height + titleSpacing + 41.0 + if !subtitleLayout.size.height.isZero { + rawHeight += subtitleLayout.size.height + 5.0 + } var insets: UIEdgeInsets let itemBackgroundColor: UIColor let itemSeparatorColor: UIColor @@ -452,10 +450,10 @@ public class ItemListInviteRequestItemNode: ListViewItemNode, ItemListItemNode { strongSelf.dismissButton.setTitle(item.presentationData.strings.MemberRequests_Dismiss, with: Font.bold(15.0), with: item.presentationData.theme.list.itemAccentColor, for: .normal) let addHeight = strongSelf.addButton.updateLayout(width: 138.0, transition: .immediate) - strongSelf.addButton.frame = CGRect(x: leftInset, y: verticalInset + titleLayout.size.height + 7.0, width: 138.0, height: addHeight) + strongSelf.addButton.frame = CGRect(x: leftInset, y: contentSize.height - addHeight - 12.0, width: 138.0, height: addHeight) let dismissSize = strongSelf.dismissButton.measure(layout.size) - strongSelf.dismissButton.frame = CGRect(origin: CGPoint(x: leftInset + 138.0 + 24.0, y: verticalInset + titleLayout.size.height + 14.0), size: dismissSize) + strongSelf.dismissButton.frame = CGRect(origin: CGPoint(x: leftInset + 138.0 + 24.0, y: verticalInset + contentSize.height - addHeight - 14.0), size: dismissSize) if item.importer == nil { let shimmerNode: ShimmerEffectNode diff --git a/submodules/JoinLinkPreviewUI/Sources/JoinLinkPreviewController.swift b/submodules/JoinLinkPreviewUI/Sources/JoinLinkPreviewController.swift index 47f5121229..d151d46ff7 100644 --- a/submodules/JoinLinkPreviewUI/Sources/JoinLinkPreviewController.swift +++ b/submodules/JoinLinkPreviewUI/Sources/JoinLinkPreviewController.swift @@ -157,6 +157,8 @@ public final class JoinLinkPreviewController: ViewController { } case .tooMuchUsers: strongSelf.present(textAlertController(context: strongSelf.context, title: nil, text: strongSelf.presentationData.strings.Conversation_UsersTooMuchError, actions: [TextAlertAction(type: .defaultAction, title: strongSelf.presentationData.strings.Common_OK, action: {})]), in: .window(.root)) + case .requestSent: + break case .generic: break } diff --git a/submodules/TelegramApi/Sources/Api0.swift b/submodules/TelegramApi/Sources/Api0.swift index 8fab5231e4..aea40542c7 100644 --- a/submodules/TelegramApi/Sources/Api0.swift +++ b/submodules/TelegramApi/Sources/Api0.swift @@ -745,7 +745,7 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = { dict[-1625153079] = { return Api.InputWebFileLocation.parse_inputWebFileGeoPointLocation($0) } dict[-1275374751] = { return Api.EmojiLanguage.parse_emojiLanguage($0) } dict[1601666510] = { return Api.MessageFwdHeader.parse_messageFwdHeader($0) } - dict[708589599] = { return Api.SponsoredMessage.parse_sponsoredMessage($0) } + dict[-783162982] = { return Api.SponsoredMessage.parse_sponsoredMessage($0) } dict[-1012849566] = { return Api.BaseTheme.parse_baseThemeClassic($0) } dict[-69724536] = { return Api.BaseTheme.parse_baseThemeDay($0) } dict[-1212997976] = { return Api.BaseTheme.parse_baseThemeNight($0) } @@ -787,7 +787,7 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = { dict[-1673717362] = { return Api.InputPeerNotifySettings.parse_inputPeerNotifySettings($0) } dict[-1634752813] = { return Api.messages.FavedStickers.parse_favedStickersNotModified($0) } dict[750063767] = { return Api.messages.FavedStickers.parse_favedStickers($0) } - dict[19682803] = { return Api.ExportedChatInvite.parse_chatInviteExported($0) } + dict[-1283792928] = { return Api.ExportedChatInvite.parse_chatInviteExported($0) } dict[-1389486888] = { return Api.account.AuthorizationForm.parse_authorizationForm($0) } dict[-1392388579] = { return Api.Authorization.parse_authorization($0) } dict[-1361650766] = { return Api.MaskCoords.parse_maskCoords($0) } @@ -838,6 +838,7 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = { dict[-1781355374] = { return Api.MessageAction.parse_messageActionChannelCreate($0) } dict[-519864430] = { return Api.MessageAction.parse_messageActionChatMigrateTo($0) } dict[-365344535] = { return Api.MessageAction.parse_messageActionChannelMigrateFrom($0) } + dict[-339958837] = { return Api.MessageAction.parse_messageActionChatJoinedByRequest($0) } dict[-1799538451] = { return Api.MessageAction.parse_messageActionPinMessage($0) } dict[-1615153660] = { return Api.MessageAction.parse_messageActionHistoryClear($0) } dict[-1834538890] = { return Api.MessageAction.parse_messageActionGameScore($0) } @@ -856,7 +857,6 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = { dict[-1441072131] = { return Api.MessageAction.parse_messageActionSetMessagesTTL($0) } dict[-1281329567] = { return Api.MessageAction.parse_messageActionGroupCallScheduled($0) } dict[-1434950843] = { return Api.MessageAction.parse_messageActionSetChatTheme($0) } - dict[-339958837] = { return Api.MessageAction.parse_messageActionChatJoinedByRequest($0) } dict[1399245077] = { return Api.PhoneCall.parse_phoneCallEmpty($0) } dict[-987599081] = { return Api.PhoneCall.parse_phoneCallWaiting($0) } dict[347139340] = { return Api.PhoneCall.parse_phoneCallRequested($0) } diff --git a/submodules/TelegramApi/Sources/Api2.swift b/submodules/TelegramApi/Sources/Api2.swift index dcb98c3e98..6e0f5b914c 100644 --- a/submodules/TelegramApi/Sources/Api2.swift +++ b/submodules/TelegramApi/Sources/Api2.swift @@ -19396,17 +19396,18 @@ public extension Api { } public enum SponsoredMessage: TypeConstructorDescription { - case sponsoredMessage(flags: Int32, randomId: Buffer, fromId: Api.Peer, startParam: String?, message: String, entities: [Api.MessageEntity]?) + case sponsoredMessage(flags: Int32, randomId: Buffer, fromId: Api.Peer, channelPost: Int32?, startParam: String?, message: String, entities: [Api.MessageEntity]?) public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { switch self { - case .sponsoredMessage(let flags, let randomId, let fromId, let startParam, let message, let entities): + case .sponsoredMessage(let flags, let randomId, let fromId, let channelPost, let startParam, let message, let entities): if boxed { - buffer.appendInt32(708589599) + buffer.appendInt32(-783162982) } serializeInt32(flags, buffer: buffer, boxed: false) serializeBytes(randomId, buffer: buffer, boxed: false) fromId.serialize(buffer, true) + if Int(flags) & Int(1 << 2) != 0 {serializeInt32(channelPost!, buffer: buffer, boxed: false)} if Int(flags) & Int(1 << 0) != 0 {serializeString(startParam!, buffer: buffer, boxed: false)} serializeString(message, buffer: buffer, boxed: false) if Int(flags) & Int(1 << 1) != 0 {buffer.appendInt32(481674261) @@ -19420,8 +19421,8 @@ public extension Api { public func descriptionFields() -> (String, [(String, Any)]) { switch self { - case .sponsoredMessage(let flags, let randomId, let fromId, let startParam, let message, let entities): - return ("sponsoredMessage", [("flags", flags), ("randomId", randomId), ("fromId", fromId), ("startParam", startParam), ("message", message), ("entities", entities)]) + case .sponsoredMessage(let flags, let randomId, let fromId, let channelPost, let startParam, let message, let entities): + return ("sponsoredMessage", [("flags", flags), ("randomId", randomId), ("fromId", fromId), ("channelPost", channelPost), ("startParam", startParam), ("message", message), ("entities", entities)]) } } @@ -19434,22 +19435,25 @@ public extension Api { if let signature = reader.readInt32() { _3 = Api.parse(reader, signature: signature) as? Api.Peer } - var _4: String? - if Int(_1!) & Int(1 << 0) != 0 {_4 = parseString(reader) } + var _4: Int32? + if Int(_1!) & Int(1 << 2) != 0 {_4 = reader.readInt32() } var _5: String? - _5 = parseString(reader) - var _6: [Api.MessageEntity]? + if Int(_1!) & Int(1 << 0) != 0 {_5 = parseString(reader) } + var _6: String? + _6 = parseString(reader) + var _7: [Api.MessageEntity]? if Int(_1!) & Int(1 << 1) != 0 {if let _ = reader.readInt32() { - _6 = Api.parseVector(reader, elementSignature: 0, elementType: Api.MessageEntity.self) + _7 = Api.parseVector(reader, elementSignature: 0, elementType: Api.MessageEntity.self) } } let _c1 = _1 != nil let _c2 = _2 != nil let _c3 = _3 != nil - let _c4 = (Int(_1!) & Int(1 << 0) == 0) || _4 != nil - let _c5 = _5 != nil - let _c6 = (Int(_1!) & Int(1 << 1) == 0) || _6 != nil - if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 { - return Api.SponsoredMessage.sponsoredMessage(flags: _1!, randomId: _2!, fromId: _3!, startParam: _4, message: _5!, entities: _6) + let _c4 = (Int(_1!) & Int(1 << 2) == 0) || _4 != nil + let _c5 = (Int(_1!) & Int(1 << 0) == 0) || _5 != nil + let _c6 = _6 != nil + let _c7 = (Int(_1!) & Int(1 << 1) == 0) || _7 != nil + if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 { + return Api.SponsoredMessage.sponsoredMessage(flags: _1!, randomId: _2!, fromId: _3!, channelPost: _4, startParam: _5, message: _6!, entities: _7) } else { return nil @@ -20166,13 +20170,13 @@ public extension Api { } public enum ExportedChatInvite: TypeConstructorDescription { - case chatInviteExported(flags: Int32, link: String, adminId: Int64, date: Int32, startDate: Int32?, expireDate: Int32?, usageLimit: Int32?, usage: Int32?, approved: Int32?) + case chatInviteExported(flags: Int32, link: String, adminId: Int64, date: Int32, startDate: Int32?, expireDate: Int32?, usageLimit: Int32?, usage: Int32?, requested: Int32?) public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { switch self { - case .chatInviteExported(let flags, let link, let adminId, let date, let startDate, let expireDate, let usageLimit, let usage, let approved): + case .chatInviteExported(let flags, let link, let adminId, let date, let startDate, let expireDate, let usageLimit, let usage, let requested): if boxed { - buffer.appendInt32(19682803) + buffer.appendInt32(-1283792928) } serializeInt32(flags, buffer: buffer, boxed: false) serializeString(link, buffer: buffer, boxed: false) @@ -20182,15 +20186,15 @@ public extension Api { if Int(flags) & Int(1 << 1) != 0 {serializeInt32(expireDate!, buffer: buffer, boxed: false)} if Int(flags) & Int(1 << 2) != 0 {serializeInt32(usageLimit!, buffer: buffer, boxed: false)} if Int(flags) & Int(1 << 3) != 0 {serializeInt32(usage!, buffer: buffer, boxed: false)} - if Int(flags) & Int(1 << 7) != 0 {serializeInt32(approved!, buffer: buffer, boxed: false)} + if Int(flags) & Int(1 << 7) != 0 {serializeInt32(requested!, buffer: buffer, boxed: false)} break } } public func descriptionFields() -> (String, [(String, Any)]) { switch self { - case .chatInviteExported(let flags, let link, let adminId, let date, let startDate, let expireDate, let usageLimit, let usage, let approved): - return ("chatInviteExported", [("flags", flags), ("link", link), ("adminId", adminId), ("date", date), ("startDate", startDate), ("expireDate", expireDate), ("usageLimit", usageLimit), ("usage", usage), ("approved", approved)]) + case .chatInviteExported(let flags, let link, let adminId, let date, let startDate, let expireDate, let usageLimit, let usage, let requested): + return ("chatInviteExported", [("flags", flags), ("link", link), ("adminId", adminId), ("date", date), ("startDate", startDate), ("expireDate", expireDate), ("usageLimit", usageLimit), ("usage", usage), ("requested", requested)]) } } @@ -20223,7 +20227,7 @@ public extension Api { let _c8 = (Int(_1!) & Int(1 << 3) == 0) || _8 != nil let _c9 = (Int(_1!) & Int(1 << 7) == 0) || _9 != nil if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 && _c7 && _c8 && _c9 { - return Api.ExportedChatInvite.chatInviteExported(flags: _1!, link: _2!, adminId: _3!, date: _4!, startDate: _5, expireDate: _6, usageLimit: _7, usage: _8, approved: _9) + return Api.ExportedChatInvite.chatInviteExported(flags: _1!, link: _2!, adminId: _3!, date: _4!, startDate: _5, expireDate: _6, usageLimit: _7, usage: _8, requested: _9) } else { return nil @@ -21079,6 +21083,7 @@ public extension Api { case messageActionChannelCreate(title: String) case messageActionChatMigrateTo(channelId: Int64) case messageActionChannelMigrateFrom(title: String, chatId: Int64) + case messageActionChatJoinedByRequest case messageActionPinMessage case messageActionHistoryClear case messageActionGameScore(gameId: Int64, score: Int32) @@ -21097,7 +21102,6 @@ public extension Api { case messageActionSetMessagesTTL(period: Int32) case messageActionGroupCallScheduled(call: Api.InputGroupCall, scheduleDate: Int32) case messageActionSetChatTheme(emoticon: String) - case messageActionChatJoinedByRequest public func serialize(_ buffer: Buffer, _ boxed: Swift.Bool) { switch self { @@ -21176,6 +21180,12 @@ public extension Api { } serializeString(title, buffer: buffer, boxed: false) serializeInt64(chatId, buffer: buffer, boxed: false) + break + case .messageActionChatJoinedByRequest: + if boxed { + buffer.appendInt32(-339958837) + } + break case .messageActionPinMessage: if boxed { @@ -21314,12 +21324,6 @@ public extension Api { buffer.appendInt32(-1434950843) } serializeString(emoticon, buffer: buffer, boxed: false) - break - case .messageActionChatJoinedByRequest: - if boxed { - buffer.appendInt32(-339958837) - } - break } } @@ -21348,6 +21352,8 @@ public extension Api { return ("messageActionChatMigrateTo", [("channelId", channelId)]) case .messageActionChannelMigrateFrom(let title, let chatId): return ("messageActionChannelMigrateFrom", [("title", title), ("chatId", chatId)]) + case .messageActionChatJoinedByRequest: + return ("messageActionChatJoinedByRequest", []) case .messageActionPinMessage: return ("messageActionPinMessage", []) case .messageActionHistoryClear: @@ -21384,8 +21390,6 @@ public extension Api { return ("messageActionGroupCallScheduled", [("call", call), ("scheduleDate", scheduleDate)]) case .messageActionSetChatTheme(let emoticon): return ("messageActionSetChatTheme", [("emoticon", emoticon)]) - case .messageActionChatJoinedByRequest: - return ("messageActionChatJoinedByRequest", []) } } @@ -21506,6 +21510,9 @@ public extension Api { return nil } } + public static func parse_messageActionChatJoinedByRequest(_ reader: BufferReader) -> MessageAction? { + return Api.MessageAction.messageActionChatJoinedByRequest + } public static func parse_messageActionPinMessage(_ reader: BufferReader) -> MessageAction? { return Api.MessageAction.messageActionPinMessage } @@ -21750,9 +21757,6 @@ public extension Api { return nil } } - public static func parse_messageActionChatJoinedByRequest(_ reader: BufferReader) -> MessageAction? { - return Api.MessageAction.messageActionChatJoinedByRequest - } } public enum PhoneCall: TypeConstructorDescription { diff --git a/submodules/TelegramApi/Sources/Api4.swift b/submodules/TelegramApi/Sources/Api4.swift index 4df54958c7..6ceff156f5 100644 --- a/submodules/TelegramApi/Sources/Api4.swift +++ b/submodules/TelegramApi/Sources/Api4.swift @@ -4371,16 +4371,17 @@ public extension Api { }) } - public static func getChatInviteImporters(flags: Int32, peer: Api.InputPeer, link: String?, offsetDate: Int32, offsetUser: Api.InputUser, limit: Int32) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + public static func getChatInviteImporters(flags: Int32, peer: Api.InputPeer, link: String?, q: String?, offsetDate: Int32, offsetUser: Api.InputUser, limit: Int32) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { let buffer = Buffer() - buffer.appendInt32(-1742901790) + buffer.appendInt32(-553329330) serializeInt32(flags, buffer: buffer, boxed: false) peer.serialize(buffer, true) if Int(flags) & Int(1 << 1) != 0 {serializeString(link!, buffer: buffer, boxed: false)} + if Int(flags) & Int(1 << 2) != 0 {serializeString(q!, buffer: buffer, boxed: false)} serializeInt32(offsetDate, buffer: buffer, boxed: false) offsetUser.serialize(buffer, true) serializeInt32(limit, buffer: buffer, boxed: false) - return (FunctionDescription(name: "messages.getChatInviteImporters", parameters: [("flags", flags), ("peer", peer), ("link", link), ("offsetDate", offsetDate), ("offsetUser", offsetUser), ("limit", limit)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.messages.ChatInviteImporters? in + return (FunctionDescription(name: "messages.getChatInviteImporters", parameters: [("flags", flags), ("peer", peer), ("link", link), ("q", q), ("offsetDate", offsetDate), ("offsetUser", offsetUser), ("limit", limit)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.messages.ChatInviteImporters? in let reader = BufferReader(buffer) var result: Api.messages.ChatInviteImporters? if let signature = reader.readInt32() { @@ -4484,6 +4485,22 @@ public extension Api { }) } + public static func hideChatJoinRequest(flags: Int32, peer: Api.InputPeer, userId: Api.InputUser) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { + let buffer = Buffer() + buffer.appendInt32(2145904661) + serializeInt32(flags, buffer: buffer, boxed: false) + peer.serialize(buffer, true) + userId.serialize(buffer, true) + return (FunctionDescription(name: "messages.hideChatJoinRequest", parameters: [("flags", flags), ("peer", peer), ("userId", userId)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.Updates? in + let reader = BufferReader(buffer) + var result: Api.Updates? + if let signature = reader.readInt32() { + result = Api.parse(reader, signature: signature) as? Api.Updates + } + return result + }) + } + public static func getSearchResultsPositions(peer: Api.InputPeer, filter: Api.MessagesFilter, offsetId: Int32, limit: Int32) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { let buffer = Buffer() buffer.appendInt32(1855292323) @@ -4500,22 +4517,6 @@ public extension Api { return result }) } - - public static func hideChatJoinRequest(flags: Int32, peer: Api.InputPeer, userId: Api.InputUser) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { - let buffer = Buffer() - buffer.appendInt32(2145904661) - serializeInt32(flags, buffer: buffer, boxed: false) - peer.serialize(buffer, true) - userId.serialize(buffer, true) - return (FunctionDescription(name: "messages.hideChatJoinRequest", parameters: [("flags", flags), ("peer", peer), ("userId", userId)]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.Updates? in - let reader = BufferReader(buffer) - var result: Api.Updates? - if let signature = reader.readInt32() { - result = Api.parse(reader, signature: signature) as? Api.Updates - } - return result - }) - } } public struct channels { public static func readHistory(channel: Api.InputChannel, maxId: Int32) -> (FunctionDescription, Buffer, DeserializeFunctionResponse) { diff --git a/submodules/TelegramCore/Sources/ApiUtils/ExportedInvitation.swift b/submodules/TelegramCore/Sources/ApiUtils/ExportedInvitation.swift index 2d5d0b3ed3..448c5f9469 100644 --- a/submodules/TelegramCore/Sources/ApiUtils/ExportedInvitation.swift +++ b/submodules/TelegramCore/Sources/ApiUtils/ExportedInvitation.swift @@ -6,8 +6,8 @@ import TelegramApi extension ExportedInvitation { init(apiExportedInvite: Api.ExportedChatInvite) { switch apiExportedInvite { - case let .chatInviteExported(flags, link, adminId, date, startDate, expireDate, usageLimit, usage, approved): - self = ExportedInvitation(link: link, isPermanent: (flags & (1 << 5)) != 0, requestApproval: (flags & (1 << 6)) != 0, isRevoked: (flags & (1 << 0)) != 0, adminId: PeerId(namespace: Namespaces.Peer.CloudUser, id: PeerId.Id._internalFromInt64Value(adminId)), date: date, startDate: startDate, expireDate: expireDate, usageLimit: usageLimit, count: usage, approvedDate: approved) + case let .chatInviteExported(flags, link, adminId, date, startDate, expireDate, usageLimit, usage, requested): + self = ExportedInvitation(link: link, isPermanent: (flags & (1 << 5)) != 0, requestApproval: (flags & (1 << 6)) != 0, isRevoked: (flags & (1 << 0)) != 0, adminId: PeerId(namespace: Namespaces.Peer.CloudUser, id: PeerId.Id._internalFromInt64Value(adminId)), date: date, startDate: startDate, expireDate: expireDate, usageLimit: usageLimit, count: usage, requestedCount: requested) } } } diff --git a/submodules/TelegramCore/Sources/SyncCore/SyncCore_ExportedInvitation.swift b/submodules/TelegramCore/Sources/SyncCore/SyncCore_ExportedInvitation.swift index 10f45a0b04..1889aa1e77 100644 --- a/submodules/TelegramCore/Sources/SyncCore/SyncCore_ExportedInvitation.swift +++ b/submodules/TelegramCore/Sources/SyncCore/SyncCore_ExportedInvitation.swift @@ -11,9 +11,9 @@ public struct ExportedInvitation: Codable, Equatable { public let expireDate: Int32? public let usageLimit: Int32? public let count: Int32? - public let approvedDate: Int32? + public let requestedCount: Int32? - public init(link: String, isPermanent: Bool, requestApproval: Bool, isRevoked: Bool, adminId: PeerId, date: Int32, startDate: Int32?, expireDate: Int32?, usageLimit: Int32?, count: Int32?, approvedDate: Int32?) { + public init(link: String, isPermanent: Bool, requestApproval: Bool, isRevoked: Bool, adminId: PeerId, date: Int32, startDate: Int32?, expireDate: Int32?, usageLimit: Int32?, count: Int32?, requestedCount: Int32?) { self.link = link self.isPermanent = isPermanent self.requestApproval = requestApproval @@ -24,7 +24,7 @@ public struct ExportedInvitation: Codable, Equatable { self.expireDate = expireDate self.usageLimit = usageLimit self.count = count - self.approvedDate = approvedDate + self.requestedCount = requestedCount } public init(from decoder: Decoder) throws { @@ -40,7 +40,7 @@ public struct ExportedInvitation: Codable, Equatable { self.expireDate = try container.decodeIfPresent(Int32.self, forKey: "expireDate") self.usageLimit = try container.decodeIfPresent(Int32.self, forKey: "usageLimit") self.count = try container.decodeIfPresent(Int32.self, forKey: "count") - self.approvedDate = try? container.decodeIfPresent(Int32.self, forKey: "approvedDate") + self.requestedCount = try? container.decodeIfPresent(Int32.self, forKey: "requestedCount") } public func encode(to encoder: Encoder) throws { @@ -56,14 +56,14 @@ public struct ExportedInvitation: Codable, Equatable { try container.encodeIfPresent(self.expireDate, forKey: "expireDate") try container.encodeIfPresent(self.usageLimit, forKey: "usageLimit") try container.encodeIfPresent(self.count, forKey: "count") - try container.encodeIfPresent(self.approvedDate, forKey: "approvedDate") + try container.encodeIfPresent(self.requestedCount, forKey: "requestedCount") } public static func ==(lhs: ExportedInvitation, rhs: ExportedInvitation) -> Bool { - return lhs.link == rhs.link && lhs.isPermanent == rhs.isPermanent && lhs.requestApproval == rhs.requestApproval && lhs.isRevoked == rhs.isRevoked && lhs.adminId == rhs.adminId && lhs.date == rhs.date && lhs.startDate == rhs.startDate && lhs.expireDate == rhs.expireDate && lhs.usageLimit == rhs.usageLimit && lhs.count == rhs.count && lhs.approvedDate == rhs.approvedDate + return lhs.link == rhs.link && lhs.isPermanent == rhs.isPermanent && lhs.requestApproval == rhs.requestApproval && lhs.isRevoked == rhs.isRevoked && lhs.adminId == rhs.adminId && lhs.date == rhs.date && lhs.startDate == rhs.startDate && lhs.expireDate == rhs.expireDate && lhs.usageLimit == rhs.usageLimit && lhs.count == rhs.count && lhs.requestedCount == rhs.requestedCount } public func withUpdated(isRevoked: Bool) -> ExportedInvitation { - return ExportedInvitation(link: self.link, isPermanent: self.isPermanent, requestApproval: self.requestApproval, isRevoked: isRevoked, adminId: self.adminId, date: self.date, startDate: self.startDate, expireDate: self.expireDate, usageLimit: self.usageLimit, count: self.count, approvedDate: self.approvedDate) + return ExportedInvitation(link: self.link, isPermanent: self.isPermanent, requestApproval: self.requestApproval, isRevoked: isRevoked, adminId: self.adminId, date: self.date, startDate: self.startDate, expireDate: self.expireDate, usageLimit: self.usageLimit, count: self.count, requestedCount: self.requestedCount) } } diff --git a/submodules/TelegramCore/Sources/TelegramEngine/Messages/AdMessages.swift b/submodules/TelegramCore/Sources/TelegramEngine/Messages/AdMessages.swift index 6c87d81cb6..1671d33c1d 100644 --- a/submodules/TelegramCore/Sources/TelegramEngine/Messages/AdMessages.swift +++ b/submodules/TelegramCore/Sources/TelegramEngine/Messages/AdMessages.swift @@ -11,6 +11,7 @@ private class AdMessagesHistoryContextImpl { case textEntities case media case authorId + case messageId case startParam } @@ -19,6 +20,7 @@ private class AdMessagesHistoryContextImpl { public let textEntities: [MessageTextEntity] public let media: [Media] public let authorId: PeerId + public let messageId: MessageId? public let startParam: String? public init( @@ -27,6 +29,7 @@ private class AdMessagesHistoryContextImpl { textEntities: [MessageTextEntity], media: [Media], authorId: PeerId, + messageId: MessageId?, startParam: String? ) { self.opaqueId = opaqueId @@ -34,6 +37,7 @@ private class AdMessagesHistoryContextImpl { self.textEntities = textEntities self.media = media self.authorId = authorId + self.messageId = messageId self.startParam = startParam } @@ -51,7 +55,7 @@ private class AdMessagesHistoryContextImpl { } self.authorId = try container.decode(PeerId.self, forKey: .authorId) - + self.messageId = try container.decodeIfPresent(MessageId.self, forKey: .messageId) self.startParam = try container.decodeIfPresent(String.self, forKey: .startParam) } @@ -70,6 +74,7 @@ private class AdMessagesHistoryContextImpl { try container.encode(mediaData, forKey: .media) try container.encode(self.authorId, forKey: .authorId) + try container.encodeIfPresent(self.messageId, forKey: .messageId) try container.encodeIfPresent(self.startParam, forKey: .startParam) } @@ -94,6 +99,9 @@ private class AdMessagesHistoryContextImpl { if lhs.authorId != rhs.authorId { return false } + if lhs.messageId != rhs.messageId { + return false + } if lhs.startParam != rhs.startParam { return false } @@ -317,7 +325,7 @@ private class AdMessagesHistoryContextImpl { for message in messages { switch message { - case let .sponsoredMessage(_, randomId, fromId, startParam, message, entities): + case let .sponsoredMessage(_, randomId, fromId, channelPost, startParam, message, entities): var parsedEntities: [MessageTextEntity] = [] if let entities = entities { parsedEntities = messageTextEntitiesFromApiEntities(entities) @@ -337,6 +345,7 @@ private class AdMessagesHistoryContextImpl { textEntities: parsedEntities, media: parsedMedia, authorId: fromId.peerId, + messageId: channelPost.flatMap { MessageId(peerId: fromId.peerId, namespace: Namespaces.Message.Cloud, id: $0) }, startParam: startParam )) } diff --git a/submodules/TelegramCore/Sources/TelegramEngine/Peers/InvitationLinks.swift b/submodules/TelegramCore/Sources/TelegramEngine/Peers/InvitationLinks.swift index 85b8fa9c9d..4ef602b7c0 100644 --- a/submodules/TelegramCore/Sources/TelegramEngine/Peers/InvitationLinks.swift +++ b/submodules/TelegramCore/Sources/TelegramEngine/Peers/InvitationLinks.swift @@ -655,6 +655,8 @@ public struct PeerInvitationImportersState: Equatable { public var waitingCount: Int { return importers.filter { $0.approvedBy == nil }.count } + + public static var Empty = PeerInvitationImportersState(importers: [], isLoadingMore: false, hasLoadedOnce: true, canLoadMore: false, count: 0) } final class CachedPeerInvitationImporters: Codable { @@ -662,10 +664,10 @@ final class CachedPeerInvitationImporters: Codable { let dates: [PeerId: Int32] let count: Int32 - static func key(peerId: PeerId, link: String) -> ValueBoxKey { + static func key(peerId: PeerId, link: String, requested: Bool) -> ValueBoxKey { let key = ValueBoxKey(length: 8 + 4) key.setInt64(0, value: peerId.toInt64()) - key.setInt32(8, value: Int32(HashFunctions.murMurHash32(link))) + key.setInt32(8, value: Int32(HashFunctions.murMurHash32(link + (requested ? "_requested" : "")))) return key } @@ -722,6 +724,8 @@ private final class PeerInvitationImportersContextImpl { private let account: Account private let peerId: PeerId private let link: String? + private let requested: Bool + private let query: String? private let disposable = MetaDisposable() private let updateDisposable = MetaDisposable() private let actionDisposables = DisposableSet() @@ -735,18 +739,34 @@ private final class PeerInvitationImportersContextImpl { let state = Promise() - init(queue: Queue, account: Account, peerId: PeerId, invite: ExportedInvitation?) { + init(queue: Queue, account: Account, peerId: PeerId, subject: PeerInvitationImportersContext.Subject) { self.queue = queue self.account = account self.peerId = peerId + + var invite: ExportedInvitation? + var requested = false + var query: String? + switch subject { + case let .invite(subjectInvite, subjectRequested): + invite = subjectInvite + requested = subjectRequested + case let .requests(maybeQuery): + query = maybeQuery + } self.link = invite?.link + self.requested = requested + self.query = query let count = invite?.count ?? 0 self.count = count self.isLoadingMore = true self.disposable.set((account.postbox.transaction { transaction -> (peers: [PeerInvitationImportersState.Importer], count: Int32, canLoadMore: Bool)? in - let cachedResult = transaction.retrieveItemCacheEntry(id: ItemCacheEntryId(collectionId: Namespaces.CachedItemCollection.cachedPeerInvitationImporters, key: CachedPeerInvitationImporters.key(peerId: peerId, link: invite?.link ?? "requests")))?.get(CachedPeerInvitationImporters.self) + guard query == nil else { + return nil + } + let cachedResult = transaction.retrieveItemCacheEntry(id: ItemCacheEntryId(collectionId: Namespaces.CachedItemCollection.cachedPeerInvitationImporters, key: CachedPeerInvitationImporters.key(peerId: peerId, link: invite?.link ?? "requests", requested: self.requested)))?.get(CachedPeerInvitationImporters.self) if let cachedResult = cachedResult, (Int(cachedResult.count) == count || invite == nil) { var result: [PeerInvitationImportersState.Importer] = [] for peerId in cachedResult.peerIds { @@ -794,6 +814,7 @@ private final class PeerInvitationImportersContextImpl { let peerId = self.peerId let link = self.link let populateCache = self.populateCache + let query = self.query var lastResult = self.results.last if self.loadedFromCache { @@ -811,12 +832,19 @@ private final class PeerInvitationImportersContextImpl { var flags: Int32 = 0 if let _ = link { + if self.requested { + flags |= (1 << 0) + } flags |= (1 << 1) } else { flags |= (1 << 0) } - let signal = account.network.request(Api.functions.messages.getChatInviteImporters(flags: flags, peer: inputPeer, link: link, offsetDate: offsetDate, offsetUser: offsetUser, limit: lastResult == nil ? 10 : 50)) + if let _ = query { + flags |= (1 << 2) + } + + let signal = account.network.request(Api.functions.messages.getChatInviteImporters(flags: flags, peer: inputPeer, link: link, q: query, offsetDate: offsetDate, offsetUser: offsetUser, limit: lastResult == nil ? 10 : 50)) |> map(Optional.init) |> `catch` { _ -> Signal in return .single(nil) @@ -852,9 +880,9 @@ private final class PeerInvitationImportersContextImpl { resultImporters.append(PeerInvitationImportersState.Importer(peer: RenderedPeer(peer: peer), date: date, about: about, approvedBy: approvedBy)) } } - if populateCache { + if populateCache && query == nil { if let entry = CodableEntry(CachedPeerInvitationImporters(importers: resultImporters, count: count)) { - transaction.putItemCacheEntry(id: ItemCacheEntryId(collectionId: Namespaces.CachedItemCollection.cachedPeerInvitationImporters, key: CachedPeerInvitationImporters.key(peerId: peerId, link: link ?? "requests")), entry: entry, collectionSpec: cachedPeerInvitationImportersCollectionSpec) + transaction.putItemCacheEntry(id: ItemCacheEntryId(collectionId: Namespaces.CachedItemCollection.cachedPeerInvitationImporters, key: CachedPeerInvitationImporters.key(peerId: peerId, link: link ?? "requests", requested: self.requested)), entry: entry, collectionSpec: cachedPeerInvitationImportersCollectionSpec) } } return (resultImporters, count) @@ -906,7 +934,7 @@ private final class PeerInvitationImportersContextImpl { } private func updateCache() { - guard self.hasLoadedOnce && !self.isLoadingMore else { + guard self.hasLoadedOnce && !self.isLoadingMore && self.query == nil else { return } @@ -916,7 +944,7 @@ private final class PeerInvitationImportersContextImpl { let link = self.link self.updateDisposable.set(self.account.postbox.transaction({ transaction in if let entry = CodableEntry(CachedPeerInvitationImporters(importers: resultImporters, count: count)) { - transaction.putItemCacheEntry(id: ItemCacheEntryId(collectionId: Namespaces.CachedItemCollection.cachedPeerInvitationImporters, key: CachedPeerInvitationImporters.key(peerId: peerId, link: link ?? "requests")), entry: entry, collectionSpec: cachedPeerInvitationImportersCollectionSpec) + transaction.putItemCacheEntry(id: ItemCacheEntryId(collectionId: Namespaces.CachedItemCollection.cachedPeerInvitationImporters, key: CachedPeerInvitationImporters.key(peerId: peerId, link: link ?? "requests", requested: self.requested)), entry: entry, collectionSpec: cachedPeerInvitationImportersCollectionSpec) } }).start()) } @@ -927,6 +955,11 @@ private final class PeerInvitationImportersContextImpl { } public final class PeerInvitationImportersContext { + public enum Subject { + case invite(invite: ExportedInvitation, requested: Bool) + case requests(query: String?) + } + public enum UpdateAction { case approve case deny @@ -947,10 +980,10 @@ public final class PeerInvitationImportersContext { } } - init(account: Account, peerId: PeerId, invite: ExportedInvitation?) { + init(account: Account, peerId: PeerId, subject: Subject) { let queue = self.queue self.impl = QueueLocalObject(queue: queue, generate: { - return PeerInvitationImportersContextImpl(queue: queue, account: account, peerId: peerId, invite: invite) + return PeerInvitationImportersContextImpl(queue: queue, account: account, peerId: peerId, subject: subject) }) } diff --git a/submodules/TelegramCore/Sources/TelegramEngine/Peers/JoinLink.swift b/submodules/TelegramCore/Sources/TelegramEngine/Peers/JoinLink.swift index 6ee6178feb..4b8dd9984f 100644 --- a/submodules/TelegramCore/Sources/TelegramEngine/Peers/JoinLink.swift +++ b/submodules/TelegramCore/Sources/TelegramEngine/Peers/JoinLink.swift @@ -8,6 +8,7 @@ public enum JoinLinkError { case generic case tooMuchJoined case tooMuchUsers + case requestSent } func apiUpdatesGroups(_ updates: Api.Updates) -> [Api.Chat] { @@ -44,6 +45,8 @@ func _internal_joinChatInteractively(with hash: String, account: Account) -> Sig return .tooMuchJoined case "USERS_TOO_MUCH": return .tooMuchUsers + case "INVITE_REQUEST_SENT": + return .requestSent default: return .generic } diff --git a/submodules/TelegramCore/Sources/TelegramEngine/Peers/TelegramEnginePeers.swift b/submodules/TelegramCore/Sources/TelegramEngine/Peers/TelegramEnginePeers.swift index a9bc529b64..ecccb96e0f 100644 --- a/submodules/TelegramCore/Sources/TelegramEngine/Peers/TelegramEnginePeers.swift +++ b/submodules/TelegramCore/Sources/TelegramEngine/Peers/TelegramEnginePeers.swift @@ -454,8 +454,8 @@ public extension TelegramEngine { return _internal_revokePersistentPeerExportedInvitation(account: self.account, peerId: peerId) } - public func peerInvitationImporters(peerId: PeerId, invite: ExportedInvitation?) -> PeerInvitationImportersContext { - return PeerInvitationImportersContext(account: self.account, peerId: peerId, invite: invite) + public func peerInvitationImporters(peerId: PeerId, subject: PeerInvitationImportersContext.Subject) -> PeerInvitationImportersContext { + return PeerInvitationImportersContext(account: self.account, peerId: peerId, subject: subject) } public func notificationExceptionsList() -> Signal { diff --git a/submodules/TelegramUI/Images.xcassets/Chat/Info/GroupRequestsIcon.imageset/Contents.json b/submodules/TelegramUI/Images.xcassets/Chat/Info/GroupRequestsIcon.imageset/Contents.json new file mode 100644 index 0000000000..049209d34f --- /dev/null +++ b/submodules/TelegramUI/Images.xcassets/Chat/Info/GroupRequestsIcon.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "Requests@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/submodules/TelegramUI/Images.xcassets/Chat/Info/GroupRequestsIcon.imageset/Requests@3x.png b/submodules/TelegramUI/Images.xcassets/Chat/Info/GroupRequestsIcon.imageset/Requests@3x.png new file mode 100644 index 0000000000..b853894a8b Binary files /dev/null and b/submodules/TelegramUI/Images.xcassets/Chat/Info/GroupRequestsIcon.imageset/Requests@3x.png differ diff --git a/submodules/TelegramUI/Sources/ChatController.swift b/submodules/TelegramUI/Sources/ChatController.swift index 944a29b9fd..93e0ba7cec 100644 --- a/submodules/TelegramUI/Sources/ChatController.swift +++ b/submodules/TelegramUI/Sources/ChatController.swift @@ -4802,7 +4802,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G } if canManageInvitations, let inviteRequestsPending = inviteRequestsPending, inviteRequestsPending >= 0, strongSelf.inviteRequestsContext == nil { - let inviteRequestsContext = strongSelf.context.engine.peers.peerInvitationImporters(peerId: peerId, invite: nil) + let inviteRequestsContext = strongSelf.context.engine.peers.peerInvitationImporters(peerId: peerId, subject: .requests(query: nil)) strongSelf.inviteRequestsContext = inviteRequestsContext strongSelf.inviteRequestsDisposable.set((inviteRequestsContext.state diff --git a/submodules/TelegramUI/Sources/PeerInfo/PeerInfoData.swift b/submodules/TelegramUI/Sources/PeerInfo/PeerInfoData.swift index ef19c33b1b..2d5a94c80a 100644 --- a/submodules/TelegramUI/Sources/PeerInfo/PeerInfoData.swift +++ b/submodules/TelegramUI/Sources/PeerInfo/PeerInfoData.swift @@ -666,7 +666,7 @@ func peerInfoScreenData(context: AccountContext, peerId: PeerId, strings: Presen if currentRequestsContext == nil { if canManageInvitations { - let requestsContext = context.engine.peers.peerInvitationImporters(peerId: peerId, invite: nil) + let requestsContext = context.engine.peers.peerInvitationImporters(peerId: peerId, subject: .requests(query: nil)) requestsContextPromise.set(.single(requestsContext)) requestsStatePromise.set(requestsContext.state |> map(Optional.init)) } @@ -843,7 +843,7 @@ func peerInfoScreenData(context: AccountContext, peerId: PeerId, strings: Presen if currentRequestsContext == nil { if canManageInvitations { - let requestsContext = context.engine.peers.peerInvitationImporters(peerId: peerId, invite: nil) + let requestsContext = context.engine.peers.peerInvitationImporters(peerId: peerId, subject: .requests(query: nil)) requestsContextPromise.set(.single(requestsContext)) requestsStatePromise.set(requestsContext.state |> map(Optional.init)) } diff --git a/submodules/TelegramUI/Sources/PeerInfo/PeerInfoScreen.swift b/submodules/TelegramUI/Sources/PeerInfo/PeerInfoScreen.swift index bf7f9d7fe8..df8f2f6109 100644 --- a/submodules/TelegramUI/Sources/PeerInfo/PeerInfoScreen.swift +++ b/submodules/TelegramUI/Sources/PeerInfo/PeerInfoScreen.swift @@ -1112,7 +1112,7 @@ private func infoItems(data: PeerInfoScreenData?, context: AccountContext, prese })) if let count = data.requests?.count, count > 0 { - items[.peerInfo]!.append(PeerInfoScreenDisclosureItem(id: ItemMemberRequests, label: .badge(presentationStringsFormattedNumber(count, presentationData.dateTimeFormat.groupingSeparator), presentationData.theme.list.itemAccentColor), text: presentationData.strings.GroupInfo_MemberRequests, icon: UIImage(bundleImageName: "Chat/Info/GroupMembersIcon"), action: { + items[.peerInfo]!.append(PeerInfoScreenDisclosureItem(id: ItemMemberRequests, label: .badge(presentationStringsFormattedNumber(count, presentationData.dateTimeFormat.groupingSeparator), presentationData.theme.list.itemAccentColor), text: presentationData.strings.GroupInfo_MemberRequests, icon: UIImage(bundleImageName: "Chat/Info/GroupRequestsIcon"), action: { interaction.openParticipantsSection(.memberRequests) })) }