From aa244fbccee3309d5b6d36b353b7ff06798b1fa7 Mon Sep 17 00:00:00 2001 From: Ilya Laktyushin Date: Mon, 28 Jul 2025 02:08:28 +0200 Subject: [PATCH 1/2] Various improvements --- .../MultilineTextWithEntitiesComponent.swift | 9 ++ .../ChatMessagePaymentAlertController.swift | 86 +++++++++++++------ .../Sources/GiftStoreScreen.swift | 8 +- .../Sources/GiftPurchaseAlertController.swift | 17 +++- .../Sources/GiftViewScreen.swift | 58 ++++++++----- .../Stars/StarsBalanceOverlayComponent/BUILD | 1 + .../StarsBalanceOverlayComponent.swift | 32 ++++++- .../Sources/TabSelectorComponent.swift | 6 +- 8 files changed, 162 insertions(+), 55 deletions(-) diff --git a/submodules/Components/MultilineTextWithEntitiesComponent/Sources/MultilineTextWithEntitiesComponent.swift b/submodules/Components/MultilineTextWithEntitiesComponent/Sources/MultilineTextWithEntitiesComponent.swift index 1f1d326fc9..aeb2ea838f 100644 --- a/submodules/Components/MultilineTextWithEntitiesComponent/Sources/MultilineTextWithEntitiesComponent.swift +++ b/submodules/Components/MultilineTextWithEntitiesComponent/Sources/MultilineTextWithEntitiesComponent.swift @@ -34,6 +34,7 @@ public final class MultilineTextWithEntitiesComponent: Component { public let handleSpoilers: Bool public let manualVisibilityControl: Bool public let resetAnimationsOnVisibilityChange: Bool + public let displaysAsynchronously: Bool public let highlightAction: (([NSAttributedString.Key: Any]) -> NSAttributedString.Key?)? public let tapAction: (([NSAttributedString.Key: Any], Int) -> Void)? public let longTapAction: (([NSAttributedString.Key: Any], Int) -> Void)? @@ -58,6 +59,7 @@ public final class MultilineTextWithEntitiesComponent: Component { handleSpoilers: Bool = false, manualVisibilityControl: Bool = false, resetAnimationsOnVisibilityChange: Bool = false, + displaysAsynchronously: Bool = true, highlightAction: (([NSAttributedString.Key: Any]) -> NSAttributedString.Key?)? = nil, tapAction: (([NSAttributedString.Key: Any], Int) -> Void)? = nil, longTapAction: (([NSAttributedString.Key: Any], Int) -> Void)? = nil @@ -82,6 +84,7 @@ public final class MultilineTextWithEntitiesComponent: Component { self.handleSpoilers = handleSpoilers self.manualVisibilityControl = manualVisibilityControl self.resetAnimationsOnVisibilityChange = resetAnimationsOnVisibilityChange + self.displaysAsynchronously = displaysAsynchronously self.tapAction = tapAction self.longTapAction = longTapAction } @@ -120,6 +123,9 @@ public final class MultilineTextWithEntitiesComponent: Component { if lhs.resetAnimationsOnVisibilityChange != rhs.resetAnimationsOnVisibilityChange { return false } + if lhs.displaysAsynchronously != rhs.displaysAsynchronously { + return false + } if let lhsTextShadowColor = lhs.textShadowColor, let rhsTextShadowColor = rhs.textShadowColor { if !lhsTextShadowColor.isEqual(rhsTextShadowColor) { return false @@ -161,6 +167,7 @@ public final class MultilineTextWithEntitiesComponent: Component { public override init(frame: CGRect) { self.textNode = ImmediateTextNodeWithEntities() + super.init(frame: frame) self.addSubview(self.textNode.view) @@ -175,6 +182,8 @@ public final class MultilineTextWithEntitiesComponent: Component { } public func update(component: MultilineTextWithEntitiesComponent, availableSize: CGSize, transition: ComponentTransition) -> CGSize { + self.textNode.displaysAsynchronously = component.displaysAsynchronously + let attributedString: NSAttributedString switch component.text { case let .plain(string): diff --git a/submodules/TelegramUI/Components/Chat/ChatMessagePaymentAlertController/Sources/ChatMessagePaymentAlertController.swift b/submodules/TelegramUI/Components/Chat/ChatMessagePaymentAlertController/Sources/ChatMessagePaymentAlertController.swift index 5e2cc65719..ea8efafcfa 100644 --- a/submodules/TelegramUI/Components/Chat/ChatMessagePaymentAlertController/Sources/ChatMessagePaymentAlertController.swift +++ b/submodules/TelegramUI/Components/Chat/ChatMessagePaymentAlertController/Sources/ChatMessagePaymentAlertController.swift @@ -4,6 +4,7 @@ import SwiftSignalKit import AsyncDisplayKit import Display import ComponentFlow +import ComponentDisplayAdapters import Postbox import TelegramCore import TelegramPresentationData @@ -323,28 +324,41 @@ public class ChatMessagePaymentAlertController: AlertController { private weak var parentNavigationController: NavigationController? private let chatPeerId: EnginePeer.Id private let showBalance: Bool + private let animateBalanceOverlay: Bool + private var didUpdateCurrency = false public var currency: CurrencyAmount.Currency { didSet { + self.didUpdateCurrency = true if let layout = self.validLayout { - self.containerLayoutUpdated(layout, transition: .immediate) + self.containerLayoutUpdated(layout, transition: .animated(duration: 0.25, curve: .easeInOut)) } } } - + private let balance = ComponentView() private var didAppear = false private var validLayout: ContainerViewLayout? - public init(context: AccountContext?, presentationData: PresentationData, contentNode: AlertContentNode, navigationController: NavigationController?, chatPeerId: EnginePeer.Id, showBalance: Bool = true, currency: CurrencyAmount.Currency = .stars) { + public init( + context: AccountContext?, + presentationData: PresentationData, + contentNode: AlertContentNode, + navigationController: NavigationController?, + chatPeerId: EnginePeer.Id, + showBalance: Bool = true, + currency: CurrencyAmount.Currency = .stars, + animateBalanceOverlay: Bool = true + ) { self.context = context self.presentationData = presentationData self.parentNavigationController = navigationController self.chatPeerId = chatPeerId self.showBalance = showBalance self.currency = currency + self.animateBalanceOverlay = animateBalanceOverlay super.init(theme: AlertControllerTheme(presentationData: presentationData), contentNode: contentNode) @@ -361,9 +375,18 @@ public class ChatMessagePaymentAlertController: AlertController { } private func animateOut() { - if let view = self.balance.view { - view.layer.animateScale(from: 1.0, to: 0.8, duration: 0.4, removeOnCompletion: false) - view.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.3, removeOnCompletion: false) + if !self.animateBalanceOverlay { + if self.currency == .ton && self.didUpdateCurrency { + self.currency = .stars + } + Queue.mainQueue().after(0.39, { + + }) + } else { + if let view = self.balance.view { + view.layer.animateScale(from: 1.0, to: 0.8, duration: 0.4, removeOnCompletion: false) + view.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.3, removeOnCompletion: false) + } } } @@ -389,8 +412,13 @@ public class ChatMessagePaymentAlertController: AlertController { if let context = self.context, let _ = self.parentNavigationController, self.showBalance { let insets = layout.insets(options: .statusBar) + var balanceTransition = ComponentTransition(transition) + if self.balance.view == nil { + balanceTransition = .immediate + } + let balanceSize = self.balance.update( - transition: .immediate, + transition: balanceTransition, component: AnyComponent( StarsBalanceOverlayComponent( context: context, @@ -401,20 +429,28 @@ public class ChatMessagePaymentAlertController: AlertController { guard let self, let starsContext = context.starsContext, let navigationController = self.parentNavigationController else { return } + switch self.currency { + case .stars: + let _ = (context.engine.payments.starsTopUpOptions() + |> take(1) + |> deliverOnMainQueue).startStandalone(next: { options in + let controller = context.sharedContext.makeStarsPurchaseScreen( + context: context, + starsContext: starsContext, + options: options, + purpose: .generic, + completion: { _ in } + ) + navigationController.pushViewController(controller) + }) + case .ton: + var fragmentUrl = "https://fragment.com/ads/topup" + if let data = context.currentAppConfiguration.with({ $0 }).data, let value = data["ton_topup_url"] as? String { + fragmentUrl = value + } + context.sharedContext.applicationBindings.openUrl(fragmentUrl) + } self.dismissAnimated() - - let _ = (context.engine.payments.starsTopUpOptions() - |> take(1) - |> deliverOnMainQueue).startStandalone(next: { options in - let controller = context.sharedContext.makeStarsPurchaseScreen( - context: context, - starsContext: starsContext, - options: options, - purpose: .generic, - completion: { _ in } - ) - navigationController.pushViewController(controller) - }) } ) ), @@ -425,11 +461,13 @@ public class ChatMessagePaymentAlertController: AlertController { if view.superview == nil { self.view.addSubview(view) - view.layer.animatePosition(from: CGPoint(x: 0.0, y: -64.0), to: .zero, duration: 0.4, timingFunction: kCAMediaTimingFunctionSpring, additive: true) - view.layer.animateSpring(from: 0.8 as NSNumber, to: 1.0 as NSNumber, keyPath: "transform.scale", duration: 0.5, initialVelocity: 0.0, removeOnCompletion: true, additive: false, completion: nil) - view.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.25) + if self.animateBalanceOverlay { + view.layer.animatePosition(from: CGPoint(x: 0.0, y: -64.0), to: .zero, duration: 0.4, timingFunction: kCAMediaTimingFunctionSpring, additive: true) + view.layer.animateSpring(from: 0.8 as NSNumber, to: 1.0 as NSNumber, keyPath: "transform.scale", duration: 0.5, initialVelocity: 0.0, removeOnCompletion: true, additive: false, completion: nil) + view.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.25) + } } - view.frame = CGRect(origin: CGPoint(x: floorToScreenPixels((layout.size.width - balanceSize.width) / 2.0), y: insets.top + 5.0), size: balanceSize) + balanceTransition.setFrame(view: view, frame: CGRect(origin: CGPoint(x: floorToScreenPixels((layout.size.width - balanceSize.width) / 2.0), y: insets.top + 5.0), size: balanceSize)) } } } diff --git a/submodules/TelegramUI/Components/Gifts/GiftStoreScreen/Sources/GiftStoreScreen.swift b/submodules/TelegramUI/Components/Gifts/GiftStoreScreen/Sources/GiftStoreScreen.swift index 8d9dfaf95f..726b43a459 100644 --- a/submodules/TelegramUI/Components/Gifts/GiftStoreScreen/Sources/GiftStoreScreen.swift +++ b/submodules/TelegramUI/Components/Gifts/GiftStoreScreen/Sources/GiftStoreScreen.swift @@ -162,9 +162,11 @@ final class GiftStoreScreenComponent: Component { } private func updateScrolling(interactive: Bool = false, transition: ComponentTransition) { - guard let environment = self.environment, let component = self.component, self.state?.starGiftsState?.dataState != .loading else { + guard let environment = self.environment, let component = self.component else { return } + + //, self.state?.starGiftsState?.dataState != .loading let availableWidth = self.scrollView.bounds.width let availableHeight = self.scrollView.bounds.height @@ -456,7 +458,7 @@ final class GiftStoreScreenComponent: Component { } let bottomContentOffset = max(0.0, self.scrollView.contentSize.height - self.scrollView.contentOffset.y - self.scrollView.frame.height) - if interactive, bottomContentOffset < 1000.0 { + if interactive, bottomContentOffset < 800.0 { self.state?.starGiftsContext.loadMore() } } @@ -1142,7 +1144,7 @@ final class GiftStoreScreenComponent: Component { context: component.context, colors: FilterSelectorComponent.Colors( foreground: theme.list.itemPrimaryTextColor.withMultipliedAlpha(0.65), - background: theme.list.itemSecondaryTextColor.mixedWith(theme.list.blocksBackgroundColor, alpha: 0.85) + background: theme.list.itemSecondaryTextColor.withMultipliedAlpha(0.15) ), items: filterItems, selectedItemId: self.selectedFilterId diff --git a/submodules/TelegramUI/Components/Gifts/GiftViewScreen/Sources/GiftPurchaseAlertController.swift b/submodules/TelegramUI/Components/Gifts/GiftViewScreen/Sources/GiftPurchaseAlertController.swift index 123c972eea..f7a10e0c95 100644 --- a/submodules/TelegramUI/Components/Gifts/GiftViewScreen/Sources/GiftPurchaseAlertController.swift +++ b/submodules/TelegramUI/Components/Gifts/GiftViewScreen/Sources/GiftPurchaseAlertController.swift @@ -446,7 +446,8 @@ public func giftPurchaseAlertController( gift: StarGift.UniqueGift, peer: EnginePeer, navigationController: NavigationController?, - commit: @escaping (CurrencyAmount.Currency) -> Void + commit: @escaping (CurrencyAmount.Currency) -> Void, + dismissed: @escaping () -> Void ) -> AlertController { let presentationData = context.sharedContext.currentPresentationData.with { $0 } let strings = presentationData.strings @@ -463,7 +464,19 @@ public func giftPurchaseAlertController( contentNode = GiftPurchaseAlertContentNode(context: context, theme: AlertControllerTheme(presentationData: presentationData), presentationTheme: presentationData.theme, strings: strings, gift: gift, peer: peer, actions: actions) - let controller = ChatMessagePaymentAlertController(context: context, presentationData: presentationData, contentNode: contentNode!, navigationController: navigationController, chatPeerId: context.account.peerId, showBalance: true, currency: gift.resellForTonOnly ? .ton : .stars) + let controller = ChatMessagePaymentAlertController( + context: context, + presentationData: presentationData, + contentNode: contentNode!, + navigationController: navigationController, + chatPeerId: context.account.peerId, + showBalance: true, + currency: gift.resellForTonOnly ? .ton : .stars, + animateBalanceOverlay: false + ) + controller.dismissed = { _ in + dismissed() + } dismissImpl = { [weak controller] animated in if animated { diff --git a/submodules/TelegramUI/Components/Gifts/GiftViewScreen/Sources/GiftViewScreen.swift b/submodules/TelegramUI/Components/Gifts/GiftViewScreen/Sources/GiftViewScreen.swift index d8da28ca82..dd233c0f29 100644 --- a/submodules/TelegramUI/Components/Gifts/GiftViewScreen/Sources/GiftViewScreen.swift +++ b/submodules/TelegramUI/Components/Gifts/GiftViewScreen/Sources/GiftViewScreen.swift @@ -1367,8 +1367,9 @@ private final class GiftViewSheetContent: CombinedComponent { ) } - if let buyForm = self.buyForm, let price = buyForm.invoice.prices.first?.amount { - if buyForm.invoice.currency == "XTR", let starsContext = context.starsContext, let starsState = context.starsContext?.currentState, starsState.balance < StarsAmount(value: price, nanos: 0) { + + if let _ = self.buyForm { + if resellAmount.currency == .stars, let starsContext = context.starsContext, let starsState = context.starsContext?.currentState, starsState.balance < resellAmount.amount { if self.options.isEmpty { self.inProgress = true self.updated() @@ -1384,7 +1385,7 @@ private final class GiftViewSheetContent: CombinedComponent { context: context, starsContext: starsContext, options: options ?? [], - purpose: .buyStarGift(requiredStars: price), + purpose: .buyStarGift(requiredStars: resellAmount.amount.value), completion: { [weak self, weak starsContext] stars in guard let self, let starsContext else { return @@ -1402,7 +1403,7 @@ private final class GiftViewSheetContent: CombinedComponent { guard let self, let starsContext = self.context.starsContext, let starsState = starsContext.currentState else { return } - if starsState.balance < StarsAmount(value: price, nanos: 0) { + if starsState.balance < resellAmount.amount { self.inProgress = false self.updated() @@ -1416,11 +1417,11 @@ private final class GiftViewSheetContent: CombinedComponent { ) controller.push(purchaseController) }) - } else if buyForm.invoice.currency == "TON", let tonState = context.tonContext?.currentState, tonState.balance < StarsAmount(value: price, nanos: 0) { + } else if resellAmount.currency == .ton, let tonState = context.tonContext?.currentState, tonState.balance < resellAmount.amount { guard let controller = self.getController() else { return } - let needed = StarsAmount(value: price, nanos: 0) - tonState.balance + let needed = resellAmount.amount - tonState.balance var fragmentUrl = "https://fragment.com/ads/topup" if let data = self.context.currentAppConfiguration.with({ $0 }).data, let value = data["ton_topup_url"] as? String { fragmentUrl = value @@ -1463,9 +1464,18 @@ private final class GiftViewSheetContent: CombinedComponent { navigationController: controller.navigationController as? NavigationController, commit: { currency in action(currency) + }, + dismissed: { [weak controller] in + if let balanceView = controller?.balanceOverlay.view { + balanceView.isHidden = false + } } ) controller.present(alertController, in: .window(.root)) + + if let balanceView = controller.balanceOverlay.view { + balanceView.isHidden = true + } } }) } @@ -3835,7 +3845,7 @@ public class GiftViewScreen: ViewControllerComponentContainer { } fileprivate var balanceCurrency: CurrencyAmount.Currency - private let balanceOverlay = ComponentView() + fileprivate let balanceOverlay = ComponentView() fileprivate let updateSavedToProfile: ((StarGiftReference, Bool) -> Void)? fileprivate let convertToStars: (() -> Void)? @@ -4007,20 +4017,28 @@ public class GiftViewScreen: ViewControllerComponentContainer { guard let self, let starsContext = context.starsContext, let navigationController = self.navigationController as? NavigationController else { return } + switch self.balanceCurrency { + case .stars: + let _ = (context.engine.payments.starsTopUpOptions() + |> take(1) + |> deliverOnMainQueue).startStandalone(next: { options in + let controller = context.sharedContext.makeStarsPurchaseScreen( + context: context, + starsContext: starsContext, + options: options, + purpose: .generic, + completion: { _ in } + ) + navigationController.pushViewController(controller) + }) + case .ton: + var fragmentUrl = "https://fragment.com/ads/topup" + if let data = context.currentAppConfiguration.with({ $0 }).data, let value = data["ton_topup_url"] as? String { + fragmentUrl = value + } + context.sharedContext.applicationBindings.openUrl(fragmentUrl) + } self.dismissAnimated() - - let _ = (context.engine.payments.starsTopUpOptions() - |> take(1) - |> deliverOnMainQueue).startStandalone(next: { options in - let controller = context.sharedContext.makeStarsPurchaseScreen( - context: context, - starsContext: starsContext, - options: options, - purpose: .generic, - completion: { _ in } - ) - navigationController.pushViewController(controller) - }) } ) ), diff --git a/submodules/TelegramUI/Components/Stars/StarsBalanceOverlayComponent/BUILD b/submodules/TelegramUI/Components/Stars/StarsBalanceOverlayComponent/BUILD index b7cb88ace6..d3e5547d25 100644 --- a/submodules/TelegramUI/Components/Stars/StarsBalanceOverlayComponent/BUILD +++ b/submodules/TelegramUI/Components/Stars/StarsBalanceOverlayComponent/BUILD @@ -16,6 +16,7 @@ swift_library( "//submodules/SSignalKit/SwiftSignalKit", "//submodules/AccountContext", "//submodules/ComponentFlow", + "//submodules/Components/ComponentDisplayAdapters", "//submodules/Components/MultilineTextComponent", "//submodules/Components/MultilineTextWithEntitiesComponent", "//submodules/TelegramPresentationData", diff --git a/submodules/TelegramUI/Components/Stars/StarsBalanceOverlayComponent/Sources/StarsBalanceOverlayComponent.swift b/submodules/TelegramUI/Components/Stars/StarsBalanceOverlayComponent/Sources/StarsBalanceOverlayComponent.swift index 693c9df67d..bc8f90430f 100644 --- a/submodules/TelegramUI/Components/Stars/StarsBalanceOverlayComponent/Sources/StarsBalanceOverlayComponent.swift +++ b/submodules/TelegramUI/Components/Stars/StarsBalanceOverlayComponent/Sources/StarsBalanceOverlayComponent.swift @@ -2,6 +2,7 @@ import Foundation import UIKit import Display import ComponentFlow +import ComponentDisplayAdapters import SwiftSignalKit import TelegramCore import AccountContext @@ -172,7 +173,13 @@ public final class StarsBalanceOverlayComponent: Component { if previousComponent?.currency != component.currency { if let textView = self.text.view { - textView.removeFromSuperview() + if !transition.animation.isImmediate { + transition.setAlpha(view: textView, alpha: 0.0, completion: { _ in + textView.removeFromSuperview() + }) + } else { + textView.removeFromSuperview() + } } self.text = ComponentView() } @@ -185,7 +192,8 @@ public final class StarsBalanceOverlayComponent: Component { animationCache: component.context.animationCache, animationRenderer: component.context.animationRenderer, placeholderColor: .white, - text: .plain(attributedText) + text: .plain(attributedText), + displaysAsynchronously: false ) ), environment: {}, @@ -219,7 +227,12 @@ public final class StarsBalanceOverlayComponent: Component { if let actionView = self.action.view { if actionView.superview == nil { + actionView.alpha = 1.0 self.backgroundView.addSubview(actionView) + + if !transition.animation.isImmediate { + transition.animateAlpha(view: actionView, from: 0.0, to: 1.0) + } } actionView.frame = CGRect(origin: CGPoint(x: floorToScreenPixels((size.width - actionSize.width) / 2.0), y: 29.0), size: actionSize) } @@ -227,19 +240,30 @@ public final class StarsBalanceOverlayComponent: Component { size = CGSize(width: textSize.width + 40.0, height: 35.0) if let actionView = self.action.view, actionView.superview != nil { - actionView.removeFromSuperview() + if !transition.animation.isImmediate { + transition.setAlpha(view: actionView, alpha: 0.0, completion: { _ in + actionView.removeFromSuperview() + }) + } else { + actionView.removeFromSuperview() + } } } if let textView = self.text.view { if textView.superview == nil { + textView.alpha = 1.0 self.backgroundView.addSubview(textView) + + if !transition.animation.isImmediate { + transition.animateAlpha(view: textView, from: 0.0, to: 1.0) + } } textView.frame = CGRect(origin: CGPoint(x: floorToScreenPixels((size.width - textSize.width) / 2.0), y: 10.0), size: textSize) } self.backgroundView.updateColor(color: component.theme.rootController.navigationBar.opaqueBackgroundColor, transition: .immediate) - self.backgroundView.update(size: size, cornerRadius: size.height / 2.0, transition: .immediate) + self.backgroundView.update(size: size, cornerRadius: size.height / 2.0, transition: transition.containedViewLayoutTransition) transition.setFrame(view: self.backgroundView, frame: CGRect(origin: CGPoint(x: floor((availableSize.width - size.width) / 2.0), y: 0.0), size: size)) return CGSize(width: availableSize.width, height: size.height) diff --git a/submodules/TelegramUI/Components/TabSelectorComponent/Sources/TabSelectorComponent.swift b/submodules/TelegramUI/Components/TabSelectorComponent/Sources/TabSelectorComponent.swift index ef0827e734..b9b2f275ec 100644 --- a/submodules/TelegramUI/Components/TabSelectorComponent/Sources/TabSelectorComponent.swift +++ b/submodules/TelegramUI/Components/TabSelectorComponent/Sources/TabSelectorComponent.swift @@ -842,7 +842,8 @@ private final class ItemComponent: CombinedComponent { animationCache: component.context?.animationCache, animationRenderer: component.context?.animationRenderer, placeholderColor: .white, - text: .plain(attributedTitle) + text: .plain(attributedTitle), + displaysAsynchronously: false ), availableSize: context.availableSize, transition: .immediate @@ -864,7 +865,8 @@ private final class ItemComponent: CombinedComponent { animationCache: nil, animationRenderer: nil, placeholderColor: .white, - text: .plain(selectedAttributedTitle) + text: .plain(selectedAttributedTitle), + displaysAsynchronously: false ), availableSize: context.availableSize, transition: .immediate From 17140bf9616ce2aca148d07c36b72577012aa3ab Mon Sep 17 00:00:00 2001 From: Ilya Laktyushin Date: Mon, 28 Jul 2025 03:20:17 +0200 Subject: [PATCH 2/2] Various improvements --- .../DataAndStorageSettingsController.swift | 35 +++++++++++++------ 1 file changed, 24 insertions(+), 11 deletions(-) diff --git a/submodules/SettingsUI/Sources/Data and Storage/DataAndStorageSettingsController.swift b/submodules/SettingsUI/Sources/Data and Storage/DataAndStorageSettingsController.swift index 5db34b987b..3554501b8c 100644 --- a/submodules/SettingsUI/Sources/Data and Storage/DataAndStorageSettingsController.swift +++ b/submodules/SettingsUI/Sources/Data and Storage/DataAndStorageSettingsController.swift @@ -618,7 +618,7 @@ private func autosaveLabelAndValue(presentationData: PresentationData, settings: return (label, value) } -private func dataAndStorageControllerEntries(state: DataAndStorageControllerState, data: DataAndStorageData, presentationData: PresentationData, defaultWebBrowser: String, contentSettingsConfiguration: ContentSettingsConfiguration?, networkUsage: Int64, storageUsage: Int64, mediaAutoSaveSettings: MediaAutoSaveSettings, autosaveExceptionPeers: [EnginePeer.Id: EnginePeer?], mediaSettings: MediaDisplaySettings, showSensitiveContentSetting: Bool) -> [DataAndStorageEntry] { +private func dataAndStorageControllerEntries(context: AccountContext, state: DataAndStorageControllerState, data: DataAndStorageData, presentationData: PresentationData, defaultWebBrowser: String, contentSettingsConfiguration: ContentSettingsConfiguration?, networkUsage: Int64, storageUsage: Int64, mediaAutoSaveSettings: MediaAutoSaveSettings, autosaveExceptionPeers: [EnginePeer.Id: EnginePeer?], mediaSettings: MediaDisplaySettings, showSensitiveContentSetting: Bool) -> [DataAndStorageEntry] { var entries: [DataAndStorageEntry] = [] entries.append(.storageUsage(presentationData.theme, presentationData.strings.ChatSettings_Cache, dataSizeString(storageUsage, formatting: DataSizeStringFormatting(presentationData: presentationData)))) @@ -657,7 +657,7 @@ private func dataAndStorageControllerEntries(state: DataAndStorageControllerStat entries.append(.raiseToListen(presentationData.theme, presentationData.strings.Settings_RaiseToListen, data.mediaInputSettings.enableRaiseToSpeak)) entries.append(.raiseToListenInfo(presentationData.theme, presentationData.strings.Settings_RaiseToListenInfo)) - if let contentSettingsConfiguration = contentSettingsConfiguration, contentSettingsConfiguration.canAdjustSensitiveContent && showSensitiveContentSetting { + if let contentSettingsConfiguration = contentSettingsConfiguration, contentSettingsConfiguration.canAdjustSensitiveContent && (showSensitiveContentSetting || requireAgeVerification(context: context)) { entries.append(.sensitiveContent(presentationData.strings.Settings_SensitiveContent, contentSettingsConfiguration.sensitiveContentEnabled)) entries.append(.sensitiveContentInfo(presentationData.strings.Settings_SensitiveContentInfo)) } @@ -685,6 +685,7 @@ public func dataAndStorageController(context: AccountContext, focusOnItemTag: Da var pushControllerImpl: ((ViewController) -> Void)? var presentControllerImpl: ((ViewController, ViewControllerPresentationArguments?) -> Void)? + var presentAgeVerificationImpl: ((@escaping () -> Void) -> Void)? let actionsDisposable = DisposableSet() @@ -914,14 +915,18 @@ public func dataAndStorageController(context: AccountContext, focusOnItemTag: Da updateSensitiveContentDisposable.set(updateRemoteContentSettingsConfiguration(postbox: context.account.postbox, network: context.account.network, sensitiveContentEnabled: value).start()) } if value { - let presentationData = context.sharedContext.currentPresentationData.with { $0 } - let alertController = textAlertController(context: context, title: presentationData.strings.SensitiveContent_Enable_Title, text: presentationData.strings.SensitiveContent_Enable_Text, actions: [ - TextAlertAction(type: .genericAction, title: presentationData.strings.Common_Cancel, action: {}), - TextAlertAction(type: .defaultAction, title: presentationData.strings.SensitiveContent_Enable_Confirm, action: { - update() - }) - ]) - presentControllerImpl?(alertController, nil) + if requireAgeVerification(context: context) { + presentAgeVerificationImpl?(update) + } else { + let presentationData = context.sharedContext.currentPresentationData.with { $0 } + let alertController = textAlertController(context: context, title: presentationData.strings.SensitiveContent_Enable_Title, text: presentationData.strings.SensitiveContent_Enable_Text, actions: [ + TextAlertAction(type: .genericAction, title: presentationData.strings.Common_Cancel, action: {}), + TextAlertAction(type: .defaultAction, title: presentationData.strings.SensitiveContent_Enable_Confirm, action: { + update() + }) + ]) + presentControllerImpl?(alertController, nil) + } } else { update() } @@ -983,7 +988,7 @@ public func dataAndStorageController(context: AccountContext, focusOnItemTag: Da let showSensitiveContentSetting = canAdjustSensitiveContent.with { $0 } ?? false let controllerState = ItemListControllerState(presentationData: ItemListPresentationData(presentationData), title: .text(presentationData.strings.ChatSettings_Title), leftNavigationButton: nil, rightNavigationButton: nil, backNavigationButton: ItemListBackButton(title: presentationData.strings.Common_Back), animateChanges: false) - let listState = ItemListNodeState(presentationData: ItemListPresentationData(presentationData), entries: dataAndStorageControllerEntries(state: state, data: dataAndStorageData, presentationData: presentationData, defaultWebBrowser: defaultWebBrowser, contentSettingsConfiguration: contentSettingsConfiguration, networkUsage: usageSignal.network, storageUsage: usageSignal.storage, mediaAutoSaveSettings: mediaAutoSaveSettings, autosaveExceptionPeers: autosaveExceptionPeers, mediaSettings: mediaSettings, showSensitiveContentSetting: showSensitiveContentSetting), style: .blocks, ensureVisibleItemTag: focusOnItemTag, emptyStateItem: nil, animateChanges: animateChanges) + let listState = ItemListNodeState(presentationData: ItemListPresentationData(presentationData), entries: dataAndStorageControllerEntries(context: context, state: state, data: dataAndStorageData, presentationData: presentationData, defaultWebBrowser: defaultWebBrowser, contentSettingsConfiguration: contentSettingsConfiguration, networkUsage: usageSignal.network, storageUsage: usageSignal.storage, mediaAutoSaveSettings: mediaAutoSaveSettings, autosaveExceptionPeers: autosaveExceptionPeers, mediaSettings: mediaSettings, showSensitiveContentSetting: showSensitiveContentSetting), style: .blocks, ensureVisibleItemTag: focusOnItemTag, emptyStateItem: nil, animateChanges: animateChanges) return (controllerState, (listState, arguments)) } |> afterDisposed { @@ -999,6 +1004,14 @@ public func dataAndStorageController(context: AccountContext, focusOnItemTag: Da presentControllerImpl = { [weak controller] c, a in controller?.present(c, in: .window(.root), with: a) } + presentAgeVerificationImpl = { [weak controller] update in + guard let controller else { + return + } + presentAgeVerification(context: context, parentController: controller, completion: { + update() + }) + } return controller }