diff --git a/Telegram/Telegram-iOS/en.lproj/Localizable.strings b/Telegram/Telegram-iOS/en.lproj/Localizable.strings index 12c803e0ae..fa815b93cc 100644 --- a/Telegram/Telegram-iOS/en.lproj/Localizable.strings +++ b/Telegram/Telegram-iOS/en.lproj/Localizable.strings @@ -10525,6 +10525,7 @@ Sorry for the inconvenience."; "Message.AdSponsoredLabel" = "Sponsored"; "Message.AdRecommendedLabel" = "Recommended"; +"Message.AdWhatIsThis" = "what's this?"; "Stats.StoryTitle" = "Story Statistics"; @@ -11682,7 +11683,7 @@ Sorry for the inconvenience."; "Monetization.AdRevenueTitle" = "AD REVENUE"; "Monetization.OverviewTitle" = "PROCEEDS OVERVIEW"; "Monetization.BalanceTitle" = "AVAILABLE BALANCE"; -"Monetization.BalanceInfo" = "You will be able to collect rewards using Fragment, a third-party platform used by the advertizer to pay for the ad. [Learn More >]()"; +"Monetization.BalanceInfo" = "You will be able to collect rewards using Fragment, a third-party platform used by advertisers to pay for ads. [Learn More >]()"; "Monetization.BalanceInfo_URL" = "https://telegram.org"; "Monetization.BalanceWithdraw" = "Withdraw via Fragment"; "Monetization.TransactionsTitle" = "TRANSACTION HISTORY"; diff --git a/submodules/ItemListUI/Sources/Items/ItemListDisclosureItem.swift b/submodules/ItemListUI/Sources/Items/ItemListDisclosureItem.swift index d19322435d..56bed4446f 100644 --- a/submodules/ItemListUI/Sources/Items/ItemListDisclosureItem.swift +++ b/submodules/ItemListUI/Sources/Items/ItemListDisclosureItem.swift @@ -410,7 +410,7 @@ public class ItemListDisclosureItemNode: ListViewItemNode, ItemListItemNode { if let additionalDetailLabel = item.additionalDetailLabel { var detailRightInset: CGFloat = 20.0 + params.rightInset + additionalTextRightInset if labelLayout.size.width != 0 { - detailRightInset += labelLayout.size.width + 12.0 + detailRightInset += labelLayout.size.width + 7.0 } let additionalDetailColor: UIColor switch item.additionalDetailLabelColor { diff --git a/submodules/TelegramUI/Components/Ads/AdsReportScreen/Sources/AdsReportScreen.swift b/submodules/TelegramUI/Components/Ads/AdsReportScreen/Sources/AdsReportScreen.swift index 4d2a30c1fa..4edd1f6afb 100644 --- a/submodules/TelegramUI/Components/Ads/AdsReportScreen/Sources/AdsReportScreen.swift +++ b/submodules/TelegramUI/Components/Ads/AdsReportScreen/Sources/AdsReportScreen.swift @@ -179,7 +179,7 @@ private final class SheetPageContent: CombinedComponent { maximumNumberOfLines: 1 ))), ], alignment: .left, spacing: 2.0)), - accessory: nil, + accessory: .arrow, action: { _ in component.action(item) } diff --git a/submodules/TelegramUI/Components/Chat/ChatMessageAttachedContentNode/Sources/ChatMessageAttachedContentNode.swift b/submodules/TelegramUI/Components/Chat/ChatMessageAttachedContentNode/Sources/ChatMessageAttachedContentNode.swift index 5ed3934282..7588b9f77d 100644 --- a/submodules/TelegramUI/Components/Chat/ChatMessageAttachedContentNode/Sources/ChatMessageAttachedContentNode.swift +++ b/submodules/TelegramUI/Components/Chat/ChatMessageAttachedContentNode/Sources/ChatMessageAttachedContentNode.swift @@ -90,6 +90,9 @@ public final class ChatMessageAttachedContentNode: ASDisplayNode { private var contentFile: ChatMessageInteractiveFileNode? private var actionButton: ChatMessageAttachedContentButtonNode? private var actionButtonSeparator: SimpleLayer? + + private var titleBadgeLabel: TextNode? + private var titleBadgeButton: HighlightTrackingButtonNode? public var statusNode: ChatMessageDateAndStatusNode? private var closeButton: ComponentView? @@ -104,12 +107,14 @@ public final class ChatMessageAttachedContentNode: ASDisplayNode { private var message: Message? private var media: Media? private var theme: ChatPresentationThemeData? + private var mainColor: UIColor? private var isHighlighted: Bool = false private var highlightTimer: Foundation.Timer? public var openMedia: ((InteractiveMediaNodeActivateContent) -> Void)? public var activateAction: (() -> Void)? + public var activateBadgeAction: (() -> Void)? public var requestUpdateLayout: (() -> Void)? private var currentProgressDisposable: Disposable? @@ -153,6 +158,10 @@ public final class ChatMessageAttachedContentNode: ASDisplayNode { self.activateAction?() } + @objc private func badgePressed() { + self.activateBadgeAction?() + } + public typealias AsyncLayout = (_ presentationData: ChatPresentationData, _ automaticDownloadSettings: MediaAutoDownloadSettings, _ associatedData: ChatMessageItemAssociatedData, _ attributes: ChatMessageEntryAttributes, _ context: AccountContext, _ controllerInteraction: ChatControllerInteraction, _ message: Message, _ messageRead: Bool, _ chatLocation: ChatLocation, _ title: String?, _ titleBadge: String?, _ subtitle: NSAttributedString?, _ text: String?, _ entities: [MessageTextEntity]?, _ media: (Media, ChatMessageAttachedContentNodeMediaFlags)?, _ mediaBadge: String?, _ actionIcon: ChatMessageAttachedContentActionIcon?, _ actionTitle: String?, _ displayLine: Bool, _ layoutConstants: ChatMessageItemLayoutConstants, _ preparePosition: ChatMessageBubblePreparePosition, _ constrainedSize: CGSize, _ animationCache: AnimationCache, _ animationRenderer: MultiAnimationRenderer) -> (CGFloat, (CGSize, ChatMessageBubbleContentPosition) -> (CGFloat, (CGFloat) -> (CGSize, (ListViewItemUpdateAnimation, Bool, ListViewItemApply?) -> Void))) public func makeProgress() -> Promise { @@ -173,6 +182,7 @@ public final class ChatMessageAttachedContentNode: ASDisplayNode { let makeTitleLayout = TextNodeWithEntities.asyncLayout(self.title) let makeSubtitleLayout = TextNodeWithEntities.asyncLayout(self.subtitle) let makeTextLayout = TextNodeWithEntities.asyncLayout(self.text) + let makeTitleBadgeLayout = TextNode.asyncLayout(self.titleBadgeLabel) let makeContentMedia = ChatMessageInteractiveMediaNode.asyncLayout(self.contentMedia) let makeContentFile = ChatMessageInteractiveFileNode.asyncLayout(self.contentFile) let makeActionButtonLayout = ChatMessageAttachedContentButtonNode.asyncLayout(self.actionButton) @@ -194,6 +204,7 @@ public final class ChatMessageAttachedContentNode: ASDisplayNode { let textBoldItalicFont = Font.semiboldItalic(fontSize) let textFixedFont = Font.regular(fontSize) let textBlockQuoteFont = Font.regular(fontSize) + let badgeFont = Font.regular(floor(presentationData.fontSize.baseDisplaySize * 11.0 / 17.0)) var incoming = message.effectivelyIncoming(context.account.peerId) if let subject = associatedData.subject, case let .messageOptions(_, _, info) = subject, case .forward = info { @@ -489,6 +500,7 @@ public final class ChatMessageAttachedContentNode: ASDisplayNode { var titleLayoutAndApply: (TextNodeLayout, (TextNodeWithEntities.Arguments?) -> TextNodeWithEntities)? var subtitleLayoutAndApply: (TextNodeLayout, (TextNodeWithEntities.Arguments?) -> TextNodeWithEntities)? var textLayoutAndApply: (TextNodeLayout, (TextNodeWithEntities.Arguments?) -> TextNodeWithEntities)? + var titleBadgeLayoutAndApply: (TextNodeLayout, () -> TextNode)? var remainingCutoutHeight: CGFloat = 0.0 var cutoutWidth: CGFloat = 0.0 @@ -509,6 +521,11 @@ public final class ChatMessageAttachedContentNode: ASDisplayNode { let titleLayoutAndApplyValue = makeTitleLayout(TextNodeLayoutArguments(attributedString: titleString, backgroundColor: nil, maximumNumberOfLines: 2, truncationType: .end, constrainedSize: CGSize(width: maxContentsWidth, height: 10000.0), alignment: .natural, lineSpacing: textLineSpacing, cutout: cutout, insets: UIEdgeInsets())) titleLayoutAndApply = titleLayoutAndApplyValue + if let titleBadge { + let titleBadgeString = NSAttributedString(string: titleBadge, font: badgeFont, textColor: mainColor) + titleBadgeLayoutAndApply = makeTitleBadgeLayout(TextNodeLayoutArguments(attributedString: titleBadgeString, maximumNumberOfLines: 1, truncationType: .end, constrainedSize: CGSize(width: maxContentsWidth, height: 10000.0))) + } + remainingCutoutHeight -= titleLayoutAndApplyValue.0.size.height } case .subtitle: @@ -548,8 +565,13 @@ public final class ChatMessageAttachedContentNode: ASDisplayNode { } } + let titleBadgePadding: CGFloat = 5.0 + let titleBadgeSpacing: CGFloat = 5.0 if let (titleLayout, _) = titleLayoutAndApply { actualWidth = max(actualWidth, titleLayout.size.width) + if let (titleBadgeLayout, _) = titleBadgeLayoutAndApply { + actualWidth = max(actualWidth, titleLayout.size.width + titleBadgeLayout.size.width + (titleBadgePadding + titleBadgeSpacing) * 2.0) + } } if let (subtitleLayout, _) = subtitleLayoutAndApply { actualWidth = max(actualWidth, subtitleLayout.size.width) @@ -921,10 +943,13 @@ public final class ChatMessageAttachedContentNode: ASDisplayNode { return } + let themeUpdated = self.theme !== presentationData.theme || self.mainColor != mainColor + self.context = context self.message = message self.media = mediaAndFlags?.0 self.theme = presentationData.theme + self.mainColor = mainColor animation.animator.updateFrame(layer: self.transformContainer.layer, frame: CGRect(origin: CGPoint(), size: actualSize), completion: nil) @@ -1061,11 +1086,71 @@ public final class ChatMessageAttachedContentNode: ASDisplayNode { title.textNode.bounds = CGRect(origin: CGPoint(), size: titleFrame.size) animation.animator.updatePosition(layer: title.textNode.layer, position: titleFrame.origin, completion: nil) } + + if let (titleBadgeLayout, titleBadgeApply) = titleBadgeLayoutAndApply { + let titleBadgeLabel = titleBadgeApply() + let titleBadgeFrame = CGRect(origin: CGPoint(x: titleFrame.maxX + titleBadgeSpacing + titleBadgePadding, y: floorToScreenPixels(titleFrame.midY - titleBadgeLayout.size.height / 2.0)), size: titleBadgeLayout.size) + let badgeBackgroundFrame = titleBadgeFrame.insetBy(dx: -titleBadgePadding, dy: -1.0 + UIScreenPixel) + + let button: HighlightTrackingButtonNode + if let current = self.titleBadgeButton { + button = current + button.bounds = CGRect(origin: .zero, size: badgeBackgroundFrame.size) + animation.animator.updatePosition(layer: button.layer, position: badgeBackgroundFrame.center, completion: nil) + } else { + button = HighlightTrackingButtonNode() + button.addTarget(self, action: #selector(self.badgePressed), forControlEvents: .touchUpInside) + button.frame = badgeBackgroundFrame + button.highligthedChanged = { [weak self, weak button] highlighted in + if let self, let button { + if highlighted { + button.layer.removeAnimation(forKey: "opacity") + button.alpha = 0.4 + self.titleBadgeLabel?.layer.removeAnimation(forKey: "opacity") + self.titleBadgeLabel?.alpha = 0.4 + } else { + button.alpha = 1.0 + button.layer.animateAlpha(from: 0.4, to: 1.0, duration: 0.2) + self.titleBadgeLabel?.alpha = 1.0 + self.titleBadgeLabel?.layer.animateAlpha(from: 0.4, to: 1.0, duration: 0.2) + } + } + } + self.titleBadgeButton = button + self.transformContainer.addSubnode(button) + } + + if themeUpdated || button.backgroundImage(for: .normal) == nil { + button.setBackgroundImage(generateFilledCircleImage(diameter: badgeBackgroundFrame.height, color: mainColor.withMultipliedAlpha(0.1))?.stretchableImage(withLeftCapWidth: Int(badgeBackgroundFrame.height / 2), topCapHeight: Int(badgeBackgroundFrame.height / 2)), for: .normal) + } + + if self.titleBadgeLabel !== titleBadgeLabel { + self.titleBadgeLabel?.removeFromSupernode() + self.titleBadgeLabel = titleBadgeLabel + titleBadgeLabel.layer.anchorPoint = CGPoint() + titleBadgeLabel.isUserInteractionEnabled = false + self.transformContainer.addSubnode(titleBadgeLabel) + + titleBadgeLabel.frame = titleBadgeFrame + titleBadgeLabel.displaysAsynchronously = !presentationData.isPreview + } else { + titleBadgeLabel.bounds = CGRect(origin: CGPoint(), size: titleBadgeFrame.size) + animation.animator.updatePosition(layer: titleBadgeLabel.layer, position: titleBadgeFrame.origin, completion: nil) + } + } } else { if let title = self.title { self.title = nil title.textNode.removeFromSupernode() } + if let titleBadgeLabel = self.titleBadgeLabel { + self.titleBadgeLabel = nil + titleBadgeLabel.removeFromSupernode() + } + if let titleBadgeButton = self.titleBadgeButton { + self.titleBadgeButton = nil + titleBadgeButton.removeFromSupernode() + } if let closeButton = self.closeButton { self.closeButton = nil closeButton.view?.removeFromSuperview() @@ -1449,6 +1534,10 @@ public final class ChatMessageAttachedContentNode: ASDisplayNode { return ChatMessageBubbleContentTapAction(content: .ignore) } + if let titleBadgeButton = self.titleBadgeButton, titleBadgeButton.frame.contains(point) { + return ChatMessageBubbleContentTapAction(content: .ignore) + } + if let backgroundView = self.backgroundView, backgroundView.frame.contains(point) { if let message = self.message, message.adAttribute != nil { return ChatMessageBubbleContentTapAction(content: .none) diff --git a/submodules/TelegramUI/Components/Chat/ChatMessageShareButton/Sources/ChatMessageShareButton.swift b/submodules/TelegramUI/Components/Chat/ChatMessageShareButton/Sources/ChatMessageShareButton.swift index 627476f7bc..c0b6f916e1 100644 --- a/submodules/TelegramUI/Components/Chat/ChatMessageShareButton/Sources/ChatMessageShareButton.swift +++ b/submodules/TelegramUI/Components/Chat/ChatMessageShareButton/Sources/ChatMessageShareButton.swift @@ -25,6 +25,7 @@ public class ChatMessageShareButton: ASDisplayNode { private var theme: PresentationTheme? private var isReplies: Bool = false + private var hasMore: Bool = false private var textNode: ImmediateTextNode? @@ -97,18 +98,26 @@ public class ChatMessageShareButton: ASDisplayNode { isReplies = false } - if self.theme !== presentationData.theme.theme || self.isReplies != isReplies { + var hasMore = false + if let adAttribute = message.adAttribute, adAttribute.canReport { + hasMore = true + } + + if self.theme !== presentationData.theme.theme || self.isReplies != isReplies || self.hasMore != hasMore { self.theme = presentationData.theme.theme self.isReplies = isReplies + self.hasMore = hasMore var updatedIconImage: UIImage? var updatedBottomIconImage: UIImage? var updatedIconOffset = CGPoint() - if message.adAttribute != nil { + if let _ = message.adAttribute { updatedIconImage = PresentationResourcesChat.chatFreeCloseButtonIcon(presentationData.theme.theme, wallpaper: presentationData.theme.wallpaper) updatedIconOffset = CGPoint(x: UIScreenPixel, y: UIScreenPixel) - updatedBottomIconImage = PresentationResourcesChat.chatFreeMoreButtonIcon(presentationData.theme.theme, wallpaper: presentationData.theme.wallpaper) + if hasMore { + updatedBottomIconImage = PresentationResourcesChat.chatFreeMoreButtonIcon(presentationData.theme.theme, wallpaper: presentationData.theme.wallpaper) + } } else if case .pinnedMessages = subject { updatedIconImage = PresentationResourcesChat.chatFreeNavigateButtonIcon(presentationData.theme.theme, wallpaper: presentationData.theme.wallpaper) updatedIconOffset = CGPoint(x: UIScreenPixel, y: 1.0) @@ -173,7 +182,7 @@ public class ChatMessageShareButton: ASDisplayNode { } } var size = CGSize(width: 30.0, height: 30.0) - if message.adAttribute != nil { + if hasMore { size.height += 30.0 } var offsetIcon = false diff --git a/submodules/TelegramUI/Components/Chat/ChatMessageWebpageBubbleContentNode/Sources/ChatMessageWebpageBubbleContentNode.swift b/submodules/TelegramUI/Components/Chat/ChatMessageWebpageBubbleContentNode/Sources/ChatMessageWebpageBubbleContentNode.swift index 3ad5078c2d..4315bccdf9 100644 --- a/submodules/TelegramUI/Components/Chat/ChatMessageWebpageBubbleContentNode/Sources/ChatMessageWebpageBubbleContentNode.swift +++ b/submodules/TelegramUI/Components/Chat/ChatMessageWebpageBubbleContentNode/Sources/ChatMessageWebpageBubbleContentNode.swift @@ -132,6 +132,11 @@ public final class ChatMessageWebpageBubbleContentNode: ChatMessageBubbleContent } } } + self.contentNode.activateBadgeAction = { [weak self] in + if let strongSelf = self, let item = strongSelf.item { + item.controllerInteraction.openAdsInfo() + } + } self.contentNode.activateAction = { [weak self] in if let strongSelf = self, let item = strongSelf.item { if let _ = item.message.adAttribute { @@ -506,7 +511,9 @@ public final class ChatMessageWebpageBubbleContentNode: ChatMessageBubbleContent } } - titleBadge = "what's this?" + if adAttribute.canReport { + titleBadge = item.presentationData.strings.Message_AdWhatIsThis + } if let buttonText = adAttribute.buttonText { actionTitle = buttonText.uppercased() diff --git a/submodules/TelegramUI/Components/Chat/ChatRecentActionsController/Sources/ChatRecentActionsControllerNode.swift b/submodules/TelegramUI/Components/Chat/ChatRecentActionsController/Sources/ChatRecentActionsControllerNode.swift index 15118ffa9a..25f00a7482 100644 --- a/submodules/TelegramUI/Components/Chat/ChatRecentActionsController/Sources/ChatRecentActionsControllerNode.swift +++ b/submodules/TelegramUI/Components/Chat/ChatRecentActionsController/Sources/ChatRecentActionsControllerNode.swift @@ -568,6 +568,7 @@ final class ChatRecentActionsControllerNode: ViewControllerTracingNode { }, openRequestedPeerSelection: { _, _, _, _ in }, saveMediaToFiles: { _ in }, openNoAdsDemo: { + }, openAdsInfo: { }, displayGiveawayParticipationStatus: { _ in }, openPremiumStatusInfo: { _, _, _, _ in }, openRecommendedChannelContextMenu: { _, _, _ in diff --git a/submodules/TelegramUI/Components/ChatControllerInteraction/Sources/ChatControllerInteraction.swift b/submodules/TelegramUI/Components/ChatControllerInteraction/Sources/ChatControllerInteraction.swift index f9d764597d..8d2452d1dc 100644 --- a/submodules/TelegramUI/Components/ChatControllerInteraction/Sources/ChatControllerInteraction.swift +++ b/submodules/TelegramUI/Components/ChatControllerInteraction/Sources/ChatControllerInteraction.swift @@ -228,6 +228,7 @@ public final class ChatControllerInteraction: ChatControllerInteractionProtocol public let openRequestedPeerSelection: (EngineMessage.Id, ReplyMarkupButtonRequestPeerType, Int32, Int32) -> Void public let saveMediaToFiles: (EngineMessage.Id) -> Void public let openNoAdsDemo: () -> Void + public let openAdsInfo: () -> Void public let displayGiveawayParticipationStatus: (EngineMessage.Id) -> Void public let openPremiumStatusInfo: (EnginePeer.Id, UIView, Int64?, PeerNameColor) -> Void public let openRecommendedChannelContextMenu: (EnginePeer, UIView, ContextGesture?) -> Void @@ -352,6 +353,7 @@ public final class ChatControllerInteraction: ChatControllerInteractionProtocol openRequestedPeerSelection: @escaping (EngineMessage.Id, ReplyMarkupButtonRequestPeerType, Int32, Int32) -> Void, saveMediaToFiles: @escaping (EngineMessage.Id) -> Void, openNoAdsDemo: @escaping () -> Void, + openAdsInfo: @escaping () -> Void, displayGiveawayParticipationStatus: @escaping (EngineMessage.Id) -> Void, openPremiumStatusInfo: @escaping (EnginePeer.Id, UIView, Int64?, PeerNameColor) -> Void, openRecommendedChannelContextMenu: @escaping (EnginePeer, UIView, ContextGesture?) -> Void, @@ -456,6 +458,7 @@ public final class ChatControllerInteraction: ChatControllerInteractionProtocol self.openRequestedPeerSelection = openRequestedPeerSelection self.saveMediaToFiles = saveMediaToFiles self.openNoAdsDemo = openNoAdsDemo + self.openAdsInfo = openAdsInfo self.displayGiveawayParticipationStatus = displayGiveawayParticipationStatus self.openPremiumStatusInfo = openPremiumStatusInfo self.openRecommendedChannelContextMenu = openRecommendedChannelContextMenu diff --git a/submodules/TelegramUI/Components/MediaEditorScreen/Sources/MediaEditorScreen.swift b/submodules/TelegramUI/Components/MediaEditorScreen/Sources/MediaEditorScreen.swift index 88dbe55ed6..e150cfb2cb 100644 --- a/submodules/TelegramUI/Components/MediaEditorScreen/Sources/MediaEditorScreen.swift +++ b/submodules/TelegramUI/Components/MediaEditorScreen/Sources/MediaEditorScreen.swift @@ -3232,6 +3232,8 @@ public final class MediaEditorScreen: ViewController, UIDropInteractionDelegate controller.statusBar.statusBarStyle = .Ignore self.isUserInteractionEnabled = false + self.saveTooltip?.dismiss() + if self.entitiesView.hasSelection { self.entitiesView.selectEntity(nil) } @@ -3472,7 +3474,7 @@ public final class MediaEditorScreen: ViewController, UIDropInteractionDelegate self.controller?.present(tooltipController, in: .current) } - private weak var saveTooltip: SaveProgressScreen? + fileprivate weak var saveTooltip: SaveProgressScreen? func presentSaveTooltip() { guard let controller = self.controller else { return @@ -3525,7 +3527,7 @@ public final class MediaEditorScreen: ViewController, UIDropInteractionDelegate controller.cancelVideoExport() } } - controller.present(tooltipController, in: .current) + controller.present(tooltipController, in: .window(.root)) self.saveTooltip = tooltipController } } @@ -3554,7 +3556,7 @@ public final class MediaEditorScreen: ViewController, UIDropInteractionDelegate controller.requestLayout(transition: .animated(duration: 0.25, curve: .easeInOut)) } } - controller.present(tooltipController, in: .current) + controller.present(tooltipController, in: .window(.root)) self.saveTooltip = tooltipController } } @@ -5768,10 +5770,17 @@ public final class MediaEditorScreen: ViewController, UIDropInteractionDelegate } let resource = LocalFileMediaResource(fileId: Int64.random(in: Int64.min ... Int64.max)) + let thumbnailResource = LocalFileMediaResource(fileId: Int64.random(in: Int64.min ... Int64.max)) var isVideo = false if mediaEditor.resultIsVideo { isVideo = true + + Queue.concurrentDefaultQueue().async { + if let data = try? WebP.convert(toWebP: image, quality: 97.0) { + self.context.account.postbox.mediaBox.storeResourceData(thumbnailResource.id, data: data) + } + } } else { Queue.concurrentDefaultQueue().async { if let data = try? WebP.convert(toWebP: image, quality: 97.0) { @@ -5782,7 +5791,7 @@ public final class MediaEditorScreen: ViewController, UIDropInteractionDelegate let presentationData = self.context.sharedContext.currentPresentationData.with { $0 }.withUpdated(theme: defaultDarkColorPresentationTheme) - let file = stickerFile(resource: resource, size: Int64(0), dimensions: PixelDimensions(image.size), isVideo: isVideo) + let file = stickerFile(resource: resource, thumbnailResource: thumbnailResource, size: Int64(0), dimensions: PixelDimensions(image.size), isVideo: isVideo) var menuItems: [ContextMenuItem] = [] if case let .stickerEditor(mode) = self.mode { @@ -6073,7 +6082,7 @@ public final class MediaEditorScreen: ViewController, UIDropInteractionDelegate case let .progress(progress): return .single(.progress(isVideo ? 0.5 + progress * 0.5 : progress)) case let .complete(resource, _): - let file = stickerFile(resource: resource, size: file.size ?? 0, dimensions: dimensions, isVideo: isVideo) + let file = stickerFile(resource: resource, thumbnailResource: file.previewRepresentations.first?.resource, size: file.size ?? 0, dimensions: dimensions, isVideo: isVideo) switch action { case .send: return .single(status) @@ -6147,7 +6156,7 @@ public final class MediaEditorScreen: ViewController, UIDropInteractionDelegate let result: MediaEditorScreen.Result switch action { case .upload, .send: - let file = stickerFile(resource: resource, size: resource.size ?? 0, dimensions: dimensions, isVideo: isVideo) + let file = stickerFile(resource: resource, thumbnailResource: file.previewRepresentations.first?.resource, size: resource.size ?? 0, dimensions: dimensions, isVideo: isVideo) result = MediaEditorScreen.Result(media: .sticker(file: file)) default: result = MediaEditorScreen.Result() @@ -7045,11 +7054,16 @@ extension MediaScrubberComponent.Track { } } -private func stickerFile(resource: TelegramMediaResource, size: Int64, dimensions: PixelDimensions, isVideo: Bool) -> TelegramMediaFile { +private func stickerFile(resource: TelegramMediaResource, thumbnailResource: TelegramMediaResource?, size: Int64, dimensions: PixelDimensions, isVideo: Bool) -> TelegramMediaFile { var fileAttributes: [TelegramMediaFileAttribute] = [] fileAttributes.append(.FileName(fileName: isVideo ? "sticker.webm" : "sticker.webp")) fileAttributes.append(.Sticker(displayText: "", packReference: nil, maskData: nil)) fileAttributes.append(.ImageSize(size: dimensions)) - return TelegramMediaFile(fileId: MediaId(namespace: Namespaces.Media.LocalFile, id: Int64.random(in: Int64.min ... Int64.max)), partialReference: nil, resource: resource, previewRepresentations: [], videoThumbnails: [], immediateThumbnailData: nil, mimeType: isVideo ? "video/webm" : "image/webp", size: size, attributes: fileAttributes) + var previewRepresentations: [TelegramMediaImageRepresentation] = [] + if let thumbnailResource { + previewRepresentations.append(TelegramMediaImageRepresentation(dimensions: dimensions, resource: thumbnailResource, progressiveSizes: [], immediateThumbnailData: nil)) + } + + return TelegramMediaFile(fileId: MediaId(namespace: Namespaces.Media.LocalFile, id: Int64.random(in: Int64.min ... Int64.max)), partialReference: nil, resource: resource, previewRepresentations: previewRepresentations, videoThumbnails: [], immediateThumbnailData: nil, mimeType: isVideo ? "video/webm" : "image/webp", size: size, attributes: fileAttributes) } diff --git a/submodules/TelegramUI/Components/MediaEditorScreen/Sources/SaveProgressScreen.swift b/submodules/TelegramUI/Components/MediaEditorScreen/Sources/SaveProgressScreen.swift index 2aeb3f1dfa..d16c858c64 100644 --- a/submodules/TelegramUI/Components/MediaEditorScreen/Sources/SaveProgressScreen.swift +++ b/submodules/TelegramUI/Components/MediaEditorScreen/Sources/SaveProgressScreen.swift @@ -486,7 +486,8 @@ public final class SaveProgressScreen: ViewController { self.view.addSubview(componentView) } let componentFrame = CGRect(origin: .zero, size: componentSize) - transition.setFrame(view: componentView, frame: CGRect(origin: componentFrame.origin, size: CGSize(width: componentFrame.width, height: componentFrame.height))) + componentView.center = componentFrame.center + componentView.bounds = CGRect(origin: .zero, size: componentFrame.size) } if isFirstTime { diff --git a/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/PeerInfoBirthdayOverlay.swift b/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/PeerInfoBirthdayOverlay.swift index 40f7d38aab..103d3d82a4 100644 --- a/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/PeerInfoBirthdayOverlay.swift +++ b/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/PeerInfoBirthdayOverlay.swift @@ -32,7 +32,6 @@ final class PeerInfoBirthdayOverlay: ASDisplayNode { self.setupAnimations(size: size, birthday: birthday, sourceRect: sourceRect) Queue.mainQueue().after(0.1) { - HapticFeedback().success() self.view.addSubview(ConfettiView(frame: CGRect(origin: .zero, size: size))) } } diff --git a/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/PeerInfoScreen.swift b/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/PeerInfoScreen.swift index eb331c6045..f19d68bb18 100644 --- a/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/PeerInfoScreen.swift +++ b/submodules/TelegramUI/Components/PeerInfo/PeerInfoScreen/Sources/PeerInfoScreen.swift @@ -2696,7 +2696,9 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, PeerInfoScreenNodePro if let self { if value { if let data = self.data?.cachedData as? CachedUserData { - if data.birthday == nil && self.state.updatingBirthDate == nil { + if data.birthday == nil && (self.state.updatingBirthDate == nil || self.state.updatingBirthDate == .some(nil)) { + self.state = self.state.withUpdatingBirthDate(TelegramBirthday(day: 1, month: 1, year: nil)) + } else if self.state.updatingBirthDate == .some(nil) { self.state = self.state.withUpdatingBirthDate(TelegramBirthday(day: 1, month: 1, year: nil)) } } @@ -3249,6 +3251,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, PeerInfoScreenNodePro }, openRequestedPeerSelection: { _, _, _, _ in }, saveMediaToFiles: { _ in }, openNoAdsDemo: { + }, openAdsInfo: { }, displayGiveawayParticipationStatus: { _ in }, openPremiumStatusInfo: { _, _, _, _ in }, openRecommendedChannelContextMenu: { _, _, _ in diff --git a/submodules/TelegramUI/Sources/ChatController.swift b/submodules/TelegramUI/Sources/ChatController.swift index 9a6770893c..587e39857d 100644 --- a/submodules/TelegramUI/Sources/ChatController.swift +++ b/submodules/TelegramUI/Sources/ChatController.swift @@ -122,6 +122,7 @@ import AudioWaveform import PeerNameColorScreen import ChatEmptyNode import ChatMediaInputStickerGridItem +import AdsInfoScreen public enum ChatControllerPeekActions { case standard @@ -4438,6 +4439,11 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G controller?.replace(with: c) } self.push(controller) + }, openAdsInfo: { [weak self] in + guard let self else { + return + } + self.push(AdsInfoScreen(context: self.context)) }, displayGiveawayParticipationStatus: { [weak self] messageId in guard let self else { return diff --git a/submodules/TelegramUI/Sources/OverlayAudioPlayerControllerNode.swift b/submodules/TelegramUI/Sources/OverlayAudioPlayerControllerNode.swift index e7be8e9ccd..4335325b8a 100644 --- a/submodules/TelegramUI/Sources/OverlayAudioPlayerControllerNode.swift +++ b/submodules/TelegramUI/Sources/OverlayAudioPlayerControllerNode.swift @@ -169,6 +169,7 @@ final class OverlayAudioPlayerControllerNode: ViewControllerTracingNode, UIGestu }, openRequestedPeerSelection: { _, _, _, _ in }, saveMediaToFiles: { _ in }, openNoAdsDemo: { + }, openAdsInfo: { }, displayGiveawayParticipationStatus: { _ in }, openPremiumStatusInfo: { _, _, _, _ in }, openRecommendedChannelContextMenu: { _, _, _ in diff --git a/submodules/TelegramUI/Sources/SharedAccountContext.swift b/submodules/TelegramUI/Sources/SharedAccountContext.swift index 1604a7bb3d..abfa71b331 100644 --- a/submodules/TelegramUI/Sources/SharedAccountContext.swift +++ b/submodules/TelegramUI/Sources/SharedAccountContext.swift @@ -1756,6 +1756,7 @@ public final class SharedAccountContextImpl: SharedAccountContext { }, openRequestedPeerSelection: { _, _, _, _ in }, saveMediaToFiles: { _ in }, openNoAdsDemo: { + }, openAdsInfo: { }, displayGiveawayParticipationStatus: { _ in }, openPremiumStatusInfo: { _, _, _, _ in }, openRecommendedChannelContextMenu: { _, _, _ in