diff --git a/TelegramUI/BotCheckoutControllerNode.swift b/TelegramUI/BotCheckoutControllerNode.swift index 190e42186b..7e108c8624 100644 --- a/TelegramUI/BotCheckoutControllerNode.swift +++ b/TelegramUI/BotCheckoutControllerNode.swift @@ -451,9 +451,56 @@ final class BotCheckoutControllerNode: ItemListControllerNode, } var dismissImpl: (() -> Void)? - + let canSave = paymentForm.canSaveCredentials || paymentForm.passwordMissing let controller = BotCheckoutNativeCardEntryController(account: strongSelf.account, additionalFields: additionalFields, publishableKey: publishableKey, completion: { method in - applyPaymentMethod(method) + guard let strongSelf = self else { + return + } + if canSave && paymentForm.passwordMissing { + switch method { + case let .webToken(webToken) where webToken.saveOnServer: + var text = strongSelf.presentationData.strings.Checkout_NewCard_SaveInfoEnableHelp + text = text.replacingOccurrences(of: "[", with: "") + text = text.replacingOccurrences(of: "]", with: "") + present(standardTextAlertController(theme: AlertControllerTheme(presentationTheme: strongSelf.presentationData.theme), title: nil, text: text, actions: [TextAlertAction(type: .genericAction, title: strongSelf.presentationData.strings.Common_NotNow, action: { + var updatedToken = webToken + updatedToken.saveOnServer = false + applyPaymentMethod(.webToken(updatedToken)) + }), TextAlertAction(type: .defaultAction, title: strongSelf.presentationData.strings.Common_Yes, action: { + guard let strongSelf = self else { + return + } + if paymentForm.passwordMissing { + var updatedToken = webToken + updatedToken.saveOnServer = false + applyPaymentMethod(.webToken(updatedToken)) + + let controller = SetupTwoStepVerificationController(account: strongSelf.account, initialState: .automatic, stateUpdated: { update, shouldDismiss, controller in + if shouldDismiss { + controller.dismiss() + } + switch update { + case .noPassword, .awaitingEmailConfirmation: + break + case .passwordSet: + var updatedToken = webToken + updatedToken.saveOnServer = true + applyPaymentMethod(.webToken(updatedToken)) + } + }) + strongSelf.present(controller, ViewControllerPresentationArguments(presentationAnimation: .modalSheet)) + } else { + var updatedToken = webToken + updatedToken.saveOnServer = true + applyPaymentMethod(.webToken(updatedToken)) + } + })]), nil) + default: + break + } + } else { + applyPaymentMethod(method) + } dismissImpl?() }) dismissImpl = { [weak controller] in diff --git a/TelegramUI/BotPaymentSwitchItemNode.swift b/TelegramUI/BotPaymentSwitchItemNode.swift index 84c1295b03..d24982ae01 100644 --- a/TelegramUI/BotPaymentSwitchItemNode.swift +++ b/TelegramUI/BotPaymentSwitchItemNode.swift @@ -5,12 +5,21 @@ import Display private let titleFont = Font.regular(17.0) final class BotPaymentSwitchItemNode: BotPaymentItemNode { + private let toggled: (Bool) -> Void + private let title: String private let titleNode: ASTextNode private let switchNode: SwitchNode + private let buttonNode: HighlightableButtonNode private var theme: PresentationTheme? + var canBeSwitched: Bool { + didSet { + + } + } + var isOn: Bool { get { return self.switchNode.isOn @@ -21,8 +30,10 @@ final class BotPaymentSwitchItemNode: BotPaymentItemNode { } } - init(title: String, isOn: Bool) { + init(title: String, isOn: Bool, canBeSwitched: Bool = true, toggled: @escaping (Bool) -> Void = { _ in }) { self.title = title + self.canBeSwitched = canBeSwitched + self.toggled = toggled self.titleNode = ASTextNode() self.titleNode.maximumNumberOfLines = 1 @@ -30,10 +41,21 @@ final class BotPaymentSwitchItemNode: BotPaymentItemNode { self.switchNode = SwitchNode() self.switchNode.setOn(isOn, animated: false) + self.buttonNode = HighlightableButtonNode() + super.init(needsBackground: true) self.addSubnode(self.titleNode) self.addSubnode(self.switchNode) + self.addSubnode(self.buttonNode) + self.buttonNode.addTarget(self, action: #selector(self.buttonPressed), forControlEvents: .touchUpInside) + if canBeSwitched { + self.switchNode.isUserInteractionEnabled = true + self.buttonNode.isUserInteractionEnabled = false + } else { + self.switchNode.isUserInteractionEnabled = false + self.buttonNode.isUserInteractionEnabled = true + } } override func layoutContents(theme: PresentationTheme, width: CGFloat, measuredInset: CGFloat, transition: ContainedViewLayoutTransition) -> CGFloat { @@ -53,8 +75,14 @@ final class BotPaymentSwitchItemNode: BotPaymentItemNode { transition.updateFrame(node: self.titleNode, frame: CGRect(origin: CGPoint(x: leftInset, y: 11.0), size: titleSize)) let switchSize = self.switchNode.measure(CGSize(width: 100.0, height: 100.0)) - transition.updateFrame(node: self.switchNode, frame: CGRect(origin: CGPoint(x: width - switchSize.width - 15.0, y: 6.0), size: switchSize)) + let switchFrame = CGRect(origin: CGPoint(x: width - switchSize.width - 15.0, y: 6.0), size: switchSize) + transition.updateFrame(node: self.switchNode, frame: switchFrame) + transition.updateFrame(node: self.buttonNode, frame: switchFrame) return 44.0 } + + @objc private func buttonPressed() { + self.toggled(!self.isOn) + } } diff --git a/TelegramUI/ChatListController.swift b/TelegramUI/ChatListController.swift index ac9380a9fc..923e8dcdfa 100644 --- a/TelegramUI/ChatListController.swift +++ b/TelegramUI/ChatListController.swift @@ -4,28 +4,6 @@ import SwiftSignalKit import Display import TelegramCore -//private let tabImageNone = UIImage(bundleImageName: "Chat List/Tabs/IconChats")?.precomposed() -//private let tabImageUp = tabImageNone.flatMap({ image in -// return generateImage(image.size, contextGenerator: { size, context in -// context.clear(CGRect(origin: CGPoint(), size: size)) -// context.draw(image.cgImage!, in: CGRect(origin: CGPoint(), size: size)) -// context.setBlendMode(.copy) -// context.setFillColor(UIColor.clear.cgColor) -// context.translateBy(x: 0.0, y: 7.0) -// let _ = try? drawSvgPath(context, path: "M14.6557321,9.04533883 C14.9642504,8.81236784 15.4032142,8.87361104 15.6361852,9.18212936 C15.8691562,9.49064768 15.807913,9.9296115 15.4993947,10.1625825 L11.612306,13.0978342 C11.3601561,13.2882398 11.0117095,13.2861239 10.7618904,13.0926701 L6.97141581,10.1574184 C6.66574952,9.92071787 6.60984175,9.48104267 6.84654232,9.17537638 C7.08324289,8.86971009 7.5229181,8.81380232 7.82858438,9.05050289 L11.1958257,11.658013 L14.6557321,9.04533883 Z ") -// }) -//}) -//private let tabImageUnread = tabImageNone.flatMap({ image in -// return generateImage(image.size, contextGenerator: { size, context in -// context.clear(CGRect(origin: CGPoint(), size: size)) -// context.draw(image.cgImage!, in: CGRect(origin: CGPoint(), size: size)) -// context.setBlendMode(.copy) -// context.setFillColor(UIColor.clear.cgColor) -// context.translateBy(x: 0.0, y: 7.0) -// let _ = try? drawSvgPath(context, path: "M14.6557321,12.0977948 L11.1958257,9.48512064 L7.82858438,12.0926307 C7.5229181,12.3293313 7.08324289,12.2734235 6.84654232,11.9677572 C6.60984175,11.662091 6.66574952,11.2224158 6.97141581,10.9857152 L10.7618904,8.05046348 C11.0117095,7.85700968 11.3601561,7.85489378 11.612306,8.04529942 L15.4993947,10.9805511 C15.807913,11.2135221 15.8691562,11.6524859 15.6361852,11.9610043 C15.4032142,12.2695226 14.9642504,12.3307658 14.6557321,12.0977948 Z ") -// }) -//}) - public class ChatListController: TelegramController, KeyShortcutResponder, UIViewControllerPreviewingDelegate { private var validLayout: ContainerViewLayout? @@ -284,7 +262,7 @@ public class ChatListController: TelegramController, KeyShortcutResponder, UIVie } override public func loadDisplayNode() { - self.displayNode = ChatListControllerNode(account: self.account, groupId: self.groupId, controlsHistoryPreload: self.controlsHistoryPreload, presentationData: self.presentationData) + self.displayNode = ChatListControllerNode(account: self.account, groupId: self.groupId, controlsHistoryPreload: self.controlsHistoryPreload, presentationData: self.presentationData, controller: self) self.chatListDisplayNode.navigationBar = self.navigationBar @@ -520,7 +498,7 @@ public class ChatListController: TelegramController, KeyShortcutResponder, UIVie if !self.didSetup3dTouch { self.didSetup3dTouch = true if #available(iOSApplicationExtension 9.0, *) { - self.registerForPreviewing(with: self, sourceView: self.view, theme: PeekControllerTheme(presentationTheme: self.presentationData.theme), onlyNative: false) + self.registerForPreviewingNonNative(with: self, sourceView: self.view, theme: PeekControllerTheme(presentationTheme: self.presentationData.theme)) } } @@ -678,6 +656,19 @@ public class ChatListController: TelegramController, KeyShortcutResponder, UIVie } public func previewingContext(_ previewingContext: UIViewControllerPreviewing, viewControllerForLocation location: CGPoint) -> UIViewController? { + if #available(iOSApplicationExtension 9.0, *) { + if let (controller, rect) = self.previewingController(from: previewingContext.sourceView, for: location) { + previewingContext.sourceRect = rect + return controller + } else { + return nil + } + } else { + return nil + } + } + + func previewingController(from sourceView: UIView, for location: CGPoint) -> (UIViewController, CGRect)? { guard let layout = self.validLayout, case .compact = layout.metrics.widthClass else { return nil } @@ -693,11 +684,8 @@ public class ChatListController: TelegramController, KeyShortcutResponder, UIVie if let searchController = self.chatListDisplayNode.searchDisplayController { if let (view, action) = searchController.previewViewAndActionAtLocation(location) { if let peerId = action as? PeerId, peerId.namespace != Namespaces.Peer.SecretChat { - if #available(iOSApplicationExtension 9.0, *) { - var sourceRect = view.superview!.convert(view.frame, to: self.view) - sourceRect.size.height -= UIScreenPixel - previewingContext.sourceRect = sourceRect - } + var sourceRect = view.superview!.convert(view.frame, to: sourceView) + sourceRect.size.height -= UIScreenPixel let chatController = ChatController(account: self.account, chatLocation: .peer(peerId), mode: .standard(previewing: true)) // chatController.peekActions = .remove({ [weak self] in @@ -709,18 +697,15 @@ public class ChatListController: TelegramController, KeyShortcutResponder, UIVie // }) chatController.canReadHistory.set(false) chatController.containerLayoutUpdated(ContainerViewLayout(size: contentSize, metrics: LayoutMetrics(), intrinsicInsets: UIEdgeInsets(), safeInsets: UIEdgeInsets(), statusBarHeight: nil, inputHeight: nil, standardInputHeight: 216.0, inputHeightIsInteractivellyChanging: false), transition: .immediate) - return chatController + return (chatController, sourceRect) } else if let messageId = action as? MessageId, messageId.peerId.namespace != Namespaces.Peer.SecretChat { - if #available(iOSApplicationExtension 9.0, *) { - var sourceRect = view.superview!.convert(view.frame, to: self.view) - sourceRect.size.height -= UIScreenPixel - previewingContext.sourceRect = sourceRect - } + var sourceRect = view.superview!.convert(view.frame, to: sourceView) + sourceRect.size.height -= UIScreenPixel let chatController = ChatController(account: self.account, chatLocation: .peer(messageId.peerId), messageId: messageId, mode: .standard(previewing: true)) chatController.canReadHistory.set(false) chatController.containerLayoutUpdated(ContainerViewLayout(size: contentSize, metrics: LayoutMetrics(), intrinsicInsets: UIEdgeInsets(), safeInsets: UIEdgeInsets(), statusBarHeight: nil, inputHeight: nil, standardInputHeight: 216.0, inputHeightIsInteractivellyChanging: false), transition: .immediate) - return chatController + return (chatController, sourceRect) } } return nil @@ -745,25 +730,22 @@ public class ChatListController: TelegramController, KeyShortcutResponder, UIVie } } if let selectedNode = selectedNode, let item = selectedNode.item { - if #available(iOSApplicationExtension 9.0, *) { - var sourceRect = selectedNode.view.superview!.convert(selectedNode.frame, to: self.view) - sourceRect.size.height -= UIScreenPixel - previewingContext.sourceRect = sourceRect - } + var sourceRect = selectedNode.view.superview!.convert(selectedNode.frame, to: sourceView) + sourceRect.size.height -= UIScreenPixel switch item.content { case let .peer(_, peer, _, _, _, _, _, _, _): if peer.peerId.namespace != Namespaces.Peer.SecretChat { let chatController = ChatController(account: self.account, chatLocation: .peer(peer.peerId), mode: .standard(previewing: true)) chatController.canReadHistory.set(false) chatController.containerLayoutUpdated(ContainerViewLayout(size: contentSize, metrics: LayoutMetrics(), intrinsicInsets: UIEdgeInsets(), safeInsets: UIEdgeInsets(), statusBarHeight: nil, inputHeight: nil, standardInputHeight: 216.0, inputHeightIsInteractivellyChanging: false), transition: .immediate) - return chatController + return (chatController, sourceRect) } else { return nil } case let .groupReference(groupId, _, _, _): let chatListController = ChatListController(account: self.account, groupId: groupId, controlsHistoryPreload: false) chatListController.containerLayoutUpdated(ContainerViewLayout(size: contentSize, metrics: LayoutMetrics(), intrinsicInsets: UIEdgeInsets(), safeInsets: UIEdgeInsets(), statusBarHeight: nil, inputHeight: nil, standardInputHeight: 216.0, inputHeightIsInteractivellyChanging: false), transition: .immediate) - return chatListController + return (chatListController, sourceRect) } } else { return nil @@ -771,6 +753,10 @@ public class ChatListController: TelegramController, KeyShortcutResponder, UIVie } public func previewingContext(_ previewingContext: UIViewControllerPreviewing, commit viewControllerToCommit: UIViewController) { + self.previewingCommit(viewControllerToCommit) + } + + func previewingCommit(_ viewControllerToCommit: UIViewController) { if let viewControllerToCommit = viewControllerToCommit as? ViewController { if let chatController = viewControllerToCommit as? ChatController { chatController.canReadHistory.set(true) diff --git a/TelegramUI/ChatListControllerNode.swift b/TelegramUI/ChatListControllerNode.swift index fca3ec36d5..d2a98dc783 100644 --- a/TelegramUI/ChatListControllerNode.swift +++ b/TelegramUI/ChatListControllerNode.swift @@ -4,6 +4,18 @@ import Display import Postbox import TelegramCore +private final class ChatListControllerNodeView: UITracingLayerView, PreviewingHostView { + var previewingDelegate: PreviewingHostViewDelegate? { + return PreviewingHostViewDelegate(controllerForLocation: { [weak self] sourceView, point in + return self?.controller?.previewingController(from: sourceView, for: point) + }, commitController: { [weak self] controller in + self?.controller?.previewingCommit(controller) + }) + } + + weak var controller: ChatListController? +} + class ChatListControllerNode: ASDisplayNode { private let account: Account private let groupId: PeerGroupId? @@ -11,6 +23,7 @@ class ChatListControllerNode: ASDisplayNode { private var chatListEmptyNode: ChatListEmptyNode? let chatListNode: ChatListNode var navigationBar: NavigationBar? + weak var controller: ChatListController? private(set) var searchDisplayController: SearchDisplayController? @@ -24,17 +37,19 @@ class ChatListControllerNode: ASDisplayNode { var themeAndStrings: (PresentationTheme, PresentationStrings, dateTimeFormat: PresentationDateTimeFormat) - init(account: Account, groupId: PeerGroupId?, controlsHistoryPreload: Bool, presentationData: PresentationData) { + init(account: Account, groupId: PeerGroupId?, controlsHistoryPreload: Bool, presentationData: PresentationData, controller: ChatListController) { self.account = account self.groupId = groupId self.chatListNode = ChatListNode(account: account, groupId: groupId, controlsHistoryPreload: controlsHistoryPreload, mode: .chatList, theme: presentationData.theme, strings: presentationData.strings, dateTimeFormat: presentationData.dateTimeFormat, nameSortOrder: presentationData.nameSortOrder, nameDisplayOrder: presentationData.nameDisplayOrder, disableAnimations: presentationData.disableAnimations) self.themeAndStrings = (presentationData.theme, presentationData.strings, presentationData.dateTimeFormat) + self.controller = controller + super.init() self.setViewBlock({ - return UITracingLayerView() + return ChatListControllerNodeView() }) self.backgroundColor = presentationData.theme.chatList.backgroundColor @@ -62,6 +77,12 @@ class ChatListControllerNode: ASDisplayNode { } } + override func didLoad() { + super.didLoad() + + (self.view as? ChatListControllerNodeView)?.controller = self.controller + } + func updateThemeAndStrings(theme: PresentationTheme, strings: PresentationStrings, dateTimeFormat: PresentationDateTimeFormat, nameSortOrder: PresentationPersonNameOrder, nameDisplayOrder: PresentationPersonNameOrder, disableAnimations: Bool) { self.themeAndStrings = (theme, strings, dateTimeFormat) diff --git a/TelegramUI/ChatRecentActionsController.swift b/TelegramUI/ChatRecentActionsController.swift index 5004365417..073fcedb02 100644 --- a/TelegramUI/ChatRecentActionsController.swift +++ b/TelegramUI/ChatRecentActionsController.swift @@ -109,7 +109,7 @@ final class ChatRecentActionsController: TelegramController { self.displayNode = ChatRecentActionsControllerNode(account: self.account, peer: self.peer, presentationData: self.presentationData, interaction: self.interaction, pushController: { [weak self] c in (self?.navigationController as? NavigationController)?.pushViewController(c) }, presentController: { [weak self] c, a in - self?.present(c, in: .window(.root), with: a) + self?.present(c, in: .window(.root), with: a, blockInteraction: true) }, getNavigationController: { [weak self] in return self?.navigationController as? NavigationController }) diff --git a/TelegramUI/PeerMediaCollectionController.swift b/TelegramUI/PeerMediaCollectionController.swift index 6b77a758bf..0677f0ee3a 100644 --- a/TelegramUI/PeerMediaCollectionController.swift +++ b/TelegramUI/PeerMediaCollectionController.swift @@ -87,7 +87,7 @@ public class PeerMediaCollectionController: TelegramController { return openChatMessage(account: account, message: galleryMessage.message, standalone: false, reverseMessageGalleryOrder: true, navigationController: navigationController, dismissInput: { self?.mediaCollectionDisplayNode.view.endEditing(true) }, present: { c, a in - self?.present(c, in: .window(.root), with: a) + self?.present(c, in: .window(.root), with: a, blockInteraction: true) }, transitionNode: { messageId, media in if let strongSelf = self { return strongSelf.mediaCollectionDisplayNode.transitionNodeForGallery(messageId: messageId, media: media) diff --git a/TelegramUI/PhotoResources.swift b/TelegramUI/PhotoResources.swift index 189d453cb1..cd29ea5f8f 100644 --- a/TelegramUI/PhotoResources.swift +++ b/TelegramUI/PhotoResources.swift @@ -1463,17 +1463,51 @@ func internalMediaGridMessageVideo(postbox: Postbox, videoReference: FileMediaRe let blurSourceImage = thumbnailImage ?? fullSizeImage if let fullSizeImage = blurSourceImage { + var sideBlurredImage: UIImage? let thumbnailSize = CGSize(width: fullSizeImage.width, height: fullSizeImage.height) - let thumbnailContextSize = thumbnailSize.aspectFitted(CGSize(width: 74.0, height: 74.0)) - let thumbnailContext = DrawingContext(size: thumbnailContextSize, scale: 1.0) - thumbnailContext.withFlippedContext { c in - c.interpolationQuality = .none - c.draw(fullSizeImage, in: CGRect(origin: CGPoint(), size: thumbnailContextSize)) + if true { + let initialThumbnailContextFittingSize = fittedSize.fitted(CGSize(width: 100.0, height: 100.0)) + + let thumbnailContextSize = thumbnailSize.aspectFitted(initialThumbnailContextFittingSize) + let thumbnailContext = DrawingContext(size: thumbnailContextSize, scale: 1.0) + thumbnailContext.withFlippedContext { c in + c.interpolationQuality = .none + c.draw(fullSizeImage, in: CGRect(origin: CGPoint(), size: thumbnailContextSize)) + } + telegramFastBlur(Int32(thumbnailContextSize.width), Int32(thumbnailContextSize.height), Int32(thumbnailContext.bytesPerRow), thumbnailContext.bytes) + + var thumbnailContextFittingSize = CGSize(width: floor(arguments.drawingSize.width * 0.5), height: floor(arguments.drawingSize.width * 0.5)) + if thumbnailContextFittingSize.width < 150.0 || thumbnailContextFittingSize.height < 150.0 { + thumbnailContextFittingSize = thumbnailContextFittingSize.aspectFilled(CGSize(width: 150.0, height: 150.0)) + } + + if thumbnailContextFittingSize.width > thumbnailContextSize.width { + let additionalContextSize = thumbnailContextFittingSize + let additionalBlurContext = DrawingContext(size: additionalContextSize, scale: 1.0) + additionalBlurContext.withFlippedContext { c in + c.interpolationQuality = .default + if let image = thumbnailContext.generateImage()?.cgImage { + c.draw(image, in: CGRect(origin: CGPoint(), size: additionalContextSize)) + } + } + telegramFastBlur(Int32(additionalContextSize.width), Int32(additionalContextSize.height), Int32(additionalBlurContext.bytesPerRow), additionalBlurContext.bytes) + sideBlurredImage = additionalBlurContext.generateImage() + } else { + sideBlurredImage = thumbnailContext.generateImage() + } + } else { + let thumbnailContextSize = thumbnailSize.aspectFitted(CGSize(width: 74.0, height: 74.0)) + let thumbnailContext = DrawingContext(size: thumbnailContextSize, scale: 1.0) + thumbnailContext.withFlippedContext { c in + c.interpolationQuality = .none + c.draw(fullSizeImage, in: CGRect(origin: CGPoint(), size: thumbnailContextSize)) + } + telegramFastBlur(Int32(thumbnailContextSize.width), Int32(thumbnailContextSize.height), Int32(thumbnailContext.bytesPerRow), thumbnailContext.bytes) + telegramFastBlur(Int32(thumbnailContextSize.width), Int32(thumbnailContextSize.height), Int32(thumbnailContext.bytesPerRow), thumbnailContext.bytes) + sideBlurredImage = thumbnailContext.generateImage() } - telegramFastBlur(Int32(thumbnailContextSize.width), Int32(thumbnailContextSize.height), Int32(thumbnailContext.bytesPerRow), thumbnailContext.bytes) - telegramFastBlur(Int32(thumbnailContextSize.width), Int32(thumbnailContextSize.height), Int32(thumbnailContext.bytesPerRow), thumbnailContext.bytes) - if let blurredImage = thumbnailContext.generateImage() { + if let blurredImage = sideBlurredImage { let filledSize = thumbnailSize.aspectFilled(arguments.drawingRect.size) c.interpolationQuality = .medium c.draw(blurredImage.cgImage!, in: CGRect(origin: CGPoint(x: arguments.drawingRect.minX + (arguments.drawingRect.width - filledSize.width) / 2.0, y: arguments.drawingRect.minY + (arguments.drawingRect.height - filledSize.height) / 2.0), size: filledSize)) diff --git a/TelegramUI/TelegramController.swift b/TelegramUI/TelegramController.swift index b0e9cb2446..912b405528 100644 --- a/TelegramUI/TelegramController.swift +++ b/TelegramUI/TelegramController.swift @@ -22,7 +22,7 @@ private func presentLiveLocationController(account: Account, peerId: PeerId, con let _ = openChatMessage(account: account, message: message, standalone: false, reverseMessageGalleryOrder: false, navigationController: strongController.navigationController as? NavigationController, modal: true, dismissInput: { controller?.view.endEditing(true) }, present: { c, a in - controller?.present(c, in: .window(.root), with: a) + controller?.present(c, in: .window(.root), with: a, blockInteraction: true) }, transitionNode: { _, _ in return nil }, addToTransitionSurface: { _ in