mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-06-16 05:55:20 +00:00
Various fixes
This commit is contained in:
parent
45fa1b5ddb
commit
3bf092aff8
@ -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?";
|
||||
|
@ -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),
|
||||
|
@ -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 {
|
||||
|
@ -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()
|
||||
|
@ -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"
|
||||
|
@ -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 {
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
)
|
||||
),
|
||||
|
@ -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 {
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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 {
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
@ -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
@ -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)
|
||||
|
@ -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)
|
||||
}
|
||||
|
||||
|
@ -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 {
|
||||
|
Loading…
x
Reference in New Issue
Block a user