diff --git a/Telegram/Telegram-iOS/en.lproj/Localizable.strings b/Telegram/Telegram-iOS/en.lproj/Localizable.strings index 7051fae35d..c369488679 100644 --- a/Telegram/Telegram-iOS/en.lproj/Localizable.strings +++ b/Telegram/Telegram-iOS/en.lproj/Localizable.strings @@ -14736,8 +14736,8 @@ Sorry for the inconvenience."; "Gift.Options.Gift.BuyLimitReached_any" = "You've already sent %@ of these gifts, and it's the limit."; "AgeVerification.Title" = "Age Verification"; -"AgeVerification.Text" = "To access this content, you must confirm you are at least **18** years old as required by UK law.\n\nThis is a one-time process using your phone's camera. Your selfie will not be stored by Telegram."; -"AgeVerification.Text.gb" = "To access this content, you must confirm you are at least **18** years old as required by UK law.\n\nThis is a one-time process using your phone's camera. Your selfie will not be stored by Telegram."; +"AgeVerification.Text" = "To access this content, you must confirm you are at least **18** years old.\n\nThis is a one-time process using your phone's camera. Your selfie will not be stored by Telegram."; +"AgeVerification.Text.GB" = "To access this content, you must confirm you are at least **18** years old as required by UK law.\n\nThis is a one-time process using your phone's camera. Your selfie will not be stored by Telegram."; "AgeVerification.Verify" = "Verify My Age"; "AgeVerification.Success.Title" = "Age check passed!"; diff --git a/submodules/BotPaymentsUI/Sources/BotCheckoutController.swift b/submodules/BotPaymentsUI/Sources/BotCheckoutController.swift index 95baaa332f..035fa49f99 100644 --- a/submodules/BotPaymentsUI/Sources/BotCheckoutController.swift +++ b/submodules/BotPaymentsUI/Sources/BotCheckoutController.swift @@ -12,6 +12,7 @@ public final class BotCheckoutController: ViewController { public enum FetchError { case generic case disallowedStarGifts + case starGiftsUserLimit } public let form: BotPaymentForm @@ -58,6 +59,8 @@ public final class BotCheckoutController: ViewController { switch error { case .disallowedStarGift: return .disallowedStarGifts + case .starGiftUserLimit: + return .starGiftsUserLimit default: return .generic } diff --git a/submodules/TelegramCore/Sources/TelegramEngine/Payments/BotPaymentForm.swift b/submodules/TelegramCore/Sources/TelegramEngine/Payments/BotPaymentForm.swift index 9330c8db39..173c4b50c5 100644 --- a/submodules/TelegramCore/Sources/TelegramEngine/Payments/BotPaymentForm.swift +++ b/submodules/TelegramCore/Sources/TelegramEngine/Payments/BotPaymentForm.swift @@ -180,6 +180,7 @@ public enum BotPaymentFormRequestError { case noPaymentNeeded case disallowedStarGift case starGiftResellTooEarly(Int32) + case starGiftUserLimit } extension BotPaymentInvoice { @@ -488,6 +489,8 @@ func _internal_fetchBotPaymentForm(accountPeerId: PeerId, postbox: Postbox, netw if let value = Int32(timeout) { return .fail(.starGiftResellTooEarly(value)) } + } else if error.errorDescription == "STARGIFT_USER_USAGE_LIMITED" { + return .fail(.starGiftUserLimit) } return .fail(.generic) } @@ -651,6 +654,7 @@ public enum SendBotPaymentFormError { case alreadyPaid case starGiftOutOfStock case disallowedStarGift + case starGiftUserLimit } public enum SendBotPaymentResult { diff --git a/submodules/TelegramUI/Components/FaceScanScreen/Sources/AgeVerificationScreen.swift b/submodules/TelegramUI/Components/FaceScanScreen/Sources/AgeVerificationScreen.swift index efb8d18c65..bcf91273b2 100644 --- a/submodules/TelegramUI/Components/FaceScanScreen/Sources/AgeVerificationScreen.swift +++ b/submodules/TelegramUI/Components/FaceScanScreen/Sources/AgeVerificationScreen.swift @@ -407,7 +407,12 @@ public func presentAgeVerification(context: AccountContext, parentController: Vi } else { let infoScreen = AgeVerificationScreen(context: context, completion: { [weak parentController] check, availability in if check { - let scanScreen = FaceScanScreen(context: context, availability: availability, completion: { [weak parentController] passed in + var requiredAge = 18 + if let value = context.currentAppConfiguration.with({ $0 }).data?["verify_age_min"] as? Double { + requiredAge = Int(value) + } + + let scanScreen = FaceScanScreen(context: context, availability: availability, requiredAge: requiredAge, completion: { [weak parentController] passed in if passed { let _ = updateAgeVerificationState(engine: context.engine, { _ in return AgeVerificationState(verificationPassed: passed) diff --git a/submodules/TelegramUI/Components/FaceScanScreen/Sources/FaceScanScreen.swift b/submodules/TelegramUI/Components/FaceScanScreen/Sources/FaceScanScreen.swift index 334469152d..2be0e9db59 100644 --- a/submodules/TelegramUI/Components/FaceScanScreen/Sources/FaceScanScreen.swift +++ b/submodules/TelegramUI/Components/FaceScanScreen/Sources/FaceScanScreen.swift @@ -20,20 +20,21 @@ import ZipArchive import PlainButtonComponent import MultilineTextComponent -private let requiredAge = 18 - final class FaceScanScreenComponent: Component { typealias EnvironmentType = ViewControllerComponentContainer.Environment let context: AccountContext let availability: Signal + let requiredAge: Int init( context: AccountContext, - availability: Signal + availability: Signal, + requiredAge: Int ) { self.context = context self.availability = availability + self.requiredAge = requiredAge } static func ==(lhs: FaceScanScreenComponent, rhs: FaceScanScreenComponent) -> Bool { @@ -109,7 +110,7 @@ final class FaceScanScreenComponent: Component { self.backgroundColor = .black - self.previewLayer.backgroundColor = UIColor.red.cgColor + //self.previewLayer.backgroundColor = UIColor.red.cgColor self.previewLayer.videoGravity = .resizeAspectFill self.layer.addSublayer(previewLayer) @@ -240,7 +241,7 @@ final class FaceScanScreenComponent: Component { let targetCenter = CGPoint(x: 0.5, y: 0.5) let distance = sqrt(pow(faceCenter.x - targetCenter.x, 2) + pow(faceCenter.y - targetCenter.y, 2)) - if distance < 0.35 { + if distance < 0.24 { switch processState { case .waitingForFace: self.processState = .positioning @@ -306,7 +307,7 @@ final class FaceScanScreenComponent: Component { } private func fillSegment(_ segmentIndex: Int) { - guard !self.completedAngles.contains(segmentIndex) else { + guard let component = self.component, !self.completedAngles.contains(segmentIndex) else { return } self.completedAngles.insert(segmentIndex) @@ -320,7 +321,7 @@ final class FaceScanScreenComponent: Component { if !self.ages.isEmpty { let averageAge = self.ages.reduce(0, +) / Double(self.ages.count) if let environment = self.environment, let controller = environment.controller() as? FaceScanScreen { - controller.completion(averageAge >= Double(requiredAge)) + controller.completion(averageAge >= Double(component.requiredAge)) controller.dismiss(animated: true) } } else { @@ -457,7 +458,6 @@ final class FaceScanScreenComponent: Component { self.frameView.frame = frameViewFrame self.frameView.update(size: frameViewFrame.size) - //TODO:localize var instructionString = environment.strings.FaceScan_Instruction_Position switch self.processState { case .waitingForFace, .positioning: @@ -550,6 +550,7 @@ public final class FaceScanScreen: ViewControllerComponentContainer { public init( context: AccountContext, availability: Signal, + requiredAge: Int, completion: @escaping (Bool) -> Void ) { self.context = context @@ -557,7 +558,8 @@ public final class FaceScanScreen: ViewControllerComponentContainer { super.init(context: context, component: FaceScanScreenComponent( context: context, - availability: availability + availability: availability, + requiredAge: requiredAge ), navigationBarAppearance: .none, theme: .default, updatedPresentationData: nil) self.title = "" diff --git a/submodules/TelegramUI/Components/Gifts/GiftSetupScreen/Sources/GiftSetupScreen.swift b/submodules/TelegramUI/Components/Gifts/GiftSetupScreen/Sources/GiftSetupScreen.swift index eec3b4716c..fd33e2dc21 100644 --- a/submodules/TelegramUI/Components/Gifts/GiftSetupScreen/Sources/GiftSetupScreen.swift +++ b/submodules/TelegramUI/Components/Gifts/GiftSetupScreen/Sources/GiftSetupScreen.swift @@ -363,6 +363,8 @@ final class GiftSetupScreenComponent: Component { let entities = generateChatInputTextEntities(self.textInputState.text) var finalPrice: Int64 + var perUserLimit: Int32? + var giftFile: TelegramMediaFile? let source: BotPaymentInvoiceSource switch component.subject { case let .premium(product): @@ -377,6 +379,8 @@ final class GiftSetupScreenComponent: Component { if self.includeUpgrade, let upgradeStars = starGift.upgradeStars { finalPrice += upgradeStars } + perUserLimit = starGift.perUserLimit?.total + giftFile = starGift.file source = .starGift(hideName: self.hideName, includeUpgrade: self.includeUpgrade, peerId: peerId, giftId: starGift.id, text: self.textInputState.text.string, entities: entities) } @@ -395,6 +399,8 @@ final class GiftSetupScreenComponent: Component { switch error { case .disallowedStarGifts: return .fail(.disallowedStarGift) + case .starGiftsUserLimit: + return .fail(.starGiftUserLimit) default: return .fail(.generic) } @@ -468,6 +474,14 @@ final class GiftSetupScreenComponent: Component { var errorText: String? switch error { + case .starGiftUserLimit: + if let perUserLimit, let giftFile { + let text = presentationData.strings.Gift_Options_Gift_BuyLimitReached(perUserLimit) + let undoController = UndoOverlayController(presentationData: presentationData, content: .sticker(context: component.context, file: giftFile, loop: true, title: nil, text: text, undoText: nil, customAction: nil), action: { _ in return false }) + controller.present(undoController, in: .current) + return + } + return case .starGiftOutOfStock: errorText = presentationData.strings.Gift_Send_ErrorOutOfStock case .disallowedStarGift: diff --git a/submodules/TelegramUI/Components/Gifts/GiftViewScreen/Sources/GiftViewScreen.swift b/submodules/TelegramUI/Components/Gifts/GiftViewScreen/Sources/GiftViewScreen.swift index 3f2bb8baec..9ff2dc3ff3 100644 --- a/submodules/TelegramUI/Components/Gifts/GiftViewScreen/Sources/GiftViewScreen.swift +++ b/submodules/TelegramUI/Components/Gifts/GiftViewScreen/Sources/GiftViewScreen.swift @@ -288,11 +288,14 @@ private final class GiftViewSheetContent: CombinedComponent { } var minRequiredAmount = StarsAmount(value: 100, nanos: 0) + var canUpgrade = false if let resellStars = self.subject.arguments?.resellStars { minRequiredAmount = StarsAmount(value: resellStars, nanos: 0) + } else if let arguments = self.subject.arguments, arguments.canUpgrade && arguments.upgradeStars == nil { + canUpgrade = true } - if let starsContext = context.starsContext, let state = starsContext.currentState, state.balance < minRequiredAmount { + if let starsContext = context.starsContext, let state = starsContext.currentState, state.balance < minRequiredAmount || canUpgrade { self.optionsDisposable = (context.engine.payments.starsTopUpOptions() |> deliverOnMainQueue).start(next: { [weak self] options in guard let self else { diff --git a/submodules/TelegramUI/Components/PeerInfo/PeerInfoVisualMediaPaneNode/Sources/AddGiftsScreen.swift b/submodules/TelegramUI/Components/PeerInfo/PeerInfoVisualMediaPaneNode/Sources/AddGiftsScreen.swift index b1ec546109..23cdd4f560 100644 --- a/submodules/TelegramUI/Components/PeerInfo/PeerInfoVisualMediaPaneNode/Sources/AddGiftsScreen.swift +++ b/submodules/TelegramUI/Components/PeerInfo/PeerInfoVisualMediaPaneNode/Sources/AddGiftsScreen.swift @@ -23,17 +23,20 @@ final class AddGiftsScreenComponent: Component { let context: AccountContext let peerId: EnginePeer.Id let collectionId: Int32 + let remainingCount: Int32 let profileGifts: ProfileGiftsContext init( context: AccountContext, peerId: EnginePeer.Id, collectionId: Int32, + remainingCount: Int32, profileGifts: ProfileGiftsContext ) { self.context = context self.peerId = peerId self.collectionId = collectionId + self.remainingCount = remainingCount self.profileGifts = profileGifts } @@ -128,7 +131,7 @@ final class AddGiftsScreenComponent: Component { if let current = self.giftsListView { giftsListView = current } else { - giftsListView = GiftsListView(context: component.context, peerId: component.peerId, profileGifts: component.profileGifts, giftsCollections: nil, canSelect: true, ignoreCollection: component.collectionId) + giftsListView = GiftsListView(context: component.context, peerId: component.peerId, profileGifts: component.profileGifts, giftsCollections: nil, canSelect: true, ignoreCollection: component.collectionId, remainingSelectionCount: component.remainingCount) giftsListView.selectionUpdated = { [weak self] in guard let self else { return @@ -248,6 +251,7 @@ public final class AddGiftsScreen: ViewControllerComponentContainer { context: AccountContext, peerId: EnginePeer.Id, collectionId: Int32, + remainingCount: Int32, completion: @escaping ([ProfileGiftsContext.State.StarGift]) -> Void ) { self.context = context @@ -264,10 +268,10 @@ public final class AddGiftsScreen: ViewControllerComponentContainer { context: context, peerId: peerId, collectionId: collectionId, + remainingCount: remainingCount, profileGifts: self.profileGifts ), navigationBarAppearance: .default, theme: .default, updatedPresentationData: nil) - self.title = presentationData.strings.AddGifts_Title self.navigationPresentation = .modal diff --git a/submodules/TelegramUI/Components/PeerInfo/PeerInfoVisualMediaPaneNode/Sources/GiftsListView.swift b/submodules/TelegramUI/Components/PeerInfo/PeerInfoVisualMediaPaneNode/Sources/GiftsListView.swift index ef195fb43d..b42e5eae26 100644 --- a/submodules/TelegramUI/Components/PeerInfo/PeerInfoVisualMediaPaneNode/Sources/GiftsListView.swift +++ b/submodules/TelegramUI/Components/PeerInfo/PeerInfoVisualMediaPaneNode/Sources/GiftsListView.swift @@ -36,6 +36,7 @@ final class GiftsListView: UIView { private let canSelect: Bool private let ignoreCollection: Int32? + private let remainingSelectionCount: Int32 private var dataDisposable: Disposable? @@ -124,13 +125,14 @@ final class GiftsListView: UIView { var contextAction: ((ProfileGiftsContext.State.StarGift, UIView, ContextGesture) -> Void)? var addToCollection: (() -> Void)? - init(context: AccountContext, peerId: PeerId, profileGifts: ProfileGiftsContext, giftsCollections: ProfileGiftsCollectionsContext?, canSelect: Bool, ignoreCollection: Int32? = nil) { + init(context: AccountContext, peerId: PeerId, profileGifts: ProfileGiftsContext, giftsCollections: ProfileGiftsCollectionsContext?, canSelect: Bool, ignoreCollection: Int32? = nil, remainingSelectionCount: Int32 = 0) { self.context = context self.peerId = peerId self.profileGifts = profileGifts self.giftsCollections = giftsCollections self.canSelect = canSelect self.ignoreCollection = ignoreCollection + self.remainingSelectionCount = remainingSelectionCount if let value = context.currentAppConfiguration.with({ $0 }).data?["stargifts_pinned_to_top_limit"] as? Double { self.maxPinnedCount = Int(value) @@ -548,8 +550,10 @@ final class GiftsListView: UIView { if self.selectedItemIds.contains(itemReferenceId) { self.selectedItemIds.remove(itemReferenceId) } else { - self.selectedItemIds.insert(itemReferenceId) - self.selectedItemsMap[itemReferenceId] = product + if self.selectedItemIds.count < self.remainingSelectionCount { + self.selectedItemIds.insert(itemReferenceId) + self.selectedItemsMap[itemReferenceId] = product + } } self.selectionUpdated() self.updateScrolling(transition: .easeInOut(duration: 0.25)) diff --git a/submodules/TelegramUI/Components/PeerInfo/PeerInfoVisualMediaPaneNode/Sources/PeerInfoGiftsPaneNode.swift b/submodules/TelegramUI/Components/PeerInfo/PeerInfoVisualMediaPaneNode/Sources/PeerInfoGiftsPaneNode.swift index ab1595fa59..a736019aad 100644 --- a/submodules/TelegramUI/Components/PeerInfo/PeerInfoVisualMediaPaneNode/Sources/PeerInfoGiftsPaneNode.swift +++ b/submodules/TelegramUI/Components/PeerInfo/PeerInfoVisualMediaPaneNode/Sources/PeerInfoGiftsPaneNode.swift @@ -242,7 +242,15 @@ public final class PeerInfoGiftsPaneNode: ASDisplayNode, PeerInfoPaneNode, UIScr } public func addGiftsToCollection(id: Int32) { - let screen = AddGiftsScreen(context: self.context, peerId: self.peerId, collectionId: id, completion: { [weak self] gifts in + var collectionGiftsMaxCount: Int32 = 1000 + if let value = self.context.currentAppConfiguration.with({ $0 }).data?["stargifts_collection_gifts_limit"] as? Double { + collectionGiftsMaxCount = Int32(value) + } + var remainingCount = collectionGiftsMaxCount + if let currentCount = self.giftsListView.profileGifts.currentState?.count { + remainingCount = max(0, collectionGiftsMaxCount - currentCount) + } + let screen = AddGiftsScreen(context: self.context, peerId: self.peerId, collectionId: id, remainingCount: remainingCount, completion: { [weak self] gifts in guard let self else { return } diff --git a/submodules/TelegramUI/Sources/TelegramRootController.swift b/submodules/TelegramUI/Sources/TelegramRootController.swift index 683e3bb911..35348db5b1 100644 --- a/submodules/TelegramUI/Sources/TelegramRootController.swift +++ b/submodules/TelegramUI/Sources/TelegramRootController.swift @@ -31,7 +31,6 @@ import PeerInfoScreen import PeerInfoStoryGridScreen import ShareWithPeersScreen import ChatEmptyNode -//import FaceScanScreen import UndoUI private class DetailsChatPlaceholderNode: ASDisplayNode, NavigationDetailsPlaceholderNode { @@ -237,22 +236,6 @@ public final class TelegramRootController: NavigationController, TelegramRootCon self.accountSettingsController = accountSettingsController self.rootTabController = tabBarController self.pushViewController(tabBarController, animated: false) - -// Queue.mainQueue().after(1.0) { -// let context = self.context -// let infoScreen = AgeVerificationScreen(context: context, completion: { [weak chatListController] proceed in -// if proceed { -// let scanScreen = FaceScanScreen(context: context, completion: { success in -// let controller = UndoOverlayController(presentationData: self.presentationData, content: .actionSucceeded(title: "Age check passed!", text: "You can now view this content.", cancel: nil, destructive: false), elevatedLayout: true, action: { _ in return true }) -// Queue.mainQueue().after(0.1) { -// chatListController?.present(controller, in: .window(.root)) -// } -// }) -// chatListController?.push(scanScreen) -// } -// }) -// chatListController.push(infoScreen) -// } } public func updateRootControllers(showCallsTab: Bool) {