Update API

This commit is contained in:
Ilya Laktyushin 2025-11-12 22:06:23 +04:00
parent 1be0aaef7c
commit e680691988
15 changed files with 592 additions and 95 deletions

View file

@ -1423,8 +1423,8 @@ public protocol SharedAccountContext: AnyObject {
func makeGiftViewScreen(context: AccountContext, gift: StarGift.UniqueGift, shareStory: ((StarGift.UniqueGift) -> Void)?, openChatTheme: (() -> Void)?, dismissed: (() -> Void)?) -> ViewController
func makeGiftWearPreviewScreen(context: AccountContext, gift: StarGift.UniqueGift) -> ViewController
func makeGiftAuctionInfoScreen(context: AccountContext, auctionContext: GiftAuctionContext, completion: (() -> Void)?) -> ViewController
func makeGiftAuctionBidScreen(context: AccountContext, auctionContext: GiftAuctionContext) -> ViewController
func makeGiftAuctionViewScreen(context: AccountContext, auctionContext: GiftAuctionContext) -> ViewController
func makeGiftAuctionBidScreen(context: AccountContext, toPeerId: EnginePeer.Id, auctionContext: GiftAuctionContext) -> ViewController
func makeGiftAuctionViewScreen(context: AccountContext, toPeerId: EnginePeer.Id, auctionContext: GiftAuctionContext) -> ViewController
func makeGiftAuctionActiveBidsScreen(context: AccountContext) -> ViewController
func makeStorySharingScreen(context: AccountContext, subject: StorySharingSubject, parentController: ViewController) -> ViewController

View file

@ -397,8 +397,7 @@ fileprivate let parsers: [Int32 : (BufferReader) -> Any?] = {
dict[-625298705] = { return Api.InputInvoice.parse_inputInvoicePremiumGiftStars($0) }
dict[-1020867857] = { return Api.InputInvoice.parse_inputInvoiceSlug($0) }
dict[-396206446] = { return Api.InputInvoice.parse_inputInvoiceStarGift($0) }
dict[2010287526] = { return Api.InputInvoice.parse_inputInvoiceStarGiftAuctionBid($0) }
dict[-2061017960] = { return Api.InputInvoice.parse_inputInvoiceStarGiftAuctionUpdateBid($0) }
dict[516618768] = { return Api.InputInvoice.parse_inputInvoiceStarGiftAuctionBid($0) }
dict[153344209] = { return Api.InputInvoice.parse_inputInvoiceStarGiftDropOriginalDetails($0) }
dict[-1710536520] = { return Api.InputInvoice.parse_inputInvoiceStarGiftPrepaidUpgrade($0) }
dict[-1012968668] = { return Api.InputInvoice.parse_inputInvoiceStarGiftResale($0) }

View file

@ -566,8 +566,7 @@ public extension Api {
case inputInvoicePremiumGiftStars(flags: Int32, userId: Api.InputUser, months: Int32, message: Api.TextWithEntities?)
case inputInvoiceSlug(slug: String)
case inputInvoiceStarGift(flags: Int32, peer: Api.InputPeer, giftId: Int64, message: Api.TextWithEntities?)
case inputInvoiceStarGiftAuctionBid(flags: Int32, peer: Api.InputPeer, giftId: Int64, bidAmount: Int64, message: Api.TextWithEntities?)
case inputInvoiceStarGiftAuctionUpdateBid(giftId: Int64, bidAmount: Int64)
case inputInvoiceStarGiftAuctionBid(flags: Int32, peer: Api.InputPeer?, giftId: Int64, bidAmount: Int64, message: Api.TextWithEntities?)
case inputInvoiceStarGiftDropOriginalDetails(stargift: Api.InputSavedStarGift)
case inputInvoiceStarGiftPrepaidUpgrade(peer: Api.InputPeer, hash: String)
case inputInvoiceStarGiftResale(flags: Int32, slug: String, toId: Api.InputPeer)
@ -636,21 +635,14 @@ public extension Api {
break
case .inputInvoiceStarGiftAuctionBid(let flags, let peer, let giftId, let bidAmount, let message):
if boxed {
buffer.appendInt32(2010287526)
buffer.appendInt32(516618768)
}
serializeInt32(flags, buffer: buffer, boxed: false)
peer.serialize(buffer, true)
if Int(flags) & Int(1 << 3) != 0 {peer!.serialize(buffer, true)}
serializeInt64(giftId, buffer: buffer, boxed: false)
serializeInt64(bidAmount, buffer: buffer, boxed: false)
if Int(flags) & Int(1 << 1) != 0 {message!.serialize(buffer, true)}
break
case .inputInvoiceStarGiftAuctionUpdateBid(let giftId, let bidAmount):
if boxed {
buffer.appendInt32(-2061017960)
}
serializeInt64(giftId, buffer: buffer, boxed: false)
serializeInt64(bidAmount, buffer: buffer, boxed: false)
break
case .inputInvoiceStarGiftDropOriginalDetails(let stargift):
if boxed {
buffer.appendInt32(153344209)
@ -715,8 +707,6 @@ public extension Api {
return ("inputInvoiceStarGift", [("flags", flags as Any), ("peer", peer as Any), ("giftId", giftId as Any), ("message", message as Any)])
case .inputInvoiceStarGiftAuctionBid(let flags, let peer, let giftId, let bidAmount, let message):
return ("inputInvoiceStarGiftAuctionBid", [("flags", flags as Any), ("peer", peer as Any), ("giftId", giftId as Any), ("bidAmount", bidAmount as Any), ("message", message as Any)])
case .inputInvoiceStarGiftAuctionUpdateBid(let giftId, let bidAmount):
return ("inputInvoiceStarGiftAuctionUpdateBid", [("giftId", giftId as Any), ("bidAmount", bidAmount as Any)])
case .inputInvoiceStarGiftDropOriginalDetails(let stargift):
return ("inputInvoiceStarGiftDropOriginalDetails", [("stargift", stargift as Any)])
case .inputInvoiceStarGiftPrepaidUpgrade(let peer, let hash):
@ -869,9 +859,9 @@ public extension Api {
var _1: Int32?
_1 = reader.readInt32()
var _2: Api.InputPeer?
if let signature = reader.readInt32() {
if Int(_1!) & Int(1 << 3) != 0 {if let signature = reader.readInt32() {
_2 = Api.parse(reader, signature: signature) as? Api.InputPeer
}
} }
var _3: Int64?
_3 = reader.readInt64()
var _4: Int64?
@ -881,26 +871,12 @@ public extension Api {
_5 = Api.parse(reader, signature: signature) as? Api.TextWithEntities
} }
let _c1 = _1 != nil
let _c2 = _2 != nil
let _c2 = (Int(_1!) & Int(1 << 3) == 0) || _2 != nil
let _c3 = _3 != nil
let _c4 = _4 != nil
let _c5 = (Int(_1!) & Int(1 << 1) == 0) || _5 != nil
if _c1 && _c2 && _c3 && _c4 && _c5 {
return Api.InputInvoice.inputInvoiceStarGiftAuctionBid(flags: _1!, peer: _2!, giftId: _3!, bidAmount: _4!, message: _5)
}
else {
return nil
}
}
public static func parse_inputInvoiceStarGiftAuctionUpdateBid(_ reader: BufferReader) -> InputInvoice? {
var _1: Int64?
_1 = reader.readInt64()
var _2: Int64?
_2 = reader.readInt64()
let _c1 = _1 != nil
let _c2 = _2 != nil
if _c1 && _c2 {
return Api.InputInvoice.inputInvoiceStarGiftAuctionUpdateBid(giftId: _1!, bidAmount: _2!)
return Api.InputInvoice.inputInvoiceStarGiftAuctionBid(flags: _1!, peer: _2, giftId: _3!, bidAmount: _4!, message: _5)
}
else {
return nil

View file

@ -560,7 +560,7 @@ open class TelegramBaseController: ViewController, KeyShortcutResponder {
guard let self, let auction else {
return
}
let controller = self.context.sharedContext.makeGiftAuctionBidScreen(context: self.context, auctionContext: auction)
let controller = self.context.sharedContext.makeGiftAuctionBidScreen(context: self.context, toPeerId: auction.currentBidPeerId ?? self.context.account.peerId, auctionContext: auction)
self.push(controller)
})
}

View file

@ -20,8 +20,7 @@ public enum BotPaymentInvoiceSource {
case starGiftResale(slug: String, toPeerId: EnginePeer.Id, ton: Bool)
case starGiftPrepaidUpgrade(peerId: EnginePeer.Id, hash: String)
case starGiftDropOriginalDetails(reference: StarGiftReference)
case starGiftAuctionBid(hideName: Bool, peerId: EnginePeer.Id, giftId: Int64, bidAmount: Int64, text: String?, entities: [MessageTextEntity]?)
case starGiftAuctionUpdateBid(giftId: Int64, bidAmount: Int64)
case starGiftAuctionBid(update: Bool, hideName: Bool, peerId: EnginePeer.Id, giftId: Int64, bidAmount: Int64, text: String?, entities: [MessageTextEntity]?)
}
public struct BotPaymentInvoiceFields: OptionSet {
@ -426,7 +425,7 @@ func _internal_parseInputInvoice(transaction: Transaction, source: BotPaymentInv
case let .starGiftDropOriginalDetails(reference):
return reference.apiStarGiftReference(transaction: transaction).flatMap { .inputInvoiceStarGiftDropOriginalDetails(stargift: $0) }
case let .starGiftAuctionBid(hideName, peerId, giftId, bidAmount, text, entities):
case let .starGiftAuctionBid(update, hideName, peerId, giftId, bidAmount, text, entities):
guard let peer = transaction.getPeer(peerId), let inputPeer = apiInputPeer(peer) else {
return nil
}
@ -434,14 +433,17 @@ func _internal_parseInputInvoice(transaction: Transaction, source: BotPaymentInv
if hideName {
flags |= (1 << 0)
}
if update {
flags |= (1 << 2)
}
flags |= (1 << 3)
var message: Api.TextWithEntities?
if let text, !text.isEmpty {
flags |= (1 << 1)
message = .textWithEntities(text: text, entities: entities.flatMap { apiEntitiesFromMessageTextEntities($0, associatedPeers: SimpleDictionary()) } ?? [])
}
return .inputInvoiceStarGiftAuctionBid(flags: flags, peer: inputPeer, giftId: giftId, bidAmount: bidAmount, message: message)
case let .starGiftAuctionUpdateBid(giftId, bidAmount):
return .inputInvoiceStarGiftAuctionUpdateBid(giftId: giftId, bidAmount: bidAmount)
}
}
@ -784,7 +786,7 @@ func _internal_sendBotPaymentForm(account: Account, formId: Int64, source: BotPa
receiptMessageId = id
}
}
case .giftCode, .stars, .starsGift, .starsChatSubscription, .starGift, .starGiftUpgrade, .starGiftTransfer, .premiumGift, .starGiftResale, .starGiftPrepaidUpgrade, .starGiftDropOriginalDetails, .starGiftAuctionBid, .starGiftAuctionUpdateBid:
case .giftCode, .stars, .starsGift, .starsChatSubscription, .starGift, .starGiftUpgrade, .starGiftTransfer, .premiumGift, .starGiftResale, .starGiftPrepaidUpgrade, .starGiftDropOriginalDetails, .starGiftAuctionBid:
receiptMessageId = nil
}
}

View file

@ -1637,7 +1637,7 @@ func _internal_sendStarsPaymentForm(account: Account, formId: Int64, source: Bot
receiptMessageId = id
}
}
case .giftCode, .stars, .starsGift, .starsChatSubscription, .starGift, .starGiftUpgrade, .starGiftTransfer, .premiumGift, .starGiftResale, .starGiftPrepaidUpgrade, .starGiftDropOriginalDetails, .starGiftAuctionBid, .starGiftAuctionUpdateBid:
case .giftCode, .stars, .starsGift, .starsChatSubscription, .starGift, .starGiftUpgrade, .starGiftTransfer, .premiumGift, .starGiftResale, .starGiftPrepaidUpgrade, .starGiftDropOriginalDetails, .starGiftAuctionBid:
receiptMessageId = nil
}
} else if case let .starGiftUnique(gift, _, _, savedToProfile, canExportDate, transferStars, _, _, peerId, _, savedId, _, canTransferDate, canResaleDate, dropOriginalDetailsStars, _) = action.action, case let .Id(messageId) = message.id {

View file

@ -2034,12 +2034,10 @@ private final class CameraScreenComponent: CombinedComponent {
availableModeControlSize = availableSize
}
let availableModes: [CameraMode]
//#if DEBUG
availableModes = [.photo, .video, .live]
//#else
//availableModes = [.photo, .video]
//#endif
var availableModes: [CameraMode] = [.photo, .video]
if !isTablet {
availableModes.append(.live)
}
let modeControl = modeControl.update(
component: ModeComponent(

View file

@ -389,6 +389,7 @@ final class GiftOptionsScreenComponent: Component {
if currentBidPeerId == component.peerId {
let giftController = component.context.sharedContext.makeGiftAuctionBidScreen(
context: component.context,
toPeerId: currentBidPeerId,
auctionContext: auctionContext
)
mainController.push(giftController)
@ -411,6 +412,7 @@ final class GiftOptionsScreenComponent: Component {
}
let giftController = component.context.sharedContext.makeGiftAuctionBidScreen(
context: component.context,
toPeerId: currentBidPeerId,
auctionContext: auctionContext
)
mainController.push(giftController)
@ -424,6 +426,7 @@ final class GiftOptionsScreenComponent: Component {
} else {
let giftController = component.context.sharedContext.makeGiftAuctionViewScreen(
context: component.context,
toPeerId: component.peerId,
auctionContext: auctionContext
)
mainController.push(giftController)

View file

@ -293,6 +293,7 @@ private final class GiftAuctionAcquiredScreenComponent: Component {
} else {
fillingSize = min(availableSize.width, 428.0) - environment.safeInsets.left * 2.0
}
let rawSideInset = floor((availableSize.width - fillingSize) * 0.5)
let sideInset: CGFloat = floor((availableSize.width - fillingSize) * 0.5) + 24.0
self.component = component
@ -474,7 +475,7 @@ private final class GiftAuctionAcquiredScreenComponent: Component {
environment: {},
containerSize: CGSize(width: 40.0, height: 40.0)
)
let closeButtonFrame = CGRect(origin: CGPoint(x: 16.0, y: 16.0), size: closeButtonSize)
let closeButtonFrame = CGRect(origin: CGPoint(x: rawSideInset + 16.0, y: 16.0), size: closeButtonSize)
if let closeButtonView = self.closeButton.view {
if closeButtonView.superview == nil {
self.navigationBarContainer.addSubview(closeButtonView)
@ -538,12 +539,11 @@ private final class GiftAuctionAcquiredScreenComponent: Component {
}
)),
environment: {},
containerSize: CGSize(width: availableSize.width - buttonInsets.left - buttonInsets.right, height: 54.0)
containerSize: CGSize(width: fillingSize - buttonInsets.left - buttonInsets.right, height: 54.0)
)
let edgeEffectHeight: CGFloat = 80.0
let edgeEffectFrame = CGRect(origin: CGPoint(x: 0.0, y: 0.0), size: CGSize(width: availableSize.width, height: edgeEffectHeight))
let edgeEffectFrame = CGRect(origin: CGPoint(x: rawSideInset, y: 0.0), size: CGSize(width: fillingSize, height: edgeEffectHeight))
transition.setFrame(view: self.topEdgeEffectView, frame: edgeEffectFrame)
self.topEdgeEffectView.update(content: environment.theme.actionSheet.opaqueItemBackgroundColor, blur: true, alpha: 1.0, rect: edgeEffectFrame, edge: .top, edgeSize: edgeEffectFrame.height, transition: transition)
if self.topEdgeEffectView.superview == nil {
@ -553,14 +553,14 @@ private final class GiftAuctionAcquiredScreenComponent: Component {
var bottomPanelHeight = 13.0 + buttonInsets.bottom + actionButtonSize.height
let bottomEdgeEffectHeight: CGFloat = bottomPanelHeight
let bottomEdgeEffectFrame = CGRect(origin: CGPoint(x: 0.0, y: availableSize.height - bottomEdgeEffectHeight), size: CGSize(width: availableSize.width, height: bottomEdgeEffectHeight))
let bottomEdgeEffectFrame = CGRect(origin: CGPoint(x: rawSideInset, y: availableSize.height - bottomEdgeEffectHeight), size: CGSize(width: fillingSize, height: bottomEdgeEffectHeight))
transition.setFrame(view: self.bottomEdgeEffectView, frame: bottomEdgeEffectFrame)
self.bottomEdgeEffectView.update(content: environment.theme.actionSheet.opaqueItemBackgroundColor, blur: true, alpha: 1.0, rect: bottomEdgeEffectFrame, edge: .bottom, edgeSize: bottomEdgeEffectFrame.height, transition: transition)
if self.bottomEdgeEffectView.superview == nil {
self.containerView.addSubview(self.bottomEdgeEffectView)
}
let actionButtonFrame = CGRect(origin: CGPoint(x: buttonInsets.left, y: availableSize.height - buttonInsets.bottom - actionButtonSize.height), size: actionButtonSize)
let actionButtonFrame = CGRect(origin: CGPoint(x: rawSideInset + buttonInsets.left, y: availableSize.height - buttonInsets.bottom - actionButtonSize.height), size: actionButtonSize)
bottomPanelHeight -= 1.0
if let actionButtonView = actionButton.view {
if actionButtonView.superview == nil {

View file

@ -318,7 +318,7 @@ private final class GiftAuctionActiveBidsScreenComponent: Component {
}
controller.dismiss()
let bidController = component.context.sharedContext.makeGiftAuctionBidScreen(context: component.context, auctionContext: auction)
let bidController = component.context.sharedContext.makeGiftAuctionBidScreen(context: component.context, toPeerId: auction.currentBidPeerId ?? component.context.account.peerId, auctionContext: auction)
navigationController.pushViewController(bidController)
})
}

View file

@ -486,6 +486,7 @@ private final class PeerComponent: Component {
let amount: Int64
let status: Status?
let isLast: Bool
let action: (() -> Void)?
init(
context: AccountContext,
@ -495,7 +496,8 @@ private final class PeerComponent: Component {
place: Int32,
amount: Int64,
status: Status? = nil,
isLast: Bool
isLast: Bool,
action: (() -> Void)?
) {
self.context = context
self.theme = theme
@ -505,6 +507,7 @@ private final class PeerComponent: Component {
self.amount = amount
self.status = status
self.isLast = isLast
self.action = action
}
static func ==(lhs: PeerComponent, rhs: PeerComponent) -> Bool {
@ -533,31 +536,59 @@ private final class PeerComponent: Component {
}
final class View: UIView {
private let selectionLayer = SimpleLayer()
private var avatarNode: AvatarNode?
private let place = ComponentView<Empty>()
private let title = ComponentView<Empty>()
private let amount = ComponentView<Empty>()
private let amountStar = UIImageView()
private let separator = SimpleLayer()
private let button = HighlightTrackingButton()
private var component: PeerComponent?
override init(frame: CGRect) {
super.init(frame: frame)
self.selectionLayer.opacity = 0.0
self.layer.addSublayer(self.separator)
self.layer.addSublayer(self.selectionLayer)
self.amountStar.image = UIImage(bundleImageName: "Premium/Stars/StarSmall")
self.addSubview(self.amountStar)
self.button.addTarget(self, action: #selector(self.buttonPressed), for: .touchUpInside)
self.addSubview(self.button)
self.button.highligthedChanged = { [weak self] highlighted in
if let self {
if highlighted {
self.selectionLayer.removeAnimation(forKey: "opacity")
self.selectionLayer.opacity = 1.0
} else {
self.selectionLayer.opacity = 0.0
self.selectionLayer.animateAlpha(from: 1.0, to: 0.0, duration: 0.2)
}
}
}
}
required init(coder: NSCoder) {
preconditionFailure()
}
@objc private func buttonPressed() {
if let component = self.component {
component.action?()
}
}
func update(component: PeerComponent, availableSize: CGSize, state: EmptyComponentState, environment: Environment<Empty>, transition: ComponentTransition) -> CGSize {
self.component = component
self.button.isUserInteractionEnabled = component.action != nil
let size = CGSize(width: availableSize.width, height: 52.0)
var color = component.theme.list.itemSecondaryTextColor
@ -569,6 +600,7 @@ private final class PeerComponent: Component {
default:
break
}
self.selectionLayer.backgroundColor = component.theme.list.itemHighlightedBackgroundColor.cgColor
let presentationData = component.context.sharedContext.currentPresentationData.with { $0 }
let placeSize = self.place.update(
@ -580,6 +612,7 @@ private final class PeerComponent: Component {
let placeFrame = CGRect(origin: CGPoint(x: 0.0, y: floorToScreenPixels((size.height - placeSize.height) / 2.0)), size: placeSize)
if let placeView = self.place.view {
if placeView.superview == nil {
placeView.isUserInteractionEnabled = false
self.addSubview(placeView)
}
placeView.frame = placeFrame
@ -590,6 +623,7 @@ private final class PeerComponent: Component {
avatarNode = current
} else {
avatarNode = AvatarNode(font: avatarPlaceholderFont(size: 16.0))
avatarNode.isUserInteractionEnabled = false
self.avatarNode = avatarNode
self.addSubview(avatarNode.view)
}
@ -611,6 +645,7 @@ private final class PeerComponent: Component {
let titleFrame = CGRect(origin: CGPoint(x: 110.0, y: floorToScreenPixels((size.height - titleSize.height) / 2.0)), size: titleSize)
if let titleView = self.title.view {
if titleView.superview == nil {
titleView.isUserInteractionEnabled = false
self.addSubview(titleView)
}
titleView.frame = titleFrame
@ -627,6 +662,7 @@ private final class PeerComponent: Component {
let amountFrame = CGRect(origin: CGPoint(x: availableSize.width - amountSize.width, y: floorToScreenPixels((size.height - amountSize.height) / 2.0)), size: amountSize)
if let amountView = self.amount.view {
if amountView.superview == nil {
amountView.isUserInteractionEnabled = false
self.addSubview(amountView)
}
amountView.frame = amountFrame
@ -637,9 +673,12 @@ private final class PeerComponent: Component {
}
self.separator.backgroundColor = component.theme.list.itemPlainSeparatorColor.cgColor
self.separator.frame = CGRect(origin: CGPoint(x: 110.0, y: size.height), size: CGSize(width: size.width - 110.0, height: 1.0 - UIScreenPixel))
self.separator.frame = CGRect(origin: CGPoint(x: 110.0, y: size.height - UIScreenPixel), size: CGSize(width: size.width - 110.0, height: UIScreenPixel))
transition.setAlpha(layer: self.separator, alpha: component.isLast ? 0.0 : 1.0)
self.button.frame = CGRect(origin: .zero, size: size)
self.selectionLayer.frame = CGRect(origin: .zero, size: size).insetBy(dx: -24.0, dy: -UIScreenPixel)
return size
}
}
@ -900,15 +939,18 @@ private final class GiftAuctionBidScreenComponent: Component {
typealias EnvironmentType = ViewControllerComponentContainer.Environment
let context: AccountContext
let toPeerId: EnginePeer.Id
let gift: StarGift
let auctionContext: GiftAuctionContext
init(
context: AccountContext,
toPeerId: EnginePeer.Id,
gift: StarGift,
auctionContext: GiftAuctionContext
) {
self.context = context
self.toPeerId = toPeerId
self.gift = gift
self.auctionContext = auctionContext
}
@ -1412,22 +1454,15 @@ private final class GiftAuctionBidScreenComponent: Component {
self.isLoading = true
self.state?.updated()
let source: BotPaymentInvoiceSource
if let state = self.giftAuctionState, state.myState.bidAmount != nil {
source = .starGiftAuctionUpdateBid(
giftId: gift.id,
bidAmount: value
)
} else {
source = .starGiftAuctionBid(
hideName: false,
peerId: component.context.account.peerId,
giftId: gift.id,
bidAmount: value,
text: nil,
entities: nil
)
}
let source: BotPaymentInvoiceSource = .starGiftAuctionBid(
update: isUpdate,
hideName: false,
peerId: component.toPeerId,
giftId: gift.id,
bidAmount: value,
text: nil,
entities: nil
)
let signal = BotCheckoutController.InputData.fetch(context: component.context, source: source)
|> `catch` { error -> Signal<BotCheckoutController.InputData, SendBotPaymentFormError> in
@ -1644,6 +1679,29 @@ private final class GiftAuctionBidScreenComponent: Component {
controller.presentInGlobalOverlay(contextController)
}
func presentCustomBidController() {
guard let component = self.component else {
return
}
if "".isEmpty {
return
}
let controller = giftAuctionCustomBidController(
context: component.context,
title: "Place a Custom Bid",
text: "Description",
placeholder: "Bid",
value: 100,
apply: { [weak self] value in
guard let self else {
return
}
self.commitBid(value: value)
}
)
self.environment?.controller()?.present(controller, in: .window(.root))
}
func update(component: GiftAuctionBidScreenComponent, availableSize: CGSize, state: EmptyComponentState, environment: Environment<ViewControllerComponentContainer.Environment>, transition: ComponentTransition) -> CGSize {
self.isUpdating = true
defer {
@ -1661,6 +1719,7 @@ private final class GiftAuctionBidScreenComponent: Component {
} else {
fillingSize = min(availableSize.width, 428.0) - environment.safeInsets.left * 2.0
}
let rawSideInset = floor((availableSize.width - fillingSize) * 0.5)
let sideInset: CGFloat = floor((availableSize.width - fillingSize) * 0.5) + 24.0
let context = component.context
@ -1794,7 +1853,8 @@ private final class GiftAuctionBidScreenComponent: Component {
})
self.giftAuctionTimer = SwiftSignalKit.Timer(timeout: 0.5, repeat: true, completion: { [weak self] in
self?.state?.updated()
let _ = self
//self?.state?.updated()
}, queue: Queue.mainQueue())
self.giftAuctionTimer?.start()
}
@ -1827,7 +1887,7 @@ private final class GiftAuctionBidScreenComponent: Component {
return
}
let maxAmount: Int = 1000
let maxAmount: Int = 999
self.amount = self.amount.withSliderValue(value)
self.didChangeAmount = true
@ -1851,6 +1911,10 @@ private final class GiftAuctionBidScreenComponent: Component {
}
}
if sliderValue == 1.0 && self.previousSliderValue != 1.0 {
self.presentCustomBidController()
}
self.previousSliderValue = sliderValue
self.previousTimestamp = currentTimestamp
}
@ -1985,7 +2049,7 @@ private final class GiftAuctionBidScreenComponent: Component {
let badgeOriginX = sliderBackgroundFrame.minX + sliderForegroundFrame.width - 15.0
badgeFrame = CGRect(origin: CGPoint(x: badgeOriginX - apparentBadgeSize.width * 0.5, y: sliderForegroundFrame.minY - 9.0 - badgeSize.height), size: apparentBadgeSize)
let badgeSideInset: CGFloat = 23.0
let badgeSideInset: CGFloat = rawSideInset + 23.0
let badgeOverflowWidth: CGFloat
if badgeFrame.minX < badgeSideInset {
@ -2008,7 +2072,7 @@ private final class GiftAuctionBidScreenComponent: Component {
let starsRect = CGRect(origin: .zero, size: CGSize(width: availableSize.width, height: sliderForegroundFrame.midY))
self.badgeStars.frame = starsRect
self.badgeStars.update(size: starsRect.size, color: sliderColor, emitterPosition: CGPoint(x: badgeFrame.minX, y: badgeFrame.midY - 64.0))
self.badgeStars.update(size: starsRect.size, color: sliderColor, emitterPosition: CGPoint(x: badgeFrame.midX, y: badgeFrame.maxY - 32.0))
}
var perks: [([AnimatedTextComponent.Item], String)] = []
@ -2116,7 +2180,7 @@ private final class GiftAuctionBidScreenComponent: Component {
let perkHeight: CGFloat = 60.0
let perkSpacing: CGFloat = 10.0
let perkWidth: CGFloat = floor((fillingSize - sideInset * 2.0 - perkSpacing * CGFloat(perks.count - 1)) / CGFloat(perks.count))
let perkWidth: CGFloat = floor((availableSize.width - sideInset * 2.0 - perkSpacing * CGFloat(perks.count - 1)) / CGFloat(perks.count))
for i in 0 ..< perks.count {
var perkFrame = CGRect(origin: CGPoint(x: sideInset + CGFloat(i) * (perkWidth + perkSpacing), y: contentHeight), size: CGSize(width: perkWidth, height: perkHeight))
@ -2187,7 +2251,7 @@ private final class GiftAuctionBidScreenComponent: Component {
environment: {},
containerSize: CGSize(width: 40.0, height: 40.0)
)
let closeButtonFrame = CGRect(origin: CGPoint(x: 16.0, y: 16.0), size: closeButtonSize)
let closeButtonFrame = CGRect(origin: CGPoint(x: rawSideInset + 16.0, y: 16.0), size: closeButtonSize)
if let closeButtonView = self.closeButton.view {
if closeButtonView.superview == nil {
self.navigationBarContainer.addSubview(closeButtonView)
@ -2223,7 +2287,7 @@ private final class GiftAuctionBidScreenComponent: Component {
environment: {},
containerSize: CGSize(width: 40.0, height: 40.0)
)
let infoButtonFrame = CGRect(origin: CGPoint(x: availableSize.width - 16.0 - moreButtonSize.width, y: 16.0), size: moreButtonSize)
let infoButtonFrame = CGRect(origin: CGPoint(x: availableSize.width - rawSideInset - 16.0 - moreButtonSize.width, y: 16.0), size: moreButtonSize)
if let infoButtonView = self.moreButton.view {
if infoButtonView.superview == nil {
self.navigationBarContainer.addSubview(infoButtonView)
@ -2290,7 +2354,7 @@ private final class GiftAuctionBidScreenComponent: Component {
}
myBidTitleComponent = AnyComponent(MultilineTextComponent(text: .plain(NSAttributedString(string: bidTitle.uppercased(), font: Font.medium(13.0), textColor: bidTitleColor))))
myBidComponent = AnyComponent(PeerComponent(context: component.context, theme: environment.theme, groupingSeparator: environment.dateTimeFormat.groupingSeparator, peer: peer, place: place, amount: myBidAmount, status: bidStatus, isLast: true))
myBidComponent = AnyComponent(PeerComponent(context: component.context, theme: environment.theme, groupingSeparator: environment.dateTimeFormat.groupingSeparator, peer: peer, place: place, amount: myBidAmount, status: bidStatus, isLast: true, action: nil))
}
var i: Int32 = 1
@ -2303,7 +2367,7 @@ private final class GiftAuctionBidScreenComponent: Component {
break
}
}
topBidsComponents.append((bidder, AnyComponent(PeerComponent(context: component.context, theme: environment.theme, groupingSeparator: environment.dateTimeFormat.groupingSeparator, peer: peer, place: i, amount: bid, isLast: i == topBidders.count))))
topBidsComponents.append((bidder, AnyComponent(PeerComponent(context: component.context, theme: environment.theme, groupingSeparator: environment.dateTimeFormat.groupingSeparator, peer: peer, place: i, amount: bid, isLast: i == topBidders.count, action: peer.id != component.context.account.peerId ? { [weak self] in self?.openPeer(peer, dismiss: false) } : nil))))
}
i += 1
}
@ -2541,11 +2605,11 @@ private final class GiftAuctionBidScreenComponent: Component {
}
)),
environment: {},
containerSize: CGSize(width: availableSize.width - buttonInsets.left - buttonInsets.right, height: 54.0)
containerSize: CGSize(width: fillingSize - buttonInsets.left - buttonInsets.right, height: 54.0)
)
let edgeEffectHeight: CGFloat = 80.0
let edgeEffectFrame = CGRect(origin: CGPoint(x: 0.0, y: 0.0), size: CGSize(width: availableSize.width, height: edgeEffectHeight))
let edgeEffectFrame = CGRect(origin: CGPoint(x: rawSideInset, y: 0.0), size: CGSize(width: fillingSize, height: edgeEffectHeight))
transition.setFrame(view: self.topEdgeEffectView, frame: edgeEffectFrame)
self.topEdgeEffectView.update(content: environment.theme.actionSheet.opaqueItemBackgroundColor, blur: true, alpha: 1.0, rect: edgeEffectFrame, edge: .top, edgeSize: edgeEffectFrame.height, transition: transition)
if self.topEdgeEffectView.superview == nil {
@ -2555,14 +2619,14 @@ private final class GiftAuctionBidScreenComponent: Component {
var bottomPanelHeight = 13.0 + buttonInsets.bottom + actionButtonSize.height
let bottomEdgeEffectHeight: CGFloat = bottomPanelHeight
let bottomEdgeEffectFrame = CGRect(origin: CGPoint(x: 0.0, y: availableSize.height - bottomEdgeEffectHeight), size: CGSize(width: availableSize.width, height: bottomEdgeEffectHeight))
let bottomEdgeEffectFrame = CGRect(origin: CGPoint(x: rawSideInset, y: availableSize.height - bottomEdgeEffectHeight), size: CGSize(width: fillingSize, height: bottomEdgeEffectHeight))
transition.setFrame(view: self.bottomEdgeEffectView, frame: bottomEdgeEffectFrame)
self.bottomEdgeEffectView.update(content: environment.theme.actionSheet.opaqueItemBackgroundColor, blur: true, alpha: 1.0, rect: bottomEdgeEffectFrame, edge: .bottom, edgeSize: bottomEdgeEffectFrame.height, transition: transition)
if self.bottomEdgeEffectView.superview == nil {
self.containerView.addSubview(self.bottomEdgeEffectView)
}
let actionButtonFrame = CGRect(origin: CGPoint(x: buttonInsets.left, y: availableSize.height - buttonInsets.bottom - actionButtonSize.height), size: actionButtonSize)
let actionButtonFrame = CGRect(origin: CGPoint(x: rawSideInset + buttonInsets.left, y: availableSize.height - buttonInsets.bottom - actionButtonSize.height), size: actionButtonSize)
bottomPanelHeight -= 1.0
if let actionButtonView = actionButton.view {
if actionButtonView.superview == nil {
@ -2645,11 +2709,12 @@ public class GiftAuctionBidScreen: ViewControllerComponentContainer {
private var didPlayAppearAnimation: Bool = false
private var isDismissed: Bool = false
public init(context: AccountContext, auctionContext: GiftAuctionContext) {
public init(context: AccountContext, toPeerId: EnginePeer.Id, auctionContext: GiftAuctionContext) {
self.context = context
super.init(context: context, component: GiftAuctionBidScreenComponent(
context: context,
toPeerId: toPeerId,
gift: auctionContext.gift,
auctionContext: auctionContext
), navigationBarAppearance: .none, theme: .default)

View file

@ -0,0 +1,440 @@
import Foundation
import UIKit
import SwiftSignalKit
import AsyncDisplayKit
import Display
import TelegramCore
import TelegramPresentationData
import AccountContext
import UrlEscaping
private final class GiftAuctionCustomBidInputFieldNode: ASDisplayNode, ASEditableTextNodeDelegate {
private var theme: PresentationTheme
private let backgroundNode: ASImageNode
private let textInputNode: EditableTextNode
private let placeholderNode: ASTextNode
var updateHeight: (() -> Void)?
var complete: (() -> Void)?
var textChanged: ((String) -> Void)?
private let backgroundInsets = UIEdgeInsets(top: 8.0, left: 16.0, bottom: 15.0, right: 16.0)
private let inputInsets = UIEdgeInsets(top: 5.0, left: 12.0, bottom: 5.0, right: 12.0)
var text: String {
get {
return self.textInputNode.attributedText?.string ?? ""
}
set {
self.textInputNode.attributedText = NSAttributedString(string: newValue, font: Font.regular(17.0), textColor: self.theme.actionSheet.inputTextColor)
self.placeholderNode.isHidden = !newValue.isEmpty
}
}
var placeholder: String = "" {
didSet {
self.placeholderNode.attributedText = NSAttributedString(string: self.placeholder, font: Font.regular(17.0), textColor: self.theme.actionSheet.inputPlaceholderColor)
}
}
init(theme: PresentationTheme, placeholder: String, returnKeyType: UIReturnKeyType = .done) {
self.theme = theme
self.backgroundNode = ASImageNode()
self.backgroundNode.isLayerBacked = true
self.backgroundNode.displaysAsynchronously = false
self.backgroundNode.displayWithoutProcessing = true
self.backgroundNode.image = generateStretchableFilledCircleImage(diameter: 12.0, color: theme.actionSheet.inputHollowBackgroundColor, strokeColor: theme.actionSheet.inputBorderColor, strokeWidth: 1.0)
self.textInputNode = EditableTextNode()
self.textInputNode.typingAttributes = [NSAttributedString.Key.font.rawValue: Font.regular(17.0), NSAttributedString.Key.foregroundColor.rawValue: theme.actionSheet.inputTextColor]
self.textInputNode.clipsToBounds = true
self.textInputNode.hitTestSlop = UIEdgeInsets(top: -5.0, left: -5.0, bottom: -5.0, right: -5.0)
self.textInputNode.textContainerInset = UIEdgeInsets(top: self.inputInsets.top, left: 0.0, bottom: self.inputInsets.bottom, right: 0.0)
self.textInputNode.keyboardAppearance = theme.rootController.keyboardColor.keyboardAppearance
self.textInputNode.keyboardType = .default
self.textInputNode.autocapitalizationType = .sentences
self.textInputNode.returnKeyType = returnKeyType
self.textInputNode.autocorrectionType = .default
self.textInputNode.tintColor = theme.actionSheet.controlAccentColor
self.textInputNode.keyboardType = .numberPad
self.placeholderNode = ASTextNode()
self.placeholderNode.isUserInteractionEnabled = false
self.placeholderNode.displaysAsynchronously = false
self.placeholderNode.attributedText = NSAttributedString(string: placeholder, font: Font.regular(17.0), textColor: self.theme.actionSheet.inputPlaceholderColor)
super.init()
self.textInputNode.delegate = self
self.addSubnode(self.backgroundNode)
self.addSubnode(self.textInputNode)
self.addSubnode(self.placeholderNode)
}
func updateTheme(_ theme: PresentationTheme) {
self.theme = theme
self.backgroundNode.image = generateStretchableFilledCircleImage(diameter: 12.0, color: self.theme.actionSheet.inputHollowBackgroundColor, strokeColor: self.theme.actionSheet.inputBorderColor, strokeWidth: 1.0)
self.textInputNode.keyboardAppearance = self.theme.rootController.keyboardColor.keyboardAppearance
self.placeholderNode.attributedText = NSAttributedString(string: self.placeholderNode.attributedText?.string ?? "", font: Font.regular(17.0), textColor: self.theme.actionSheet.inputPlaceholderColor)
self.textInputNode.tintColor = self.theme.actionSheet.controlAccentColor
}
func updateLayout(width: CGFloat, transition: ContainedViewLayoutTransition) -> CGFloat {
let backgroundInsets = self.backgroundInsets
let inputInsets = self.inputInsets
let textFieldHeight = self.calculateTextFieldMetrics(width: width)
let panelHeight = textFieldHeight + backgroundInsets.top + backgroundInsets.bottom
let backgroundFrame = CGRect(origin: CGPoint(x: backgroundInsets.left, y: backgroundInsets.top), size: CGSize(width: width - backgroundInsets.left - backgroundInsets.right, height: panelHeight - backgroundInsets.top - backgroundInsets.bottom))
transition.updateFrame(node: self.backgroundNode, frame: backgroundFrame)
let placeholderSize = self.placeholderNode.measure(backgroundFrame.size)
transition.updateFrame(node: self.placeholderNode, frame: CGRect(origin: CGPoint(x: backgroundFrame.minX + inputInsets.left, y: backgroundFrame.minY + floor((backgroundFrame.size.height - placeholderSize.height) / 2.0)), size: placeholderSize))
transition.updateFrame(node: self.textInputNode, frame: CGRect(origin: CGPoint(x: backgroundFrame.minX + inputInsets.left, y: backgroundFrame.minY), size: CGSize(width: backgroundFrame.size.width - inputInsets.left - inputInsets.right - 20.0, height: backgroundFrame.size.height)))
return panelHeight
}
func activateInput() {
self.textInputNode.becomeFirstResponder()
}
func deactivateInput() {
self.textInputNode.resignFirstResponder()
}
@objc func editableTextNodeDidUpdateText(_ editableTextNode: ASEditableTextNode) {
self.updateTextNodeText(animated: true)
self.textChanged?(editableTextNode.textView.text)
self.placeholderNode.isHidden = !(editableTextNode.textView.text ?? "").isEmpty
}
func editableTextNodeDidBeginEditing(_ editableTextNode: ASEditableTextNode) {
}
func editableTextNodeDidFinishEditing(_ editableTextNode: ASEditableTextNode) {
}
func editableTextNode(_ editableTextNode: ASEditableTextNode, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool {
let updatedText = (editableTextNode.textView.text as NSString).replacingCharacters(in: range, with: text)
if updatedText.count > 1 {
self.textInputNode.layer.addShakeAnimation()
return false
}
if text == "\n" {
self.complete?()
return false
}
return true
}
private func calculateTextFieldMetrics(width: CGFloat) -> CGFloat {
let backgroundInsets = self.backgroundInsets
let inputInsets = self.inputInsets
let unboundTextFieldHeight = max(33.0, ceil(self.textInputNode.measure(CGSize(width: width - backgroundInsets.left - backgroundInsets.right - inputInsets.left - inputInsets.right - 20.0, height: CGFloat.greatestFiniteMagnitude)).height))
return min(61.0, max(33.0, unboundTextFieldHeight))
}
private func updateTextNodeText(animated: Bool) {
let backgroundInsets = self.backgroundInsets
let textFieldHeight = self.calculateTextFieldMetrics(width: self.bounds.size.width)
let panelHeight = textFieldHeight + backgroundInsets.top + backgroundInsets.bottom
if !self.bounds.size.height.isEqual(to: panelHeight) {
self.updateHeight?()
}
}
@objc func clearPressed() {
self.placeholderNode.isHidden = false
self.textInputNode.attributedText = nil
self.updateHeight?()
}
}
private final class giftAuctionCustomBidAlertContentNode: AlertContentNode {
private let strings: PresentationStrings
private let title: String
private let text: String
private let titleNode: ASTextNode
private let textNode: ASTextNode
let inputFieldNode: GiftAuctionCustomBidInputFieldNode
private let actionNodesSeparator: ASDisplayNode
private let actionNodes: [TextAlertContentActionNode]
private let actionVerticalSeparators: [ASDisplayNode]
private let disposable = MetaDisposable()
private var validLayout: CGSize?
private let hapticFeedback = HapticFeedback()
var complete: (() -> Void)? {
didSet {
self.inputFieldNode.complete = self.complete
}
}
override var dismissOnOutsideTap: Bool {
return self.isUserInteractionEnabled
}
init(theme: AlertControllerTheme, ptheme: PresentationTheme, strings: PresentationStrings, actions: [TextAlertAction], title: String, text: String, placeholder: String, value: Int64) {
self.strings = strings
self.title = title
self.text = text
self.titleNode = ASTextNode()
self.titleNode.maximumNumberOfLines = 2
self.textNode = ASTextNode()
self.textNode.maximumNumberOfLines = 8
self.inputFieldNode = GiftAuctionCustomBidInputFieldNode(theme: ptheme, placeholder: placeholder)
self.inputFieldNode.text = "\(value)"
self.actionNodesSeparator = ASDisplayNode()
self.actionNodesSeparator.isLayerBacked = true
self.actionNodes = actions.map { action -> TextAlertContentActionNode in
return TextAlertContentActionNode(theme: theme, action: action)
}
var actionVerticalSeparators: [ASDisplayNode] = []
if actions.count > 1 {
for _ in 0 ..< actions.count - 1 {
let separatorNode = ASDisplayNode()
separatorNode.isLayerBacked = true
actionVerticalSeparators.append(separatorNode)
}
}
self.actionVerticalSeparators = actionVerticalSeparators
super.init()
self.addSubnode(self.titleNode)
self.addSubnode(self.textNode)
self.addSubnode(self.inputFieldNode)
self.addSubnode(self.actionNodesSeparator)
for actionNode in self.actionNodes {
self.addSubnode(actionNode)
}
for separatorNode in self.actionVerticalSeparators {
self.addSubnode(separatorNode)
}
self.inputFieldNode.updateHeight = { [weak self] in
if let strongSelf = self {
if let _ = strongSelf.validLayout {
strongSelf.requestLayout?(.animated(duration: 0.15, curve: .spring))
}
}
}
self.updateTheme(theme)
}
deinit {
self.disposable.dispose()
}
var value: String {
return self.inputFieldNode.text
}
override func updateTheme(_ theme: AlertControllerTheme) {
self.titleNode.attributedText = NSAttributedString(string: self.title, font: Font.bold(17.0), textColor: theme.primaryColor, paragraphAlignment: .center)
self.textNode.attributedText = NSAttributedString(string: self.text, font: Font.regular(13.0), textColor: theme.primaryColor, paragraphAlignment: .center)
self.actionNodesSeparator.backgroundColor = theme.separatorColor
for actionNode in self.actionNodes {
actionNode.updateTheme(theme)
}
for separatorNode in self.actionVerticalSeparators {
separatorNode.backgroundColor = theme.separatorColor
}
if let size = self.validLayout {
_ = self.updateLayout(size: size, transition: .immediate)
}
}
override func updateLayout(size: CGSize, transition: ContainedViewLayoutTransition) -> CGSize {
var size = size
size.width = min(size.width, 270.0)
let measureSize = CGSize(width: size.width - 16.0 * 2.0, height: CGFloat.greatestFiniteMagnitude)
let hadValidLayout = self.validLayout != nil
self.validLayout = size
var origin: CGPoint = CGPoint(x: 0.0, y: 20.0)
let spacing: CGFloat = 5.0
let titleSize = self.titleNode.measure(measureSize)
transition.updateFrame(node: self.titleNode, frame: CGRect(origin: CGPoint(x: floorToScreenPixels((size.width - titleSize.width) / 2.0), y: origin.y), size: titleSize))
origin.y += titleSize.height + 4.0
let textSize = self.textNode.measure(measureSize)
transition.updateFrame(node: self.textNode, frame: CGRect(origin: CGPoint(x: floorToScreenPixels((size.width - textSize.width) / 2.0), y: origin.y), size: textSize))
origin.y += textSize.height + 6.0 + spacing
let actionButtonHeight: CGFloat = 44.0
var minActionsWidth: CGFloat = 0.0
let maxActionWidth: CGFloat = floor(size.width / CGFloat(self.actionNodes.count))
let actionTitleInsets: CGFloat = 8.0
var effectiveActionLayout = TextAlertContentActionLayout.horizontal
for actionNode in self.actionNodes {
let actionTitleSize = actionNode.titleNode.updateLayout(CGSize(width: maxActionWidth, height: actionButtonHeight))
if case .horizontal = effectiveActionLayout, actionTitleSize.height > actionButtonHeight * 0.6667 {
effectiveActionLayout = .vertical
}
switch effectiveActionLayout {
case .horizontal:
minActionsWidth += actionTitleSize.width + actionTitleInsets
case .vertical:
minActionsWidth = max(minActionsWidth, actionTitleSize.width + actionTitleInsets)
}
}
let insets = UIEdgeInsets(top: 18.0, left: 18.0, bottom: 9.0, right: 18.0)
var contentWidth = max(titleSize.width, minActionsWidth)
contentWidth = max(contentWidth, 234.0)
var actionsHeight: CGFloat = 0.0
switch effectiveActionLayout {
case .horizontal:
actionsHeight = actionButtonHeight
case .vertical:
actionsHeight = actionButtonHeight * CGFloat(self.actionNodes.count)
}
let resultWidth = contentWidth + insets.left + insets.right
let inputFieldWidth = resultWidth
let inputFieldHeight = self.inputFieldNode.updateLayout(width: inputFieldWidth, transition: transition)
let inputHeight = inputFieldHeight
transition.updateFrame(node: self.inputFieldNode, frame: CGRect(x: 0.0, y: origin.y, width: resultWidth, height: inputFieldHeight))
transition.updateAlpha(node: self.inputFieldNode, alpha: inputHeight > 0.0 ? 1.0 : 0.0)
let resultSize = CGSize(width: resultWidth, height: titleSize.height + textSize.height + spacing + inputHeight + actionsHeight + insets.top + insets.bottom)
transition.updateFrame(node: self.actionNodesSeparator, frame: CGRect(origin: CGPoint(x: 0.0, y: resultSize.height - actionsHeight - UIScreenPixel), size: CGSize(width: resultSize.width, height: UIScreenPixel)))
var actionOffset: CGFloat = 0.0
let actionWidth: CGFloat = floor(resultSize.width / CGFloat(self.actionNodes.count))
var separatorIndex = -1
var nodeIndex = 0
for actionNode in self.actionNodes {
if separatorIndex >= 0 {
let separatorNode = self.actionVerticalSeparators[separatorIndex]
switch effectiveActionLayout {
case .horizontal:
transition.updateFrame(node: separatorNode, frame: CGRect(origin: CGPoint(x: actionOffset - UIScreenPixel, y: resultSize.height - actionsHeight), size: CGSize(width: UIScreenPixel, height: actionsHeight - UIScreenPixel)))
case .vertical:
transition.updateFrame(node: separatorNode, frame: CGRect(origin: CGPoint(x: 0.0, y: resultSize.height - actionsHeight + actionOffset - UIScreenPixel), size: CGSize(width: resultSize.width, height: UIScreenPixel)))
}
}
separatorIndex += 1
let currentActionWidth: CGFloat
switch effectiveActionLayout {
case .horizontal:
if nodeIndex == self.actionNodes.count - 1 {
currentActionWidth = resultSize.width - actionOffset
} else {
currentActionWidth = actionWidth
}
case .vertical:
currentActionWidth = resultSize.width
}
let actionNodeFrame: CGRect
switch effectiveActionLayout {
case .horizontal:
actionNodeFrame = CGRect(origin: CGPoint(x: actionOffset, y: resultSize.height - actionsHeight), size: CGSize(width: currentActionWidth, height: actionButtonHeight))
actionOffset += currentActionWidth
case .vertical:
actionNodeFrame = CGRect(origin: CGPoint(x: 0.0, y: resultSize.height - actionsHeight + actionOffset), size: CGSize(width: currentActionWidth, height: actionButtonHeight))
actionOffset += actionButtonHeight
}
transition.updateFrame(node: actionNode, frame: actionNodeFrame)
nodeIndex += 1
}
if !hadValidLayout {
self.inputFieldNode.activateInput()
}
return resultSize
}
func animateError() {
self.inputFieldNode.layer.addShakeAnimation()
self.hapticFeedback.error()
}
}
func giftAuctionCustomBidController(context: AccountContext, title: String, text: String, placeholder: String, value: Int64, apply: @escaping (Int64) -> Void) -> AlertController {
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
var dismissImpl: ((Bool) -> Void)?
var applyImpl: (() -> Void)?
let actions: [TextAlertAction] = [TextAlertAction(type: .genericAction, title: presentationData.strings.Common_Cancel, action: {
dismissImpl?(true)
}), TextAlertAction(type: .defaultAction, title: "Place a Bid", action: {
applyImpl?()
})]
let contentNode = giftAuctionCustomBidAlertContentNode(theme: AlertControllerTheme(presentationData: presentationData), ptheme: presentationData.theme, strings: presentationData.strings, actions: actions, title: title, text: text, placeholder: placeholder, value: value)
contentNode.complete = {
applyImpl?()
}
applyImpl = { [weak contentNode] in
guard let contentNode = contentNode else {
return
}
dismissImpl?(true)
if let value = Int64(contentNode.value.trimmingCharacters(in: .whitespacesAndNewlines)) {
apply(value)
}
}
let controller = AlertController(theme: AlertControllerTheme(presentationData: presentationData), contentNode: contentNode)
let presentationDataDisposable = context.sharedContext.presentationData.start(next: { [weak controller, weak contentNode] presentationData in
controller?.theme = AlertControllerTheme(presentationData: presentationData)
contentNode?.inputFieldNode.updateTheme(presentationData.theme)
})
controller.dismissed = { _ in
presentationDataDisposable.dispose()
}
dismissImpl = { [weak controller, weak contentNode] animated in
contentNode?.inputFieldNode.deactivateInput()
if animated {
controller?.dismissAnimated()
} else {
controller?.dismiss()
}
}
return controller
}

View file

@ -33,17 +33,20 @@ private final class GiftAuctionViewSheetContent: CombinedComponent {
typealias EnvironmentType = ViewControllerComponentContainer.Environment
let context: AccountContext
let toPeerId: EnginePeer.Id
let auctionContext: GiftAuctionContext
let animateOut: ActionSlot<Action<()>>
let getController: () -> ViewController?
init(
context: AccountContext,
toPeerId: EnginePeer.Id,
auctionContext: GiftAuctionContext,
animateOut: ActionSlot<Action<()>>,
getController: @escaping () -> ViewController?
) {
self.context = context
self.toPeerId = toPeerId
self.auctionContext = auctionContext
self.animateOut = animateOut
self.getController = getController
@ -60,6 +63,7 @@ private final class GiftAuctionViewSheetContent: CombinedComponent {
let averagePriceTag = GenericComponentViewTag()
private let context: AccountContext
private let toPeerId: EnginePeer.Id
private let auctionContext: GiftAuctionContext
private let animateOut: ActionSlot<Action<()>>
private let getController: () -> ViewController?
@ -78,11 +82,13 @@ private final class GiftAuctionViewSheetContent: CombinedComponent {
init(
context: AccountContext,
toPeerId: EnginePeer.Id,
auctionContext: GiftAuctionContext,
animateOut: ActionSlot<Action<()>>,
getController: @escaping () -> ViewController?
) {
self.context = context
self.toPeerId = toPeerId
self.auctionContext = auctionContext
self.animateOut = animateOut
self.getController = getController
@ -163,7 +169,7 @@ private final class GiftAuctionViewSheetContent: CombinedComponent {
self.dismiss(animated: true)
let bidController = self.context.sharedContext.makeGiftAuctionBidScreen(context: self.context, auctionContext: self.auctionContext)
let bidController = self.context.sharedContext.makeGiftAuctionBidScreen(context: self.context, toPeerId: self.auctionContext.currentBidPeerId ?? self.toPeerId, auctionContext: self.auctionContext)
navigationController.pushViewController(bidController)
}
@ -344,7 +350,7 @@ private final class GiftAuctionViewSheetContent: CombinedComponent {
}
func makeState() -> State {
return State(context: self.context, auctionContext: self.auctionContext, animateOut: self.animateOut, getController: self.getController)
return State(context: self.context, toPeerId: self.toPeerId, auctionContext: self.auctionContext, animateOut: self.animateOut, getController: self.getController)
}
static var body: Body {
@ -958,13 +964,16 @@ final class GiftAuctionViewSheetComponent: CombinedComponent {
typealias EnvironmentType = ViewControllerComponentContainer.Environment
let context: AccountContext
let toPeerId: EnginePeer.Id
let auctionContext: GiftAuctionContext
init(
context: AccountContext,
toPeerId: EnginePeer.Id,
auctionContext: GiftAuctionContext
) {
self.context = context
self.toPeerId = toPeerId
self.auctionContext = auctionContext
}
@ -989,6 +998,7 @@ final class GiftAuctionViewSheetComponent: CombinedComponent {
component: SheetComponent<EnvironmentType>(
content: AnyComponent<EnvironmentType>(GiftAuctionViewSheetContent(
context: context.component.context,
toPeerId: context.component.toPeerId,
auctionContext: context.component.auctionContext,
animateOut: animateOut,
getController: controller
@ -1071,12 +1081,14 @@ final class GiftAuctionViewSheetComponent: CombinedComponent {
public final class GiftAuctionViewScreen: ViewControllerComponentContainer {
public init(
context: AccountContext,
toPeerId: EnginePeer.Id,
auctionContext: GiftAuctionContext
) {
super.init(
context: context,
component: GiftAuctionViewSheetComponent(
context: context,
toPeerId: toPeerId,
auctionContext: auctionContext
),
navigationBarAppearance: .none,

View file

@ -1499,15 +1499,17 @@ func openResolvedUrlImpl(
}
case let .auction(auctionContext):
if let auctionContext {
if let _ = auctionContext.currentBidPeerId {
if let currentBidPeerId = auctionContext.currentBidPeerId {
let controller = context.sharedContext.makeGiftAuctionBidScreen(
context: context,
toPeerId: currentBidPeerId,
auctionContext: auctionContext
)
navigationController?.pushViewController(controller)
} else {
let controller = context.sharedContext.makeGiftAuctionViewScreen(
context: context,
toPeerId: context.account.peerId,
auctionContext: auctionContext
)
navigationController?.pushViewController(controller)

View file

@ -3846,12 +3846,12 @@ public final class SharedAccountContextImpl: SharedAccountContext {
return GiftAuctionInfoScreen(context: context, auctionContext: auctionContext, completion: completion)
}
public func makeGiftAuctionBidScreen(context: AccountContext, auctionContext: GiftAuctionContext) -> ViewController {
return GiftAuctionBidScreen(context: context, auctionContext: auctionContext)
public func makeGiftAuctionBidScreen(context: AccountContext, toPeerId: EnginePeer.Id, auctionContext: GiftAuctionContext) -> ViewController {
return GiftAuctionBidScreen(context: context, toPeerId: toPeerId, auctionContext: auctionContext)
}
public func makeGiftAuctionViewScreen(context: AccountContext, auctionContext: GiftAuctionContext) -> ViewController {
return GiftAuctionViewScreen(context: context, auctionContext: auctionContext)
public func makeGiftAuctionViewScreen(context: AccountContext, toPeerId: EnginePeer.Id, auctionContext: GiftAuctionContext) -> ViewController {
return GiftAuctionViewScreen(context: context, toPeerId: toPeerId, auctionContext: auctionContext)
}
public func makeGiftAuctionActiveBidsScreen(context: AccountContext) -> ViewController {