diff --git a/submodules/BrowserUI/Sources/BrowserBookmarksScreen.swift b/submodules/BrowserUI/Sources/BrowserBookmarksScreen.swift index 1cf00e619e..a3bcafe42c 100644 --- a/submodules/BrowserUI/Sources/BrowserBookmarksScreen.swift +++ b/submodules/BrowserUI/Sources/BrowserBookmarksScreen.swift @@ -55,7 +55,7 @@ public final class BrowserBookmarksScreen: ViewController { }, navigateToMessage: { _, _, _ in }, navigateToMessageStandalone: { _ in }, navigateToThreadMessage: { _, _, _ in - }, tapMessage: nil, clickThroughMessage: { + }, tapMessage: nil, clickThroughMessage: { _, _ in }, toggleMessagesSelection: { _, _ in }, sendCurrentMessage: { _, _ in }, sendMessage: { _ in diff --git a/submodules/DrawingUI/BUILD b/submodules/DrawingUI/BUILD index 5d8642145c..68824329eb 100644 --- a/submodules/DrawingUI/BUILD +++ b/submodules/DrawingUI/BUILD @@ -97,6 +97,7 @@ swift_library( "//submodules/ChatPresentationInterfaceState:ChatPresentationInterfaceState", "//submodules/StickerPackPreviewUI:StickerPackPreviewUI", "//submodules/TelegramUI/Components/LottieComponent", + "//submodules/TelegramUI/Components/LottieComponentResourceContent", "//submodules/ImageTransparency", "//submodules/GalleryUI", "//submodules/MediaPlayer:UniversalMediaPlayer", diff --git a/submodules/DrawingUI/Sources/DrawingWeatherEntityView.swift b/submodules/DrawingUI/Sources/DrawingWeatherEntityView.swift index 1012eb1c77..5815a10143 100644 --- a/submodules/DrawingUI/Sources/DrawingWeatherEntityView.swift +++ b/submodules/DrawingUI/Sources/DrawingWeatherEntityView.swift @@ -1,6 +1,7 @@ import Foundation import UIKit import Display +import ComponentFlow import SwiftSignalKit import AccountContext import TelegramCore @@ -9,6 +10,8 @@ import TelegramAnimatedStickerNode import StickerResources import MediaEditor import TelegramStringFormatting +import LottieComponent +import LottieComponentResourceContent private func generateIcon(style: DrawingWeatherEntity.Style) -> UIImage? { guard let image = UIImage(bundleImageName: "Chat/Attach Menu/Location") else { @@ -53,9 +56,8 @@ public final class DrawingWeatherEntityView: DrawingEntityView, UITextViewDelega let backgroundView: UIView let textView: DrawingTextView - let iconView: UIImageView - private let imageNode: TransformImageNode - private var animationNode: AnimatedStickerNode? + + private var animation = ComponentView() private var didSetUpAnimationNode = false private let stickerFetchedDisposable = MetaDisposable() @@ -88,20 +90,14 @@ public final class DrawingWeatherEntityView: DrawingEntityView, UITextViewDelega self.textView.spellCheckingType = .no self.textView.textContainer.maximumNumberOfLines = 2 self.textView.textContainer.lineBreakMode = .byTruncatingTail - - self.iconView = UIImageView() - self.imageNode = TransformImageNode() - + super.init(context: context, entity: entity) self.textView.delegate = self self.addSubview(self.backgroundView) self.addSubview(self.textView) - self.addSubview(self.iconView) self.update(animated: false) - - self.setup() } required init?(coder: NSCoder) { @@ -134,17 +130,35 @@ public final class DrawingWeatherEntityView: DrawingEntityView, UITextViewDelega let iconSize = min(80.0, floor(self.bounds.height * 0.7)) let iconOffset: CGFloat = 0.3 - self.iconView.frame = CGRect(origin: CGPoint(x: floorToScreenPixels(iconSize * iconOffset), y: floorToScreenPixels((self.bounds.height - iconSize) / 2.0)), size: CGSize(width: iconSize, height: iconSize)) - self.imageNode.frame = self.iconView.frame.offsetBy(dx: 0.0, dy: 2.0) + let iconFrame = CGRect(origin: CGPoint(x: floorToScreenPixels(iconSize * iconOffset), y: floorToScreenPixels((self.bounds.height - iconSize) / 2.0)), size: CGSize(width: iconSize, height: iconSize)) - if let animationNode = self.animationNode { - animationNode.frame = self.iconView.frame - animationNode.updateLayout(size: self.iconView.frame.size) + if let icon = self.weatherEntity.icon { + let _ = self.animation.update( + transition: .immediate, + component: AnyComponent( + LottieComponent( + content: LottieComponent.ResourceContent( + context: self.context, + file: icon, + attemptSynchronously: true, + providesPlaceholder: true + ), + color: nil, + placeholderColor: UIColor(rgb: 0x000000, alpha: 0.1), + loop: !["🌑", "🌒", "🌓", "🌔", "🌕", "🌖", "🌗", "🌘"].contains(self.weatherEntity.emoji) + ) + ), + environment: {}, + containerSize: iconFrame.size + ) + if let animationView = self.animation.view { + if animationView.superview == nil { + self.addSubview(animationView) + } + animationView.frame = iconFrame + } } - - let imageSize = CGSize(width: iconSize, height: iconSize) - self.imageNode.asyncLayout()(TransformImageArguments(corners: ImageCorners(), imageSize: imageSize, boundingSize: imageSize, intrinsicInsets: UIEdgeInsets()))() - + self.textView.frame = CGRect(origin: CGPoint(x: self.bounds.width - self.textSize.width - 6.0, y: floorToScreenPixels((self.bounds.height - self.textSize.height) / 2.0)), size: self.textSize) self.backgroundView.frame = self.bounds } @@ -263,10 +277,8 @@ public final class DrawingWeatherEntityView: DrawingEntityView, UITextViewDelega self.sizeToFit() - if self.currentStyle != self.weatherEntity.style { - self.currentStyle = self.weatherEntity.style - self.iconView.image = generateIcon(style: self.weatherEntity.style) - } + + self.currentStyle = self.weatherEntity.style self.backgroundView.layer.cornerRadius = self.textSize.height * 0.2 if #available(iOS 13.0, *) { @@ -276,42 +288,6 @@ public final class DrawingWeatherEntityView: DrawingEntityView, UITextViewDelega super.update(animated: animated) } - private func setup() { - if let file = self.weatherEntity.icon { - self.iconView.isHidden = true - self.addSubnode(self.imageNode) - if let dimensions = file.dimensions { - if file.isAnimatedSticker || file.isVideoSticker || file.mimeType == "video/webm" { - let fittedDimensions = dimensions.cgSize.aspectFitted(CGSize(width: 256.0, height: 256.0)) - if self.animationNode == nil { - let animationNode = DefaultAnimatedStickerNodeImpl() - animationNode.autoplay = true - self.animationNode = animationNode - animationNode.started = { [weak self] in - self?.imageNode.isHidden = true - } - animationNode.setup(source: AnimatedStickerResourceSource(account: self.context.account, resource: file.resource, isVideo: file.isVideoSticker), width: Int(fittedDimensions.width), height: Int(fittedDimensions.height), playbackMode: .loop, mode: .direct(cachePathPrefix: nil)) - - self.addSubnode(animationNode) - } - self.imageNode.setSignal(chatMessageAnimatedSticker(postbox: self.context.account.postbox, userLocation: .other, file: file, small: false, size: fittedDimensions)) - self.stickerFetchedDisposable.set(freeMediaFileResourceInteractiveFetched(account: self.context.account, userLocation: .other, fileReference: stickerPackFileReference(file), resource: file.resource).start()) - } else { - if let animationNode = self.animationNode { - animationNode.visibility = false - self.animationNode = nil - animationNode.removeFromSupernode() - self.imageNode.isHidden = false - self.didSetUpAnimationNode = false - } - self.imageNode.setSignal(chatMessageSticker(account: self.context.account, userLocation: .other, file: file, small: false, synchronousLoad: false)) - self.stickerFetchedDisposable.set(freeMediaFileResourceInteractiveFetched(account: self.context.account, userLocation: .other, fileReference: stickerPackFileReference(file), resource: chatMessageStickerResource(file: file, small: false)).start()) - } - self.setNeedsLayout() - } - } - } - override func updateSelectionView() { guard let selectionView = self.selectionView as? DrawingWeatherEntitySelectionView else { return diff --git a/submodules/TelegramUI/Components/Stars/StarsPurchaseScreen/Sources/StarsPurchaseScreen.swift b/submodules/TelegramUI/Components/Stars/StarsPurchaseScreen/Sources/StarsPurchaseScreen.swift index 843c567bcc..74529be6e7 100644 --- a/submodules/TelegramUI/Components/Stars/StarsPurchaseScreen/Sources/StarsPurchaseScreen.swift +++ b/submodules/TelegramUI/Components/Stars/StarsPurchaseScreen/Sources/StarsPurchaseScreen.swift @@ -86,6 +86,7 @@ private final class StarsPurchaseScreenContentComponent: CombinedComponent { let peers: [EnginePeer.Id: EnginePeer] let stateUpdated: (ComponentTransition) -> Void let buy: (StarsProduct) -> Void + let openAppExamples: () -> Void init( context: AccountContext, @@ -100,7 +101,8 @@ private final class StarsPurchaseScreenContentComponent: CombinedComponent { expanded: Bool, peers: [EnginePeer.Id: EnginePeer], stateUpdated: @escaping (ComponentTransition) -> Void, - buy: @escaping (StarsProduct) -> Void + buy: @escaping (StarsProduct) -> Void, + openAppExamples: @escaping () -> Void ) { self.context = context self.externalState = externalState @@ -115,6 +117,7 @@ private final class StarsPurchaseScreenContentComponent: CombinedComponent { self.peers = peers self.stateUpdated = stateUpdated self.buy = buy + self.openAppExamples = openAppExamples } static func ==(lhs: StarsPurchaseScreenContentComponent, rhs: StarsPurchaseScreenContentComponent) -> Bool { @@ -225,15 +228,16 @@ private final class StarsPurchaseScreenContentComponent: CombinedComponent { state.cachedChevronImage = (generateTintedImage(image: UIImage(bundleImageName: "Settings/TextArrowRight"), color: accentColor)!, theme) } - let titleAttributedString = parseMarkdownIntoAttributedString(textString, attributes: markdownAttributes).mutableCopy() as! NSMutableAttributedString + let textAttributedString = parseMarkdownIntoAttributedString(textString, attributes: markdownAttributes).mutableCopy() as! NSMutableAttributedString - if let range = titleAttributedString.string.range(of: ">"), let chevronImage = state.cachedChevronImage?.0 { - titleAttributedString.addAttribute(.attachment, value: chevronImage, range: NSRange(range, in: titleAttributedString.string)) + if let range = textAttributedString.string.range(of: ">"), let chevronImage = state.cachedChevronImage?.0 { + textAttributedString.addAttribute(.attachment, value: chevronImage, range: NSRange(range, in: textAttributedString.string)) } + let openAppExamples = component.openAppExamples let text = text.update( component: BalancedTextComponent( - text: .plain(titleAttributedString), + text: .plain(textAttributedString), horizontalAlignment: .center, maximumNumberOfLines: 0, lineSpacing: 0.2, @@ -246,6 +250,7 @@ private final class StarsPurchaseScreenContentComponent: CombinedComponent { } }, tapAction: { _, _ in + openAppExamples() } ), environment: {}, @@ -473,6 +478,7 @@ private final class StarsPurchaseScreenComponent: CombinedComponent { let options: [Any] let purpose: StarsPurchasePurpose let forceDark: Bool + let openAppExamples: () -> Void let updateInProgress: (Bool) -> Void let present: (ViewController) -> Void let completion: (Int64) -> Void @@ -483,6 +489,7 @@ private final class StarsPurchaseScreenComponent: CombinedComponent { options: [Any], purpose: StarsPurchasePurpose, forceDark: Bool, + openAppExamples: @escaping () -> Void, updateInProgress: @escaping (Bool) -> Void, present: @escaping (ViewController) -> Void, completion: @escaping (Int64) -> Void @@ -492,6 +499,7 @@ private final class StarsPurchaseScreenComponent: CombinedComponent { self.options = options self.purpose = purpose self.forceDark = forceDark + self.openAppExamples = openAppExamples self.updateInProgress = updateInProgress self.present = present self.completion = completion @@ -872,7 +880,8 @@ private final class StarsPurchaseScreenComponent: CombinedComponent { }, buy: { [weak state] product in state?.buy(product: product) - } + }, + openAppExamples: context.component.openAppExamples )), contentInsets: UIEdgeInsets(top: environment.navigationHeight, left: 0.0, bottom: environment.safeInsets.bottom, right: 0.0), contentOffsetUpdated: { [weak state] topContentOffset, bottomContentOffset in @@ -985,6 +994,7 @@ public final class StarsPurchaseScreen: ViewControllerComponentContainer { self.context = context self.starsContext = starsContext + var openAppExamplesImpl: (() -> Void)? var updateInProgressImpl: ((Bool) -> Void)? var presentImpl: ((ViewController) -> Void)? var completionImpl: ((Int64) -> Void)? @@ -994,6 +1004,9 @@ public final class StarsPurchaseScreen: ViewControllerComponentContainer { options: options, purpose: purpose, forceDark: false, + openAppExamples: { + openAppExamplesImpl?() + }, updateInProgress: { inProgress in updateInProgressImpl?(inProgress) }, @@ -1011,6 +1024,19 @@ public final class StarsPurchaseScreen: ViewControllerComponentContainer { self.navigationItem.setLeftBarButton(cancelItem, animated: false) self.navigationPresentation = .modal + openAppExamplesImpl = { [weak self] in + guard let self else { + return + } + let _ = (context.sharedContext.makeMiniAppListScreenInitialData(context: context) + |> deliverOnMainQueue).startStandalone(next: { [weak self] initialData in + guard let self, let navigationController = self.navigationController as? NavigationController else { + return + } + navigationController.pushViewController(context.sharedContext.makeMiniAppListScreen(context: context, initialData: initialData)) + }) + } + updateInProgressImpl = { [weak self] inProgress in if let strongSelf = self { strongSelf.navigationItem.leftBarButtonItem?.isEnabled = !inProgress diff --git a/submodules/TelegramUI/Components/Stars/StarsTransactionScreen/BUILD b/submodules/TelegramUI/Components/Stars/StarsTransactionScreen/BUILD index 66f7f31423..62a8ef68a8 100644 --- a/submodules/TelegramUI/Components/Stars/StarsTransactionScreen/BUILD +++ b/submodules/TelegramUI/Components/Stars/StarsTransactionScreen/BUILD @@ -34,6 +34,7 @@ swift_library( "//submodules/TelegramUI/Components/Stars/StarsImageComponent", "//submodules/TelegramUI/Components/Stars/StarsAvatarComponent", "//submodules/GalleryUI", + "//submodules/TelegramUI/Components/MiniAppListScreen", ], visibility = [ "//visibility:public", diff --git a/submodules/TelegramUI/Components/Stars/StarsTransactionScreen/Sources/StarsTransactionScreen.swift b/submodules/TelegramUI/Components/Stars/StarsTransactionScreen/Sources/StarsTransactionScreen.swift index 21f05af42e..ee53a897b4 100644 --- a/submodules/TelegramUI/Components/Stars/StarsTransactionScreen/Sources/StarsTransactionScreen.swift +++ b/submodules/TelegramUI/Components/Stars/StarsTransactionScreen/Sources/StarsTransactionScreen.swift @@ -23,6 +23,7 @@ import UndoUI import StarsImageComponent import GalleryUI import StarsAvatarComponent +import MiniAppListScreen private final class StarsTransactionSheetContent: CombinedComponent { typealias EnvironmentType = ViewControllerComponentContainer.Environment @@ -34,6 +35,7 @@ private final class StarsTransactionSheetContent: CombinedComponent { let openPeer: (EnginePeer) -> Void let openMessage: (EngineMessage.Id) -> Void let openMedia: ([Media], @escaping (Media) -> (ASDisplayNode, CGRect, () -> (UIView?, UIView?))?, @escaping (UIView) -> Void) -> Void + let openAppExamples: () -> Void let copyTransactionId: (String) -> Void init( @@ -44,6 +46,7 @@ private final class StarsTransactionSheetContent: CombinedComponent { openPeer: @escaping (EnginePeer) -> Void, openMessage: @escaping (EngineMessage.Id) -> Void, openMedia: @escaping ([Media], @escaping (Media) -> (ASDisplayNode, CGRect, () -> (UIView?, UIView?))?, @escaping (UIView) -> Void) -> Void, + openAppExamples: @escaping () -> Void, copyTransactionId: @escaping (String) -> Void ) { self.context = context @@ -53,6 +56,7 @@ private final class StarsTransactionSheetContent: CombinedComponent { self.openPeer = openPeer self.openMessage = openMessage self.openMedia = openMedia + self.openAppExamples = openAppExamples self.copyTransactionId = copyTransactionId } @@ -345,6 +349,7 @@ private final class StarsTransactionSheetContent: CombinedComponent { photo = nil isRefund = false isGift = true + delayedCloseOnOpenPeer = false } if let spaceRegex { let nsRange = NSRange(descriptionText.startIndex..., in: descriptionText) @@ -647,6 +652,8 @@ private final class StarsTransactionSheetContent: CombinedComponent { var descriptionSize: CGSize = .zero if !descriptionText.isEmpty { + let openAppExamples = component.openAppExamples + if state.cachedChevronImage == nil || state.cachedChevronImage?.1 !== environment.theme { state.cachedChevronImage = (generateTintedImage(image: UIImage(bundleImageName: "Settings/TextArrowRight"), color: linkColor)!, theme) } @@ -665,7 +672,18 @@ private final class StarsTransactionSheetContent: CombinedComponent { text: .plain(attributedString), horizontalAlignment: .center, maximumNumberOfLines: 5, - lineSpacing: 0.2 + lineSpacing: 0.2, + highlightColor: linkColor.withAlphaComponent(0.2), + highlightAction: { attributes in + if let _ = attributes[NSAttributedString.Key(rawValue: TelegramTextAttributes.URL)] { + return NSAttributedString.Key(rawValue: TelegramTextAttributes.URL) + } else { + return nil + } + }, + tapAction: { _, _ in + openAppExamples() + } ), availableSize: CGSize(width: context.availableSize.width - sideInset * 2.0 - 60.0, height: CGFloat.greatestFiniteMagnitude), transition: .immediate @@ -765,6 +783,7 @@ private final class StarsTransactionSheetComponent: CombinedComponent { let openPeer: (EnginePeer) -> Void let openMessage: (EngineMessage.Id) -> Void let openMedia: ([Media], @escaping (Media) -> (ASDisplayNode, CGRect, () -> (UIView?, UIView?))?, @escaping (UIView) -> Void) -> Void + let openAppExamples: () -> Void let copyTransactionId: (String) -> Void init( @@ -774,6 +793,7 @@ private final class StarsTransactionSheetComponent: CombinedComponent { openPeer: @escaping (EnginePeer) -> Void, openMessage: @escaping (EngineMessage.Id) -> Void, openMedia: @escaping ([Media], @escaping (Media) -> (ASDisplayNode, CGRect, () -> (UIView?, UIView?))?, @escaping (UIView) -> Void) -> Void, + openAppExamples: @escaping () -> Void, copyTransactionId: @escaping (String) -> Void ) { self.context = context @@ -782,6 +802,7 @@ private final class StarsTransactionSheetComponent: CombinedComponent { self.openPeer = openPeer self.openMessage = openMessage self.openMedia = openMedia + self.openAppExamples = openAppExamples self.copyTransactionId = copyTransactionId } @@ -826,6 +847,7 @@ private final class StarsTransactionSheetComponent: CombinedComponent { openPeer: context.component.openPeer, openMessage: context.component.openMessage, openMedia: context.component.openMedia, + openAppExamples: context.component.openAppExamples, copyTransactionId: context.component.copyTransactionId )), backgroundColor: .color(environment.theme.actionSheet.opaqueItemBackgroundColor), @@ -915,6 +937,7 @@ public class StarsTransactionScreen: ViewControllerComponentContainer { var openPeerImpl: ((EnginePeer) -> Void)? var openMessageImpl: ((EngineMessage.Id) -> Void)? var openMediaImpl: (([Media], @escaping (Media) -> (ASDisplayNode, CGRect, () -> (UIView?, UIView?))?, @escaping (UIView) -> Void) -> Void)? + var openAppExamplesImpl: (() -> Void)? var copyTransactionIdImpl: ((String) -> Void)? super.init( context: context, @@ -931,6 +954,9 @@ public class StarsTransactionScreen: ViewControllerComponentContainer { openMedia: { media, transitionNode, addToTransitionSurface in openMediaImpl?(media, transitionNode, addToTransitionSurface) }, + openAppExamples: { + openAppExamplesImpl?() + }, copyTransactionId: { transactionId in copyTransactionIdImpl?(transactionId) } @@ -1018,6 +1044,19 @@ public class StarsTransactionScreen: ViewControllerComponentContainer { })) } + openAppExamplesImpl = { [weak self] in + guard let self else { + return + } + let _ = (context.sharedContext.makeMiniAppListScreenInitialData(context: context) + |> deliverOnMainQueue).startStandalone(next: { [weak self] initialData in + guard let self, let navigationController = self.navigationController as? NavigationController else { + return + } + navigationController.pushViewController(context.sharedContext.makeMiniAppListScreen(context: context, initialData: initialData)) + }) + } + copyTransactionIdImpl = { [weak self] transactionId in guard let self else { return