diff --git a/submodules/AttachmentUI/Sources/AttachmentContainer.swift b/submodules/AttachmentUI/Sources/AttachmentContainer.swift index 7ea7aecff3..bf75ed7100 100644 --- a/submodules/AttachmentUI/Sources/AttachmentContainer.swift +++ b/submodules/AttachmentUI/Sources/AttachmentContainer.swift @@ -38,6 +38,7 @@ final class AttachmentContainer: ASDisplayNode, UIGestureRecognizerDelegate { var controllerRemoved: ((ViewController) -> Void)? var shouldCancelPanGesture: (() -> Bool)? + var requestDismiss: (() -> Void)? var updateModalProgress: ((CGFloat, ContainedViewLayoutTransition) -> Void)? @@ -236,6 +237,7 @@ final class AttachmentContainer: ASDisplayNode, UIGestureRecognizerDelegate { if !self.isExpanded, translation > 40.0, let shouldCancelPanGesture = self.shouldCancelPanGesture, shouldCancelPanGesture() { self.cancelPanGesture() + self.requestDismiss?() return } @@ -284,8 +286,13 @@ final class AttachmentContainer: ASDisplayNode, UIGestureRecognizerDelegate { let offset = currentTopInset + panOffset let topInset: CGFloat = edgeTopInset + var ignoreDismiss = false + if let shouldCancelPanGesture = self.shouldCancelPanGesture, shouldCancelPanGesture() { + ignoreDismiss = true + } + var dismissing = false - if bounds.minY < -60 || (bounds.minY < 0.0 && velocity.y > 300.0) || (self.isExpanded && bounds.minY.isZero && velocity.y > 1800.0) { + if (bounds.minY < -60 || (bounds.minY < 0.0 && velocity.y > 300.0) || (self.isExpanded && bounds.minY.isZero && velocity.y > 1800.0)) && !ignoreDismiss { self.interactivelyDismissed?() dismissing = true } else if self.isExpanded { diff --git a/submodules/AttachmentUI/Sources/AttachmentController.swift b/submodules/AttachmentUI/Sources/AttachmentController.swift index 0d792e7619..e8bfdf2ad8 100644 --- a/submodules/AttachmentUI/Sources/AttachmentController.swift +++ b/submodules/AttachmentUI/Sources/AttachmentController.swift @@ -320,11 +320,6 @@ public class AttachmentController: ViewController { self.container.shouldCancelPanGesture = { [weak self] in if let strongSelf = self, let currentController = strongSelf.currentControllers.last { if !currentController.shouldDismissImmediately() { - currentController.requestDismiss { [weak self] in - if let strongSelf = self { - strongSelf.controller?.dismiss(animated: true) - } - } return true } else { return false @@ -334,6 +329,16 @@ public class AttachmentController: ViewController { } } + self.container.requestDismiss = { [weak self] in + if let strongSelf = self, let currentController = strongSelf.currentControllers.last { + currentController.requestDismiss { [weak self] in + if let strongSelf = self { + strongSelf.controller?.dismiss(animated: true) + } + } + } + } + self.panel.selectionChanged = { [weak self] type in if let strongSelf = self { return strongSelf.switchToController(type) diff --git a/submodules/PremiumUI/Sources/GiftAvatarComponent.swift b/submodules/PremiumUI/Sources/GiftAvatarComponent.swift index f5fe398dd5..668a2e6a1f 100644 --- a/submodules/PremiumUI/Sources/GiftAvatarComponent.swift +++ b/submodules/PremiumUI/Sources/GiftAvatarComponent.swift @@ -50,11 +50,11 @@ private func generateDiffuseTexture() -> UIImage { class GiftAvatarComponent: Component { let context: AccountContext - let peer: EnginePeer + let peer: EnginePeer? let isVisible: Bool let hasIdleAnimations: Bool - init(context: AccountContext, peer: EnginePeer, isVisible: Bool, hasIdleAnimations: Bool) { + init(context: AccountContext, peer: EnginePeer?, isVisible: Bool, hasIdleAnimations: Bool) { self.context = context self.peer = peer self.isVisible = isVisible @@ -62,7 +62,7 @@ class GiftAvatarComponent: Component { } static func ==(lhs: GiftAvatarComponent, rhs: GiftAvatarComponent) -> Bool { - return lhs.isVisible == rhs.isVisible && lhs.hasIdleAnimations == rhs.hasIdleAnimations + return lhs.peer == rhs.peer && lhs.isVisible == rhs.isVisible && lhs.hasIdleAnimations == rhs.hasIdleAnimations } final class View: UIView, SCNSceneRendererDelegate, ComponentTaggedView { @@ -276,7 +276,9 @@ class GiftAvatarComponent: Component { self.hasIdleAnimations = component.hasIdleAnimations let avatarSize = CGSize(width: 100.0, height: 100.0) - self.avatarNode.setSignal(peerAvatarCompleteImage(account: component.context.account, peer: component.peer, size: avatarSize, font: avatarPlaceholderFont(size: 43.0), fullSize: true)) + if let peer = component.peer { + self.avatarNode.setSignal(peerAvatarCompleteImage(account: component.context.account, peer: peer, size: avatarSize, font: avatarPlaceholderFont(size: 43.0), fullSize: true)) + } self.avatarNode.frame = CGRect(origin: CGPoint(x: floorToScreenPixels((availableSize.width - avatarSize.width) / 2.0), y: 63.0), size: avatarSize) return availableSize diff --git a/submodules/PremiumUI/Sources/PremiumGiftScreen.swift b/submodules/PremiumUI/Sources/PremiumGiftScreen.swift index 370322e728..6fef507b35 100644 --- a/submodules/PremiumUI/Sources/PremiumGiftScreen.swift +++ b/submodules/PremiumUI/Sources/PremiumGiftScreen.swift @@ -500,14 +500,14 @@ private final class PremiumGiftScreenContentComponent: CombinedComponent { typealias EnvironmentType = (ViewControllerComponentContainer.Environment, ScrollChildEnvironment) let context: AccountContext - let peer: EnginePeer - let products: [InAppPurchaseManager.Product] - let selectedProductId: String + let peer: EnginePeer? + let products: [InAppPurchaseManager.Product]? + let selectedProductId: String? let present: (ViewController) -> Void let selectProduct: (String) -> Void - init(context: AccountContext, peer: EnginePeer, products: [InAppPurchaseManager.Product], selectedProductId: String, present: @escaping (ViewController) -> Void, selectProduct: @escaping (String) -> Void) { + init(context: AccountContext, peer: EnginePeer?, products: [InAppPurchaseManager.Product]?, selectedProductId: String?, present: @escaping (ViewController) -> Void, selectProduct: @escaping (String) -> Void) { self.context = context self.peer = peer self.products = products @@ -583,7 +583,6 @@ private final class PremiumGiftScreenContentComponent: CombinedComponent { let textColor = theme.list.itemPrimaryTextColor let subtitleColor = theme.list.itemSecondaryTextColor -// let arrowColor = theme.list.disclosureArrowColor let textFont = Font.regular(15.0) let boldTextFont = Font.semibold(15.0) @@ -594,7 +593,7 @@ private final class PremiumGiftScreenContentComponent: CombinedComponent { let text = text.update( component: MultilineTextComponent( text: .markdown( - text: strings.Premium_Gift_Description(component.peer.compactDisplayTitle).string, + text: strings.Premium_Gift_Description(component.peer?.compactDisplayTitle ?? "").string, attributes: markdownAttributes ), horizontalAlignment: .center, @@ -620,52 +619,54 @@ private final class PremiumGiftScreenContentComponent: CombinedComponent { ] var i = 0 - for product in component.products { - let monthsCount: Int - let giftTitle: String - let discount: String - switch product.id { - case "org.telegram.telegramPremium.twelveMonths": - giftTitle = strings.Premium_Gift_Years(1) - monthsCount = 12 - discount = "-15%" - case "org.telegram.telegramPremium.sixMonths": - giftTitle = strings.Premium_Gift_Months(6) - monthsCount = 6 - discount = "-10%" - case "org.telegram.telegramPremium.threeMonths": - giftTitle = strings.Premium_Gift_Months(3) - monthsCount = 3 - discount = "-7%" - default: - giftTitle = "" - monthsCount = 1 - discount = "" - } - - items.append(ProductGroupComponent.Item( - AnyComponentWithIdentity( - id: product.id, - component: AnyComponent( - GiftComponent( - title: giftTitle, - totalPrice: product.price, - perMonthPrice: strings.Premium_Gift_PricePerMonth(product.pricePerMonth(monthsCount)).string, - discount: discount, - selected: product.id == component.selectedProductId, - primaryTextColor: textColor, - secondaryTextColor: subtitleColor, - accentColor: gradientColors[i], - checkForegroundColor: environment.theme.list.itemCheckColors.foregroundColor, - checkBorderColor: environment.theme.list.itemCheckColors.strokeColor + if let products = component.products { + for product in products { + let monthsCount: Int + let giftTitle: String + let discount: String + switch product.id { + case "org.telegram.telegramPremium.twelveMonths": + giftTitle = strings.Premium_Gift_Years(1) + monthsCount = 12 + discount = "-15%" + case "org.telegram.telegramPremium.sixMonths": + giftTitle = strings.Premium_Gift_Months(6) + monthsCount = 6 + discount = "-10%" + case "org.telegram.telegramPremium.threeMonths": + giftTitle = strings.Premium_Gift_Months(3) + monthsCount = 3 + discount = "-7%" + default: + giftTitle = "" + monthsCount = 1 + discount = "" + } + + items.append(ProductGroupComponent.Item( + AnyComponentWithIdentity( + id: product.id, + component: AnyComponent( + GiftComponent( + title: giftTitle, + totalPrice: product.price, + perMonthPrice: strings.Premium_Gift_PricePerMonth(product.pricePerMonth(monthsCount)).string, + discount: discount, + selected: product.id == component.selectedProductId, + primaryTextColor: textColor, + secondaryTextColor: subtitleColor, + accentColor: gradientColors[i], + checkForegroundColor: environment.theme.list.itemCheckColors.foregroundColor, + checkBorderColor: environment.theme.list.itemCheckColors.strokeColor + ) ) - ) - ), - action: { - component.selectProduct(product.id) - }) - ) - i += 1 + ), + action: { + component.selectProduct(product.id) + }) + ) + i += 1 + } } let section = section.update( @@ -960,45 +961,43 @@ private final class PremiumGiftScreenComponent: CombinedComponent { .position(CGPoint(x: context.availableSize.width / 2.0, y: context.availableSize.height / 2.0)) ) - if let peer = state.peer, let products = state.products, let selectedProductId = state.selectedProductId { - let scrollContent = scrollContent.update( - component: ScrollComponent( - content: AnyComponent(PremiumGiftScreenContentComponent( - context: context.component.context, - peer: peer, - products: products, - selectedProductId: selectedProductId, - present: context.component.present, - selectProduct: { [weak state] productId in - state?.selectProduct(id: productId) - } - )), - contentInsets: UIEdgeInsets(top: environment.navigationHeight, left: 0.0, bottom: bottomPanelHeight, right: 0.0), - contentOffsetUpdated: { [weak state] topContentOffset, bottomContentOffset in - state?.topContentOffset = topContentOffset - state?.bottomContentOffset = bottomContentOffset - Queue.mainQueue().justDispatch { - state?.updated(transition: .immediate) - } - }, - contentOffsetWillCommit: { targetContentOffset in - if targetContentOffset.pointee.y < 100.0 { - targetContentOffset.pointee = CGPoint(x: 0.0, y: 0.0) - } else if targetContentOffset.pointee.y < 123.0 { - targetContentOffset.pointee = CGPoint(x: 0.0, y: 123.0) - } + let scrollContent = scrollContent.update( + component: ScrollComponent( + content: AnyComponent(PremiumGiftScreenContentComponent( + context: context.component.context, + peer: state.peer, + products: state.products, + selectedProductId: state.selectedProductId, + present: context.component.present, + selectProduct: { [weak state] productId in + state?.selectProduct(id: productId) } - ), - environment: { environment }, - availableSize: context.availableSize, - transition: context.transition - ) - - context.add(scrollContent - .position(CGPoint(x: context.availableSize.width / 2.0, y: context.availableSize.height / 2.0)) - ) - } - + )), + contentInsets: UIEdgeInsets(top: environment.navigationHeight, left: 0.0, bottom: bottomPanelHeight, right: 0.0), + contentOffsetUpdated: { [weak state] topContentOffset, bottomContentOffset in + state?.topContentOffset = topContentOffset + state?.bottomContentOffset = bottomContentOffset + Queue.mainQueue().justDispatch { + state?.updated(transition: .immediate) + } + }, + contentOffsetWillCommit: { targetContentOffset in + if targetContentOffset.pointee.y < 100.0 { + targetContentOffset.pointee = CGPoint(x: 0.0, y: 0.0) + } else if targetContentOffset.pointee.y < 123.0 { + targetContentOffset.pointee = CGPoint(x: 0.0, y: 123.0) + } + } + ), + environment: { environment }, + availableSize: context.availableSize, + transition: context.transition + ) + + context.add(scrollContent + .position(CGPoint(x: context.availableSize.width / 2.0, y: context.availableSize.height / 2.0)) + ) + let topPanelAlpha: CGFloat let titleOffset: CGFloat let titleScale: CGFloat @@ -1019,23 +1018,21 @@ private final class PremiumGiftScreenComponent: CombinedComponent { titleAlpha = 1.0 } - if let peer = context.state.peer { - let star = star.update( - component: GiftAvatarComponent( - context: context.component.context, - peer: peer, - isVisible: starIsVisible, - hasIdleAnimations: state.hasIdleAnimations - ), - availableSize: CGSize(width: min(390.0, context.availableSize.width), height: 220.0), - transition: context.transition - ) - - context.add(star - .position(CGPoint(x: context.availableSize.width / 2.0, y: topInset + star.size.height / 2.0 - 30.0 - titleOffset * titleScale)) - .scale(titleScale) - ) - } + let star = star.update( + component: GiftAvatarComponent( + context: context.component.context, + peer: context.state.peer, + isVisible: starIsVisible, + hasIdleAnimations: state.hasIdleAnimations + ), + availableSize: CGSize(width: min(390.0, context.availableSize.width), height: 220.0), + transition: context.transition + ) + + context.add(star + .position(CGPoint(x: context.availableSize.width / 2.0, y: topInset + star.size.height / 2.0 - 30.0 - titleOffset * titleScale)) + .scale(titleScale) + ) context.add(topPanel .position(CGPoint(x: context.availableSize.width / 2.0, y: topPanel.size.height / 2.0)) @@ -1251,27 +1248,16 @@ public final class PremiumGiftScreen: ViewControllerComponentContainer { strongSelf.view.disablesInteractiveModalDismiss = inProgress } } - -// presentImpl = { [weak self] c in -// self?.present(c, in: .window(.root)) -// } - + pushImpl = { [weak self] c in self?.push(c) } completionImpl = { [weak self] duration in if let strongSelf = self, let navigationController = strongSelf.navigationController as? NavigationController { -// let introController = PremiumIntroScreen(context: context, source: .gift(from: context.account.peerId, to: peerId, duration: duration)) var controllers = navigationController.viewControllers controllers = controllers.filter { !($0 is PeerInfoScreen) && !($0 is PremiumGiftScreen) } navigationController.setViewControllers(controllers, animated: true) - - Queue.mainQueue().after(2.8, { - if let topController = navigationController.viewControllers.last { - topController.view.addSubview(ConfettiView(frame: topController.view.bounds)) - } - }) } } } diff --git a/submodules/ShareController/Sources/ShareControllerNode.swift b/submodules/ShareController/Sources/ShareControllerNode.swift index 0130b9cb35..e014df4d9b 100644 --- a/submodules/ShareController/Sources/ShareControllerNode.swift +++ b/submodules/ShareController/Sources/ShareControllerNode.swift @@ -650,21 +650,23 @@ final class ShareControllerNode: ViewControllerTracingNode, UIScrollViewDelegate let doneImpl: (Bool) -> Void = { [weak self] shouldDelay in let minDelay: Double = shouldDelay ? 0.9 : 0.6 let delay: Double + let hapticDelay: Double + if let strongSelf = self, let contentNode = strongSelf.contentNode as? ShareProlongedLoadingContainerNode { delay = contentNode.completionDuration - - if shouldDelay { - Queue.mainQueue().after(delay - 1.5, { - if strongSelf.hapticFeedback == nil { - strongSelf.hapticFeedback = HapticFeedback() - } - strongSelf.hapticFeedback?.success() - }) - } + hapticDelay = shouldDelay ? delay - 1.5 : delay } else { delay = max(minDelay, (timestamp + minDelay) - CACurrentMediaTime()) + hapticDelay = delay } - + + Queue.mainQueue().after(hapticDelay, { + if self?.hapticFeedback == nil { + self?.hapticFeedback = HapticFeedback() + } + self?.hapticFeedback?.success() + }) + Queue.mainQueue().after(delay, { self?.animateOut(shared: true, completion: { self?.dismiss?(true)