diff --git a/Telegram/Telegram-iOS/en.lproj/Localizable.strings b/Telegram/Telegram-iOS/en.lproj/Localizable.strings index a93c850ef2..3745e0790a 100644 --- a/Telegram/Telegram-iOS/en.lproj/Localizable.strings +++ b/Telegram/Telegram-iOS/en.lproj/Localizable.strings @@ -7564,6 +7564,15 @@ Sorry for the inconvenience."; "OldChannels.TooManyCommunitiesText" = "You are a member of **%@** groups and channels. Please leave some before joining a new one or upgrade to **Telegram Premium** to double the limit to **%@** groups and channels."; "OldChannels.TooManyCommunitiesNoPremiumText" = "You are a member of **%@** groups and channels. Please leave some before joining a new one. We are working to let you increase this limit in the future."; "OldChannels.TooManyCommunitiesFinalText" = "You are a member of **%@** groups and channels. Please leave some before joining a new one."; + +"OldChannels.TooManyCommunitiesCreateText" = "You are a member of **%@** groups and channels. Please leave some before creating a new one or upgrade to **Telegram Premium** to double the limit to **%@** groups and channels."; +"OldChannels.TooManyCommunitiesCreateNoPremiumText" = "You are a member of **%@** groups and channels. Please leave some before creating a new one. We are working to let you increase this limit in the future."; +"OldChannels.TooManyCommunitiesCreateFinalText" = "You are a member of **%@** groups and channels. Please leave some before creating a new one."; + +"OldChannels.TooManyCommunitiesUpgradeText" = "You are a member of **%@** groups and channels. For technical reasons, you need to leave some first before changing this setting in your groups or upgrade to **Telegram Premium** to double the limit to **%@** groups and channels."; +"OldChannels.TooManyCommunitiesUpgradeNoPremiumText" = "You are a member of **%@** groups and channels. For technical reasons, you need to leave some first before changing this setting in your groups. We are working to let you increase this limit in the future."; +"OldChannels.TooManyCommunitiesUpgradeFinalText" = "You are a member of **%@** groups and channels. For technical reasons, you need to leave some first before changing this setting in your groups."; + "OldChannels.LeaveCommunities_1" = "Leave %@ Community"; "OldChannels.LeaveCommunities_any" = "Leave %@ Communities"; @@ -7714,3 +7723,5 @@ Sorry for the inconvenience."; "Premium.Purchase.ErrorCantMakePayments" = "In-app purchases are not allowed on this device."; "Settings.Premium" = "Telegram Premium"; + +"Settings.AddAnotherAccount.PremiumHelp" = "You can add up to four accounts with different phone numbers."; diff --git a/submodules/ChatListUI/Sources/ChatListFilterPresetListItem.swift b/submodules/ChatListUI/Sources/ChatListFilterPresetListItem.swift index 431fc37e46..efecbd9832 100644 --- a/submodules/ChatListUI/Sources/ChatListFilterPresetListItem.swift +++ b/submodules/ChatListUI/Sources/ChatListFilterPresetListItem.swift @@ -276,6 +276,23 @@ private final class ChatListFilterPresetListItemNode: ItemListRevealOptionsItemN transition = .immediate } + if let reorderControlSizeAndApply = reorderControlSizeAndApply { + if strongSelf.reorderControlNode == nil { + let reorderControlNode = reorderControlSizeAndApply.1(layout.contentSize.height, false, .immediate) + strongSelf.reorderControlNode = reorderControlNode + strongSelf.controlsContainer.addSubnode(reorderControlNode) + reorderControlNode.alpha = 0.0 + transition.updateAlpha(node: reorderControlNode, alpha: 1.0) + } + let reorderControlFrame = CGRect(origin: CGPoint(x: params.width + revealOffset - params.rightInset - reorderControlSizeAndApply.0, y: 0.0), size: CGSize(width: reorderControlSizeAndApply.0, height: layout.contentSize.height)) + strongSelf.reorderControlNode?.frame = reorderControlFrame + } else if let reorderControlNode = strongSelf.reorderControlNode { + strongSelf.reorderControlNode = nil + transition.updateAlpha(node: reorderControlNode, alpha: 0.0, completion: { [weak reorderControlNode] _ in + reorderControlNode?.removeFromSupernode() + }) + } + if let editableControlSizeAndApply = editableControlSizeAndApply { let editableControlFrame = CGRect(origin: CGPoint(x: params.leftInset + revealOffset, y: 0.0), size: CGSize(width: editableControlSizeAndApply.0, height: layout.contentSize.height)) if strongSelf.editableControlNode == nil { @@ -306,24 +323,7 @@ private final class ChatListFilterPresetListItemNode: ItemListRevealOptionsItemN }) } strongSelf.editableControlNode?.isHidden = !item.canBeDeleted - - if let reorderControlSizeAndApply = reorderControlSizeAndApply { - if strongSelf.reorderControlNode == nil { - let reorderControlNode = reorderControlSizeAndApply.1(layout.contentSize.height, false, .immediate) - strongSelf.reorderControlNode = reorderControlNode - strongSelf.addSubnode(reorderControlNode) - reorderControlNode.alpha = 0.0 - transition.updateAlpha(node: reorderControlNode, alpha: 1.0) - } - let reorderControlFrame = CGRect(origin: CGPoint(x: params.width + revealOffset - params.rightInset - reorderControlSizeAndApply.0, y: 0.0), size: CGSize(width: reorderControlSizeAndApply.0, height: layout.contentSize.height)) - strongSelf.reorderControlNode?.frame = reorderControlFrame - } else if let reorderControlNode = strongSelf.reorderControlNode { - strongSelf.reorderControlNode = nil - transition.updateAlpha(node: reorderControlNode, alpha: 0.0, completion: { [weak reorderControlNode] _ in - reorderControlNode?.removeFromSupernode() - }) - } - + let _ = titleApply() let _ = labelApply() diff --git a/submodules/ChatListUI/Sources/ChatListFilterTabContainerNode.swift b/submodules/ChatListUI/Sources/ChatListFilterTabContainerNode.swift index a752b1ec32..b9f8461875 100644 --- a/submodules/ChatListUI/Sources/ChatListFilterTabContainerNode.swift +++ b/submodules/ChatListUI/Sources/ChatListFilterTabContainerNode.swift @@ -294,7 +294,7 @@ private final class ItemNode: ASDisplayNode { if let deleteButtonNode = self.deleteButtonNode { if let theme = self.theme { let deleteButtonSize = deleteButtonNode.update(theme: theme) - deleteButtonNode.frame = CGRect(origin: CGPoint(x: -deleteButtonSize.width, y: 5.0), size: deleteButtonSize) + deleteButtonNode.frame = CGRect(origin: CGPoint(x: -deleteButtonSize.width + 3.0, y: 5.0), size: deleteButtonSize) } } @@ -788,7 +788,7 @@ final class ChatListFilterTabContainerNode: ASDisplayNode { selectionFraction = 0.0 } - itemNode.updateText(strings: presentationData.strings, title: filter.title(strings: presentationData.strings), shortTitle: filter.shortTitle(strings: presentationData.strings), unreadCount: unreadCount, unreadHasUnmuted: unreadHasUnmuted, isNoFilter: isNoFilter, selectionFraction: selectionFraction, isEditing: isEditing, isReordering: isReordering, canReorderAllChats: canReorderAllChats, isDisabled: isDisabled, presentationData: presentationData, transition: itemNodeTransition) + itemNode.updateText(strings: presentationData.strings, title: filter.title(strings: presentationData.strings), shortTitle: i == 0 ? filter.shortTitle(strings: presentationData.strings) : filter.title(strings: presentationData.strings), unreadCount: unreadCount, unreadHasUnmuted: unreadHasUnmuted, isNoFilter: isNoFilter, selectionFraction: selectionFraction, isEditing: isEditing, isReordering: isReordering, canReorderAllChats: canReorderAllChats, isDisabled: isDisabled, presentationData: presentationData, transition: itemNodeTransition) } var removeKeys: [ChatListFilterTabEntryId] = [] for (id, _) in self.itemNodes { diff --git a/submodules/ContactsPeerItem/Sources/ContactsPeerItem.swift b/submodules/ContactsPeerItem/Sources/ContactsPeerItem.swift index 70bd21072f..ea842498af 100644 --- a/submodules/ContactsPeerItem/Sources/ContactsPeerItem.swift +++ b/submodules/ContactsPeerItem/Sources/ContactsPeerItem.swift @@ -932,7 +932,7 @@ public class ContactsPeerItemNode: ItemListRevealOptionsItemNode { iconNode.isLayerBacked = true iconNode.displaysAsynchronously = false iconNode.displayWithoutProcessing = true - strongSelf.containerNode.addSubnode(iconNode) + strongSelf.offsetContainerNode.addSubnode(iconNode) strongSelf.credibilityIconNode = iconNode } iconNode.image = currentCredibilityIconImage diff --git a/submodules/PeerInfoUI/Sources/OldChannelsController.swift b/submodules/PeerInfoUI/Sources/OldChannelsController.swift index f546d714cc..9b01607fbd 100644 --- a/submodules/PeerInfoUI/Sources/OldChannelsController.swift +++ b/submodules/PeerInfoUI/Sources/OldChannelsController.swift @@ -191,12 +191,33 @@ private func oldChannelsEntries(presentationData: PresentationData, state: OldCh let count = max(limit, Int32(peers?.count ?? 0)) var text: String? if count >= premiumLimit { - text = presentationData.strings.OldChannels_TooManyCommunitiesFinalText("\(premiumLimit)").string + switch intent { + case .create: + text = presentationData.strings.OldChannels_TooManyCommunitiesCreateFinalText("\(premiumLimit)").string + case .upgrade: + text = presentationData.strings.OldChannels_TooManyCommunitiesUpgradeFinalText("\(premiumLimit)").string + case .join: + text = presentationData.strings.OldChannels_TooManyCommunitiesFinalText("\(premiumLimit)").string + } } else if count >= limit { if isPremiumDisabled { - text = presentationData.strings.OldChannels_TooManyCommunitiesNoPremiumText("\(count)").string + switch intent { + case .create: + text = presentationData.strings.OldChannels_TooManyCommunitiesCreateNoPremiumText("\(premiumLimit)").string + case .upgrade: + text = presentationData.strings.OldChannels_TooManyCommunitiesUpgradeNoPremiumText("\(premiumLimit)").string + case .join: + text = presentationData.strings.OldChannels_TooManyCommunitiesNoPremiumText("\(count)").string + } } else { - text = presentationData.strings.OldChannels_TooManyCommunitiesText("\(count)", "\(premiumLimit)").string + switch intent { + case .create: + text = presentationData.strings.OldChannels_TooManyCommunitiesCreateText("\(count)", "\(premiumLimit)").string + case .upgrade: + text = presentationData.strings.OldChannels_TooManyCommunitiesUpgradeText("\(count)", "\(premiumLimit)").string + case .join: + text = presentationData.strings.OldChannels_TooManyCommunitiesText("\(count)", "\(premiumLimit)").string + } } } diff --git a/submodules/PremiumUI/Sources/PremiumIntroScreen.swift b/submodules/PremiumUI/Sources/PremiumIntroScreen.swift index cae6c1b59d..aac2278425 100644 --- a/submodules/PremiumUI/Sources/PremiumIntroScreen.swift +++ b/submodules/PremiumUI/Sources/PremiumIntroScreen.swift @@ -1161,7 +1161,6 @@ private final class PremiumIntroScreenContentComponent: CombinedComponent { }) let termsString: MultilineTextComponent.TextContent -// if context.component.isPremium == true { if let promoConfiguration = context.state.promoConfiguration { let attributedString = stringWithAppliedEntities(promoConfiguration.status, entities: promoConfiguration.statusEntities, baseColor: termsTextColor, linkColor: environment.theme.list.itemAccentColor, baseFont: termsFont, linkFont: termsFont, boldFont: boldTermsFont, italicFont: italicTermsFont, boldItalicFont: boldItalicTermsFont, fixedFont: monospaceTermsFont, blockQuoteFont: termsFont) termsString = .plain(attributedString) @@ -1390,6 +1389,13 @@ private final class PremiumIntroScreenComponent: CombinedComponent { return } + guard !self.context.account.testingEnvironment else { + let presentationData = self.context.sharedContext.currentPresentationData.with { $0 } + let alertController = textAlertController(context: self.context, title: nil, text: "Telegram Premium purchase is not available in the test environment.", actions: [TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_OK, action: {})]) + self.present(alertController) + return + } + addAppLogEvent(postbox: self.context.account.postbox, type: "premium.promo_screen_accept") self.inProgress = true diff --git a/submodules/TelegramUI/Sources/ChatController.swift b/submodules/TelegramUI/Sources/ChatController.swift index 2a6d52527e..5fd0ef4b1a 100644 --- a/submodules/TelegramUI/Sources/ChatController.swift +++ b/submodules/TelegramUI/Sources/ChatController.swift @@ -3602,7 +3602,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G return true } - self.chatTitleView = ChatTitleView(account: self.context.account, theme: self.presentationData.theme, strings: self.presentationData.strings, dateTimeFormat: self.presentationData.dateTimeFormat, nameDisplayOrder: self.presentationData.nameDisplayOrder) + self.chatTitleView = ChatTitleView(context: self.context, theme: self.presentationData.theme, strings: self.presentationData.strings, dateTimeFormat: self.presentationData.dateTimeFormat, nameDisplayOrder: self.presentationData.nameDisplayOrder) self.navigationItem.titleView = self.chatTitleView self.chatTitleView?.pressed = { [weak self] in if let strongSelf = self { diff --git a/submodules/TelegramUI/Sources/ChatTitleView.swift b/submodules/TelegramUI/Sources/ChatTitleView.swift index 0feb087087..7261c51428 100644 --- a/submodules/TelegramUI/Sources/ChatTitleView.swift +++ b/submodules/TelegramUI/Sources/ChatTitleView.swift @@ -16,6 +16,7 @@ import LocalizedPeerData import PhoneNumberFormat import ChatTitleActivityNode import AnimatedCountLabelNode +import AccountContext private let titleFont = Font.with(size: 17.0, design: .regular, weight: .semibold, traits: [.monospacedNumbers]) private let subtitleFont = Font.regular(13.0) @@ -46,7 +47,7 @@ private enum ChatTitleCredibilityIcon { } final class ChatTitleView: UIView, NavigationBarTitleView { - private let account: Account + private let context: AccountContext private var theme: PresentationTheme private var hasEmbeddedTitleContent: Bool = false @@ -122,7 +123,7 @@ final class ChatTitleView: UIView, NavigationBarTitleView { segments = [.text(0, NSAttributedString(string: typeText, font: titleFont, textColor: titleTheme.rootController.navigationBar.primaryTextColor))] isEnabled = false } else if isScheduledMessages { - if peerView.peerId == self.account.peerId { + if peerView.peerId == self.context.account.peerId { segments = [.text(0, NSAttributedString(string: self.strings.ScheduledMessages_RemindersTitle, font: titleFont, textColor: titleTheme.rootController.navigationBar.primaryTextColor))] } else { segments = [.text(0, NSAttributedString(string: self.strings.ScheduledMessages_Title, font: titleFont, textColor: titleTheme.rootController.navigationBar.primaryTextColor))] @@ -130,7 +131,7 @@ final class ChatTitleView: UIView, NavigationBarTitleView { isEnabled = false } else { if let peer = peerViewMainPeer(peerView) { - if peerView.peerId == self.account.peerId { + if peerView.peerId == self.context.account.peerId { segments = [.text(0, NSAttributedString(string: self.strings.Conversation_SavedMessages, font: titleFont, textColor: titleTheme.rootController.navigationBar.primaryTextColor))] } else { if !peerView.peerIsContact, let user = peer as? TelegramUser, !user.flags.contains(.isSupport), user.botInfo == nil, let phone = user.phone, !phone.isEmpty { @@ -139,14 +140,15 @@ final class ChatTitleView: UIView, NavigationBarTitleView { segments = [.text(0, NSAttributedString(string: EnginePeer(peer).displayTitle(strings: self.strings, displayOrder: self.nameDisplayOrder), font: titleFont, textColor: titleTheme.rootController.navigationBar.primaryTextColor))] } } - if peer.id != self.account.peerId { + if peer.id != self.context.account.peerId { + let premiumConfiguration = PremiumConfiguration.with(appConfiguration: self.context.currentAppConfiguration.with { $0 }) if peer.isFake { titleCredibilityIcon = .fake } else if peer.isScam { titleCredibilityIcon = .scam } else if peer.isVerified { titleCredibilityIcon = .verified - } else if peer.isPremium { + } else if peer.isPremium && !premiumConfiguration.isPremiumDisabled { titleCredibilityIcon = .premium } } @@ -303,7 +305,7 @@ final class ChatTitleView: UIView, NavigationBarTitleView { switch titleContent { case let .peer(peerView, _, isScheduledMessages): if let peer = peerViewMainPeer(peerView) { - if peer.id == self.account.peerId || isScheduledMessages || peer.id.isReplies { + if peer.id == self.context.account.peerId || isScheduledMessages || peer.id.isReplies { inputActivitiesAllowed = false } } @@ -405,7 +407,7 @@ final class ChatTitleView: UIView, NavigationBarTitleView { case let .peer(peerView, onlineMemberCount, isScheduledMessages): if let peer = peerViewMainPeer(peerView) { let servicePeer = isServicePeer(peer) - if peer.id == self.account.peerId || isScheduledMessages || peer.id.isReplies { + if peer.id == self.context.account.peerId || isScheduledMessages || peer.id.isReplies { let string = NSAttributedString(string: "", font: subtitleFont, textColor: titleTheme.rootController.navigationBar.secondaryTextColor) state = .info(string, .generic) } else if let user = peer as? TelegramUser { @@ -541,13 +543,13 @@ final class ChatTitleView: UIView, NavigationBarTitleView { } } - init(account: Account, theme: PresentationTheme, strings: PresentationStrings, dateTimeFormat: PresentationDateTimeFormat, nameDisplayOrder: PresentationPersonNameOrder) { - self.account = account + init(context: AccountContext, theme: PresentationTheme, strings: PresentationStrings, dateTimeFormat: PresentationDateTimeFormat, nameDisplayOrder: PresentationPersonNameOrder) { + self.context = context self.theme = theme self.strings = strings self.dateTimeFormat = dateTimeFormat self.nameDisplayOrder = nameDisplayOrder - + self.contentContainer = ASDisplayNode() self.titleNode = ImmediateAnimatedCountLabelNode() diff --git a/submodules/TelegramUI/Sources/PeerInfo/PeerInfoScreen.swift b/submodules/TelegramUI/Sources/PeerInfo/PeerInfoScreen.swift index e8990e4def..e4369d1b43 100644 --- a/submodules/TelegramUI/Sources/PeerInfo/PeerInfoScreen.swift +++ b/submodules/TelegramUI/Sources/PeerInfo/PeerInfoScreen.swift @@ -842,7 +842,23 @@ private func settingsEditingItems(data: PeerInfoScreenData?, state: PeerInfoStat items[.account]!.append(PeerInfoScreenActionItem(id: ItemAddAccount, text: presentationData.strings.Settings_AddAnotherAccount, alignment: .center, action: { interaction.openSettings(.addAccount) })) - items[.account]!.append(PeerInfoScreenCommentItem(id: ItemAddAccountHelp, text: presentationData.strings.Settings_AddAnotherAccount_Help)) + + var hasPremiumAccounts = false + if data.peer?.isPremium == true && !context.account.testingEnvironment { + hasPremiumAccounts = true + } + if let settings = data.globalSettings { + for (accountContext, peer, _) in settings.accountsAndPeers { + if !accountContext.account.testingEnvironment { + if peer.isPremium { + hasPremiumAccounts = true + break + } + } + } + } + + items[.account]!.append(PeerInfoScreenCommentItem(id: ItemAddAccountHelp, text: hasPremiumAccounts ? presentationData.strings.Settings_AddAnotherAccount_PremiumHelp : presentationData.strings.Settings_AddAnotherAccount_Help)) items[.logout]!.append(PeerInfoScreenActionItem(id: ItemLogout, text: presentationData.strings.Settings_Logout, color: .destructive, alignment: .center, action: { interaction.openSettings(.logout) @@ -6275,36 +6291,38 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewDelegate case .username: push(usernameSetupController(context: self.context)) case .addAccount: - var maximumAvailableAccounts: Int = 3 - if self.data?.peer?.isPremium == true && !self.context.account.testingEnvironment { - maximumAvailableAccounts = 4 - } - var count: Int = 1 - if let settings = self.data?.globalSettings { - for (accountContext, peer, _) in settings.accountsAndPeers { - if !accountContext.account.testingEnvironment { - if peer.isPremium { - maximumAvailableAccounts = 4 + if let data = self.data { + var maximumAvailableAccounts: Int = 3 + if data.peer?.isPremium == true && !self.context.account.testingEnvironment { + maximumAvailableAccounts = 4 + } + var count: Int = 1 + if let settings = data.globalSettings { + for (accountContext, peer, _) in settings.accountsAndPeers { + if !accountContext.account.testingEnvironment { + if peer.isPremium { + maximumAvailableAccounts = 4 + } + count += 1 } - count += 1 } } - } - if count >= maximumAvailableAccounts { - let context = self.context - var replaceImpl: ((ViewController) -> Void)? - let controller = PremiumLimitScreen(context: context, subject: .accounts, count: Int32(count), action: { - let controller = PremiumIntroScreen(context: context, source: .accounts) - replaceImpl?(controller) - }) - replaceImpl = { [weak controller] c in - controller?.replace(with: c) + if count >= maximumAvailableAccounts { + let context = self.context + var replaceImpl: ((ViewController) -> Void)? + let controller = PremiumLimitScreen(context: context, subject: .accounts, count: Int32(count), action: { + let controller = PremiumIntroScreen(context: context, source: .accounts) + replaceImpl?(controller) + }) + replaceImpl = { [weak controller] c in + controller?.replace(with: c) + } + if let navigationController = context.sharedContext.mainWindow?.viewController as? NavigationController { + navigationController.pushViewController(controller) + } + } else { + self.context.sharedContext.beginNewAuth(testingEnvironment: self.context.account.testingEnvironment) } - if let navigationController = context.sharedContext.mainWindow?.viewController as? NavigationController { - navigationController.pushViewController(controller) - } - } else { - self.context.sharedContext.beginNewAuth(testingEnvironment: self.context.account.testingEnvironment) } case .logout: if let user = self.data?.peer as? TelegramUser, let phoneNumber = user.phone {