diff --git a/Telegram/Telegram-iOS/en.lproj/Localizable.strings b/Telegram/Telegram-iOS/en.lproj/Localizable.strings index e58d2d0c61..c9cac9a575 100644 --- a/Telegram/Telegram-iOS/en.lproj/Localizable.strings +++ b/Telegram/Telegram-iOS/en.lproj/Localizable.strings @@ -10773,3 +10773,6 @@ Sorry for the inconvenience."; "ChatList.PremiumXmasGiftText" = "Gift Telegram Premium for Christmas."; "ReassignBoost.DescriptionWithLink" = "To boost **%1$@**, reassign a previous boost or [gift Telegram Premium]() to a friend to get **%2$@** additional boosts."; + +"ChatList.PremiumGiftInSettingsInfo" = "You can gift **Telegram Premium** to a friend later in **Settings**."; + diff --git a/submodules/ChatListUI/Sources/ChatListSearchListPaneNode.swift b/submodules/ChatListUI/Sources/ChatListSearchListPaneNode.swift index 9efaf4cd31..ebcb16827f 100644 --- a/submodules/ChatListUI/Sources/ChatListSearchListPaneNode.swift +++ b/submodules/ChatListUI/Sources/ChatListSearchListPaneNode.swift @@ -2251,6 +2251,7 @@ final class ChatListSearchListPaneNode: ASDisplayNode, ChatListSearchPaneNode { if let sourceNode = sourceNode as? ChatListItemNode { self.interaction.openStories?(id, sourceNode.avatarNode) } + }, dismissNotice: { _ in }) chatListInteraction.isSearchMode = true @@ -3561,6 +3562,7 @@ public final class ChatListSearchShimmerNode: ASDisplayNode { }, performActiveSessionAction: { _, _ in }, openChatFolderUpdates: {}, hideChatFolderUpdates: { }, openStories: { _, _ in + }, dismissNotice: { _ in }) var isInlineMode = false if case .topics = key { diff --git a/submodules/ChatListUI/Sources/ChatListShimmerNode.swift b/submodules/ChatListUI/Sources/ChatListShimmerNode.swift index f9a989c274..d07e4174d9 100644 --- a/submodules/ChatListUI/Sources/ChatListShimmerNode.swift +++ b/submodules/ChatListUI/Sources/ChatListShimmerNode.swift @@ -156,7 +156,8 @@ final class ChatListShimmerNode: ASDisplayNode { let interaction = ChatListNodeInteraction(context: context, animationCache: animationCache, animationRenderer: animationRenderer, activateSearch: {}, peerSelected: { _, _, _, _ in }, disabledPeerSelected: { _, _ in }, togglePeerSelected: { _, _ in }, togglePeersSelection: { _, _ in }, additionalCategorySelected: { _ in }, messageSelected: { _, _, _, _ in}, groupSelected: { _ in }, addContact: { _ in }, setPeerIdWithRevealedOptions: { _, _ in }, setItemPinned: { _, _ in }, setPeerMuted: { _, _ in }, setPeerThreadMuted: { _, _, _ in }, deletePeer: { _, _ in }, deletePeerThread: { _, _ in }, setPeerThreadStopped: { _, _, _ in }, setPeerThreadPinned: { _, _, _ in }, setPeerThreadHidden: { _, _, _ in }, updatePeerGrouping: { _, _ in }, togglePeerMarkedUnread: { _, _ in}, toggleArchivedFolderHiddenByDefault: {}, toggleThreadsSelection: { _, _ in }, hidePsa: { _ in }, activateChatPreview: { _, _, _, gesture, _ in gesture?.cancel() - }, present: { _ in }, openForumThread: { _, _ in }, openStorageManagement: {}, openPasswordSetup: {}, openPremiumIntro: {}, openPremiumGift: {}, openActiveSessions: {}, performActiveSessionAction: { _, _ in }, openChatFolderUpdates: {}, hideChatFolderUpdates: {}, openStories: { _, _ in }) + }, present: { _ in }, openForumThread: { _, _ in }, openStorageManagement: {}, openPasswordSetup: {}, openPremiumIntro: {}, openPremiumGift: {}, openActiveSessions: {}, performActiveSessionAction: { _, _ in }, openChatFolderUpdates: {}, hideChatFolderUpdates: {}, openStories: { _, _ in }, dismissNotice: { _ in + }) interaction.isInlineMode = isInlineMode let items = (0 ..< 2).map { _ -> ChatListItem in diff --git a/submodules/ChatListUI/Sources/Node/ChatListNode.swift b/submodules/ChatListUI/Sources/Node/ChatListNode.swift index d78f60b438..9f7a21fb85 100644 --- a/submodules/ChatListUI/Sources/Node/ChatListNode.swift +++ b/submodules/ChatListUI/Sources/Node/ChatListNode.swift @@ -106,6 +106,7 @@ public final class ChatListNodeInteraction { let openChatFolderUpdates: () -> Void let hideChatFolderUpdates: () -> Void let openStories: (ChatListNode.OpenStoriesSubject, ASDisplayNode?) -> Void + let dismissNotice: (ChatListNotice) -> Void public var searchTextHighightState: String? var highlightedChatLocation: ChatListHighlightedLocation? @@ -156,7 +157,8 @@ public final class ChatListNodeInteraction { performActiveSessionAction: @escaping (NewSessionReview, Bool) -> Void, openChatFolderUpdates: @escaping () -> Void, hideChatFolderUpdates: @escaping () -> Void, - openStories: @escaping (ChatListNode.OpenStoriesSubject, ASDisplayNode?) -> Void + openStories: @escaping (ChatListNode.OpenStoriesSubject, ASDisplayNode?) -> Void, + dismissNotice: @escaping (ChatListNotice) -> Void ) { self.activateSearch = activateSearch self.peerSelected = peerSelected @@ -195,6 +197,7 @@ public final class ChatListNodeInteraction { self.openChatFolderUpdates = openChatFolderUpdates self.hideChatFolderUpdates = hideChatFolderUpdates self.openStories = openStories + self.dismissNotice = dismissNotice } } @@ -701,7 +704,7 @@ private func mappedInsertEntries(context: AccountContext, nodeInteraction: ChatL hideChatListContacts(context: context) } : nil), directionHint: entry.directionHint) case let .Notice(presentationData, notice): - return ListViewInsertItem(index: entry.index, previousIndex: entry.previousIndex, item: ChatListStorageInfoItem(theme: presentationData.theme, strings: presentationData.strings, notice: notice, action: { [weak nodeInteraction] action in + return ListViewInsertItem(index: entry.index, previousIndex: entry.previousIndex, item: ChatListStorageInfoItem(context: context, theme: presentationData.theme, strings: presentationData.strings, notice: notice, action: { [weak nodeInteraction] action in switch action { case .activate: switch notice { @@ -717,10 +720,7 @@ private func mappedInsertEntries(context: AccountContext, nodeInteraction: ChatL break } case .hide: - switch notice { - default: - break - } + nodeInteraction?.dismissNotice(notice) case let .buttonChoice(isPositive): switch notice { case let .reviewLogin(newSessionReview, _): @@ -1023,7 +1023,7 @@ private func mappedUpdateEntries(context: AccountContext, nodeInteraction: ChatL hideChatListContacts(context: context) } : nil), directionHint: entry.directionHint) case let .Notice(presentationData, notice): - return ListViewUpdateItem(index: entry.index, previousIndex: entry.previousIndex, item: ChatListStorageInfoItem(theme: presentationData.theme, strings: presentationData.strings, notice: notice, action: { [weak nodeInteraction] action in + return ListViewUpdateItem(index: entry.index, previousIndex: entry.previousIndex, item: ChatListStorageInfoItem(context: context, theme: presentationData.theme, strings: presentationData.strings, notice: notice, action: { [weak nodeInteraction] action in switch action { case .activate: switch notice { @@ -1039,10 +1039,7 @@ private func mappedUpdateEntries(context: AccountContext, nodeInteraction: ChatL break } case .hide: - switch notice { - default: - break - } + nodeInteraction?.dismissNotice(notice) case let .buttonChoice(isPositive): switch notice { case let .reviewLogin(newSessionReview, _): @@ -1703,6 +1700,20 @@ public final class ChatListNode: ListView { return } self.openStories?(subject, itemNode) + }, dismissNotice: { [weak self] notice in + guard let self else { + return + } + let presentationData = self.context.sharedContext.currentPresentationData.with { $0 } + switch notice { + case .xmasPremiumGift: + let _ = dismissServerProvidedSuggestion(account: self.context.account, suggestion: .xmasPremiumGift).startStandalone() + self.present?(UndoOverlayController(presentationData: presentationData, content: .info(title: nil, text: presentationData.strings.ChatList_PremiumGiftInSettingsInfo, timeout: 5.0, customUndoText: nil), elevatedLayout: false, action: { _ in + return true + })) + default: + break + } }) nodeInteraction.isInlineMode = isInlineMode diff --git a/submodules/ChatListUI/Sources/Node/ChatListNodeEntries.swift b/submodules/ChatListUI/Sources/Node/ChatListNodeEntries.swift index bd2ee5f620..b8007ffcae 100644 --- a/submodules/ChatListUI/Sources/Node/ChatListNodeEntries.swift +++ b/submodules/ChatListUI/Sources/Node/ChatListNodeEntries.swift @@ -79,7 +79,7 @@ public enum ChatListNodeEntryPromoInfo: Equatable { case psa(type: String, message: String?) } -enum ChatListNotice: Equatable { +public enum ChatListNotice: Equatable { case clearStorage(sizeFraction: Double) case setupPassword case premiumUpgrade(discount: Int32) diff --git a/submodules/ChatListUI/Sources/Node/ChatListStorageInfoItem.swift b/submodules/ChatListUI/Sources/Node/ChatListStorageInfoItem.swift index 246ac15a9c..5d4f82c091 100644 --- a/submodules/ChatListUI/Sources/Node/ChatListStorageInfoItem.swift +++ b/submodules/ChatListUI/Sources/Node/ChatListStorageInfoItem.swift @@ -8,6 +8,8 @@ import ListSectionHeaderNode import AppBundle import ItemListUI import Markdown +import AccountContext +import TelegramCore class ChatListStorageInfoItem: ListViewItem { enum Action { @@ -16,6 +18,7 @@ class ChatListStorageInfoItem: ListViewItem { case buttonChoice(isPositive: Bool) } + let context: AccountContext let theme: PresentationTheme let strings: PresentationStrings let notice: ChatListNotice @@ -23,7 +26,8 @@ class ChatListStorageInfoItem: ListViewItem { let selectable: Bool = true - init(theme: PresentationTheme, strings: PresentationStrings, notice: ChatListNotice, action: @escaping (Action) -> Void) { + init(context: AccountContext, theme: PresentationTheme, strings: PresentationStrings, notice: ChatListNotice, action: @escaping (Action) -> Void) { + self.context = context self.theme = theme self.strings = strings self.notice = notice @@ -86,6 +90,8 @@ class ChatListStorageInfoItemNode: ItemListRevealOptionsItemNode { private let arrowNode: ASImageNode private let separatorNode: ASDisplayNode + private var closeButton: HighlightableButtonNode? + private var okButtonText: TextNode? private var cancelButtonText: TextNode? private var okButton: HighlightableButtonNode? @@ -127,6 +133,13 @@ class ChatListStorageInfoItemNode: ItemListRevealOptionsItemNode { super.didLoad() } + @objc private func closePressed() { + guard let item = self.item else { + return + } + item.action(.hide) + } + override func layoutForParams(_ params: ListViewItemLayoutParams, item: ListViewItem, previousItem: ListViewItem?, nextItem: ListViewItem?) { let layout = self.asyncLayout() let (_, apply) = layout(item as! ChatListStorageInfoItem, params, nextItem == nil) @@ -205,7 +218,7 @@ class ChatListStorageInfoItemNode: ItemListRevealOptionsItemNode { textString = NSAttributedString(string: item.strings.ChatList_PremiumRestoreDiscountText, font: textFont, textColor: item.theme.rootController.navigationBar.secondaryTextColor) case .xmasPremiumGift: - titleString = parseMarkdownIntoAttributedString(item.strings.ChatList_PremiumXmasGiftTitle, attributes: MarkdownAttributes(body: MarkdownAttributeSet(font: titleFont, textColor: item.theme.rootController.navigationBar.primaryTextColor), bold: MarkdownAttributeSet(font: titleFont, textColor: item.theme.rootController.navigationBar.accentTextColor), link: MarkdownAttributeSet(font: titleFont, textColor: item.theme.rootController.navigationBar.primaryTextColor), linkAttribute: { _ in return nil })) + titleString = parseMarkdownIntoAttributedString(item.strings.ChatList_PremiumXmasGiftTitle, attributes: MarkdownAttributes(body: MarkdownAttributeSet(font: titleFont, textColor: item.theme.rootController.navigationBar.primaryTextColor), bold: MarkdownAttributeSet(font: titleFont, textColor: item.theme.rootController.navigationBar.accentTextColor), link: MarkdownAttributeSet(font: titleFont, textColor: item.theme.rootController.navigationBar.primaryTextColor), linkAttribute: { _ in return nil })) textString = NSAttributedString(string: item.strings.ChatList_PremiumXmasGiftText, font: textFont, textColor: item.theme.rootController.navigationBar.secondaryTextColor) case let .reviewLogin(newSessionReview, totalCount): spacing = 2.0 @@ -263,7 +276,7 @@ class ChatListStorageInfoItemNode: ItemListRevealOptionsItemNode { if let image = strongSelf.arrowNode.image { strongSelf.arrowNode.frame = CGRect(origin: CGPoint(x: layout.size.width - sideInset - image.size.width + 8.0, y: floor((layout.size.height - image.size.height) / 2.0)), size: image.size) } - + if let okButtonLayout, let cancelButtonLayout { strongSelf.arrowNode.isHidden = true @@ -334,6 +347,31 @@ class ChatListStorageInfoItemNode: ItemListRevealOptionsItemNode { } } + let arrowIsHidden = strongSelf.arrowNode.isHidden + if case .xmasPremiumGift = item.notice { + strongSelf.arrowNode.isHidden = true + + let closeButton: HighlightableButtonNode + if let current = strongSelf.closeButton { + closeButton = current + } else { + closeButton = HighlightableButtonNode() + closeButton.hitTestSlop = UIEdgeInsets(top: -8.0, left: -8.0, bottom: -8.0, right: -8.0) + closeButton.addTarget(self, action: #selector(strongSelf.closePressed), forControlEvents: [.touchUpInside]) + strongSelf.contentContainer.addSubnode(closeButton) + strongSelf.closeButton = closeButton + } + + if themeUpdated { + closeButton.setImage(PresentationResourcesItemList.itemListCloseIconImage(item.theme), for: .normal) + } + + let closeButtonSize = closeButton.measure(CGSize(width: 100.0, height: 100.0)) + closeButton.frame = CGRect(origin: CGPoint(x: layout.size.width - sideInset - closeButtonSize.width, y: floor((layout.size.height - closeButtonSize.height) / 2.0)), size: closeButtonSize) + } else { + strongSelf.arrowNode.isHidden = arrowIsHidden + } + strongSelf.contentSize = layout.contentSize strongSelf.insets = layout.insets diff --git a/submodules/HashtagSearchUI/Sources/HashtagSearchController.swift b/submodules/HashtagSearchUI/Sources/HashtagSearchController.swift index 2b60d8e325..2ed45cdf2c 100644 --- a/submodules/HashtagSearchUI/Sources/HashtagSearchController.swift +++ b/submodules/HashtagSearchUI/Sources/HashtagSearchController.swift @@ -101,6 +101,7 @@ public final class HashtagSearchController: TelegramBaseController { }, openChatFolderUpdates: { }, hideChatFolderUpdates: { }, openStories: { _, _ in + }, dismissNotice: { _ in }) let previousSearchItems = Atomic<[ChatListSearchEntry]?>(value: nil) diff --git a/submodules/SettingsUI/Sources/Text Size/TextSizeSelectionController.swift b/submodules/SettingsUI/Sources/Text Size/TextSizeSelectionController.swift index 4c4560408d..39b8e37855 100644 --- a/submodules/SettingsUI/Sources/Text Size/TextSizeSelectionController.swift +++ b/submodules/SettingsUI/Sources/Text Size/TextSizeSelectionController.swift @@ -226,6 +226,7 @@ private final class TextSizeSelectionControllerNode: ASDisplayNode, UIScrollView }, performActiveSessionAction: { _, _ in }, openChatFolderUpdates: {}, hideChatFolderUpdates: { }, openStories: { _, _ in + }, dismissNotice: { _ in }) let chatListPresentationData = ChatListPresentationData(theme: self.presentationData.theme, fontSize: self.presentationData.listsFontSize, strings: self.presentationData.strings, dateTimeFormat: self.presentationData.dateTimeFormat, nameSortOrder: self.presentationData.nameSortOrder, nameDisplayOrder: self.presentationData.nameDisplayOrder, disableAnimations: true) diff --git a/submodules/SettingsUI/Sources/Themes/ThemePreviewControllerNode.swift b/submodules/SettingsUI/Sources/Themes/ThemePreviewControllerNode.swift index d2f4e8a75e..9dd1e3c964 100644 --- a/submodules/SettingsUI/Sources/Themes/ThemePreviewControllerNode.swift +++ b/submodules/SettingsUI/Sources/Themes/ThemePreviewControllerNode.swift @@ -375,6 +375,7 @@ final class ThemePreviewControllerNode: ASDisplayNode, UIScrollViewDelegate { }, performActiveSessionAction: { _, _ in }, openChatFolderUpdates: {}, hideChatFolderUpdates: { }, openStories: { _, _ in + }, dismissNotice: { _ in }) func makeChatListItem( diff --git a/submodules/TelegramUI/Components/Settings/ThemeAccentColorScreen/Sources/ThemeAccentColorControllerNode.swift b/submodules/TelegramUI/Components/Settings/ThemeAccentColorScreen/Sources/ThemeAccentColorControllerNode.swift index e1028d3402..a23fef5c55 100644 --- a/submodules/TelegramUI/Components/Settings/ThemeAccentColorScreen/Sources/ThemeAccentColorControllerNode.swift +++ b/submodules/TelegramUI/Components/Settings/ThemeAccentColorScreen/Sources/ThemeAccentColorControllerNode.swift @@ -869,6 +869,7 @@ final class ThemeAccentColorControllerNode: ASDisplayNode, UIScrollViewDelegate }, performActiveSessionAction: { _, _ in }, openChatFolderUpdates: {}, hideChatFolderUpdates: { }, openStories: { _, _ in + }, dismissNotice: { _ in }) let chatListPresentationData = ChatListPresentationData(theme: self.presentationData.theme, fontSize: self.presentationData.listsFontSize, strings: self.presentationData.strings, dateTimeFormat: self.presentationData.dateTimeFormat, nameSortOrder: self.presentationData.nameSortOrder, nameDisplayOrder: self.presentationData.nameDisplayOrder, disableAnimations: true) diff --git a/submodules/TelegramUI/Sources/ChatSearchResultsContollerNode.swift b/submodules/TelegramUI/Sources/ChatSearchResultsContollerNode.swift index 6039167ad2..5b124d6689 100644 --- a/submodules/TelegramUI/Sources/ChatSearchResultsContollerNode.swift +++ b/submodules/TelegramUI/Sources/ChatSearchResultsContollerNode.swift @@ -272,6 +272,7 @@ class ChatSearchResultsControllerNode: ViewControllerTracingNode, UIScrollViewDe }, openChatFolderUpdates: { }, hideChatFolderUpdates: { }, openStories: { _, _ in + }, dismissNotice: { _ in }) interaction.searchTextHighightState = searchQuery self.interaction = interaction