mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-06-16 05:55:20 +00:00
Various fixes
This commit is contained in:
parent
89d2ad8cf6
commit
eb4519e192
@ -13008,6 +13008,8 @@ Sorry for the inconvenience.";
|
||||
"Gift.Options.Gift.Filter.AllGifts" = "All Gifts";
|
||||
"Gift.Options.Gift.Filter.Limited" = "Limited";
|
||||
"Gift.Options.Gift.Limited" = "Limited";
|
||||
"Gift.Options.Gift.SoldOut" = "Sold Out";
|
||||
"Gift.Options.SoldOut.Text" = "Sorry, this gift is sold out.";
|
||||
|
||||
"PeerInfo.PaneGifts" = "Gifts";
|
||||
|
||||
@ -13039,6 +13041,10 @@ Sorry for the inconvenience.";
|
||||
"Gift.Send.HideMyName.Info" = "Hide my name and message from visitors to %1$@'s profile. %2$@ will still see your name and message.";
|
||||
"Gift.Send.Send" = "Send a Gift for";
|
||||
"Gift.Send.Limited" = "Limited";
|
||||
"Gift.Send.Left" = "left";
|
||||
|
||||
"Gift.Send.ErrorUnknown" = "An error occurred. Please try again.";
|
||||
"Gift.Send.ErrorOutOfStock" = "Sorry, this gift is sold out. Please choose another gift.";
|
||||
|
||||
"Profile.SendGift" = "Send a Gift";
|
||||
"Settings.SendGift" = "Send a Gift";
|
||||
@ -13061,6 +13067,7 @@ Sorry for the inconvenience.";
|
||||
|
||||
"Notification.PremiumGift.YearsTitle_1" = "%@ Year Premium";
|
||||
"Notification.PremiumGift.YearsTitle_any" = "%@ Years Premium";
|
||||
"Notification.PremiumGift.More" = "more";
|
||||
|
||||
"Notification.PremiumGift.SubscriptionDescription" = "Subscription for exclusive Telegram features.";
|
||||
|
||||
|
@ -931,13 +931,13 @@ public final class AvatarNode: ASDisplayNode {
|
||||
if let repliesIcon = repliesIcon {
|
||||
context.draw(repliesIcon.cgImage!, in: CGRect(origin: CGPoint(x: floor((bounds.size.width - repliesIcon.size.width) / 2.0), y: floor((bounds.size.height - repliesIcon.size.height) / 2.0)), size: repliesIcon.size))
|
||||
}
|
||||
} else if case .anonymousSavedMessagesIcon = parameters.icon {
|
||||
} else if case let .anonymousSavedMessagesIcon(isColored) = parameters.icon {
|
||||
let factor = bounds.size.width / 60.0
|
||||
context.translateBy(x: bounds.size.width / 2.0, y: bounds.size.height / 2.0)
|
||||
context.scaleBy(x: factor, y: -factor)
|
||||
context.translateBy(x: -bounds.size.width / 2.0, y: -bounds.size.height / 2.0)
|
||||
|
||||
if let theme = parameters.theme, theme.overallDarkAppearance {
|
||||
if let theme = parameters.theme, theme.overallDarkAppearance, !isColored {
|
||||
if let anonymousSavedMessagesDarkIcon = anonymousSavedMessagesDarkIcon {
|
||||
context.draw(anonymousSavedMessagesDarkIcon.cgImage!, in: CGRect(origin: CGPoint(x: floor((bounds.size.width - anonymousSavedMessagesDarkIcon.size.width) / 2.0), y: floor((bounds.size.height - anonymousSavedMessagesDarkIcon.size.height) / 2.0)), size: anonymousSavedMessagesDarkIcon.size))
|
||||
}
|
||||
|
@ -1558,7 +1558,7 @@ final class BotCheckoutControllerNode: ItemListControllerNode, PKPaymentAuthoriz
|
||||
applePayController.presentingViewController?.dismiss(animated: true, completion: nil)
|
||||
}
|
||||
|
||||
let text: String
|
||||
let text: String?
|
||||
switch error {
|
||||
case .precheckoutFailed:
|
||||
text = strongSelf.presentationData.strings.Checkout_ErrorPrecheckoutFailed
|
||||
@ -1568,9 +1568,13 @@ final class BotCheckoutControllerNode: ItemListControllerNode, PKPaymentAuthoriz
|
||||
text = strongSelf.presentationData.strings.Checkout_ErrorInvoiceAlreadyPaid
|
||||
case .generic:
|
||||
text = strongSelf.presentationData.strings.Checkout_ErrorGeneric
|
||||
default:
|
||||
text = nil
|
||||
}
|
||||
|
||||
if let text {
|
||||
strongSelf.present(textAlertController(context: strongSelf.context, title: nil, text: text, actions: [TextAlertAction(type: .defaultAction, title: strongSelf.presentationData.strings.Common_OK, action: {})]), nil)
|
||||
}
|
||||
|
||||
strongSelf.failed()
|
||||
}
|
||||
|
@ -588,6 +588,7 @@ public enum SendBotPaymentFormError {
|
||||
case precheckoutFailed
|
||||
case paymentFailed
|
||||
case alreadyPaid
|
||||
case starGiftOutOfStock
|
||||
}
|
||||
|
||||
public enum SendBotPaymentResult {
|
||||
@ -702,6 +703,8 @@ func _internal_sendBotPaymentForm(account: Account, formId: Int64, source: BotPa
|
||||
return .fail(.paymentFailed)
|
||||
} else if error.errorDescription == "INVOICE_ALREADY_PAID" {
|
||||
return .fail(.alreadyPaid)
|
||||
} else if error.errorDescription == "STARGIFT_USAGE_LIMITED" {
|
||||
return .fail(.starGiftOutOfStock)
|
||||
}
|
||||
return .fail(.generic)
|
||||
}
|
||||
|
@ -6224,7 +6224,7 @@ public class ChatMessageBubbleItemNode: ChatMessageItemView, ChatMessagePreviewI
|
||||
}
|
||||
|
||||
for contentNode in self.contentNodes {
|
||||
if contentNode is ChatMessageMediaBubbleContentNode {
|
||||
if contentNode is ChatMessageMediaBubbleContentNode || contentNode is ChatMessageGiftBubbleContentNode {
|
||||
contentNode.visibility = mapVisibility(effectiveMediaVisibility, boundsSize: self.bounds.size, insets: self.insets, to: contentNode)
|
||||
} else {
|
||||
contentNode.visibility = mapVisibility(effectiveVisibility, boundsSize: self.bounds.size, insets: self.insets, to: contentNode)
|
||||
|
@ -50,6 +50,8 @@ public class ChatMessageGiftBubbleContentNode: ChatMessageBubbleContentNode {
|
||||
private let buttonStarsNode: PremiumStarsNode
|
||||
private let buttonTitleNode: TextNode
|
||||
|
||||
private let moreTextNode: TextNode
|
||||
|
||||
private var maskView: UIImageView?
|
||||
private var maskOverlayView: UIView?
|
||||
|
||||
@ -61,6 +63,8 @@ public class ChatMessageGiftBubbleContentNode: ChatMessageBubbleContentNode {
|
||||
private var isExpanded: Bool = false
|
||||
private var appliedIsExpanded: Bool = false
|
||||
|
||||
private var isStarGift = false
|
||||
|
||||
private var currentProgressDisposable: Disposable?
|
||||
|
||||
override public var visibility: ListViewItemNodeVisibility {
|
||||
@ -138,6 +142,10 @@ public class ChatMessageGiftBubbleContentNode: ChatMessageBubbleContentNode {
|
||||
self.ribbonTextNode.isUserInteractionEnabled = false
|
||||
self.ribbonTextNode.displaysAsynchronously = false
|
||||
|
||||
self.moreTextNode = TextNode()
|
||||
self.moreTextNode.isUserInteractionEnabled = false
|
||||
self.moreTextNode.displaysAsynchronously = false
|
||||
|
||||
super.init()
|
||||
|
||||
self.addSubnode(self.labelNode)
|
||||
@ -147,6 +155,7 @@ public class ChatMessageGiftBubbleContentNode: ChatMessageBubbleContentNode {
|
||||
self.textClippingNode.addSubnode(self.subtitleNode.textNode)
|
||||
self.addSubnode(self.placeholderNode)
|
||||
self.addSubnode(self.animationNode)
|
||||
self.addSubnode(self.moreTextNode)
|
||||
|
||||
self.addSubnode(self.buttonNode)
|
||||
self.buttonNode.addSubnode(self.buttonStarsNode)
|
||||
@ -183,6 +192,19 @@ public class ChatMessageGiftBubbleContentNode: ChatMessageBubbleContentNode {
|
||||
self.currentProgressDisposable?.dispose()
|
||||
}
|
||||
|
||||
override public func didLoad() {
|
||||
super.didLoad()
|
||||
|
||||
self.maskView = UIImageView()
|
||||
|
||||
let maskOverlayView = UIView()
|
||||
maskOverlayView.alpha = 0.0
|
||||
maskOverlayView.backgroundColor = .white
|
||||
self.maskOverlayView = maskOverlayView
|
||||
|
||||
self.maskView?.addSubview(maskOverlayView)
|
||||
}
|
||||
|
||||
@objc private func buttonPressed() {
|
||||
guard let item = self.item else {
|
||||
return
|
||||
@ -190,6 +212,14 @@ public class ChatMessageGiftBubbleContentNode: ChatMessageBubbleContentNode {
|
||||
let _ = item.controllerInteraction.openMessage(item.message, OpenMessageParams(mode: .default, progress: self.makeProgress()))
|
||||
}
|
||||
|
||||
private func expandPressed() {
|
||||
self.isExpanded = !self.isExpanded
|
||||
guard let item = self.item else{
|
||||
return
|
||||
}
|
||||
let _ = item.controllerInteraction.requestMessageUpdate(item.message.id, false)
|
||||
}
|
||||
|
||||
private func makeProgress() -> Promise<Bool> {
|
||||
let progress = Promise<Bool>()
|
||||
self.currentProgressDisposable?.dispose()
|
||||
@ -263,6 +293,7 @@ public class ChatMessageGiftBubbleContentNode: ChatMessageBubbleContentNode {
|
||||
let makeButtonTitleLayout = TextNode.asyncLayout(self.buttonTitleNode)
|
||||
let makeRibbonTextLayout = TextNode.asyncLayout(self.ribbonTextNode)
|
||||
let makeMeasureTextLayout = TextNode.asyncLayout(nil)
|
||||
let makeMoreTextLayout = TextNode.asyncLayout(self.moreTextNode)
|
||||
|
||||
let cachedMaskBackgroundImage = self.cachedMaskBackgroundImage
|
||||
|
||||
@ -290,6 +321,7 @@ public class ChatMessageGiftBubbleContentNode: ChatMessageBubbleContentNode {
|
||||
var ribbonTitle = ""
|
||||
var hasServiceMessage = true
|
||||
var textSpacing: CGFloat = 0.0
|
||||
var isStarGift = false
|
||||
for media in item.message.media {
|
||||
if let action = media as? TelegramMediaAction {
|
||||
switch action.action {
|
||||
@ -377,6 +409,7 @@ public class ChatMessageGiftBubbleContentNode: ChatMessageBubbleContentNode {
|
||||
hasServiceMessage = false
|
||||
}
|
||||
case let .starGift(gift, convertStars, giftText, giftEntities, _, savedToProfile, converted):
|
||||
isStarGift = true
|
||||
let authorName = item.message.author.flatMap { EnginePeer($0) }?.compactDisplayTitle ?? ""
|
||||
title = item.presentationData.strings.Notification_StarGift_Title(authorName).string
|
||||
if let giftText, !giftText.isEmpty {
|
||||
@ -439,8 +472,10 @@ public class ChatMessageGiftBubbleContentNode: ChatMessageBubbleContentNode {
|
||||
|
||||
let (titleLayout, titleApply) = makeTitleLayout(TextNodeLayoutArguments(attributedString: NSAttributedString(string: title, font: Font.semibold(15.0), textColor: primaryTextColor, paragraphAlignment: .center), backgroundColor: nil, maximumNumberOfLines: 0, truncationType: .end, constrainedSize: CGSize(width: giftSize.width - 32.0, height: CGFloat.greatestFiniteMagnitude), alignment: .center, cutout: nil, insets: UIEdgeInsets()))
|
||||
|
||||
let (moreLayout, moreApply) = makeMoreTextLayout(TextNodeLayoutArguments(attributedString: NSAttributedString(string: item.presentationData.strings.Notification_PremiumGift_More, font: Font.semibold(13.0), textColor: primaryTextColor, paragraphAlignment: .center), backgroundColor: nil, maximumNumberOfLines: 0, truncationType: .end, constrainedSize: CGSize(width: giftSize.width - 32.0, height: CGFloat.greatestFiniteMagnitude), alignment: .center, cutout: nil, insets: UIEdgeInsets()))
|
||||
|
||||
let attributedText: NSAttributedString
|
||||
if let _ = animationFile {
|
||||
if !entities.isEmpty {
|
||||
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(
|
||||
@ -578,6 +613,7 @@ public class ChatMessageGiftBubbleContentNode: ChatMessageBubbleContentNode {
|
||||
}
|
||||
}
|
||||
strongSelf.item = item
|
||||
strongSelf.isStarGift = isStarGift
|
||||
|
||||
strongSelf.updateVisibility()
|
||||
|
||||
@ -599,6 +635,7 @@ public class ChatMessageGiftBubbleContentNode: ChatMessageBubbleContentNode {
|
||||
))
|
||||
let _ = buttonTitleApply()
|
||||
let _ = ribbonTextApply()
|
||||
let _ = moreApply()
|
||||
|
||||
let labelFrame = CGRect(origin: CGPoint(x: 8.0, y: 2.0), size: labelLayout.size)
|
||||
strongSelf.labelNode.frame = labelFrame
|
||||
@ -606,7 +643,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: boundingWidth, 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: CGPoint(x: mediaBackgroundFrame.minX + floorToScreenPixels((mediaBackgroundFrame.width - subtitleLayout.size.width) / 2.0) , y: titleFrame.maxY + textSpacing), size: subtitleLayout.size)
|
||||
strongSelf.subtitleNode.textNode.frame = CGRect(origin: .zero, size: subtitleLayout.size)
|
||||
@ -617,10 +654,10 @@ public class ChatMessageGiftBubbleContentNode: ChatMessageBubbleContentNode {
|
||||
animation.animator.updateFrame(layer: strongSelf.textClippingNode.layer, frame: clippingTextFrame, completion: nil)
|
||||
}
|
||||
if let maskView = strongSelf.maskView, let maskOverlayView = strongSelf.maskOverlayView {
|
||||
animation.animator.updateFrame(layer: maskView.layer, frame: CGRect(origin: .zero, size: CGSize(width: boundingWidth, height: clippingTextFrame.size.height)), completion: nil)
|
||||
animation.animator.updateFrame(layer: maskOverlayView.layer, frame: CGRect(origin: .zero, size: CGSize(width: boundingWidth, height: clippingTextFrame.size.height)), completion: nil)
|
||||
animation.animator.updateFrame(layer: maskView.layer, frame: CGRect(origin: .zero, size: CGSize(width: clippingTextFrame.width, height: clippingTextFrame.height)), completion: nil)
|
||||
animation.animator.updateFrame(layer: maskOverlayView.layer, frame: CGRect(origin: .zero, size: CGSize(width: clippingTextFrame.width, height: clippingTextFrame.height)), completion: nil)
|
||||
}
|
||||
|
||||
animation.animator.updateFrame(layer: strongSelf.moreTextNode.layer, frame: CGRect(origin: CGPoint(x: clippingTextFrame.maxX - moreLayout.size.width, y: clippingTextFrame.maxY - moreLayout.size.height), size: moreLayout.size), completion: nil)
|
||||
|
||||
if !subtitleLayout.spoilers.isEmpty {
|
||||
let dustColor = serviceMessageColorComponents(theme: item.presentationData.theme.theme, wallpaper: item.presentationData.theme.wallpaper).primaryText
|
||||
@ -734,24 +771,16 @@ public class ChatMessageGiftBubbleContentNode: ChatMessageBubbleContentNode {
|
||||
strongSelf.updateAbsoluteRect(rect, within: size)
|
||||
}
|
||||
|
||||
if canExpand {
|
||||
if strongSelf.maskView?.image == nil {
|
||||
strongSelf.maskView?.image = generateMaskImage()
|
||||
if canExpand, let maskView = strongSelf.maskView {
|
||||
if maskView.image == nil {
|
||||
maskView.image = generateMaskImage()
|
||||
}
|
||||
strongSelf.textClippingNode.view.mask = strongSelf.maskView
|
||||
|
||||
// var expandIconFrame: CGRect = .zero
|
||||
// if let icon = strongSelf.expandIcon.image {
|
||||
// expandIconFrame = CGRect(origin: CGPoint(x: boundingWidth - icon.size.width - 19.0, y: backgroundFrame.maxY - icon.size.height - 6.0), size: icon.size)
|
||||
// if wasHidden || isFirstTime {
|
||||
// strongSelf.expandIcon.position = expandIconFrame.center
|
||||
// } else {
|
||||
// animation.animator.updatePosition(layer: strongSelf.expandIcon.layer, position: expandIconFrame.center, completion: nil)
|
||||
// }
|
||||
// strongSelf.expandIcon.bounds = CGRect(origin: .zero, size: expandIconFrame.size)
|
||||
// }
|
||||
animation.animator.updateAlpha(layer: strongSelf.moreTextNode.layer, alpha: strongSelf.isExpanded ? 0.0 : 1.0, completion: nil)
|
||||
} else {
|
||||
strongSelf.textClippingNode.view.mask = nil
|
||||
strongSelf.moreTextNode.alpha = 0.0
|
||||
}
|
||||
|
||||
switch strongSelf.visibility {
|
||||
@ -876,6 +905,9 @@ public class ChatMessageGiftBubbleContentNode: ChatMessageBubbleContentNode {
|
||||
|
||||
if self.buttonNode.frame.contains(point) {
|
||||
return ChatMessageBubbleContentTapAction(content: .ignore)
|
||||
} else if self.textClippingNode.frame.contains(point) && !self.isExpanded && !self.moreTextNode.alpha.isZero {
|
||||
self.expandPressed()
|
||||
return ChatMessageBubbleContentTapAction(content: .ignore)
|
||||
} else if let backgroundNode = self.backgroundNode, backgroundNode.frame.contains(point) {
|
||||
return ChatMessageBubbleContentTapAction(content: .openMessage)
|
||||
} else if self.mediaBackgroundContent?.frame.contains(point) == true {
|
||||
@ -934,7 +966,8 @@ public class ChatMessageGiftBubbleContentNode: ChatMessageBubbleContentNode {
|
||||
|
||||
if !alreadySeen && self.animationNode.isPlaying {
|
||||
item.controllerInteraction.playNextOutgoingGift = false
|
||||
Queue.mainQueue().after(1.0) {
|
||||
|
||||
Queue.mainQueue().after(self.isStarGift ? 0.1 : 1.0) {
|
||||
item.controllerInteraction.animateDiceSuccess(false, true)
|
||||
}
|
||||
}
|
||||
@ -943,7 +976,7 @@ public class ChatMessageGiftBubbleContentNode: ChatMessageBubbleContentNode {
|
||||
}
|
||||
|
||||
private func generateMaskImage() -> UIImage? {
|
||||
return generateImage(CGSize(width: 140, height: 30), rotatedContext: { size, context in
|
||||
return generateImage(CGSize(width: 100.0, height: 30.0), rotatedContext: { size, context in
|
||||
context.clear(CGRect(origin: .zero, size: size))
|
||||
|
||||
context.setFillColor(UIColor.white.cgColor)
|
||||
@ -956,7 +989,7 @@ private func generateMaskImage() -> UIImage? {
|
||||
let gradient = CGGradient(colorsSpace: colorSpace, colors: colors as CFArray, locations: &locations)!
|
||||
|
||||
context.setBlendMode(.copy)
|
||||
context.clip(to: CGRect(origin: CGPoint(x: 10.0, y: 8.0), size: CGSize(width: 130.0, height: 22.0)))
|
||||
context.drawLinearGradient(gradient, start: CGPoint(x: 10.0, y: 0.0), end: CGPoint(x: size.width, y: 0.0), options: CGGradientDrawingOptions())
|
||||
})?.resizableImage(withCapInsets: UIEdgeInsets(top: 0.0, left: 0.0, bottom: 22.0, right: 130.0))
|
||||
context.clip(to: CGRect(origin: CGPoint(x: 10.0, y: 12.0), size: CGSize(width: 130.0, height: 18.0)))
|
||||
context.drawLinearGradient(gradient, start: CGPoint(x: 30.0, y: 0.0), end: CGPoint(x: size.width, y: 0.0), options: CGGradientDrawingOptions())
|
||||
})?.resizableImage(withCapInsets: UIEdgeInsets(top: 0.0, left: 0.0, bottom: 18.0, right: 70.0))
|
||||
}
|
||||
|
@ -64,6 +64,7 @@ public final class GiftItemComponent: Component {
|
||||
let ribbon: Ribbon?
|
||||
let isLoading: Bool
|
||||
let isHidden: Bool
|
||||
let isSoldOut: Bool
|
||||
|
||||
public init(
|
||||
context: AccountContext,
|
||||
@ -75,7 +76,8 @@ public final class GiftItemComponent: Component {
|
||||
price: String,
|
||||
ribbon: Ribbon? = nil,
|
||||
isLoading: Bool = false,
|
||||
isHidden: Bool = false
|
||||
isHidden: Bool = false,
|
||||
isSoldOut: Bool = false
|
||||
) {
|
||||
self.context = context
|
||||
self.theme = theme
|
||||
@ -87,6 +89,7 @@ public final class GiftItemComponent: Component {
|
||||
self.ribbon = ribbon
|
||||
self.isLoading = isLoading
|
||||
self.isHidden = isHidden
|
||||
self.isSoldOut = isSoldOut
|
||||
}
|
||||
|
||||
public static func ==(lhs: GiftItemComponent, rhs: GiftItemComponent) -> Bool {
|
||||
@ -120,6 +123,9 @@ public final class GiftItemComponent: Component {
|
||||
if lhs.isHidden != rhs.isHidden {
|
||||
return false
|
||||
}
|
||||
if lhs.isSoldOut != rhs.isSoldOut {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
@ -284,14 +290,26 @@ public final class GiftItemComponent: Component {
|
||||
}
|
||||
}
|
||||
|
||||
let buttonColor: UIColor
|
||||
var isStars = false
|
||||
if component.isSoldOut {
|
||||
buttonColor = component.theme.list.itemDestructiveColor
|
||||
} else if component.price.containsEmoji {
|
||||
buttonColor = UIColor(rgb: 0xd3720a)
|
||||
isStars = true
|
||||
} else {
|
||||
buttonColor = component.theme.list.itemAccentColor
|
||||
}
|
||||
|
||||
let buttonSize = self.button.update(
|
||||
transition: transition,
|
||||
component: AnyComponent(
|
||||
ButtonContentComponent(
|
||||
context: component.context,
|
||||
text: component.price,
|
||||
color: component.price.containsEmoji ? UIColor(rgb: 0xd3720a) : component.theme.list.itemAccentColor,
|
||||
isStars: component.price.containsEmoji)
|
||||
color: buttonColor,
|
||||
isStars: isStars
|
||||
)
|
||||
),
|
||||
environment: {},
|
||||
containerSize: availableSize
|
||||
|
@ -25,6 +25,7 @@ import GiftItemComponent
|
||||
import InAppPurchaseManager
|
||||
import TabSelectorComponent
|
||||
import GiftSetupScreen
|
||||
import UndoUI
|
||||
|
||||
final class GiftOptionsScreenComponent: Component {
|
||||
typealias EnvironmentType = ViewControllerComponentContainer.Environment
|
||||
@ -173,6 +174,20 @@ final class GiftOptionsScreenComponent: Component {
|
||||
self.updateScrolling(transition: .immediate)
|
||||
}
|
||||
|
||||
private func dismissAllTooltips(controller: ViewController) {
|
||||
controller.forEachController({ controller in
|
||||
if let controller = controller as? UndoOverlayController {
|
||||
controller.dismissWithCommitAction()
|
||||
}
|
||||
return true
|
||||
})
|
||||
controller.window?.forEachController({ controller in
|
||||
if let controller = controller as? UndoOverlayController {
|
||||
controller.dismissWithCommitAction()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
private func updateScrolling(transition: ComponentTransition) {
|
||||
guard let environment = self.environment, let component = self.component else {
|
||||
return
|
||||
@ -274,6 +289,7 @@ final class GiftOptionsScreenComponent: Component {
|
||||
self.starsItems[itemId] = visibleItem
|
||||
}
|
||||
|
||||
let isSoldOut = gift.availability?.remains == 0
|
||||
let _ = visibleItem.update(
|
||||
transition: itemTransition,
|
||||
component: AnyComponent(
|
||||
@ -284,13 +300,14 @@ final class GiftOptionsScreenComponent: Component {
|
||||
theme: environment.theme,
|
||||
peer: nil,
|
||||
subject: .starGift(gift.id, gift.file),
|
||||
price: "⭐️ \(gift.price)",
|
||||
price: isSoldOut ? environment.strings.Gift_Options_Gift_SoldOut : "⭐️ \(gift.price)",
|
||||
ribbon: gift.availability != nil ?
|
||||
GiftItemComponent.Ribbon(
|
||||
text: environment.strings.Gift_Options_Gift_Limited,
|
||||
color: .blue
|
||||
)
|
||||
: nil
|
||||
: nil,
|
||||
isSoldOut: isSoldOut
|
||||
)
|
||||
),
|
||||
effectAlignment: .center,
|
||||
@ -303,6 +320,17 @@ final class GiftOptionsScreenComponent: Component {
|
||||
} else {
|
||||
mainController = controller
|
||||
}
|
||||
if gift.availability?.remains == 0 {
|
||||
self.dismissAllTooltips(controller: mainController)
|
||||
let presentationData = component.context.sharedContext.currentPresentationData.with { $0 }
|
||||
let resultController = UndoOverlayController(
|
||||
presentationData: presentationData,
|
||||
content: .sticker(context: component.context, file: gift.file, loop: false, title: nil, text: presentationData.strings.Gift_Options_SoldOut_Text, undoText: nil, customAction: nil),
|
||||
elevatedLayout: false,
|
||||
action: { _ in return true }
|
||||
)
|
||||
mainController.present(resultController, in: .window(.root))
|
||||
} else {
|
||||
let giftController = GiftSetupScreen(
|
||||
context: component.context,
|
||||
peerId: component.peerId,
|
||||
@ -312,6 +340,7 @@ final class GiftOptionsScreenComponent: Component {
|
||||
mainController.push(giftController)
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
animateAlpha: false
|
||||
)
|
||||
|
@ -43,6 +43,7 @@ swift_library(
|
||||
"//submodules/TelegramUI/Components/EmojiSuggestionsComponent",
|
||||
"//submodules/TelegramUI/Components/ChatEntityKeyboardInputNode",
|
||||
"//submodules/InAppPurchaseManager",
|
||||
"//submodules/Components/BlurredBackgroundComponent",
|
||||
],
|
||||
visibility = [
|
||||
"//visibility:public",
|
||||
|
@ -258,7 +258,7 @@ final class ChatGiftPreviewItemNode: ListViewItemNode {
|
||||
apply().1(ListViewItemApply(isOnScreen: true))
|
||||
})
|
||||
itemNode!.isUserInteractionEnabled = false
|
||||
itemNode?.visibility = .visible(1.0, .infinite)
|
||||
itemNode!.visibility = .visible(1.0, .infinite)
|
||||
messageNodes.append(itemNode!)
|
||||
|
||||
self.initialBubbleHeight = itemNode?.frame.height
|
||||
|
@ -29,6 +29,7 @@ import ChatPresentationInterfaceState
|
||||
import AudioToolbox
|
||||
import TextFormat
|
||||
import InAppPurchaseManager
|
||||
import BlurredBackgroundComponent
|
||||
|
||||
final class GiftSetupScreenComponent: Component {
|
||||
typealias EnvironmentType = ViewControllerComponentContainer.Environment
|
||||
@ -78,6 +79,9 @@ final class GiftSetupScreenComponent: Component {
|
||||
private let introContent = ComponentView<Empty>()
|
||||
private let introSection = ComponentView<Empty>()
|
||||
private let hideSection = ComponentView<Empty>()
|
||||
|
||||
private let buttonBackground = ComponentView<Empty>()
|
||||
private let buttonSeparator = SimpleLayer()
|
||||
private let button = ComponentView<Empty>()
|
||||
|
||||
private var ignoreScrolling: Bool = false
|
||||
@ -356,6 +360,27 @@ final class GiftSetupScreenComponent: Component {
|
||||
}
|
||||
|
||||
starsContext.load(force: true)
|
||||
}, error: { [weak self] error in
|
||||
guard let self, let controller = self.environment?.controller() else {
|
||||
return
|
||||
}
|
||||
|
||||
self.inProgress = false
|
||||
self.state?.updated()
|
||||
|
||||
let presentationData = component.context.sharedContext.currentPresentationData.with { $0 }
|
||||
var errorText: String?
|
||||
switch error {
|
||||
case .starGiftOutOfStock:
|
||||
errorText = presentationData.strings.Gift_Send_ErrorOutOfStock
|
||||
default:
|
||||
errorText = presentationData.strings.Gift_Send_ErrorUnknown
|
||||
}
|
||||
|
||||
if let errorText = errorText {
|
||||
let alertController = textAlertController(context: component.context, title: nil, text: errorText, actions: [TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_OK, action: {})])
|
||||
controller.present(alertController, in: .window(.root))
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
@ -826,6 +851,34 @@ final class GiftSetupScreenComponent: Component {
|
||||
self.starImage = (generateTintedImage(image: UIImage(bundleImageName: "Item List/PremiumIcon"), color: environment.theme.list.itemCheckColors.foregroundColor)!, environment.theme)
|
||||
}
|
||||
|
||||
let buttonHeight: CGFloat = 50.0
|
||||
let bottomPanelPadding: CGFloat = 12.0
|
||||
let bottomInset: CGFloat = environment.safeInsets.bottom > 0.0 ? environment.safeInsets.bottom + 5.0 : bottomPanelPadding
|
||||
let bottomPanelHeight = bottomPanelPadding + buttonHeight + bottomInset
|
||||
|
||||
let bottomPanelAlpha: CGFloat = 1.0
|
||||
let bottomPanelSize = self.buttonBackground.update(
|
||||
transition: transition,
|
||||
component: AnyComponent(BlurredBackgroundComponent(
|
||||
color: environment.theme.rootController.tabBar.backgroundColor
|
||||
)),
|
||||
environment: {},
|
||||
containerSize: CGSize(width: availableSize.width, height: bottomPanelHeight)
|
||||
)
|
||||
self.buttonSeparator.backgroundColor = environment.theme.rootController.tabBar.separatorColor.cgColor
|
||||
self.buttonSeparator.opacity = Float(bottomPanelAlpha)
|
||||
|
||||
if let view = self.buttonBackground.view {
|
||||
if view.superview == nil {
|
||||
self.addSubview(view)
|
||||
self.layer.addSublayer(self.buttonSeparator)
|
||||
}
|
||||
view.alpha = bottomPanelAlpha
|
||||
view.frame = CGRect(origin: CGPoint(x: 0.0, y: availableSize.height - bottomPanelSize.height), size: bottomPanelSize)
|
||||
self.buttonSeparator.frame = CGRect(origin: CGPoint(x: 0.0, y: availableSize.height - bottomPanelSize.height), size: CGSize(width: availableSize.width, height: UIScreenPixel))
|
||||
}
|
||||
|
||||
var buttonIsEnabled = true
|
||||
let buttonString: String
|
||||
switch component.subject {
|
||||
case let .premium(product):
|
||||
@ -834,6 +887,9 @@ final class GiftSetupScreenComponent: Component {
|
||||
case let .starGift(starGift):
|
||||
let amountString = presentationStringsFormattedNumber(Int32(starGift.price), presentationData.dateTimeFormat.groupingSeparator)
|
||||
buttonString = "\(environment.strings.Gift_Send_Send) # \(amountString)"
|
||||
if let availability = starGift.availability, availability.remains == 0 {
|
||||
buttonIsEnabled = false
|
||||
}
|
||||
}
|
||||
|
||||
let buttonAttributedString = NSMutableAttributedString(string: buttonString, font: Font.semibold(17.0), textColor: environment.theme.list.itemCheckColors.foregroundColor, paragraphAlignment: .center)
|
||||
@ -856,20 +912,20 @@ final class GiftSetupScreenComponent: Component {
|
||||
id: AnyHashable(0),
|
||||
component: AnyComponent(MultilineTextComponent(text: .plain(buttonAttributedString)))
|
||||
),
|
||||
isEnabled: true,
|
||||
isEnabled: buttonIsEnabled,
|
||||
displaysProgress: self.inProgress,
|
||||
action: { [weak self] in
|
||||
self?.proceed()
|
||||
}
|
||||
)),
|
||||
environment: {},
|
||||
containerSize: CGSize(width: availableSize.width - sideInset * 2.0, height: 50)
|
||||
containerSize: CGSize(width: availableSize.width - sideInset * 2.0, height: buttonHeight)
|
||||
)
|
||||
if let buttonView = self.button.view {
|
||||
if buttonView.superview == nil {
|
||||
self.addSubview(buttonView)
|
||||
}
|
||||
buttonView.frame = CGRect(origin: CGPoint(x: floor((availableSize.width - buttonSize.width) / 2.0), y: availableSize.height - environment.safeInsets.bottom - buttonSize.height), size: buttonSize)
|
||||
buttonView.frame = CGRect(origin: CGPoint(x: floor((availableSize.width - buttonSize.width) / 2.0), y: availableSize.height - bottomPanelHeight + bottomPanelPadding), size: buttonSize)
|
||||
}
|
||||
|
||||
if self.textInputState.isEditing, let emojiSuggestion = self.textInputState.currentEmojiSuggestion, emojiSuggestion.disposable == nil {
|
||||
|
@ -119,6 +119,7 @@ public class RemainingCountComponent: Component {
|
||||
|
||||
private let badgeForeground: SimpleLayer
|
||||
private let badgeLabel: BadgeLabelView
|
||||
private let badgeLeftLabel = ComponentView<Empty>()
|
||||
private let badgeLabelMaskView = UIImageView()
|
||||
|
||||
private var badgeTailPosition: CGFloat = 0.0
|
||||
@ -737,7 +738,6 @@ final class BadgeLabelView: UIView {
|
||||
}
|
||||
|
||||
private var itemViews: [Int: StackView] = [:]
|
||||
private var staticLabel = UILabel()
|
||||
|
||||
init() {
|
||||
super.init(frame: .zero)
|
||||
@ -752,7 +752,6 @@ final class BadgeLabelView: UIView {
|
||||
|
||||
var color: UIColor = .white {
|
||||
didSet {
|
||||
self.staticLabel.textColor = self.color
|
||||
for (_, view) in self.itemViews {
|
||||
view.color = self.color
|
||||
}
|
||||
@ -760,25 +759,6 @@ final class BadgeLabelView: UIView {
|
||||
}
|
||||
|
||||
func update(value: String, transition: ComponentTransition) -> CGSize {
|
||||
if value.contains(" ") {
|
||||
for (_, view) in self.itemViews {
|
||||
view.isHidden = true
|
||||
}
|
||||
|
||||
if self.staticLabel.superview == nil {
|
||||
self.staticLabel.textColor = self.color
|
||||
self.staticLabel.font = font
|
||||
|
||||
self.addSubview(self.staticLabel)
|
||||
}
|
||||
|
||||
self.staticLabel.text = value
|
||||
let size = self.staticLabel.sizeThatFits(CGSize(width: 100.0, height: 100.0))
|
||||
self.staticLabel.frame = CGRect(origin: .zero, size: CGSize(width: size.width, height: labelHeight))
|
||||
|
||||
return CGSize(width: ceil(self.staticLabel.bounds.width), height: ceil(self.staticLabel.bounds.height))
|
||||
}
|
||||
|
||||
let string = value
|
||||
let stringArray = Array(string.map { String($0) }.reversed())
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user