mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-11-25 17:43:18 +00:00
Stars subscriptions
This commit is contained in:
parent
5145337d87
commit
cf28e1b651
@ -12674,3 +12674,5 @@ Sorry for the inconvenience.";
|
|||||||
"MediaPicker.CreateSticker" = "Create a sticker from a photo";
|
"MediaPicker.CreateSticker" = "Create a sticker from a photo";
|
||||||
|
|
||||||
"Stickers.CreateSticker" = "Create\nSticker";
|
"Stickers.CreateSticker" = "Create\nSticker";
|
||||||
|
|
||||||
|
"InviteLink.CreateNewInfo" = "You can create additional invite links that are limited by time, number of users, or require a paid subscription.";
|
||||||
|
|||||||
@ -351,7 +351,7 @@ private func inviteLinkListControllerEntries(presentationData: PresentationData,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if admin == nil {
|
if admin == nil {
|
||||||
entries.append(.linksInfo(presentationData.theme, presentationData.strings.InviteLink_CreateInfo))
|
entries.append(.linksInfo(presentationData.theme, presentationData.strings.InviteLink_CreateNewInfo))
|
||||||
}
|
}
|
||||||
|
|
||||||
if let revokedInvites = revokedInvites {
|
if let revokedInvites = revokedInvites {
|
||||||
|
|||||||
@ -798,7 +798,13 @@ public final class InviteLinkViewController: ViewController {
|
|||||||
if let pricing = invite.pricing {
|
if let pricing = invite.pricing {
|
||||||
//TODO:localize
|
//TODO:localize
|
||||||
entries.append(.subscriptionHeader(presentationData.theme, "SUBSCRIPTION FEE"))
|
entries.append(.subscriptionHeader(presentationData.theme, "SUBSCRIPTION FEE"))
|
||||||
entries.append(.subscriptionPricing(presentationData.theme, "⭐️\(pricing.amount) / month x \(state.count)", "You get approximately $\(Float(pricing.amount * Int64(state.count)) * 0.01) monthly"))
|
var title = "⭐️\(pricing.amount) / month"
|
||||||
|
var subtitle = "No one joined yet"
|
||||||
|
if state.count > 0 {
|
||||||
|
title += " x \(state.count)"
|
||||||
|
subtitle = "You get approximately $\(Float(pricing.amount * Int64(state.count)) * 0.01) monthly"
|
||||||
|
}
|
||||||
|
entries.append(.subscriptionPricing(presentationData.theme, title, subtitle))
|
||||||
}
|
}
|
||||||
|
|
||||||
entries.append(.creatorHeader(presentationData.theme, presentationData.strings.InviteLink_CreatedBy.uppercased()))
|
entries.append(.creatorHeader(presentationData.theme, presentationData.strings.InviteLink_CreatedBy.uppercased()))
|
||||||
|
|||||||
@ -231,15 +231,19 @@ final class StarsTransactionItemNode: ListViewItemNode, ItemListItemNode {
|
|||||||
var itemDate: String
|
var itemDate: String
|
||||||
switch item.transaction.peer {
|
switch item.transaction.peer {
|
||||||
case let .peer(peer):
|
case let .peer(peer):
|
||||||
if !item.transaction.media.isEmpty {
|
if !item.transaction.media.isEmpty {
|
||||||
itemTitle = item.presentationData.strings.Stars_Intro_Transaction_MediaPurchase
|
itemTitle = item.presentationData.strings.Stars_Intro_Transaction_MediaPurchase
|
||||||
itemSubtitle = peer.displayTitle(strings: item.presentationData.strings, displayOrder: .firstLast)
|
itemSubtitle = peer.displayTitle(strings: item.presentationData.strings, displayOrder: .firstLast)
|
||||||
} else if let title = item.transaction.title {
|
} else if let title = item.transaction.title {
|
||||||
itemTitle = title
|
itemTitle = title
|
||||||
itemSubtitle = peer.displayTitle(strings: item.presentationData.strings, displayOrder: .firstLast)
|
itemSubtitle = peer.displayTitle(strings: item.presentationData.strings, displayOrder: .firstLast)
|
||||||
} else {
|
} else {
|
||||||
|
if let _ = item.transaction.subscriptionPeriod {
|
||||||
|
itemSubtitle = "Monthly subscription fee"
|
||||||
|
} else {
|
||||||
|
itemSubtitle = nil
|
||||||
|
}
|
||||||
itemTitle = peer.displayTitle(strings: item.presentationData.strings, displayOrder: .firstLast)
|
itemTitle = peer.displayTitle(strings: item.presentationData.strings, displayOrder: .firstLast)
|
||||||
itemSubtitle = nil
|
|
||||||
}
|
}
|
||||||
case .appStore:
|
case .appStore:
|
||||||
itemTitle = item.presentationData.strings.Stars_Intro_Transaction_AppleTopUp_Title
|
itemTitle = item.presentationData.strings.Stars_Intro_Transaction_AppleTopUp_Title
|
||||||
|
|||||||
@ -297,11 +297,16 @@ public final class StarsImageComponent: Component {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public enum Icon {
|
||||||
|
case star
|
||||||
|
}
|
||||||
|
|
||||||
public let context: AccountContext
|
public let context: AccountContext
|
||||||
public let subject: Subject
|
public let subject: Subject
|
||||||
public let theme: PresentationTheme
|
public let theme: PresentationTheme
|
||||||
public let diameter: CGFloat
|
public let diameter: CGFloat
|
||||||
public let backgroundColor: UIColor
|
public let backgroundColor: UIColor
|
||||||
|
public let icon: Icon?
|
||||||
public let action: ((@escaping (Media) -> (ASDisplayNode, CGRect, () -> (UIView?, UIView?))?, @escaping (UIView) -> Void) -> Void)?
|
public let action: ((@escaping (Media) -> (ASDisplayNode, CGRect, () -> (UIView?, UIView?))?, @escaping (UIView) -> Void) -> Void)?
|
||||||
|
|
||||||
public init(
|
public init(
|
||||||
@ -310,6 +315,7 @@ public final class StarsImageComponent: Component {
|
|||||||
theme: PresentationTheme,
|
theme: PresentationTheme,
|
||||||
diameter: CGFloat,
|
diameter: CGFloat,
|
||||||
backgroundColor: UIColor,
|
backgroundColor: UIColor,
|
||||||
|
icon: Icon? = nil,
|
||||||
action: ((@escaping (Media) -> (ASDisplayNode, CGRect, () -> (UIView?, UIView?))?, @escaping (UIView) -> Void) -> Void)? = nil
|
action: ((@escaping (Media) -> (ASDisplayNode, CGRect, () -> (UIView?, UIView?))?, @escaping (UIView) -> Void) -> Void)? = nil
|
||||||
) {
|
) {
|
||||||
self.context = context
|
self.context = context
|
||||||
@ -317,6 +323,7 @@ public final class StarsImageComponent: Component {
|
|||||||
self.theme = theme
|
self.theme = theme
|
||||||
self.diameter = diameter
|
self.diameter = diameter
|
||||||
self.backgroundColor = backgroundColor
|
self.backgroundColor = backgroundColor
|
||||||
|
self.icon = icon
|
||||||
self.action = action
|
self.action = action
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -336,6 +343,9 @@ public final class StarsImageComponent: Component {
|
|||||||
if lhs.backgroundColor != rhs.backgroundColor {
|
if lhs.backgroundColor != rhs.backgroundColor {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
if lhs.icon != rhs.icon {
|
||||||
|
return false
|
||||||
|
}
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -353,6 +363,8 @@ public final class StarsImageComponent: Component {
|
|||||||
private var avatarNode: ImageNode?
|
private var avatarNode: ImageNode?
|
||||||
private var iconBackgroundView: UIImageView?
|
private var iconBackgroundView: UIImageView?
|
||||||
private var iconView: UIImageView?
|
private var iconView: UIImageView?
|
||||||
|
private var smallIconOutlineView: UIImageView?
|
||||||
|
private var smallIconView: UIImageView?
|
||||||
private var dustNode: MediaDustNode?
|
private var dustNode: MediaDustNode?
|
||||||
private var button: UIControl?
|
private var button: UIControl?
|
||||||
|
|
||||||
@ -814,6 +826,36 @@ public final class StarsImageComponent: Component {
|
|||||||
animationNode.updateLayout(size: animationFrame.size)
|
animationNode.updateLayout(size: animationFrame.size)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if let _ = component.icon {
|
||||||
|
let smallIconView: UIImageView
|
||||||
|
let smallIconOutlineView: UIImageView
|
||||||
|
if let current = self.smallIconView, let currentOutline = self.smallIconOutlineView {
|
||||||
|
smallIconView = current
|
||||||
|
smallIconOutlineView = currentOutline
|
||||||
|
} else {
|
||||||
|
smallIconOutlineView = UIImageView()
|
||||||
|
containerNode.view.addSubview(smallIconOutlineView)
|
||||||
|
|
||||||
|
smallIconView = UIImageView()
|
||||||
|
containerNode.view.addSubview(smallIconView)
|
||||||
|
}
|
||||||
|
|
||||||
|
smallIconView.image = UIImage(bundleImageName: "Premium/Stars/BalanceStar")
|
||||||
|
if smallIconOutlineView.image == nil {
|
||||||
|
smallIconOutlineView.image = generateTintedImage(image: smallIconView.image, color: .white)?.withRenderingMode(.alwaysTemplate)
|
||||||
|
}
|
||||||
|
smallIconOutlineView.tintColor = component.backgroundColor
|
||||||
|
|
||||||
|
if let icon = smallIconView.image {
|
||||||
|
let smallIconFrame = CGRect(origin: CGPoint(x: imageFrame.maxX - icon.size.width - 5.0, y: imageFrame.maxY - icon.size.height - 5.0), size: icon.size)
|
||||||
|
smallIconView.frame = smallIconFrame
|
||||||
|
smallIconOutlineView.frame = smallIconFrame.insetBy(dx: -3.0 + UIScreenPixel, dy: -3.0 + UIScreenPixel)
|
||||||
|
}
|
||||||
|
} else if let smallIconView = self.smallIconView {
|
||||||
|
self.smallIconView = nil
|
||||||
|
smallIconView.removeFromSuperview()
|
||||||
|
}
|
||||||
|
|
||||||
if let _ = component.action {
|
if let _ = component.action {
|
||||||
if self.button == nil {
|
if self.button == nil {
|
||||||
let button = UIControl(frame: imageFrame)
|
let button = UIControl(frame: imageFrame)
|
||||||
|
|||||||
@ -97,6 +97,8 @@ private final class StarsTransactionSheetContent: CombinedComponent {
|
|||||||
peerIds.append(receipt.botPaymentId)
|
peerIds.append(receipt.botPaymentId)
|
||||||
case let .gift(message):
|
case let .gift(message):
|
||||||
peerIds.append(message.id.peerId)
|
peerIds.append(message.id.peerId)
|
||||||
|
case let .subscription(subscription):
|
||||||
|
peerIds.append(subscription.peer.id)
|
||||||
}
|
}
|
||||||
|
|
||||||
self.disposable = (context.engine.data.get(
|
self.disposable = (context.engine.data.get(
|
||||||
@ -195,17 +197,30 @@ private final class StarsTransactionSheetContent: CombinedComponent {
|
|||||||
let messageId: EngineMessage.Id?
|
let messageId: EngineMessage.Id?
|
||||||
let toPeer: EnginePeer?
|
let toPeer: EnginePeer?
|
||||||
let transactionPeer: StarsContext.State.Transaction.Peer?
|
let transactionPeer: StarsContext.State.Transaction.Peer?
|
||||||
let media: [AnyMediaReference]
|
var media: [AnyMediaReference] = []
|
||||||
let photo: TelegramMediaWebFile?
|
var photo: TelegramMediaWebFile?
|
||||||
let isRefund: Bool
|
var isRefund = false
|
||||||
let isGift: Bool
|
var isGift = false
|
||||||
|
var isSubscription = false
|
||||||
|
var isSubscriptionFee = false
|
||||||
|
|
||||||
var delayedCloseOnOpenPeer = true
|
var delayedCloseOnOpenPeer = true
|
||||||
switch subject {
|
switch subject {
|
||||||
|
case let .subscription(subscription):
|
||||||
|
titleText = "Subscription"
|
||||||
|
descriptionText = ""
|
||||||
|
count = subscription.pricing.amount
|
||||||
|
transactionId = nil
|
||||||
|
date = subscription.untilDate
|
||||||
|
via = nil
|
||||||
|
messageId = nil
|
||||||
|
toPeer = subscription.peer
|
||||||
|
transactionPeer = .peer(subscription.peer)
|
||||||
|
isSubscription = true
|
||||||
case let .transaction(transaction, parentPeer):
|
case let .transaction(transaction, parentPeer):
|
||||||
if let _ = transaction.subscriptionPeriod {
|
if let _ = transaction.subscriptionPeriod {
|
||||||
//TODO:localize
|
//TODO:localize
|
||||||
titleText = "Monthly Subscription Fee"
|
titleText = "Monthly subscription fee"
|
||||||
descriptionText = ""
|
descriptionText = ""
|
||||||
count = transaction.count
|
count = transaction.count
|
||||||
countOnTop = false
|
countOnTop = false
|
||||||
@ -219,10 +234,7 @@ private final class StarsTransactionSheetContent: CombinedComponent {
|
|||||||
toPeer = nil
|
toPeer = nil
|
||||||
}
|
}
|
||||||
transactionPeer = transaction.peer
|
transactionPeer = transaction.peer
|
||||||
media = []
|
isSubscriptionFee = true
|
||||||
photo = nil
|
|
||||||
isRefund = false
|
|
||||||
isGift = false
|
|
||||||
} else if transaction.flags.contains(.isGift) {
|
} else if transaction.flags.contains(.isGift) {
|
||||||
titleText = strings.Stars_Gift_Received_Title
|
titleText = strings.Stars_Gift_Received_Title
|
||||||
descriptionText = strings.Stars_Gift_Received_Text
|
descriptionText = strings.Stars_Gift_Received_Text
|
||||||
@ -238,9 +250,6 @@ private final class StarsTransactionSheetContent: CombinedComponent {
|
|||||||
toPeer = nil
|
toPeer = nil
|
||||||
}
|
}
|
||||||
transactionPeer = transaction.peer
|
transactionPeer = transaction.peer
|
||||||
media = []
|
|
||||||
photo = nil
|
|
||||||
isRefund = false
|
|
||||||
isGift = true
|
isGift = true
|
||||||
} else {
|
} else {
|
||||||
switch transaction.peer {
|
switch transaction.peer {
|
||||||
@ -319,7 +328,6 @@ private final class StarsTransactionSheetContent: CombinedComponent {
|
|||||||
transactionPeer = transaction.peer
|
transactionPeer = transaction.peer
|
||||||
media = transaction.media.map { AnyMediaReference.starsTransaction(transaction: StarsTransactionReference(peerId: parentPeer.id, id: transaction.id, isRefund: transaction.flags.contains(.isRefund)), media: $0) }
|
media = transaction.media.map { AnyMediaReference.starsTransaction(transaction: StarsTransactionReference(peerId: parentPeer.id, id: transaction.id, isRefund: transaction.flags.contains(.isRefund)), media: $0) }
|
||||||
photo = transaction.photo
|
photo = transaction.photo
|
||||||
isGift = false
|
|
||||||
isRefund = transaction.flags.contains(.isRefund)
|
isRefund = transaction.flags.contains(.isRefund)
|
||||||
}
|
}
|
||||||
case let .receipt(receipt):
|
case let .receipt(receipt):
|
||||||
@ -336,10 +344,7 @@ private final class StarsTransactionSheetContent: CombinedComponent {
|
|||||||
toPeer = nil
|
toPeer = nil
|
||||||
}
|
}
|
||||||
transactionPeer = nil
|
transactionPeer = nil
|
||||||
media = []
|
|
||||||
photo = receipt.invoiceMedia.photo
|
photo = receipt.invoiceMedia.photo
|
||||||
isRefund = false
|
|
||||||
isGift = false
|
|
||||||
delayedCloseOnOpenPeer = false
|
delayedCloseOnOpenPeer = false
|
||||||
case let .gift(message):
|
case let .gift(message):
|
||||||
let incoming = message.flags.contains(.Incoming)
|
let incoming = message.flags.contains(.Incoming)
|
||||||
@ -365,9 +370,6 @@ private final class StarsTransactionSheetContent: CombinedComponent {
|
|||||||
toPeer = state.peerMap[message.id.peerId]
|
toPeer = state.peerMap[message.id.peerId]
|
||||||
}
|
}
|
||||||
transactionPeer = nil
|
transactionPeer = nil
|
||||||
media = []
|
|
||||||
photo = nil
|
|
||||||
isRefund = false
|
|
||||||
isGift = true
|
isGift = true
|
||||||
delayedCloseOnOpenPeer = false
|
delayedCloseOnOpenPeer = false
|
||||||
}
|
}
|
||||||
@ -416,6 +418,7 @@ private final class StarsTransactionSheetContent: CombinedComponent {
|
|||||||
)
|
)
|
||||||
|
|
||||||
let imageSubject: StarsImageComponent.Subject
|
let imageSubject: StarsImageComponent.Subject
|
||||||
|
let imageIcon: StarsImageComponent.Icon?
|
||||||
if isGift {
|
if isGift {
|
||||||
imageSubject = .gift(count)
|
imageSubject = .gift(count)
|
||||||
} else if !media.isEmpty {
|
} else if !media.isEmpty {
|
||||||
@ -429,6 +432,11 @@ private final class StarsTransactionSheetContent: CombinedComponent {
|
|||||||
} else {
|
} else {
|
||||||
imageSubject = .none
|
imageSubject = .none
|
||||||
}
|
}
|
||||||
|
if isSubscription || isSubscriptionFee {
|
||||||
|
imageIcon = .star
|
||||||
|
} else {
|
||||||
|
imageIcon = nil
|
||||||
|
}
|
||||||
let star = star.update(
|
let star = star.update(
|
||||||
component: StarsImageComponent(
|
component: StarsImageComponent(
|
||||||
context: component.context,
|
context: component.context,
|
||||||
@ -436,6 +444,7 @@ private final class StarsTransactionSheetContent: CombinedComponent {
|
|||||||
theme: theme,
|
theme: theme,
|
||||||
diameter: 90.0,
|
diameter: 90.0,
|
||||||
backgroundColor: theme.actionSheet.opaqueItemBackgroundColor,
|
backgroundColor: theme.actionSheet.opaqueItemBackgroundColor,
|
||||||
|
icon: imageIcon,
|
||||||
action: !media.isEmpty ? { transitionNode, addToTransitionSurface in
|
action: !media.isEmpty ? { transitionNode, addToTransitionSurface in
|
||||||
component.openMedia(media.map { $0.media }, transitionNode, addToTransitionSurface)
|
component.openMedia(media.map { $0.media }, transitionNode, addToTransitionSurface)
|
||||||
} : nil
|
} : nil
|
||||||
@ -939,6 +948,7 @@ public class StarsTransactionScreen: ViewControllerComponentContainer {
|
|||||||
case transaction(StarsContext.State.Transaction, EnginePeer)
|
case transaction(StarsContext.State.Transaction, EnginePeer)
|
||||||
case receipt(BotPaymentReceipt)
|
case receipt(BotPaymentReceipt)
|
||||||
case gift(EngineMessage)
|
case gift(EngineMessage)
|
||||||
|
case subscription(StarsContext.State.Subscription)
|
||||||
}
|
}
|
||||||
|
|
||||||
private let context: AccountContext
|
private let context: AccountContext
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user