mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-08-08 08:31:13 +00:00
Update API [skip ci]
This commit is contained in:
parent
d64208df43
commit
e3ee1dde7e
@ -13469,15 +13469,21 @@ Sorry for the inconvenience.";
|
||||
"Gift.View.Status.NonUnique" = "Non-Unique";
|
||||
"Gift.View.Status.Upgrade" = "upgrade";
|
||||
"Gift.View.DisplayedInfoHide" = "The gift is visible on your Page. [Hide >]()";
|
||||
"Gift.View.HiddenInfoShow" = "This gift is hidden. Only you can see it. [Show >]()";
|
||||
|
||||
"Gift.Upgrade.Title" = "Upgrade Gift";
|
||||
"Gift.Upgrade.IncludeTitle" = "Make Unique";
|
||||
"Gift.Upgrade.Description" = "Turn your gift into a unique collectible that you can transfer or auction.";
|
||||
"Gift.Upgrade.IncludeDescription" = "Let %@ turn your gift into a unique collectible.";
|
||||
"Gift.Upgrade.Unique.Title" = "Unique";
|
||||
"Gift.Upgrade.Unique.Description" = "Get a unique number, model backdrop and and symbol for your gift.";
|
||||
"Gift.Upgrade.Unique.Description" = "Get a unique number, model, backdrop, and symbol for your gift.";
|
||||
"Gift.Upgrade.Unique.IncludeDescription" = "The recipient will get a unique number, model, backdrop, and symbol for the gift.";
|
||||
"Gift.Upgrade.Transferable.Title" = "Transferable";
|
||||
"Gift.Upgrade.Transferable.Description" = "Send your upgraded gift to any of your friends on Telegram.";
|
||||
"Gift.Upgrade.Transferable.IncludeDescription" = "The recipient will be able to send the gift to anyone Telegram.";
|
||||
"Gift.Upgrade.Tradable.Title" = "Tradable";
|
||||
"Gift.Upgrade.Tradable.Description" = "Sell or auction your gift on third-party NFT marketplaces.";
|
||||
"Gift.Upgrade.Tradable.IncludeDescription" = "The recipient will be able to auction the gift on third-party NFT marketplaces.";
|
||||
"Gift.Upgrade.Soon" = "SOON";
|
||||
"Gift.Upgrade.AddName" = "Add sender's name";
|
||||
"Gift.Upgrade.AddNameAndComment" = "Add sender's name and comment";
|
||||
@ -13525,6 +13531,7 @@ Sorry for the inconvenience.";
|
||||
"Gift.Transfer.Confirmation.Transfer" = "Transfer for";
|
||||
"Gift.Transfer.Confirmation.TransferFree" = "Transfer";
|
||||
|
||||
"Gift.View.UpgradeForFree" = "Upgrade for Free";
|
||||
"Gift.View.KeepUpgradeOrConvertDescription" = "You can keep this gift, upgrade it, or sell it for %@. [More About Stars >]()";
|
||||
|
||||
"PeerInfo.VerificationInfo.Bot" = "This bot is verified as official by the representatives of Telegram.";
|
||||
@ -13537,8 +13544,21 @@ Sorry for the inconvenience.";
|
||||
"Gift.Send.Upgrade" = "Make Unique for %@";
|
||||
"Gift.Send.Upgrade.Info" = "Enable this to let %1$@ turn your gift into a unique collectible. [Learn More >]()";
|
||||
|
||||
"Notification.StarGift.Unpack" = "Unpack";
|
||||
|
||||
"Notification.StarGift.Model" = "Model";
|
||||
"Notification.StarGift.Backdrop" = "Backdrop";
|
||||
"Notification.StarGift.Symbol" = "Symbol";
|
||||
|
||||
"Notification.StarGift.Gift" = "gift";
|
||||
|
||||
"Notification.StarsGift.Upgrade" = "%@ turned the gift from you to a unique collectible";
|
||||
"Notification.StarsGift.UpgradeYou" = "You turned the gift from %@ to a unique collectible";
|
||||
|
||||
"Notification.StarsGift.Transfer" = "%@ transferred you a unique collectible";
|
||||
"Notification.StarsGift.TransferYou" = "You transferred a unique collectible";
|
||||
|
||||
"Notification.StarGift.Subtitle.Refunded" = "This gift cannot be converted to Stars because the payment related to it was refunded.";
|
||||
"Notification.StarGift.Subtitle.Downgraded" = "This gift was downgraded because a request to refund the payment related to this gift was made, and the money was returned.";
|
||||
|
||||
"Gift.View.KeepOrUpgradeDescription" = "You can keep this gift or upgrade it.";
|
||||
|
@ -3107,7 +3107,7 @@ public class ChatListItemNode: ItemListRevealOptionsItemNode {
|
||||
|
||||
var titleLeftOffset: CGFloat = 0.0
|
||||
if let currentVerifiedIconContent {
|
||||
if titleLeftOffset.isZero, currentVerifiedIconContent != .none {
|
||||
if titleLeftOffset.isZero, case .animation = currentVerifiedIconContent {
|
||||
titleLeftOffset += 20.0
|
||||
}
|
||||
|
||||
@ -3127,10 +3127,6 @@ public class ChatListItemNode: ItemListRevealOptionsItemNode {
|
||||
}
|
||||
|
||||
if let currentCredibilityIconContent {
|
||||
if titleLeftOffset.isZero, case .verified = currentCredibilityIconContent {
|
||||
titleLeftOffset += 20.0
|
||||
}
|
||||
|
||||
if titleIconsWidth.isZero {
|
||||
titleIconsWidth += 4.0
|
||||
} else {
|
||||
@ -4500,11 +4496,8 @@ public class ChatListItemNode: ItemListRevealOptionsItemNode {
|
||||
)
|
||||
strongSelf.credibilityIconComponent = credibilityIconComponent
|
||||
|
||||
var iconOrigin: CGFloat = nextTitleIconOrigin
|
||||
let iconOrigin: CGFloat = nextTitleIconOrigin
|
||||
let containerSize = CGSize(width: 20.0, height: 20.0)
|
||||
if case .verified = currentCredibilityIconContent {
|
||||
iconOrigin = contentRect.origin.x
|
||||
}
|
||||
let iconSize = credibilityIconView.update(
|
||||
transition: .immediate,
|
||||
component: AnyComponent(credibilityIconComponent),
|
||||
@ -4512,10 +4505,7 @@ public class ChatListItemNode: ItemListRevealOptionsItemNode {
|
||||
containerSize: containerSize
|
||||
)
|
||||
transition.updateFrame(view: credibilityIconView, frame: CGRect(origin: CGPoint(x: iconOrigin, y: floorToScreenPixels(titleFrame.maxY - lastLineRect.height * 0.5 - iconSize.height / 2.0) - UIScreenPixel), size: iconSize))
|
||||
if case .verified = currentCredibilityIconContent {
|
||||
} else {
|
||||
nextTitleIconOrigin += credibilityIconView.bounds.width + 4.0
|
||||
}
|
||||
nextTitleIconOrigin += credibilityIconView.bounds.width + 4.0
|
||||
} else if let credibilityIconView = strongSelf.credibilityIconView {
|
||||
strongSelf.credibilityIconView = nil
|
||||
credibilityIconView.removeFromSuperview()
|
||||
@ -4541,7 +4531,12 @@ public class ChatListItemNode: ItemListRevealOptionsItemNode {
|
||||
)
|
||||
strongSelf.verifiedIconComponent = verifiedIconComponent
|
||||
|
||||
let iconOrigin = contentRect.origin.x
|
||||
let iconOrigin: CGFloat
|
||||
if case .animation = currentVerifiedIconContent {
|
||||
iconOrigin = contentRect.origin.x
|
||||
} else {
|
||||
iconOrigin = nextTitleIconOrigin
|
||||
}
|
||||
let containerSize = CGSize(width: 16.0, height: 16.0)
|
||||
|
||||
let iconSize = verifiedIconView.update(
|
||||
|
@ -582,77 +582,6 @@ private func makeLayerSubtreeSnapshot(layer: CALayer) -> CALayer? {
|
||||
view.cornerRadius = layer.cornerRadius
|
||||
view.backgroundColor = layer.backgroundColor
|
||||
view.layerTintColor = layer.layerTintColor
|
||||
|
||||
/*
|
||||
open var path: CGPath?
|
||||
|
||||
|
||||
/* The color to fill the path, or nil for no fill. Defaults to opaque
|
||||
* black. Animatable. */
|
||||
|
||||
open var fillColor: CGColor?
|
||||
|
||||
|
||||
/* The fill rule used when filling the path. Options are `non-zero' and
|
||||
* `even-odd'. Defaults to `non-zero'. */
|
||||
|
||||
open var fillRule: CAShapeLayerFillRule
|
||||
|
||||
|
||||
/* The color to fill the path's stroked outline, or nil for no stroking.
|
||||
* Defaults to nil. Animatable. */
|
||||
|
||||
open var strokeColor: CGColor?
|
||||
|
||||
|
||||
/* These values define the subregion of the path used to draw the
|
||||
* stroked outline. The values must be in the range [0,1] with zero
|
||||
* representing the start of the path and one the end. Values in
|
||||
* between zero and one are interpolated linearly along the path
|
||||
* length. strokeStart defaults to zero and strokeEnd to one. Both are
|
||||
* animatable. */
|
||||
|
||||
open var strokeStart: CGFloat
|
||||
|
||||
open var strokeEnd: CGFloat
|
||||
|
||||
|
||||
/* The line width used when stroking the path. Defaults to one.
|
||||
* Animatable. */
|
||||
|
||||
open var lineWidth: CGFloat
|
||||
|
||||
|
||||
/* The miter limit used when stroking the path. Defaults to ten.
|
||||
* Animatable. */
|
||||
|
||||
open var miterLimit: CGFloat
|
||||
|
||||
|
||||
/* The cap style used when stroking the path. Options are `butt', `round'
|
||||
* and `square'. Defaults to `butt'. */
|
||||
|
||||
open var lineCap: CAShapeLayerLineCap
|
||||
|
||||
|
||||
/* The join style used when stroking the path. Options are `miter', `round'
|
||||
* and `bevel'. Defaults to `miter'. */
|
||||
|
||||
open var lineJoin: CAShapeLayerLineJoin
|
||||
|
||||
|
||||
/* The phase of the dashing pattern applied when creating the stroke.
|
||||
* Defaults to zero. Animatable. */
|
||||
|
||||
open var lineDashPhase: CGFloat
|
||||
|
||||
|
||||
/* The dash pattern (an array of NSNumbers) applied when creating the
|
||||
* stroked version of the path. Defaults to nil. */
|
||||
|
||||
open var lineDashPattern: [NSNumber]?
|
||||
*/
|
||||
|
||||
view.path = layer.path
|
||||
view.fillColor = layer.fillColor
|
||||
view.fillRule = layer.fillRule
|
||||
@ -666,6 +595,40 @@ private func makeLayerSubtreeSnapshot(layer: CALayer) -> CALayer? {
|
||||
view.lineDashPhase = layer.lineDashPhase
|
||||
view.lineDashPattern = layer.lineDashPattern
|
||||
|
||||
if let sublayers = layer.sublayers {
|
||||
for sublayer in sublayers {
|
||||
let subtree = makeLayerSubtreeSnapshot(layer: sublayer)
|
||||
if let subtree = subtree {
|
||||
subtree.transform = sublayer.transform
|
||||
subtree.position = sublayer.position
|
||||
subtree.bounds = sublayer.bounds
|
||||
subtree.anchorPoint = sublayer.anchorPoint
|
||||
view.addSublayer(subtree)
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
return view
|
||||
} else if let layer = layer as? CAGradientLayer {
|
||||
let view = CAGradientLayer()
|
||||
view.isHidden = layer.isHidden
|
||||
view.opacity = layer.opacity
|
||||
view.contents = layer.contents
|
||||
view.contentsRect = layer.contentsRect
|
||||
view.contentsScale = layer.contentsScale
|
||||
view.contentsCenter = layer.contentsCenter
|
||||
view.contentsGravity = layer.contentsGravity
|
||||
view.masksToBounds = layer.masksToBounds
|
||||
view.cornerRadius = layer.cornerRadius
|
||||
view.backgroundColor = layer.backgroundColor
|
||||
view.layerTintColor = layer.layerTintColor
|
||||
view.colors = layer.colors
|
||||
view.locations = layer.locations
|
||||
view.startPoint = layer.startPoint
|
||||
view.endPoint = layer.endPoint
|
||||
view.type = layer.type
|
||||
|
||||
if let sublayers = layer.sublayers {
|
||||
for sublayer in sublayers {
|
||||
let subtree = makeLayerSubtreeSnapshot(layer: sublayer)
|
||||
|
@ -47,6 +47,7 @@ final class DrawingMetalView: MTKView {
|
||||
super.init(frame: CGRect(origin: .zero, size: size), device: device)
|
||||
|
||||
self.drawableSize = self.size
|
||||
self.colorPixelFormat = .bgra8Unorm
|
||||
self.autoResizeDrawable = false
|
||||
self.isOpaque = false
|
||||
self.contentScaleFactor = 1.0
|
||||
@ -123,7 +124,7 @@ final class DrawingMetalView: MTKView {
|
||||
let pipelineDescription = MTLRenderPipelineDescriptor()
|
||||
pipelineDescription.vertexFunction = vertexFunction
|
||||
pipelineDescription.fragmentFunction = fragmentFunction
|
||||
pipelineDescription.colorAttachments[0].pixelFormat = colorPixelFormat
|
||||
pipelineDescription.colorAttachments[0].pixelFormat = self.colorPixelFormat
|
||||
|
||||
do {
|
||||
self.pipelineState = try self.device?.makeRenderPipelineState(descriptor: pipelineDescription)
|
||||
@ -250,6 +251,7 @@ private class Drawable {
|
||||
attachment?.texture = self.texture?.texture
|
||||
attachment?.loadAction = .load
|
||||
attachment?.storeAction = .store
|
||||
attachment?.clearColor = MTLClearColor(red: 0, green: 0, blue: 0, alpha: 0)
|
||||
|
||||
self.updateBuffer(with: size)
|
||||
}
|
||||
@ -288,7 +290,6 @@ private class Drawable {
|
||||
return commandBuffer.makeRenderCommandEncoder(descriptor: renderPassDescriptor)
|
||||
}
|
||||
|
||||
|
||||
internal func commit(wait: Bool = false) {
|
||||
self.commandBuffer?.commit()
|
||||
if wait {
|
||||
@ -673,9 +674,9 @@ final class Texture {
|
||||
origin: MTLOrigin(x: 0, y: 0, z: 0),
|
||||
size: MTLSize(width: self.width, height: self.height, depth: 1)
|
||||
)
|
||||
let data = Data(capacity: Int(self.bytesPerRow * self.height))
|
||||
if let bytes = data.withUnsafeBytes({ $0.baseAddress }) {
|
||||
self.texture.replace(region: region, mipmapLevel: 0, withBytes: bytes, bytesPerRow: self.bytesPerRow)
|
||||
let zeroData = [UInt8](repeating: 0, count: self.bytesPerRow * self.height)
|
||||
zeroData.withUnsafeBytes { bytes in
|
||||
self.texture.replace(region: region, mipmapLevel: 0, withBytes: bytes.baseAddress!, bytesPerRow: self.bytesPerRow)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -583,7 +583,7 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = {
|
||||
dict[-1434950843] = { return Api.MessageAction.parse_messageActionSetChatTheme($0) }
|
||||
dict[1348510708] = { return Api.MessageAction.parse_messageActionSetChatWallPaper($0) }
|
||||
dict[1007897979] = { return Api.MessageAction.parse_messageActionSetMessagesTTL($0) }
|
||||
dict[1785072017] = { return Api.MessageAction.parse_messageActionStarGift($0) }
|
||||
dict[-655036249] = { return Api.MessageAction.parse_messageActionStarGift($0) }
|
||||
dict[638024601] = { return Api.MessageAction.parse_messageActionStarGiftUnique($0) }
|
||||
dict[1474192222] = { return Api.MessageAction.parse_messageActionSuggestProfilePhoto($0) }
|
||||
dict[228168278] = { return Api.MessageAction.parse_messageActionTopicCreate($0) }
|
||||
|
@ -373,7 +373,7 @@ public extension Api {
|
||||
case messageActionSetChatTheme(emoticon: String)
|
||||
case messageActionSetChatWallPaper(flags: Int32, wallpaper: Api.WallPaper)
|
||||
case messageActionSetMessagesTTL(flags: Int32, period: Int32, autoSettingFrom: Int64?)
|
||||
case messageActionStarGift(flags: Int32, gift: Api.StarGift, message: Api.TextWithEntities?, convertStars: Int64?, upgradeStars: Int64?)
|
||||
case messageActionStarGift(flags: Int32, gift: Api.StarGift, message: Api.TextWithEntities?, convertStars: Int64?, upgradeMsgId: Int32?, upgradeStars: Int64?)
|
||||
case messageActionStarGiftUnique(flags: Int32, gift: Api.StarGift, canExportAt: Int32?, transferStars: Int64?)
|
||||
case messageActionSuggestProfilePhoto(photo: Api.Photo)
|
||||
case messageActionTopicCreate(flags: Int32, title: String, iconColor: Int32, iconEmojiId: Int64?)
|
||||
@ -720,14 +720,15 @@ public extension Api {
|
||||
serializeInt32(period, buffer: buffer, boxed: false)
|
||||
if Int(flags) & Int(1 << 0) != 0 {serializeInt64(autoSettingFrom!, buffer: buffer, boxed: false)}
|
||||
break
|
||||
case .messageActionStarGift(let flags, let gift, let message, let convertStars, let upgradeStars):
|
||||
case .messageActionStarGift(let flags, let gift, let message, let convertStars, let upgradeMsgId, let upgradeStars):
|
||||
if boxed {
|
||||
buffer.appendInt32(1785072017)
|
||||
buffer.appendInt32(-655036249)
|
||||
}
|
||||
serializeInt32(flags, buffer: buffer, boxed: false)
|
||||
gift.serialize(buffer, true)
|
||||
if Int(flags) & Int(1 << 1) != 0 {message!.serialize(buffer, true)}
|
||||
if Int(flags) & Int(1 << 4) != 0 {serializeInt64(convertStars!, buffer: buffer, boxed: false)}
|
||||
if Int(flags) & Int(1 << 5) != 0 {serializeInt32(upgradeMsgId!, buffer: buffer, boxed: false)}
|
||||
if Int(flags) & Int(1 << 8) != 0 {serializeInt64(upgradeStars!, buffer: buffer, boxed: false)}
|
||||
break
|
||||
case .messageActionStarGiftUnique(let flags, let gift, let canExportAt, let transferStars):
|
||||
@ -864,8 +865,8 @@ public extension Api {
|
||||
return ("messageActionSetChatWallPaper", [("flags", flags as Any), ("wallpaper", wallpaper as Any)])
|
||||
case .messageActionSetMessagesTTL(let flags, let period, let autoSettingFrom):
|
||||
return ("messageActionSetMessagesTTL", [("flags", flags as Any), ("period", period as Any), ("autoSettingFrom", autoSettingFrom as Any)])
|
||||
case .messageActionStarGift(let flags, let gift, let message, let convertStars, let upgradeStars):
|
||||
return ("messageActionStarGift", [("flags", flags as Any), ("gift", gift as Any), ("message", message as Any), ("convertStars", convertStars as Any), ("upgradeStars", upgradeStars as Any)])
|
||||
case .messageActionStarGift(let flags, let gift, let message, let convertStars, let upgradeMsgId, let upgradeStars):
|
||||
return ("messageActionStarGift", [("flags", flags as Any), ("gift", gift as Any), ("message", message as Any), ("convertStars", convertStars as Any), ("upgradeMsgId", upgradeMsgId as Any), ("upgradeStars", upgradeStars as Any)])
|
||||
case .messageActionStarGiftUnique(let flags, let gift, let canExportAt, let transferStars):
|
||||
return ("messageActionStarGiftUnique", [("flags", flags as Any), ("gift", gift as Any), ("canExportAt", canExportAt as Any), ("transferStars", transferStars as Any)])
|
||||
case .messageActionSuggestProfilePhoto(let photo):
|
||||
@ -1528,15 +1529,18 @@ public extension Api {
|
||||
} }
|
||||
var _4: Int64?
|
||||
if Int(_1!) & Int(1 << 4) != 0 {_4 = reader.readInt64() }
|
||||
var _5: Int64?
|
||||
if Int(_1!) & Int(1 << 8) != 0 {_5 = reader.readInt64() }
|
||||
var _5: Int32?
|
||||
if Int(_1!) & Int(1 << 5) != 0 {_5 = reader.readInt32() }
|
||||
var _6: Int64?
|
||||
if Int(_1!) & Int(1 << 8) != 0 {_6 = reader.readInt64() }
|
||||
let _c1 = _1 != nil
|
||||
let _c2 = _2 != nil
|
||||
let _c3 = (Int(_1!) & Int(1 << 1) == 0) || _3 != nil
|
||||
let _c4 = (Int(_1!) & Int(1 << 4) == 0) || _4 != nil
|
||||
let _c5 = (Int(_1!) & Int(1 << 8) == 0) || _5 != nil
|
||||
if _c1 && _c2 && _c3 && _c4 && _c5 {
|
||||
return Api.MessageAction.messageActionStarGift(flags: _1!, gift: _2!, message: _3, convertStars: _4, upgradeStars: _5)
|
||||
let _c5 = (Int(_1!) & Int(1 << 5) == 0) || _5 != nil
|
||||
let _c6 = (Int(_1!) & Int(1 << 8) == 0) || _6 != nil
|
||||
if _c1 && _c2 && _c3 && _c4 && _c5 && _c6 {
|
||||
return Api.MessageAction.messageActionStarGift(flags: _1!, gift: _2!, message: _3, convertStars: _4, upgradeMsgId: _5, upgradeStars: _6)
|
||||
}
|
||||
else {
|
||||
return nil
|
||||
|
@ -9463,6 +9463,25 @@ public extension Api.functions.payments {
|
||||
})
|
||||
}
|
||||
}
|
||||
public extension Api.functions.payments {
|
||||
static func getUserStarGift(msgId: [Int32]) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.payments.UserStarGifts>) {
|
||||
let buffer = Buffer()
|
||||
buffer.appendInt32(-1258101595)
|
||||
buffer.appendInt32(481674261)
|
||||
buffer.appendInt32(Int32(msgId.count))
|
||||
for item in msgId {
|
||||
serializeInt32(item, buffer: buffer, boxed: false)
|
||||
}
|
||||
return (FunctionDescription(name: "payments.getUserStarGift", parameters: [("msgId", String(describing: msgId))]), buffer, DeserializeFunctionResponse { (buffer: Buffer) -> Api.payments.UserStarGifts? in
|
||||
let reader = BufferReader(buffer)
|
||||
var result: Api.payments.UserStarGifts?
|
||||
if let signature = reader.readInt32() {
|
||||
result = Api.parse(reader, signature: signature) as? Api.payments.UserStarGifts
|
||||
}
|
||||
return result
|
||||
})
|
||||
}
|
||||
}
|
||||
public extension Api.functions.payments {
|
||||
static func getUserStarGifts(userId: Api.InputUser, offset: String, limit: Int32) -> (FunctionDescription, Buffer, DeserializeFunctionResponse<Api.payments.UserStarGifts>) {
|
||||
let buffer = Buffer()
|
||||
|
@ -132,7 +132,6 @@ enum AccountStateMutationOperation {
|
||||
case UpdateStarsBalance(peerId: PeerId, balance: Api.StarsAmount)
|
||||
case UpdateStarsRevenueStatus(peerId: PeerId, status: StarsRevenueStats.Balances)
|
||||
case UpdateStarsReactionsAreAnonymousByDefault(isAnonymous: Bool)
|
||||
case UpdateUpgradedStarGift(from: Api.UserStarGift, to: Api.UserStarGift)
|
||||
}
|
||||
|
||||
struct HoleFromPreviousState {
|
||||
@ -702,14 +701,10 @@ struct AccountMutableState {
|
||||
mutating func updateStarsReactionsAreAnonymousByDefault(isAnonymous: Bool) {
|
||||
self.addOperation(.UpdateStarsReactionsAreAnonymousByDefault(isAnonymous: isAnonymous))
|
||||
}
|
||||
|
||||
mutating func updateUpgradedStarGift(from: Api.UserStarGift, to: Api.UserStarGift) {
|
||||
self.addOperation(.UpdateUpgradedStarGift(from: from, to: to))
|
||||
}
|
||||
|
||||
mutating func addOperation(_ operation: AccountStateMutationOperation) {
|
||||
switch operation {
|
||||
case .DeleteMessages, .DeleteMessagesWithGlobalIds, .EditMessage, .UpdateMessagePoll, .UpdateMessageReactions, .UpdateMedia, .ReadOutbox, .ReadGroupFeedInbox, .MergePeerPresences, .UpdateSecretChat, .AddSecretMessages, .ReadSecretOutbox, .AddPeerInputActivity, .UpdateCachedPeerData, .UpdatePinnedItemIds, .UpdatePinnedSavedItemIds, .UpdatePinnedTopic, .UpdatePinnedTopicOrder, .ReadMessageContents, .UpdateMessageImpressionCount, .UpdateMessageForwardsCount, .UpdateInstalledStickerPacks, .UpdateRecentGifs, .UpdateChatInputState, .UpdateCall, .AddCallSignalingData, .UpdateLangPack, .UpdateMinAvailableMessage, .UpdatePeerChatUnreadMark, .UpdateIsContact, .UpdatePeerChatInclusion, .UpdatePeersNearby, .UpdateTheme, .UpdateWallpaper, .SyncChatListFilters, .UpdateChatListFilterOrder, .UpdateChatListFilter, .UpdateReadThread, .UpdateGroupCallParticipants, .UpdateGroupCall, .UpdateMessagesPinned, .UpdateAutoremoveTimeout, .UpdateAttachMenuBots, .UpdateAudioTranscription, .UpdateConfig, .UpdateExtendedMedia, .ResetForumTopic, .UpdateStory, .UpdateReadStories, .UpdateStoryStealthMode, .UpdateStorySentReaction, .UpdateNewAuthorization, .UpdateRevenueBalances, .UpdateStarsBalance, .UpdateStarsRevenueStatus, .UpdateStarsReactionsAreAnonymousByDefault, .UpdateUpgradedStarGift:
|
||||
case .DeleteMessages, .DeleteMessagesWithGlobalIds, .EditMessage, .UpdateMessagePoll, .UpdateMessageReactions, .UpdateMedia, .ReadOutbox, .ReadGroupFeedInbox, .MergePeerPresences, .UpdateSecretChat, .AddSecretMessages, .ReadSecretOutbox, .AddPeerInputActivity, .UpdateCachedPeerData, .UpdatePinnedItemIds, .UpdatePinnedSavedItemIds, .UpdatePinnedTopic, .UpdatePinnedTopicOrder, .ReadMessageContents, .UpdateMessageImpressionCount, .UpdateMessageForwardsCount, .UpdateInstalledStickerPacks, .UpdateRecentGifs, .UpdateChatInputState, .UpdateCall, .AddCallSignalingData, .UpdateLangPack, .UpdateMinAvailableMessage, .UpdatePeerChatUnreadMark, .UpdateIsContact, .UpdatePeerChatInclusion, .UpdatePeersNearby, .UpdateTheme, .UpdateWallpaper, .SyncChatListFilters, .UpdateChatListFilterOrder, .UpdateChatListFilter, .UpdateReadThread, .UpdateGroupCallParticipants, .UpdateGroupCall, .UpdateMessagesPinned, .UpdateAutoremoveTimeout, .UpdateAttachMenuBots, .UpdateAudioTranscription, .UpdateConfig, .UpdateExtendedMedia, .ResetForumTopic, .UpdateStory, .UpdateReadStories, .UpdateStoryStealthMode, .UpdateStorySentReaction, .UpdateNewAuthorization, .UpdateRevenueBalances, .UpdateStarsBalance, .UpdateStarsRevenueStatus, .UpdateStarsReactionsAreAnonymousByDefault:
|
||||
break
|
||||
case let .AddMessages(messages, location):
|
||||
for message in messages {
|
||||
@ -856,7 +851,6 @@ struct AccountReplayedFinalState {
|
||||
let updatedRevenueBalances: [PeerId: RevenueStats.Balances]
|
||||
let updatedStarsBalance: [PeerId: StarsAmount]
|
||||
let updatedStarsRevenueStatus: [PeerId: StarsRevenueStats.Balances]
|
||||
let updatedUpgradedStarGifts:[(ProfileGiftsContext.State.StarGift, ProfileGiftsContext.State.StarGift)]
|
||||
let sentScheduledMessageIds: Set<MessageId>
|
||||
}
|
||||
|
||||
@ -888,13 +882,12 @@ struct AccountFinalStateEvents {
|
||||
let updatedRevenueBalances: [PeerId: RevenueStats.Balances]
|
||||
let updatedStarsBalance: [PeerId: StarsAmount]
|
||||
let updatedStarsRevenueStatus: [PeerId: StarsRevenueStats.Balances]
|
||||
let updatedUpgradedStarGifts: [(ProfileGiftsContext.State.StarGift, ProfileGiftsContext.State.StarGift)]
|
||||
|
||||
var isEmpty: Bool {
|
||||
return self.addedIncomingMessageIds.isEmpty && self.addedReactionEvents.isEmpty && self.wasScheduledMessageIds.isEmpty && self.deletedMessageIds.isEmpty && self.sentScheduledMessageIds.isEmpty && self.updatedTypingActivities.isEmpty && self.updatedWebpages.isEmpty && self.updatedCalls.isEmpty && self.addedCallSignalingData.isEmpty && self.updatedGroupCallParticipants.isEmpty && self.storyUpdates.isEmpty && self.updatedPeersNearby?.isEmpty ?? true && self.isContactUpdates.isEmpty && self.displayAlerts.isEmpty && self.dismissBotWebViews.isEmpty && self.delayNotificatonsUntil == nil && self.updatedMaxMessageId == nil && self.updatedQts == nil && self.externallyUpdatedPeerId.isEmpty && !authorizationListUpdated && self.updatedIncomingThreadReadStates.isEmpty && self.updatedOutgoingThreadReadStates.isEmpty && !self.updateConfig && !self.isPremiumUpdated && self.updatedRevenueBalances.isEmpty && self.updatedStarsBalance.isEmpty && self.updatedStarsRevenueStatus.isEmpty && self.updatedUpgradedStarGifts.isEmpty
|
||||
return self.addedIncomingMessageIds.isEmpty && self.addedReactionEvents.isEmpty && self.wasScheduledMessageIds.isEmpty && self.deletedMessageIds.isEmpty && self.sentScheduledMessageIds.isEmpty && self.updatedTypingActivities.isEmpty && self.updatedWebpages.isEmpty && self.updatedCalls.isEmpty && self.addedCallSignalingData.isEmpty && self.updatedGroupCallParticipants.isEmpty && self.storyUpdates.isEmpty && self.updatedPeersNearby?.isEmpty ?? true && self.isContactUpdates.isEmpty && self.displayAlerts.isEmpty && self.dismissBotWebViews.isEmpty && self.delayNotificatonsUntil == nil && self.updatedMaxMessageId == nil && self.updatedQts == nil && self.externallyUpdatedPeerId.isEmpty && !authorizationListUpdated && self.updatedIncomingThreadReadStates.isEmpty && self.updatedOutgoingThreadReadStates.isEmpty && !self.updateConfig && !self.isPremiumUpdated && self.updatedRevenueBalances.isEmpty && self.updatedStarsBalance.isEmpty && self.updatedStarsRevenueStatus.isEmpty
|
||||
}
|
||||
|
||||
init(addedIncomingMessageIds: [MessageId] = [], addedReactionEvents: [(reactionAuthor: Peer, reaction: MessageReaction.Reaction, message: Message, timestamp: Int32)] = [], wasScheduledMessageIds: [MessageId] = [], deletedMessageIds: [DeletedMessageId] = [], updatedTypingActivities: [PeerActivitySpace: [PeerId: PeerInputActivity?]] = [:], updatedWebpages: [MediaId: TelegramMediaWebpage] = [:], updatedCalls: [Api.PhoneCall] = [], addedCallSignalingData: [(Int64, Data)] = [], updatedGroupCallParticipants: [(Int64, GroupCallParticipantsContext.Update)] = [], storyUpdates: [InternalStoryUpdate] = [], updatedPeersNearby: [PeerNearby]? = nil, isContactUpdates: [(PeerId, Bool)] = [], displayAlerts: [(text: String, isDropAuth: Bool)] = [], dismissBotWebViews: [Int64] = [], delayNotificatonsUntil: Int32? = nil, updatedMaxMessageId: Int32? = nil, updatedQts: Int32? = nil, externallyUpdatedPeerId: Set<PeerId> = Set(), authorizationListUpdated: Bool = false, updatedIncomingThreadReadStates: [MessageId: MessageId.Id] = [:], updatedOutgoingThreadReadStates: [MessageId: MessageId.Id] = [:], updateConfig: Bool = false, isPremiumUpdated: Bool = false, updatedRevenueBalances: [PeerId: RevenueStats.Balances] = [:], updatedStarsBalance: [PeerId: StarsAmount] = [:], updatedStarsRevenueStatus: [PeerId: StarsRevenueStats.Balances] = [:], sentScheduledMessageIds: Set<MessageId> = Set(), updatedUpgradedStarGifts: [(ProfileGiftsContext.State.StarGift, ProfileGiftsContext.State.StarGift)] = []) {
|
||||
init(addedIncomingMessageIds: [MessageId] = [], addedReactionEvents: [(reactionAuthor: Peer, reaction: MessageReaction.Reaction, message: Message, timestamp: Int32)] = [], wasScheduledMessageIds: [MessageId] = [], deletedMessageIds: [DeletedMessageId] = [], updatedTypingActivities: [PeerActivitySpace: [PeerId: PeerInputActivity?]] = [:], updatedWebpages: [MediaId: TelegramMediaWebpage] = [:], updatedCalls: [Api.PhoneCall] = [], addedCallSignalingData: [(Int64, Data)] = [], updatedGroupCallParticipants: [(Int64, GroupCallParticipantsContext.Update)] = [], storyUpdates: [InternalStoryUpdate] = [], updatedPeersNearby: [PeerNearby]? = nil, isContactUpdates: [(PeerId, Bool)] = [], displayAlerts: [(text: String, isDropAuth: Bool)] = [], dismissBotWebViews: [Int64] = [], delayNotificatonsUntil: Int32? = nil, updatedMaxMessageId: Int32? = nil, updatedQts: Int32? = nil, externallyUpdatedPeerId: Set<PeerId> = Set(), authorizationListUpdated: Bool = false, updatedIncomingThreadReadStates: [MessageId: MessageId.Id] = [:], updatedOutgoingThreadReadStates: [MessageId: MessageId.Id] = [:], updateConfig: Bool = false, isPremiumUpdated: Bool = false, updatedRevenueBalances: [PeerId: RevenueStats.Balances] = [:], updatedStarsBalance: [PeerId: StarsAmount] = [:], updatedStarsRevenueStatus: [PeerId: StarsRevenueStats.Balances] = [:], sentScheduledMessageIds: Set<MessageId> = Set()) {
|
||||
self.addedIncomingMessageIds = addedIncomingMessageIds
|
||||
self.addedReactionEvents = addedReactionEvents
|
||||
self.wasScheduledMessageIds = wasScheduledMessageIds
|
||||
@ -921,7 +914,6 @@ struct AccountFinalStateEvents {
|
||||
self.updatedRevenueBalances = updatedRevenueBalances
|
||||
self.updatedStarsBalance = updatedStarsBalance
|
||||
self.updatedStarsRevenueStatus = updatedStarsRevenueStatus
|
||||
self.updatedUpgradedStarGifts = updatedUpgradedStarGifts
|
||||
self.sentScheduledMessageIds = sentScheduledMessageIds
|
||||
}
|
||||
|
||||
@ -952,7 +944,6 @@ struct AccountFinalStateEvents {
|
||||
self.updatedRevenueBalances = state.updatedRevenueBalances
|
||||
self.updatedStarsBalance = state.updatedStarsBalance
|
||||
self.updatedStarsRevenueStatus = state.updatedStarsRevenueStatus
|
||||
self.updatedUpgradedStarGifts = state.updatedUpgradedStarGifts
|
||||
self.sentScheduledMessageIds = state.sentScheduledMessageIds
|
||||
}
|
||||
|
||||
@ -986,6 +977,6 @@ struct AccountFinalStateEvents {
|
||||
var sentScheduledMessageIds = self.sentScheduledMessageIds
|
||||
sentScheduledMessageIds.formUnion(other.sentScheduledMessageIds)
|
||||
|
||||
return AccountFinalStateEvents(addedIncomingMessageIds: self.addedIncomingMessageIds + other.addedIncomingMessageIds, addedReactionEvents: self.addedReactionEvents + other.addedReactionEvents, wasScheduledMessageIds: self.wasScheduledMessageIds + other.wasScheduledMessageIds, deletedMessageIds: self.deletedMessageIds + other.deletedMessageIds, updatedTypingActivities: self.updatedTypingActivities, updatedWebpages: self.updatedWebpages, updatedCalls: self.updatedCalls + other.updatedCalls, addedCallSignalingData: self.addedCallSignalingData + other.addedCallSignalingData, updatedGroupCallParticipants: self.updatedGroupCallParticipants + other.updatedGroupCallParticipants, storyUpdates: self.storyUpdates + other.storyUpdates, isContactUpdates: self.isContactUpdates + other.isContactUpdates, displayAlerts: self.displayAlerts + other.displayAlerts, dismissBotWebViews: self.dismissBotWebViews + other.dismissBotWebViews, delayNotificatonsUntil: delayNotificatonsUntil, updatedMaxMessageId: updatedMaxMessageId, updatedQts: updatedQts, externallyUpdatedPeerId: externallyUpdatedPeerId, authorizationListUpdated: authorizationListUpdated, updatedIncomingThreadReadStates: self.updatedIncomingThreadReadStates.merging(other.updatedIncomingThreadReadStates, uniquingKeysWith: { lhs, _ in lhs }), updateConfig: updateConfig, isPremiumUpdated: isPremiumUpdated, updatedRevenueBalances: self.updatedRevenueBalances.merging(other.updatedRevenueBalances, uniquingKeysWith: { lhs, _ in lhs }), updatedStarsBalance: self.updatedStarsBalance.merging(other.updatedStarsBalance, uniquingKeysWith: { lhs, _ in lhs }), updatedStarsRevenueStatus: self.updatedStarsRevenueStatus.merging(other.updatedStarsRevenueStatus, uniquingKeysWith: { lhs, _ in lhs }), sentScheduledMessageIds: sentScheduledMessageIds, updatedUpgradedStarGifts: self.updatedUpgradedStarGifts + other.updatedUpgradedStarGifts)
|
||||
return AccountFinalStateEvents(addedIncomingMessageIds: self.addedIncomingMessageIds + other.addedIncomingMessageIds, addedReactionEvents: self.addedReactionEvents + other.addedReactionEvents, wasScheduledMessageIds: self.wasScheduledMessageIds + other.wasScheduledMessageIds, deletedMessageIds: self.deletedMessageIds + other.deletedMessageIds, updatedTypingActivities: self.updatedTypingActivities, updatedWebpages: self.updatedWebpages, updatedCalls: self.updatedCalls + other.updatedCalls, addedCallSignalingData: self.addedCallSignalingData + other.addedCallSignalingData, updatedGroupCallParticipants: self.updatedGroupCallParticipants + other.updatedGroupCallParticipants, storyUpdates: self.storyUpdates + other.storyUpdates, isContactUpdates: self.isContactUpdates + other.isContactUpdates, displayAlerts: self.displayAlerts + other.displayAlerts, dismissBotWebViews: self.dismissBotWebViews + other.dismissBotWebViews, delayNotificatonsUntil: delayNotificatonsUntil, updatedMaxMessageId: updatedMaxMessageId, updatedQts: updatedQts, externallyUpdatedPeerId: externallyUpdatedPeerId, authorizationListUpdated: authorizationListUpdated, updatedIncomingThreadReadStates: self.updatedIncomingThreadReadStates.merging(other.updatedIncomingThreadReadStates, uniquingKeysWith: { lhs, _ in lhs }), updateConfig: updateConfig, isPremiumUpdated: isPremiumUpdated, updatedRevenueBalances: self.updatedRevenueBalances.merging(other.updatedRevenueBalances, uniquingKeysWith: { lhs, _ in lhs }), updatedStarsBalance: self.updatedStarsBalance.merging(other.updatedStarsBalance, uniquingKeysWith: { lhs, _ in lhs }), updatedStarsRevenueStatus: self.updatedStarsRevenueStatus.merging(other.updatedStarsRevenueStatus, uniquingKeysWith: { lhs, _ in lhs }), sentScheduledMessageIds: sentScheduledMessageIds)
|
||||
}
|
||||
}
|
||||
|
@ -171,7 +171,7 @@ func telegramMediaActionFromApiAction(_ action: Api.MessageAction) -> TelegramMe
|
||||
return TelegramMediaAction(action: .paymentRefunded(peerId: peer.peerId, currency: currency, totalAmount: totalAmount, payload: payload?.makeData(), transactionId: transactionId))
|
||||
case let .messageActionPrizeStars(flags, stars, transactionId, boostPeer, giveawayMsgId):
|
||||
return TelegramMediaAction(action: .prizeStars(amount: stars, isUnclaimed: (flags & (1 << 2)) != 0, boostPeerId: boostPeer.peerId, transactionId: transactionId, giveawayMessageId: MessageId(peerId: boostPeer.peerId, namespace: Namespaces.Message.Cloud, id: giveawayMsgId)))
|
||||
case let .messageActionStarGift(flags, apiGift, message, convertStars, upgradeStars):
|
||||
case let .messageActionStarGift(flags, apiGift, message, convertStars, _, upgradeStars):
|
||||
let text: String?
|
||||
let entities: [MessageTextEntity]?
|
||||
switch message {
|
||||
@ -185,12 +185,12 @@ func telegramMediaActionFromApiAction(_ action: Api.MessageAction) -> TelegramMe
|
||||
guard let gift = StarGift(apiStarGift: apiGift) else {
|
||||
return nil
|
||||
}
|
||||
return TelegramMediaAction(action: .starGift(gift: gift, convertStars: convertStars, text: text, entities: entities, nameHidden: (flags & (1 << 0)) != 0, savedToProfile: (flags & (1 << 2)) != 0, converted: (flags & (1 << 3)) != 0, upgraded: (flags & (1 << 5)) != 0, upgradeStars: upgradeStars))
|
||||
return TelegramMediaAction(action: .starGift(gift: gift, convertStars: convertStars, text: text, entities: entities, nameHidden: (flags & (1 << 0)) != 0, savedToProfile: (flags & (1 << 2)) != 0, converted: (flags & (1 << 3)) != 0, upgraded: (flags & (1 << 5)) != 0, canUpgrade: (flags & (1 << 10)) != 0, upgradeStars: upgradeStars, isRefunded: (flags & (1 << 9)) != 0))
|
||||
case let .messageActionStarGiftUnique(flags, apiGift, canExportAt, transferStars):
|
||||
guard let gift = StarGift(apiStarGift: apiGift) else {
|
||||
return nil
|
||||
}
|
||||
return TelegramMediaAction(action: .starGiftUnique(gift: gift, isUpgrade: (flags & (1 << 0)) != 0, isTransferred: (flags & (1 << 1)) != 0, savedToProfile: (flags & (1 << 2)) != 0, canExportDate: canExportAt, transferStars: transferStars))
|
||||
return TelegramMediaAction(action: .starGiftUnique(gift: gift, isUpgrade: (flags & (1 << 0)) != 0, isTransferred: (flags & (1 << 1)) != 0, savedToProfile: (flags & (1 << 2)) != 0, canExportDate: canExportAt, transferStars: transferStars, isRefunded: (flags & (1 << 5)) != 0))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3282,7 +3282,7 @@ private func optimizedOperations(_ operations: [AccountStateMutationOperation])
|
||||
var currentAddQuickReplyMessages: OptimizeAddMessagesState?
|
||||
for operation in operations {
|
||||
switch operation {
|
||||
case .DeleteMessages, .DeleteMessagesWithGlobalIds, .EditMessage, .UpdateMessagePoll, .UpdateMessageReactions, .UpdateMedia, .MergeApiChats, .MergeApiUsers, .MergePeerPresences, .UpdatePeer, .ReadInbox, .ReadOutbox, .ReadGroupFeedInbox, .ResetReadState, .ResetIncomingReadState, .UpdatePeerChatUnreadMark, .ResetMessageTagSummary, .UpdateNotificationSettings, .UpdateGlobalNotificationSettings, .UpdateSecretChat, .AddSecretMessages, .ReadSecretOutbox, .AddPeerInputActivity, .UpdateCachedPeerData, .UpdatePinnedItemIds, .UpdatePinnedSavedItemIds, .UpdatePinnedTopic, .UpdatePinnedTopicOrder, .ReadMessageContents, .UpdateMessageImpressionCount, .UpdateMessageForwardsCount, .UpdateInstalledStickerPacks, .UpdateRecentGifs, .UpdateChatInputState, .UpdateCall, .AddCallSignalingData, .UpdateLangPack, .UpdateMinAvailableMessage, .UpdateIsContact, .UpdatePeerChatInclusion, .UpdatePeersNearby, .UpdateTheme, .SyncChatListFilters, .UpdateChatListFilter, .UpdateChatListFilterOrder, .UpdateReadThread, .UpdateMessagesPinned, .UpdateGroupCallParticipants, .UpdateGroupCall, .UpdateAutoremoveTimeout, .UpdateAttachMenuBots, .UpdateAudioTranscription, .UpdateConfig, .UpdateExtendedMedia, .ResetForumTopic, .UpdateStory, .UpdateReadStories, .UpdateStoryStealthMode, .UpdateStorySentReaction, .UpdateNewAuthorization, .UpdateWallpaper, .UpdateRevenueBalances, .UpdateStarsBalance, .UpdateStarsRevenueStatus, .UpdateStarsReactionsAreAnonymousByDefault, .UpdateUpgradedStarGift:
|
||||
case .DeleteMessages, .DeleteMessagesWithGlobalIds, .EditMessage, .UpdateMessagePoll, .UpdateMessageReactions, .UpdateMedia, .MergeApiChats, .MergeApiUsers, .MergePeerPresences, .UpdatePeer, .ReadInbox, .ReadOutbox, .ReadGroupFeedInbox, .ResetReadState, .ResetIncomingReadState, .UpdatePeerChatUnreadMark, .ResetMessageTagSummary, .UpdateNotificationSettings, .UpdateGlobalNotificationSettings, .UpdateSecretChat, .AddSecretMessages, .ReadSecretOutbox, .AddPeerInputActivity, .UpdateCachedPeerData, .UpdatePinnedItemIds, .UpdatePinnedSavedItemIds, .UpdatePinnedTopic, .UpdatePinnedTopicOrder, .ReadMessageContents, .UpdateMessageImpressionCount, .UpdateMessageForwardsCount, .UpdateInstalledStickerPacks, .UpdateRecentGifs, .UpdateChatInputState, .UpdateCall, .AddCallSignalingData, .UpdateLangPack, .UpdateMinAvailableMessage, .UpdateIsContact, .UpdatePeerChatInclusion, .UpdatePeersNearby, .UpdateTheme, .SyncChatListFilters, .UpdateChatListFilter, .UpdateChatListFilterOrder, .UpdateReadThread, .UpdateMessagesPinned, .UpdateGroupCallParticipants, .UpdateGroupCall, .UpdateAutoremoveTimeout, .UpdateAttachMenuBots, .UpdateAudioTranscription, .UpdateConfig, .UpdateExtendedMedia, .ResetForumTopic, .UpdateStory, .UpdateReadStories, .UpdateStoryStealthMode, .UpdateStorySentReaction, .UpdateNewAuthorization, .UpdateWallpaper, .UpdateRevenueBalances, .UpdateStarsBalance, .UpdateStarsRevenueStatus, .UpdateStarsReactionsAreAnonymousByDefault:
|
||||
if let currentAddMessages = currentAddMessages, !currentAddMessages.messages.isEmpty {
|
||||
result.append(.AddMessages(currentAddMessages.messages, currentAddMessages.location))
|
||||
}
|
||||
@ -3421,7 +3421,6 @@ func replayFinalState(
|
||||
var updatedStarsBalance: [PeerId: StarsAmount] = [:]
|
||||
var updatedStarsRevenueStatus: [PeerId: StarsRevenueStats.Balances] = [:]
|
||||
var updatedStarsReactionsAreAnonymousByDefault: Bool?
|
||||
var updatedUpgradedStarGifts: [(ProfileGiftsContext.State.StarGift, ProfileGiftsContext.State.StarGift)] = []
|
||||
|
||||
var holesFromPreviousStateMessageIds: [MessageId] = []
|
||||
var clearHolesFromPreviousStateForChannelMessagesWithPts: [PeerIdAndMessageNamespace: Int32] = [:]
|
||||
@ -4856,10 +4855,6 @@ func replayFinalState(
|
||||
updatedStarsRevenueStatus[peerId] = status
|
||||
case let .UpdateStarsReactionsAreAnonymousByDefault(value):
|
||||
updatedStarsReactionsAreAnonymousByDefault = value
|
||||
case let .UpdateUpgradedStarGift(from, to):
|
||||
if let fromGift = ProfileGiftsContext.State.StarGift(apiUserStarGift: from, transaction: transaction), let toGift = ProfileGiftsContext.State.StarGift(apiUserStarGift: to, transaction: transaction) {
|
||||
updatedUpgradedStarGifts.append((fromGift, toGift))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -5381,7 +5376,6 @@ func replayFinalState(
|
||||
updatedRevenueBalances: updatedRevenueBalances,
|
||||
updatedStarsBalance: updatedStarsBalance,
|
||||
updatedStarsRevenueStatus: updatedStarsRevenueStatus,
|
||||
updatedUpgradedStarGifts: updatedUpgradedStarGifts,
|
||||
sentScheduledMessageIds: finalState.state.sentScheduledMessageIds
|
||||
)
|
||||
}
|
||||
|
@ -56,10 +56,6 @@ private final class UpdatedStarsRevenueStatusSubscriberContext {
|
||||
let subscribers = Bag<([PeerId: StarsRevenueStats.Balances]) -> Void>()
|
||||
}
|
||||
|
||||
private final class UpgradedStarGiftsSubscriberContext {
|
||||
let subscribers = Bag<([(ProfileGiftsContext.State.StarGift, ProfileGiftsContext.State.StarGift)]) -> Void>()
|
||||
}
|
||||
|
||||
public enum DeletedMessageId: Hashable {
|
||||
case global(Int32)
|
||||
case messageId(MessageId)
|
||||
@ -350,7 +346,6 @@ public final class AccountStateManager {
|
||||
private var updatedRevenueBalancesContext = UpdatedRevenueBalancesSubscriberContext()
|
||||
private var updatedStarsBalanceContext = UpdatedStarsBalanceSubscriberContext()
|
||||
private var updatedStarsRevenueStatusContext = UpdatedStarsRevenueStatusSubscriberContext()
|
||||
private var upgradedStarGiftsContext = UpgradedStarGiftsSubscriberContext()
|
||||
|
||||
private let delayNotificatonsUntil = Atomic<Int32?>(value: nil)
|
||||
private let appliedMaxMessageIdPromise = Promise<Int32?>(nil)
|
||||
@ -1113,9 +1108,6 @@ public final class AccountStateManager {
|
||||
if !events.updatedStarsRevenueStatus.isEmpty {
|
||||
strongSelf.notifyUpdatedStarsRevenueStatus(events.updatedStarsRevenueStatus)
|
||||
}
|
||||
if !events.updatedUpgradedStarGifts.isEmpty {
|
||||
strongSelf.notifyUpgradedStarGifts(events.updatedUpgradedStarGifts)
|
||||
}
|
||||
if !events.updatedCalls.isEmpty {
|
||||
for call in events.updatedCalls {
|
||||
strongSelf.callSessionManager?.updateSession(call, completion: { _ in })
|
||||
@ -1774,34 +1766,7 @@ public final class AccountStateManager {
|
||||
subscriber(updatedStarsRevenueStatus)
|
||||
}
|
||||
}
|
||||
|
||||
public func upgradedStarGifts() -> Signal<[(ProfileGiftsContext.State.StarGift, ProfileGiftsContext.State.StarGift)], NoError> {
|
||||
let queue = self.queue
|
||||
return Signal { [weak self] subscriber in
|
||||
let disposable = MetaDisposable()
|
||||
queue.async {
|
||||
if let strongSelf = self {
|
||||
let index = strongSelf.upgradedStarGiftsContext.subscribers.add({ upgradedGifts in
|
||||
subscriber.putNext(upgradedGifts)
|
||||
})
|
||||
|
||||
disposable.set(ActionDisposable {
|
||||
if let strongSelf = self {
|
||||
strongSelf.upgradedStarGiftsContext.subscribers.remove(index)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
return disposable
|
||||
}
|
||||
}
|
||||
|
||||
private func notifyUpgradedStarGifts(_ upgradedStarGifts: [(ProfileGiftsContext.State.StarGift, ProfileGiftsContext.State.StarGift)]) {
|
||||
for subscriber in self.upgradedStarGiftsContext.subscribers.copyItems() {
|
||||
subscriber(upgradedStarGifts)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
func notifyDeletedMessages(messageIds: [MessageId]) {
|
||||
self.deletedMessagesPipe.putNext(messageIds.map { .messageId($0) })
|
||||
}
|
||||
@ -2143,12 +2108,6 @@ public final class AccountStateManager {
|
||||
}
|
||||
}
|
||||
|
||||
public func upgradedStarGifts() -> Signal<[(ProfileGiftsContext.State.StarGift, ProfileGiftsContext.State.StarGift)], NoError> {
|
||||
return self.impl.signalWith { impl, subscriber in
|
||||
return impl.upgradedStarGifts().start(next: subscriber.putNext, error: subscriber.putError, completed: subscriber.putCompletion)
|
||||
}
|
||||
}
|
||||
|
||||
func addCustomOperation<T, E>(_ f: Signal<T, E>) -> Signal<T, E> {
|
||||
return self.impl.signalWith { impl, subscriber in
|
||||
return impl.addCustomOperation(f).start(next: subscriber.putNext, error: subscriber.putError, completed: subscriber.putCompletion)
|
||||
|
@ -137,6 +137,7 @@ public struct Namespaces {
|
||||
public static let recommendedApps: Int8 = 40
|
||||
public static let starsReactionDefaultToPrivate: Int8 = 41
|
||||
public static let cachedPremiumGiftCodeOptions: Int8 = 42
|
||||
public static let cachedProfileGifts: Int8 = 43
|
||||
}
|
||||
|
||||
public struct UnorderedItemList {
|
||||
|
@ -130,8 +130,8 @@ public enum TelegramMediaActionType: PostboxCoding, Equatable {
|
||||
case paymentRefunded(peerId: PeerId, currency: String, totalAmount: Int64, payload: Data?, transactionId: String)
|
||||
case giftStars(currency: String, amount: Int64, count: Int64, cryptoCurrency: String?, cryptoAmount: Int64?, transactionId: String?)
|
||||
case prizeStars(amount: Int64, isUnclaimed: Bool, boostPeerId: PeerId?, transactionId: String?, giveawayMessageId: MessageId?)
|
||||
case starGift(gift: StarGift, convertStars: Int64?, text: String?, entities: [MessageTextEntity]?, nameHidden: Bool, savedToProfile: Bool, converted: Bool, upgraded: Bool, upgradeStars: Int64?)
|
||||
case starGiftUnique(gift: StarGift, isUpgrade: Bool, isTransferred: Bool, savedToProfile: Bool, canExportDate: Int32?, transferStars: Int64?)
|
||||
case starGift(gift: StarGift, convertStars: Int64?, text: String?, entities: [MessageTextEntity]?, nameHidden: Bool, savedToProfile: Bool, converted: Bool, upgraded: Bool, canUpgrade: Bool, upgradeStars: Int64?, isRefunded: Bool)
|
||||
case starGiftUnique(gift: StarGift, isUpgrade: Bool, isTransferred: Bool, savedToProfile: Bool, canExportDate: Int32?, transferStars: Int64?, isRefunded: Bool)
|
||||
|
||||
public init(decoder: PostboxDecoder) {
|
||||
let rawValue: Int32 = decoder.decodeInt32ForKey("_rawValue", orElse: 0)
|
||||
@ -253,9 +253,9 @@ public enum TelegramMediaActionType: PostboxCoding, Equatable {
|
||||
}
|
||||
self = .prizeStars(amount: decoder.decodeInt64ForKey("amount", orElse: 0), isUnclaimed: decoder.decodeBoolForKey("unclaimed", orElse: false), boostPeerId: boostPeerId, transactionId: decoder.decodeOptionalStringForKey("transactionId"), giveawayMessageId: giveawayMessageId)
|
||||
case 44:
|
||||
self = .starGift(gift: decoder.decodeObjectForKey("gift", decoder: { StarGift(decoder: $0) }) as! StarGift, convertStars: decoder.decodeOptionalInt64ForKey("convertStars"), text: decoder.decodeOptionalStringForKey("text"), entities: decoder.decodeOptionalObjectArrayWithDecoderForKey("entities"), nameHidden: decoder.decodeBoolForKey("nameHidden", orElse: false), savedToProfile: decoder.decodeBoolForKey("savedToProfile", orElse: false), converted: decoder.decodeBoolForKey("converted", orElse: false), upgraded: decoder.decodeBoolForKey("upgraded", orElse: false), upgradeStars: decoder.decodeOptionalInt64ForKey("upgradeStars"))
|
||||
self = .starGift(gift: decoder.decodeObjectForKey("gift", decoder: { StarGift(decoder: $0) }) as! StarGift, convertStars: decoder.decodeOptionalInt64ForKey("convertStars"), text: decoder.decodeOptionalStringForKey("text"), entities: decoder.decodeOptionalObjectArrayWithDecoderForKey("entities"), nameHidden: decoder.decodeBoolForKey("nameHidden", orElse: false), savedToProfile: decoder.decodeBoolForKey("savedToProfile", orElse: false), converted: decoder.decodeBoolForKey("converted", orElse: false), upgraded: decoder.decodeBoolForKey("upgraded", orElse: false), canUpgrade: decoder.decodeBoolForKey("canUpgrade", orElse: false), upgradeStars: decoder.decodeOptionalInt64ForKey("upgradeStars"), isRefunded: decoder.decodeBoolForKey("isRefunded", orElse: false))
|
||||
case 45:
|
||||
self = .starGiftUnique(gift: decoder.decodeObjectForKey("gift", decoder: { StarGift(decoder: $0) }) as! StarGift, isUpgrade: decoder.decodeBoolForKey("isUpgrade", orElse: false), isTransferred: decoder.decodeBoolForKey("isTransferred", orElse: false), savedToProfile: decoder.decodeBoolForKey("savedToProfile", orElse: false), canExportDate: decoder.decodeOptionalInt32ForKey("canExportDate"), transferStars: decoder.decodeOptionalInt64ForKey("transferStars"))
|
||||
self = .starGiftUnique(gift: decoder.decodeObjectForKey("gift", decoder: { StarGift(decoder: $0) }) as! StarGift, isUpgrade: decoder.decodeBoolForKey("isUpgrade", orElse: false), isTransferred: decoder.decodeBoolForKey("isTransferred", orElse: false), savedToProfile: decoder.decodeBoolForKey("savedToProfile", orElse: false), canExportDate: decoder.decodeOptionalInt32ForKey("canExportDate"), transferStars: decoder.decodeOptionalInt64ForKey("transferStars"), isRefunded: decoder.decodeBoolForKey("isRefunded", orElse: false))
|
||||
default:
|
||||
self = .unknown
|
||||
}
|
||||
@ -548,7 +548,7 @@ public enum TelegramMediaActionType: PostboxCoding, Equatable {
|
||||
} else {
|
||||
encoder.encodeNil(forKey: "giveawayMsgId")
|
||||
}
|
||||
case let .starGift(gift, convertStars, text, entities, nameHidden, savedToProfile, converted, upgraded, upgradeStars):
|
||||
case let .starGift(gift, convertStars, text, entities, nameHidden, savedToProfile, converted, upgraded, canUpgrade, upgradeStars, isRefunded):
|
||||
encoder.encodeInt32(44, forKey: "_rawValue")
|
||||
encoder.encodeObject(gift, forKey: "gift")
|
||||
if let convertStars {
|
||||
@ -567,12 +567,14 @@ public enum TelegramMediaActionType: PostboxCoding, Equatable {
|
||||
encoder.encodeBool(savedToProfile, forKey: "savedToProfile")
|
||||
encoder.encodeBool(converted, forKey: "converted")
|
||||
encoder.encodeBool(upgraded, forKey: "upgraded")
|
||||
encoder.encodeBool(canUpgrade, forKey: "canUpgrade")
|
||||
if let upgradeStars {
|
||||
encoder.encodeInt64(upgradeStars, forKey: "upgradeStars")
|
||||
} else {
|
||||
encoder.encodeNil(forKey: "upgradeStars")
|
||||
}
|
||||
case let .starGiftUnique(gift, isUpgrade, isTransferred, savedToProfile, canExportDate, transferStars):
|
||||
encoder.encodeBool(isRefunded, forKey: "isRefunded")
|
||||
case let .starGiftUnique(gift, isUpgrade, isTransferred, savedToProfile, canExportDate, transferStars, isRefunded):
|
||||
encoder.encodeInt32(45, forKey: "_rawValue")
|
||||
encoder.encodeObject(gift, forKey: "gift")
|
||||
encoder.encodeBool(isUpgrade, forKey: "isUpgrade")
|
||||
@ -588,6 +590,7 @@ public enum TelegramMediaActionType: PostboxCoding, Equatable {
|
||||
} else {
|
||||
encoder.encodeNil(forKey: "transferStars")
|
||||
}
|
||||
encoder.encodeBool(isRefunded, forKey: "isRefunded")
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -707,8 +707,17 @@ public enum UpgradeStarGiftError {
|
||||
case generic
|
||||
}
|
||||
|
||||
func _internal_upgradeStarGift(account: Account, prepaid: Bool, messageId: EngineMessage.Id, keepOriginalInfo: Bool) -> Signal<ProfileGiftsContext.State.StarGift, UpgradeStarGiftError> {
|
||||
if prepaid {
|
||||
func _internal_upgradeStarGift(account: Account, formId: Int64?, messageId: EngineMessage.Id, keepOriginalInfo: Bool) -> Signal<ProfileGiftsContext.State.StarGift, UpgradeStarGiftError> {
|
||||
if let formId {
|
||||
let source: BotPaymentInvoiceSource = .starGiftUpgrade(keepOriginalInfo: keepOriginalInfo, messageId: messageId)
|
||||
return _internal_sendStarsPaymentForm(account: account, formId: formId, source: source)
|
||||
|> mapError { _ -> UpgradeStarGiftError in
|
||||
return .generic
|
||||
}
|
||||
|> mapToSignal { _ in
|
||||
return .complete()
|
||||
}
|
||||
} else {
|
||||
var flags: Int32 = 0
|
||||
if keepOriginalInfo {
|
||||
flags |= (1 << 0)
|
||||
@ -719,57 +728,35 @@ func _internal_upgradeStarGift(account: Account, prepaid: Bool, messageId: Engin
|
||||
}
|
||||
|> mapToSignal { updates in
|
||||
account.stateManager.addUpdates(updates)
|
||||
|
||||
return account.stateManager.upgradedStarGifts()
|
||||
|> castError(UpgradeStarGiftError.self)
|
||||
|> take(until: { updates in
|
||||
for update in updates {
|
||||
if update.0.messageId == messageId {
|
||||
return .init(passthrough: true, complete: true)
|
||||
}
|
||||
}
|
||||
return .init(passthrough: false, complete: false)
|
||||
})
|
||||
|> mapToSignal { updates in
|
||||
for update in updates {
|
||||
if update.0.messageId == messageId {
|
||||
return .single(update.1)
|
||||
}
|
||||
}
|
||||
return .complete()
|
||||
}
|
||||
}
|
||||
} else {
|
||||
let source: BotPaymentInvoiceSource = .starGiftUpgrade(keepOriginalInfo: keepOriginalInfo, messageId: messageId)
|
||||
return _internal_fetchBotPaymentForm(accountPeerId: account.peerId, postbox: account.postbox, network: account.network, source: source, themeParams: nil)
|
||||
|> mapError { _ -> UpgradeStarGiftError in
|
||||
return .generic
|
||||
}
|
||||
|> mapToSignal { paymentForm in
|
||||
return _internal_sendStarsPaymentForm(account: account, formId: paymentForm.id, source: source)
|
||||
|> mapError { _ -> UpgradeStarGiftError in
|
||||
return .generic
|
||||
}
|
||||
|> mapToSignal { _ in
|
||||
return account.stateManager.upgradedStarGifts()
|
||||
|> castError(UpgradeStarGiftError.self)
|
||||
|> take(until: { updates in
|
||||
for update in updates {
|
||||
if update.0.messageId == messageId {
|
||||
return .init(passthrough: true, complete: true)
|
||||
for update in updates.allUpdates {
|
||||
switch update {
|
||||
case let .updateNewMessage(message, _, _):
|
||||
if let message = StoreMessage(apiMessage: message, accountPeerId: account.peerId, peerIsForum: false) {
|
||||
for media in message.media {
|
||||
if let action = media as? TelegramMediaAction, case let .starGiftUnique(gift, _, _, savedToProfile, canExportDate, transferStars, _) = action.action, case let .Id(messageId) = message.id {
|
||||
return .single(ProfileGiftsContext.State.StarGift(
|
||||
gift: gift,
|
||||
fromPeer: nil,
|
||||
date: message.timestamp,
|
||||
text: nil,
|
||||
entities: nil,
|
||||
messageId: messageId,
|
||||
nameHidden: false,
|
||||
savedToProfile: savedToProfile,
|
||||
convertStars: nil,
|
||||
canUpgrade: false,
|
||||
canExportDate: canExportDate,
|
||||
upgradeStars: nil,
|
||||
transferStars: transferStars
|
||||
))
|
||||
}
|
||||
}
|
||||
}
|
||||
return .init(passthrough: false, complete: false)
|
||||
})
|
||||
|> mapToSignal { updates in
|
||||
for update in updates {
|
||||
if update.0.messageId == messageId {
|
||||
return .single(update.1)
|
||||
}
|
||||
}
|
||||
return .complete()
|
||||
default:
|
||||
break
|
||||
}
|
||||
}
|
||||
return .fail(.generic)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -791,7 +778,49 @@ func _internal_starGiftUpgradePreview(account: Account, giftId: Int64) -> Signal
|
||||
}
|
||||
}
|
||||
|
||||
private var cachedAccountGifts: [EnginePeer.Id: [ProfileGiftsContext.State.StarGift]] = [:]
|
||||
private final class CachedProfileGifts: Codable {
|
||||
enum CodingKeys: String, CodingKey {
|
||||
case gifts
|
||||
case count
|
||||
}
|
||||
|
||||
var gifts: [ProfileGiftsContext.State.StarGift]
|
||||
let count: Int32
|
||||
|
||||
init(gifts: [ProfileGiftsContext.State.StarGift], count: Int32) {
|
||||
self.gifts = gifts
|
||||
self.count = count
|
||||
}
|
||||
|
||||
init(from decoder: Decoder) throws {
|
||||
let container = try decoder.container(keyedBy: CodingKeys.self)
|
||||
|
||||
self.gifts = try container.decode([ProfileGiftsContext.State.StarGift].self, forKey: .gifts)
|
||||
self.count = try container.decode(Int32.self, forKey: .count)
|
||||
}
|
||||
|
||||
func encode(to encoder: Encoder) throws {
|
||||
var container = encoder.container(keyedBy: CodingKeys.self)
|
||||
|
||||
try container.encode(self.gifts, forKey: .gifts)
|
||||
try container.encode(self.count, forKey: .count)
|
||||
}
|
||||
|
||||
func render(transaction: Transaction) {
|
||||
for i in 0 ..< self.gifts.count {
|
||||
let gift = self.gifts[i]
|
||||
if gift.fromPeer == nil, let fromPeerId = gift._fromPeerId, let peer = transaction.getPeer(fromPeerId) {
|
||||
self.gifts[i] = gift.withFromPeer(EnginePeer(peer))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private func entryId(peerId: EnginePeer.Id) -> ItemCacheEntryId {
|
||||
let cacheKey = ValueBoxKey(length: 8)
|
||||
cacheKey.setInt64(0, value: peerId.toInt64())
|
||||
return ItemCacheEntryId(collectionId: Namespaces.CachedItemCollection.cachedProfileGifts, key: cacheKey)
|
||||
}
|
||||
|
||||
private final class ProfileGiftsContextImpl {
|
||||
private let queue: Queue
|
||||
@ -799,6 +828,7 @@ private final class ProfileGiftsContextImpl {
|
||||
private let peerId: PeerId
|
||||
|
||||
private let disposable = MetaDisposable()
|
||||
private let cacheDisposable = MetaDisposable()
|
||||
private let actionDisposable = MetaDisposable()
|
||||
|
||||
private var gifts: [ProfileGiftsContext.State.StarGift] = []
|
||||
@ -821,22 +851,37 @@ private final class ProfileGiftsContextImpl {
|
||||
|
||||
deinit {
|
||||
self.disposable.dispose()
|
||||
self.cacheDisposable.dispose()
|
||||
self.actionDisposable.dispose()
|
||||
}
|
||||
|
||||
func loadMore() {
|
||||
let peerId = self.peerId
|
||||
let accountPeerId = self.account.peerId
|
||||
let network = self.account.network
|
||||
let postbox = self.account.postbox
|
||||
|
||||
if case let .ready(true, initialNextOffset) = self.dataState {
|
||||
if self.gifts.isEmpty, self.peerId == self.account.peerId, let cachedGifts = cachedAccountGifts[self.peerId] {
|
||||
self.gifts = cachedGifts
|
||||
if self.gifts.isEmpty, initialNextOffset == nil {
|
||||
self.cacheDisposable.set((self.account.postbox.transaction { transaction -> CachedProfileGifts? in
|
||||
let cachedGifts = transaction.retrieveItemCacheEntry(id: entryId(peerId: peerId))?.get(CachedProfileGifts.self)
|
||||
cachedGifts?.render(transaction: transaction)
|
||||
return cachedGifts
|
||||
} |> deliverOn(self.queue)).start(next: { [weak self] cachedGifts in
|
||||
guard let self, let cachedGifts else {
|
||||
return
|
||||
}
|
||||
if case .loading = self.dataState {
|
||||
self.gifts = cachedGifts.gifts
|
||||
self.count = cachedGifts.count
|
||||
self.pushState()
|
||||
}
|
||||
}))
|
||||
}
|
||||
|
||||
self.dataState = .loading
|
||||
self.pushState()
|
||||
|
||||
let peerId = self.peerId
|
||||
let accountPeerId = self.account.peerId
|
||||
let network = self.account.network
|
||||
let postbox = self.account.postbox
|
||||
|
||||
let signal: Signal<([ProfileGiftsContext.State.StarGift], Int32, String?), NoError> = self.account.postbox.transaction { transaction -> Api.InputUser? in
|
||||
return transaction.getPeer(peerId).flatMap(apiInputUser)
|
||||
}
|
||||
@ -871,10 +916,15 @@ private final class ProfileGiftsContextImpl {
|
||||
guard let strongSelf = self else {
|
||||
return
|
||||
}
|
||||
if initialNextOffset == nil, strongSelf.peerId == strongSelf.account.peerId {
|
||||
cachedAccountGifts[strongSelf.peerId] = gifts
|
||||
if initialNextOffset == nil {
|
||||
strongSelf.gifts = gifts
|
||||
} else {
|
||||
|
||||
strongSelf.cacheDisposable.set(strongSelf.account.postbox.transaction { transaction in
|
||||
if let entry = CodableEntry(CachedProfileGifts(gifts: gifts, count: count)) {
|
||||
transaction.putItemCacheEntry(id: entryId(peerId: peerId), entry: entry)
|
||||
}
|
||||
}.start())
|
||||
} else {
|
||||
for gift in gifts {
|
||||
strongSelf.gifts.append(gift)
|
||||
}
|
||||
@ -920,9 +970,14 @@ private final class ProfileGiftsContextImpl {
|
||||
self.pushState()
|
||||
}
|
||||
|
||||
func upgradeStarGift(prepaid: Bool, messageId: EngineMessage.Id, keepOriginalInfo: Bool) {
|
||||
func upgradeStarGift(formId: Int64?, messageId: EngineMessage.Id, keepOriginalInfo: Bool) {
|
||||
self.actionDisposable.set(
|
||||
_internal_upgradeStarGift(account: self.account, prepaid: prepaid, messageId: messageId, keepOriginalInfo: keepOriginalInfo).startStrict()
|
||||
_internal_upgradeStarGift(account: self.account, formId: formId, messageId: messageId, keepOriginalInfo: keepOriginalInfo).startStrict(next: { [weak self] result in
|
||||
guard let self else {
|
||||
return
|
||||
}
|
||||
let _ = self
|
||||
})
|
||||
)
|
||||
self.pushState()
|
||||
}
|
||||
@ -935,7 +990,23 @@ private final class ProfileGiftsContextImpl {
|
||||
|
||||
public final class ProfileGiftsContext {
|
||||
public struct State: Equatable {
|
||||
public struct StarGift: Equatable {
|
||||
public struct StarGift: Equatable, Codable {
|
||||
enum CodingKeys: String, CodingKey {
|
||||
case gift
|
||||
case fromPeerId
|
||||
case date
|
||||
case text
|
||||
case entities
|
||||
case messageId
|
||||
case nameHidden
|
||||
case savedToProfile
|
||||
case convertStars
|
||||
case canUpgrade
|
||||
case canExportDate
|
||||
case upgradeStars
|
||||
case transferStars
|
||||
}
|
||||
|
||||
public let gift: TelegramCore.StarGift
|
||||
public let fromPeer: EnginePeer?
|
||||
public let date: Int32
|
||||
@ -950,6 +1021,76 @@ public final class ProfileGiftsContext {
|
||||
public let upgradeStars: Int64?
|
||||
public let transferStars: Int64?
|
||||
|
||||
fileprivate let _fromPeerId: EnginePeer.Id?
|
||||
|
||||
public init (
|
||||
gift: TelegramCore.StarGift,
|
||||
fromPeer: EnginePeer?,
|
||||
date: Int32,
|
||||
text: String?,
|
||||
entities: [MessageTextEntity]?,
|
||||
messageId: EngineMessage.Id?,
|
||||
nameHidden: Bool,
|
||||
savedToProfile: Bool,
|
||||
convertStars: Int64?,
|
||||
canUpgrade: Bool,
|
||||
canExportDate: Int32?,
|
||||
upgradeStars: Int64?,
|
||||
transferStars: Int64?
|
||||
) {
|
||||
self.gift = gift
|
||||
self.fromPeer = fromPeer
|
||||
self._fromPeerId = fromPeer?.id
|
||||
self.date = date
|
||||
self.text = text
|
||||
self.entities = entities
|
||||
self.messageId = messageId
|
||||
self.nameHidden = nameHidden
|
||||
self.savedToProfile = savedToProfile
|
||||
self.convertStars = convertStars
|
||||
self.canUpgrade = canUpgrade
|
||||
self.canExportDate = canExportDate
|
||||
self.upgradeStars = upgradeStars
|
||||
self.transferStars = transferStars
|
||||
}
|
||||
|
||||
public init(from decoder: Decoder) throws {
|
||||
let container = try decoder.container(keyedBy: CodingKeys.self)
|
||||
|
||||
self.gift = try container.decode(TelegramCore.StarGift.self, forKey: .gift)
|
||||
self.fromPeer = nil
|
||||
self._fromPeerId = try container.decodeIfPresent(EnginePeer.Id.self, forKey: .fromPeerId)
|
||||
self.date = try container.decode(Int32.self, forKey: .date)
|
||||
self.text = try container.decodeIfPresent(String.self, forKey: .text)
|
||||
self.entities = try container.decodeIfPresent([MessageTextEntity].self, forKey: .entities)
|
||||
self.messageId = try container.decodeIfPresent(EngineMessage.Id.self, forKey: .messageId)
|
||||
self.nameHidden = try container.decode(Bool.self, forKey: .nameHidden)
|
||||
self.savedToProfile = try container.decode(Bool.self, forKey: .savedToProfile)
|
||||
self.convertStars = try container.decodeIfPresent(Int64.self, forKey: .convertStars)
|
||||
self.canUpgrade = try container.decode(Bool.self, forKey: .canUpgrade)
|
||||
self.canExportDate = try container.decodeIfPresent(Int32.self, forKey: .canExportDate)
|
||||
self.upgradeStars = try container.decodeIfPresent(Int64.self, forKey: .upgradeStars)
|
||||
self.transferStars = try container.decodeIfPresent(Int64.self, forKey: .transferStars)
|
||||
}
|
||||
|
||||
public func encode(to encoder: Encoder) throws {
|
||||
var container = encoder.container(keyedBy: CodingKeys.self)
|
||||
|
||||
try container.encode(self.gift, forKey: .gift)
|
||||
try container.encodeIfPresent(self.fromPeer?.id, forKey: .fromPeerId)
|
||||
try container.encode(self.date, forKey: .date)
|
||||
try container.encodeIfPresent(self.text, forKey: .text)
|
||||
try container.encodeIfPresent(self.entities, forKey: .entities)
|
||||
try container.encodeIfPresent(self.messageId, forKey: .messageId)
|
||||
try container.encode(self.nameHidden, forKey: .nameHidden)
|
||||
try container.encode(self.savedToProfile, forKey: .savedToProfile)
|
||||
try container.encodeIfPresent(self.convertStars, forKey: .convertStars)
|
||||
try container.encode(self.canUpgrade, forKey: .canUpgrade)
|
||||
try container.encodeIfPresent(self.canExportDate, forKey: .canExportDate)
|
||||
try container.encodeIfPresent(self.upgradeStars, forKey: .upgradeStars)
|
||||
try container.encodeIfPresent(self.transferStars, forKey: .transferStars)
|
||||
}
|
||||
|
||||
public func withSavedToProfile(_ savedToProfile: Bool) -> StarGift {
|
||||
return StarGift(
|
||||
gift: self.gift,
|
||||
@ -967,6 +1108,24 @@ public final class ProfileGiftsContext {
|
||||
transferStars: self.transferStars
|
||||
)
|
||||
}
|
||||
|
||||
fileprivate func withFromPeer(_ fromPeer: EnginePeer?) -> StarGift {
|
||||
return StarGift(
|
||||
gift: self.gift,
|
||||
fromPeer: fromPeer,
|
||||
date: self.date,
|
||||
text: self.text,
|
||||
entities: self.entities,
|
||||
messageId: self.messageId,
|
||||
nameHidden: self.nameHidden,
|
||||
savedToProfile: savedToProfile,
|
||||
convertStars: self.convertStars,
|
||||
canUpgrade: self.canUpgrade,
|
||||
canExportDate: self.canExportDate,
|
||||
upgradeStars: self.upgradeStars,
|
||||
transferStars: self.transferStars
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
public enum DataState: Equatable {
|
||||
@ -1027,9 +1186,9 @@ public final class ProfileGiftsContext {
|
||||
}
|
||||
}
|
||||
|
||||
public func upgradeStarGift(prepaid: Bool, messageId: EngineMessage.Id, keepOriginalInfo: Bool) {
|
||||
public func upgradeStarGift(formId: Int64?, messageId: EngineMessage.Id, keepOriginalInfo: Bool) {
|
||||
self.impl.with { impl in
|
||||
impl.upgradeStarGift(prepaid: prepaid, messageId: messageId, keepOriginalInfo: keepOriginalInfo)
|
||||
impl.upgradeStarGift(formId: formId, messageId: messageId, keepOriginalInfo: keepOriginalInfo)
|
||||
}
|
||||
}
|
||||
|
||||
@ -1055,6 +1214,7 @@ extension ProfileGiftsContext.State.StarGift {
|
||||
} else {
|
||||
self.fromPeer = nil
|
||||
}
|
||||
self._fromPeerId = self.fromPeer?.id
|
||||
self.date = date
|
||||
|
||||
if let message {
|
||||
@ -1081,7 +1241,7 @@ extension ProfileGiftsContext.State.StarGift {
|
||||
self.nameHidden = (flags & (1 << 0)) != 0
|
||||
self.savedToProfile = (flags & (1 << 5)) == 0
|
||||
self.convertStars = convertStars
|
||||
self.canUpgrade = (flags & (1 << 6)) != 0
|
||||
self.canUpgrade = (flags & (1 << 10)) != 0
|
||||
self.canExportDate = canExportDate
|
||||
self.upgradeStars = upgradeStars
|
||||
self.transferStars = transferStars
|
||||
|
@ -125,8 +125,8 @@ public extension TelegramEngine {
|
||||
return _internal_transferStarGift(account: self.account, prepaid: prepaid, messageId: messageId, peerId: peerId)
|
||||
}
|
||||
|
||||
public func upgradeStarGift(prepaid: Bool, messageId: EngineMessage.Id, keepOriginalInfo: Bool) -> Signal<ProfileGiftsContext.State.StarGift, UpgradeStarGiftError> {
|
||||
return _internal_upgradeStarGift(account: self.account, prepaid: prepaid, messageId: messageId, keepOriginalInfo: keepOriginalInfo)
|
||||
public func upgradeStarGift(formId: Int64?, messageId: EngineMessage.Id, keepOriginalInfo: Bool) -> Signal<ProfileGiftsContext.State.StarGift, UpgradeStarGiftError> {
|
||||
return _internal_upgradeStarGift(account: self.account, formId: formId, messageId: messageId, keepOriginalInfo: keepOriginalInfo)
|
||||
}
|
||||
|
||||
public func starGiftUpgradePreview(giftId: Int64) -> Signal<[StarGift.UniqueGift.Attribute], NoError> {
|
||||
|
@ -1066,7 +1066,7 @@ public func universalServiceMessageString(presentationData: (PresentationTheme,
|
||||
attributedString = mutableString
|
||||
case .prizeStars:
|
||||
attributedString = NSAttributedString(string: strings.Notification_StarsPrize, font: titleFont, textColor: primaryTextColor)
|
||||
case let .starGift(gift, _, text, entities, _, _, _, _, _):
|
||||
case let .starGift(gift, _, text, entities, _, _, _, _, _, upgradeStars, _):
|
||||
if !forAdditionalServiceMessage {
|
||||
if let text {
|
||||
let mutableAttributedString = NSMutableAttributedString(attributedString: stringWithAppliedEntities(text, entities: entities ?? [], baseColor: primaryTextColor, linkColor: primaryTextColor, baseFont: titleFont, linkFont: titleBoldFont, boldFont: titleBoldFont, italicFont: titleFont, boldItalicFont: titleBoldFont, fixedFont: titleFont, blockQuoteFont: titleFont, underlineLinks: false, message: message._asMessage()))
|
||||
@ -1075,7 +1075,11 @@ public func universalServiceMessageString(presentationData: (PresentationTheme,
|
||||
attributedString = NSAttributedString(string: strings.Notification_Gift, font: titleFont, textColor: primaryTextColor)
|
||||
}
|
||||
} else if case let .generic(gift) = gift {
|
||||
let starsPrice = strings.Notification_StarsGift_Stars(Int32(gift.price))
|
||||
var finalPrice = gift.price
|
||||
if let upgradeStars {
|
||||
finalPrice += upgradeStars
|
||||
}
|
||||
let starsPrice = strings.Notification_StarsGift_Stars(Int32(finalPrice))
|
||||
var authorName = compactAuthorName
|
||||
var peerIds: [(Int, EnginePeer.Id?)] = [(0, message.author?.id)]
|
||||
if message.id.peerId.namespace == Namespaces.Peer.CloudUser && message.id.peerId.id._internalGetInt64Value() == 777000 {
|
||||
@ -1090,7 +1094,7 @@ public func universalServiceMessageString(presentationData: (PresentationTheme,
|
||||
attributedString = addAttributesToStringWithRanges(strings.Notification_StarsGift_Sent(authorName, starsPrice)._tuple, body: bodyAttributes, argumentAttributes: attributes)
|
||||
}
|
||||
}
|
||||
case let .starGiftUnique(gift, isUpgrade, isTransferred, _, _, _):
|
||||
case let .starGiftUnique(gift, isUpgrade, isTransferred, _, _, _, _):
|
||||
if case let .unique(gift) = gift {
|
||||
if !forAdditionalServiceMessage {
|
||||
attributedString = NSAttributedString(string: "\(gift.title) #\(gift.number)", font: titleFont, textColor: primaryTextColor)
|
||||
|
@ -32,6 +32,7 @@ swift_library(
|
||||
"//submodules/TelegramUI/Components/Chat/ChatMessageItemCommon",
|
||||
"//submodules/TelegramUI/Components/TextNodeWithEntities",
|
||||
"//submodules/InvisibleInkDustNode",
|
||||
"//submodules/TelegramUI/Components/PeerInfo/PeerInfoCoverComponent",
|
||||
],
|
||||
visibility = [
|
||||
"//visibility:public",
|
||||
|
@ -3,6 +3,7 @@ import UIKit
|
||||
import AsyncDisplayKit
|
||||
import Display
|
||||
import SwiftSignalKit
|
||||
import ComponentFlow
|
||||
import TelegramCore
|
||||
import AccountContext
|
||||
import TelegramPresentationData
|
||||
@ -22,6 +23,7 @@ import ChatMessageBubbleContentNode
|
||||
import ChatMessageItemCommon
|
||||
import TextNodeWithEntities
|
||||
import InvisibleInkDustNode
|
||||
import PeerInfoCoverComponent
|
||||
|
||||
private func attributedServiceMessageString(theme: ChatPresentationThemeData, strings: PresentationStrings, nameDisplayOrder: PresentationPersonNameOrder, dateTimeFormat: PresentationDateTimeFormat, message: EngineMessage, accountPeerId: EnginePeer.Id) -> NSAttributedString? {
|
||||
return universalServiceMessageString(presentationData: (theme.theme, theme.wallpaper), strings: strings, nameDisplayOrder: nameDisplayOrder, dateTimeFormat: dateTimeFormat, message: message, accountPeerId: accountPeerId, forChatList: false, forForumOverview: false, forAdditionalServiceMessage: true)
|
||||
@ -33,6 +35,7 @@ public class ChatMessageGiftBubbleContentNode: ChatMessageBubbleContentNode {
|
||||
private let backgroundMaskNode: ASImageNode
|
||||
private var linkHighlightingNode: LinkHighlightingNode?
|
||||
|
||||
private let patternView = ComponentView<Empty>()
|
||||
private let mediaBackgroundMaskNode: ASImageNode
|
||||
private var mediaBackgroundContent: WallpaperBubbleBackgroundNode?
|
||||
private let titleNode: TextNode
|
||||
@ -43,6 +46,13 @@ public class ChatMessageGiftBubbleContentNode: ChatMessageBubbleContentNode {
|
||||
private let placeholderNode: StickerShimmerEffectNode
|
||||
private let animationNode: AnimatedStickerNode
|
||||
|
||||
private let modelTitleTextNode: TextNode
|
||||
private let modelValueTextNode: TextNode
|
||||
private let backdropTitleTextNode: TextNode
|
||||
private let backdropValueTextNode: TextNode
|
||||
private let symbolTitleTextNode: TextNode
|
||||
private let symbolValueTextNode: TextNode
|
||||
|
||||
private let ribbonBackgroundNode: ASImageNode
|
||||
private let ribbonTextNode: TextNode
|
||||
|
||||
@ -50,6 +60,7 @@ public class ChatMessageGiftBubbleContentNode: ChatMessageBubbleContentNode {
|
||||
private let buttonNode: HighlightTrackingButtonNode
|
||||
private let buttonStarsNode: PremiumStarsNode
|
||||
private let buttonTitleNode: TextNode
|
||||
private let buttonIconNode: ASImageNode
|
||||
|
||||
private let moreTextNode: TextNode
|
||||
|
||||
@ -120,6 +131,25 @@ public class ChatMessageGiftBubbleContentNode: ChatMessageBubbleContentNode {
|
||||
self.textClippingNode = ASDisplayNode()
|
||||
self.textClippingNode.clipsToBounds = true
|
||||
|
||||
self.modelTitleTextNode = TextNode()
|
||||
self.modelTitleTextNode.isUserInteractionEnabled = false
|
||||
self.modelTitleTextNode.displaysAsynchronously = false
|
||||
self.modelValueTextNode = TextNode()
|
||||
self.modelValueTextNode.isUserInteractionEnabled = false
|
||||
self.modelValueTextNode.displaysAsynchronously = false
|
||||
self.backdropTitleTextNode = TextNode()
|
||||
self.backdropTitleTextNode.isUserInteractionEnabled = false
|
||||
self.backdropTitleTextNode.displaysAsynchronously = false
|
||||
self.backdropValueTextNode = TextNode()
|
||||
self.backdropValueTextNode.isUserInteractionEnabled = false
|
||||
self.backdropValueTextNode.displaysAsynchronously = false
|
||||
self.symbolTitleTextNode = TextNode()
|
||||
self.symbolTitleTextNode.isUserInteractionEnabled = false
|
||||
self.symbolTitleTextNode.displaysAsynchronously = false
|
||||
self.symbolValueTextNode = TextNode()
|
||||
self.symbolValueTextNode.isUserInteractionEnabled = false
|
||||
self.symbolValueTextNode.displaysAsynchronously = false
|
||||
|
||||
self.buttonNode = HighlightTrackingButtonNode()
|
||||
self.buttonNode.clipsToBounds = true
|
||||
self.buttonNode.cornerRadius = 17.0
|
||||
@ -136,6 +166,10 @@ public class ChatMessageGiftBubbleContentNode: ChatMessageBubbleContentNode {
|
||||
self.buttonTitleNode.isUserInteractionEnabled = false
|
||||
self.buttonTitleNode.displaysAsynchronously = false
|
||||
|
||||
self.buttonIconNode = ASImageNode()
|
||||
self.buttonIconNode.displaysAsynchronously = false
|
||||
self.buttonIconNode.isUserInteractionEnabled = false
|
||||
|
||||
self.ribbonBackgroundNode = ASImageNode()
|
||||
self.ribbonBackgroundNode.displaysAsynchronously = false
|
||||
|
||||
@ -161,6 +195,7 @@ public class ChatMessageGiftBubbleContentNode: ChatMessageBubbleContentNode {
|
||||
self.addSubnode(self.buttonNode)
|
||||
self.buttonNode.addSubnode(self.buttonStarsNode)
|
||||
self.buttonNode.addSubnode(self.buttonTitleNode)
|
||||
self.buttonNode.addSubnode(self.buttonIconNode)
|
||||
|
||||
self.addSubnode(self.ribbonBackgroundNode)
|
||||
self.addSubnode(self.ribbonTextNode)
|
||||
@ -292,6 +327,13 @@ public class ChatMessageGiftBubbleContentNode: ChatMessageBubbleContentNode {
|
||||
let makeRibbonTextLayout = TextNode.asyncLayout(self.ribbonTextNode)
|
||||
let makeMeasureTextLayout = TextNode.asyncLayout(nil)
|
||||
let makeMoreTextLayout = TextNode.asyncLayout(self.moreTextNode)
|
||||
|
||||
let makeModelTitleLayout = TextNode.asyncLayout(self.modelTitleTextNode)
|
||||
let makeModelValueLayout = TextNode.asyncLayout(self.modelValueTextNode)
|
||||
let makeBackdropTitleLayout = TextNode.asyncLayout(self.backdropTitleTextNode)
|
||||
let makeBackdropValueLayout = TextNode.asyncLayout(self.backdropValueTextNode)
|
||||
let makeSymbolTitleLayout = TextNode.asyncLayout(self.symbolTitleTextNode)
|
||||
let makeSymbolValueLayout = TextNode.asyncLayout(self.symbolValueTextNode)
|
||||
|
||||
let cachedMaskBackgroundImage = self.cachedMaskBackgroundImage
|
||||
|
||||
@ -303,7 +345,12 @@ public class ChatMessageGiftBubbleContentNode: ChatMessageBubbleContentNode {
|
||||
return (contentProperties, nil, CGFloat.greatestFiniteMagnitude, { constrainedSize, position in
|
||||
var giftSize = CGSize(width: 220.0, height: 240.0)
|
||||
|
||||
let incoming = item.message.effectivelyIncoming(item.context.account.peerId)
|
||||
let incoming: Bool
|
||||
if item.message.id.peerId == item.context.account.peerId && item.message.forwardInfo == nil {
|
||||
incoming = true
|
||||
} else {
|
||||
incoming = item.message.effectivelyIncoming(item.context.account.peerId)
|
||||
}
|
||||
|
||||
let attributedString = attributedServiceMessageString(theme: item.presentationData.theme, strings: item.presentationData.strings, nameDisplayOrder: item.presentationData.nameDisplayOrder, dateTimeFormat: item.presentationData.dateTimeFormat, message: EngineMessage(item.message), accountPeerId: item.context.account.peerId)
|
||||
|
||||
@ -314,12 +361,26 @@ public class ChatMessageGiftBubbleContentNode: ChatMessageBubbleContentNode {
|
||||
var animationFile: TelegramMediaFile?
|
||||
var title = item.presentationData.strings.Notification_PremiumGift_Title
|
||||
var text = ""
|
||||
var subtitleColor = primaryTextColor
|
||||
var entities: [MessageTextEntity] = []
|
||||
var buttonTitle = item.presentationData.strings.Notification_PremiumGift_View
|
||||
var buttonIcon: String?
|
||||
var ribbonTitle = ""
|
||||
var hasServiceMessage = true
|
||||
var textSpacing: CGFloat = 0.0
|
||||
var isStarGift = false
|
||||
|
||||
var modelTitle: String?
|
||||
var modelValue: String?
|
||||
var backdropTitle: String?
|
||||
var backdropValue: String?
|
||||
var symbolTitle: String?
|
||||
var symbolValue: String?
|
||||
var uniqueBackgroundColor: UIColor?
|
||||
var uniqueSecondBackgroundColor: UIColor?
|
||||
var uniquePatternColor: UIColor?
|
||||
var uniquePatternFile: TelegramMediaFile?
|
||||
|
||||
for media in item.message.media {
|
||||
if let action = media as? TelegramMediaAction {
|
||||
switch action.action {
|
||||
@ -406,7 +467,7 @@ public class ChatMessageGiftBubbleContentNode: ChatMessageBubbleContentNode {
|
||||
buttonTitle = item.presentationData.strings.Notification_PremiumPrize_View
|
||||
hasServiceMessage = false
|
||||
}
|
||||
case let .starGift(gift, convertStars, giftText, giftEntities, _, savedToProfile, converted, _, _):
|
||||
case let .starGift(gift, convertStars, giftText, giftEntities, _, savedToProfile, converted, upgraded, _, upgradeStars, isRefunded):
|
||||
if case let .generic(gift) = gift {
|
||||
isStarGift = true
|
||||
let authorName = item.message.author.flatMap { EnginePeer($0) }?.compactDisplayTitle ?? ""
|
||||
@ -415,7 +476,9 @@ public class ChatMessageGiftBubbleContentNode: ChatMessageBubbleContentNode {
|
||||
text = giftText
|
||||
entities = giftEntities ?? []
|
||||
} else {
|
||||
if incoming {
|
||||
if isRefunded {
|
||||
text = item.presentationData.strings.Notification_StarGift_Subtitle_Refunded
|
||||
} else if incoming {
|
||||
if converted {
|
||||
text = item.presentationData.strings.Notification_StarGift_Subtitle_Converted(item.presentationData.strings.Notification_StarGift_Subtitle_Converted_Stars(Int32(convertStars ?? 0))).string
|
||||
} else if savedToProfile {
|
||||
@ -461,26 +524,49 @@ public class ChatMessageGiftBubbleContentNode: ChatMessageBubbleContentNode {
|
||||
}
|
||||
ribbonTitle = item.presentationData.strings.Notification_StarGift_OneOf(availabilityString).string
|
||||
}
|
||||
if incoming {
|
||||
buttonTitle = item.presentationData.strings.Notification_StarGift_View
|
||||
if incoming, let upgradeStars, upgradeStars > 0, !upgraded {
|
||||
buttonTitle = item.presentationData.strings.Notification_StarGift_Unpack
|
||||
buttonIcon = "Premium/GiftUnpack"
|
||||
} else {
|
||||
buttonTitle = ""
|
||||
buttonTitle = item.presentationData.strings.Notification_StarGift_View
|
||||
}
|
||||
}
|
||||
case let .starGiftUnique(gift, _, _, _, _, _):
|
||||
case let .starGiftUnique(gift, _, _, _, _, _, isRefunded):
|
||||
if case let .unique(uniqueGift) = gift {
|
||||
isStarGift = true
|
||||
let authorName = item.message.author.flatMap { EnginePeer($0) }?.compactDisplayTitle ?? ""
|
||||
title = item.presentationData.strings.Notification_StarGift_Title(authorName).string
|
||||
text = "**\(uniqueGift.title) #\(uniqueGift.number)**"
|
||||
ribbonTitle = item.presentationData.strings.Notification_StarGift_Gift
|
||||
buttonTitle = item.presentationData.strings.Notification_StarGift_View
|
||||
modelTitle = item.presentationData.strings.Notification_StarGift_Model
|
||||
backdropTitle = item.presentationData.strings.Notification_StarGift_Backdrop
|
||||
symbolTitle = item.presentationData.strings.Notification_StarGift_Symbol
|
||||
|
||||
for attribute in uniqueGift.attributes {
|
||||
if case let .model(_, file, _) = attribute {
|
||||
switch attribute {
|
||||
case let .model(name, file, _):
|
||||
modelValue = name
|
||||
animationFile = file
|
||||
case let .backdrop(name, innerColor, outerColor, patternColor, _, _):
|
||||
uniqueBackgroundColor = UIColor(rgb: UInt32(bitPattern: outerColor))
|
||||
uniqueSecondBackgroundColor = UIColor(rgb: UInt32(bitPattern: innerColor))
|
||||
uniquePatternColor = UIColor(rgb: UInt32(bitPattern: patternColor))
|
||||
backdropValue = name
|
||||
subtitleColor = UIColor(rgb: UInt32(bitPattern: innerColor)).withMultiplied(hue: 1.0, saturation: 1.02, brightness: 1.25).mixedWith(UIColor.white, alpha: 0.3)
|
||||
case let .pattern(name, file, _):
|
||||
symbolValue = name
|
||||
uniquePatternFile = file
|
||||
default:
|
||||
break
|
||||
}
|
||||
}
|
||||
//TODO:localize
|
||||
ribbonTitle = "gift"
|
||||
buttonTitle = item.presentationData.strings.Notification_StarGift_View
|
||||
} else if isRefunded, case let .generic(gift) = gift {
|
||||
isStarGift = true
|
||||
let authorName = item.message.author.flatMap { EnginePeer($0) }?.compactDisplayTitle ?? ""
|
||||
title = item.presentationData.strings.Notification_StarGift_Title(authorName).string
|
||||
text = item.presentationData.strings.Notification_StarGift_Subtitle_Refunded
|
||||
animationFile = gift.file
|
||||
}
|
||||
default:
|
||||
break
|
||||
@ -510,9 +596,9 @@ public class ChatMessageGiftBubbleContentNode: ChatMessageBubbleContentNode {
|
||||
attributedText = stringWithAppliedEntities(text, entities: entities, baseColor: primaryTextColor, linkColor: primaryTextColor, baseFont: Font.regular(13.0), linkFont: Font.regular(13.0), boldFont: Font.semibold(13.0), italicFont: Font.italic(13.0), boldItalicFont: Font.semiboldItalic(13.0), fixedFont: Font.monospace(13.0), blockQuoteFont: Font.regular(13.0), message: nil)
|
||||
} else {
|
||||
attributedText = parseMarkdownIntoAttributedString(text, attributes: MarkdownAttributes(
|
||||
body: MarkdownAttributeSet(font: Font.regular(13.0), textColor: primaryTextColor),
|
||||
bold: MarkdownAttributeSet(font: Font.semibold(13.0), textColor: primaryTextColor),
|
||||
link: MarkdownAttributeSet(font: Font.regular(13.0), textColor: primaryTextColor),
|
||||
body: MarkdownAttributeSet(font: Font.regular(13.0), textColor: subtitleColor),
|
||||
bold: MarkdownAttributeSet(font: Font.semibold(13.0), textColor: subtitleColor),
|
||||
link: MarkdownAttributeSet(font: Font.regular(13.0), textColor: subtitleColor),
|
||||
linkAttribute: { url in
|
||||
return ("URL", url)
|
||||
}
|
||||
@ -533,12 +619,57 @@ public class ChatMessageGiftBubbleContentNode: ChatMessageBubbleContentNode {
|
||||
clippedTextHeight = measuredTextLayout.size.height
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
let infoConstrainedSize = CGSize(width: (giftSize.width - 32.0) * 0.7, height: CGFloat.greatestFiniteMagnitude)
|
||||
let modelTitleLayoutAndApply: (TextNodeLayout, () -> TextNode)?
|
||||
if let modelTitle {
|
||||
modelTitleLayoutAndApply = makeModelTitleLayout(TextNodeLayoutArguments(attributedString: NSAttributedString(string: modelTitle, font: Font.regular(13.0), textColor: subtitleColor), backgroundColor: nil, maximumNumberOfLines: 1, truncationType: .end, constrainedSize: infoConstrainedSize, alignment: .center, cutout: nil, insets: UIEdgeInsets()))
|
||||
} else {
|
||||
modelTitleLayoutAndApply = nil
|
||||
}
|
||||
let modelValueLayoutAndApply: (TextNodeLayout, () -> TextNode)?
|
||||
if let modelValue {
|
||||
modelValueLayoutAndApply = makeModelValueLayout(TextNodeLayoutArguments(attributedString: NSAttributedString(string: modelValue, font: Font.semibold(13.0), textColor: primaryTextColor), backgroundColor: nil, maximumNumberOfLines: 1, truncationType: .end, constrainedSize: infoConstrainedSize, alignment: .center, cutout: nil, insets: UIEdgeInsets()))
|
||||
} else {
|
||||
modelValueLayoutAndApply = nil
|
||||
}
|
||||
|
||||
let backdropTitleLayoutAndApply: (TextNodeLayout, () -> TextNode)?
|
||||
if let backdropTitle {
|
||||
backdropTitleLayoutAndApply = makeBackdropTitleLayout(TextNodeLayoutArguments(attributedString: NSAttributedString(string: backdropTitle, font: Font.regular(13.0), textColor: subtitleColor), backgroundColor: nil, maximumNumberOfLines: 1, truncationType: .end, constrainedSize: infoConstrainedSize, alignment: .center, cutout: nil, insets: UIEdgeInsets()))
|
||||
} else {
|
||||
backdropTitleLayoutAndApply = nil
|
||||
}
|
||||
let backdropValueLayoutAndApply: (TextNodeLayout, () -> TextNode)?
|
||||
if let backdropValue {
|
||||
backdropValueLayoutAndApply = makeBackdropValueLayout(TextNodeLayoutArguments(attributedString: NSAttributedString(string: backdropValue, font: Font.semibold(13.0), textColor: primaryTextColor), backgroundColor: nil, maximumNumberOfLines: 1, truncationType: .end, constrainedSize: infoConstrainedSize, alignment: .center, cutout: nil, insets: UIEdgeInsets()))
|
||||
} else {
|
||||
backdropValueLayoutAndApply = nil
|
||||
}
|
||||
|
||||
let symbolTitleLayoutAndApply: (TextNodeLayout, () -> TextNode)?
|
||||
if let symbolTitle {
|
||||
symbolTitleLayoutAndApply = makeSymbolTitleLayout(TextNodeLayoutArguments(attributedString: NSAttributedString(string: symbolTitle, font: Font.regular(13.0), textColor: subtitleColor), backgroundColor: nil, maximumNumberOfLines: 1, truncationType: .end, constrainedSize: infoConstrainedSize, alignment: .center, cutout: nil, insets: UIEdgeInsets()))
|
||||
} else {
|
||||
symbolTitleLayoutAndApply = nil
|
||||
}
|
||||
let symbolValueLayoutAndApply: (TextNodeLayout, () -> TextNode)?
|
||||
if let symbolValue {
|
||||
symbolValueLayoutAndApply = makeSymbolValueLayout(TextNodeLayoutArguments(attributedString: NSAttributedString(string: symbolValue, font: Font.semibold(13.0), textColor: primaryTextColor), backgroundColor: nil, maximumNumberOfLines: 1, truncationType: .end, constrainedSize: infoConstrainedSize, alignment: .center, cutout: nil, insets: UIEdgeInsets()))
|
||||
} else {
|
||||
symbolValueLayoutAndApply = nil
|
||||
}
|
||||
|
||||
let (buttonTitleLayout, buttonTitleApply) = makeButtonTitleLayout(TextNodeLayoutArguments(attributedString: NSAttributedString(string: buttonTitle, font: Font.semibold(15.0), textColor: primaryTextColor, paragraphAlignment: .center), backgroundColor: nil, maximumNumberOfLines: 0, truncationType: .end, constrainedSize: CGSize(width: giftSize.width - 32.0, height: CGFloat.greatestFiniteMagnitude), alignment: .center, cutout: nil, insets: UIEdgeInsets()))
|
||||
|
||||
let (ribbonTextLayout, ribbonTextApply) = makeRibbonTextLayout(TextNodeLayoutArguments(attributedString: NSAttributedString(string: ribbonTitle, font: Font.semibold(11.0), textColor: primaryTextColor, paragraphAlignment: .center), backgroundColor: nil, maximumNumberOfLines: 0, truncationType: .end, constrainedSize: CGSize(width: giftSize.width - 32.0, height: CGFloat.greatestFiniteMagnitude), alignment: .center, cutout: nil, insets: UIEdgeInsets()))
|
||||
|
||||
giftSize.height = titleLayout.size.height + textSpacing + clippedTextHeight + 164.0
|
||||
|
||||
if let _ = modelTitle {
|
||||
giftSize.height += 70.0
|
||||
}
|
||||
|
||||
if !buttonTitle.isEmpty {
|
||||
giftSize.height += 48.0
|
||||
}
|
||||
@ -614,6 +745,7 @@ public class ChatMessageGiftBubbleContentNode: ChatMessageBubbleContentNode {
|
||||
|
||||
strongSelf.buttonNode.isHidden = buttonTitle.isEmpty
|
||||
strongSelf.buttonTitleNode.isHidden = buttonTitle.isEmpty
|
||||
strongSelf.buttonIconNode.isHidden = buttonIcon == nil
|
||||
|
||||
if strongSelf.item == nil {
|
||||
strongSelf.animationNode.started = { [weak self] in
|
||||
@ -677,7 +809,7 @@ public class ChatMessageGiftBubbleContentNode: ChatMessageBubbleContentNode {
|
||||
let titleFrame = CGRect(origin: CGPoint(x: mediaBackgroundFrame.minX + floorToScreenPixels((mediaBackgroundFrame.width - titleLayout.size.width) / 2.0) , y: mediaBackgroundFrame.minY + 151.0), size: titleLayout.size)
|
||||
strongSelf.titleNode.frame = titleFrame
|
||||
|
||||
let clippingTextFrame = CGRect(origin: CGPoint(x: mediaBackgroundFrame.minX + floorToScreenPixels((mediaBackgroundFrame.width - subtitleLayout.size.width) / 2.0) , y: titleFrame.maxY + textSpacing), size: CGSize(width: subtitleLayout.size.width, height: clippedTextHeight))
|
||||
let clippingTextFrame = CGRect(origin: CGPoint(x: mediaBackgroundFrame.minX + floorToScreenPixels((mediaBackgroundFrame.width - subtitleLayout.size.width) / 2.0), y: titleFrame.maxY + textSpacing), size: CGSize(width: subtitleLayout.size.width, height: clippedTextHeight))
|
||||
|
||||
let subtitleFrame = CGRect(origin: .zero, size: subtitleLayout.size)
|
||||
strongSelf.subtitleNode.textNode.frame = subtitleFrame
|
||||
@ -727,19 +859,97 @@ public class ChatMessageGiftBubbleContentNode: ChatMessageBubbleContentNode {
|
||||
strongSelf.dustNode = nil
|
||||
}
|
||||
|
||||
let buttonSize = CGSize(width: buttonTitleLayout.size.width + 38.0, height: 34.0)
|
||||
strongSelf.buttonTitleNode.frame = CGRect(origin: CGPoint(x: floorToScreenPixels((buttonSize.width - buttonTitleLayout.size.width) / 2.0), y: 8.0), size: buttonTitleLayout.size)
|
||||
var middleX = mediaBackgroundFrame.width / 2.0
|
||||
if let (modelValueLayout, _) = modelValueLayoutAndApply, let (backdropValueLayout, _) = backdropValueLayoutAndApply, let (symbolValueLayout, _) = symbolValueLayoutAndApply {
|
||||
let maxWidth = max(modelValueLayout.size.width, max(backdropValueLayout.size.width, symbolValueLayout.size.width))
|
||||
middleX = min(mediaBackgroundFrame.width - maxWidth - 16.0, middleX)
|
||||
}
|
||||
|
||||
let titleMaxX: CGFloat = mediaBackgroundFrame.minX + middleX - 2.0
|
||||
let valueMinX: CGFloat = mediaBackgroundFrame.minX + middleX + 3.0
|
||||
|
||||
if let (modelTitleLayout, modelTitleApply) = modelTitleLayoutAndApply {
|
||||
if strongSelf.modelTitleTextNode.supernode == nil {
|
||||
strongSelf.addSubnode(strongSelf.modelTitleTextNode)
|
||||
}
|
||||
let _ = modelTitleApply()
|
||||
strongSelf.modelTitleTextNode.frame = CGRect(origin: CGPoint(x: titleMaxX - modelTitleLayout.size.width, y: clippingTextFrame.maxY + 10.0), size: modelTitleLayout.size)
|
||||
}
|
||||
|
||||
animation.animator.updateFrame(layer: strongSelf.buttonNode.layer, frame: CGRect(origin: CGPoint(x: mediaBackgroundFrame.minX + floorToScreenPixels((mediaBackgroundFrame.width - buttonSize.width) / 2.0), y: clippingTextFrame.maxY + 10.0), size: buttonSize), completion: nil)
|
||||
if let (modelValueLayout, modelValueApply) = modelValueLayoutAndApply {
|
||||
if strongSelf.modelValueTextNode.supernode == nil {
|
||||
strongSelf.addSubnode(strongSelf.modelValueTextNode)
|
||||
}
|
||||
let _ = modelValueApply()
|
||||
strongSelf.modelValueTextNode.frame = CGRect(origin: CGPoint(x: valueMinX, y: clippingTextFrame.maxY + 10.0), size: modelValueLayout.size)
|
||||
}
|
||||
|
||||
if let (backdropTitleLayout, backdropTitleApply) = backdropTitleLayoutAndApply {
|
||||
if strongSelf.backdropTitleTextNode.supernode == nil {
|
||||
strongSelf.addSubnode(strongSelf.backdropTitleTextNode)
|
||||
}
|
||||
let _ = backdropTitleApply()
|
||||
strongSelf.backdropTitleTextNode.frame = CGRect(origin: CGPoint(x: titleMaxX - backdropTitleLayout.size.width, y: clippingTextFrame.maxY + 32.0), size: backdropTitleLayout.size)
|
||||
}
|
||||
|
||||
if let (backdropValueLayout, backdropValueApply) = backdropValueLayoutAndApply {
|
||||
if strongSelf.backdropValueTextNode.supernode == nil {
|
||||
strongSelf.addSubnode(strongSelf.backdropValueTextNode)
|
||||
}
|
||||
let _ = backdropValueApply()
|
||||
strongSelf.backdropValueTextNode.frame = CGRect(origin: CGPoint(x: valueMinX, y: clippingTextFrame.maxY + 32.0), size: backdropValueLayout.size)
|
||||
}
|
||||
|
||||
if let (symbolTitleLayout, symbolTitleApply) = symbolTitleLayoutAndApply {
|
||||
if strongSelf.symbolTitleTextNode.supernode == nil {
|
||||
strongSelf.addSubnode(strongSelf.symbolTitleTextNode)
|
||||
}
|
||||
let _ = symbolTitleApply()
|
||||
strongSelf.symbolTitleTextNode.frame = CGRect(origin: CGPoint(x: titleMaxX - symbolTitleLayout.size.width, y: clippingTextFrame.maxY + 54.0), size: symbolTitleLayout.size)
|
||||
}
|
||||
|
||||
if let (symbolValueLayout, symbolValueApply) = symbolValueLayoutAndApply {
|
||||
if strongSelf.symbolValueTextNode.supernode == nil {
|
||||
strongSelf.addSubnode(strongSelf.symbolValueTextNode)
|
||||
}
|
||||
let _ = symbolValueApply()
|
||||
strongSelf.symbolValueTextNode.frame = CGRect(origin: CGPoint(x: valueMinX, y: clippingTextFrame.maxY + 54.0), size: symbolValueLayout.size)
|
||||
}
|
||||
|
||||
var buttonSize = CGSize(width: buttonTitleLayout.size.width + 38.0, height: 34.0)
|
||||
var buttonOriginY = clippingTextFrame.maxY + 10.0
|
||||
if modelTitleLayoutAndApply != nil {
|
||||
buttonOriginY = clippingTextFrame.maxY + 80.0
|
||||
}
|
||||
if let buttonIcon {
|
||||
buttonSize.width += 15.0
|
||||
if strongSelf.buttonIconNode.image == nil {
|
||||
strongSelf.buttonIconNode.image = generateTintedImage(image: UIImage(bundleImageName: buttonIcon), color: .white)
|
||||
}
|
||||
}
|
||||
strongSelf.buttonTitleNode.frame = CGRect(origin: CGPoint(x: 19.0, y: 8.0), size: buttonTitleLayout.size)
|
||||
strongSelf.buttonIconNode.frame = CGRect(origin: CGPoint(x: buttonSize.width - 30.0, y: 9.0), size: CGSize(width: 14.0, height: 14.0))
|
||||
|
||||
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)
|
||||
|
||||
if ribbonTextLayout.size.width > 0.0 {
|
||||
if strongSelf.ribbonBackgroundNode.image == nil {
|
||||
let ribbonImage = generateTintedImage(image: UIImage(bundleImageName: "Chat/Message/GiftRibbon"), color: overlayColor)
|
||||
strongSelf.ribbonBackgroundNode.image = ribbonImage
|
||||
if let uniqueBackgroundColor {
|
||||
let colors = [
|
||||
uniqueBackgroundColor.withMultiplied(hue: 0.97, saturation: 1.45, brightness: 0.89),
|
||||
uniqueBackgroundColor.withMultiplied(hue: 1.01, saturation: 1.22, brightness: 1.04)
|
||||
]
|
||||
strongSelf.ribbonBackgroundNode.image = generateGradientTintedImage(image: UIImage(bundleImageName: "Premium/GiftRibbon"), colors: colors, direction: .mirroredDiagonal)
|
||||
} else {
|
||||
strongSelf.ribbonBackgroundNode.image = generateTintedImage(image: UIImage(bundleImageName: "Chat/Message/GiftRibbon"), color: overlayColor)
|
||||
}
|
||||
}
|
||||
if let ribbonImage = strongSelf.ribbonBackgroundNode.image {
|
||||
let ribbonFrame = CGRect(origin: CGPoint(x: mediaBackgroundFrame.maxX - ribbonImage.size.width + 2.0, y: mediaBackgroundFrame.minY - 2.0), size: ribbonImage.size)
|
||||
var ribbonFrame = CGRect(origin: CGPoint(x: mediaBackgroundFrame.maxX - ribbonImage.size.width + 2.0, y: mediaBackgroundFrame.minY - 2.0), size: ribbonImage.size)
|
||||
if let _ = uniqueBackgroundColor {
|
||||
ribbonFrame = ribbonFrame.offsetBy(dx: -4.0, dy: 4.0)
|
||||
}
|
||||
strongSelf.ribbonBackgroundNode.frame = ribbonFrame
|
||||
|
||||
strongSelf.ribbonTextNode.transform = CATransform3DMakeRotation(.pi / 4.0, 0.0, 0.0, 1.0)
|
||||
@ -757,7 +967,7 @@ public class ChatMessageGiftBubbleContentNode: ChatMessageBubbleContentNode {
|
||||
}
|
||||
|
||||
if let backgroundContent = strongSelf.mediaBackgroundContent {
|
||||
if ribbonTextLayout.size.width > 0.0 {
|
||||
if ribbonTextLayout.size.width > 0.0, uniqueBackgroundColor == nil {
|
||||
let backgroundMaskFrame = mediaBackgroundFrame.insetBy(dx: -2.0, dy: -2.0)
|
||||
backgroundContent.frame = backgroundMaskFrame
|
||||
animation.animator.updateFrame(layer: backgroundContent.layer, frame: backgroundMaskFrame, completion: nil)
|
||||
@ -787,6 +997,36 @@ public class ChatMessageGiftBubbleContentNode: ChatMessageBubbleContentNode {
|
||||
}
|
||||
}
|
||||
|
||||
if let uniqueBackgroundColor, let uniqueSecondBackgroundColor, let uniquePatternColor, let uniquePatternFile {
|
||||
let patternInset: CGFloat = 4.0
|
||||
let patternSize = CGSize(width: mediaBackgroundFrame.width - patternInset * 2.0, height: mediaBackgroundFrame.height - patternInset * 2.0)
|
||||
let files: [Int64: TelegramMediaFile] = [uniquePatternFile.fileId.id: uniquePatternFile]
|
||||
let _ = strongSelf.patternView.update(
|
||||
transition: .immediate,
|
||||
component: AnyComponent(PeerInfoCoverComponent(
|
||||
context: item.context,
|
||||
subject: .custom(uniqueBackgroundColor, uniqueSecondBackgroundColor, uniquePatternColor, uniquePatternFile.fileId.id),
|
||||
files: files,
|
||||
isDark: false,
|
||||
avatarCenter: CGPoint(x: patternSize.width / 2.0, y: 106.0),
|
||||
avatarScale: 1.0,
|
||||
defaultHeight: patternSize.height,
|
||||
avatarTransitionFraction: 0.0,
|
||||
patternTransitionFraction: 0.0
|
||||
)),
|
||||
environment: {},
|
||||
containerSize: patternSize
|
||||
)
|
||||
if let backgroundView = strongSelf.patternView.view {
|
||||
if backgroundView.superview == nil {
|
||||
backgroundView.layer.cornerRadius = 20.0
|
||||
backgroundView.clipsToBounds = true
|
||||
strongSelf.view.insertSubview(backgroundView, belowSubview: strongSelf.titleNode.view)
|
||||
}
|
||||
backgroundView.frame = CGRect(origin: .zero, size: patternSize).offsetBy(dx: mediaBackgroundFrame.minX + patternInset, dy: mediaBackgroundFrame.minY + patternInset)
|
||||
}
|
||||
}
|
||||
|
||||
let baseBackgroundFrame = labelFrame.offsetBy(dx: 0.0, dy: -11.0)
|
||||
if let (offset, image) = backgroundMaskImage {
|
||||
if strongSelf.backgroundNode == nil {
|
||||
|
@ -909,7 +909,7 @@ public final class ChatTitleView: UIView, NavigationBarTitleView {
|
||||
var titleFrame: CGRect
|
||||
if size.height > 40.0 {
|
||||
var titleInsets: UIEdgeInsets = .zero
|
||||
if verifiedIconWidth > 0.0 {
|
||||
if case .emojiStatus = self.titleVerifiedIcon, verifiedIconWidth > 0.0 {
|
||||
titleInsets.left = verifiedIconWidth + 2.0
|
||||
}
|
||||
|
||||
@ -951,7 +951,18 @@ public final class ChatTitleView: UIView, NavigationBarTitleView {
|
||||
|
||||
var nextIconX: CGFloat = titleFrame.width
|
||||
|
||||
self.titleVerifiedIconView.frame = CGRect(origin: CGPoint(x: 0.0, y: floor((titleFrame.height - titleVerifiedSize.height) / 2.0)), size: titleVerifiedSize)
|
||||
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.titleCredibilityIconView.frame = CGRect(origin: CGPoint(x: nextIconX - titleCredibilitySize.width, y: floor((titleFrame.height - titleCredibilitySize.height) / 2.0)), size: titleCredibilitySize)
|
||||
nextIconX -= titleCredibilitySize.width
|
||||
|
@ -26,6 +26,7 @@ swift_library(
|
||||
"//submodules/Components/ViewControllerComponent",
|
||||
"//submodules/Components/BundleIconComponent",
|
||||
"//submodules/Components/MultilineTextComponent",
|
||||
"//submodules/Components/MultilineTextWithEntitiesComponent",
|
||||
"//submodules/Components/BalancedTextComponent",
|
||||
"//submodules/TelegramUI/Components/ListSectionComponent",
|
||||
"//submodules/TelegramUI/Components/ListActionItemComponent",
|
||||
@ -45,6 +46,7 @@ swift_library(
|
||||
"//submodules/InAppPurchaseManager",
|
||||
"//submodules/Components/BlurredBackgroundComponent",
|
||||
"//submodules/ProgressNavigationButtonNode",
|
||||
"//submodules/TelegramUI/Components/Gifts/GiftViewScreen",
|
||||
],
|
||||
visibility = [
|
||||
"//visibility:public",
|
||||
|
@ -143,6 +143,9 @@ final class ChatGiftPreviewItem: ListViewItem, ItemListItem, ListItemComponentAd
|
||||
if lhs.entities != rhs.entities {
|
||||
return false
|
||||
}
|
||||
if lhs.includeUpgrade != rhs.includeUpgrade {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
}
|
||||
@ -224,7 +227,7 @@ final class ChatGiftPreviewItemNode: ListViewItemNode {
|
||||
case let .starGift(gift):
|
||||
media = [
|
||||
TelegramMediaAction(
|
||||
action: .starGift(gift: .generic(gift), convertStars: gift.convertStars, text: item.text, entities: item.entities, nameHidden: false, savedToProfile: false, converted: false, upgraded: false, upgradeStars: item.includeUpgrade ? 0 : gift.upgradeStars)
|
||||
action: .starGift(gift: .generic(gift), convertStars: gift.convertStars, text: item.text, entities: item.entities, nameHidden: false, savedToProfile: false, converted: false, upgraded: false, canUpgrade: true, upgradeStars: item.includeUpgrade ? gift.upgradeStars : 0, isRefunded: false)
|
||||
)
|
||||
]
|
||||
}
|
||||
|
@ -13,6 +13,7 @@ import AccountContext
|
||||
import ComponentFlow
|
||||
import ViewControllerComponent
|
||||
import MultilineTextComponent
|
||||
import MultilineTextWithEntitiesComponent
|
||||
import BalancedTextComponent
|
||||
import ListSectionComponent
|
||||
import ListActionItemComponent
|
||||
@ -32,6 +33,7 @@ import InAppPurchaseManager
|
||||
import BlurredBackgroundComponent
|
||||
import ProgressNavigationButtonNode
|
||||
import Markdown
|
||||
import GiftViewScreen
|
||||
|
||||
final class GiftSetupScreenComponent: Component {
|
||||
typealias EnvironmentType = ViewControllerComponentContainer.Environment
|
||||
@ -131,6 +133,7 @@ final class GiftSetupScreenComponent: Component {
|
||||
}
|
||||
}
|
||||
private let optionsPromise = ValuePromise<[StarsTopUpOption]?>(nil)
|
||||
private let previewPromise = Promise<[StarGift.UniqueGift.Attribute]?>(nil)
|
||||
|
||||
private var cachedChevronImage: (UIImage, PresentationTheme)?
|
||||
|
||||
@ -578,7 +581,7 @@ final class GiftSetupScreenComponent: Component {
|
||||
}
|
||||
)
|
||||
|
||||
if case .starGift = component.subject {
|
||||
if case let .starGift(gift) = component.subject {
|
||||
self.optionsDisposable = (component.context.engine.payments.starsTopUpOptions()
|
||||
|> deliverOnMainQueue).start(next: { [weak self] options in
|
||||
guard let self else {
|
||||
@ -586,6 +589,13 @@ final class GiftSetupScreenComponent: Component {
|
||||
}
|
||||
self.options = options
|
||||
})
|
||||
|
||||
if let _ = gift.upgradeStars {
|
||||
self.previewPromise.set(
|
||||
component.context.engine.payments.starGiftUpgradePreview(giftId: gift.id)
|
||||
|> map(Optional.init)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -845,6 +855,13 @@ final class GiftSetupScreenComponent: Component {
|
||||
upgradeFooterText.addAttribute(.attachment, value: chevronImage, range: NSRange(range, in: upgradeFooterText.string))
|
||||
}
|
||||
|
||||
let upgradeAttributedText = NSMutableAttributedString(string: environment.strings.Gift_Send_Upgrade("#\(upgradeStars)").string, font: Font.regular(presentationData.listsFontSize.baseDisplaySize), textColor: environment.theme.list.itemPrimaryTextColor)
|
||||
let range = (upgradeAttributedText.string as NSString).range(of: "#")
|
||||
if range.location != NSNotFound {
|
||||
upgradeAttributedText.addAttribute(ChatTextInputAttributes.customEmoji, value: ChatTextInputTextCustomEmojiAttribute(interactivelySelectedFromPackId: nil, fileId: 0, file: nil, custom: .stars(tinted: false)), range: range)
|
||||
upgradeAttributedText.addAttribute(.baselineOffset, value: 1.0, range: range)
|
||||
}
|
||||
|
||||
let upgradeSectionSize = self.upgradeSection.update(
|
||||
transition: transition,
|
||||
component: AnyComponent(ListSectionComponent(
|
||||
@ -852,20 +869,47 @@ final class GiftSetupScreenComponent: Component {
|
||||
header: nil,
|
||||
footer: AnyComponent(MultilineTextComponent(
|
||||
text: .plain(upgradeFooterText),
|
||||
maximumNumberOfLines: 0
|
||||
maximumNumberOfLines: 0,
|
||||
highlightColor: environment.theme.list.itemAccentColor.withAlphaComponent(0.1),
|
||||
highlightInset: UIEdgeInsets(top: 0.0, left: 0.0, bottom: 0.0, right: -8.0),
|
||||
highlightAction: { attributes in
|
||||
if let _ = attributes[NSAttributedString.Key(rawValue: TelegramTextAttributes.URL)] {
|
||||
return NSAttributedString.Key(rawValue: TelegramTextAttributes.URL)
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
},
|
||||
tapAction: { [weak self] _, _ in
|
||||
guard let self else {
|
||||
return
|
||||
}
|
||||
let _ = (self.previewPromise.get()
|
||||
|> take(1)
|
||||
|> deliverOnMainQueue).start(next: { [weak self] attributes in
|
||||
guard let self, let component = self.component, let controller = self.environment?.controller(), let attributes else {
|
||||
return
|
||||
}
|
||||
let previewController = GiftViewScreen(
|
||||
context: component.context,
|
||||
subject: .upgradePreview(attributes, peerName)
|
||||
)
|
||||
controller.push(previewController)
|
||||
})
|
||||
}
|
||||
)),
|
||||
items: [
|
||||
AnyComponentWithIdentity(id: 0, component: AnyComponent(ListActionItemComponent(
|
||||
theme: environment.theme,
|
||||
title: AnyComponent(VStack([
|
||||
AnyComponentWithIdentity(id: AnyHashable(0), component: AnyComponent(MultilineTextComponent(
|
||||
text: .plain(NSAttributedString(
|
||||
string: environment.strings.Gift_Send_Upgrade("\(upgradeStars)").string,
|
||||
font: Font.regular(presentationData.listsFontSize.baseDisplaySize),
|
||||
textColor: environment.theme.list.itemPrimaryTextColor
|
||||
)),
|
||||
maximumNumberOfLines: 1
|
||||
))),
|
||||
AnyComponentWithIdentity(id: AnyHashable(0), component: AnyComponent(
|
||||
MultilineTextWithEntitiesComponent(
|
||||
context: component.context,
|
||||
animationCache: component.context.animationCache,
|
||||
animationRenderer: component.context.animationRenderer,
|
||||
placeholderColor: environment.theme.list.mediaPlaceholderColor,
|
||||
text: .plain(upgradeAttributedText)
|
||||
)
|
||||
)),
|
||||
], alignment: .left, spacing: 2.0)),
|
||||
accessory: .toggle(ListActionItemComponent.Toggle(style: .regular, isOn: self.includeUpgrade, action: { [weak self] _ in
|
||||
guard let self else {
|
||||
@ -982,7 +1026,11 @@ final class GiftSetupScreenComponent: Component {
|
||||
let amountString = product.price
|
||||
buttonString = "\(environment.strings.Gift_Send_Send) \(amountString)"
|
||||
case let .starGift(starGift):
|
||||
let amountString = presentationStringsFormattedNumber(Int32(starGift.price), presentationData.dateTimeFormat.groupingSeparator)
|
||||
var finalPrice: Int64 = starGift.price
|
||||
if self.includeUpgrade, let upgradePrice = starGift.upgradeStars {
|
||||
finalPrice += upgradePrice
|
||||
}
|
||||
let amountString = presentationStringsFormattedNumber(Int32(finalPrice), presentationData.dateTimeFormat.groupingSeparator)
|
||||
buttonString = "\(environment.strings.Gift_Send_Send) # \(amountString)"
|
||||
if let availability = starGift.availability, availability.remains == 0 {
|
||||
buttonIsEnabled = false
|
||||
|
@ -14,6 +14,13 @@ import AnimatedStickerNode
|
||||
import TelegramAnimatedStickerNode
|
||||
|
||||
final class GiftCompositionComponent: Component {
|
||||
public class ExternalState {
|
||||
public fileprivate(set) var previewPatternColor: UIColor?
|
||||
public init() {
|
||||
self.previewPatternColor = nil
|
||||
}
|
||||
}
|
||||
|
||||
enum Subject: Equatable {
|
||||
case generic(TelegramMediaFile)
|
||||
case unique(StarGift.UniqueGift)
|
||||
@ -23,15 +30,21 @@ final class GiftCompositionComponent: Component {
|
||||
let context: AccountContext
|
||||
let theme: PresentationTheme
|
||||
let subject: Subject
|
||||
let externalState: ExternalState
|
||||
let requestUpdate: () -> Void
|
||||
|
||||
init(
|
||||
context: AccountContext,
|
||||
theme: PresentationTheme,
|
||||
subject: Subject
|
||||
subject: Subject,
|
||||
externalState: ExternalState,
|
||||
requestUpdate: @escaping () -> Void
|
||||
) {
|
||||
self.context = context
|
||||
self.theme = theme
|
||||
self.subject = subject
|
||||
self.externalState = externalState
|
||||
self.requestUpdate = requestUpdate
|
||||
}
|
||||
|
||||
static func ==(lhs: GiftCompositionComponent, rhs: GiftCompositionComponent) -> Bool {
|
||||
@ -193,6 +206,8 @@ final class GiftCompositionComponent: Component {
|
||||
self.previewTimer?.start()
|
||||
}
|
||||
}
|
||||
|
||||
component.externalState.previewPatternColor = secondBackgroundColor
|
||||
|
||||
var animateTransition = false
|
||||
if self.animatePreviewTransition {
|
||||
@ -200,6 +215,10 @@ final class GiftCompositionComponent: Component {
|
||||
self.animatePreviewTransition = false
|
||||
} else if let previousComponent, case .preview = previousComponent.subject, case .unique = component.subject {
|
||||
animateTransition = true
|
||||
} else if let previousComponent, case .generic = previousComponent.subject, case .preview = component.subject {
|
||||
animateTransition = true
|
||||
} else if let previousComponent, case .preview = previousComponent.subject, case .generic = component.subject {
|
||||
animateTransition = true
|
||||
}
|
||||
|
||||
if let backgroundColor {
|
||||
@ -235,7 +254,7 @@ final class GiftCompositionComponent: Component {
|
||||
backgroundTransition.setFrame(view: backgroundView, frame: CGRect(origin: .zero, size: availableSize))
|
||||
}
|
||||
} else if let backgroundView = self.background.view, backgroundView.superview != nil {
|
||||
backgroundView.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.25, completion: { _ in
|
||||
backgroundView.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.25, removeOnCompletion: false, completion: { _ in
|
||||
backgroundView.removeFromSuperview()
|
||||
})
|
||||
}
|
||||
@ -264,7 +283,6 @@ final class GiftCompositionComponent: Component {
|
||||
|
||||
if let startFromIndex {
|
||||
animationNode.play(firstFrame: false, fromIndex: startFromIndex)
|
||||
//animationNode.seekTo(.frameIndex(startFromIndex))
|
||||
} else {
|
||||
animationNode.playLoop()
|
||||
}
|
||||
@ -276,31 +294,6 @@ final class GiftCompositionComponent: Component {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// if self.animationLayer == nil, let animationFile {
|
||||
// let emoji = ChatTextInputTextCustomEmojiAttribute(
|
||||
// interactivelySelectedFromPackId: nil,
|
||||
// fileId: animationFile.fileId.id,
|
||||
// file: animationFile
|
||||
// )
|
||||
//
|
||||
// let animationLayer = InlineStickerItemLayer(
|
||||
// context: .account(component.context),
|
||||
// userLocation: .other,
|
||||
// attemptSynchronousLoad: false,
|
||||
// emoji: emoji,
|
||||
// file: animationFile,
|
||||
// cache: component.context.animationCache,
|
||||
// renderer: component.context.animationRenderer,
|
||||
// unique: true,
|
||||
// placeholderColor: component.theme.list.mediaPlaceholderColor,
|
||||
// pointSize: CGSize(width: iconSize.width * 1.2, height: iconSize.height * 1.2),
|
||||
// loopCount: 1
|
||||
// )
|
||||
// animationLayer.isVisibleForAnimations = true
|
||||
// self.animationLayer = animationLayer
|
||||
// self.layer.addSublayer(animationLayer)
|
||||
// }
|
||||
if let animationNode = self.animationNode {
|
||||
transition.setFrame(layer: animationNode.layer, frame: CGRect(origin: CGPoint(x: floorToScreenPixels((availableSize.width - iconSize.width) / 2.0), y: 25.0), size: iconSize))
|
||||
}
|
||||
|
@ -51,7 +51,7 @@ private final class GiftViewSheetContent: CombinedComponent {
|
||||
init(
|
||||
context: AccountContext,
|
||||
subject: GiftViewScreen.Subject,
|
||||
cancel: @escaping (Bool) -> Void,
|
||||
cancel: @escaping (Bool) -> Void,
|
||||
openPeer: @escaping (EnginePeer) -> Void,
|
||||
updateSavedToProfile: @escaping (Bool) -> Void,
|
||||
convertToStars: @escaping () -> Void,
|
||||
@ -108,11 +108,13 @@ private final class GiftViewSheetContent: CombinedComponent {
|
||||
var inProgress = false
|
||||
|
||||
var inUpgradePreview = false
|
||||
var upgradeForm: BotPaymentForm?
|
||||
var upgradeDisposable: Disposable?
|
||||
|
||||
var sampleGiftAttributes: [StarGift.UniqueGift.Attribute]?
|
||||
var sampleDisposable: Disposable?
|
||||
let sampleDisposable = DisposableSet()
|
||||
|
||||
var keepOriginalInfo = false
|
||||
var upgradeDisposable: Disposable?
|
||||
|
||||
private var optionsDisposable: Disposable?
|
||||
private(set) var options: [StarsTopUpOption] = [] {
|
||||
@ -151,15 +153,40 @@ private final class GiftViewSheetContent: CombinedComponent {
|
||||
break
|
||||
}
|
||||
}
|
||||
} else if case let .generic(gift) = arguments.gift, let _ = arguments.upgradeStars {
|
||||
self.sampleDisposable = (context.engine.payments.starGiftUpgradePreview(giftId: gift.id)
|
||||
|> deliverOnMainQueue).start(next: { [weak self] attributes in
|
||||
guard let self else {
|
||||
return
|
||||
} else if case let .generic(gift) = arguments.gift {
|
||||
if arguments.canUpgrade || arguments.upgradeStars != nil {
|
||||
self.sampleDisposable.add((context.engine.payments.starGiftUpgradePreview(giftId: gift.id)
|
||||
|> deliverOnMainQueue).start(next: { [weak self] attributes in
|
||||
guard let self else {
|
||||
return
|
||||
}
|
||||
self.sampleGiftAttributes = attributes
|
||||
|
||||
for attribute in attributes {
|
||||
switch attribute {
|
||||
case let .model(_, file, _):
|
||||
self.sampleDisposable.add(freeMediaFileResourceInteractiveFetched(account: self.context.account, userLocation: .other, fileReference: .standalone(media: file), resource: file.resource).start())
|
||||
case let .pattern(_, file, _):
|
||||
self.sampleDisposable.add(freeMediaFileResourceInteractiveFetched(account: self.context.account, userLocation: .other, fileReference: .standalone(media: file), resource: file.resource).start())
|
||||
default:
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
self.updated()
|
||||
}))
|
||||
|
||||
if arguments.upgradeStars == nil, let messageId = arguments.messageId {
|
||||
self.upgradeDisposable = (context.engine.payments.fetchBotPaymentForm(source: .starGiftUpgrade(keepOriginalInfo: false, messageId: messageId), themeParams: nil)
|
||||
|> deliverOnMainQueue).start(next: { [weak self] paymentForm in
|
||||
guard let self else {
|
||||
return
|
||||
}
|
||||
self.upgradeForm = paymentForm
|
||||
self.updated()
|
||||
})
|
||||
}
|
||||
self.sampleGiftAttributes = attributes
|
||||
self.updated()
|
||||
})
|
||||
}
|
||||
}
|
||||
self.disposable = combineLatest(queue: Queue.mainQueue(),
|
||||
context.engine.data.get(EngineDataMap(
|
||||
@ -209,7 +236,7 @@ private final class GiftViewSheetContent: CombinedComponent {
|
||||
|
||||
deinit {
|
||||
self.disposable?.dispose()
|
||||
self.sampleDisposable?.dispose()
|
||||
self.sampleDisposable.dispose()
|
||||
self.upgradeDisposable?.dispose()
|
||||
}
|
||||
|
||||
@ -217,20 +244,22 @@ private final class GiftViewSheetContent: CombinedComponent {
|
||||
guard let _ = self.subject.arguments?.upgradeStars else {
|
||||
return
|
||||
}
|
||||
self.context.starsContext?.load(force: false)
|
||||
|
||||
self.inUpgradePreview = true
|
||||
self.updated(transition: .spring(duration: 0.4))
|
||||
}
|
||||
|
||||
func commitUpgrade() {
|
||||
guard let arguments = self.subject.arguments, let messageId = arguments.messageId, let starsContext = self.context.starsContext, let starsState = starsContext.currentState, let upgradeStars = arguments.upgradeStars else {
|
||||
guard let arguments = self.subject.arguments, let messageId = arguments.messageId, let starsContext = self.context.starsContext, let starsState = starsContext.currentState else {
|
||||
return
|
||||
}
|
||||
let peerId = arguments.peerId
|
||||
let proceed: (Bool) -> Void = { prepaid in
|
||||
let proceed: (Int64?) -> Void = { formId in
|
||||
self.inProgress = true
|
||||
self.updated()
|
||||
|
||||
let _ = (self.context.engine.payments.upgradeStarGift(prepaid: prepaid, messageId: messageId, keepOriginalInfo: self.keepOriginalInfo)
|
||||
let _ = (self.context.engine.payments.upgradeStarGift(formId: formId, messageId: messageId, keepOriginalInfo: self.keepOriginalInfo)
|
||||
|> deliverOnMainQueue).start(next: { [weak self] result in
|
||||
guard let self, let controller = self.getController() as? GiftViewScreen else {
|
||||
return
|
||||
@ -245,8 +274,10 @@ private final class GiftViewSheetContent: CombinedComponent {
|
||||
})
|
||||
}
|
||||
|
||||
if upgradeStars > 0 {
|
||||
if starsState.balance < StarsAmount(value: upgradeStars, nanos: 0) {
|
||||
if let upgradeStars = arguments.upgradeStars, upgradeStars > 0 {
|
||||
proceed(nil)
|
||||
} else if let upgradeForm = self.upgradeForm, let price = upgradeForm.invoice.prices.first?.amount {
|
||||
if starsState.balance < StarsAmount(value: price, nanos: 0) {
|
||||
let _ = (self.optionsPromise.get()
|
||||
|> filter { $0 != nil }
|
||||
|> take(1)
|
||||
@ -258,21 +289,19 @@ private final class GiftViewSheetContent: CombinedComponent {
|
||||
context: self.context,
|
||||
starsContext: starsContext,
|
||||
options: options ?? [],
|
||||
purpose: .upgradeStarGift(requiredStars: upgradeStars),
|
||||
purpose: .upgradeStarGift(requiredStars: price),
|
||||
completion: { [weak starsContext] stars in
|
||||
starsContext?.add(balance: StarsAmount(value: stars, nanos: 0))
|
||||
Queue.mainQueue().after(2.0) {
|
||||
proceed(false)
|
||||
proceed(upgradeForm.id)
|
||||
}
|
||||
}
|
||||
)
|
||||
controller.push(purchaseController)
|
||||
})
|
||||
} else {
|
||||
proceed(false)
|
||||
proceed(upgradeForm.id)
|
||||
}
|
||||
} else {
|
||||
proceed(true)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -298,6 +327,8 @@ private final class GiftViewSheetContent: CombinedComponent {
|
||||
|
||||
let spaceRegex = try? NSRegularExpression(pattern: "\\[(.*?)\\]", options: [])
|
||||
|
||||
let giftCompositionExternalState = GiftCompositionComponent.ExternalState()
|
||||
|
||||
return { context in
|
||||
let environment = context.environment[ViewControllerComponentContainer.Environment.self].value
|
||||
|
||||
@ -326,6 +357,8 @@ private final class GiftViewSheetContent: CombinedComponent {
|
||||
var date: Int32?
|
||||
var soldOut = false
|
||||
var nameHidden = false
|
||||
var upgraded = false
|
||||
var canUpgrade = false
|
||||
var upgradeStars: Int64?
|
||||
var uniqueGift: StarGift.UniqueGift?
|
||||
if case let .soldOutGift(gift) = subject {
|
||||
@ -351,6 +384,8 @@ private final class GiftViewSheetContent: CombinedComponent {
|
||||
converted = arguments.converted
|
||||
giftId = gift.id
|
||||
date = arguments.date
|
||||
upgraded = arguments.upgraded
|
||||
canUpgrade = arguments.canUpgrade
|
||||
upgradeStars = arguments.upgradeStars
|
||||
case let .unique(gift):
|
||||
stars = 0
|
||||
@ -387,11 +422,27 @@ private final class GiftViewSheetContent: CombinedComponent {
|
||||
state.cachedOverlayCloseImage = closeOverlayImage
|
||||
}
|
||||
|
||||
var showUpgradePreview = false
|
||||
if state.inUpgradePreview, let _ = state.sampleGiftAttributes {
|
||||
showUpgradePreview = true
|
||||
} else if case .upgradePreview = component.subject {
|
||||
showUpgradePreview = true
|
||||
}
|
||||
|
||||
let cancel = component.cancel
|
||||
let closeButton = closeButton.update(
|
||||
component: Button(
|
||||
content: AnyComponent(Image(image: state.inUpgradePreview || uniqueGift != nil ? closeOverlayImage : closeImage)),
|
||||
action: { [weak component] in
|
||||
component?.cancel(true)
|
||||
content: AnyComponent(Image(image: showUpgradePreview || uniqueGift != nil ? closeOverlayImage : closeImage)),
|
||||
action: { [weak state] in
|
||||
guard let state else {
|
||||
return
|
||||
}
|
||||
if state.inUpgradePreview {
|
||||
state.inUpgradePreview = false
|
||||
state.updated(transition: .spring(duration: 0.4))
|
||||
} else {
|
||||
cancel(true)
|
||||
}
|
||||
}
|
||||
),
|
||||
availableSize: CGSize(width: 30.0, height: 30.0),
|
||||
@ -405,9 +456,12 @@ private final class GiftViewSheetContent: CombinedComponent {
|
||||
if let uniqueGift {
|
||||
animationHeight = 240.0
|
||||
animationSubject = .unique(uniqueGift)
|
||||
} else if state.inUpgradePreview, let sampleGiftAttributes = state.sampleGiftAttributes {
|
||||
} else if state.inUpgradePreview, let attributes = state.sampleGiftAttributes {
|
||||
animationHeight = 258.0
|
||||
animationSubject = .preview(sampleGiftAttributes)
|
||||
animationSubject = .preview(attributes)
|
||||
} else if case let .upgradePreview(attributes, _) = component.subject {
|
||||
animationHeight = 258.0
|
||||
animationSubject = .preview(attributes)
|
||||
} else if let animationFile {
|
||||
animationHeight = 210.0
|
||||
animationSubject = .generic(animationFile)
|
||||
@ -420,7 +474,11 @@ private final class GiftViewSheetContent: CombinedComponent {
|
||||
component: GiftCompositionComponent(
|
||||
context: component.context,
|
||||
theme: environment.theme,
|
||||
subject: animationSubject
|
||||
subject: animationSubject,
|
||||
externalState: giftCompositionExternalState,
|
||||
requestUpdate: { [weak state] in
|
||||
state?.updated()
|
||||
}
|
||||
),
|
||||
availableSize: CGSize(width: context.availableSize.width, height: animationHeight),
|
||||
transition: .immediate
|
||||
@ -430,13 +488,31 @@ private final class GiftViewSheetContent: CombinedComponent {
|
||||
)
|
||||
}
|
||||
originY += animationHeight
|
||||
|
||||
|
||||
if state.inUpgradePreview, let _ = state.sampleGiftAttributes {
|
||||
|
||||
if showUpgradePreview {
|
||||
let title: String
|
||||
let description: String
|
||||
let uniqueText: String
|
||||
let transferableText: String
|
||||
let tradableText: String
|
||||
if case let .upgradePreview(_, name) = component.subject {
|
||||
title = environment.strings.Gift_Upgrade_IncludeTitle
|
||||
description = environment.strings.Gift_Upgrade_IncludeDescription(name).string
|
||||
uniqueText = strings.Gift_Upgrade_Unique_IncludeDescription
|
||||
transferableText = strings.Gift_Upgrade_Transferable_IncludeDescription
|
||||
tradableText = strings.Gift_Upgrade_Tradable_IncludeDescription
|
||||
} else {
|
||||
title = environment.strings.Gift_Upgrade_Title
|
||||
description = environment.strings.Gift_Upgrade_Description
|
||||
uniqueText = strings.Gift_Upgrade_Unique_Description
|
||||
transferableText = strings.Gift_Upgrade_Transferable_Description
|
||||
tradableText = strings.Gift_Upgrade_Tradable_Description
|
||||
}
|
||||
|
||||
let upgradeTitle = upgradeTitle.update(
|
||||
component: MultilineTextComponent(
|
||||
text: .plain(NSAttributedString(
|
||||
string: environment.strings.Gift_Upgrade_Title,
|
||||
string: title,
|
||||
font: Font.bold(20.0),
|
||||
textColor: .white,
|
||||
paragraphAlignment: .center
|
||||
@ -447,18 +523,18 @@ private final class GiftViewSheetContent: CombinedComponent {
|
||||
availableSize: CGSize(width: context.availableSize.width - sideInset * 2.0 - 60.0, height: CGFloat.greatestFiniteMagnitude),
|
||||
transition: .immediate
|
||||
)
|
||||
context.add(upgradeTitle
|
||||
.position(CGPoint(x: context.availableSize.width / 2.0, y: 191.0))
|
||||
.appear(.default(alpha: true))
|
||||
.disappear(.default(alpha: true))
|
||||
)
|
||||
|
||||
let descriptionColor: UIColor
|
||||
if let previewPatternColor = giftCompositionExternalState.previewPatternColor {
|
||||
descriptionColor = previewPatternColor.withMultiplied(hue: 1.0, saturation: 1.02, brightness: 1.25).mixedWith(UIColor.white, alpha: 0.3)
|
||||
} else {
|
||||
descriptionColor = UIColor.white.withAlphaComponent(0.6)
|
||||
}
|
||||
let upgradeDescription = upgradeDescription.update(
|
||||
component: BalancedTextComponent(
|
||||
text: .plain(NSAttributedString(
|
||||
string: environment.strings.Gift_Upgrade_Description,
|
||||
string: description,
|
||||
font: Font.regular(13.0),
|
||||
textColor: UIColor.white.withAlphaComponent(0.6),
|
||||
textColor: descriptionColor,
|
||||
paragraphAlignment: .center
|
||||
)),
|
||||
horizontalAlignment: .center,
|
||||
@ -468,8 +544,18 @@ private final class GiftViewSheetContent: CombinedComponent {
|
||||
availableSize: CGSize(width: context.availableSize.width - sideInset * 2.0 - 50.0, height: CGFloat.greatestFiniteMagnitude),
|
||||
transition: .immediate
|
||||
)
|
||||
|
||||
let spacing: CGFloat = 6.0
|
||||
let totalHeight: CGFloat = upgradeTitle.size.height + spacing + upgradeDescription.size.height
|
||||
|
||||
context.add(upgradeTitle
|
||||
.position(CGPoint(x: context.availableSize.width / 2.0, y: floor(212.0 - totalHeight / 2.0 + upgradeTitle.size.height / 2.0)))
|
||||
.appear(.default(alpha: true))
|
||||
.disappear(.default(alpha: true))
|
||||
)
|
||||
|
||||
context.add(upgradeDescription
|
||||
.position(CGPoint(x: context.availableSize.width / 2.0, y: 208.0 + upgradeDescription.size.height / 2.0))
|
||||
.position(CGPoint(x: context.availableSize.width / 2.0, y: floor(212.0 + totalHeight / 2.0 - upgradeDescription.size.height / 2.0)))
|
||||
.appear(.default(alpha: true))
|
||||
.disappear(.default(alpha: true))
|
||||
)
|
||||
@ -486,7 +572,7 @@ private final class GiftViewSheetContent: CombinedComponent {
|
||||
component: AnyComponent(ParagraphComponent(
|
||||
title: strings.Gift_Upgrade_Unique_Title,
|
||||
titleColor: textColor,
|
||||
text: strings.Gift_Upgrade_Unique_Description,
|
||||
text: uniqueText,
|
||||
textColor: secondaryTextColor,
|
||||
accentColor: linkColor,
|
||||
iconName: "Premium/Collectible/Unique",
|
||||
@ -500,7 +586,7 @@ private final class GiftViewSheetContent: CombinedComponent {
|
||||
component: AnyComponent(ParagraphComponent(
|
||||
title: strings.Gift_Upgrade_Transferable_Title,
|
||||
titleColor: textColor,
|
||||
text: strings.Gift_Upgrade_Transferable_Description,
|
||||
text: transferableText,
|
||||
textColor: secondaryTextColor,
|
||||
accentColor: linkColor,
|
||||
iconName: "Premium/Collectible/Transferable",
|
||||
@ -514,7 +600,7 @@ private final class GiftViewSheetContent: CombinedComponent {
|
||||
component: AnyComponent(ParagraphComponent(
|
||||
title: strings.Gift_Upgrade_Tradable_Title,
|
||||
titleColor: textColor,
|
||||
text: strings.Gift_Upgrade_Tradable_Description,
|
||||
text: tradableText,
|
||||
textColor: secondaryTextColor,
|
||||
accentColor: linkColor,
|
||||
iconName: "Premium/Collectible/Tradable",
|
||||
@ -538,55 +624,59 @@ private final class GiftViewSheetContent: CombinedComponent {
|
||||
originY += upgradePerks.size.height
|
||||
originY += 16.0
|
||||
|
||||
let checkTheme = CheckComponent.Theme(
|
||||
backgroundColor: theme.list.itemCheckColors.fillColor,
|
||||
strokeColor: theme.list.itemCheckColors.foregroundColor,
|
||||
borderColor: theme.list.itemCheckColors.strokeColor,
|
||||
overlayBorder: false,
|
||||
hasInset: false,
|
||||
hasShadow: false
|
||||
)
|
||||
let keepInfoText: String
|
||||
if let nameHidden = subject.arguments?.nameHidden, nameHidden {
|
||||
keepInfoText = strings.Gift_Upgrade_AddMyName
|
||||
if case .upgradePreview = component.subject {
|
||||
|
||||
} else {
|
||||
keepInfoText = text != nil ? strings.Gift_Upgrade_AddNameAndComment : strings.Gift_Upgrade_AddName
|
||||
let checkTheme = CheckComponent.Theme(
|
||||
backgroundColor: theme.list.itemCheckColors.fillColor,
|
||||
strokeColor: theme.list.itemCheckColors.foregroundColor,
|
||||
borderColor: theme.list.itemCheckColors.strokeColor,
|
||||
overlayBorder: false,
|
||||
hasInset: false,
|
||||
hasShadow: false
|
||||
)
|
||||
let keepInfoText: String
|
||||
if let nameHidden = subject.arguments?.nameHidden, nameHidden {
|
||||
keepInfoText = strings.Gift_Upgrade_AddMyName
|
||||
} else {
|
||||
keepInfoText = text != nil ? strings.Gift_Upgrade_AddNameAndComment : strings.Gift_Upgrade_AddName
|
||||
}
|
||||
let upgradeKeepName = upgradeKeepName.update(
|
||||
component: PlainButtonComponent(
|
||||
content: AnyComponent(HStack([
|
||||
AnyComponentWithIdentity(id: AnyHashable(0), component: AnyComponent(CheckComponent(
|
||||
theme: checkTheme,
|
||||
size: CGSize(width: 18.0, height: 18.0),
|
||||
selected: state.keepOriginalInfo
|
||||
))),
|
||||
AnyComponentWithIdentity(id: AnyHashable(1), component: AnyComponent(MultilineTextComponent(
|
||||
text: .plain(NSAttributedString(string: keepInfoText, font: Font.regular(13.0), textColor: theme.list.itemSecondaryTextColor))
|
||||
)))
|
||||
],
|
||||
spacing: 10.0
|
||||
)),
|
||||
effectAlignment: .center,
|
||||
action: { [weak state] in
|
||||
guard let state else {
|
||||
return
|
||||
}
|
||||
state.keepOriginalInfo = !state.keepOriginalInfo
|
||||
state.updated(transition: .easeInOut(duration: 0.2))
|
||||
},
|
||||
animateAlpha: false,
|
||||
animateScale: false
|
||||
),
|
||||
availableSize: CGSize(width: context.availableSize.width - sideInset * 2.0, height: 1000.0),
|
||||
transition: context.transition
|
||||
)
|
||||
context.add(upgradeKeepName
|
||||
.position(CGPoint(x: context.availableSize.width / 2.0, y: originY + upgradeKeepName.size.height / 2.0))
|
||||
.appear(.default(alpha: true))
|
||||
.disappear(.default(alpha: true))
|
||||
)
|
||||
originY += upgradeKeepName.size.height
|
||||
originY += 18.0
|
||||
}
|
||||
let upgradeKeepName = upgradeKeepName.update(
|
||||
component: PlainButtonComponent(
|
||||
content: AnyComponent(HStack([
|
||||
AnyComponentWithIdentity(id: AnyHashable(0), component: AnyComponent(CheckComponent(
|
||||
theme: checkTheme,
|
||||
size: CGSize(width: 18.0, height: 18.0),
|
||||
selected: state.keepOriginalInfo
|
||||
))),
|
||||
AnyComponentWithIdentity(id: AnyHashable(1), component: AnyComponent(MultilineTextComponent(
|
||||
text: .plain(NSAttributedString(string: keepInfoText, font: Font.regular(13.0), textColor: theme.list.itemSecondaryTextColor))
|
||||
)))
|
||||
],
|
||||
spacing: 10.0
|
||||
)),
|
||||
effectAlignment: .center,
|
||||
action: { [weak state] in
|
||||
guard let state else {
|
||||
return
|
||||
}
|
||||
state.keepOriginalInfo = !state.keepOriginalInfo
|
||||
state.updated(transition: .easeInOut(duration: 0.2))
|
||||
},
|
||||
animateAlpha: false,
|
||||
animateScale: false
|
||||
),
|
||||
availableSize: CGSize(width: context.availableSize.width - sideInset * 2.0, height: 1000.0),
|
||||
transition: context.transition
|
||||
)
|
||||
context.add(upgradeKeepName
|
||||
.position(CGPoint(x: context.availableSize.width / 2.0, y: originY + upgradeKeepName.size.height / 2.0))
|
||||
.appear(.default(alpha: true))
|
||||
.disappear(.default(alpha: true))
|
||||
)
|
||||
originY += upgradeKeepName.size.height
|
||||
originY += 18.0
|
||||
} else {
|
||||
var descriptionText: String
|
||||
if let uniqueGift {
|
||||
@ -595,12 +685,18 @@ private final class GiftViewSheetContent: CombinedComponent {
|
||||
} else if soldOut {
|
||||
descriptionText = strings.Gift_View_UnavailableDescription
|
||||
} else if incoming {
|
||||
if let convertStars {
|
||||
if let convertStars, !upgraded {
|
||||
if !converted {
|
||||
descriptionText = strings.Gift_View_KeepUpgradeOrConvertDescription(strings.Gift_View_KeepOrConvertDescription_Stars(Int32(convertStars))).string
|
||||
if canUpgrade || upgradeStars != nil {
|
||||
descriptionText = strings.Gift_View_KeepUpgradeOrConvertDescription(strings.Gift_View_KeepOrConvertDescription_Stars(Int32(convertStars))).string
|
||||
} else {
|
||||
descriptionText = strings.Gift_View_KeepOrConvertDescription(strings.Gift_View_KeepOrConvertDescription_Stars(Int32(convertStars))).string
|
||||
}
|
||||
} else {
|
||||
descriptionText = strings.Gift_View_ConvertedDescription(strings.Gift_View_ConvertedDescription_Stars(Int32(convertStars))).string
|
||||
}
|
||||
} else if (canUpgrade || upgradeStars != nil) && !upgraded {
|
||||
descriptionText = strings.Gift_View_KeepOrUpgradeDescription
|
||||
} else {
|
||||
descriptionText = strings.Gift_View_BotDescription
|
||||
}
|
||||
@ -660,17 +756,13 @@ private final class GiftViewSheetContent: CombinedComponent {
|
||||
|
||||
let textFont: UIFont
|
||||
let textColor: UIColor
|
||||
if let uniqueGift {
|
||||
if let _ = uniqueGift {
|
||||
textFont = Font.regular(13.0)
|
||||
|
||||
var giftTextColor: UIColor?
|
||||
for attribute in uniqueGift.attributes {
|
||||
if case let .backdrop(_, _, _, _, textColor, _) = attribute {
|
||||
giftTextColor = UIColor(rgb: UInt32(bitPattern: textColor))
|
||||
break
|
||||
}
|
||||
if let previewPatternColor = giftCompositionExternalState.previewPatternColor {
|
||||
textColor = previewPatternColor.withMultiplied(hue: 1.0, saturation: 1.02, brightness: 1.25).mixedWith(UIColor.white, alpha: 0.3)
|
||||
} else {
|
||||
textColor = UIColor.white.withAlphaComponent(0.6)
|
||||
}
|
||||
textColor = giftTextColor ?? UIColor.white.withAlphaComponent(0.6)
|
||||
} else {
|
||||
textFont = soldOut ? Font.medium(15.0) : Font.regular(15.0)
|
||||
textColor = soldOut ? theme.list.itemDestructiveColor : theme.list.itemPrimaryTextColor
|
||||
@ -1043,7 +1135,11 @@ private final class GiftViewSheetContent: CombinedComponent {
|
||||
))
|
||||
}
|
||||
|
||||
let valueString = "⭐️\(presentationStringsFormattedNumber(abs(Int32(stars)), dateTimeFormat.groupingSeparator))"
|
||||
var finalStars = stars
|
||||
if let upgradeStars, upgradeStars > 0 {
|
||||
finalStars += upgradeStars
|
||||
}
|
||||
let valueString = "⭐️\(presentationStringsFormattedNumber(abs(Int32(finalStars)), dateTimeFormat.groupingSeparator))"
|
||||
let valueAttributedString = NSMutableAttributedString(string: valueString, font: tableFont, textColor: tableTextColor)
|
||||
let range = (valueAttributedString.string as NSString).range(of: "⭐️")
|
||||
if range.location != NSNotFound {
|
||||
@ -1115,7 +1211,7 @@ private final class GiftViewSheetContent: CombinedComponent {
|
||||
))
|
||||
}
|
||||
|
||||
if !soldOut && upgradeStars != nil {
|
||||
if !soldOut && canUpgrade {
|
||||
var items: [AnyComponentWithIdentity<Empty>] = []
|
||||
items.append(
|
||||
AnyComponentWithIdentity(
|
||||
@ -1190,7 +1286,14 @@ private final class GiftViewSheetContent: CombinedComponent {
|
||||
if state.cachedSmallChevronImage == nil || state.cachedSmallChevronImage?.1 !== environment.theme {
|
||||
state.cachedSmallChevronImage = (generateTintedImage(image: UIImage(bundleImageName: "Item List/InlineTextRightArrow"), color: linkColor)!, theme)
|
||||
}
|
||||
let descriptionText = savedToProfile ? strings.Gift_View_DisplayedInfoHide : strings.Gift_View_HiddenInfo
|
||||
let descriptionText: String
|
||||
if savedToProfile {
|
||||
descriptionText = strings.Gift_View_DisplayedInfoHide
|
||||
} else if let upgradeStars, upgradeStars > 0 && !upgraded {
|
||||
descriptionText = strings.Gift_View_HiddenInfoShow
|
||||
} else {
|
||||
descriptionText = strings.Gift_View_HiddenInfo
|
||||
}
|
||||
|
||||
let textFont = Font.regular(13.0)
|
||||
let textColor = theme.list.itemSecondaryTextColor
|
||||
@ -1219,7 +1322,7 @@ private final class GiftViewSheetContent: CombinedComponent {
|
||||
}
|
||||
},
|
||||
tapAction: { _, _ in
|
||||
component.updateSavedToProfile(false)
|
||||
component.updateSavedToProfile(!savedToProfile)
|
||||
Queue.mainQueue().after(1.0, {
|
||||
component.cancel(false)
|
||||
})
|
||||
@ -1239,11 +1342,15 @@ private final class GiftViewSheetContent: CombinedComponent {
|
||||
}
|
||||
|
||||
let buttonChild: _UpdatedChildComponent
|
||||
if state.inUpgradePreview, let upgradeStars = subject.arguments?.upgradeStars {
|
||||
if state.inUpgradePreview {
|
||||
if state.cachedStarImage == nil || state.cachedStarImage?.1 !== theme {
|
||||
state.cachedStarImage = (generateTintedImage(image: UIImage(bundleImageName: "Item List/PremiumIcon"), color: theme.list.itemCheckColors.foregroundColor)!, theme)
|
||||
}
|
||||
let buttonTitle = upgradeStars > 0 ? "\(strings.Gift_Upgrade_Upgrade) # \(upgradeStars)" : strings.Gift_Upgrade_Confirm
|
||||
var upgradeString = strings.Gift_Upgrade_Upgrade
|
||||
if let upgradeForm = state.upgradeForm, let price = upgradeForm.invoice.prices.first?.amount {
|
||||
upgradeString += " # \(price)"
|
||||
}
|
||||
let buttonTitle = subject.arguments?.upgradeStars != nil ? strings.Gift_Upgrade_Confirm : upgradeString
|
||||
let buttonAttributedString = NSMutableAttributedString(string: buttonTitle, font: Font.semibold(17.0), textColor: theme.list.itemCheckColors.foregroundColor, paragraphAlignment: .center)
|
||||
if let range = buttonAttributedString.string.range(of: "#"), let starImage = state.cachedStarImage?.0 {
|
||||
buttonAttributedString.addAttribute(.attachment, value: starImage, range: NSRange(range, in: buttonAttributedString.string))
|
||||
@ -1259,7 +1366,7 @@ private final class GiftViewSheetContent: CombinedComponent {
|
||||
cornerRadius: 10.0
|
||||
),
|
||||
content: AnyComponentWithIdentity(
|
||||
id: AnyHashable(0),
|
||||
id: AnyHashable("upgrade"),
|
||||
component: AnyComponent(MultilineTextComponent(text: .plain(buttonAttributedString)))
|
||||
),
|
||||
isEnabled: true,
|
||||
@ -1270,7 +1377,8 @@ private final class GiftViewSheetContent: CombinedComponent {
|
||||
availableSize: CGSize(width: context.availableSize.width - sideInset * 2.0, height: 50.0),
|
||||
transition: context.transition
|
||||
)
|
||||
} else if incoming && !converted && !savedToProfile {
|
||||
} else if incoming && !converted && !upgraded, let upgradeStars, upgradeStars > 0 {
|
||||
let buttonTitle = strings.Gift_View_UpgradeForFree
|
||||
buttonChild = button.update(
|
||||
component: ButtonComponent(
|
||||
background: ButtonComponent.Background(
|
||||
@ -1280,8 +1388,36 @@ private final class GiftViewSheetContent: CombinedComponent {
|
||||
cornerRadius: 10.0
|
||||
),
|
||||
content: AnyComponentWithIdentity(
|
||||
id: AnyHashable(0),
|
||||
component: AnyComponent(MultilineTextComponent(text: .plain(NSAttributedString(string: savedToProfile ? strings.Gift_View_Hide : strings.Gift_View_Display, font: Font.semibold(17.0), textColor: theme.list.itemCheckColors.foregroundColor, paragraphAlignment: .center))))
|
||||
id: AnyHashable("freeUpgrade"),
|
||||
component: AnyComponent(HStack([
|
||||
AnyComponentWithIdentity(id: 0, component: AnyComponent(
|
||||
MultilineTextComponent(text: .plain(NSAttributedString(string: buttonTitle, font: Font.semibold(17.0), textColor: theme.list.itemCheckColors.foregroundColor, paragraphAlignment: .center))
|
||||
))),
|
||||
AnyComponentWithIdentity(id: 1, component: AnyComponent(BundleIconComponent(name: "Premium/GiftUpgrade", tintColor: theme.list.itemCheckColors.foregroundColor)))
|
||||
], spacing: 6.0))
|
||||
),
|
||||
isEnabled: true,
|
||||
displaysProgress: state.inProgress,
|
||||
action: { [weak state] in
|
||||
state?.requestUpgradePreview()
|
||||
}
|
||||
),
|
||||
availableSize: CGSize(width: context.availableSize.width - sideInset * 2.0, height: 50.0),
|
||||
transition: context.transition
|
||||
)
|
||||
} else if incoming && !converted && !savedToProfile {
|
||||
let buttonTitle = savedToProfile ? strings.Gift_View_Hide : strings.Gift_View_Display
|
||||
buttonChild = button.update(
|
||||
component: ButtonComponent(
|
||||
background: ButtonComponent.Background(
|
||||
color: theme.list.itemCheckColors.fillColor,
|
||||
foreground: theme.list.itemCheckColors.foregroundColor,
|
||||
pressedColor: theme.list.itemCheckColors.fillColor.withMultipliedAlpha(0.9),
|
||||
cornerRadius: 10.0
|
||||
),
|
||||
content: AnyComponentWithIdentity(
|
||||
id: AnyHashable("button"),
|
||||
component: AnyComponent(MultilineTextComponent(text: .plain(NSAttributedString(string: buttonTitle, font: Font.semibold(17.0), textColor: theme.list.itemCheckColors.foregroundColor, paragraphAlignment: .center))))
|
||||
),
|
||||
isEnabled: true,
|
||||
displaysProgress: state.inProgress,
|
||||
@ -1301,7 +1437,7 @@ private final class GiftViewSheetContent: CombinedComponent {
|
||||
cornerRadius: 10.0
|
||||
),
|
||||
content: AnyComponentWithIdentity(
|
||||
id: AnyHashable(0),
|
||||
id: AnyHashable("ok"),
|
||||
component: AnyComponent(MultilineTextComponent(text: .plain(NSAttributedString(string: strings.Common_OK, font: Font.semibold(17.0), textColor: theme.list.itemCheckColors.foregroundColor, paragraphAlignment: .center))))
|
||||
),
|
||||
isEnabled: true,
|
||||
@ -1486,24 +1622,31 @@ public class GiftViewScreen: ViewControllerComponentContainer {
|
||||
case message(EngineMessage)
|
||||
case profileGift(EnginePeer.Id, ProfileGiftsContext.State.StarGift)
|
||||
case soldOutGift(StarGift.Gift)
|
||||
case upgradePreview([StarGift.UniqueGift.Attribute], String)
|
||||
|
||||
var arguments: (peerId: EnginePeer.Id, fromPeerId: EnginePeer.Id?, fromPeerName: String?, messageId: EngineMessage.Id?, incoming: Bool, gift: StarGift, date: Int32, convertStars: Int64?, text: String?, entities: [MessageTextEntity]?, nameHidden: Bool, savedToProfile: Bool, converted: Bool, canUpgrade: Bool, upgradeStars: Int64?, transferStars: Int64?, canExportDate: Int32?)? {
|
||||
var arguments: (peerId: EnginePeer.Id, fromPeerId: EnginePeer.Id?, fromPeerName: String?, messageId: EngineMessage.Id?, incoming: Bool, gift: StarGift, date: Int32, convertStars: Int64?, text: String?, entities: [MessageTextEntity]?, nameHidden: Bool, savedToProfile: Bool, converted: Bool, upgraded: Bool, canUpgrade: Bool, upgradeStars: Int64?, transferStars: Int64?, canExportDate: Int32?)? {
|
||||
switch self {
|
||||
case let .message(message):
|
||||
if let action = message.media.first(where: { $0 is TelegramMediaAction }) as? TelegramMediaAction {
|
||||
switch action.action {
|
||||
case let .starGift(gift, convertStars, text, entities, nameHidden, savedToProfile, converted, _, upgradeStars):
|
||||
return (message.id.peerId, message.author?.id, message.author?.compactDisplayTitle, message.id, message.flags.contains(.Incoming), gift, message.timestamp, convertStars, text, entities, nameHidden, savedToProfile, converted, false, upgradeStars, nil, nil)
|
||||
case let .starGiftUnique(gift, _, _, savedToProfile, canExportDate, transferStars):
|
||||
return (message.id.peerId, message.author?.id, message.author?.compactDisplayTitle, message.id, message.flags.contains(.Incoming), gift, message.timestamp, nil, nil, nil, false, savedToProfile, false, false, nil, transferStars, canExportDate)
|
||||
case let .starGift(gift, convertStars, text, entities, nameHidden, savedToProfile, converted, upgraded, canUpgrade, upgradeStars, _):
|
||||
return (message.id.peerId, message.author?.id, message.author?.compactDisplayTitle, message.id, message.flags.contains(.Incoming), gift, message.timestamp, convertStars, text, entities, nameHidden, savedToProfile, converted, upgraded, canUpgrade, upgradeStars, nil, nil)
|
||||
case let .starGiftUnique(gift, _, _, savedToProfile, canExportDate, transferStars, _):
|
||||
return (message.id.peerId, message.author?.id, message.author?.compactDisplayTitle, message.id, message.flags.contains(.Incoming), gift, message.timestamp, nil, nil, nil, false, savedToProfile, false, true, false, nil, transferStars, canExportDate)
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
case let .profileGift(peerId, gift):
|
||||
return (peerId, gift.fromPeer?.id, gift.fromPeer?.compactDisplayTitle, gift.messageId, false, gift.gift, gift.date, gift.convertStars, gift.text, gift.entities, gift.nameHidden, gift.savedToProfile, false, gift.canUpgrade, gift.upgradeStars, gift.transferStars, gift.canExportDate)
|
||||
var upgraded = false
|
||||
if case .unique = gift.gift {
|
||||
upgraded = true
|
||||
}
|
||||
return (peerId, gift.fromPeer?.id, gift.fromPeer?.compactDisplayTitle, gift.messageId, false, gift.gift, gift.date, gift.convertStars, gift.text, gift.entities, gift.nameHidden, gift.savedToProfile, false, upgraded, gift.canUpgrade, gift.upgradeStars, gift.transferStars, gift.canExportDate)
|
||||
case .soldOutGift:
|
||||
return nil
|
||||
case .upgradePreview:
|
||||
return nil
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@ -1772,6 +1915,8 @@ public class GiftViewScreen: ViewControllerComponentContainer {
|
||||
guard let self else {
|
||||
return
|
||||
}
|
||||
self.dismissAllTooltips()
|
||||
|
||||
guard let sourceView = self.node.hostView.findTaggedView(tag: tag), let absoluteLocation = sourceView.superview?.convert(sourceView.center, to: self.view) else {
|
||||
return
|
||||
}
|
||||
@ -1818,13 +1963,16 @@ public class GiftViewScreen: ViewControllerComponentContainer {
|
||||
fileprivate func dismissAllTooltips() {
|
||||
self.window?.forEachController({ controller in
|
||||
if let controller = controller as? TooltipScreen {
|
||||
controller.dismiss()
|
||||
controller.dismiss(inPlace: false)
|
||||
}
|
||||
if let controller = controller as? UndoOverlayController {
|
||||
controller.dismiss()
|
||||
}
|
||||
})
|
||||
self.forEachController({ controller in
|
||||
if let controller = controller as? TooltipScreen {
|
||||
controller.dismiss(inPlace: false)
|
||||
}
|
||||
if let controller = controller as? UndoOverlayController {
|
||||
controller.dismiss()
|
||||
}
|
||||
|
@ -222,29 +222,24 @@ public final class PeerInfoCoverComponent: Component {
|
||||
}
|
||||
|
||||
public func animateTransition() {
|
||||
if let snapshotLayer = self.backgroundView.layer.snapshotContentTree() {
|
||||
self.layer.insertSublayer(snapshotLayer, above: self.backgroundGradientLayer)
|
||||
if let gradientSnapshotLayer = self.backgroundGradientLayer.snapshotContentTree() {
|
||||
self.layer.insertSublayer(gradientSnapshotLayer, above: snapshotLayer)
|
||||
snapshotLayer.animateAlpha(from: 1.0, to: 0.0, duration: 0.25, removeOnCompletion: false, completion: { _ in
|
||||
snapshotLayer.removeFromSuperlayer()
|
||||
})
|
||||
gradientSnapshotLayer.animateAlpha(from: 1.0, to: 0.0, duration: 0.25, removeOnCompletion: false, completion: { _ in
|
||||
gradientSnapshotLayer.removeFromSuperlayer()
|
||||
})
|
||||
}
|
||||
if let gradientSnapshotLayer = self.backgroundGradientLayer.snapshotContentTree() {
|
||||
gradientSnapshotLayer.frame = self.backgroundGradientLayer.frame
|
||||
self.layer.insertSublayer(gradientSnapshotLayer, above: self.backgroundGradientLayer)
|
||||
gradientSnapshotLayer.animateAlpha(from: 1.0, to: 0.0, duration: 0.25, removeOnCompletion: false, completion: { _ in
|
||||
gradientSnapshotLayer.removeFromSuperlayer()
|
||||
})
|
||||
}
|
||||
for layer in self.avatarPatternContentLayers {
|
||||
if let snapshot = layer.snapshotContentTree() {
|
||||
if let _ = layer.contents, let snapshot = layer.snapshotContentTree() {
|
||||
layer.superlayer?.addSublayer(snapshot)
|
||||
snapshot.animateAlpha(from: 1.0, to: 0.0, duration: 0.25, removeOnCompletion: false, completion: { _ in
|
||||
snapshot.removeFromSuperlayer()
|
||||
})
|
||||
layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.25)
|
||||
}
|
||||
layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.25)
|
||||
}
|
||||
let values: [NSNumber] = [1.0, 1.08, 1.0]
|
||||
self.avatarBackgroundPatternContentsLayer.animateKeyframes(values: values, duration: 0.25, keyPath: "transform.scale")
|
||||
self.avatarBackgroundPatternContentsLayer.animateKeyframes(values: values, duration: 0.25, keyPath: "sublayerTransform.scale")
|
||||
}
|
||||
|
||||
private func loadPatternFromFile() {
|
||||
@ -298,7 +293,10 @@ public final class PeerInfoCoverComponent: Component {
|
||||
}
|
||||
|
||||
func update(component: PeerInfoCoverComponent, availableSize: CGSize, state: EmptyComponentState, environment: Environment<Empty>, transition: ComponentTransition) -> CGSize {
|
||||
if self.component?.subject?.fileId != component.subject?.fileId {
|
||||
let previousComponent = self.component
|
||||
self.component = component
|
||||
|
||||
if previousComponent?.subject?.fileId != component.subject?.fileId {
|
||||
if let fileId = component.subject?.fileId, fileId != 0 {
|
||||
if self.patternContentsTarget == nil {
|
||||
self.patternContentsTarget = PatternContentsTarget(imageUpdated: { [weak self] hadContents in
|
||||
@ -337,8 +335,7 @@ public final class PeerInfoCoverComponent: Component {
|
||||
self.updatePatternLayerImages(animated: false)
|
||||
}
|
||||
}
|
||||
|
||||
self.component = component
|
||||
|
||||
self.state = state
|
||||
|
||||
let backgroundColor: UIColor
|
||||
|
@ -1210,9 +1210,15 @@ final class PeerInfoPaneContainerNode: ASDisplayNode, ASGestureRecognizerDelegat
|
||||
case .gifts:
|
||||
title = presentationData.strings.PeerInfo_PaneGifts
|
||||
icons = data?.profileGiftsContext?.currentState?.gifts.prefix(3).compactMap { gift in
|
||||
if case let .generic(gift) = gift.gift {
|
||||
switch gift.gift {
|
||||
case let .generic(gift):
|
||||
return gift.file
|
||||
} else {
|
||||
case let .unique(gift):
|
||||
for attribute in gift.attributes {
|
||||
if case let .model(_, file, _) = attribute {
|
||||
return file
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
} ?? []
|
||||
|
12
submodules/TelegramUI/Images.xcassets/Premium/GiftUnpack.imageset/Contents.json
vendored
Normal file
12
submodules/TelegramUI/Images.xcassets/Premium/GiftUnpack.imageset/Contents.json
vendored
Normal file
@ -0,0 +1,12 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"filename" : "unpack_14.pdf",
|
||||
"idiom" : "universal"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
BIN
submodules/TelegramUI/Images.xcassets/Premium/GiftUnpack.imageset/unpack_14.pdf
vendored
Normal file
BIN
submodules/TelegramUI/Images.xcassets/Premium/GiftUnpack.imageset/unpack_14.pdf
vendored
Normal file
Binary file not shown.
12
submodules/TelegramUI/Images.xcassets/Premium/GiftUpgrade.imageset/Contents.json
vendored
Normal file
12
submodules/TelegramUI/Images.xcassets/Premium/GiftUpgrade.imageset/Contents.json
vendored
Normal file
@ -0,0 +1,12 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"filename" : "upgrade_30.pdf",
|
||||
"idiom" : "universal"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
BIN
submodules/TelegramUI/Images.xcassets/Premium/GiftUpgrade.imageset/upgrade_30.pdf
vendored
Normal file
BIN
submodules/TelegramUI/Images.xcassets/Premium/GiftUpgrade.imageset/upgrade_30.pdf
vendored
Normal file
Binary file not shown.
@ -2289,18 +2289,13 @@ public final class SharedAccountContextImpl: SharedAccountContext {
|
||||
var currentBirthdays: [EnginePeer.Id: TelegramBirthday]?
|
||||
|
||||
if case let .starGiftTransfer(birthdays, _, _, _, _) = source {
|
||||
if let birthdays, !birthdays.isEmpty {
|
||||
mode = .starsGifting(birthdays: birthdays, hasActions: false, showSelf: true)
|
||||
currentBirthdays = birthdays
|
||||
} else {
|
||||
mode = .starsGifting(birthdays: nil, hasActions: false, showSelf: true)
|
||||
}
|
||||
}
|
||||
if case let .chatList(birthdays) = source, let birthdays, !birthdays.isEmpty {
|
||||
mode = .starsGifting(birthdays: birthdays, hasActions: true, showSelf: false)
|
||||
mode = .starsGifting(birthdays: birthdays, hasActions: false, showSelf: false)
|
||||
currentBirthdays = birthdays
|
||||
} else if case let .settings(birthdays) = source, let birthdays, !birthdays.isEmpty {
|
||||
mode = .starsGifting(birthdays: birthdays, hasActions: true, showSelf: false)
|
||||
} else if case let .chatList(birthdays) = source {
|
||||
mode = .starsGifting(birthdays: birthdays, hasActions: true, showSelf: true)
|
||||
currentBirthdays = birthdays
|
||||
} else if case let .settings(birthdays) = source {
|
||||
mode = .starsGifting(birthdays: birthdays, hasActions: true, showSelf: true)
|
||||
currentBirthdays = birthdays
|
||||
} else {
|
||||
mode = .starsGifting(birthdays: nil, hasActions: true, showSelf: false)
|
||||
|
Loading…
x
Reference in New Issue
Block a user