Various fixes

This commit is contained in:
Ilya Laktyushin 2025-01-02 04:03:51 +04:00
parent 45fa1b5ddb
commit 3bf092aff8
18 changed files with 361 additions and 292 deletions

View File

@ -13054,6 +13054,7 @@ Sorry for the inconvenience.";
"Gift.Options.Gift.Text" = "Give **%@** gifts that can be kept on the profile or converted to Stars. [What are Stars >]()";
"Gift.Options.Gift.Filter.AllGifts" = "All Gifts";
"Gift.Options.Gift.Filter.Limited" = "Limited";
"Gift.Options.Gift.Filter.InStock" = "In Stock";
"Gift.Options.Gift.Limited" = "limited";
"Gift.Options.Gift.SoldOut" = "sold out";
"Gift.Options.SoldOut.Text" = "Sorry, this gift is sold out.";
@ -13087,6 +13088,7 @@ Sorry for the inconvenience.";
"Gift.Send.HideMyName" = "Hide My Name";
"Gift.Send.HideMyName.Info" = "Hide my name and message from visitors to %1$@'s profile. %2$@ will still see your name and message.";
"Gift.Send.Send" = "Send a Gift for";
"Gift.Send.Buy" = "Buy a Gift for";
"Gift.Send.Limited" = "Limited";
"Gift.Send.Remains_1" = "%@ left";
"Gift.Send.Remains_any" = "%@ left";
@ -13616,7 +13618,7 @@ Sorry for the inconvenience.";
"BotVerification.Verify.Channel.Text" = "Do you want to verify this channel with your verification mark and description?";
"BotVerification.Verify.Group.Title" = "Verify Group";
"BotVerification.Verify.Group.Text" = "Do you want to verify this group with your verification mark and description?";
"BotVerification.Verify.User.Title" = "Verify Bot";
"BotVerification.Verify.User.Title" = "Verify User";
"BotVerification.Verify.User.Text" = "Do you want to verify this user with your verification mark and description?";
"BotVerification.Verify.Bot.Title" = "Verify Bot";
"BotVerification.Verify.Bot.Text" = "Do you want to verify this bot with your verification mark and description?";

View File

