Various improvements

This commit is contained in:
Ilya Laktyushin
2024-07-13 18:13:58 +04:00
parent 3134a4ef1b
commit 4216ee3933
125 changed files with 4969 additions and 1474 deletions

View File

@@ -27,9 +27,32 @@ import BundleIconComponent
import ConfettiEffect
private struct StarsProduct: Equatable {
let option: StarsTopUpOption
enum Option: Equatable {
case topUp(StarsTopUpOption)
case gift(StarsGiftOption)
}
let option: Option
let storeProduct: InAppPurchaseManager.Product
var count: Int64 {
switch self.option {
case let .topUp(option):
return option.count
case let .gift(option):
return option.count
}
}
var isExtended: Bool {
switch self.option {
case let .topUp(option):
return option.isExtended
case let .gift(option):
return option.isExtended
}
}
var id: String {
return self.storeProduct.id
}
@@ -54,13 +77,13 @@ private final class StarsPurchaseScreenContentComponent: CombinedComponent {
let externalState: ExternalState
let containerSize: CGSize
let balance: Int64?
let options: [StarsTopUpOption]
let peerId: EnginePeer.Id?
let requiredStars: Int64?
let options: [Any]
let purpose: StarsPurchasePurpose
let selectedProductId: String?
let forceDark: Bool
let products: [StarsProduct]?
let expanded: Bool
let peers: [EnginePeer.Id: EnginePeer]
let stateUpdated: (ComponentTransition) -> Void
let buy: (StarsProduct) -> Void
@@ -69,13 +92,13 @@ private final class StarsPurchaseScreenContentComponent: CombinedComponent {
externalState: ExternalState,
containerSize: CGSize,
balance: Int64?,
options: [StarsTopUpOption],
peerId: EnginePeer.Id?,
requiredStars: Int64?,
options: [Any],
purpose: StarsPurchasePurpose,
selectedProductId: String?,
forceDark: Bool,
products: [StarsProduct]?,
expanded: Bool,
peers: [EnginePeer.Id: EnginePeer],
stateUpdated: @escaping (ComponentTransition) -> Void,
buy: @escaping (StarsProduct) -> Void
) {
@@ -84,12 +107,12 @@ private final class StarsPurchaseScreenContentComponent: CombinedComponent {
self.containerSize = containerSize
self.balance = balance
self.options = options
self.peerId = peerId
self.requiredStars = requiredStars
self.purpose = purpose
self.selectedProductId = selectedProductId
self.forceDark = forceDark
self.products = products
self.expanded = expanded
self.peers = peers
self.stateUpdated = stateUpdated
self.buy = buy
}
@@ -101,13 +124,7 @@ private final class StarsPurchaseScreenContentComponent: CombinedComponent {
if lhs.containerSize != rhs.containerSize {
return false
}
if lhs.options != rhs.options {
return false
}
if lhs.peerId != rhs.peerId {
return false
}
if lhs.requiredStars != rhs.requiredStars {
if lhs.purpose != rhs.purpose {
return false
}
if lhs.selectedProductId != rhs.selectedProductId {
@@ -122,6 +139,9 @@ private final class StarsPurchaseScreenContentComponent: CombinedComponent {
if lhs.expanded != rhs.expanded {
return false
}
if lhs.peers != rhs.peers {
return false
}
return true
}
@@ -129,31 +149,18 @@ private final class StarsPurchaseScreenContentComponent: CombinedComponent {
private let context: AccountContext
var products: [StarsProduct]?
var peer: EnginePeer?
private var disposable: Disposable?
var cachedChevronImage: (UIImage, PresentationTheme)?
init(
context: AccountContext,
peerId: EnginePeer.Id?
purpose: StarsPurchasePurpose
) {
self.context = context
super.init()
if let peerId {
self.disposable = (context.engine.data.subscribe(
TelegramEngine.EngineData.Item.Peer.Peer(id: peerId)
)
|> deliverOnMainQueue).start(next: { [weak self] peer in
if let self, let peer {
self.peer = peer
self.updated(transition: .immediate)
}
})
}
let _ = updatePremiumPromoConfigurationOnce(account: context.account).start()
}
deinit {
@@ -162,63 +169,32 @@ private final class StarsPurchaseScreenContentComponent: CombinedComponent {
}
func makeState() -> State {
return State(context: self.context, peerId: self.peerId)
return State(context: self.context, purpose: self.purpose)
}
static var body: Body {
// let overscroll = Child(Rectangle.self)
// let fade = Child(RoundedRectangle.self)
let text = Child(BalancedTextComponent.self)
let list = Child(VStack<Empty>.self)
let termsText = Child(BalancedTextComponent.self)
return { context in
let sideInset: CGFloat = 16.0
let component = context.component
let scrollEnvironment = context.environment[ScrollChildEnvironment.self].value
let environment = context.environment[ViewControllerComponentContainer.Environment.self].value
let state = context.state
state.products = context.component.products
state.products = component.products
let theme = environment.theme
let strings = environment.strings
let presentationData = context.component.context.sharedContext.currentPresentationData.with { $0 }
let presentationData = component.context.sharedContext.currentPresentationData.with { $0 }
let availableWidth = context.availableSize.width
let sideInsets = sideInset * 2.0 + environment.safeInsets.left + environment.safeInsets.right
var size = CGSize(width: context.availableSize.width, height: 0.0)
// var topBackgroundColor = theme.list.plainBackgroundColor
// let bottomBackgroundColor = theme.list.blocksBackgroundColor
// if theme.overallDarkAppearance {
// topBackgroundColor = bottomBackgroundColor
// }
//
// let overscroll = overscroll.update(
// component: Rectangle(color: topBackgroundColor),
// availableSize: CGSize(width: context.availableSize.width, height: 1000),
// transition: context.transition
// )
// context.add(overscroll
// .position(CGPoint(x: overscroll.size.width / 2.0, y: -overscroll.size.height / 2.0))
// )
//
// let fade = fade.update(
// component: RoundedRectangle(
// colors: [
// topBackgroundColor,
// bottomBackgroundColor
// ],
// cornerRadius: 0.0,
// gradientDirection: .vertical
// ),
// availableSize: CGSize(width: availableWidth, height: 300),
// transition: context.transition
// )
// context.add(fade
// .position(CGPoint(x: fade.size.width / 2.0, y: fade.size.height / 2.0))
// )
size.height += 183.0 + 10.0 + environment.navigationHeight - 56.0
let textColor = theme.list.itemPrimaryTextColor
@@ -228,22 +204,36 @@ private final class StarsPurchaseScreenContentComponent: CombinedComponent {
let boldTextFont = Font.semibold(15.0)
let textString: String
if let _ = context.component.requiredStars {
textString = state.peer == nil ? strings.Stars_Purchase_StarsNeededUnlockInfo : strings.Stars_Purchase_StarsNeededInfo(state.peer?.compactDisplayTitle ?? "").string
} else {
switch context.component.purpose {
case .generic:
textString = strings.Stars_Purchase_GetStarsInfo
case .gift:
textString = strings.Stars_Purchase_GiftInfo(component.peers.first?.value.compactDisplayTitle ?? "").string
case .transfer:
textString = strings.Stars_Purchase_StarsNeededInfo(component.peers.first?.value.compactDisplayTitle ?? "").string
case let .subscription(_, _, renew):
textString = renew ? strings.Stars_Purchase_SubscriptionRenewInfo(component.peers.first?.value.compactDisplayTitle ?? "").string : strings.Stars_Purchase_SubscriptionInfo(component.peers.first?.value.compactDisplayTitle ?? "").string
case .unlockMedia:
textString = strings.Stars_Purchase_StarsNeededUnlockInfo
}
let markdownAttributes = MarkdownAttributes(body: MarkdownAttributeSet(font: textFont, textColor: textColor), bold: MarkdownAttributeSet(font: boldTextFont, textColor: textColor), link: MarkdownAttributeSet(font: textFont, textColor: accentColor), linkAttribute: { contents in
return (TelegramTextAttributes.URL, contents)
})
if state.cachedChevronImage == nil || state.cachedChevronImage?.1 !== theme {
state.cachedChevronImage = (generateTintedImage(image: UIImage(bundleImageName: "Settings/TextArrowRight"), color: accentColor)!, theme)
}
let titleAttributedString = parseMarkdownIntoAttributedString(textString, attributes: markdownAttributes).mutableCopy() as! NSMutableAttributedString
if let range = titleAttributedString.string.range(of: ">"), let chevronImage = state.cachedChevronImage?.0 {
titleAttributedString.addAttribute(.attachment, value: chevronImage, range: NSRange(range, in: titleAttributedString.string))
}
let text = text.update(
component: BalancedTextComponent(
text: .markdown(
text: textString,
attributes: markdownAttributes
),
text: .plain(titleAttributedString),
horizontalAlignment: .center,
maximumNumberOfLines: 0,
lineSpacing: 0.2,
@@ -271,16 +261,7 @@ private final class StarsPurchaseScreenContentComponent: CombinedComponent {
size.height += 21.0
context.component.externalState.descriptionHeight = text.size.height
let initialValues: [Int64] = [
15,
75,
250,
500,
1000,
2500
]
let stars: [Int64: Int] = [
15: 1,
75: 2,
@@ -312,21 +293,21 @@ private final class StarsPurchaseScreenContentComponent: CombinedComponent {
if let products = state.products, let balance = context.component.balance {
var minimumCount: Int64?
if let requiredStars = context.component.requiredStars {
if let requiredStars = context.component.purpose.requiredStars {
minimumCount = requiredStars - balance
}
for product in products {
if let minimumCount, minimumCount > product.option.count && !(items.isEmpty && product.id == products.last?.id) {
if let minimumCount, minimumCount > product.count && !(items.isEmpty && product.id == products.last?.id) {
continue
}
if let _ = minimumCount, items.isEmpty {
} else if !context.component.expanded && !initialValues.contains(product.option.count) {
} else if !context.component.expanded && product.isExtended {
continue
}
let title = strings.Stars_Purchase_Stars(Int32(product.option.count))
let title = strings.Stars_Purchase_Stars(Int32(product.count))
let price = product.price
let titleComponent = AnyComponent(MultilineTextComponent(
@@ -360,7 +341,7 @@ private final class StarsPurchaseScreenContentComponent: CombinedComponent {
title: titleComponent,
contentInsets: UIEdgeInsets(top: 12.0, left: -6.0, bottom: 12.0, right: 0.0),
leftIcon: .custom(AnyComponentWithIdentity(id: 0, component: AnyComponent(StarsIconComponent(
count: stars[product.option.count] ?? 1
count: stars[product.count] ?? 1
))), true),
accessory: .custom(ListActionItemComponent.CustomAccessory(component: AnyComponentWithIdentity(id: 0, component: AnyComponent(MultilineTextComponent(
text: .plain(NSAttributedString(
@@ -445,7 +426,6 @@ private final class StarsPurchaseScreenContentComponent: CombinedComponent {
})
let textSideInset: CGFloat = 16.0
let component = context.component
let termsText = termsText.update(
component: BalancedTextComponent(
text: .markdown(text: strings.Stars_Purchase_Info, attributes: termsMarkdownAttributes),
@@ -490,9 +470,8 @@ private final class StarsPurchaseScreenComponent: CombinedComponent {
let context: AccountContext
let starsContext: StarsContext
let options: [StarsTopUpOption]
let peerId: EnginePeer.Id?
let requiredStars: Int64?
let options: [Any]
let purpose: StarsPurchasePurpose
let forceDark: Bool
let updateInProgress: (Bool) -> Void
let present: (ViewController) -> Void
@@ -501,9 +480,8 @@ private final class StarsPurchaseScreenComponent: CombinedComponent {
init(
context: AccountContext,
starsContext: StarsContext,
options: [StarsTopUpOption],
peerId: EnginePeer.Id?,
requiredStars: Int64?,
options: [Any],
purpose: StarsPurchasePurpose,
forceDark: Bool,
updateInProgress: @escaping (Bool) -> Void,
present: @escaping (ViewController) -> Void,
@@ -512,8 +490,7 @@ private final class StarsPurchaseScreenComponent: CombinedComponent {
self.context = context
self.starsContext = starsContext
self.options = options
self.peerId = peerId
self.requiredStars = requiredStars
self.purpose = purpose
self.forceDark = forceDark
self.updateInProgress = updateInProgress
self.present = present
@@ -527,13 +504,7 @@ private final class StarsPurchaseScreenComponent: CombinedComponent {
if lhs.starsContext !== rhs.starsContext {
return false
}
if lhs.options != rhs.options {
return false
}
if lhs.peerId != rhs.peerId {
return false
}
if lhs.requiredStars != rhs.requiredStars {
if lhs.purpose != rhs.purpose {
return false
}
if lhs.forceDark != rhs.forceDark {
@@ -544,6 +515,8 @@ private final class StarsPurchaseScreenComponent: CombinedComponent {
final class State: ComponentState {
private let context: AccountContext
private let purpose: StarsPurchasePurpose
private let updateInProgress: (Bool) -> Void
private let present: (ViewController) -> Void
private let completion: (Int64) -> Void
@@ -554,11 +527,11 @@ private final class StarsPurchaseScreenComponent: CombinedComponent {
var hasIdleAnimations = true
var progressProduct: StarsProduct?
private(set) var promoConfiguration: PremiumPromoConfiguration?
private(set) var products: [StarsProduct]?
private(set) var starsState: StarsContext.State?
var peers: [EnginePeer.Id: EnginePeer] = [:]
let animationCache: AnimationCache
let animationRenderer: MultiAnimationRenderer
@@ -569,12 +542,14 @@ private final class StarsPurchaseScreenComponent: CombinedComponent {
init(
context: AccountContext,
starsContext: StarsContext,
initialOptions: [StarsTopUpOption],
purpose: StarsPurchasePurpose,
initialOptions: [Any],
updateInProgress: @escaping (Bool) -> Void,
present: @escaping (ViewController) -> Void,
completion: @escaping (Int64) -> Void
) {
self.context = context
self.purpose = purpose
self.updateInProgress = updateInProgress
self.present = present
self.completion = completion
@@ -590,32 +565,65 @@ private final class StarsPurchaseScreenComponent: CombinedComponent {
} else {
availableProducts = .single([])
}
let options: Signal<[StarsTopUpOption], NoError>
if !initialOptions.isEmpty {
options = .single(initialOptions)
} else {
options = .single([]) |> then(context.engine.payments.starsTopUpOptions())
let products: Signal<[StarsProduct], NoError>
switch purpose {
case .gift:
let options: Signal<[StarsGiftOption], NoError>
if !initialOptions.isEmpty, let initialGiftOptions = initialOptions as? [StarsGiftOption] {
options = .single(initialGiftOptions)
} else {
options = .single([]) |> then(context.engine.payments.starsGiftOptions(peerId: nil))
}
products = combineLatest(availableProducts, options)
|> map { availableProducts, options in
var products: [StarsProduct] = []
for option in options {
if let product = availableProducts.first(where: { $0.id == option.storeProductId }) {
products.append(StarsProduct(option: .gift(option), storeProduct: product))
}
}
return products
}
default:
let options: Signal<[StarsTopUpOption], NoError>
if !initialOptions.isEmpty, let initialTopUpOptions = initialOptions as? [StarsTopUpOption] {
options = .single(initialTopUpOptions)
} else {
options = .single([]) |> then(context.engine.payments.starsTopUpOptions())
}
products = combineLatest(availableProducts, options)
|> map { availableProducts, options in
var products: [StarsProduct] = []
for option in options {
if let product = availableProducts.first(where: { $0.id == option.storeProductId }) {
products.append(StarsProduct(option: .topUp(option), storeProduct: product))
}
}
return products
}
}
let peerIds = purpose.peerIds
self.disposable = combineLatest(
queue: Queue.mainQueue(),
availableProducts,
options,
starsContext.state
).start(next: { [weak self] availableProducts, options, starsState in
products,
starsContext.state,
context.engine.data.get(EngineDataMap(peerIds.map(TelegramEngine.EngineData.Item.Peer.Peer.init(id:))))
).start(next: { [weak self] products, starsState, result in
guard let self else {
return
}
var products: [StarsProduct] = []
for option in options {
if let product = availableProducts.first(where: { $0.id == option.storeProductId }) {
products.append(StarsProduct(option: option, storeProduct: product))
self.products = products.sorted(by: { $0.count < $1.count })
self.starsState = starsState
var peers: [EnginePeer.Id: EnginePeer] = [:]
for peerId in peerIds {
if let maybePeer = result[peerId], let peer = maybePeer {
peers[peerId] = peer
}
}
self.products = products.sorted(by: { $0.option.count < $1.option.count })
self.starsState = starsState
self.peers = peers
self.updated(transition: .immediate)
})
@@ -636,7 +644,13 @@ private final class StarsPurchaseScreenComponent: CombinedComponent {
self.updated(transition: .easeInOut(duration: 0.2))
let (currency, amount) = product.storeProduct.priceCurrencyAndAmount
let purpose: AppStoreTransactionPurpose = .stars(count: product.option.count, currency: currency, amount: amount)
let purpose: AppStoreTransactionPurpose
switch self.purpose {
case let .gift(peerId):
purpose = .starsGift(peerId: peerId, count: product.count, currency: currency, amount: amount)
default:
purpose = .stars(count: product.count, currency: currency, amount: amount)
}
let _ = (self.context.engine.payments.canPurchasePremium(purpose: purpose)
|> deliverOnMainQueue).start(next: { [weak self] available in
@@ -649,7 +663,7 @@ private final class StarsPurchaseScreenComponent: CombinedComponent {
self.updateInProgress(false)
self.updated(transition: .easeInOut(duration: 0.2))
self.completion(product.option.count)
self.completion(product.count)
}
}, error: { [weak self] error in
if let strongSelf = self {
@@ -699,13 +713,14 @@ private final class StarsPurchaseScreenComponent: CombinedComponent {
}
func makeState() -> State {
return State(context: self.context, starsContext: self.starsContext, initialOptions: self.options, updateInProgress: self.updateInProgress, present: self.present, completion: self.completion)
return State(context: self.context, starsContext: self.starsContext, purpose: self.purpose, initialOptions: self.options, updateInProgress: self.updateInProgress, present: self.present, completion: self.completion)
}
static var body: Body {
let background = Child(Rectangle.self)
let scrollContent = Child(ScrollComponent<EnvironmentType>.self)
let star = Child(PremiumStarComponent.self)
let avatar = Child(GiftAvatarComponent.self)
let topPanel = Child(BlurredBackgroundComponent.self)
let topSeparator = Child(Rectangle.self)
let title = Child(MultilineTextComponent.self)
@@ -730,23 +745,44 @@ private final class StarsPurchaseScreenComponent: CombinedComponent {
starIsVisible = false
}
let header = star.update(
component: PremiumStarComponent(
theme: environment.theme,
isIntro: true,
isVisible: starIsVisible,
hasIdleAnimations: state.hasIdleAnimations,
colors: [
UIColor(rgb: 0xe57d02),
UIColor(rgb: 0xf09903),
UIColor(rgb: 0xf9b004),
UIColor(rgb: 0xfdd219)
],
particleColor: UIColor(rgb: 0xf9b004)
),
availableSize: CGSize(width: min(414.0, context.availableSize.width), height: 220.0),
transition: context.transition
)
let header: _UpdatedChildComponent
if case let .gift(peerId) = context.component.purpose {
var peers: [EnginePeer] = []
if let peer = state.peers[peerId] {
peers.append(peer)
}
header = avatar.update(
component: GiftAvatarComponent(
context: context.component.context,
theme: environment.theme,
peers: peers,
isVisible: starIsVisible,
hasIdleAnimations: state.hasIdleAnimations,
color: UIColor(rgb: 0xf9b004),
hasLargeParticles: true
),
availableSize: CGSize(width: min(414.0, context.availableSize.width), height: 220.0),
transition: context.transition
)
} else {
header = star.update(
component: PremiumStarComponent(
theme: environment.theme,
isIntro: true,
isVisible: starIsVisible,
hasIdleAnimations: state.hasIdleAnimations,
colors: [
UIColor(rgb: 0xe57d02),
UIColor(rgb: 0xf09903),
UIColor(rgb: 0xf9b004),
UIColor(rgb: 0xfdd219)
],
particleColor: UIColor(rgb: 0xf9b004)
),
availableSize: CGSize(width: min(414.0, context.availableSize.width), height: 220.0),
transition: context.transition
)
}
let topPanel = topPanel.update(
component: BlurredBackgroundComponent(
@@ -765,10 +801,13 @@ private final class StarsPurchaseScreenComponent: CombinedComponent {
)
let titleText: String
if let requiredStars = context.component.requiredStars {
titleText = strings.Stars_Purchase_StarsNeeded(Int32(requiredStars))
} else {
switch context.component.purpose {
case .generic:
titleText = strings.Stars_Purchase_GetStars
case .gift:
titleText = strings.Stars_Purchase_GiftStars
case let .transfer(_, requiredStars), let .subscription(_, requiredStars, _), let .unlockMedia(requiredStars):
titleText = strings.Stars_Purchase_StarsNeeded(Int32(requiredStars))
}
let title = title.update(
@@ -820,12 +859,12 @@ private final class StarsPurchaseScreenComponent: CombinedComponent {
containerSize: context.availableSize,
balance: state.starsState?.balance,
options: context.component.options,
peerId: context.component.peerId,
requiredStars: context.component.requiredStars,
purpose: context.component.purpose,
selectedProductId: state.progressProduct?.storeProduct.id,
forceDark: context.component.forceDark,
products: state.products,
expanded: state.isExpanded,
peers: state.peers,
stateUpdated: { [weak state] transition in
scrollAction.invoke(CGPoint(x: 0.0, y: 150.0 + contentExternalState.descriptionHeight))
state?.isExpanded = true
@@ -929,7 +968,6 @@ private final class StarsPurchaseScreenComponent: CombinedComponent {
public final class StarsPurchaseScreen: ViewControllerComponentContainer {
fileprivate let context: AccountContext
fileprivate let starsContext: StarsContext
fileprivate let options: [StarsTopUpOption]
private var didSetReady = false
private let _ready = Promise<Bool>()
@@ -940,16 +978,12 @@ public final class StarsPurchaseScreen: ViewControllerComponentContainer {
public init(
context: AccountContext,
starsContext: StarsContext,
options: [StarsTopUpOption],
peerId: EnginePeer.Id?,
requiredStars: Int64?,
modal: Bool = true,
forceDark: Bool = false,
options: [Any] = [],
purpose: StarsPurchasePurpose,
completion: @escaping (Int64) -> Void = { _ in }
) {
self.context = context
self.starsContext = starsContext
self.options = options
var updateInProgressImpl: ((Bool) -> Void)?
var presentImpl: ((ViewController) -> Void)?
@@ -958,9 +992,8 @@ public final class StarsPurchaseScreen: ViewControllerComponentContainer {
context: context,
starsContext: starsContext,
options: options,
peerId: peerId,
requiredStars: requiredStars,
forceDark: forceDark,
purpose: purpose,
forceDark: false,
updateInProgress: { inProgress in
updateInProgressImpl?(inProgress)
},
@@ -970,17 +1003,13 @@ public final class StarsPurchaseScreen: ViewControllerComponentContainer {
completion: { stars in
completionImpl?(stars)
}
), navigationBarAppearance: .transparent, presentationMode: modal ? .modal : .default, theme: forceDark ? .dark : .default)
), navigationBarAppearance: .transparent, presentationMode: .modal, theme: .default)
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
if modal {
let cancelItem = UIBarButtonItem(title: presentationData.strings.Common_Close, style: .plain, target: self, action: #selector(self.cancelPressed))
self.navigationItem.setLeftBarButton(cancelItem, animated: false)
self.navigationPresentation = .modal
} else {
self.navigationPresentation = .modalInLargeLayout
}
let cancelItem = UIBarButtonItem(title: presentationData.strings.Common_Close, style: .plain, target: self, action: #selector(self.cancelPressed))
self.navigationItem.setLeftBarButton(cancelItem, animated: false)
self.navigationPresentation = .modal
updateInProgressImpl = { [weak self] inProgress in
if let strongSelf = self {
@@ -1043,6 +1072,9 @@ public final class StarsPurchaseScreen: ViewControllerComponentContainer {
if let view = self.node.hostView.findTaggedView(tag: PremiumStarComponent.View.Tag()) as? PremiumStarComponent.View {
self.didSetReady = true
self._ready.set(view.ready)
} else if let view = self.node.hostView.findTaggedView(tag: GiftAvatarComponent.View.Tag()) as? GiftAvatarComponent.View {
self.didSetReady = true
self._ready.set(view.ready)
}
}
}
@@ -1141,3 +1173,31 @@ final class StarsIconComponent: CombinedComponent {
}
}
}
private extension StarsPurchasePurpose {
var peerIds: [EnginePeer.Id] {
switch self {
case let .gift(peerId):
return [peerId]
case let .transfer(peerId, _):
return [peerId]
case let .subscription(peerId, _, _):
return [peerId]
default:
return []
}
}
var requiredStars: Int64? {
switch self {
case let .transfer(_, requiredStars):
return requiredStars
case let .subscription(_, requiredStars, _):
return requiredStars
case let .unlockMedia(requiredStars):
return requiredStars
default:
return nil
}
}
}