Stars ref

This commit is contained in:
Isaac 2024-11-29 17:05:02 +04:00
parent ef652c0e30
commit 005887b8a8
7 changed files with 295 additions and 54 deletions

View File

@ -896,14 +896,12 @@ public enum JoinAffiliateProgramScreenMode {
public final class Active {
public let targetPeer: EnginePeer
public let link: String
public let userCount: Int
public let copyLink: () -> Void
public let bot: TelegramConnectedStarRefBotList.Item
public let copyLink: (TelegramConnectedStarRefBotList.Item) -> Void
public init(targetPeer: EnginePeer, link: String, userCount: Int, copyLink: @escaping () -> Void) {
public init(targetPeer: EnginePeer, bot: TelegramConnectedStarRefBotList.Item, copyLink: @escaping (TelegramConnectedStarRefBotList.Item) -> Void) {
self.targetPeer = targetPeer
self.link = link
self.userCount = userCount
self.bot = bot
self.copyLink = copyLink
}
}

View File

@ -632,7 +632,6 @@ func _internal_updateStarRefProgram(account: Account, id: EnginePeer.Id, program
}
public final class TelegramConnectedStarRefBotList : Equatable {
public final class Item: Equatable {
public let peer: EnginePeer
public let url: String

View File

@ -302,6 +302,10 @@ public struct StarsAmount: Equatable, Comparable, Hashable, Codable, CustomStrin
}
public static func +(lhs: StarsAmount, rhs: StarsAmount) -> StarsAmount {
if rhs.value < 0 || rhs.nanos < 0 {
return lhs - StarsAmount(value: abs(rhs.value), nanos: abs(rhs.nanos))
}
let totalNanos = Int64(lhs.nanos) + Int64(rhs.nanos)
let overflow = totalNanos / 1_000_000_000
let remainingNanos = totalNanos % 1_000_000_000
@ -529,7 +533,7 @@ private final class StarsContextImpl {
}
var transactions = state.transactions
if addTransaction {
transactions.insert(.init(flags: [.isLocal], id: "\(arc4random())", count: balance, date: Int32(Date().timeIntervalSince1970), peer: .appStore, title: nil, description: nil, photo: nil, transactionDate: nil, transactionUrl: nil, paidMessageId: nil, giveawayMessageId: nil, media: [], subscriptionPeriod: nil, starGift: nil, floodskipNumber: nil), at: 0)
transactions.insert(.init(flags: [.isLocal], id: "\(arc4random())", count: balance, date: Int32(Date().timeIntervalSince1970), peer: .appStore, title: nil, description: nil, photo: nil, transactionDate: nil, transactionUrl: nil, paidMessageId: nil, giveawayMessageId: nil, media: [], subscriptionPeriod: nil, starGift: nil, floodskipNumber: nil, starrefCommissionPermille: nil, starrefPeerId: nil, starrefAmount: nil), at: 0)
}
self.updateState(StarsContext.State(flags: [.isPendingBalance], balance: max(StarsAmount(value: 0, nanos: 0), state.balance + balance), subscriptions: state.subscriptions, canLoadMoreSubscriptions: state.canLoadMoreSubscriptions, transactions: transactions, canLoadMoreTransactions: state.canLoadMoreTransactions, isLoading: state.isLoading))
@ -552,10 +556,6 @@ private extension StarsContext.State.Transaction {
init?(apiTransaction: Api.StarsTransaction, peerId: EnginePeer.Id?, transaction: Transaction) {
switch apiTransaction {
case let .starsTransaction(apiFlags, id, stars, date, transactionPeer, title, description, photo, transactionDate, transactionUrl, _, messageId, extendedMedia, subscriptionPeriod, giveawayPostId, starGift, floodskipNumber, starrefCommissionPermille, starrefPeer, starrefAmount):
let _ = starrefCommissionPermille
let _ = starrefPeer
let _ = starrefAmount
let parsedPeer: StarsContext.State.Transaction.Peer
var paidMessageId: MessageId?
var giveawayMessageId: MessageId?
@ -611,7 +611,7 @@ private extension StarsContext.State.Transaction {
let media = extendedMedia.flatMap({ $0.compactMap { textMediaAndExpirationTimerFromApiMedia($0, PeerId(0)).media } }) ?? []
let _ = subscriptionPeriod
self.init(flags: flags, id: id, count: StarsAmount(apiAmount: stars), date: date, peer: parsedPeer, title: title, description: description, photo: photo.flatMap(TelegramMediaWebFile.init), transactionDate: transactionDate, transactionUrl: transactionUrl, paidMessageId: paidMessageId, giveawayMessageId: giveawayMessageId, media: media, subscriptionPeriod: subscriptionPeriod, starGift: starGift.flatMap { StarGift(apiStarGift: $0) }, floodskipNumber: floodskipNumber)
self.init(flags: flags, id: id, count: StarsAmount(apiAmount: stars), date: date, peer: parsedPeer, title: title, description: description, photo: photo.flatMap(TelegramMediaWebFile.init), transactionDate: transactionDate, transactionUrl: transactionUrl, paidMessageId: paidMessageId, giveawayMessageId: giveawayMessageId, media: media, subscriptionPeriod: subscriptionPeriod, starGift: starGift.flatMap { StarGift(apiStarGift: $0) }, floodskipNumber: floodskipNumber, starrefCommissionPermille: starrefCommissionPermille, starrefPeerId: starrefPeer.flatMap(\.peerId), starrefAmount: starrefAmount.flatMap(StarsAmount.init(apiAmount:)))
}
}
}
@ -686,6 +686,9 @@ public final class StarsContext {
public let subscriptionPeriod: Int32?
public let starGift: StarGift?
public let floodskipNumber: Int32?
public let starrefCommissionPermille: Int32?
public let starrefPeerId: PeerId?
public let starrefAmount: StarsAmount?
public init(
flags: Flags,
@ -703,7 +706,10 @@ public final class StarsContext {
media: [Media],
subscriptionPeriod: Int32?,
starGift: StarGift?,
floodskipNumber: Int32?
floodskipNumber: Int32?,
starrefCommissionPermille: Int32?,
starrefPeerId: PeerId?,
starrefAmount: StarsAmount?
) {
self.flags = flags
self.id = id
@ -721,6 +727,9 @@ public final class StarsContext {
self.subscriptionPeriod = subscriptionPeriod
self.starGift = starGift
self.floodskipNumber = floodskipNumber
self.starrefCommissionPermille = starrefCommissionPermille
self.starrefPeerId = starrefPeerId
self.starrefAmount = starrefAmount
}
public static func == (lhs: Transaction, rhs: Transaction) -> Bool {
@ -772,6 +781,15 @@ public final class StarsContext {
if lhs.floodskipNumber != rhs.floodskipNumber {
return false
}
if lhs.starrefCommissionPermille != rhs.starrefCommissionPermille {
return false
}
if lhs.starrefPeerId != rhs.starrefPeerId {
return false
}
if lhs.starrefAmount != rhs.starrefAmount {
return false
}
return true
}
}

View File

@ -364,9 +364,8 @@ If you end your affiliate program:
programDuration: bot.durationMonths,
mode: .active(JoinAffiliateProgramScreenMode.Active(
targetPeer: targetPeer,
link: bot.url,
userCount: Int(bot.participants),
copyLink: { [weak self] in
bot: bot,
copyLink: { [weak self] bot in
guard let self, let component = self.component else {
return
}

View File

@ -119,10 +119,14 @@ private final class JoinAffiliateProgramScreenComponent: Component {
private var topOffsetDistance: CGFloat?
private var currentTargetPeer: EnginePeer?
private var currentMode: JoinAffiliateProgramScreen.Mode?
private var possibleTargetPeers: [EnginePeer] = []
private var possibleTargetPeersDisposable: Disposable?
private var changeTargetPeerDisposable: Disposable?
private var isChangingTargetPeer: Bool = false
private var cachedCloseImage: UIImage?
override init(frame: CGRect) {
@ -194,6 +198,7 @@ private final class JoinAffiliateProgramScreenComponent: Component {
deinit {
self.possibleTargetPeersDisposable?.dispose()
self.changeTargetPeerDisposable?.dispose()
}
func scrollViewDidScroll(_ scrollView: UIScrollView) {
@ -337,7 +342,7 @@ private final class JoinAffiliateProgramScreenComponent: Component {
guard let component = self.component, let environment = self.environment, let controller = environment.controller() else {
return
}
guard case let .join(join) = component.mode else {
guard let currentTargetPeer = self.currentTargetPeer else {
return
}
@ -346,7 +351,7 @@ private final class JoinAffiliateProgramScreenComponent: Component {
let presentationData = component.context.sharedContext.currentPresentationData.with({ $0 })
let peers: [EnginePeer] = self.possibleTargetPeers.isEmpty ? [
join.initialTargetPeer
currentTargetPeer
] : self.possibleTargetPeers
let avatarSize = CGSize(width: 30.0, height: 30.0)
@ -360,14 +365,80 @@ private final class JoinAffiliateProgramScreenComponent: Component {
} else {
peerLabel = "bot"
}
items.append(.action(ContextMenuActionItem(text: peer.displayTitle(strings: environment.strings, displayOrder: presentationData.nameDisplayOrder), textLayout: .secondLineWithValue(peerLabel), icon: { _ in nil }, iconSource: ContextMenuActionItemIconSource(size: avatarSize, signal: peerAvatarCompleteImage(account: component.context.account, peer: peer, size: avatarSize)), action: { [weak self] c, _ in
let isSelected = peer.id == self.currentTargetPeer?.id
let accentColor = environment.theme.list.itemAccentColor
let avatarSignal = peerAvatarCompleteImage(account: component.context.account, peer: peer, size: avatarSize)
|> map { image in
let context = DrawingContext(size: avatarSize, scale: 0.0, clear: true)
context?.withContext { c in
UIGraphicsPushContext(c)
defer {
UIGraphicsPopContext()
}
if isSelected {
}
c.saveGState()
let scaleFactor = (avatarSize.width - 3.0 * 2.0) / avatarSize.width
if isSelected {
c.translateBy(x: avatarSize.width * 0.5, y: avatarSize.height * 0.5)
c.scaleBy(x: scaleFactor, y: scaleFactor)
c.translateBy(x: -avatarSize.width * 0.5, y: -avatarSize.height * 0.5)
}
if let image {
image.draw(in: CGRect(origin: CGPoint(), size: avatarSize))
}
c.restoreGState()
if isSelected {
c.setStrokeColor(accentColor.cgColor)
let lineWidth: CGFloat = 1.0 + UIScreenPixel
c.setLineWidth(lineWidth)
c.strokeEllipse(in: CGRect(origin: CGPoint(), size: avatarSize).insetBy(dx: lineWidth * 0.5, dy: lineWidth * 0.5))
}
}
return context?.generateImage()
}
items.append(.action(ContextMenuActionItem(text: peer.displayTitle(strings: environment.strings, displayOrder: presentationData.nameDisplayOrder), textLayout: .secondLineWithValue(peerLabel), icon: { _ in nil }, iconSource: ContextMenuActionItemIconSource(size: avatarSize, signal: avatarSignal), action: { [weak self] c, _ in
c?.dismiss(completion: {})
guard let self else {
guard let self, let currentMode = self.currentMode, let component = self.component else {
return
}
if self.currentTargetPeer?.id == peer.id {
return
}
self.currentTargetPeer = peer
switch currentMode {
case .join:
self.currentTargetPeer = peer
case let .active(active):
self.isChangingTargetPeer = true
self.changeTargetPeerDisposable?.dispose()
self.changeTargetPeerDisposable = (component.context.engine.peers.connectStarRefBot(id: peer.id, botId: component.sourcePeer.id)
|> deliverOnMainQueue).startStrict(next: { [weak self] result in
guard let self else {
return
}
self.isChangingTargetPeer = false
self.currentMode = .active(JoinAffiliateProgramScreen.Mode.Active(
targetPeer: peer,
bot: result,
copyLink: active.copyLink
))
self.state?.updated(transition: .immediate)
}, error: { [weak self] _ in
guard let self else {
return
}
self.isChangingTargetPeer = false
self.state?.updated(transition: .immediate)
})
}
self.state?.updated(transition: .immediate)
})))
}
@ -389,7 +460,11 @@ private final class JoinAffiliateProgramScreenComponent: Component {
let sideInset: CGFloat = 16.0 + environment.safeInsets.left
let currentMode = self.currentMode ?? component.mode
if self.component == nil {
self.currentMode = component.mode
var loadPossibleTargetPeers = false
switch component.mode {
case let .join(join):
@ -461,7 +536,7 @@ private final class JoinAffiliateProgramScreenComponent: Component {
let clippingY: CGFloat
if let currentTargetPeer = self.currentTargetPeer, case .join = component.mode {
if let currentTargetPeer = self.currentTargetPeer, case .join = currentMode {
contentHeight += 34.0
let sourceAvatarSize = self.sourceAvatar.update(
@ -592,7 +667,7 @@ private final class JoinAffiliateProgramScreenComponent: Component {
transition.setFrame(view: linkIconView, frame: linkIconFrame)
}
if active.userCount != 0 {
if active.bot.participants != 0 {
let linkIconBadgeSize = self.linkIconBadge.update(
transition: .immediate,
component: AnyComponent(BorderedBadgeComponent(
@ -605,7 +680,7 @@ private final class JoinAffiliateProgramScreenComponent: Component {
scaleFactor: 1.0
))),
AnyComponentWithIdentity(id: 1, component: AnyComponent(MultilineTextComponent(
text: .plain(NSAttributedString(string: "\(active.userCount)", font: Font.bold(14.0), textColor: .white))
text: .plain(NSAttributedString(string: "\(active.bot.participants)", font: Font.bold(14.0), textColor: .white))
)))
], spacing: 4.0)),
insets: UIEdgeInsets(top: 4.0, left: 9.0, bottom: 4.0, right: 8.0),
@ -637,7 +712,7 @@ private final class JoinAffiliateProgramScreenComponent: Component {
let titleString: String
let subtitleString: String
let termsString: String
switch component.mode {
switch currentMode {
case .join:
titleString = "Affiliate Program"
subtitleString = "**\(component.sourcePeer.compactDisplayTitle)** will share **\(commissionTitle)** of the revenue from each user you refer to it for **\(durationTitle)**."
@ -651,12 +726,12 @@ private final class JoinAffiliateProgramScreenComponent: Component {
timeString = "for **\(durationTitle)** after they follow your link."
}
subtitleString = "Share this link with your users to earn a **\(commissionTitle)** commission on their spending in **\(component.sourcePeer.compactDisplayTitle)** \(timeString)."
if active.userCount == 0 {
if active.bot.participants == 0 {
termsString = "No one opened \(component.sourcePeer.compactDisplayTitle) through this link yet."
} else if active.userCount == 1 {
} else if active.bot.participants == 1 {
termsString = "1 user opened \(component.sourcePeer.compactDisplayTitle) through this link."
} else {
termsString = "\(active.userCount) users opened \(component.sourcePeer.compactDisplayTitle) through this link."
termsString = "\(active.bot.participants) users opened \(component.sourcePeer.compactDisplayTitle) through this link."
}
}
let titleSize = self.title.update(
@ -777,8 +852,8 @@ private final class JoinAffiliateProgramScreenComponent: Component {
}
contentHeight += 12.0
if case let .active(active) = component.mode {
var cleanLink = active.link
if case let .active(active) = currentMode {
var cleanLink = active.bot.url
let removePrefixes: [String] = ["http://", "https://"]
for prefix in removePrefixes {
if cleanLink.hasPrefix(prefix) {
@ -805,7 +880,7 @@ private final class JoinAffiliateProgramScreenComponent: Component {
return
}
self.environment?.controller()?.dismiss()
active.copyLink()
active.copyLink(active.bot)
},
animateAlpha: true,
animateScale: false,
@ -826,7 +901,7 @@ private final class JoinAffiliateProgramScreenComponent: Component {
}
let actionButtonTitle: String
switch component.mode {
switch currentMode {
case .join:
actionButtonTitle = "Join Program"
case .active:
@ -864,7 +939,7 @@ private final class JoinAffiliateProgramScreenComponent: Component {
join.completion(currentTargetPeer)
}
case let .active(active):
active.copyLink()
active.copyLink(active.bot)
}
}
)),
@ -928,7 +1003,7 @@ private final class JoinAffiliateProgramScreenComponent: Component {
self.itemLayout = ItemLayout(containerSize: availableSize, containerInset: containerInset, bottomInset: environment.safeInsets.bottom, topInset: topInset)
if case .active = component.mode {
if case .active = currentMode {
let toast: ComponentView<Empty>
if let current = self.toast {
toast = current

View File

@ -8620,16 +8620,15 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, PeerInfoScreenNodePro
if let result {
mode = .active(JoinAffiliateProgramScreenMode.Active(
targetPeer: accountPeer,
link: result.url,
userCount: Int(result.participants),
copyLink: { [weak self] in
bot: result,
copyLink: { [weak self] result in
guard let self else {
return
}
//TODO:localize
UIPasteboard.general.string = result.url
let presentationData = self.context.sharedContext.currentPresentationData.with({ $0 })
self.controller?.present(UndoOverlayController(presentationData: presentationData, content: .linkCopied(title: "Link copied to clipboard", text: "Share this link and earn **\(result.commissionPermille / 10)%** of what people who use it spend in **\(EnginePeer.user(peer).compactDisplayTitle)**!"), elevatedLayout: false, animateInAsReplacement: false, action: { _ in return false }), in: .current)
self.controller?.present(UndoOverlayController(presentationData: presentationData, content: .linkCopied(title: "Link copied to clipboard", text: "Share this link and earn **\(result.commissionPermille / 10)%** of what people who use it spend in **\(result.peer.compactDisplayTitle)**!"), elevatedLayout: false, animateInAsReplacement: false, action: { _ in return false }), in: .current)
}
))
} else {
@ -8654,15 +8653,14 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, PeerInfoScreenNodePro
programDuration: bot.durationMonths,
mode: .active(JoinAffiliateProgramScreenMode.Active(
targetPeer: targetPeer,
link: bot.url,
userCount: Int(bot.participants),
copyLink: { [weak self] in
bot: bot,
copyLink: { [weak self] result in
guard let self else {
return
}
UIPasteboard.general.string = bot.url
UIPasteboard.general.string = result.url
let presentationData = self.context.sharedContext.currentPresentationData.with({ $0 })
self.controller?.present(UndoOverlayController(presentationData: presentationData, content: .linkCopied(title: "Link copied to clipboard", text: "Share this link and earn **\(bot.commissionPermille / 10)%** of what people who use it spend in **\(bot.peer.compactDisplayTitle)**!"), elevatedLayout: false, animateInAsReplacement: false, action: { _ in return false }), in: .current)
self.controller?.present(UndoOverlayController(presentationData: presentationData, content: .linkCopied(title: "Link copied to clipboard", text: "Share this link and earn **\(result.commissionPermille / 10)%** of what people who use it spend in **\(result.peer.compactDisplayTitle)**!"), elevatedLayout: false, animateInAsReplacement: false, action: { _ in return false }), in: .current)
}
))
))

View File

@ -33,7 +33,7 @@ private final class StarsTransactionSheetContent: CombinedComponent {
let context: AccountContext
let subject: StarsTransactionScreen.Subject
let cancel: (Bool) -> Void
let openPeer: (EnginePeer) -> Void
let openPeer: (EnginePeer, Bool) -> Void
let openMessage: (EngineMessage.Id) -> Void
let openMedia: ([Media], @escaping (Media) -> (ASDisplayNode, CGRect, () -> (UIView?, UIView?))?, @escaping (UIView) -> Void) -> Void
let openAppExamples: () -> Void
@ -44,7 +44,7 @@ private final class StarsTransactionSheetContent: CombinedComponent {
context: AccountContext,
subject: StarsTransactionScreen.Subject,
cancel: @escaping (Bool) -> Void,
openPeer: @escaping (EnginePeer) -> Void,
openPeer: @escaping (EnginePeer, Bool) -> Void,
openMessage: @escaping (EngineMessage.Id) -> Void,
openMedia: @escaping ([Media], @escaping (Media) -> (ASDisplayNode, CGRect, () -> (UIView?, UIView?))?, @escaping (UIView) -> Void) -> Void,
openAppExamples: @escaping () -> Void,
@ -95,6 +95,9 @@ private final class StarsTransactionSheetContent: CombinedComponent {
if case let .peer(peer) = transaction.peer {
peerIds.append(peer.id)
}
if let starrefPeerId = transaction.starrefPeerId {
peerIds.append(starrefPeerId)
}
case let .receipt(receipt):
peerIds.append(receipt.botPaymentId)
case let .gift(message):
@ -232,6 +235,7 @@ private final class StarsTransactionSheetContent: CombinedComponent {
var giveawayMessageId: MessageId?
var isBoost = false
var giftAnimation: TelegramMediaFile?
var isRefProgram = false
var delayedCloseOnOpenPeer = true
switch subject {
@ -399,6 +403,23 @@ private final class StarsTransactionSheetContent: CombinedComponent {
}
transactionPeer = transaction.peer
isGift = true
} else if let starrefCommissionPermille = transaction.starrefCommissionPermille {
//TODO:localize
isRefProgram = true
if transaction.starrefPeerId == nil {
titleText = "\(starrefCommissionPermille / 10)% Commission"
} else {
titleText = transaction.title ?? "Product"
}
descriptionText = ""
count = transaction.count
countOnTop = false
transactionId = transaction.id
date = transaction.date
transactionPeer = transaction.peer
if case let .peer(peer) = transaction.peer {
toPeer = peer
}
} else if transaction.flags.contains(.isReaction) {
titleText = strings.Stars_Transaction_Reaction_Title
descriptionText = ""
@ -722,7 +743,7 @@ private final class StarsTransactionSheetContent: CombinedComponent {
)
)
))
} else if let toPeer {
} else if let toPeer, !isRefProgram {
let title: String
if isSubscription {
if isBotSubscription {
@ -751,7 +772,7 @@ private final class StarsTransactionSheetContent: CombinedComponent {
),
action: {
if delayedCloseOnOpenPeer {
component.openPeer(toPeer)
component.openPeer(toPeer, false)
Queue.mainQueue().after(1.0, {
component.cancel(false)
})
@ -846,6 +867,133 @@ private final class StarsTransactionSheetContent: CombinedComponent {
))
}
if case let .transaction(transaction, _) = subject {
//TODO:localize
if transaction.starrefCommissionPermille != nil {
if transaction.starrefPeerId == nil {
tableItems.append(.init(
id: "reason",
title: "Reason",
component: AnyComponent(
Button(
content: AnyComponent(MultilineTextComponent(text: .plain(NSAttributedString(string: "Affiliate Program", font: tableFont, textColor: tableLinkColor))
)),
action: {
if let toPeer {
component.openPeer(toPeer, true)
Queue.mainQueue().after(1.0, {
component.cancel(false)
})
}
}
)
),
insets: UIEdgeInsets(top: 0.0, left: 12.0, bottom: 0.0, right: 5.0)
))
}
if let toPeer, transaction.starrefPeerId == nil {
tableItems.append(.init(
id: "miniapp",
title: "Mini App",
component: AnyComponent(
Button(
content: AnyComponent(
PeerCellComponent(
context: component.context,
theme: theme,
peer: toPeer
)
),
action: {
if delayedCloseOnOpenPeer {
component.openPeer(toPeer, false)
Queue.mainQueue().after(1.0, {
component.cancel(false)
})
} else {
if let controller = controller() as? StarsTransactionScreen, let navigationController = controller.navigationController, let chatController = navigationController.viewControllers.first(where: { $0 is ChatController }) as? ChatController {
chatController.playShakeAnimation()
}
component.cancel(true)
}
}
)
)
))
}
}
if let starRefPeerId = transaction.starrefPeerId, let starRefPeer = state.peerMap[starRefPeerId] {
//TODO:localize
tableItems.append(.init(
id: "to",
title: "Affiliate",
component: AnyComponent(
Button(
content: AnyComponent(
PeerCellComponent(
context: component.context,
theme: theme,
peer: starRefPeer
)
),
action: {
if delayedCloseOnOpenPeer {
component.openPeer(starRefPeer, false)
Queue.mainQueue().after(1.0, {
component.cancel(false)
})
} else {
if let controller = controller() as? StarsTransactionScreen, let navigationController = controller.navigationController, let chatController = navigationController.viewControllers.first(where: { $0 is ChatController }) as? ChatController {
chatController.playShakeAnimation()
}
component.cancel(true)
}
}
)
)
))
if let toPeer {
tableItems.append(.init(
id: "referred",
title: "Referred User",
component: AnyComponent(
Button(
content: AnyComponent(
PeerCellComponent(
context: component.context,
theme: theme,
peer: toPeer
)
),
action: {
if delayedCloseOnOpenPeer {
component.openPeer(toPeer, true)
Queue.mainQueue().after(1.0, {
component.cancel(false)
})
} else {
if let controller = controller() as? StarsTransactionScreen, let navigationController = controller.navigationController, let chatController = navigationController.viewControllers.first(where: { $0 is ChatController }) as? ChatController {
chatController.playShakeAnimation()
}
component.cancel(true)
}
}
)
)
))
}
}
if let starrefCommissionPermille = transaction.starrefCommissionPermille, transaction.starrefPeerId != nil {
tableItems.append(.init(
id: "commission",
title: "Commission",
component: AnyComponent(MultilineTextComponent(text: .plain(NSAttributedString(string: "\(starrefCommissionPermille / 10)%", font: tableFont, textColor: tableTextColor))
)),
insets: UIEdgeInsets(top: 0.0, left: 12.0, bottom: 0.0, right: 5.0)
))
}
}
if let transactionId {
tableItems.append(.init(
id: "transaction",
@ -1200,7 +1348,7 @@ private final class StarsTransactionSheetComponent: CombinedComponent {
let context: AccountContext
let subject: StarsTransactionScreen.Subject
let openPeer: (EnginePeer) -> Void
let openPeer: (EnginePeer, Bool) -> Void
let openMessage: (EngineMessage.Id) -> Void
let openMedia: ([Media], @escaping (Media) -> (ASDisplayNode, CGRect, () -> (UIView?, UIView?))?, @escaping (UIView) -> Void) -> Void
let openAppExamples: () -> Void
@ -1210,7 +1358,7 @@ private final class StarsTransactionSheetComponent: CombinedComponent {
init(
context: AccountContext,
subject: StarsTransactionScreen.Subject,
openPeer: @escaping (EnginePeer) -> Void,
openPeer: @escaping (EnginePeer, Bool) -> Void,
openMessage: @escaping (EngineMessage.Id) -> Void,
openMedia: @escaping ([Media], @escaping (Media) -> (ASDisplayNode, CGRect, () -> (UIView?, UIView?))?, @escaping (UIView) -> Void) -> Void,
openAppExamples: @escaping () -> Void,
@ -1363,7 +1511,7 @@ public class StarsTransactionScreen: ViewControllerComponentContainer {
) {
self.context = context
var openPeerImpl: ((EnginePeer) -> Void)?
var openPeerImpl: ((EnginePeer, Bool) -> Void)?
var openMessageImpl: ((EngineMessage.Id) -> Void)?
var openMediaImpl: (([Media], @escaping (Media) -> (ASDisplayNode, CGRect, () -> (UIView?, UIView?))?, @escaping (UIView) -> Void) -> Void)?
var openAppExamplesImpl: (() -> Void)?
@ -1375,8 +1523,8 @@ public class StarsTransactionScreen: ViewControllerComponentContainer {
component: StarsTransactionSheetComponent(
context: context,
subject: subject,
openPeer: { peerId in
openPeerImpl?(peerId)
openPeer: { peerId, isProfile in
openPeerImpl?(peerId, isProfile)
},
openMessage: { messageId in
openMessageImpl?(messageId)
@ -1402,7 +1550,7 @@ public class StarsTransactionScreen: ViewControllerComponentContainer {
self.navigationPresentation = .flatModal
self.automaticallyControlPresentationContextLayout = false
openPeerImpl = { [weak self] peer in
openPeerImpl = { [weak self] peer, isProfile in
guard let self, let navigationController = self.navigationController as? NavigationController else {
return
}
@ -1415,7 +1563,13 @@ public class StarsTransactionScreen: ViewControllerComponentContainer {
guard let peer else {
return
}
if isProfile {
if let controller = context.sharedContext.makePeerInfoController(context: context, updatedPresentationData: nil, peer: peer._asPeer(), mode: .generic, avatarInitiallyExpanded: false, fromChat: false, requestsContext: nil) {
navigationController.pushViewController(controller)
}
} else {
context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, chatController: nil, context: context, chatLocation: .peer(peer), subject: nil, botStart: nil, updateTextInputState: nil, keepStack: .always, useExisting: true, purposefulAction: nil, scrollToEndIfExists: false, activateMessageSearch: nil, animated: true))
}
})
}