@ -3149,7 +3149,7 @@ public class ChatListItemNode: ItemListRevealOptionsItemNode {
var titleLeftOffset: CGFloat = 0.0
if let currentVerifiedIconContent {
if titleLeftOffset.isZero, case .animation = currentVerifiedIconContent {
titleLeftOffset += 20.0
titleLeftOffset += 19.0
}
if titleIconsWidth.isZero {
@ -4590,7 +4590,12 @@ public class ChatListItemNode: ItemListRevealOptionsItemNode {
strongSelf.credibilityIconComponent = credibilityIconComponent
let iconOrigin: CGFloat = nextTitleIconOrigin
let containerSize = CGSize(width: 20.0, height: 20.0)
let containerSize: CGSize
if case .verified = currentCredibilityIconContent {
containerSize = CGSize(width: 16.0, height: 16.0)
} else {
containerSize = CGSize(width: 20.0, height: 20.0)
}
let iconSize = credibilityIconView.update(
transition: .immediate,
component: AnyComponent(credibilityIconComponent),

View File

@ -794,7 +794,7 @@ public class ContactsPeerItemNode: ItemListRevealOptionsItemNode {
var verifiedIcon: EmojiStatusComponent.Content?
switch item.peer {
case let .peer(peer, _):
if let peer = peer, (peer.id != item.context.account.peerId || item.peerMode == .memberList || item.aliasHandling == .treatSelfAsSaved) {
if let peer = peer, (peer.id != item.context.account.peerId || item.peerMode == .memberList || item.aliasHandling == .standard) {
if peer.isScam {
credibilityIcon = .text(color: item.presentationData.theme.chat.message.incoming.scamColor, string: item.presentationData.strings.Message_ScamAccount.uppercased())
} else if peer.isFake {

View File

@ -1438,7 +1438,7 @@ public class ItemListPeerItemNode: ItemListRevealOptionsItemNode, ItemListItemNo
var titleLeftOffset: CGFloat = 0.0
var nextIconX: CGFloat = titleFrame.maxX
if let verifiedIcon = verifiedIcon {
if let verifiedIcon {
let animationCache = item.context.animationCache
let animationRenderer = item.context.animationRenderer
@ -1463,15 +1463,7 @@ public class ItemListPeerItemNode: ItemListRevealOptionsItemNode, ItemListItemNo
emojiFileUpdated: nil
)
strongSelf.verifiedIconComponent = verifiedIconComponent
let iconOrigin: CGFloat
if case .animation = verifiedIcon {
iconOrigin = titleFrame.minX
} else {
nextIconX += 4.0
iconOrigin = nextIconX
}
let iconSize = verifiedIconView.update(
transition: .immediate,
component: AnyComponent(verifiedIconComponent),
@ -1479,13 +1471,10 @@ public class ItemListPeerItemNode: ItemListRevealOptionsItemNode, ItemListItemNo
containerSize: CGSize(width: 20.0, height: 20.0)
)
transition.updateFrame(view: verifiedIconView, frame: CGRect(origin: CGPoint(x: iconOrigin, y: floorToScreenPixels(titleFrame.midY - iconSize.height / 2.0)), size: iconSize))
transition.updateFrame(view: verifiedIconView, frame: CGRect(origin: CGPoint(x: titleFrame.minX, y: floorToScreenPixels(titleFrame.midY - iconSize.height / 2.0)), size: iconSize))
if case .animation = verifiedIcon {
titleLeftOffset += iconSize.width + 4.0
} else {
nextIconX += iconSize.width
}
titleLeftOffset += iconSize.width + 4.0
nextIconX += iconSize.width + 4.0
} else if let verifiedIconView = strongSelf.verifiedIconView {
strongSelf.verifiedIconView = nil
verifiedIconView.removeFromSuperview()

View File

@ -2,17 +2,17 @@ import Foundation
import PresentationStrings
import TelegramCore
public func compactNumericCountString(_ count: Int, decimalSeparator: String = ".") -> String {
public func compactNumericCountString(_ count: Int, decimalSeparator: String = ".", showDecimalPart: Bool = true) -> String {
if count >= 1000 * 1000 {
let remainder = (count % (1000 * 1000)) / (1000 * 100)
if remainder != 0 {
if remainder != 0 && showDecimalPart {
return "\(count / (1000 * 1000))\(decimalSeparator)\(remainder)M"
} else {
return "\(count / (1000 * 1000))M"
}
} else if count >= 1000 {
let remainder = (count % (1000)) / (100)
if remainder != 0 {
if remainder != 0 && showDecimalPart {
return "\(count / 1000)\(decimalSeparator)\(remainder)K"
} else {
return "\(count / 1000)K"

View File

@ -59,6 +59,7 @@ public class ChatMessageGiftBubbleContentNode: ChatMessageBubbleContentNode {
private var shimmerEffectNode: ShimmerEffectForegroundNode?
private let buttonNode: HighlightTrackingButtonNode
private let buttonStarsNode: PremiumStarsNode
private let buttonContentNode: ASDisplayNode
private let buttonTitleNode: TextNode
private var buttonIconNode: DefaultAnimatedStickerNodeImpl?
@ -162,8 +163,10 @@ public class ChatMessageGiftBubbleContentNode: ChatMessageBubbleContentNode {
self.buttonStarsNode = PremiumStarsNode()
self.buttonContentNode = ASDisplayNode()
self.buttonContentNode.isUserInteractionEnabled = false
self.buttonTitleNode = TextNode()
self.buttonTitleNode.isUserInteractionEnabled = false
self.buttonTitleNode.displaysAsynchronously = false
self.ribbonBackgroundNode = ASImageNode()
@ -190,7 +193,9 @@ public class ChatMessageGiftBubbleContentNode: ChatMessageBubbleContentNode {
self.addSubnode(self.buttonNode)
self.buttonNode.addSubnode(self.buttonStarsNode)
self.buttonNode.addSubnode(self.buttonTitleNode)
self.buttonNode.addSubnode(self.buttonContentNode)
self.buttonContentNode.addSubnode(self.buttonTitleNode)
self.addSubnode(self.ribbonBackgroundNode)
self.addSubnode(self.ribbonTextNode)
@ -546,8 +551,12 @@ public class ChatMessageGiftBubbleContentNode: ChatMessageBubbleContentNode {
if case let .unique(uniqueGift) = gift {
isStarGift = true
let authorName: String
if isUpgrade && item.message.author?.id == item.context.account.peerId {
authorName = item.message.peers[item.message.id.peerId].flatMap { EnginePeer($0) }?.compactDisplayTitle ?? ""
if isUpgrade {
if item.message.author?.id == item.context.account.peerId {
authorName = item.message.peers[item.message.id.peerId].flatMap { EnginePeer($0) }?.compactDisplayTitle ?? ""
} else {
authorName = item.associatedData.accountPeer?.compactDisplayTitle ?? ""
}
} else {
authorName = item.message.author.flatMap { EnginePeer($0) }?.compactDisplayTitle ?? ""
}
@ -747,7 +756,7 @@ public class ChatMessageGiftBubbleContentNode: ChatMessageBubbleContentNode {
let overlayColor = item.presentationData.theme.theme.overallDarkAppearance ? UIColor(rgb: 0xffffff, alpha: 0.12) : UIColor(rgb: 0x000000, alpha: 0.12)
let imageFrame = CGRect(origin: CGPoint(x: floorToScreenPixels((backgroundSize.width - giftSize.width) / 2.0), y: hasServiceMessage ? labelLayout.size.height + 16.0 : 0.0), size: giftSize)
let imageFrame = CGRect(origin: CGPoint(x: floorToScreenPixels((backgroundSize.width - giftSize.width) / 2.0), y: hasServiceMessage ? labelLayout.size.height + 12.0 : 0.0), size: giftSize)
let mediaBackgroundFrame = imageFrame.insetBy(dx: -2.0, dy: -2.0)
var iconSize = CGSize(width: 160.0, height: 160.0)
@ -947,7 +956,7 @@ public class ChatMessageGiftBubbleContentNode: ChatMessageBubbleContentNode {
} else {
buttonIconNode = DefaultAnimatedStickerNodeImpl()
buttonIconNode.setup(source: AnimatedStickerNodeLocalFileSource(name: buttonIcon), width: 60, height: 60, playbackMode: .loop, mode: .direct(cachePathPrefix: nil))
strongSelf.buttonNode.addSubnode(buttonIconNode)
strongSelf.buttonContentNode.addSubnode(buttonIconNode)
strongSelf.buttonIconNode = buttonIconNode
buttonIconNode.playLoop()
}
@ -960,6 +969,7 @@ public class ChatMessageGiftBubbleContentNode: ChatMessageBubbleContentNode {
animation.animator.updateFrame(layer: strongSelf.buttonNode.layer, frame: CGRect(origin: CGPoint(x: mediaBackgroundFrame.minX + floorToScreenPixels((mediaBackgroundFrame.width - buttonSize.width) / 2.0), y: buttonOriginY), size: buttonSize), completion: nil)
strongSelf.buttonStarsNode.frame = CGRect(origin: .zero, size: buttonSize)
animation.animator.updateFrame(layer: strongSelf.buttonContentNode.layer, frame: CGRect(origin: .zero, size: buttonSize), completion: nil)
if ribbonTextLayout.size.width > 0.0 {
if strongSelf.ribbonBackgroundNode.image == nil {

View File

@ -950,13 +950,12 @@ public final class ChatTitleView: UIView, NavigationBarTitleView {
titleTransition = .immediate
}
let iconSpacing: CGFloat = 2.0
let titleSideInset: CGFloat = 6.0
var titleFrame: CGRect
if size.height > 40.0 {
var titleInsets: UIEdgeInsets = .zero
if case .emojiStatus = self.titleVerifiedIcon, verifiedIconWidth > 0.0 {
titleInsets.left = verifiedIconWidth + iconSpacing
titleInsets.left = verifiedIconWidth
}
var titleSize = self.titleTextNode.updateLayout(size: CGSize(width: clearBounds.width - leftIconWidth - credibilityIconWidth - verifiedIconWidth - statusIconWidth - rightIconWidth - titleSideInset * 2.0, height: size.height), insets: titleInsets, animated: titleTransition.isAnimated)
@ -998,18 +997,7 @@ public final class ChatTitleView: UIView, NavigationBarTitleView {
var nextIconX: CGFloat = titleFrame.width
var verifiedIconX: CGFloat
if case .emojiStatus = self.titleVerifiedIcon {
verifiedIconX = 0.0
} else {
verifiedIconX = nextIconX - titleVerifiedSize.width
}
self.titleVerifiedIconView.frame = CGRect(origin: CGPoint(x: verifiedIconX, y: floor((titleFrame.height - titleVerifiedSize.height) / 2.0)), size: titleVerifiedSize)
if case .emojiStatus = self.titleVerifiedIcon {
} else {
nextIconX -= titleVerifiedSize.width
}
self.titleVerifiedIconView.frame = CGRect(origin: CGPoint(x: 0.0, y: floor((titleFrame.height - titleVerifiedSize.height) / 2.0)), size: titleVerifiedSize)
self.titleCredibilityIconView.frame = CGRect(origin: CGPoint(x: nextIconX - titleCredibilitySize.width, y: floor((titleFrame.height - titleCredibilitySize.height) / 2.0)), size: titleCredibilitySize)
nextIconX -= titleCredibilitySize.width

View File

@ -220,7 +220,7 @@ public final class GiftItemComponent: Component {
iconSize = CGSize(width: 88.0, height: 88.0)
cornerRadius = 10.0
case .profile:
size = CGSize(width: availableSize.width, height: availableSize.width)
size = CGSize(width: availableSize.width, height: min(117 - UIScreenPixel, availableSize.width))
iconSize = CGSize(width: 88.0, height: 88.0)
cornerRadius = 10.0
case .thumbnail:
@ -460,11 +460,17 @@ public final class GiftItemComponent: Component {
}
if let ribbon = component.ribbon {
let ribbonFontSize: CGFloat
if case .profile = component.mode {
ribbonFontSize = 9.0
} else {
ribbonFontSize = 10.0
}
let ribbonTextSize = self.ribbonText.update(
transition: transition,
component: AnyComponent(
MultilineTextComponent(
text: .plain(NSAttributedString(string: ribbon.text, font: Font.semibold(10.0), textColor: .white)),
text: .plain(NSAttributedString(string: ribbon.text, font: Font.semibold(ribbonFontSize), textColor: .white)),
horizontalAlignment: .center
)
),

View File

@ -79,6 +79,7 @@ final class GiftOptionsScreenComponent: Component {
public enum StarsFilter: Equatable {
case all
case limited
case inStock
case stars(Int64)
init(rawValue: Int64) {
@ -87,6 +88,8 @@ final class GiftOptionsScreenComponent: Component {
self = .all
case -1:
self = .limited
case -2:
self = .inStock
default:
self = .stars(rawValue)
}
@ -98,6 +101,8 @@ final class GiftOptionsScreenComponent: Component {
return 0
case .limited:
return -1
case .inStock:
return -2
case let .stars(stars):
return stars
}
@ -159,6 +164,10 @@ final class GiftOptionsScreenComponent: Component {
if $0.availability != nil {
return true
}
case .inStock:
if $0.availability == nil || $0.availability!.remains > 0 {
return true
}
case let .stars(stars):
if $0.price == stars {
return true
@ -901,6 +910,11 @@ final class GiftOptionsScreenComponent: Component {
title: strings.Gift_Options_Gift_Filter_Limited
))
}
tabSelectorItems.append(TabSelectorComponent.Item(
id: AnyHashable(StarsFilter.inStock.rawValue),
title: strings.Gift_Options_Gift_Filter_InStock
))
let starsAmounts = Array(starsAmountsSet).sorted()
for amount in starsAmounts {

View File

@ -250,7 +250,7 @@ final class ChatGiftPreviewItemNode: ListViewItemNode {
let itemNode = messageNodes[i]
items[i].updateNode(async: { $0() }, node: {
return itemNode
}, params: params, previousItem: i == 0 ? nil : items[i - 1], nextItem: i == (items.count - 1) ? nil : items[i + 1], animation: .None, completion: { (layout, apply) in
}, params: params, previousItem: i == 0 ? nil : items[i - 1], nextItem: i == (items.count - 1) ? nil : items[i + 1], animation: .System(duration: 0.2, transition: ControlledTransition(duration: 0.2, curve: .spring, interactive: false)), completion: { (layout, apply) in
let nodeFrame = CGRect(origin: itemNode.frame.origin, size: CGSize(width: layout.size.width, height: layout.size.height))
itemNode.contentSize = layout.contentSize

View File

@ -417,10 +417,23 @@ final class GiftSetupScreenComponent: Component {
options: options ?? [],
purpose: .starGift(peerId: component.peerId, requiredStars: starGift.price),
completion: { [weak starsContext] stars in
starsContext?.add(balance: StarsAmount(value: stars, nanos: 0))
Queue.mainQueue().after(2.0) {
proceed()
guard let starsContext else {
return
}
starsContext.add(balance: StarsAmount(value: stars, nanos: 0))
let _ = (starsContext.state
|> take(until: { value in
if let value {
if !value.flags.contains(.isPendingBalance) {
return SignalTakeAction(passthrough: true, complete: true)
}
}
return SignalTakeAction(passthrough: false, complete: false)
})
|> deliverOnMainQueue).start(next: { _ in
proceed()
})
}
)
controller.push(purchaseController)
@ -464,8 +477,13 @@ final class GiftSetupScreenComponent: Component {
}
let peerName = self.peerMap[component.peerId]?.compactDisplayTitle ?? ""
let isSelfGift = component.peerId == component.context.account.peerId
if self.component == nil {
if isSelfGift {
self.hideName = true
}
let _ = (component.context.engine.data.get(
TelegramEngine.EngineData.Item.Peer.Peer(id: component.peerId),
TelegramEngine.EngineData.Item.Peer.Peer(id: component.context.account.peerId)
@ -615,9 +633,7 @@ final class GiftSetupScreenComponent: Component {
}
let presentationData = component.context.sharedContext.currentPresentationData.with { $0 }
let isSelfGift = component.peerId == component.context.account.peerId
let navigationTitleSize = self.navigationTitle.update(
transition: transition,
component: AnyComponent(MultilineTextComponent(
@ -1037,7 +1053,8 @@ final class GiftSetupScreenComponent: Component {
finalPrice += upgradePrice
}
let amountString = presentationStringsFormattedNumber(Int32(finalPrice), presentationData.dateTimeFormat.groupingSeparator)
buttonString = "\(environment.strings.Gift_Send_Send) # \(amountString)"
let buttonTitle = isSelfGift ? environment.strings.Gift_Send_Buy : environment.strings.Gift_Send_Send
buttonString = "\(buttonTitle) # \(amountString)"
if let availability = starGift.availability, availability.remains == 0 {
buttonIsEnabled = false
}

View File

@ -1108,21 +1108,27 @@ private final class GiftViewSheetContent: CombinedComponent {
let format = senderName != nil ? strings.Gift_Unique_OriginalInfoSenderWithText(senderName!, recipientName, dateString, "") : strings.Gift_Unique_OriginalInfoWithText(recipientName, dateString, "")
let string = NSMutableAttributedString(string: format.string, font: tableFont, textColor: tableTextColor)
string.replaceCharacters(in: format.ranges[format.ranges.count - 1].range, with: attributedText)
if let _ = senderName {
string.addAttribute(NSAttributedString.Key.foregroundColor, value: tableLinkColor, range: format.ranges[0].range)
string.addAttribute(NSAttributedString.Key.foregroundColor, value: tableLinkColor, range: format.ranges[1].range)
if let senderPeerId {
string.addAttribute(.foregroundColor, value: tableLinkColor, range: format.ranges[0].range)
string.addAttribute(NSAttributedString.Key(rawValue: TelegramTextAttributes.PeerMention), value: TelegramPeerMention(peerId: senderPeerId, mention: ""), range: format.ranges[0].range)
string.addAttribute(.foregroundColor, value: tableLinkColor, range: format.ranges[1].range)
string.addAttribute(NSAttributedString.Key(rawValue: TelegramTextAttributes.PeerMention), value: TelegramPeerMention(peerId: recipientPeerId, mention: ""), range: format.ranges[1].range)
} else {
string.addAttribute(NSAttributedString.Key.foregroundColor, value: tableLinkColor, range: format.ranges[0].range)
string.addAttribute(.foregroundColor, value: tableLinkColor, range: format.ranges[0].range)
string.addAttribute(NSAttributedString.Key(rawValue: TelegramTextAttributes.PeerMention), value: TelegramPeerMention(peerId: recipientPeerId, mention: ""), range: format.ranges[0].range)
}
value = string
} else {
let format = senderName != nil ? strings.Gift_Unique_OriginalInfoSender(senderName!, recipientName, dateString) : strings.Gift_Unique_OriginalInfo(recipientName, dateString)
let string = NSMutableAttributedString(string: format.string, font: tableFont, textColor: tableTextColor)
if let _ = senderName {
string.addAttribute(NSAttributedString.Key.foregroundColor, value: tableLinkColor, range: format.ranges[0].range)
string.addAttribute(NSAttributedString.Key.foregroundColor, value: tableLinkColor, range: format.ranges[1].range)
if let senderPeerId {
string.addAttribute(.foregroundColor, value: tableLinkColor, range: format.ranges[0].range)
string.addAttribute(NSAttributedString.Key(rawValue: TelegramTextAttributes.PeerMention), value: TelegramPeerMention(peerId: senderPeerId, mention: ""), range: format.ranges[0].range)
string.addAttribute(.foregroundColor, value: tableLinkColor, range: format.ranges[1].range)
string.addAttribute(NSAttributedString.Key(rawValue: TelegramTextAttributes.PeerMention), value: TelegramPeerMention(peerId: recipientPeerId, mention: ""), range: format.ranges[1].range)
} else {
string.addAttribute(NSAttributedString.Key.foregroundColor, value: tableLinkColor, range: format.ranges[0].range)
string.addAttribute(.foregroundColor, value: tableLinkColor, range: format.ranges[0].range)
string.addAttribute(NSAttributedString.Key(rawValue: TelegramTextAttributes.PeerMention), value: TelegramPeerMention(peerId: recipientPeerId, mention: ""), range: format.ranges[0].range)
}
value = string
@ -1146,7 +1152,26 @@ private final class GiftViewSheetContent: CombinedComponent {
horizontalAlignment: .center,
maximumNumberOfLines: 0,
insets: id == "originalInfo" ? UIEdgeInsets(top: 2.0, left: 0.0, bottom: 2.0, right: 0.0) : .zero,
handleSpoilers: true
highlightColor: tableLinkColor.withAlphaComponent(0.1),
handleSpoilers: true,
highlightAction: { attributes in
if let _ = attributes[NSAttributedString.Key(rawValue: TelegramTextAttributes.PeerMention)] {
return NSAttributedString.Key(rawValue: TelegramTextAttributes.PeerMention)
} else {
return nil
}
},
tapAction: { [weak state] attributes, _ in
guard let state else {
return
}
if let mention = attributes[NSAttributedString.Key(rawValue: TelegramTextAttributes.PeerMention)] as? TelegramPeerMention, let peer = state.peerMap[mention.peerId] {
component.openPeer(peer)
Queue.mainQueue().after(1.0, {
component.cancel(false)
})
}
}
)
)
)
@ -1178,11 +1203,13 @@ private final class GiftViewSheetContent: CombinedComponent {
}
}
let issuedString = presentationStringsFormattedNumber(uniqueGift.availability.issued, environment.dateTimeFormat.groupingSeparator)
let totalString = presentationStringsFormattedNumber(uniqueGift.availability.total, environment.dateTimeFormat.groupingSeparator)
tableItems.insert(.init(
id: "availability",
title: strings.Gift_Unique_Availability,
component: AnyComponent(
MultilineTextComponent(text: .plain(NSAttributedString(string: strings.Gift_Unique_Issued("\(uniqueGift.availability.issued)/\(uniqueGift.availability.total)").string, font: tableFont, textColor: tableTextColor)))
MultilineTextComponent(text: .plain(NSAttributedString(string: strings.Gift_Unique_Issued("\(issuedString)/\(totalString)").string, font: tableFont, textColor: tableTextColor)))
)
), at: hasOriginalInfo ? tableItems.count - 1 : tableItems.count)
} else {

View File

@ -16,6 +16,7 @@ import UndoUI
import PeerAvatarGalleryUI
import PresentationDataUtils
import LegacyComponents
import LegacyMediaPickerUI
extension PeerInfoScreenImpl {
// func newopenAvatarForEditing(mode: PeerInfoAvatarEditingMode = .generic, fromGallery: Bool = false, completion: @escaping (UIImage?) -> Void = { _ in }) {
@ -383,226 +384,226 @@ extension PeerInfoScreenImpl {
let photoResource = LocalFileMediaResource(fileId: Int64.random(in: Int64.min ... Int64.max))
self.context.account.postbox.mediaBox.storeResourceData(photoResource.id, data: data)
// let representation = TelegramMediaImageRepresentation(dimensions: PixelDimensions(width: 640, height: 640), resource: photoResource, progressiveSizes: [], immediateThumbnailData: nil, hasVideo: false, isPersonal: mode == .custom ? true : false)
//
// var markup: UploadPeerPhotoMarkup? = nil
// if let fileId = adjustments?.documentId, let backgroundColors = adjustments?.colors as? [Int32], fileId != 0 {
// if let packId = adjustments?.stickerPackId, let accessHash = adjustments?.stickerPackAccessHash, packId != 0 {
// markup = .sticker(packReference: .id(id: packId, accessHash: accessHash), fileId: fileId, backgroundColors: backgroundColors)
// } else {
// markup = .emoji(fileId: fileId, backgroundColors: backgroundColors)
// }
// }
//
// var uploadVideo = true
// if let _ = markup {
// if let data = self.context.currentAppConfiguration.with({ $0 }).data, let uploadVideoValue = data["upload_markup_video"] as? Bool, uploadVideoValue {
// uploadVideo = true
// } else {
// uploadVideo = false
// }
// }
//
// if [.suggest, .fallback].contains(mode) {
// } else {
// self.controllerNode.state = self.controllerNode.state.withUpdatingAvatar(.image(representation))
// if !uploadVideo {
// self.controllerNode.state = self.controllerNode.state.withAvatarUploadProgress(.indefinite)
// }
// }
//
// if let (layout, navigationHeight) = self.controllerNode.validLayout {
// self.controllerNode.containerLayoutUpdated(layout: layout, navigationHeight: navigationHeight, transition: mode == .custom ? .animated(duration: 0.2, curve: .easeInOut) : .immediate, additive: false)
// }
// self.controllerNode.headerNode.ignoreCollapse = false
//
// var videoStartTimestamp: Double? = nil
// if let adjustments = adjustments, adjustments.videoStartValue > 0.0 {
// videoStartTimestamp = adjustments.videoStartValue - adjustments.trimStartValue
// }
//
// let account = self.context.account
// let context = self.context
//
// let videoResource: Signal<TelegramMediaResource?, UploadPeerPhotoError>
// if uploadVideo {
// videoResource = Signal<TelegramMediaResource?, UploadPeerPhotoError> { [weak self] subscriber in
// let entityRenderer: LegacyPaintEntityRenderer? = adjustments.flatMap { adjustments in
// if let paintingData = adjustments.paintingData, paintingData.hasAnimation {
// return LegacyPaintEntityRenderer(postbox: account.postbox, adjustments: adjustments)
// } else {
// return nil
// }
// }
//
// let tempFile = EngineTempBox.shared.tempFile(fileName: "video.mp4")
// let uploadInterface = LegacyLiveUploadInterface(context: context)
// let signal: SSignal
// if let url = asset as? URL, url.absoluteString.hasSuffix(".jpg"), let data = try? Data(contentsOf: url, options: [.mappedRead]), let image = UIImage(data: data), let entityRenderer = entityRenderer {
// let durationSignal: SSignal = SSignal(generator: { subscriber in
// let disposable = (entityRenderer.duration()).start(next: { duration in
// subscriber.putNext(duration)
// subscriber.putCompletion()
// })
//
// return SBlockDisposable(block: {
// disposable.dispose()
// })
// })
// signal = durationSignal.map(toSignal: { duration -> SSignal in
// if let duration = duration as? Double {
// return TGMediaVideoConverter.renderUIImage(image, duration: duration, adjustments: adjustments, path: tempFile.path, watcher: nil, entityRenderer: entityRenderer)!
// } else {
// return SSignal.single(nil)
// }
// })
// } else if let asset = asset as? AVAsset {
// signal = TGMediaVideoConverter.convert(asset, adjustments: adjustments, path: tempFile.path, watcher: uploadInterface, entityRenderer: entityRenderer)!
// } else {
// signal = SSignal.complete()
// }
//
// let signalDisposable = signal.start(next: { next in
// if let result = next as? TGMediaVideoConversionResult {
// if let image = result.coverImage, let data = image.jpegData(compressionQuality: 0.7) {
// account.postbox.mediaBox.storeResourceData(photoResource.id, data: data)
// }
//
// if let timestamp = videoStartTimestamp {
// videoStartTimestamp = max(0.0, min(timestamp, result.duration - 0.05))
// }
//
// var value = stat()
// if stat(result.fileURL.path, &value) == 0 {
// if let data = try? Data(contentsOf: result.fileURL) {
// let resource: TelegramMediaResource
// if let liveUploadData = result.liveUploadData as? LegacyLiveUploadInterfaceResult {
// resource = LocalFileMediaResource(fileId: liveUploadData.id)
// } else {
// resource = LocalFileMediaResource(fileId: Int64.random(in: Int64.min ... Int64.max))
// }
// account.postbox.mediaBox.storeResourceData(resource.id, data: data, synchronous: true)
// subscriber.putNext(resource)
//
// EngineTempBox.shared.dispose(tempFile)
// }
// }
// subscriber.putCompletion()
// } else if let strongSelf = self, let progress = next as? NSNumber {
// Queue.mainQueue().async {
// strongSelf.state = strongSelf.state.withAvatarUploadProgress(.value(CGFloat(progress.floatValue * 0.45)))
// if let (layout, navigationHeight) = strongSelf.validLayout {
// strongSelf.containerLayoutUpdated(layout: layout, navigationHeight: navigationHeight, transition: .immediate, additive: false)
// }
// }
// }
// }, error: { _ in
// }, completed: nil)
//
// let disposable = ActionDisposable {
// signalDisposable?.dispose()
// }
//
// return ActionDisposable {
// disposable.dispose()
// }
// }
// } else {
// videoResource = .single(nil)
// }
//
// var dismissStatus: (() -> Void)?
// if [.suggest, .fallback, .accept].contains(mode) {
// let statusController = OverlayStatusController(theme: self.presentationData.theme, type: .loading(cancelled: { [weak self] in
// self?.controllerNode.updateAvatarDisposable.set(nil)
// dismissStatus?()
// }))
// dismissStatus = { [weak statusController] in
// statusController?.dismiss()
// }
// if let topController = self.navigationController?.topViewController as? ViewController {
// topController.presentInGlobalOverlay(statusController)
// } else if let topController = self.parentController?.topViewController as? ViewController {
// topController.presentInGlobalOverlay(statusController)
// } else {
// self.presentInGlobalOverlay(statusController)
// }
// }
//
// let peerId = self.peerId
// let isSettings = self.isSettings
// let isMyProfile = self.isMyProfile
// self.controllerNode.updateAvatarDisposable.set((videoResource
// |> mapToSignal { videoResource -> Signal<UpdatePeerPhotoStatus, UploadPeerPhotoError> in
// if isSettings || isMyProfile {
// if case .fallback = mode {
// return context.engine.accountData.updateFallbackPhoto(resource: photoResource, videoResource: videoResource, videoStartTimestamp: videoStartTimestamp, markup: markup, mapResourceToAvatarSizes: { resource, representations in
// return mapResourceToAvatarSizes(postbox: account.postbox, resource: resource, representations: representations)
// })
// } else {
// return context.engine.accountData.updateAccountPhoto(resource: photoResource, videoResource: videoResource, videoStartTimestamp: videoStartTimestamp, markup: markup, mapResourceToAvatarSizes: { resource, representations in
// return mapResourceToAvatarSizes(postbox: account.postbox, resource: resource, representations: representations)
// })
// }
// } else if case .custom = mode {
// return context.engine.contacts.updateContactPhoto(peerId: peerId, resource: photoResource, videoResource: videoResource, videoStartTimestamp: videoStartTimestamp, markup: markup, mode: .custom, mapResourceToAvatarSizes: { resource, representations in
// return mapResourceToAvatarSizes(postbox: account.postbox, resource: resource, representations: representations)
// })
// } else if case .suggest = mode {
// return context.engine.contacts.updateContactPhoto(peerId: peerId, resource: photoResource, videoResource: videoResource, videoStartTimestamp: videoStartTimestamp, markup: markup, mode: .suggest, mapResourceToAvatarSizes: { resource, representations in
// return mapResourceToAvatarSizes(postbox: account.postbox, resource: resource, representations: representations)
// })
// } else {
// return context.engine.peers.updatePeerPhoto(peerId: peerId, photo: context.engine.peers.uploadedPeerPhoto(resource: photoResource), video: videoResource.flatMap { context.engine.peers.uploadedPeerVideo(resource: $0) |> map(Optional.init) }, videoStartTimestamp: videoStartTimestamp, markup: markup, mapResourceToAvatarSizes: { resource, representations in
// return mapResourceToAvatarSizes(postbox: account.postbox, resource: resource, representations: representations)
// })
// }
// }
// |> deliverOnMainQueue).startStrict(next: { [weak self] result in
// guard let strongSelf = self else {
// return
// }
// switch result {
// case .complete:
// strongSelf.controllerNode.state = strongSelf.controllerNode.state.withUpdatingAvatar(nil).withAvatarUploadProgress(nil)
// case let .progress(value):
// strongSelf.controllerNode.state = strongSelf.controllerNode.state.withAvatarUploadProgress(.value(CGFloat(0.45 + value * 0.55)))
// }
// if let (layout, navigationHeight) = strongSelf.controllerNode.validLayout {
// strongSelf.controllerNode.containerLayoutUpdated(layout: layout, navigationHeight: navigationHeight, transition: .immediate, additive: false)
// }
//
// if case .complete = result {
// dismissStatus?()
//
// let _ = (strongSelf.context.engine.data.get(TelegramEngine.EngineData.Item.Peer.Peer(id: strongSelf.peerId))
// |> deliverOnMainQueue).startStandalone(next: { [weak self] peer in
// if let strongSelf = self, let peer {
// switch mode {
// case .fallback:
// (strongSelf.parentController?.topViewController as? ViewController)?.present(UndoOverlayController(presentationData: strongSelf.presentationData, content: .image(image: image, title: nil, text: strongSelf.presentationData.strings.Privacy_ProfilePhoto_PublicVideoSuccess, round: true, undoText: nil), elevatedLayout: false, animateInAsReplacement: true, action: { _ in return false }), in: .current)
// case .custom:
// strongSelf.present(UndoOverlayController(presentationData: strongSelf.presentationData, content: .invitedToVoiceChat(context: strongSelf.context, peer: peer, title: nil, text: strongSelf.presentationData.strings.UserInfo_SetCustomPhoto_SuccessVideoText(peer.compactDisplayTitle).string, action: nil, duration: 5), elevatedLayout: false, animateInAsReplacement: true, action: { _ in return false }), in: .current)
//
// let _ = (strongSelf.context.peerChannelMemberCategoriesContextsManager.profilePhotos(postbox: strongSelf.context.account.postbox, network: strongSelf.context.account.network, peerId: strongSelf.peerId, fetch: peerInfoProfilePhotos(context: strongSelf.context, peerId: strongSelf.peerId)) |> ignoreValues).startStandalone()
// case .suggest:
// if let navigationController = (strongSelf.navigationController as? NavigationController) {
// strongSelf.context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: strongSelf.context, chatLocation: .peer(peer), keepStack: .default, completion: { _ in
// }))
// }
// case .accept:
// (strongSelf.parentController?.topViewController as? ViewController)?.present(UndoOverlayController(presentationData: strongSelf.presentationData, content: .image(image: image, title: strongSelf.presentationData.strings.Conversation_SuggestedVideoSuccess, text: strongSelf.presentationData.strings.Conversation_SuggestedVideoSuccessText, round: true, undoText: nil), elevatedLayout: false, animateInAsReplacement: true, action: { [weak self] action in
// if case .info = action {
// self?.parentController?.openSettings()
// }
// return false
// }), in: .current)
// default:
// break
// }
// }
// })
// }
// }))
let representation = TelegramMediaImageRepresentation(dimensions: PixelDimensions(width: 640, height: 640), resource: photoResource, progressiveSizes: [], immediateThumbnailData: nil, hasVideo: false, isPersonal: mode == .custom ? true : false)
var markup: UploadPeerPhotoMarkup? = nil
if let fileId = adjustments?.documentId, let backgroundColors = adjustments?.colors as? [Int32], fileId != 0 {
if let packId = adjustments?.stickerPackId, let accessHash = adjustments?.stickerPackAccessHash, packId != 0 {
markup = .sticker(packReference: .id(id: packId, accessHash: accessHash), fileId: fileId, backgroundColors: backgroundColors)
} else {
markup = .emoji(fileId: fileId, backgroundColors: backgroundColors)
}
}
var uploadVideo = true
if let _ = markup {
if let data = self.context.currentAppConfiguration.with({ $0 }).data, let uploadVideoValue = data["upload_markup_video"] as? Bool, uploadVideoValue {
uploadVideo = true
} else {
uploadVideo = false
}
}
if [.suggest, .fallback].contains(mode) {
} else {
self.controllerNode.state = self.controllerNode.state.withUpdatingAvatar(.image(representation))
if !uploadVideo {
self.controllerNode.state = self.controllerNode.state.withAvatarUploadProgress(.indefinite)
}
}
if let (layout, navigationHeight) = self.controllerNode.validLayout {
self.controllerNode.containerLayoutUpdated(layout: layout, navigationHeight: navigationHeight, transition: mode == .custom ? .animated(duration: 0.2, curve: .easeInOut) : .immediate, additive: false)
}
self.controllerNode.headerNode.ignoreCollapse = false
var videoStartTimestamp: Double? = nil
if let adjustments = adjustments, adjustments.videoStartValue > 0.0 {
videoStartTimestamp = adjustments.videoStartValue - adjustments.trimStartValue
}
let account = self.context.account
let context = self.context
let videoResource: Signal<TelegramMediaResource?, UploadPeerPhotoError>
if uploadVideo {
videoResource = Signal<TelegramMediaResource?, UploadPeerPhotoError> { [weak self] subscriber in
let entityRenderer: LegacyPaintEntityRenderer? = adjustments.flatMap { adjustments in
if let paintingData = adjustments.paintingData, paintingData.hasAnimation {
return LegacyPaintEntityRenderer(postbox: account.postbox, adjustments: adjustments)
} else {
return nil
}
}
let tempFile = EngineTempBox.shared.tempFile(fileName: "video.mp4")
let uploadInterface = LegacyLiveUploadInterface(context: context)
let signal: SSignal
if let url = asset as? URL, url.absoluteString.hasSuffix(".jpg"), let data = try? Data(contentsOf: url, options: [.mappedRead]), let image = UIImage(data: data), let entityRenderer = entityRenderer {
let durationSignal: SSignal = SSignal(generator: { subscriber in
let disposable = (entityRenderer.duration()).start(next: { duration in
subscriber.putNext(duration)
subscriber.putCompletion()
})
return SBlockDisposable(block: {
disposable.dispose()
})
})
signal = durationSignal.map(toSignal: { duration -> SSignal in
if let duration = duration as? Double {
return TGMediaVideoConverter.renderUIImage(image, duration: duration, adjustments: adjustments, path: tempFile.path, watcher: nil, entityRenderer: entityRenderer)!
} else {
return SSignal.single(nil)
}
})
} else if let asset = asset as? AVAsset {
signal = TGMediaVideoConverter.convert(asset, adjustments: adjustments, path: tempFile.path, watcher: uploadInterface, entityRenderer: entityRenderer)!
} else {
signal = SSignal.complete()
}
let signalDisposable = signal.start(next: { next in
if let result = next as? TGMediaVideoConversionResult {
if let image = result.coverImage, let data = image.jpegData(compressionQuality: 0.7) {
account.postbox.mediaBox.storeResourceData(photoResource.id, data: data)
}
if let timestamp = videoStartTimestamp {
videoStartTimestamp = max(0.0, min(timestamp, result.duration - 0.05))
}
var value = stat()
if stat(result.fileURL.path, &value) == 0 {
if let data = try? Data(contentsOf: result.fileURL) {
let resource: TelegramMediaResource
if let liveUploadData = result.liveUploadData as? LegacyLiveUploadInterfaceResult {
resource = LocalFileMediaResource(fileId: liveUploadData.id)
} else {
resource = LocalFileMediaResource(fileId: Int64.random(in: Int64.min ... Int64.max))
}
account.postbox.mediaBox.storeResourceData(resource.id, data: data, synchronous: true)
subscriber.putNext(resource)
EngineTempBox.shared.dispose(tempFile)
}
}
subscriber.putCompletion()
} else if let strongSelf = self, let progress = next as? NSNumber {
Queue.mainQueue().async {
strongSelf.controllerNode.state = strongSelf.controllerNode.state.withAvatarUploadProgress(.value(CGFloat(progress.floatValue * 0.45)))
if let (layout, navigationHeight) = strongSelf.controllerNode.validLayout {
strongSelf.controllerNode.containerLayoutUpdated(layout: layout, navigationHeight: navigationHeight, transition: .immediate, additive: false)
}
}
}
}, error: { _ in
}, completed: nil)
let disposable = ActionDisposable {
signalDisposable?.dispose()
}
return ActionDisposable {
disposable.dispose()
}
}
} else {
videoResource = .single(nil)
}
var dismissStatus: (() -> Void)?
if [.suggest, .fallback, .accept].contains(mode) {
let statusController = OverlayStatusController(theme: self.presentationData.theme, type: .loading(cancelled: { [weak self] in
self?.controllerNode.updateAvatarDisposable.set(nil)
dismissStatus?()
}))
dismissStatus = { [weak statusController] in
statusController?.dismiss()
}
if let topController = self.navigationController?.topViewController as? ViewController {
topController.presentInGlobalOverlay(statusController)
} else if let topController = self.parentController?.topViewController as? ViewController {
topController.presentInGlobalOverlay(statusController)
} else {
self.presentInGlobalOverlay(statusController)
}
}
let peerId = self.peerId
let isSettings = self.isSettings
let isMyProfile = self.isMyProfile
self.controllerNode.updateAvatarDisposable.set((videoResource
|> mapToSignal { videoResource -> Signal<UpdatePeerPhotoStatus, UploadPeerPhotoError> in
if isSettings || isMyProfile {
if case .fallback = mode {
return context.engine.accountData.updateFallbackPhoto(resource: photoResource, videoResource: videoResource, videoStartTimestamp: videoStartTimestamp, markup: markup, mapResourceToAvatarSizes: { resource, representations in
return mapResourceToAvatarSizes(postbox: account.postbox, resource: resource, representations: representations)
})
} else {
return context.engine.accountData.updateAccountPhoto(resource: photoResource, videoResource: videoResource, videoStartTimestamp: videoStartTimestamp, markup: markup, mapResourceToAvatarSizes: { resource, representations in
return mapResourceToAvatarSizes(postbox: account.postbox, resource: resource, representations: representations)
})
}
} else if case .custom = mode {
return context.engine.contacts.updateContactPhoto(peerId: peerId, resource: photoResource, videoResource: videoResource, videoStartTimestamp: videoStartTimestamp, markup: markup, mode: .custom, mapResourceToAvatarSizes: { resource, representations in
return mapResourceToAvatarSizes(postbox: account.postbox, resource: resource, representations: representations)
})
} else if case .suggest = mode {
return context.engine.contacts.updateContactPhoto(peerId: peerId, resource: photoResource, videoResource: videoResource, videoStartTimestamp: videoStartTimestamp, markup: markup, mode: .suggest, mapResourceToAvatarSizes: { resource, representations in
return mapResourceToAvatarSizes(postbox: account.postbox, resource: resource, representations: representations)
})
} else {
return context.engine.peers.updatePeerPhoto(peerId: peerId, photo: context.engine.peers.uploadedPeerPhoto(resource: photoResource), video: videoResource.flatMap { context.engine.peers.uploadedPeerVideo(resource: $0) |> map(Optional.init) }, videoStartTimestamp: videoStartTimestamp, markup: markup, mapResourceToAvatarSizes: { resource, representations in
return mapResourceToAvatarSizes(postbox: account.postbox, resource: resource, representations: representations)
})
}
}
|> deliverOnMainQueue).startStrict(next: { [weak self] result in
guard let strongSelf = self else {
return
}
switch result {
case .complete:
strongSelf.controllerNode.state = strongSelf.controllerNode.state.withUpdatingAvatar(nil).withAvatarUploadProgress(nil)
case let .progress(value):
strongSelf.controllerNode.state = strongSelf.controllerNode.state.withAvatarUploadProgress(.value(CGFloat(0.45 + value * 0.55)))
}
if let (layout, navigationHeight) = strongSelf.controllerNode.validLayout {
strongSelf.controllerNode.containerLayoutUpdated(layout: layout, navigationHeight: navigationHeight, transition: .immediate, additive: false)
}
if case .complete = result {
dismissStatus?()
let _ = (strongSelf.context.engine.data.get(TelegramEngine.EngineData.Item.Peer.Peer(id: strongSelf.peerId))
|> deliverOnMainQueue).startStandalone(next: { [weak self] peer in
if let strongSelf = self, let peer {
switch mode {
case .fallback:
(strongSelf.parentController?.topViewController as? ViewController)?.present(UndoOverlayController(presentationData: strongSelf.presentationData, content: .image(image: image, title: nil, text: strongSelf.presentationData.strings.Privacy_ProfilePhoto_PublicVideoSuccess, round: true, undoText: nil), elevatedLayout: false, animateInAsReplacement: true, action: { _ in return false }), in: .current)
case .custom:
strongSelf.present(UndoOverlayController(presentationData: strongSelf.presentationData, content: .invitedToVoiceChat(context: strongSelf.context, peer: peer, title: nil, text: strongSelf.presentationData.strings.UserInfo_SetCustomPhoto_SuccessVideoText(peer.compactDisplayTitle).string, action: nil, duration: 5), elevatedLayout: false, animateInAsReplacement: true, action: { _ in return false }), in: .current)
let _ = (strongSelf.context.peerChannelMemberCategoriesContextsManager.profilePhotos(postbox: strongSelf.context.account.postbox, network: strongSelf.context.account.network, peerId: strongSelf.peerId, fetch: peerInfoProfilePhotos(context: strongSelf.context, peerId: strongSelf.peerId)) |> ignoreValues).startStandalone()
case .suggest:
if let navigationController = (strongSelf.navigationController as? NavigationController) {
strongSelf.context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: strongSelf.context, chatLocation: .peer(peer), keepStack: .default, completion: { _ in
}))
}
case .accept:
(strongSelf.parentController?.topViewController as? ViewController)?.present(UndoOverlayController(presentationData: strongSelf.presentationData, content: .image(image: image, title: strongSelf.presentationData.strings.Conversation_SuggestedVideoSuccess, text: strongSelf.presentationData.strings.Conversation_SuggestedVideoSuccessText, round: true, undoText: nil), elevatedLayout: false, animateInAsReplacement: true, action: { [weak self] action in
if case .info = action {
self?.parentController?.openSettings()
}
return false
}), in: .current)
default:
break
}
}
})
}
}))
}
}

View File

@ -176,12 +176,12 @@ public final class PeerInfoGiftsPaneNode: ASDisplayNode, PeerInfoPaneNode, UIScr
switch product.gift {
case let .generic(gift):
if let availability = gift.availability {
ribbonText = params.presentationData.strings.PeerInfo_Gifts_OneOf(compactNumericCountString(Int(availability.total))).string
ribbonText = params.presentationData.strings.PeerInfo_Gifts_OneOf(compactNumericCountString(Int(availability.total), decimalSeparator: params.presentationData.dateTimeFormat.decimalSeparator)).string
} else {
ribbonText = nil
}
case let .unique(gift):
ribbonText = params.presentationData.strings.PeerInfo_Gifts_OneOf(compactNumericCountString(Int(gift.availability.total))).string
ribbonText = params.presentationData.strings.PeerInfo_Gifts_OneOf(compactNumericCountString(Int(gift.availability.total), decimalSeparator: params.presentationData.dateTimeFormat.decimalSeparator)).string
for attribute in gift.attributes {
if case let .backdrop(_, innerColor, outerColor, _, _, _) = attribute {
ribbonColor = .custom(outerColor, innerColor)

File diff suppressed because one or more lines are too long

View File

@ -3206,7 +3206,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
}
strongSelf.selectPollOptionFeedback?.success()
strongSelf.chatDisplayNode.animateQuizCorrectOptionSelected()
strongSelf.chatDisplayNode.playConfettiAnimation()
} else {
var found = false
strongSelf.chatDisplayNode.historyNode.forEachVisibleItemNode { itemNode in
@ -3608,7 +3608,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
}, displayDiceTooltip: { [weak self] dice in
self?.displayDiceTooltip(dice: dice)
}, animateDiceSuccess: { [weak self] haptic, confetti in
guard let strongSelf = self else {
guard let strongSelf = self, strongSelf.isNodeLoaded else {
return
}
if strongSelf.selectPollOptionFeedback == nil {
@ -3618,7 +3618,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
strongSelf.selectPollOptionFeedback?.success()
}
if confetti {
strongSelf.chatDisplayNode.animateQuizCorrectOptionSelected()
strongSelf.chatDisplayNode.playConfettiAnimation()
}
}, displayPremiumStickerTooltip: { [weak self] file, message in
self?.displayPremiumStickerTooltip(file: file, message: message)

View File

@ -4297,7 +4297,17 @@ class ChatControllerNode: ASDisplayNode, ASScrollViewDelegate {
}
}
func animateQuizCorrectOptionSelected() {
private var previousConfettiAnimationTimestamp: Double?
func playConfettiAnimation() {
guard self.view.bounds.width > 0.0 else {
return
}
let currentTime = CACurrentMediaTime()
if let previousConfettiAnimationTimestamp = self.previousConfettiAnimationTimestamp, abs(currentTime - previousConfettiAnimationTimestamp) < 0.1 {
return
}
self.previousConfettiAnimationTimestamp = currentTime
self.view.insertSubview(ConfettiView(frame: self.view.bounds), aboveSubview: self.historyNode.view)
}

View File

@ -471,7 +471,7 @@ extension ChatControllerImpl {
}
if isBecomingTop {
self.chatDisplayNode.animateQuizCorrectOptionSelected()
self.chatDisplayNode.playConfettiAnimation()
}
if let itemNode, let targetView = itemNode.targetReactionView(value: .stars), self.context.sharedContext.energyUsageSettings.fullTranslucency {