From c79612819674040f41160b73a5eee63caf6a8405 Mon Sep 17 00:00:00 2001 From: Ilya Laktyushin Date: Sat, 22 Apr 2023 12:57:25 +0400 Subject: [PATCH 1/3] Fix web app button spinner color --- submodules/AttachmentUI/Sources/AttachmentPanel.swift | 1 + 1 file changed, 1 insertion(+) diff --git a/submodules/AttachmentUI/Sources/AttachmentPanel.swift b/submodules/AttachmentUI/Sources/AttachmentPanel.swift index 257d60b6d0..e81fc2894a 100644 --- a/submodules/AttachmentUI/Sources/AttachmentPanel.swift +++ b/submodules/AttachmentUI/Sources/AttachmentPanel.swift @@ -718,6 +718,7 @@ private final class MainButtonNode: HighlightTrackingButtonNode { let statusSize = CGSize(width: 20.0, height: 20.0) transition.updateFrame(node: self.statusNode, frame: CGRect(origin: CGPoint(x: size.width - statusSize.width - 15.0, y: floorToScreenPixels((size.height - statusSize.height) / 2.0)), size: statusSize)) + self.statusNode.foregroundNodeColor = state.textColor self.statusNode.transitionToState(state.progress == .side ? .progress(value: nil, cancelEnabled: false, appearance: SemanticStatusNodeState.ProgressAppearance(inset: 0.0, lineWidth: 2.0)) : .none) } } From 79ca49b4998858798119f714d9069a0c5652c9e4 Mon Sep 17 00:00:00 2001 From: Ilya Laktyushin Date: Sat, 22 Apr 2023 12:58:56 +0400 Subject: [PATCH 2/3] Add premium restore suggestion --- Telegram/Telegram-iOS/en.lproj/Localizable.strings | 3 +++ submodules/ChatListUI/Sources/Node/ChatListNode.swift | 11 +++++++---- .../ChatListUI/Sources/Node/ChatListNodeEntries.swift | 1 + .../Sources/Node/ChatListStorageInfoItem.swift | 10 ++++++++++ submodules/TelegramCore/Sources/Suggestions.swift | 1 + 5 files changed, 22 insertions(+), 4 deletions(-) diff --git a/Telegram/Telegram-iOS/en.lproj/Localizable.strings b/Telegram/Telegram-iOS/en.lproj/Localizable.strings index e4f83b5618..31f98a5226 100644 --- a/Telegram/Telegram-iOS/en.lproj/Localizable.strings +++ b/Telegram/Telegram-iOS/en.lproj/Localizable.strings @@ -9345,3 +9345,6 @@ Sorry for the inconvenience."; "Notification.LockScreenReactionPlaceholder" = "Reaction"; "UserInfo.BotNamePlaceholder" = "Bot Name"; + +"ChatList.PremiumRestoreDiscountTitle" = "Get Premium back with up to %@ off"; +"ChatList.PremiumRestoreDiscountText" = "Your Telegram Premium has recently expired. Tap here to extend it."; diff --git a/submodules/ChatListUI/Sources/Node/ChatListNode.swift b/submodules/ChatListUI/Sources/Node/ChatListNode.swift index fd358cff29..2e185e5225 100644 --- a/submodules/ChatListUI/Sources/Node/ChatListNode.swift +++ b/submodules/ChatListUI/Sources/Node/ChatListNode.swift @@ -663,7 +663,7 @@ private func mappedInsertEntries(context: AccountContext, nodeInteraction: ChatL nodeInteraction?.openStorageManagement() case .setupPassword: nodeInteraction?.openPasswordSetup() - case .premiumUpgrade, .premiumAnnualDiscount: + case .premiumUpgrade, .premiumAnnualDiscount, .premiumRestore: nodeInteraction?.openPremiumIntro() case .chatFolderUpdates: nodeInteraction?.openChatFolderUpdates() @@ -964,7 +964,7 @@ private func mappedUpdateEntries(context: AccountContext, nodeInteraction: ChatL nodeInteraction?.openStorageManagement() case .setupPassword: nodeInteraction?.openPasswordSetup() - case .premiumUpgrade, .premiumAnnualDiscount: + case .premiumUpgrade, .premiumAnnualDiscount, .premiumRestore: nodeInteraction?.openPremiumIntro() case .chatFolderUpdates: nodeInteraction?.openChatFolderUpdates() @@ -1492,6 +1492,7 @@ public final class ChatListNode: ListView { if let self { let _ = dismissServerProvidedSuggestion(account: self.context.account, suggestion: .annualPremium).start() let _ = dismissServerProvidedSuggestion(account: self.context.account, suggestion: .upgradePremium).start() + let _ = dismissServerProvidedSuggestion(account: self.context.account, suggestion: .restorePremium).start() } } let controller = self.context.sharedContext.makePremiumIntroController(context: self.context, source: .ads) @@ -1612,7 +1613,7 @@ public final class ChatListNode: ListView { return .single(.setupPassword) } } - if suggestions.contains(.annualPremium) || suggestions.contains(.upgradePremium), let inAppPurchaseManager = context.inAppPurchaseManager { + if suggestions.contains(.annualPremium) || suggestions.contains(.upgradePremium) || suggestions.contains(.restorePremium), let inAppPurchaseManager = context.inAppPurchaseManager { return inAppPurchaseManager.availableProducts |> map { products -> ChatListNotice? in if products.count > 1 { @@ -1627,7 +1628,9 @@ public final class ChatListNode: ListView { let fraction = Float(product.priceCurrencyAndAmount.amount) / Float(12) / Float(shortestOptionPrice.0) let discount = Int32(round((1.0 - fraction) * 20.0) * 5.0) if discount > 0 { - if suggestions.contains(.annualPremium) { + if suggestions.contains(.restorePremium) { + return .premiumRestore(discount: discount) + } else if suggestions.contains(.annualPremium) { return .premiumAnnualDiscount(discount: discount) } else if suggestions.contains(.upgradePremium) { return .premiumUpgrade(discount: discount) diff --git a/submodules/ChatListUI/Sources/Node/ChatListNodeEntries.swift b/submodules/ChatListUI/Sources/Node/ChatListNodeEntries.swift index 43d34c20ad..374ab85342 100644 --- a/submodules/ChatListUI/Sources/Node/ChatListNodeEntries.swift +++ b/submodules/ChatListUI/Sources/Node/ChatListNodeEntries.swift @@ -84,6 +84,7 @@ enum ChatListNotice: Equatable { case setupPassword case premiumUpgrade(discount: Int32) case premiumAnnualDiscount(discount: Int32) + case premiumRestore(discount: Int32) case chatFolderUpdates(count: Int) } diff --git a/submodules/ChatListUI/Sources/Node/ChatListStorageInfoItem.swift b/submodules/ChatListUI/Sources/Node/ChatListStorageInfoItem.swift index e33af5cb73..fd8338ec4e 100644 --- a/submodules/ChatListUI/Sources/Node/ChatListStorageInfoItem.swift +++ b/submodules/ChatListUI/Sources/Node/ChatListStorageInfoItem.swift @@ -172,6 +172,16 @@ class ChatListStorageInfoItemNode: ItemListRevealOptionsItemNode { titleString = titleStringValue textString = NSAttributedString(string: item.strings.ChatList_PremiumAnnualDiscountText, font: textFont, textColor: item.theme.rootController.navigationBar.secondaryTextColor) + case let .premiumRestore(discount): + let discountString = "\(discount)%" + let rawTitleString = item.strings.ChatList_PremiumRestoreDiscountTitle(discountString) + let titleStringValue = NSMutableAttributedString(attributedString: NSAttributedString(string: rawTitleString.string, font: titleFont, textColor: item.theme.rootController.navigationBar.primaryTextColor)) + if let range = rawTitleString.ranges.first { + titleStringValue.addAttribute(.foregroundColor, value: item.theme.rootController.navigationBar.accentTextColor, range: range.range) + } + titleString = titleStringValue + + textString = NSAttributedString(string: item.strings.ChatList_PremiumRestoreDiscountText, font: textFont, textColor: item.theme.rootController.navigationBar.secondaryTextColor) case let .chatFolderUpdates(count): let rawTitleString = item.strings.ChatList_ChatFolderUpdateHintTitle(item.strings.ChatList_ChatFolderUpdateCount(Int32(count))) let titleStringValue = NSMutableAttributedString(attributedString: NSAttributedString(string: rawTitleString.string, font: titleFont, textColor: item.theme.rootController.navigationBar.primaryTextColor)) diff --git a/submodules/TelegramCore/Sources/Suggestions.swift b/submodules/TelegramCore/Sources/Suggestions.swift index 9e8ce6b61a..792f97e781 100644 --- a/submodules/TelegramCore/Sources/Suggestions.swift +++ b/submodules/TelegramCore/Sources/Suggestions.swift @@ -11,6 +11,7 @@ public enum ServerProvidedSuggestion: String { case setupPassword = "SETUP_PASSWORD" case upgradePremium = "PREMIUM_UPGRADE" case annualPremium = "PREMIUM_ANNUAL" + case restorePremium = "PREMIUM_RESTORE" } private var dismissedSuggestionsPromise = ValuePromise<[AccountRecordId: Set]>([:]) From f58408ce0193ee85a27a67da72e704926f8bbad1 Mon Sep 17 00:00:00 2001 From: Ilya Laktyushin Date: Sat, 22 Apr 2023 12:59:24 +0400 Subject: [PATCH 3/3] Avatar animation fixes --- .../Sources/PeerInfo/PeerInfoHeaderNode.swift | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/submodules/TelegramUI/Sources/PeerInfo/PeerInfoHeaderNode.swift b/submodules/TelegramUI/Sources/PeerInfo/PeerInfoHeaderNode.swift index 87f9351a43..f04de6ac96 100644 --- a/submodules/TelegramUI/Sources/PeerInfo/PeerInfoHeaderNode.swift +++ b/submodules/TelegramUI/Sources/PeerInfo/PeerInfoHeaderNode.swift @@ -2607,6 +2607,8 @@ final class PeerInfoHeaderNode: ASDisplayNode { } } + let isLandscape = containerInset > 16.0 + let themeUpdated = self.presentationData?.theme !== presentationData.theme self.presentationData = presentationData @@ -2764,7 +2766,7 @@ final class PeerInfoHeaderNode: ASDisplayNode { let avatarFrame = CGRect(origin: CGPoint(x: floor((width - avatarSize) / 2.0), y: statusBarHeight + 22.0), size: CGSize(width: avatarSize, height: avatarSize)) self.backgroundNode.updateColor(color: presentationData.theme.rootController.navigationBar.blurredBackgroundColor, transition: .immediate) - + let headerBackgroundColor: UIColor = presentationData.theme.list.blocksBackgroundColor var effectiveSeparatorAlpha: CGFloat if let navigationTransition = self.navigationTransition { @@ -2778,7 +2780,7 @@ final class PeerInfoHeaderNode: ASDisplayNode { transitionSourceAvatarFrame = avatarNavigationNode.avatarNode.view.convert(avatarNavigationNode.avatarNode.view.bounds, to: navigationTransition.sourceNavigationBar.view) } } else { - if deviceMetrics.hasDynamicIsland { + if deviceMetrics.hasDynamicIsland && !isLandscape { transitionSourceAvatarFrame = CGRect(origin: CGPoint(x: avatarFrame.minX, y: -20.0), size: avatarFrame.size).insetBy(dx: avatarSize * 0.4, dy: avatarSize * 0.4) } else { transitionSourceAvatarFrame = avatarFrame.offsetBy(dx: 0.0, dy: -avatarFrame.maxY).insetBy(dx: avatarSize * 0.4, dy: avatarSize * 0.4) @@ -3304,7 +3306,7 @@ final class PeerInfoHeaderNode: ASDisplayNode { controlsClippingFrame = apparentAvatarFrame } - let avatarClipOffset: CGFloat = !self.isAvatarExpanded && deviceMetrics.hasDynamicIsland && self.avatarClippingNode.clipsToBounds ? 48.0 : 0.0 + let avatarClipOffset: CGFloat = !self.isAvatarExpanded && deviceMetrics.hasDynamicIsland && self.avatarClippingNode.clipsToBounds && !isLandscape ? 48.0 : 0.0 let clippingNodeTransition = ContainedViewLayoutTransition.immediate clippingNodeTransition.updateFrame(layer: self.avatarClippingNode.layer, frame: CGRect(origin: CGPoint(x: 0.0, y: avatarClipOffset), size: CGSize(width: width, height: 1000.0))) clippingNodeTransition.updateSublayerTransformOffset(layer: self.avatarClippingNode.layer, offset: CGPoint(x: 0.0, y: -avatarClipOffset)) @@ -3351,7 +3353,7 @@ final class PeerInfoHeaderNode: ASDisplayNode { transition.updateSublayerTransformScale(node: self.avatarListNode.listContainerTransformNode, scale: avatarListContainerScale) } - if deviceMetrics.hasDynamicIsland && self.forumTopicThreadId == nil && self.navigationTransition == nil { + if deviceMetrics.hasDynamicIsland && self.forumTopicThreadId == nil && self.navigationTransition == nil && !isLandscape { let maskValue = max(0.0, min(1.0, contentOffset / 120.0)) self.avatarListNode.containerNode.view.mask = self.avatarListNode.maskNode.view if maskValue > 0.03 { @@ -3368,7 +3370,12 @@ final class PeerInfoHeaderNode: ASDisplayNode { self.avatarListNode.listContainerNode.topShadowNode.isHidden = !self.isAvatarExpanded - self.avatarListNode.maskNode.position = CGPoint(x: 0.0, y: -self.avatarListNode.frame.minY + 48.0 + 85.5) + var avatarMaskOffset: CGFloat = 0.0 + if contentOffset < 0.0 { + avatarMaskOffset -= contentOffset + } + + self.avatarListNode.maskNode.position = CGPoint(x: 0.0, y: -self.avatarListNode.frame.minY + 48.0 + 85.5 + avatarMaskOffset) self.avatarListNode.maskNode.bounds = CGRect(origin: .zero, size: CGSize(width: 171.0, height: 171.0)) self.avatarListNode.bottomCoverNode.position = self.avatarListNode.maskNode.position