Various fixes

This commit is contained in:
Ilya Laktyushin 2024-03-26 17:22:00 +04:00
parent e050bb2119
commit 9bb28dcc26
15 changed files with 154 additions and 19 deletions

View File

@ -10525,6 +10525,7 @@ Sorry for the inconvenience.";
"Message.AdSponsoredLabel" = "Sponsored"; "Message.AdSponsoredLabel" = "Sponsored";
"Message.AdRecommendedLabel" = "Recommended"; "Message.AdRecommendedLabel" = "Recommended";
"Message.AdWhatIsThis" = "what's this?";
"Stats.StoryTitle" = "Story Statistics"; "Stats.StoryTitle" = "Story Statistics";
@ -11682,7 +11683,7 @@ Sorry for the inconvenience.";
"Monetization.AdRevenueTitle" = "AD REVENUE"; "Monetization.AdRevenueTitle" = "AD REVENUE";
"Monetization.OverviewTitle" = "PROCEEDS OVERVIEW"; "Monetization.OverviewTitle" = "PROCEEDS OVERVIEW";
"Monetization.BalanceTitle" = "AVAILABLE BALANCE"; "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.BalanceInfo_URL" = "https://telegram.org";
"Monetization.BalanceWithdraw" = "Withdraw via Fragment"; "Monetization.BalanceWithdraw" = "Withdraw via Fragment";
"Monetization.TransactionsTitle" = "TRANSACTION HISTORY"; "Monetization.TransactionsTitle" = "TRANSACTION HISTORY";

View File

@ -410,7 +410,7 @@ public class ItemListDisclosureItemNode: ListViewItemNode, ItemListItemNode {
if let additionalDetailLabel = item.additionalDetailLabel { if let additionalDetailLabel = item.additionalDetailLabel {
var detailRightInset: CGFloat = 20.0 + params.rightInset + additionalTextRightInset var detailRightInset: CGFloat = 20.0 + params.rightInset + additionalTextRightInset
if labelLayout.size.width != 0 { if labelLayout.size.width != 0 {
detailRightInset += labelLayout.size.width + 12.0 detailRightInset += labelLayout.size.width + 7.0
} }
let additionalDetailColor: UIColor let additionalDetailColor: UIColor
switch item.additionalDetailLabelColor { switch item.additionalDetailLabelColor {

View File

@ -179,7 +179,7 @@ private final class SheetPageContent: CombinedComponent {
maximumNumberOfLines: 1 maximumNumberOfLines: 1
))), ))),
], alignment: .left, spacing: 2.0)), ], alignment: .left, spacing: 2.0)),
accessory: nil, accessory: .arrow,
action: { _ in action: { _ in
component.action(item) component.action(item)
} }

View File

