Various fixes

This commit is contained in:
Ilya Laktyushin 2024-08-07 14:58:25 +02:00
parent c504c1d70e
commit c400ccda24
8 changed files with 128 additions and 21 deletions

View File

@ -1005,6 +1005,7 @@ public protocol SharedAccountContext: AnyObject {
func makeStarsTransactionsScreen(context: AccountContext, starsContext: StarsContext) -> ViewController func makeStarsTransactionsScreen(context: AccountContext, starsContext: StarsContext) -> ViewController
func makeStarsPurchaseScreen(context: AccountContext, starsContext: StarsContext, options: [Any], purpose: StarsPurchasePurpose, completion: @escaping (Int64) -> Void) -> ViewController func makeStarsPurchaseScreen(context: AccountContext, starsContext: StarsContext, options: [Any], purpose: StarsPurchasePurpose, completion: @escaping (Int64) -> Void) -> ViewController
func makeStarsTransferScreen(context: AccountContext, starsContext: StarsContext, invoice: TelegramMediaInvoice, source: BotPaymentInvoiceSource, extendedMedia: [TelegramExtendedMedia], inputData: Signal<(StarsContext.State, BotPaymentForm, EnginePeer?)?, NoError>, completion: @escaping (Bool) -> Void) -> ViewController func makeStarsTransferScreen(context: AccountContext, starsContext: StarsContext, invoice: TelegramMediaInvoice, source: BotPaymentInvoiceSource, extendedMedia: [TelegramExtendedMedia], inputData: Signal<(StarsContext.State, BotPaymentForm, EnginePeer?)?, NoError>, completion: @escaping (Bool) -> Void) -> ViewController
func makeStarsSubscriptionTransferScreen(context: AccountContext, starsContext: StarsContext, invoice: TelegramMediaInvoice, link: String, inputData: Signal<(StarsContext.State, BotPaymentForm, EnginePeer?)?, NoError>, navigateToPeer: @escaping (EnginePeer) -> Void) -> ViewController
func makeStarsTransactionScreen(context: AccountContext, transaction: StarsContext.State.Transaction, peer: EnginePeer) -> ViewController func makeStarsTransactionScreen(context: AccountContext, transaction: StarsContext.State.Transaction, peer: EnginePeer) -> ViewController
func makeStarsReceiptScreen(context: AccountContext, receipt: BotPaymentReceipt) -> ViewController func makeStarsReceiptScreen(context: AccountContext, receipt: BotPaymentReceipt) -> ViewController
func makeStarsSubscriptionScreen(context: AccountContext, subscription: StarsContext.State.Subscription, update: @escaping (Bool) -> Void) -> ViewController func makeStarsSubscriptionScreen(context: AccountContext, subscription: StarsContext.State.Subscription, update: @escaping (Bool) -> Void) -> ViewController

View File

@ -22,13 +22,25 @@ import TextFormat
private final class InviteLinkEditControllerArguments { private final class InviteLinkEditControllerArguments {
let context: AccountContext let context: AccountContext
let updateState: ((InviteLinkEditControllerState) -> InviteLinkEditControllerState) -> Void let updateState: ((InviteLinkEditControllerState) -> InviteLinkEditControllerState) -> Void
let focusOnItem: (InviteLinksEditEntryTag) -> Void
let errorWithItem: (InviteLinksEditEntryTag) -> Void
let scrollToUsage: () -> Void let scrollToUsage: () -> Void
let dismissInput: () -> Void let dismissInput: () -> Void
let revoke: () -> Void let revoke: () -> Void
init(context: AccountContext, updateState: @escaping ((InviteLinkEditControllerState) -> InviteLinkEditControllerState) -> Void, scrollToUsage: @escaping () -> Void, dismissInput: @escaping () -> Void, revoke: @escaping () -> Void) { init(
context: AccountContext,
updateState: @escaping ((InviteLinkEditControllerState) -> InviteLinkEditControllerState) -> Void,
focusOnItem: @escaping (InviteLinksEditEntryTag) -> Void,
errorWithItem: @escaping (InviteLinksEditEntryTag) -> Void,
scrollToUsage: @escaping () -> Void,
dismissInput: @escaping () -> Void,
revoke: @escaping () -> Void)
{
self.context = context self.context = context
self.updateState = updateState self.updateState = updateState
self.focusOnItem = focusOnItem
self.errorWithItem = errorWithItem
self.scrollToUsage = scrollToUsage self.scrollToUsage = scrollToUsage
self.dismissInput = dismissInput self.dismissInput = dismissInput
self.revoke = revoke self.revoke = revoke
@ -45,6 +57,7 @@ private enum InviteLinksEditSection: Int32 {
} }
private enum InviteLinksEditEntryTag: ItemListItemTag { private enum InviteLinksEditEntryTag: ItemListItemTag {
case subscriptionFee
case usage case usage
func isEqual(to other: ItemListItemTag) -> Bool { func isEqual(to other: ItemListItemTag) -> Bool {
@ -79,7 +92,7 @@ private enum InviteLinksEditEntry: ItemListNodeEntry {
case subscriptionFeeToggle(PresentationTheme, String, Bool, Bool) case subscriptionFeeToggle(PresentationTheme, String, Bool, Bool)
case subscriptionFee(PresentationTheme, String, Bool, Int64?, String) case subscriptionFee(PresentationTheme, String, Bool, Int64?, String, Int64?)
case subscriptionFeeInfo(PresentationTheme, String) case subscriptionFeeInfo(PresentationTheme, String)
case requestApproval(PresentationTheme, String, Bool, Bool) case requestApproval(PresentationTheme, String, Bool, Bool)
@ -182,8 +195,8 @@ private enum InviteLinksEditEntry: ItemListNodeEntry {
} else { } else {
return false return false
} }
case let .subscriptionFee(lhsTheme, lhsText, lhsValue, lhsEnabled, lhsLabel): case let .subscriptionFee(lhsTheme, lhsText, lhsValue, lhsEnabled, lhsLabel, lhsMaxValue):
if case let .subscriptionFee(rhsTheme, rhsText, rhsValue, rhsEnabled, rhsLabel) = rhs, lhsTheme === rhsTheme, lhsText == rhsText, lhsValue == rhsValue, lhsEnabled == rhsEnabled, lhsLabel == rhsLabel { if case let .subscriptionFee(rhsTheme, rhsText, rhsValue, rhsEnabled, rhsLabel, rhsMaxValue) = rhs, lhsTheme === rhsTheme, lhsText == rhsText, lhsValue == rhsValue, lhsEnabled == rhsEnabled, lhsLabel == rhsLabel, lhsMaxValue == rhsMaxValue {
return true return true
} else { } else {
return false return false
@ -300,17 +313,26 @@ private enum InviteLinksEditEntry: ItemListNodeEntry {
} }
return updatedState return updatedState
} }
if value {
Queue.mainQueue().after(0.1) {
arguments.focusOnItem(.subscriptionFee)
}
}
}) })
case let .subscriptionFee(_, placeholder, enabled, value, label): case let .subscriptionFee(_, placeholder, enabled, value, label, maxValue):
let title = NSMutableAttributedString(string: "⭐️", font: Font.semibold(18.0), textColor: .white) let title = NSMutableAttributedString(string: "⭐️", font: Font.semibold(18.0), textColor: .white)
if let range = title.string.range(of: "⭐️") { if let range = title.string.range(of: "⭐️") {
title.addAttribute(ChatTextInputAttributes.customEmoji, value: ChatTextInputTextCustomEmojiAttribute(interactivelySelectedFromPackId: nil, fileId: 0, file: nil, custom: .stars(tinted: false)), range: NSRange(range, in: title.string)) title.addAttribute(ChatTextInputAttributes.customEmoji, value: ChatTextInputTextCustomEmojiAttribute(interactivelySelectedFromPackId: nil, fileId: 0, file: nil, custom: .stars(tinted: false)), range: NSRange(range, in: title.string))
title.addAttribute(.baselineOffset, value: -1.0, range: NSRange(range, in: title.string)) title.addAttribute(.baselineOffset, value: -1.0, range: NSRange(range, in: title.string))
} }
return ItemListSingleLineInputItem(context: arguments.context, presentationData: presentationData, title: title, text: value.flatMap { "\($0)" } ?? "", placeholder: placeholder, label: label, type: .number, spacing: 3.0, enabled: enabled, sectionId: self.section, textUpdated: { text in return ItemListSingleLineInputItem(context: arguments.context, presentationData: presentationData, title: title, text: value.flatMap { "\($0)" } ?? "", placeholder: placeholder, label: label, type: .number, spacing: 3.0, enabled: enabled, tag: InviteLinksEditEntryTag.subscriptionFee, sectionId: self.section, textUpdated: { text in
arguments.updateState { state in arguments.updateState { state in
var updatedState = state var updatedState = state
if let value = Int64(text) { if var value = Int64(text) {
if let maxValue, value > maxValue {
value = maxValue
arguments.errorWithItem(.subscriptionFee)
}
updatedState.subscriptionFee = value updatedState.subscriptionFee = value
} else { } else {
updatedState.subscriptionFee = nil updatedState.subscriptionFee = nil
@ -457,7 +479,7 @@ private enum InviteLinksEditEntry: ItemListNodeEntry {
} }
} }
private func inviteLinkEditControllerEntries(invite: ExportedInvitation?, state: InviteLinkEditControllerState, isGroup: Bool, isPublic: Bool, presentationData: PresentationData, starsState: StarsRevenueStats?) -> [InviteLinksEditEntry] { private func inviteLinkEditControllerEntries(invite: ExportedInvitation?, state: InviteLinkEditControllerState, isGroup: Bool, isPublic: Bool, presentationData: PresentationData, starsState: StarsRevenueStats?, configuration: StarsSubscriptionConfiguration) -> [InviteLinksEditEntry] {
var entries: [InviteLinksEditEntry] = [] var entries: [InviteLinksEditEntry] = []
entries.append(.titleHeader(presentationData.theme, presentationData.strings.InviteLink_Create_LinkNameTitle.uppercased())) entries.append(.titleHeader(presentationData.theme, presentationData.strings.InviteLink_Create_LinkNameTitle.uppercased()))
@ -472,9 +494,9 @@ private func inviteLinkEditControllerEntries(invite: ExportedInvitation?, state:
if state.subscriptionEnabled { if state.subscriptionEnabled {
var label: String = "" var label: String = ""
if let subscriptionFee = state.subscriptionFee, subscriptionFee > 0, let starsState { if let subscriptionFee = state.subscriptionFee, subscriptionFee > 0, let starsState {
label = formatTonUsdValue(subscriptionFee, divide: false, rate: starsState.usdRate, dateTimeFormat: presentationData.dateTimeFormat) label = "\(formatTonUsdValue(subscriptionFee, divide: false, rate: starsState.usdRate, dateTimeFormat: presentationData.dateTimeFormat)) / month"
} }
entries.append(.subscriptionFee(presentationData.theme, "Stars amount per month", isEditingEnabled, state.subscriptionFee, label)) entries.append(.subscriptionFee(presentationData.theme, "Stars amount per month", isEditingEnabled, state.subscriptionFee, label, configuration.maxFee))
} }
let infoText: String let infoText: String
if let _ = invite, state.subscriptionEnabled { if let _ = invite, state.subscriptionEnabled {
@ -585,9 +607,15 @@ public func inviteLinkEditController(context: AccountContext, updatedPresentatio
var dismissImpl: (() -> Void)? var dismissImpl: (() -> Void)?
var dismissInputImpl: (() -> Void)? var dismissInputImpl: (() -> Void)?
var scrollToUsageImpl: (() -> Void)? var scrollToUsageImpl: (() -> Void)?
var focusImpl: ((InviteLinksEditEntryTag) -> Void)?
var errorImpl: ((InviteLinksEditEntryTag) -> Void)?
let arguments = InviteLinkEditControllerArguments(context: context, updateState: { f in let arguments = InviteLinkEditControllerArguments(context: context, updateState: { f in
updateState(f) updateState(f)
}, focusOnItem: { tag in
focusImpl?(tag)
}, errorWithItem: { tag in
errorImpl?(tag)
}, scrollToUsage: { }, scrollToUsage: {
scrollToUsageImpl?() scrollToUsageImpl?()
}, dismissInput: { }, dismissInput: {
@ -648,6 +676,8 @@ public func inviteLinkEditController(context: AccountContext, updatedPresentatio
let presentationData = updatedPresentationData?.signal ?? context.sharedContext.presentationData let presentationData = updatedPresentationData?.signal ?? context.sharedContext.presentationData
let configuration = StarsSubscriptionConfiguration.with(appConfiguration: context.currentAppConfiguration.with { $0 })
let previousState = Atomic<InviteLinkEditControllerState?>(value: nil) let previousState = Atomic<InviteLinkEditControllerState?>(value: nil)
let signal = combineLatest( let signal = combineLatest(
presentationData, presentationData,
@ -762,7 +792,7 @@ public func inviteLinkEditController(context: AccountContext, updatedPresentatio
} }
let controllerState = ItemListControllerState(presentationData: ItemListPresentationData(presentationData), title: .text(invite == nil ? presentationData.strings.InviteLink_Create_Title : presentationData.strings.InviteLink_Create_EditTitle), leftNavigationButton: leftNavigationButton, rightNavigationButton: rightNavigationButton, backNavigationButton: ItemListBackButton(title: presentationData.strings.Common_Back), animateChanges: true) let controllerState = ItemListControllerState(presentationData: ItemListPresentationData(presentationData), title: .text(invite == nil ? presentationData.strings.InviteLink_Create_Title : presentationData.strings.InviteLink_Create_EditTitle), leftNavigationButton: leftNavigationButton, rightNavigationButton: rightNavigationButton, backNavigationButton: ItemListBackButton(title: presentationData.strings.Common_Back), animateChanges: true)
let listState = ItemListNodeState(presentationData: ItemListPresentationData(presentationData), entries: inviteLinkEditControllerEntries(invite: invite, state: state, isGroup: isGroup, isPublic: isPublic, presentationData: presentationData, starsState: starsState), style: .blocks, emptyStateItem: nil, crossfadeState: false, animateChanges: animateChanges) let listState = ItemListNodeState(presentationData: ItemListPresentationData(presentationData), entries: inviteLinkEditControllerEntries(invite: invite, state: state, isGroup: isGroup, isPublic: isPublic, presentationData: presentationData, starsState: starsState, configuration: configuration), style: .blocks, emptyStateItem: nil, crossfadeState: false, animateChanges: animateChanges)
return (controllerState, (listState, arguments)) return (controllerState, (listState, arguments))
} }
@ -806,5 +836,41 @@ public func inviteLinkEditController(context: AccountContext, updatedPresentatio
dismissImpl = { [weak controller] in dismissImpl = { [weak controller] in
controller?.dismiss() controller?.dismiss()
} }
focusImpl = { [weak controller] targetTag in
controller?.forEachItemNode { itemNode in
if let itemNode = itemNode as? ItemListSingleLineInputItemNode, let tag = itemNode.tag, tag.isEqual(to: targetTag) {
itemNode.focus()
}
}
}
let hapticFeedback = HapticFeedback()
errorImpl = { [weak controller] targetTag in
hapticFeedback.error()
controller?.forEachItemNode { itemNode in
if let itemNode = itemNode as? ItemListSingleLineInputItemNode, let tag = itemNode.tag, tag.isEqual(to: targetTag) {
itemNode.animateError()
}
}
}
return controller return controller
} }
private struct StarsSubscriptionConfiguration {
static var defaultValue: StarsSubscriptionConfiguration {
return StarsSubscriptionConfiguration(maxFee: 2500)
}
let maxFee: Int64?
fileprivate init(maxFee: Int64?) {
self.maxFee = maxFee
}
public static func with(appConfiguration: AppConfiguration) -> StarsSubscriptionConfiguration {
if let data = appConfiguration.data, let value = data["stars_subscription_amount_max"] as? Double {
return StarsSubscriptionConfiguration(maxFee: Int64(value))
} else {
return .defaultValue
}
}
}

View File

@ -141,6 +141,7 @@ public class ItemListSingleLineInputItemNode: ListViewItemNode, UITextFieldDeleg
private let textNode: TextFieldNode private let textNode: TextFieldNode
private let clearIconNode: ASImageNode private let clearIconNode: ASImageNode
private let clearButtonNode: HighlightableButtonNode private let clearButtonNode: HighlightableButtonNode
private let labelNode: TextNode
private var item: ItemListSingleLineInputItem? private var item: ItemListSingleLineInputItem?
@ -171,12 +172,17 @@ public class ItemListSingleLineInputItemNode: ListViewItemNode, UITextFieldDeleg
self.clearButtonNode = HighlightableButtonNode() self.clearButtonNode = HighlightableButtonNode()
self.labelNode = TextNode()
self.labelNode.isUserInteractionEnabled = false
super.init(layerBacked: false, dynamicBounce: false) super.init(layerBacked: false, dynamicBounce: false)
self.addSubnode(self.titleNode.textNode) self.addSubnode(self.titleNode.textNode)
self.addSubnode(self.textNode) self.addSubnode(self.textNode)
self.addSubnode(self.clearIconNode) self.addSubnode(self.clearIconNode)
self.addSubnode(self.clearButtonNode) self.addSubnode(self.clearButtonNode)
self.addSubnode(self.textNode)
self.addSubnode(self.labelNode)
self.clearButtonNode.addTarget(self, action: #selector(self.clearButtonPressed), forControlEvents: .touchUpInside) self.clearButtonNode.addTarget(self, action: #selector(self.clearButtonPressed), forControlEvents: .touchUpInside)
self.clearButtonNode.highligthedChanged = { [weak self] highlighted in self.clearButtonNode.highligthedChanged = { [weak self] highlighted in
@ -218,6 +224,7 @@ public class ItemListSingleLineInputItemNode: ListViewItemNode, UITextFieldDeleg
let makeTitleLayout = TextNode.asyncLayout(self.titleNode.textNode) let makeTitleLayout = TextNode.asyncLayout(self.titleNode.textNode)
let makeTitleWithEntitiesLayout = TextNodeWithEntities.asyncLayout(self.titleNode) let makeTitleWithEntitiesLayout = TextNodeWithEntities.asyncLayout(self.titleNode)
let makeMeasureTitleSizeLayout = TextNode.asyncLayout(self.measureTitleSizeNode) let makeMeasureTitleSizeLayout = TextNode.asyncLayout(self.measureTitleSizeNode)
let makeLabelLayout = TextNode.asyncLayout(self.labelNode)
let currentItem = self.item let currentItem = self.item
@ -262,6 +269,8 @@ public class ItemListSingleLineInputItemNode: ListViewItemNode, UITextFieldDeleg
let (measureTitleLayout, measureTitleSizeApply) = makeMeasureTitleSizeLayout(TextNodeLayoutArguments(attributedString: NSAttributedString(string: "A", font: Font.regular(item.presentationData.fontSize.itemListBaseFontSize)), backgroundColor: nil, maximumNumberOfLines: 0, truncationType: .end, constrainedSize: CGSize(width: params.width - 32.0 - leftInset - rightInset, height: CGFloat.greatestFiniteMagnitude), alignment: .natural, cutout: nil, insets: UIEdgeInsets())) let (measureTitleLayout, measureTitleSizeApply) = makeMeasureTitleSizeLayout(TextNodeLayoutArguments(attributedString: NSAttributedString(string: "A", font: Font.regular(item.presentationData.fontSize.itemListBaseFontSize)), backgroundColor: nil, maximumNumberOfLines: 0, truncationType: .end, constrainedSize: CGSize(width: params.width - 32.0 - leftInset - rightInset, height: CGFloat.greatestFiniteMagnitude), alignment: .natural, cutout: nil, insets: UIEdgeInsets()))
let (labelLayout, labelApply) = makeLabelLayout(TextNodeLayoutArguments(attributedString: NSAttributedString(string: item.label ?? "", font: Font.regular(item.presentationData.fontSize.itemListBaseFontSize), textColor: item.presentationData.theme.list.itemSecondaryTextColor), backgroundColor: nil, maximumNumberOfLines: 0, truncationType: .end, constrainedSize: CGSize(width: params.width - 32.0 - leftInset - rightInset, height: CGFloat.greatestFiniteMagnitude), alignment: .natural, cutout: nil, insets: UIEdgeInsets()))
let separatorHeight = UIScreenPixel let separatorHeight = UIScreenPixel
let contentSize = CGSize(width: params.width, height: max(titleLayout.size.height, measureTitleLayout.size.height) + 22.0) let contentSize = CGSize(width: params.width, height: max(titleLayout.size.height, measureTitleLayout.size.height) + 22.0)
@ -310,6 +319,7 @@ public class ItemListSingleLineInputItemNode: ListViewItemNode, UITextFieldDeleg
strongSelf.titleNode.textNode.frame = CGRect(origin: CGPoint(x: leftInset, y: floor((layout.contentSize.height - titleLayout.size.height) / 2.0)), size: titleLayout.size) strongSelf.titleNode.textNode.frame = CGRect(origin: CGPoint(x: leftInset, y: floor((layout.contentSize.height - titleLayout.size.height) / 2.0)), size: titleLayout.size)
let _ = measureTitleSizeApply() let _ = measureTitleSizeApply()
let _ = labelApply()
let secureEntry: Bool let secureEntry: Bool
let capitalizationType: UITextAutocapitalizationType let capitalizationType: UITextAutocapitalizationType
@ -379,6 +389,8 @@ public class ItemListSingleLineInputItemNode: ListViewItemNode, UITextFieldDeleg
strongSelf.textNode.frame = CGRect(origin: CGPoint(x: leftInset + titleLayout.size.width + item.spacing, y: 0.0), size: CGSize(width: max(1.0, params.width - (leftInset + rightInset + titleLayout.size.width + item.spacing)), height: layout.contentSize.height - 2.0)) strongSelf.textNode.frame = CGRect(origin: CGPoint(x: leftInset + titleLayout.size.width + item.spacing, y: 0.0), size: CGSize(width: max(1.0, params.width - (leftInset + rightInset + titleLayout.size.width + item.spacing)), height: layout.contentSize.height - 2.0))
strongSelf.labelNode.frame = CGRect(origin: CGPoint(x: layoutSize.width - rightInset - labelLayout.size.width, y: floorToScreenPixels((layout.contentSize.height - labelLayout.size.height) / 2.0)), size: labelLayout.size)
switch item.alignment { switch item.alignment {
case .default: case .default:
strongSelf.textNode.textField.textAlignment = .natural strongSelf.textNode.textField.textAlignment = .natural

View File

@ -911,6 +911,7 @@ private final class StarsSubscriptionsContextImpl {
private let disposable = MetaDisposable() private let disposable = MetaDisposable()
private var stateDisposable: Disposable? private var stateDisposable: Disposable?
private let updateDisposable = MetaDisposable()
init(account: Account, starsContext: StarsContext) { init(account: Account, starsContext: StarsContext) {
assert(Queue.mainQueue().isCurrent()) assert(Queue.mainQueue().isCurrent())
@ -931,6 +932,7 @@ private final class StarsSubscriptionsContextImpl {
assert(Queue.mainQueue().isCurrent()) assert(Queue.mainQueue().isCurrent())
self.disposable.dispose() self.disposable.dispose()
self.stateDisposable?.dispose() self.stateDisposable?.dispose()
self.updateDisposable.dispose()
} }
func loadMore() { func loadMore() {
@ -978,6 +980,7 @@ private final class StarsSubscriptionsContextImpl {
updatedState.subscriptions[index] = updatedSubscription updatedState.subscriptions[index] = updatedSubscription
} }
self.updateState(updatedState) self.updateState(updatedState)
self.updateDisposable.set(_internal_updateStarsSubscription(account: self.account, peerId: self.account.peerId, subscriptionId: id, cancel: cancel).startStrict())
} }
} }

View File

@ -93,9 +93,5 @@ public extension TelegramEngine {
public func sendStarsPaymentForm(formId: Int64, source: BotPaymentInvoiceSource) -> Signal<SendBotPaymentResult, SendBotPaymentFormError> { public func sendStarsPaymentForm(formId: Int64, source: BotPaymentInvoiceSource) -> Signal<SendBotPaymentResult, SendBotPaymentFormError> {
return _internal_sendStarsPaymentForm(account: self.account, formId: formId, source: source) return _internal_sendStarsPaymentForm(account: self.account, formId: formId, source: source)
} }
public func updateStarsSubscription(peerId: EnginePeer.Id, subscriptionId: String, cancel: Bool) -> Signal<Never, UpdateStarsSubsciptionError> {
return _internal_updateStarsSubscription(account: self.account, peerId: peerId, subscriptionId: subscriptionId, cancel: cancel)
}
} }
} }

View File

@ -29,6 +29,7 @@ private final class SheetContent: CombinedComponent {
let source: BotPaymentInvoiceSource let source: BotPaymentInvoiceSource
let extendedMedia: [TelegramExtendedMedia] let extendedMedia: [TelegramExtendedMedia]
let inputData: Signal<(StarsContext.State, BotPaymentForm, EnginePeer?)?, NoError> let inputData: Signal<(StarsContext.State, BotPaymentForm, EnginePeer?)?, NoError>
let navigateToPeer: (EnginePeer) -> Void
let dismiss: () -> Void let dismiss: () -> Void
init( init(
@ -38,6 +39,7 @@ private final class SheetContent: CombinedComponent {
source: BotPaymentInvoiceSource, source: BotPaymentInvoiceSource,
extendedMedia: [TelegramExtendedMedia], extendedMedia: [TelegramExtendedMedia],
inputData: Signal<(StarsContext.State, BotPaymentForm, EnginePeer?)?, NoError>, inputData: Signal<(StarsContext.State, BotPaymentForm, EnginePeer?)?, NoError>,
navigateToPeer: @escaping (EnginePeer) -> Void,
dismiss: @escaping () -> Void dismiss: @escaping () -> Void
) { ) {
self.context = context self.context = context
@ -46,6 +48,7 @@ private final class SheetContent: CombinedComponent {
self.source = source self.source = source
self.extendedMedia = extendedMedia self.extendedMedia = extendedMedia
self.inputData = inputData self.inputData = inputData
self.navigateToPeer = navigateToPeer
self.dismiss = dismiss self.dismiss = dismiss
} }
@ -77,6 +80,7 @@ private final class SheetContent: CombinedComponent {
private var peerDisposable: Disposable? private var peerDisposable: Disposable?
private(set) var balance: Int64? private(set) var balance: Int64?
private(set) var form: BotPaymentForm? private(set) var form: BotPaymentForm?
private(set) var navigateToPeer: (EnginePeer) -> Void
private var stateDisposable: Disposable? private var stateDisposable: Disposable?
@ -96,13 +100,15 @@ private final class SheetContent: CombinedComponent {
source: BotPaymentInvoiceSource, source: BotPaymentInvoiceSource,
extendedMedia: [TelegramExtendedMedia], extendedMedia: [TelegramExtendedMedia],
invoice: TelegramMediaInvoice, invoice: TelegramMediaInvoice,
inputData: Signal<(StarsContext.State, BotPaymentForm, EnginePeer?)?, NoError> inputData: Signal<(StarsContext.State, BotPaymentForm, EnginePeer?)?, NoError>,
navigateToPeer: @escaping (EnginePeer) -> Void
) { ) {
self.context = context self.context = context
self.starsContext = starsContext self.starsContext = starsContext
self.source = source self.source = source
self.extendedMedia = extendedMedia self.extendedMedia = extendedMedia
self.invoice = invoice self.invoice = invoice
self.navigateToPeer = navigateToPeer
super.init() super.init()
@ -159,6 +165,7 @@ private final class SheetContent: CombinedComponent {
return return
} }
let navigateToPeer = self.navigateToPeer
let action = { [weak self] in let action = { [weak self] in
guard let self else { guard let self else {
return return
@ -167,8 +174,19 @@ private final class SheetContent: CombinedComponent {
self.updated() self.updated()
let _ = (self.context.engine.payments.sendStarsPaymentForm(formId: form.id, source: self.source) let _ = (self.context.engine.payments.sendStarsPaymentForm(formId: form.id, source: self.source)
|> deliverOnMainQueue).start(next: { _ in |> deliverOnMainQueue).start(next: { [weak self] _ in
guard let self else {
return
}
completion(true) completion(true)
if case let .starsChatSubscription(link) = self.source {
let _ = (self.context.engine.peers.joinLinkInformation(link)
|> deliverOnMainQueue).startStandalone(next: { result in
if case let .alreadyJoined(peer) = result {
navigateToPeer(peer)
}
})
}
}, error: { [weak self] error in }, error: { [weak self] error in
guard let self else { guard let self else {
return return
@ -235,7 +253,7 @@ private final class SheetContent: CombinedComponent {
} }
func makeState() -> State { func makeState() -> State {
return State(context: self.context, starsContext: self.starsContext, source: self.source, extendedMedia: self.extendedMedia, invoice: self.invoice, inputData: self.inputData) return State(context: self.context, starsContext: self.starsContext, source: self.source, extendedMedia: self.extendedMedia, invoice: self.invoice, inputData: self.inputData, navigateToPeer: self.navigateToPeer)
} }
static var body: Body { static var body: Body {
@ -639,6 +657,7 @@ private final class StarsTransferSheetComponent: CombinedComponent {
private let source: BotPaymentInvoiceSource private let source: BotPaymentInvoiceSource
private let extendedMedia: [TelegramExtendedMedia] private let extendedMedia: [TelegramExtendedMedia]
private let inputData: Signal<(StarsContext.State, BotPaymentForm, EnginePeer?)?, NoError> private let inputData: Signal<(StarsContext.State, BotPaymentForm, EnginePeer?)?, NoError>
private let navigateToPeer: (EnginePeer) -> Void
init( init(
context: AccountContext, context: AccountContext,
@ -646,7 +665,8 @@ private final class StarsTransferSheetComponent: CombinedComponent {
invoice: TelegramMediaInvoice, invoice: TelegramMediaInvoice,
source: BotPaymentInvoiceSource, source: BotPaymentInvoiceSource,
extendedMedia: [TelegramExtendedMedia], extendedMedia: [TelegramExtendedMedia],
inputData: Signal<(StarsContext.State, BotPaymentForm, EnginePeer?)?, NoError> inputData: Signal<(StarsContext.State, BotPaymentForm, EnginePeer?)?, NoError>,
navigateToPeer: @escaping (EnginePeer) -> Void
) { ) {
self.context = context self.context = context
self.starsContext = starsContext self.starsContext = starsContext
@ -654,6 +674,7 @@ private final class StarsTransferSheetComponent: CombinedComponent {
self.source = source self.source = source
self.extendedMedia = extendedMedia self.extendedMedia = extendedMedia
self.inputData = inputData self.inputData = inputData
self.navigateToPeer = navigateToPeer
} }
static func ==(lhs: StarsTransferSheetComponent, rhs: StarsTransferSheetComponent) -> Bool { static func ==(lhs: StarsTransferSheetComponent, rhs: StarsTransferSheetComponent) -> Bool {
@ -687,6 +708,7 @@ private final class StarsTransferSheetComponent: CombinedComponent {
source: context.component.source, source: context.component.source,
extendedMedia: context.component.extendedMedia, extendedMedia: context.component.extendedMedia,
inputData: context.component.inputData, inputData: context.component.inputData,
navigateToPeer: context.component.navigateToPeer,
dismiss: { dismiss: {
animateOut.invoke(Action { _ in animateOut.invoke(Action { _ in
if let controller = controller() { if let controller = controller() {
@ -747,6 +769,7 @@ public final class StarsTransferScreen: ViewControllerComponentContainer {
source: BotPaymentInvoiceSource, source: BotPaymentInvoiceSource,
extendedMedia: [TelegramExtendedMedia] = [], extendedMedia: [TelegramExtendedMedia] = [],
inputData: Signal<(StarsContext.State, BotPaymentForm, EnginePeer?)?, NoError>, inputData: Signal<(StarsContext.State, BotPaymentForm, EnginePeer?)?, NoError>,
navigateToPeer: @escaping (EnginePeer) -> Void = { _ in },
completion: @escaping (Bool) -> Void completion: @escaping (Bool) -> Void
) { ) {
self.context = context self.context = context
@ -761,7 +784,8 @@ public final class StarsTransferScreen: ViewControllerComponentContainer {
invoice: invoice, invoice: invoice,
source: source, source: source,
extendedMedia: extendedMedia, extendedMedia: extendedMedia,
inputData: inputData inputData: inputData,
navigateToPeer: navigateToPeer
), ),
navigationBarAppearance: .none, navigationBarAppearance: .none,
statusBarStyle: .ignore, statusBarStyle: .ignore,

View File

@ -323,7 +323,8 @@ func openResolvedUrlImpl(
} }
} }
let _ = (starsInputData |> filter { $0 != nil } |> take(1) |> deliverOnMainQueue).start(next: { _ in let _ = (starsInputData |> filter { $0 != nil } |> take(1) |> deliverOnMainQueue).start(next: { _ in
let controller = context.sharedContext.makeStarsTransferScreen(context: context, starsContext: starsContext, invoice: invoice, source: .starsChatSubscription(hash: link), extendedMedia: [], inputData: starsInputData, completion: { _ in let controller = context.sharedContext.makeStarsSubscriptionTransferScreen(context: context, starsContext: starsContext, invoice: invoice, link: link, inputData: starsInputData, navigateToPeer: { peer in
openPeer(peer, .chat(textInputState: nil, subject: nil, peekData: nil))
}) })
navigationController?.pushViewController(controller) navigationController?.pushViewController(controller)
}) })

View File

@ -2743,6 +2743,10 @@ public final class SharedAccountContextImpl: SharedAccountContext {
return StarsTransferScreen(context: context, starsContext: starsContext, invoice: invoice, source: source, extendedMedia: extendedMedia, inputData: inputData, completion: completion) return StarsTransferScreen(context: context, starsContext: starsContext, invoice: invoice, source: source, extendedMedia: extendedMedia, inputData: inputData, completion: completion)
} }
public func makeStarsSubscriptionTransferScreen(context: AccountContext, starsContext: StarsContext, invoice: TelegramMediaInvoice, link: String, inputData: Signal<(StarsContext.State, BotPaymentForm, EnginePeer?)?, NoError>, navigateToPeer: @escaping (EnginePeer) -> Void) -> ViewController {
return StarsTransferScreen(context: context, starsContext: starsContext, invoice: invoice, source: .starsChatSubscription(hash: link), extendedMedia: [], inputData: inputData, navigateToPeer: navigateToPeer, completion: { _ in })
}
public func makeStarsTransactionScreen(context: AccountContext, transaction: StarsContext.State.Transaction, peer: EnginePeer) -> ViewController { public func makeStarsTransactionScreen(context: AccountContext, transaction: StarsContext.State.Transaction, peer: EnginePeer) -> ViewController {
return StarsTransactionScreen(context: context, subject: .transaction(transaction, peer)) return StarsTransactionScreen(context: context, subject: .transaction(transaction, peer))
} }