diff --git a/Telegram/Telegram-iOS/en.lproj/Localizable.strings b/Telegram/Telegram-iOS/en.lproj/Localizable.strings index 401c009060..2747135656 100644 --- a/Telegram/Telegram-iOS/en.lproj/Localizable.strings +++ b/Telegram/Telegram-iOS/en.lproj/Localizable.strings @@ -8469,3 +8469,10 @@ Sorry for the inconvenience."; "UserInfo.ResetToOriginalAlertText" = "Are you sure you want to reset to %@ original photo?"; "UserInfo.ResetToOriginalAlertReset" = "Reset"; + +"Conversation.SuggestedPhotoTitle" = "Suggested Photo"; +"Conversation.SuggestedPhotoText" = "%@ suggests you to use this photo for your Telegram account."; +"Conversation.SuggestedPhotoTextYou" = "You suggested %@ to use this photo for their Telegram account."; +"Conversation.SuggestedVideo" = "Suggested Video"; +"Conversation.SuggestedVideoText" = "%@ suggests you to use this video for your Telegram account."; +"Conversation.SuggestedVideoTextYou" = "You suggested %@ to use this video for their Telegram account."; diff --git a/submodules/LegacyComponents/Sources/TGPhotoEditorController.m b/submodules/LegacyComponents/Sources/TGPhotoEditorController.m index fe01115bf3..17554ac1dc 100644 --- a/submodules/LegacyComponents/Sources/TGPhotoEditorController.m +++ b/submodules/LegacyComponents/Sources/TGPhotoEditorController.m @@ -1114,12 +1114,13 @@ image = TGScaleImageToPixelSize(image, CGSizeMake(150.0, 150.0)); } - if (avatar && completion != nil) { - completion(image); + if (!saveOnly && didFinishEditing != nil) { + didFinishEditing(editorValues, image, thumbnailImage, true, ^{ + if (avatar && completion != nil) { + completion(image); + } + }); } - - if (!saveOnly && didFinishEditing != nil) - didFinishEditing(editorValues, image, thumbnailImage, true, ^{}); } error:^(__unused id error) { TGLegacyLog(@"renderedImageSignal error"); @@ -1985,7 +1986,11 @@ if (![_currentTabController isDismissAllowed]) return; - self.view.userInteractionEnabled = false; + bool forAvatar = [self presentedForAvatarCreation]; + + if (!forAvatar) { + self.view.userInteractionEnabled = false; + } [_currentTabController prepareTransitionOutSaving:true]; bool saving = true; @@ -2088,9 +2093,9 @@ TGDispatchOnMainThread(^{ if (self.didFinishEditingVideo != nil) - self.didFinishEditingVideo(asset, [adjustments editAdjustmentsWithPreset:preset videoStartValue:videoStartValue trimStartValue:trimStartValue trimEndValue:trimEndValue], fullImage, nil, true, ^{}); - - [self dismissAnimated:true]; + self.didFinishEditingVideo(asset, [adjustments editAdjustmentsWithPreset:preset videoStartValue:videoStartValue trimStartValue:trimStartValue trimEndValue:trimEndValue], fullImage, nil, true, ^{ + [self dismissAnimated:true]; + }); }); }]; }]; @@ -2098,11 +2103,13 @@ } else if (_intent != TGPhotoEditorControllerVideoIntent) { - TGProgressWindow *progressWindow = [[TGProgressWindow alloc] init]; - progressWindow.windowLevel = self.view.window.windowLevel + 0.001f; - [progressWindow performSelector:@selector(showAnimated) withObject:nil afterDelay:0.5]; + TGProgressWindow *progressWindow; + if (!forAvatar) { + progressWindow = [[TGProgressWindow alloc] init]; + progressWindow.windowLevel = self.view.window.windowLevel + 0.001f; + [progressWindow performSelector:@selector(showAnimated) withObject:nil afterDelay:0.5]; + } - bool forAvatar = [self presentedForAvatarCreation]; [self createEditedImageWithEditorValues:adjustments createThumbnail:!forAvatar saveOnly:false completion:^(__unused UIImage *image) { [NSObject cancelPreviousPerformRequestsWithTarget:progressWindow selector:@selector(showAnimated) object:nil]; diff --git a/submodules/TelegramUI/Components/EntityKeyboard/Sources/EmojiPagerContentComponent.swift b/submodules/TelegramUI/Components/EntityKeyboard/Sources/EmojiPagerContentComponent.swift index ee85986a3a..dde1f64f95 100644 --- a/submodules/TelegramUI/Components/EntityKeyboard/Sources/EmojiPagerContentComponent.swift +++ b/submodules/TelegramUI/Components/EntityKeyboard/Sources/EmojiPagerContentComponent.swift @@ -7514,7 +7514,7 @@ public final class EmojiPagerContentComponent: Component { itemLayoutType: .detailed, itemContentUniqueId: nil, warpContentsOnEdges: false, - displaySearchWithPlaceholder: nil, + displaySearchWithPlaceholder: strings.StickersSearch_SearchStickersPlaceholder, searchInitiallyHidden: false, searchIsPlaceholderOnly: true, emptySearchResults: nil, diff --git a/submodules/TelegramUI/Sources/ChatMessageProfilePhotoSuggestionContentNode.swift b/submodules/TelegramUI/Sources/ChatMessageProfilePhotoSuggestionContentNode.swift new file mode 100644 index 0000000000..faa614c305 --- /dev/null +++ b/submodules/TelegramUI/Sources/ChatMessageProfilePhotoSuggestionContentNode.swift @@ -0,0 +1,189 @@ +import Foundation +import UIKit +import AsyncDisplayKit +import Display +import SwiftSignalKit +import Postbox +import TelegramCore +import AccountContext +import TelegramPresentationData +import TelegramUIPreferences +import TextFormat +import LocalizedPeerData +import TelegramStringFormatting +import WallpaperBackgroundNode +import ReactionSelectionNode + +class ChatMessageProfilePhotoSuggestionContentNode: ChatMessageBubbleContentNode { + private var mediaBackgroundContent: WallpaperBubbleBackgroundNode? + private let mediaBackgroundNode: NavigationBackgroundNode + private let titleNode: TextNode + private let subtitleNode: TextNode + + private let buttonNode: HighlightTrackingButtonNode + private let buttonStarsNode: PremiumStarsNode + private let buttonTitleNode: TextNode + + private var absoluteRect: (CGRect, CGSize)? + + required init() { + self.mediaBackgroundNode = NavigationBackgroundNode(color: .clear) + self.mediaBackgroundNode.clipsToBounds = true + self.mediaBackgroundNode.cornerRadius = 24.0 + + self.titleNode = TextNode() + self.titleNode.isUserInteractionEnabled = false + self.titleNode.displaysAsynchronously = false + + self.subtitleNode = TextNode() + self.subtitleNode.isUserInteractionEnabled = false + self.subtitleNode.displaysAsynchronously = false + + self.buttonNode = HighlightTrackingButtonNode() + self.buttonNode.clipsToBounds = true + self.buttonNode.cornerRadius = 17.0 + + self.buttonStarsNode = PremiumStarsNode() + + self.buttonTitleNode = TextNode() + self.buttonTitleNode.isUserInteractionEnabled = false + self.buttonTitleNode.displaysAsynchronously = false + + super.init() + + self.addSubnode(self.mediaBackgroundNode) + self.addSubnode(self.titleNode) + self.addSubnode(self.subtitleNode) + + self.addSubnode(self.buttonNode) + self.buttonNode.addSubnode(self.buttonStarsNode) + self.addSubnode(self.buttonTitleNode) + + self.buttonNode.highligthedChanged = { [weak self] highlighted in + if let strongSelf = self { + if highlighted { + strongSelf.buttonNode.layer.removeAnimation(forKey: "opacity") + strongSelf.buttonNode.alpha = 0.4 + strongSelf.buttonTitleNode.layer.removeAnimation(forKey: "opacity") + strongSelf.buttonTitleNode.alpha = 0.4 + } else { + strongSelf.buttonNode.alpha = 1.0 + strongSelf.buttonNode.layer.animateAlpha(from: 0.4, to: 1.0, duration: 0.2) + strongSelf.buttonTitleNode.alpha = 1.0 + strongSelf.buttonTitleNode.layer.animateAlpha(from: 0.4, to: 1.0, duration: 0.2) + } + } + } + + self.buttonNode.addTarget(self, action: #selector(self.buttonPressed), forControlEvents: .touchUpInside) + } + + required init?(coder aDecoder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + @objc private func buttonPressed() { + guard let item = self.item else { + return + } + let _ = item.controllerInteraction.openMessage(item.message, .default) + } + + override func asyncLayoutContent() -> (_ item: ChatMessageBubbleContentItem, _ layoutConstants: ChatMessageItemLayoutConstants, _ preparePosition: ChatMessageBubblePreparePosition, _ messageSelection: Bool?, _ constrainedSize: CGSize, _ avatarInset: CGFloat) -> (ChatMessageBubbleContentProperties, unboundSize: CGSize?, maxWidth: CGFloat, layout: (CGSize, ChatMessageBubbleContentPosition) -> (CGFloat, (CGFloat) -> (CGSize, (ListViewItemUpdateAnimation, Bool, ListViewItemApply?) -> Void))) { + let makeTitleLayout = TextNode.asyncLayout(self.titleNode) + let makeSubtitleLayout = TextNode.asyncLayout(self.subtitleNode) + let makeButtonTitleLayout = TextNode.asyncLayout(self.buttonTitleNode) + + return { item, layoutConstants, _, _, _, _ in + let contentProperties = ChatMessageBubbleContentProperties(hidesSimpleAuthorHeader: true, headerSpacing: 0.0, hidesBackground: .always, forceFullCorners: false, forceAlignment: .center) + + return (contentProperties, nil, CGFloat.greatestFiniteMagnitude, { constrainedSize, position in + let giftSize = CGSize(width: 220.0, height: 240.0) + + let primaryTextColor = serviceMessageColorComponents(theme: item.presentationData.theme.theme, wallpaper: item.presentationData.theme.wallpaper).primaryText + + let (titleLayout, titleApply) = makeTitleLayout(TextNodeLayoutArguments(attributedString: NSAttributedString(string: item.presentationData.strings.Notification_PremiumGift_Title, font: Font.semibold(15.0), textColor: primaryTextColor, paragraphAlignment: .center), backgroundColor: nil, maximumNumberOfLines: 0, truncationType: .end, constrainedSize: CGSize(width: giftSize.width - 32.0, height: CGFloat.greatestFiniteMagnitude), alignment: .center, cutout: nil, insets: UIEdgeInsets())) + + let (subtitleLayout, subtitleApply) = makeSubtitleLayout(TextNodeLayoutArguments(attributedString: NSAttributedString(string: "Subtitle", font: Font.regular(13.0), textColor: primaryTextColor, paragraphAlignment: .center), backgroundColor: nil, maximumNumberOfLines: 0, truncationType: .end, constrainedSize: CGSize(width: giftSize.width - 32.0, height: CGFloat.greatestFiniteMagnitude), alignment: .center, cutout: nil, insets: UIEdgeInsets())) + + let (buttonTitleLayout, buttonTitleApply) = makeButtonTitleLayout(TextNodeLayoutArguments(attributedString: NSAttributedString(string: item.presentationData.strings.Notification_PremiumGift_View, font: Font.semibold(15.0), textColor: primaryTextColor, paragraphAlignment: .center), backgroundColor: nil, maximumNumberOfLines: 0, truncationType: .end, constrainedSize: CGSize(width: giftSize.width - 32.0, height: CGFloat.greatestFiniteMagnitude), alignment: .center, cutout: nil, insets: UIEdgeInsets())) + + let backgroundSize = CGSize(width: giftSize.width, height: giftSize.height + 18.0) + + return (backgroundSize.width, { boundingWidth in + return (backgroundSize, { [weak self] animation, synchronousLoads, _ in + if let strongSelf = self { + strongSelf.item = item + + let imageFrame = CGRect(origin: CGPoint(x: floorToScreenPixels((backgroundSize.width - giftSize.width) / 2.0), y: 16.0), size: giftSize) + let mediaBackgroundFrame = imageFrame.insetBy(dx: -2.0, dy: -2.0) + strongSelf.mediaBackgroundNode.frame = mediaBackgroundFrame + + strongSelf.mediaBackgroundNode.updateColor(color: selectDateFillStaticColor(theme: item.presentationData.theme.theme, wallpaper: item.presentationData.theme.wallpaper), enableBlur: dateFillNeedsBlur(theme: item.presentationData.theme.theme, wallpaper: item.presentationData.theme.wallpaper), transition: .immediate) + strongSelf.mediaBackgroundNode.update(size: mediaBackgroundFrame.size, transition: .immediate) + strongSelf.buttonNode.backgroundColor = item.presentationData.theme.theme.overallDarkAppearance ? UIColor(rgb: 0xffffff, alpha: 0.12) : UIColor(rgb: 0x000000, alpha: 0.12) + + let _ = titleApply() + let _ = subtitleApply() + let _ = buttonTitleApply() + + let titleFrame = CGRect(origin: CGPoint(x: mediaBackgroundFrame.minX + floorToScreenPixels((mediaBackgroundFrame.width - titleLayout.size.width) / 2.0) , y: mediaBackgroundFrame.minY + 151.0), size: titleLayout.size) + strongSelf.titleNode.frame = titleFrame + + let subtitleFrame = CGRect(origin: CGPoint(x: mediaBackgroundFrame.minX + floorToScreenPixels((mediaBackgroundFrame.width - subtitleLayout.size.width) / 2.0) , y: titleFrame.maxY - 1.0), size: subtitleLayout.size) + strongSelf.subtitleNode.frame = subtitleFrame + + let buttonTitleFrame = CGRect(origin: CGPoint(x: mediaBackgroundFrame.minX + floorToScreenPixels((mediaBackgroundFrame.width - buttonTitleLayout.size.width) / 2.0), y: subtitleFrame.maxY + 18.0), size: buttonTitleLayout.size) + strongSelf.buttonTitleNode.frame = buttonTitleFrame + + let buttonSize = CGSize(width: buttonTitleLayout.size.width + 38.0, height: 34.0) + strongSelf.buttonNode.frame = CGRect(origin: CGPoint(x: mediaBackgroundFrame.minX + floorToScreenPixels((mediaBackgroundFrame.width - buttonSize.width) / 2.0), y: subtitleFrame.maxY + 10.0), size: buttonSize) + strongSelf.buttonStarsNode.frame = CGRect(origin: .zero, size: buttonSize) + + if item.controllerInteraction.presentationContext.backgroundNode?.hasExtraBubbleBackground() == true { + if strongSelf.mediaBackgroundContent == nil, let backgroundContent = item.controllerInteraction.presentationContext.backgroundNode?.makeBubbleBackground(for: .free) { + strongSelf.mediaBackgroundNode.isHidden = true + backgroundContent.clipsToBounds = true + backgroundContent.allowsGroupOpacity = true + backgroundContent.cornerRadius = 24.0 + + strongSelf.mediaBackgroundContent = backgroundContent + strongSelf.insertSubnode(backgroundContent, at: 0) + } + + strongSelf.mediaBackgroundContent?.frame = mediaBackgroundFrame + } else { + strongSelf.mediaBackgroundNode.isHidden = false + strongSelf.mediaBackgroundContent?.removeFromSupernode() + strongSelf.mediaBackgroundContent = nil + } + + if let (rect, size) = strongSelf.absoluteRect { + strongSelf.updateAbsoluteRect(rect, within: size) + } + } + }) + }) + }) + } + } + + override func updateAbsoluteRect(_ rect: CGRect, within containerSize: CGSize) { + self.absoluteRect = (rect, containerSize) + + if let mediaBackgroundContent = self.mediaBackgroundContent { + var backgroundFrame = mediaBackgroundContent.frame + backgroundFrame.origin.x += rect.minX + backgroundFrame.origin.y += rect.minY + mediaBackgroundContent.update(rect: backgroundFrame, within: containerSize, transition: .immediate) + } + } + + override func tapActionAtPoint(_ point: CGPoint, gesture: TapLongTapOrDoubleTapGesture, isEstimating: Bool) -> ChatMessageBubbleContentTapAction { + if self.mediaBackgroundNode.frame.contains(point) { + return .openMessage + } else { + return .none + } + } +}