@ -90,6 +90,9 @@ public final class ChatMessageAttachedContentNode: ASDisplayNode {
private var contentFile: ChatMessageInteractiveFileNode? private var contentFile: ChatMessageInteractiveFileNode?
private var actionButton: ChatMessageAttachedContentButtonNode? private var actionButton: ChatMessageAttachedContentButtonNode?
private var actionButtonSeparator: SimpleLayer? private var actionButtonSeparator: SimpleLayer?
private var titleBadgeLabel: TextNode?
private var titleBadgeButton: HighlightTrackingButtonNode?
public var statusNode: ChatMessageDateAndStatusNode? public var statusNode: ChatMessageDateAndStatusNode?
private var closeButton: ComponentView<Empty>? private var closeButton: ComponentView<Empty>?
@ -104,12 +107,14 @@ public final class ChatMessageAttachedContentNode: ASDisplayNode {
private var message: Message? private var message: Message?
private var media: Media? private var media: Media?
private var theme: ChatPresentationThemeData? private var theme: ChatPresentationThemeData?
private var mainColor: UIColor?
private var isHighlighted: Bool = false private var isHighlighted: Bool = false
private var highlightTimer: Foundation.Timer? private var highlightTimer: Foundation.Timer?
public var openMedia: ((InteractiveMediaNodeActivateContent) -> Void)? public var openMedia: ((InteractiveMediaNodeActivateContent) -> Void)?
public var activateAction: (() -> Void)? public var activateAction: (() -> Void)?
public var activateBadgeAction: (() -> Void)?
public var requestUpdateLayout: (() -> Void)? public var requestUpdateLayout: (() -> Void)?
private var currentProgressDisposable: Disposable? private var currentProgressDisposable: Disposable?
@ -153,6 +158,10 @@ public final class ChatMessageAttachedContentNode: ASDisplayNode {
self.activateAction?() 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 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<Bool> { public func makeProgress() -> Promise<Bool> {
@ -173,6 +182,7 @@ public final class ChatMessageAttachedContentNode: ASDisplayNode {
let makeTitleLayout = TextNodeWithEntities.asyncLayout(self.title) let makeTitleLayout = TextNodeWithEntities.asyncLayout(self.title)
let makeSubtitleLayout = TextNodeWithEntities.asyncLayout(self.subtitle) let makeSubtitleLayout = TextNodeWithEntities.asyncLayout(self.subtitle)
let makeTextLayout = TextNodeWithEntities.asyncLayout(self.text) let makeTextLayout = TextNodeWithEntities.asyncLayout(self.text)
let makeTitleBadgeLayout = TextNode.asyncLayout(self.titleBadgeLabel)
let makeContentMedia = ChatMessageInteractiveMediaNode.asyncLayout(self.contentMedia) let makeContentMedia = ChatMessageInteractiveMediaNode.asyncLayout(self.contentMedia)
let makeContentFile = ChatMessageInteractiveFileNode.asyncLayout(self.contentFile) let makeContentFile = ChatMessageInteractiveFileNode.asyncLayout(self.contentFile)
let makeActionButtonLayout = ChatMessageAttachedContentButtonNode.asyncLayout(self.actionButton) let makeActionButtonLayout = ChatMessageAttachedContentButtonNode.asyncLayout(self.actionButton)
@ -194,6 +204,7 @@ public final class ChatMessageAttachedContentNode: ASDisplayNode {
let textBoldItalicFont = Font.semiboldItalic(fontSize) let textBoldItalicFont = Font.semiboldItalic(fontSize)
let textFixedFont = Font.regular(fontSize) let textFixedFont = Font.regular(fontSize)
let textBlockQuoteFont = 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) var incoming = message.effectivelyIncoming(context.account.peerId)
if let subject = associatedData.subject, case let .messageOptions(_, _, info) = subject, case .forward = info { 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 titleLayoutAndApply: (TextNodeLayout, (TextNodeWithEntities.Arguments?) -> TextNodeWithEntities)?
var subtitleLayoutAndApply: (TextNodeLayout, (TextNodeWithEntities.Arguments?) -> TextNodeWithEntities)? var subtitleLayoutAndApply: (TextNodeLayout, (TextNodeWithEntities.Arguments?) -> TextNodeWithEntities)?
var textLayoutAndApply: (TextNodeLayout, (TextNodeWithEntities.Arguments?) -> TextNodeWithEntities)? var textLayoutAndApply: (TextNodeLayout, (TextNodeWithEntities.Arguments?) -> TextNodeWithEntities)?
var titleBadgeLayoutAndApply: (TextNodeLayout, () -> TextNode)?
var remainingCutoutHeight: CGFloat = 0.0 var remainingCutoutHeight: CGFloat = 0.0
var cutoutWidth: 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())) 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 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 remainingCutoutHeight -= titleLayoutAndApplyValue.0.size.height
} }
case .subtitle: 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 { if let (titleLayout, _) = titleLayoutAndApply {
actualWidth = max(actualWidth, titleLayout.size.width) 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 { if let (subtitleLayout, _) = subtitleLayoutAndApply {
actualWidth = max(actualWidth, subtitleLayout.size.width) actualWidth = max(actualWidth, subtitleLayout.size.width)
@ -921,10 +943,13 @@ public final class ChatMessageAttachedContentNode: ASDisplayNode {
return return
} }
let themeUpdated = self.theme !== presentationData.theme || self.mainColor != mainColor
self.context = context self.context = context
self.message = message self.message = message
self.media = mediaAndFlags?.0 self.media = mediaAndFlags?.0
self.theme = presentationData.theme self.theme = presentationData.theme
self.mainColor = mainColor
animation.animator.updateFrame(layer: self.transformContainer.layer, frame: CGRect(origin: CGPoint(), size: actualSize), completion: nil) 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) title.textNode.bounds = CGRect(origin: CGPoint(), size: titleFrame.size)
animation.animator.updatePosition(layer: title.textNode.layer, position: titleFrame.origin, completion: nil) 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 { } else {
if let title = self.title { if let title = self.title {
self.title = nil self.title = nil
title.textNode.removeFromSupernode() 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 { if let closeButton = self.closeButton {
self.closeButton = nil self.closeButton = nil
closeButton.view?.removeFromSuperview() closeButton.view?.removeFromSuperview()
@ -1449,6 +1534,10 @@ public final class ChatMessageAttachedContentNode: ASDisplayNode {
return ChatMessageBubbleContentTapAction(content: .ignore) 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 backgroundView = self.backgroundView, backgroundView.frame.contains(point) {
if let message = self.message, message.adAttribute != nil { if let message = self.message, message.adAttribute != nil {
return ChatMessageBubbleContentTapAction(content: .none) return ChatMessageBubbleContentTapAction(content: .none)

View File

@ -25,6 +25,7 @@ public class ChatMessageShareButton: ASDisplayNode {
private var theme: PresentationTheme? private var theme: PresentationTheme?
private var isReplies: Bool = false private var isReplies: Bool = false
private var hasMore: Bool = false
private var textNode: ImmediateTextNode? private var textNode: ImmediateTextNode?
@ -97,18 +98,26 @@ public class ChatMessageShareButton: ASDisplayNode {
isReplies = false 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.theme = presentationData.theme.theme
self.isReplies = isReplies self.isReplies = isReplies
self.hasMore = hasMore
var updatedIconImage: UIImage? var updatedIconImage: UIImage?
var updatedBottomIconImage: UIImage? var updatedBottomIconImage: UIImage?
var updatedIconOffset = CGPoint() var updatedIconOffset = CGPoint()
if message.adAttribute != nil { if let _ = message.adAttribute {
updatedIconImage = PresentationResourcesChat.chatFreeCloseButtonIcon(presentationData.theme.theme, wallpaper: presentationData.theme.wallpaper) updatedIconImage = PresentationResourcesChat.chatFreeCloseButtonIcon(presentationData.theme.theme, wallpaper: presentationData.theme.wallpaper)
updatedIconOffset = CGPoint(x: UIScreenPixel, y: UIScreenPixel) 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 { } else if case .pinnedMessages = subject {
updatedIconImage = PresentationResourcesChat.chatFreeNavigateButtonIcon(presentationData.theme.theme, wallpaper: presentationData.theme.wallpaper) updatedIconImage = PresentationResourcesChat.chatFreeNavigateButtonIcon(presentationData.theme.theme, wallpaper: presentationData.theme.wallpaper)
updatedIconOffset = CGPoint(x: UIScreenPixel, y: 1.0) updatedIconOffset = CGPoint(x: UIScreenPixel, y: 1.0)
@ -173,7 +182,7 @@ public class ChatMessageShareButton: ASDisplayNode {
} }
} }
var size = CGSize(width: 30.0, height: 30.0) var size = CGSize(width: 30.0, height: 30.0)
if message.adAttribute != nil { if hasMore {
size.height += 30.0 size.height += 30.0
} }
var offsetIcon = false var offsetIcon = false

View File

@ -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 self.contentNode.activateAction = { [weak self] in
if let strongSelf = self, let item = strongSelf.item { if let strongSelf = self, let item = strongSelf.item {
if let _ = item.message.adAttribute { 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 { if let buttonText = adAttribute.buttonText {
actionTitle = buttonText.uppercased() actionTitle = buttonText.uppercased()

View File

@ -568,6 +568,7 @@ final class ChatRecentActionsControllerNode: ViewControllerTracingNode {
}, openRequestedPeerSelection: { _, _, _, _ in }, openRequestedPeerSelection: { _, _, _, _ in
}, saveMediaToFiles: { _ in }, saveMediaToFiles: { _ in
}, openNoAdsDemo: { }, openNoAdsDemo: {
}, openAdsInfo: {
}, displayGiveawayParticipationStatus: { _ in }, displayGiveawayParticipationStatus: { _ in
}, openPremiumStatusInfo: { _, _, _, _ in }, openPremiumStatusInfo: { _, _, _, _ in
}, openRecommendedChannelContextMenu: { _, _, _ in }, openRecommendedChannelContextMenu: { _, _, _ in

View File

@ -228,6 +228,7 @@ public final class ChatControllerInteraction: ChatControllerInteractionProtocol
public let openRequestedPeerSelection: (EngineMessage.Id, ReplyMarkupButtonRequestPeerType, Int32, Int32) -> Void public let openRequestedPeerSelection: (EngineMessage.Id, ReplyMarkupButtonRequestPeerType, Int32, Int32) -> Void
public let saveMediaToFiles: (EngineMessage.Id) -> Void public let saveMediaToFiles: (EngineMessage.Id) -> Void
public let openNoAdsDemo: () -> Void public let openNoAdsDemo: () -> Void
public let openAdsInfo: () -> Void
public let displayGiveawayParticipationStatus: (EngineMessage.Id) -> Void public let displayGiveawayParticipationStatus: (EngineMessage.Id) -> Void
public let openPremiumStatusInfo: (EnginePeer.Id, UIView, Int64?, PeerNameColor) -> Void public let openPremiumStatusInfo: (EnginePeer.Id, UIView, Int64?, PeerNameColor) -> Void
public let openRecommendedChannelContextMenu: (EnginePeer, UIView, ContextGesture?) -> 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, openRequestedPeerSelection: @escaping (EngineMessage.Id, ReplyMarkupButtonRequestPeerType, Int32, Int32) -> Void,
saveMediaToFiles: @escaping (EngineMessage.Id) -> Void, saveMediaToFiles: @escaping (EngineMessage.Id) -> Void,
openNoAdsDemo: @escaping () -> Void, openNoAdsDemo: @escaping () -> Void,
openAdsInfo: @escaping () -> Void,
displayGiveawayParticipationStatus: @escaping (EngineMessage.Id) -> Void, displayGiveawayParticipationStatus: @escaping (EngineMessage.Id) -> Void,
openPremiumStatusInfo: @escaping (EnginePeer.Id, UIView, Int64?, PeerNameColor) -> Void, openPremiumStatusInfo: @escaping (EnginePeer.Id, UIView, Int64?, PeerNameColor) -> Void,
openRecommendedChannelContextMenu: @escaping (EnginePeer, UIView, ContextGesture?) -> Void, openRecommendedChannelContextMenu: @escaping (EnginePeer, UIView, ContextGesture?) -> Void,
@ -456,6 +458,7 @@ public final class ChatControllerInteraction: ChatControllerInteractionProtocol
self.openRequestedPeerSelection = openRequestedPeerSelection self.openRequestedPeerSelection = openRequestedPeerSelection
self.saveMediaToFiles = saveMediaToFiles self.saveMediaToFiles = saveMediaToFiles
self.openNoAdsDemo = openNoAdsDemo self.openNoAdsDemo = openNoAdsDemo
self.openAdsInfo = openAdsInfo
self.displayGiveawayParticipationStatus = displayGiveawayParticipationStatus self.displayGiveawayParticipationStatus = displayGiveawayParticipationStatus
self.openPremiumStatusInfo = openPremiumStatusInfo self.openPremiumStatusInfo = openPremiumStatusInfo
self.openRecommendedChannelContextMenu = openRecommendedChannelContextMenu self.openRecommendedChannelContextMenu = openRecommendedChannelContextMenu

View File

@ -3232,6 +3232,8 @@ public final class MediaEditorScreen: ViewController, UIDropInteractionDelegate
controller.statusBar.statusBarStyle = .Ignore controller.statusBar.statusBarStyle = .Ignore
self.isUserInteractionEnabled = false self.isUserInteractionEnabled = false
self.saveTooltip?.dismiss()
if self.entitiesView.hasSelection { if self.entitiesView.hasSelection {
self.entitiesView.selectEntity(nil) self.entitiesView.selectEntity(nil)
} }
@ -3472,7 +3474,7 @@ public final class MediaEditorScreen: ViewController, UIDropInteractionDelegate
self.controller?.present(tooltipController, in: .current) self.controller?.present(tooltipController, in: .current)
} }
private weak var saveTooltip: SaveProgressScreen? fileprivate weak var saveTooltip: SaveProgressScreen?
func presentSaveTooltip() { func presentSaveTooltip() {
guard let controller = self.controller else { guard let controller = self.controller else {
return return
@ -3525,7 +3527,7 @@ public final class MediaEditorScreen: ViewController, UIDropInteractionDelegate
controller.cancelVideoExport() controller.cancelVideoExport()
} }
} }
controller.present(tooltipController, in: .current) controller.present(tooltipController, in: .window(.root))
self.saveTooltip = tooltipController self.saveTooltip = tooltipController
} }
} }
@ -3554,7 +3556,7 @@ public final class MediaEditorScreen: ViewController, UIDropInteractionDelegate
controller.requestLayout(transition: .animated(duration: 0.25, curve: .easeInOut)) controller.requestLayout(transition: .animated(duration: 0.25, curve: .easeInOut))
} }
} }
controller.present(tooltipController, in: .current) controller.present(tooltipController, in: .window(.root))
self.saveTooltip = tooltipController 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 resource = LocalFileMediaResource(fileId: Int64.random(in: Int64.min ... Int64.max))
let thumbnailResource = LocalFileMediaResource(fileId: Int64.random(in: Int64.min ... Int64.max))
var isVideo = false var isVideo = false
if mediaEditor.resultIsVideo { if mediaEditor.resultIsVideo {
isVideo = true 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 { } else {
Queue.concurrentDefaultQueue().async { Queue.concurrentDefaultQueue().async {
if let data = try? WebP.convert(toWebP: image, quality: 97.0) { 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 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] = [] var menuItems: [ContextMenuItem] = []
if case let .stickerEditor(mode) = self.mode { if case let .stickerEditor(mode) = self.mode {
@ -6073,7 +6082,7 @@ public final class MediaEditorScreen: ViewController, UIDropInteractionDelegate
case let .progress(progress): case let .progress(progress):
return .single(.progress(isVideo ? 0.5 + progress * 0.5 : progress)) return .single(.progress(isVideo ? 0.5 + progress * 0.5 : progress))
case let .complete(resource, _): 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 { switch action {
case .send: case .send:
return .single(status) return .single(status)
@ -6147,7 +6156,7 @@ public final class MediaEditorScreen: ViewController, UIDropInteractionDelegate
let result: MediaEditorScreen.Result let result: MediaEditorScreen.Result
switch action { switch action {
case .upload, .send: 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)) result = MediaEditorScreen.Result(media: .sticker(file: file))
default: default:
result = MediaEditorScreen.Result() 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] = [] var fileAttributes: [TelegramMediaFileAttribute] = []
fileAttributes.append(.FileName(fileName: isVideo ? "sticker.webm" : "sticker.webp")) fileAttributes.append(.FileName(fileName: isVideo ? "sticker.webm" : "sticker.webp"))
fileAttributes.append(.Sticker(displayText: "", packReference: nil, maskData: nil)) fileAttributes.append(.Sticker(displayText: "", packReference: nil, maskData: nil))
fileAttributes.append(.ImageSize(size: dimensions)) 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)
} }

View File

@ -486,7 +486,8 @@ public final class SaveProgressScreen: ViewController {
self.view.addSubview(componentView) self.view.addSubview(componentView)
} }
let componentFrame = CGRect(origin: .zero, size: componentSize) 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 { if isFirstTime {

View File

@ -32,7 +32,6 @@ final class PeerInfoBirthdayOverlay: ASDisplayNode {
self.setupAnimations(size: size, birthday: birthday, sourceRect: sourceRect) self.setupAnimations(size: size, birthday: birthday, sourceRect: sourceRect)
Queue.mainQueue().after(0.1) { Queue.mainQueue().after(0.1) {
HapticFeedback().success()
self.view.addSubview(ConfettiView(frame: CGRect(origin: .zero, size: size))) self.view.addSubview(ConfettiView(frame: CGRect(origin: .zero, size: size)))
} }
} }

View File

@ -2696,7 +2696,9 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, PeerInfoScreenNodePro
if let self { if let self {
if value { if value {
if let data = self.data?.cachedData as? CachedUserData { 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)) self.state = self.state.withUpdatingBirthDate(TelegramBirthday(day: 1, month: 1, year: nil))
} }
} }
@ -3249,6 +3251,7 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, PeerInfoScreenNodePro
}, openRequestedPeerSelection: { _, _, _, _ in }, openRequestedPeerSelection: { _, _, _, _ in
}, saveMediaToFiles: { _ in }, saveMediaToFiles: { _ in
}, openNoAdsDemo: { }, openNoAdsDemo: {
}, openAdsInfo: {
}, displayGiveawayParticipationStatus: { _ in }, displayGiveawayParticipationStatus: { _ in
}, openPremiumStatusInfo: { _, _, _, _ in }, openPremiumStatusInfo: { _, _, _, _ in
}, openRecommendedChannelContextMenu: { _, _, _ in }, openRecommendedChannelContextMenu: { _, _, _ in

View File

@ -122,6 +122,7 @@ import AudioWaveform
import PeerNameColorScreen import PeerNameColorScreen
import ChatEmptyNode import ChatEmptyNode
import ChatMediaInputStickerGridItem import ChatMediaInputStickerGridItem
import AdsInfoScreen
public enum ChatControllerPeekActions { public enum ChatControllerPeekActions {
case standard case standard
@ -4438,6 +4439,11 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
controller?.replace(with: c) controller?.replace(with: c)
} }
self.push(controller) self.push(controller)
}, openAdsInfo: { [weak self] in
guard let self else {
return
}
self.push(AdsInfoScreen(context: self.context))
}, displayGiveawayParticipationStatus: { [weak self] messageId in }, displayGiveawayParticipationStatus: { [weak self] messageId in
guard let self else { guard let self else {
return return

View File

@ -169,6 +169,7 @@ final class OverlayAudioPlayerControllerNode: ViewControllerTracingNode, UIGestu
}, openRequestedPeerSelection: { _, _, _, _ in }, openRequestedPeerSelection: { _, _, _, _ in
}, saveMediaToFiles: { _ in }, saveMediaToFiles: { _ in
}, openNoAdsDemo: { }, openNoAdsDemo: {
}, openAdsInfo: {
}, displayGiveawayParticipationStatus: { _ in }, displayGiveawayParticipationStatus: { _ in
}, openPremiumStatusInfo: { _, _, _, _ in }, openPremiumStatusInfo: { _, _, _, _ in
}, openRecommendedChannelContextMenu: { _, _, _ in }, openRecommendedChannelContextMenu: { _, _, _ in

View File

@ -1756,6 +1756,7 @@ public final class SharedAccountContextImpl: SharedAccountContext {
}, openRequestedPeerSelection: { _, _, _, _ in }, openRequestedPeerSelection: { _, _, _, _ in
}, saveMediaToFiles: { _ in }, saveMediaToFiles: { _ in
}, openNoAdsDemo: { }, openNoAdsDemo: {
}, openAdsInfo: {
}, displayGiveawayParticipationStatus: { _ in }, displayGiveawayParticipationStatus: { _ in
}, openPremiumStatusInfo: { _, _, _, _ in }, openPremiumStatusInfo: { _, _, _, _ in
}, openRecommendedChannelContextMenu: { _, _, _ in }, openRecommendedChannelContextMenu: { _, _, _ in