mirror of
https://github.com/TelegramMessenger/Telegram-iOS.git
synced 2026-07-06 03:33:41 +02:00
Update API
This commit is contained in:
parent
d05425794c
commit
ea8dc07b23
11 changed files with 927 additions and 316 deletions
|
|
@ -1422,7 +1422,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, gift: StarGift, completion: (() -> Void)?) -> ViewController
|
||||
func makeGiftAuctionScreen(context: AccountContext, gift: StarGift, auctionContext: GiftAuctionContext) -> ViewController
|
||||
func makeGiftAuctionBidScreen(context: AccountContext, auctionContext: GiftAuctionContext) -> ViewController
|
||||
func makeGiftAuctionViewScreen(context: AccountContext, auctionContext: GiftAuctionContext) -> ViewController
|
||||
|
||||
func makeStorySharingScreen(context: AccountContext, subject: StorySharingSubject, parentController: ViewController) -> ViewController
|
||||
|
||||
|
|
|
|||
|
|
@ -4,22 +4,39 @@ import MtProtoKit
|
|||
import SwiftSignalKit
|
||||
import TelegramApi
|
||||
|
||||
private func _internal_getStarGiftAuctionState(postbox: Postbox, network: Network, accountPeerId: EnginePeer.Id, giftId: Int64, version: Int32) -> Signal<(state: GiftAuctionContext.State.AuctionState?, myState: GiftAuctionContext.State.MyState, timeout: Int32)?, NoError> {
|
||||
return network.request(Api.functions.payments.getStarGiftAuctionState(auction: .inputStarGiftAuction(giftId: giftId), version: version))
|
||||
public enum StarGiftAuctionReference: Equatable {
|
||||
case giftId(Int64)
|
||||
case slug(String)
|
||||
|
||||
var apiAuction: Api.InputStarGiftAuction {
|
||||
switch self {
|
||||
case let .giftId(giftId):
|
||||
return .inputStarGiftAuction(giftId: giftId)
|
||||
case let .slug(slug):
|
||||
return .inputStarGiftAuctionSlug(slug: slug)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private func _internal_getStarGiftAuctionState(postbox: Postbox, network: Network, accountPeerId: EnginePeer.Id, reference: StarGiftAuctionReference, version: Int32) -> Signal<(gift: StarGift, state: GiftAuctionContext.State.AuctionState?, myState: GiftAuctionContext.State.MyState, timeout: Int32)?, NoError> {
|
||||
return network.request(Api.functions.payments.getStarGiftAuctionState(auction: reference.apiAuction, version: version))
|
||||
|> map(Optional.init)
|
||||
|> `catch` { _ -> Signal<Api.payments.StarGiftAuctionState?, NoError> in
|
||||
return .single(nil)
|
||||
}
|
||||
|> mapToSignal { result -> Signal<(state: GiftAuctionContext.State.AuctionState?, myState: GiftAuctionContext.State.MyState, timeout: Int32)?, NoError> in
|
||||
|> mapToSignal { result -> Signal<(gift: StarGift, state: GiftAuctionContext.State.AuctionState?, myState: GiftAuctionContext.State.MyState, timeout: Int32)?, NoError> in
|
||||
guard let result else {
|
||||
return .single(nil)
|
||||
}
|
||||
return postbox.transaction { transaction -> (state: GiftAuctionContext.State.AuctionState?, myState: GiftAuctionContext.State.MyState, timeout: Int32)? in
|
||||
return postbox.transaction { transaction -> (gift: StarGift, state: GiftAuctionContext.State.AuctionState?, myState: GiftAuctionContext.State.MyState, timeout: Int32)? in
|
||||
switch result {
|
||||
case let .starGiftAuctionState(gift, state, userState, timeout, users):
|
||||
case let .starGiftAuctionState(apiGift, state, userState, timeout, users):
|
||||
updatePeers(transaction: transaction, accountPeerId: accountPeerId, peers: AccumulatedPeers(users: users))
|
||||
let _ = gift
|
||||
guard let gift = StarGift(apiStarGift: apiGift) else {
|
||||
return nil
|
||||
}
|
||||
return (
|
||||
gift: gift,
|
||||
state: GiftAuctionContext.State.AuctionState(apiAuctionState: state),
|
||||
myState: GiftAuctionContext.State.MyState(apiAuctionUserState: userState),
|
||||
timeout: timeout
|
||||
|
|
@ -39,7 +56,7 @@ public final class GiftAuctionContext {
|
|||
|
||||
public enum AuctionState: Equatable {
|
||||
case ongoing(version: Int32, minBidAmount: Int64, bidLevels: [BidLevel], topBidders: [EnginePeer.Id], nextRoundDate: Int32, giftsLeft: Int32, currentRound: Int32, totalRounds: Int32)
|
||||
case finished
|
||||
case finished(startDate: Int32, endDate: Int32, averagePrice: Int64)
|
||||
}
|
||||
|
||||
public struct MyState: Equatable {
|
||||
|
|
@ -50,13 +67,14 @@ public final class GiftAuctionContext {
|
|||
public var acquiredCount: Int32
|
||||
}
|
||||
|
||||
public var gift: StarGift
|
||||
public var auctionState: AuctionState
|
||||
public var myState: MyState
|
||||
}
|
||||
|
||||
private let queue: Queue = .mainQueue()
|
||||
private let account: Account
|
||||
let gift: StarGift
|
||||
public let gift: StarGift
|
||||
|
||||
private let disposable = MetaDisposable()
|
||||
|
||||
|
|
@ -64,8 +82,6 @@ public final class GiftAuctionContext {
|
|||
private var myState: State.MyState?
|
||||
private var timeout: Int32?
|
||||
|
||||
private var updateAuctionStateDisposable: Disposable?
|
||||
private var updateMyStateDisposable: Disposable?
|
||||
private var updateTimer: SwiftSignalKit.Timer?
|
||||
|
||||
private let stateValue = Promise<State?>()
|
||||
|
|
@ -74,55 +90,21 @@ public final class GiftAuctionContext {
|
|||
}
|
||||
|
||||
public convenience init(account: Account, gift: StarGift) {
|
||||
self.init(account: account, gift: gift, initialAuctionState: nil, initialMyState: nil)
|
||||
self.init(account: account, gift: gift, initialAuctionState: nil, initialMyState: nil, initialTimeout: nil)
|
||||
}
|
||||
|
||||
init(account: Account, gift: StarGift, initialAuctionState: State.AuctionState?, initialMyState: State.MyState?) {
|
||||
init(account: Account, gift: StarGift, initialAuctionState: State.AuctionState?, initialMyState: State.MyState?, initialTimeout: Int32?) {
|
||||
self.account = account
|
||||
self.gift = gift
|
||||
|
||||
self.auctionState = initialAuctionState
|
||||
self.myState = initialMyState
|
||||
self.timeout = initialTimeout
|
||||
|
||||
self.load()
|
||||
|
||||
self.updateAuctionStateDisposable = (self.account.stateManager.updatedStarGiftAuctionState()
|
||||
|> mapToSignal { updates in
|
||||
if let update = updates[gift.giftId] {
|
||||
return .single(update)
|
||||
}
|
||||
return .complete()
|
||||
}
|
||||
|> deliverOnMainQueue).start(next: { [weak self] auctionState in
|
||||
guard let self else {
|
||||
return
|
||||
}
|
||||
if case let .ongoing(version, _, _, _, _, _, _, _) = auctionState, version < self.currentVersion {
|
||||
} else {
|
||||
self.auctionState = auctionState
|
||||
}
|
||||
self.pushState()
|
||||
})
|
||||
|
||||
self.updateMyStateDisposable = (self.account.stateManager.updatedStarGiftAuctionMyState()
|
||||
|> mapToSignal { updates in
|
||||
if let update = updates[gift.giftId] {
|
||||
return .single(update)
|
||||
}
|
||||
return .complete()
|
||||
}
|
||||
|> deliverOnMainQueue).start(next: { [weak self] myState in
|
||||
guard let self else {
|
||||
return
|
||||
}
|
||||
self.myState = myState
|
||||
self.pushState()
|
||||
})
|
||||
}
|
||||
|
||||
deinit {
|
||||
self.updateAuctionStateDisposable?.dispose()
|
||||
self.updateMyStateDisposable?.dispose()
|
||||
self.updateTimer?.invalidate()
|
||||
self.disposable.dispose()
|
||||
}
|
||||
|
|
@ -138,12 +120,12 @@ public final class GiftAuctionContext {
|
|||
public func load() {
|
||||
self.pushState()
|
||||
|
||||
self.disposable.set((_internal_getStarGiftAuctionState(postbox: self.account.postbox, network: self.account.network, accountPeerId: self.account.peerId, giftId: self.gift.giftId, version: self.currentVersion)
|
||||
self.disposable.set((_internal_getStarGiftAuctionState(postbox: self.account.postbox, network: self.account.network, accountPeerId: self.account.peerId, reference: .giftId(self.gift.giftId), version: self.currentVersion)
|
||||
|> deliverOn(self.queue)).start(next: { [weak self] data in
|
||||
guard let self else {
|
||||
return
|
||||
}
|
||||
guard let (auctionState, myState, timeout) = data else {
|
||||
guard let (_, auctionState, myState, timeout) = data else {
|
||||
return
|
||||
}
|
||||
|
||||
|
|
@ -166,47 +148,26 @@ public final class GiftAuctionContext {
|
|||
self.updateTimer?.start()
|
||||
}))
|
||||
}
|
||||
|
||||
func updateAuctionState(_ auctionState: GiftAuctionContext.State.AuctionState) {
|
||||
self.auctionState = auctionState
|
||||
self.pushState()
|
||||
}
|
||||
|
||||
// public func placeBid(value: Int64) {
|
||||
// return _internal_fetchBotPaymentForm(accountPeerId: self.account.peerId, postbox: self.account.postbox, network: self.account.network, source: source, themeParams: nil)
|
||||
// |> map(Optional.init)
|
||||
// |> `catch` { error -> Signal<BotPaymentForm?, BuyStarGiftError> in
|
||||
// if case let .starGiftResellTooEarly(timestamp) = error {
|
||||
// return .fail(.starGiftResellTooEarly(timestamp))
|
||||
// }
|
||||
// return .fail(.generic)
|
||||
// }
|
||||
// |> mapToSignal { paymentForm in
|
||||
// if let paymentForm {
|
||||
// if let paymentPrice = paymentForm.invoice.prices.first?.amount, let price, paymentPrice > price.amount.value {
|
||||
// let currencyAmount: CurrencyAmount
|
||||
// if paymentForm.invoice.currency == "TON" {
|
||||
// currencyAmount = CurrencyAmount(amount: StarsAmount(value: paymentPrice, nanos: 0), currency: .ton)
|
||||
// } else {
|
||||
// currencyAmount = CurrencyAmount(amount: StarsAmount(value: paymentPrice, nanos: 0), currency: .stars)
|
||||
// }
|
||||
// return .fail(.priceChanged(currencyAmount))
|
||||
// }
|
||||
// return _internal_sendStarsPaymentForm(account: account, formId: paymentForm.id, source: source)
|
||||
// |> mapError { error -> BuyStarGiftError in
|
||||
// if case let .serverProvided(text) = error {
|
||||
// return .serverProvided(text)
|
||||
// } else {
|
||||
// return .generic
|
||||
// }
|
||||
// }
|
||||
// |> ignoreValues
|
||||
// } else {
|
||||
// return .fail(.generic)
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
func updateMyState(_ myState: GiftAuctionContext.State.MyState) {
|
||||
self.myState = myState
|
||||
self.pushState()
|
||||
}
|
||||
|
||||
private func pushState() {
|
||||
if let auctionState = self.auctionState, let myState = self.myState {
|
||||
self.stateValue.set(.single(
|
||||
State(auctionState: auctionState, myState: myState)
|
||||
))
|
||||
self.stateValue.set(
|
||||
.single(State(
|
||||
gift: self.gift,
|
||||
auctionState: auctionState,
|
||||
myState: myState
|
||||
))
|
||||
)
|
||||
} else {
|
||||
self.stateValue.set(.single(nil))
|
||||
}
|
||||
|
|
@ -231,8 +192,8 @@ extension GiftAuctionContext.State.AuctionState {
|
|||
let _ = startDate
|
||||
let _ = endDate
|
||||
self = .ongoing(version: version, minBidAmount: minBidAmount, bidLevels: bidLevels.map(GiftAuctionContext.State.BidLevel.init(apiBidLevel:)), topBidders: topBidders.map { EnginePeer.Id(namespace: Namespaces.Peer.CloudUser, id: PeerId.Id._internalFromInt64Value($0)) }, nextRoundDate: nextRoundAt, giftsLeft: giftsLeft, currentRound: currentRound, totalRounds: totalRounds)
|
||||
case .starGiftAuctionStateFinished:
|
||||
self = .finished
|
||||
case let .starGiftAuctionStateFinished(startDate, endDate, averagePrice):
|
||||
self = .finished(startDate: startDate, endDate: endDate, averagePrice: averagePrice)
|
||||
case .starGiftAuctionStateNotModified:
|
||||
return nil
|
||||
}
|
||||
|
|
@ -333,7 +294,8 @@ func _internal_getActiveGiftAuctions(account: Account, hash: Int64) -> Signal<[G
|
|||
account: account,
|
||||
gift: gift,
|
||||
initialAuctionState: GiftAuctionContext.State.AuctionState(apiAuctionState: auctionState),
|
||||
initialMyState: GiftAuctionContext.State.MyState(apiAuctionUserState: userState)
|
||||
initialMyState: GiftAuctionContext.State.MyState(apiAuctionUserState: userState),
|
||||
initialTimeout: nil
|
||||
))
|
||||
}
|
||||
}
|
||||
|
|
@ -351,15 +313,62 @@ public class GiftAuctionsManager {
|
|||
private var auctionContexts: [Int64 : GiftAuctionContext] = [:]
|
||||
|
||||
private let disposable = MetaDisposable()
|
||||
private var updateAuctionStateDisposable: Disposable?
|
||||
private var updateMyStateDisposable: Disposable?
|
||||
|
||||
private let statePromise = Promise<[GiftAuctionContext.State]>([])
|
||||
public var state: Signal<[GiftAuctionContext.State], NoError> {
|
||||
return self.statePromise.get()
|
||||
}
|
||||
|
||||
public init(account: Account) {
|
||||
self.account = account
|
||||
|
||||
self.updateAuctionStateDisposable = (self.account.stateManager.updatedStarGiftAuctionState()
|
||||
|> deliverOnMainQueue).start(next: { [weak self] updates in
|
||||
guard let self else {
|
||||
return
|
||||
}
|
||||
var reload = false
|
||||
for (giftId, update) in updates {
|
||||
if let auctionContext = self.auctionContexts[giftId] {
|
||||
auctionContext.updateAuctionState(update)
|
||||
} else {
|
||||
reload = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if reload {
|
||||
self.reload()
|
||||
}
|
||||
})
|
||||
|
||||
self.updateMyStateDisposable = (self.account.stateManager.updatedStarGiftAuctionMyState()
|
||||
|> deliverOnMainQueue).start(next: { [weak self] updates in
|
||||
guard let self else {
|
||||
return
|
||||
}
|
||||
var reload = false
|
||||
for (giftId, update) in updates {
|
||||
if let auctionContext = self.auctionContexts[giftId] {
|
||||
auctionContext.updateMyState(update)
|
||||
} else {
|
||||
reload = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if reload {
|
||||
self.reload()
|
||||
}
|
||||
})
|
||||
|
||||
self.reload()
|
||||
}
|
||||
|
||||
deinit {
|
||||
self.disposable.dispose()
|
||||
self.updateAuctionStateDisposable?.dispose()
|
||||
self.updateMyStateDisposable?.dispose()
|
||||
}
|
||||
|
||||
public func reload() {
|
||||
|
|
@ -373,23 +382,65 @@ public class GiftAuctionsManager {
|
|||
auctionContexts[auction.gift.giftId] = auction
|
||||
}
|
||||
self.auctionContexts = auctionContexts
|
||||
self.updateState()
|
||||
}))
|
||||
}
|
||||
|
||||
public func auctionContextForGift(gift: StarGift) -> GiftAuctionContext? {
|
||||
guard case .generic = gift else {
|
||||
return nil
|
||||
}
|
||||
if let current = self.auctionContexts[gift.giftId] {
|
||||
return current
|
||||
public func auctionContext(for reference: StarGiftAuctionReference) -> Signal<GiftAuctionContext?, NoError> {
|
||||
if case let .giftId(id) = reference, let current = self.auctionContexts[id] {
|
||||
return .single(current)
|
||||
} else {
|
||||
let auctionContext = GiftAuctionContext(account: self.account, gift: gift)
|
||||
self.auctionContexts[gift.giftId] = auctionContext
|
||||
return auctionContext
|
||||
return _internal_getStarGiftAuctionState(
|
||||
postbox: self.account.postbox,
|
||||
network: self.account.network,
|
||||
accountPeerId: self.account.peerId,
|
||||
reference: reference,
|
||||
version: 0
|
||||
) |> mapToSignal { [weak self] result in
|
||||
if let self, let result {
|
||||
let auctionContext = GiftAuctionContext(account: self.account, gift: result.gift, initialAuctionState: result.state, initialMyState: result.myState, initialTimeout: result.timeout)
|
||||
self.auctionContexts[result.gift.giftId] = auctionContext
|
||||
self.updateState()
|
||||
return .single(auctionContext)
|
||||
} else {
|
||||
return .single(nil)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
func storeAuctionContext(auctionContext: GiftAuctionContext) {
|
||||
self.auctionContexts[auctionContext.gift.giftId] = auctionContext
|
||||
self.updateState()
|
||||
}
|
||||
|
||||
private func updateState() {
|
||||
var signals: [Signal<GiftAuctionContext.State, NoError>] = []
|
||||
for (_, auction) in self.auctionContexts {
|
||||
signals.append(auction.state
|
||||
|> mapToSignal { state in
|
||||
if let state {
|
||||
return .single(state)
|
||||
} else {
|
||||
return .complete()
|
||||
}
|
||||
})
|
||||
}
|
||||
self.statePromise.set(combineLatest(signals))
|
||||
}
|
||||
}
|
||||
|
||||
public extension GiftAuctionContext.State {
|
||||
var place: Int32? {
|
||||
guard case let .ongoing(_, _, bidLevels, _, _, _, _, _) = self.auctionState, let myBid = self.myState.bidAmount, let myBidDate = self.myState.bidDate else {
|
||||
return nil
|
||||
}
|
||||
var place: Int32 = 1
|
||||
for level in bidLevels {
|
||||
if myBid < level.amount || (myBid == level.amount && myBidDate > level.date) {
|
||||
place = level.position + 1
|
||||
}
|
||||
}
|
||||
return place
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -729,9 +729,14 @@ private extension StarsContext.State.Transaction {
|
|||
if (apiFlags & (1 << 26)) != 0 {
|
||||
flags.insert(.isStarGiftDropOriginalDetails)
|
||||
}
|
||||
if (apiFlags & (1 << 27)) != 0 {
|
||||
flags.insert(.isLiveStreamPaidMessage)
|
||||
}
|
||||
if (apiFlags & (1 << 28)) != 0 {
|
||||
flags.insert(.isStarGiftAuctionBid)
|
||||
}
|
||||
|
||||
let media = extendedMedia.flatMap({ $0.compactMap { textMediaAndExpirationTimerFromApiMedia($0, PeerId(0)).media } }) ?? []
|
||||
let _ = subscriptionPeriod
|
||||
|
||||
self.init(flags: flags, id: id, count: CurrencyAmount(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?.peerId, starrefAmount: starrefAmount.flatMap(StarsAmount.init(apiAmount:)), paidMessageCount: paidMessageCount, premiumGiftMonths: premiumGiftMonths, adsProceedsFromDate: adsProceedsFromDate, adsProceedsToDate: adsProceedsToDate)
|
||||
}
|
||||
|
|
@ -786,6 +791,8 @@ public final class StarsContext {
|
|||
public static let isPostsSearch = Flags(rawValue: 1 << 10)
|
||||
public static let isStarGiftPrepaidUpgrade = Flags(rawValue: 1 << 11)
|
||||
public static let isStarGiftDropOriginalDetails = Flags(rawValue: 1 << 12)
|
||||
public static let isStarGiftAuctionBid = Flags(rawValue: 1 << 13)
|
||||
public static let isLiveStreamPaidMessage = Flags(rawValue: 1 << 14)
|
||||
}
|
||||
|
||||
public enum Peer: Equatable {
|
||||
|
|
|
|||
|
|
@ -535,13 +535,18 @@ private final class CameraScreenComponent: CombinedComponent {
|
|||
return
|
||||
}
|
||||
|
||||
if mode == .live && self.storiesBlockedPeers == nil {
|
||||
self.storiesBlockedPeers = BlockedPeersContext(account: self.context.account, subject: .stories)
|
||||
self.adminedChannels.set(.single([]) |> then(self.context.engine.peers.channelsForStories()))
|
||||
self.closeFriends.set(self.context.engine.data.get(TelegramEngine.EngineData.Item.Contacts.CloseFriends()))
|
||||
var isCollageEnabled = controller.cameraState.isCollageEnabled
|
||||
if mode == .live {
|
||||
if self.storiesBlockedPeers == nil {
|
||||
self.storiesBlockedPeers = BlockedPeersContext(account: self.context.account, subject: .stories)
|
||||
self.adminedChannels.set(.single([]) |> then(self.context.engine.peers.channelsForStories()))
|
||||
self.closeFriends.set(self.context.engine.data.get(TelegramEngine.EngineData.Item.Contacts.CloseFriends()))
|
||||
}
|
||||
|
||||
self.displayingCollageSelection = false
|
||||
isCollageEnabled = false
|
||||
}
|
||||
|
||||
controller.updateCameraState({ $0.updatedMode(mode) }, transition: .spring(duration: 0.3))
|
||||
controller.updateCameraState({ $0.updatedMode(mode).updatedIsCollageEnabled(isCollageEnabled) }, transition: .spring(duration: 0.3))
|
||||
|
||||
var flashOn = controller.cameraState.flashMode == .on
|
||||
if case .video = mode, case .auto = controller.cameraState.flashMode {
|
||||
|
|
|
|||
|
|
@ -311,7 +311,7 @@ final class GiftOptionsScreenComponent: Component {
|
|||
}
|
||||
|
||||
let _ = (component.context.engine.payments.checkCanSendStarGift(giftId: gift.id)
|
||||
|> deliverOnMainQueue).start(next: { [weak self, weak controller] result in
|
||||
|> deliverOnMainQueue).start(next: { [weak self, weak controller] result in
|
||||
guard let self, let controller else {
|
||||
return
|
||||
}
|
||||
|
|
@ -362,38 +362,45 @@ final class GiftOptionsScreenComponent: Component {
|
|||
return
|
||||
}
|
||||
|
||||
if let availability = gift.availability, availability.remains == 0 {
|
||||
if availability.resale > 0 {
|
||||
let storeController = component.context.sharedContext.makeGiftStoreController(
|
||||
if gift.flags.contains(.isAuction) {
|
||||
// let giftController = component.context.sharedContext.makeGiftAuctionViewScreen(
|
||||
// context: component,
|
||||
// auctionContext: <#T##GiftAuctionContext#>
|
||||
// )
|
||||
} else {
|
||||
if let availability = gift.availability, availability.remains == 0 {
|
||||
if availability.resale > 0 {
|
||||
let storeController = component.context.sharedContext.makeGiftStoreController(
|
||||
context: component.context,
|
||||
peerId: component.peerId,
|
||||
gift: gift
|
||||
)
|
||||
mainController.push(storeController)
|
||||
} else {
|
||||
let giftController = GiftViewScreen(
|
||||
context: component.context,
|
||||
subject: .soldOutGift(gift)
|
||||
)
|
||||
mainController.push(giftController)
|
||||
}
|
||||
} else {
|
||||
var forceUnique: Bool?
|
||||
if let disallowedGifts = self.state?.disallowedGifts {
|
||||
if disallowedGifts.contains(.limited) && !disallowedGifts.contains(.unique) {
|
||||
forceUnique = true
|
||||
} else if !disallowedGifts.contains(.limited) && disallowedGifts.contains(.unique) {
|
||||
forceUnique = false
|
||||
}
|
||||
}
|
||||
|
||||
let giftController = GiftSetupScreen(
|
||||
context: component.context,
|
||||
peerId: component.peerId,
|
||||
gift: gift
|
||||
)
|
||||
mainController.push(storeController)
|
||||
} else {
|
||||
let giftController = GiftViewScreen(
|
||||
context: component.context,
|
||||
subject: .soldOutGift(gift)
|
||||
subject: .starGift(gift, forceUnique),
|
||||
completion: component.completion
|
||||
)
|
||||
mainController.push(giftController)
|
||||
}
|
||||
} else {
|
||||
var forceUnique: Bool?
|
||||
if let disallowedGifts = self.state?.disallowedGifts {
|
||||
if disallowedGifts.contains(.limited) && !disallowedGifts.contains(.unique) {
|
||||
forceUnique = true
|
||||
} else if !disallowedGifts.contains(.limited) && disallowedGifts.contains(.unique) {
|
||||
forceUnique = false
|
||||
}
|
||||
}
|
||||
|
||||
let giftController = GiftSetupScreen(
|
||||
context: component.context,
|
||||
peerId: component.peerId,
|
||||
subject: .starGift(gift, forceUnique),
|
||||
completion: component.completion
|
||||
)
|
||||
mainController.push(giftController)
|
||||
}
|
||||
} else if case let .unique(gift) = gift {
|
||||
self.transferGift(gift)
|
||||
|
|
|
|||
|
|
@ -145,12 +145,7 @@ private final class GiftSetupScreenComponent: Component {
|
|||
|
||||
private var peerMap: [EnginePeer.Id: EnginePeer] = [:]
|
||||
private var sendPaidMessageStars: StarsAmount?
|
||||
|
||||
private var giftAuction: GiftAuctionContext?
|
||||
private var giftAuctionState: GiftAuctionContext.State?
|
||||
private var giftAuctionDisposable: Disposable?
|
||||
private var giftAuctionTimer: SwiftSignalKit.Timer?
|
||||
|
||||
|
||||
private var cachedStarImage: (UIImage, PresentationTheme)?
|
||||
|
||||
private var updateDisposable: Disposable?
|
||||
|
|
@ -232,8 +227,6 @@ private final class GiftSetupScreenComponent: Component {
|
|||
self.inputMediaNodeDataDisposable?.dispose()
|
||||
self.updateDisposable?.dispose()
|
||||
self.optionsDisposable?.dispose()
|
||||
self.giftAuctionDisposable?.dispose()
|
||||
self.giftAuctionTimer?.invalidate()
|
||||
}
|
||||
|
||||
func scrollViewDidScroll(_ scrollView: UIScrollView) {
|
||||
|
|
@ -327,29 +320,7 @@ private final class GiftSetupScreenComponent: Component {
|
|||
guard let component = self.component, let environment = self.environment else {
|
||||
return
|
||||
}
|
||||
|
||||
if case let .starGift(gift, _) = component.subject, gift.flags.contains(.isAuction), let navigationController = environment.controller()?.navigationController as? NavigationController {
|
||||
|
||||
let giftAuction = self.giftAuction
|
||||
let openAuction = { [weak giftAuction, weak navigationController] in
|
||||
guard let giftAuction, let navigationController else {
|
||||
return
|
||||
}
|
||||
let controller = component.context.sharedContext.makeGiftAuctionScreen(context: component.context, gift: .generic(gift), auctionContext: giftAuction)
|
||||
navigationController.pushViewController(controller)
|
||||
}
|
||||
|
||||
//if self.openedAuction {
|
||||
openAuction()
|
||||
// } else {
|
||||
// let controller = component.context.sharedContext.makeGiftAuctionInfoScreen(context: component.context, gift: .generic(gift), completion: {
|
||||
// openAuction()
|
||||
// })
|
||||
// environment.controller()?.push(controller)
|
||||
// }
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
switch component.subject {
|
||||
case let .premium(product):
|
||||
if self.payWithStars, let starsPrice = product.starsPrice, let peer = self.peerMap[component.peerId] {
|
||||
|
|
@ -908,24 +879,7 @@ private final class GiftSetupScreenComponent: Component {
|
|||
if isSelfGift {
|
||||
self.hideName = true
|
||||
}
|
||||
|
||||
if case let .starGift(gift, _) = component.subject, gift.flags.contains(.isAuction), let giftAuctionsManager = component.context.giftAuctionsManager, let giftAuction = giftAuctionsManager.auctionContextForGift(gift: .generic(gift)) {
|
||||
self.giftAuction = giftAuction
|
||||
self.giftAuctionDisposable = (giftAuction.state
|
||||
|> deliverOnMainQueue).start(next: { [weak self] state in
|
||||
guard let self else {
|
||||
return
|
||||
}
|
||||
self.giftAuctionState = state
|
||||
self.state?.updated()
|
||||
})
|
||||
|
||||
self.giftAuctionTimer = SwiftSignalKit.Timer(timeout: 0.5, repeat: true, completion: { [weak self] in
|
||||
self?.state?.updated()
|
||||
}, queue: Queue.mainQueue())
|
||||
self.giftAuctionTimer?.start()
|
||||
}
|
||||
|
||||
|
||||
var releasedBy: EnginePeer.Id?
|
||||
if case let .starGift(gift, true) = component.subject, gift.upgradeStars != nil {
|
||||
self.includeUpgrade = true
|
||||
|
|
@ -1773,51 +1727,6 @@ private final class GiftSetupScreenComponent: Component {
|
|||
contentHeight += remainingCountSize.height
|
||||
contentHeight += 7.0
|
||||
|
||||
if starGift.flags.contains(.isAuction) {
|
||||
let parsedString = parseMarkdownIntoAttributedString("50 gifts are dropped at varying intervals to the top 50 bidders by bid amount. [Learn more >]()", attributes: footerAttributes)
|
||||
let auctionFooterText = NSMutableAttributedString(attributedString: parsedString)
|
||||
|
||||
if self.cachedChevronImage == nil || self.cachedChevronImage?.1 !== environment.theme {
|
||||
self.cachedChevronImage = (generateTintedImage(image: UIImage(bundleImageName: "Item List/InlineTextRightArrow"), color: environment.theme.list.itemAccentColor)!, environment.theme)
|
||||
}
|
||||
if let range = auctionFooterText.string.range(of: ">"), let chevronImage = self.cachedChevronImage?.0 {
|
||||
auctionFooterText.addAttribute(.attachment, value: chevronImage, range: NSRange(range, in: auctionFooterText.string))
|
||||
}
|
||||
|
||||
let auctionFooterSize = self.auctionFooter.update(
|
||||
transition: transition,
|
||||
component: AnyComponent(MultilineTextComponent(
|
||||
text: .plain(auctionFooterText),
|
||||
maximumNumberOfLines: 0,
|
||||
highlightColor: environment.theme.list.itemAccentColor.withAlphaComponent(0.1),
|
||||
highlightInset: UIEdgeInsets(top: 0.0, left: 0.0, bottom: 0.0, right: -8.0),
|
||||
highlightAction: { attributes in
|
||||
if let _ = attributes[NSAttributedString.Key(rawValue: TelegramTextAttributes.URL)] {
|
||||
return NSAttributedString.Key(rawValue: TelegramTextAttributes.URL)
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
},
|
||||
tapAction: { [weak self] _, _ in
|
||||
guard let self, let component = self.component, case let .starGift(gift, _) = component.subject, let controller = self.environment?.controller() else {
|
||||
return
|
||||
}
|
||||
let infoController = component.context.sharedContext.makeGiftAuctionInfoScreen(context: component.context, gift: .generic(gift), completion: nil)
|
||||
controller.push(infoController)
|
||||
}
|
||||
)),
|
||||
environment: {},
|
||||
containerSize: CGSize(width: availableSize.width - sideInset * 2.0 - 16.0 * 2.0, height: 10000.0)
|
||||
)
|
||||
let auctionFooterFrame = CGRect(origin: CGPoint(x: sideInset + 16.0, y: contentHeight), size: auctionFooterSize)
|
||||
if let auctionFooterView = self.auctionFooter.view {
|
||||
if auctionFooterView.superview == nil {
|
||||
self.scrollContentView.addSubview(auctionFooterView)
|
||||
}
|
||||
transition.setFrame(view: auctionFooterView, frame: auctionFooterFrame)
|
||||
}
|
||||
contentHeight += auctionFooterSize.height
|
||||
}
|
||||
contentHeight += sectionSpacing
|
||||
}
|
||||
|
||||
|
|
@ -1863,67 +1772,9 @@ private final class GiftSetupScreenComponent: Component {
|
|||
buttonAttributedString.addAttribute(.kern, value: 2.0, range: NSRange(range, in: buttonAttributedString.string))
|
||||
}
|
||||
|
||||
var buttonIsLoading = false
|
||||
if let _ = self.giftAuction {
|
||||
//TODO:localize
|
||||
let buttonAttributedString = NSMutableAttributedString(string: "Place a Bid", font: Font.semibold(17.0), textColor: environment.theme.list.itemCheckColors.foregroundColor, paragraphAlignment: .center)
|
||||
buttonTitleItems.append(AnyComponentWithIdentity(id: "bid", component: AnyComponent(
|
||||
MultilineTextComponent(text: .plain(buttonAttributedString))
|
||||
)))
|
||||
if let giftAuctionState = self.giftAuctionState {
|
||||
switch giftAuctionState.auctionState {
|
||||
case let .ongoing(_, _, _, _, nextDropDate, _, _, _):
|
||||
let currentTime = Int32(CFAbsoluteTimeGetCurrent() + kCFAbsoluteTimeIntervalSince1970)
|
||||
let dropTimeout = nextDropDate - currentTime
|
||||
|
||||
let minutes = Int(dropTimeout / 60)
|
||||
let seconds = Int(dropTimeout % 60)
|
||||
|
||||
let rawString = environment.strings.Gift_Setup_NextDropIn
|
||||
var buttonAnimatedTitleItems: [AnimatedTextComponent.Item] = []
|
||||
var startIndex = rawString.startIndex
|
||||
while true {
|
||||
if let range = rawString.range(of: "{", range: startIndex ..< rawString.endIndex) {
|
||||
if range.lowerBound != startIndex {
|
||||
buttonAnimatedTitleItems.append(AnimatedTextComponent.Item(id: AnyHashable(buttonAnimatedTitleItems.count), content: .text(String(rawString[startIndex ..< range.lowerBound]))))
|
||||
}
|
||||
|
||||
startIndex = range.upperBound
|
||||
if let endRange = rawString.range(of: "}", range: startIndex ..< rawString.endIndex) {
|
||||
let controlString = rawString[range.upperBound ..< endRange.lowerBound]
|
||||
if controlString == "m" {
|
||||
buttonAnimatedTitleItems.append(AnimatedTextComponent.Item(id: AnyHashable(buttonAnimatedTitleItems.count), content: .number(minutes, minDigits: 2)))
|
||||
} else if controlString == "s" {
|
||||
buttonAnimatedTitleItems.append(AnimatedTextComponent.Item(id: AnyHashable(buttonAnimatedTitleItems.count), content: .number(seconds, minDigits: 2)))
|
||||
}
|
||||
|
||||
startIndex = endRange.upperBound
|
||||
}
|
||||
} else {
|
||||
break
|
||||
}
|
||||
}
|
||||
if startIndex != rawString.endIndex {
|
||||
buttonAnimatedTitleItems.append(AnimatedTextComponent.Item(id: AnyHashable(buttonAnimatedTitleItems.count), content: .text(String(rawString[startIndex ..< rawString.endIndex]))))
|
||||
}
|
||||
|
||||
buttonTitleItems.append(AnyComponentWithIdentity(id: "timer", component: AnyComponent(AnimatedTextComponent(
|
||||
font: Font.with(size: 12.0, weight: .medium, traits: .monospacedNumbers),
|
||||
color: environment.theme.list.itemCheckColors.foregroundColor.withAlphaComponent(0.7),
|
||||
items: buttonAnimatedTitleItems,
|
||||
noDelay: true
|
||||
))))
|
||||
case .finished:
|
||||
buttonIsEnabled = false
|
||||
}
|
||||
} else {
|
||||
buttonIsLoading = true
|
||||
}
|
||||
} else {
|
||||
buttonTitleItems.append(AnyComponentWithIdentity(id: buttonString, component: AnyComponent(
|
||||
MultilineTextComponent(text: .plain(buttonAttributedString))
|
||||
)))
|
||||
}
|
||||
buttonTitleItems.append(AnyComponentWithIdentity(id: buttonString, component: AnyComponent(
|
||||
MultilineTextComponent(text: .plain(buttonAttributedString))
|
||||
)))
|
||||
|
||||
let buttonInsets = ContainerViewLayout.concentricInsets(bottomInset: environment.safeInsets.bottom, innerDiameter: 52.0, sideInset: 32.0)
|
||||
let buttonHeight: CGFloat = 52.0
|
||||
|
|
@ -1942,7 +1793,7 @@ private final class GiftSetupScreenComponent: Component {
|
|||
component: AnyComponent(VStack(buttonTitleItems, spacing: 1.0))
|
||||
),
|
||||
isEnabled: buttonIsEnabled,
|
||||
displaysProgress: buttonIsLoading || self.inProgress,
|
||||
displaysProgress: self.inProgress,
|
||||
action: { [weak self] in
|
||||
self?.proceed()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ import GlassBarButtonComponent
|
|||
import GiftItemComponent
|
||||
import EdgeEffect
|
||||
|
||||
private final class GiftAuctionBoughtScreenComponent: Component {
|
||||
private final class GiftAuctionAcquiredScreenComponent: Component {
|
||||
typealias EnvironmentType = ViewControllerComponentContainer.Environment
|
||||
|
||||
let context: AccountContext
|
||||
|
|
@ -37,7 +37,7 @@ private final class GiftAuctionBoughtScreenComponent: Component {
|
|||
self.acquiredGifts = acquiredGifts
|
||||
}
|
||||
|
||||
static func ==(lhs: GiftAuctionBoughtScreenComponent, rhs: GiftAuctionBoughtScreenComponent) -> Bool {
|
||||
static func ==(lhs: GiftAuctionAcquiredScreenComponent, rhs: GiftAuctionAcquiredScreenComponent) -> Bool {
|
||||
return true
|
||||
}
|
||||
|
||||
|
|
@ -84,7 +84,7 @@ private final class GiftAuctionBoughtScreenComponent: Component {
|
|||
|
||||
private var ignoreScrolling: Bool = false
|
||||
|
||||
private var component: GiftAuctionBoughtScreenComponent?
|
||||
private var component: GiftAuctionAcquiredScreenComponent?
|
||||
private weak var state: EmptyComponentState?
|
||||
private var isUpdating: Bool = false
|
||||
private var environment: ViewControllerComponentContainer.Environment?
|
||||
|
|
@ -242,7 +242,7 @@ private final class GiftAuctionBoughtScreenComponent: Component {
|
|||
self.bottomEdgeEffectView.layer.animatePosition(from: CGPoint(), to: CGPoint(x: 0.0, y: animateOffset), duration: 0.3, timingFunction: CAMediaTimingFunctionName.easeInEaseOut.rawValue, removeOnCompletion: false, additive: true)
|
||||
}
|
||||
|
||||
func update(component: GiftAuctionBoughtScreenComponent, availableSize: CGSize, state: EmptyComponentState, environment: Environment<ViewControllerComponentContainer.Environment>, transition: ComponentTransition) -> CGSize {
|
||||
func update(component: GiftAuctionAcquiredScreenComponent, availableSize: CGSize, state: EmptyComponentState, environment: Environment<ViewControllerComponentContainer.Environment>, transition: ComponentTransition) -> CGSize {
|
||||
self.isUpdating = true
|
||||
defer {
|
||||
self.isUpdating = false
|
||||
|
|
@ -325,7 +325,7 @@ private final class GiftAuctionBoughtScreenComponent: Component {
|
|||
AnyComponentWithIdentity(
|
||||
id: "title",
|
||||
component: AnyComponent(
|
||||
MultilineTextComponent(text: .plain(NSAttributedString(string: "Round #1", font: tableBoldFont, textColor: tableTextColor)))
|
||||
MultilineTextComponent(text: .plain(NSAttributedString(string: "Round #\(gift.round)", font: tableBoldFont, textColor: tableTextColor)))
|
||||
)
|
||||
)
|
||||
], spacing: 1.0))
|
||||
|
|
@ -616,7 +616,7 @@ private final class GiftAuctionBoughtScreenComponent: Component {
|
|||
}
|
||||
}
|
||||
|
||||
public class GiftAuctionBoughtScreen: ViewControllerComponentContainer {
|
||||
public class GiftAuctionAcquiredScreen: ViewControllerComponentContainer {
|
||||
public final class TransitionOut {
|
||||
public let sourceView: UIView
|
||||
|
||||
|
|
@ -633,7 +633,7 @@ public class GiftAuctionBoughtScreen: ViewControllerComponentContainer {
|
|||
public init(context: AccountContext, gift: StarGift, acquiredGifts: [GiftAuctionAcquiredGift]) {
|
||||
self.context = context
|
||||
|
||||
super.init(context: context, component: GiftAuctionBoughtScreenComponent(
|
||||
super.init(context: context, component: GiftAuctionAcquiredScreenComponent(
|
||||
context: context,
|
||||
gift: gift,
|
||||
acquiredGifts: acquiredGifts
|
||||
|
|
@ -660,7 +660,7 @@ public class GiftAuctionBoughtScreen: ViewControllerComponentContainer {
|
|||
if !self.didPlayAppearAnimation {
|
||||
self.didPlayAppearAnimation = true
|
||||
|
||||
if let componentView = self.node.hostView.componentView as? GiftAuctionBoughtScreenComponent.View {
|
||||
if let componentView = self.node.hostView.componentView as? GiftAuctionAcquiredScreenComponent.View {
|
||||
componentView.animateIn()
|
||||
}
|
||||
}
|
||||
|
|
@ -670,7 +670,7 @@ public class GiftAuctionBoughtScreen: ViewControllerComponentContainer {
|
|||
if !self.isDismissed {
|
||||
self.isDismissed = true
|
||||
|
||||
if let componentView = self.node.hostView.componentView as? GiftAuctionBoughtScreenComponent.View {
|
||||
if let componentView = self.node.hostView.componentView as? GiftAuctionAcquiredScreenComponent.View {
|
||||
componentView.animateOut(completion: { [weak self] in
|
||||
completion?()
|
||||
self?.dismiss(animated: false)
|
||||
|
|
@ -729,7 +729,7 @@ private final class SliderBackgroundComponent: Component {
|
|||
|
||||
let topLineFrameTransition = transition
|
||||
let topLineAlphaTransition = transition
|
||||
/*if transition.userData(GiftAuctionScreenComponent.IsAdjustingAmountHint.self) != nil {
|
||||
/*if transition.userData(GiftAuctionBidScreenComponent.IsAdjustingAmountHint.self) != nil {
|
||||
topLineFrameTransition = .easeInOut(duration: 0.12)
|
||||
topLineAlphaTransition = .easeInOut(duration: 0.12)
|
||||
}*/
|
||||
|
|
@ -786,7 +786,7 @@ private final class SliderBackgroundComponent: Component {
|
|||
}
|
||||
|
||||
var animateTopTextAdditionalX: CGFloat = 0.0
|
||||
if transition.userData(GiftAuctionScreenComponent.IsAdjustingAmountHint.self) != nil {
|
||||
if transition.userData(GiftAuctionBidScreenComponent.IsAdjustingAmountHint.self) != nil {
|
||||
if let previousState = self.topTextOverflowState, previousState != topTextOverflowState, topTextOverflowState.animates(from: previousState) {
|
||||
animateTopTextAdditionalX = topForegroundTextView.center.x - topTextFrame.origin.x
|
||||
}
|
||||
|
|
@ -823,7 +823,7 @@ private final class SliderBackgroundComponent: Component {
|
|||
}
|
||||
}
|
||||
|
||||
private final class GiftAuctionScreenComponent: Component {
|
||||
private final class GiftAuctionBidScreenComponent: Component {
|
||||
final class IsAdjustingAmountHint {
|
||||
}
|
||||
|
||||
|
|
@ -843,7 +843,7 @@ private final class GiftAuctionScreenComponent: Component {
|
|||
self.auctionContext = auctionContext
|
||||
}
|
||||
|
||||
static func ==(lhs: GiftAuctionScreenComponent, rhs: GiftAuctionScreenComponent) -> Bool {
|
||||
static func ==(lhs: GiftAuctionBidScreenComponent, rhs: GiftAuctionBidScreenComponent) -> Bool {
|
||||
return true
|
||||
}
|
||||
|
||||
|
|
@ -998,7 +998,7 @@ private final class GiftAuctionScreenComponent: Component {
|
|||
|
||||
private var ignoreScrolling: Bool = false
|
||||
|
||||
private var component: GiftAuctionScreenComponent?
|
||||
private var component: GiftAuctionBidScreenComponent?
|
||||
private weak var state: EmptyComponentState?
|
||||
private var isUpdating: Bool = false
|
||||
private var environment: ViewControllerComponentContainer.Environment?
|
||||
|
|
@ -1369,7 +1369,7 @@ private final class GiftAuctionScreenComponent: Component {
|
|||
})
|
||||
}
|
||||
|
||||
func update(component: GiftAuctionScreenComponent, availableSize: CGSize, state: EmptyComponentState, environment: Environment<ViewControllerComponentContainer.Environment>, transition: ComponentTransition) -> CGSize {
|
||||
func update(component: GiftAuctionBidScreenComponent, availableSize: CGSize, state: EmptyComponentState, environment: Environment<ViewControllerComponentContainer.Environment>, transition: ComponentTransition) -> CGSize {
|
||||
self.isUpdating = true
|
||||
defer {
|
||||
self.isUpdating = false
|
||||
|
|
@ -1880,7 +1880,7 @@ private final class GiftAuctionScreenComponent: Component {
|
|||
guard let self, let component = self.component else {
|
||||
return
|
||||
}
|
||||
let giftController = GiftAuctionBoughtScreen(context: component.context, gift: component.gift, acquiredGifts: self.giftAuctionAcquiredGifts)
|
||||
let giftController = GiftAuctionAcquiredScreen(context: component.context, gift: component.gift, acquiredGifts: self.giftAuctionAcquiredGifts)
|
||||
self.environment?.controller()?.push(giftController)
|
||||
}, animateScale: false)
|
||||
),
|
||||
|
|
@ -2355,7 +2355,7 @@ private final class GiftAuctionScreenComponent: Component {
|
|||
}
|
||||
}
|
||||
|
||||
public class GiftAuctionScreen: ViewControllerComponentContainer {
|
||||
public class GiftAuctionBidScreen: ViewControllerComponentContainer {
|
||||
public final class TransitionOut {
|
||||
public let sourceView: UIView
|
||||
|
||||
|
|
@ -2369,12 +2369,12 @@ public class GiftAuctionScreen: ViewControllerComponentContainer {
|
|||
private var didPlayAppearAnimation: Bool = false
|
||||
private var isDismissed: Bool = false
|
||||
|
||||
public init(context: AccountContext, gift: StarGift, auctionContext: GiftAuctionContext) {
|
||||
public init(context: AccountContext, auctionContext: GiftAuctionContext) {
|
||||
self.context = context
|
||||
|
||||
super.init(context: context, component: GiftAuctionScreenComponent(
|
||||
super.init(context: context, component: GiftAuctionBidScreenComponent(
|
||||
context: context,
|
||||
gift: gift,
|
||||
gift: auctionContext.gift,
|
||||
auctionContext: auctionContext
|
||||
), navigationBarAppearance: .none, theme: .default)
|
||||
|
||||
|
|
@ -2399,7 +2399,7 @@ public class GiftAuctionScreen: ViewControllerComponentContainer {
|
|||
if !self.didPlayAppearAnimation {
|
||||
self.didPlayAppearAnimation = true
|
||||
|
||||
if let componentView = self.node.hostView.componentView as? GiftAuctionScreenComponent.View {
|
||||
if let componentView = self.node.hostView.componentView as? GiftAuctionBidScreenComponent.View {
|
||||
componentView.animateIn()
|
||||
}
|
||||
}
|
||||
|
|
@ -2409,7 +2409,7 @@ public class GiftAuctionScreen: ViewControllerComponentContainer {
|
|||
if !self.isDismissed {
|
||||
self.isDismissed = true
|
||||
|
||||
if let componentView = self.node.hostView.componentView as? GiftAuctionScreenComponent.View {
|
||||
if let componentView = self.node.hostView.componentView as? GiftAuctionBidScreenComponent.View {
|
||||
componentView.animateOut(completion: { [weak self] in
|
||||
completion?()
|
||||
self?.dismiss(animated: false)
|
||||
|
|
@ -0,0 +1,682 @@
|
|||
import Foundation
|
||||
import UIKit
|
||||
import Display
|
||||
import AsyncDisplayKit
|
||||
import Postbox
|
||||
import TelegramCore
|
||||
import SwiftSignalKit
|
||||
import AccountContext
|
||||
import TelegramPresentationData
|
||||
import PresentationDataUtils
|
||||
import ComponentFlow
|
||||
import ViewControllerComponent
|
||||
import SheetComponent
|
||||
import MultilineTextComponent
|
||||
import MultilineTextWithEntitiesComponent
|
||||
import BundleIconComponent
|
||||
import Markdown
|
||||
import BalancedTextComponent
|
||||
import TextFormat
|
||||
import TelegramStringFormatting
|
||||
import StarsAvatarComponent
|
||||
import PlainButtonComponent
|
||||
import TooltipUI
|
||||
import GiftAnimationComponent
|
||||
import ContextUI
|
||||
import GiftItemComponent
|
||||
import GlassBarButtonComponent
|
||||
|
||||
private final class GiftAuctionViewSheetContent: CombinedComponent {
|
||||
typealias EnvironmentType = ViewControllerComponentContainer.Environment
|
||||
|
||||
let context: AccountContext
|
||||
let auctionContext: GiftAuctionContext
|
||||
let animateOut: ActionSlot<Action<()>>
|
||||
let getController: () -> ViewController?
|
||||
|
||||
init(
|
||||
context: AccountContext,
|
||||
auctionContext: GiftAuctionContext,
|
||||
animateOut: ActionSlot<Action<()>>,
|
||||
getController: @escaping () -> ViewController?
|
||||
) {
|
||||
self.context = context
|
||||
self.auctionContext = auctionContext
|
||||
self.animateOut = animateOut
|
||||
self.getController = getController
|
||||
}
|
||||
|
||||
static func ==(lhs: GiftAuctionViewSheetContent, rhs: GiftAuctionViewSheetContent) -> Bool {
|
||||
if lhs.context !== rhs.context {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
final class State: ComponentState {
|
||||
let lastSalePriceTag = GenericComponentViewTag()
|
||||
let floorPriceTag = GenericComponentViewTag()
|
||||
let averagePriceTag = GenericComponentViewTag()
|
||||
|
||||
private let context: AccountContext
|
||||
private let animateOut: ActionSlot<Action<()>>
|
||||
private let getController: () -> ViewController?
|
||||
|
||||
private var disposable: Disposable?
|
||||
var initialized = false
|
||||
|
||||
var cachedStarImage: (UIImage, PresentationTheme)?
|
||||
var cachedSmallStarImage: (UIImage, PresentationTheme)?
|
||||
var cachedSubtitleStarImage: (UIImage, PresentationTheme)?
|
||||
var cachedTonImage: (UIImage, PresentationTheme)?
|
||||
|
||||
var cachedChevronImage: (UIImage, PresentationTheme)?
|
||||
var cachedSmallChevronImage: (UIImage, PresentationTheme)?
|
||||
|
||||
init(
|
||||
context: AccountContext,
|
||||
animateOut: ActionSlot<Action<()>>,
|
||||
getController: @escaping () -> ViewController?
|
||||
) {
|
||||
self.context = context
|
||||
self.animateOut = animateOut
|
||||
self.getController = getController
|
||||
|
||||
super.init()
|
||||
|
||||
// if case let .starGift(gift, _) = component.subject, gift.flags.contains(.isAuction), let giftAuctionsManager = component.context.giftAuctionsManager, let giftAuction = giftAuctionsManager.auctionContext(for: .giftId(gift.id)) {
|
||||
// self.giftAuction = giftAuction
|
||||
// self.giftAuctionDisposable = (giftAuction.state
|
||||
// |> deliverOnMainQueue).start(next: { [weak self] state in
|
||||
// guard let self else {
|
||||
// return
|
||||
// }
|
||||
// self.giftAuctionState = state
|
||||
// self.state?.updated()
|
||||
// })
|
||||
//
|
||||
// self.giftAuctionTimer = SwiftSignalKit.Timer(timeout: 0.5, repeat: true, completion: { [weak self] in
|
||||
// self?.state?.updated()
|
||||
// }, queue: Queue.mainQueue())
|
||||
// self.giftAuctionTimer?.start()
|
||||
// }
|
||||
|
||||
// if let _ = self.giftAuction {
|
||||
// //TODO:localize
|
||||
// let buttonAttributedString = NSMutableAttributedString(string: "Place a Bid", font: Font.semibold(17.0), textColor: environment.theme.list.itemCheckColors.foregroundColor, paragraphAlignment: .center)
|
||||
// buttonTitleItems.append(AnyComponentWithIdentity(id: "bid", component: AnyComponent(
|
||||
// MultilineTextComponent(text: .plain(buttonAttributedString))
|
||||
// )))
|
||||
// if let giftAuctionState = self.giftAuctionState {
|
||||
// switch giftAuctionState.auctionState {
|
||||
// case let .ongoing(_, _, _, _, nextDropDate, _, _, _):
|
||||
// let currentTime = Int32(CFAbsoluteTimeGetCurrent() + kCFAbsoluteTimeIntervalSince1970)
|
||||
// let dropTimeout = nextDropDate - currentTime
|
||||
//
|
||||
// let minutes = Int(dropTimeout / 60)
|
||||
// let seconds = Int(dropTimeout % 60)
|
||||
//
|
||||
// let rawString = environment.strings.Gift_Setup_NextDropIn
|
||||
// var buttonAnimatedTitleItems: [AnimatedTextComponent.Item] = []
|
||||
// var startIndex = rawString.startIndex
|
||||
// while true {
|
||||
// if let range = rawString.range(of: "{", range: startIndex ..< rawString.endIndex) {
|
||||
// if range.lowerBound != startIndex {
|
||||
// buttonAnimatedTitleItems.append(AnimatedTextComponent.Item(id: AnyHashable(buttonAnimatedTitleItems.count), content: .text(String(rawString[startIndex ..< range.lowerBound]))))
|
||||
// }
|
||||
//
|
||||
// startIndex = range.upperBound
|
||||
// if let endRange = rawString.range(of: "}", range: startIndex ..< rawString.endIndex) {
|
||||
// let controlString = rawString[range.upperBound ..< endRange.lowerBound]
|
||||
// if controlString == "m" {
|
||||
// buttonAnimatedTitleItems.append(AnimatedTextComponent.Item(id: AnyHashable(buttonAnimatedTitleItems.count), content: .number(minutes, minDigits: 2)))
|
||||
// } else if controlString == "s" {
|
||||
// buttonAnimatedTitleItems.append(AnimatedTextComponent.Item(id: AnyHashable(buttonAnimatedTitleItems.count), content: .number(seconds, minDigits: 2)))
|
||||
// }
|
||||
//
|
||||
// startIndex = endRange.upperBound
|
||||
// }
|
||||
// } else {
|
||||
// break
|
||||
// }
|
||||
// }
|
||||
// if startIndex != rawString.endIndex {
|
||||
// buttonAnimatedTitleItems.append(AnimatedTextComponent.Item(id: AnyHashable(buttonAnimatedTitleItems.count), content: .text(String(rawString[startIndex ..< rawString.endIndex]))))
|
||||
// }
|
||||
//
|
||||
// buttonTitleItems.append(AnyComponentWithIdentity(id: "timer", component: AnyComponent(AnimatedTextComponent(
|
||||
// font: Font.with(size: 12.0, weight: .medium, traits: .monospacedNumbers),
|
||||
// color: environment.theme.list.itemCheckColors.foregroundColor.withAlphaComponent(0.7),
|
||||
// items: buttonAnimatedTitleItems,
|
||||
// noDelay: true
|
||||
// ))))
|
||||
// case .finished:
|
||||
// buttonIsEnabled = false
|
||||
// }
|
||||
// } else {
|
||||
// buttonIsLoading = true
|
||||
// }
|
||||
// } else {
|
||||
}
|
||||
|
||||
deinit {
|
||||
self.disposable?.dispose()
|
||||
}
|
||||
|
||||
func showAttributeInfo(tag: Any, text: String) {
|
||||
guard let controller = self.getController() as? GiftAuctionViewScreen else {
|
||||
return
|
||||
}
|
||||
controller.dismissAllTooltips()
|
||||
|
||||
guard let sourceView = controller.node.hostView.findTaggedView(tag: tag), let absoluteLocation = sourceView.superview?.convert(sourceView.center, to: controller.view) else {
|
||||
return
|
||||
}
|
||||
|
||||
let location = CGRect(origin: CGPoint(x: absoluteLocation.x, y: absoluteLocation.y - 12.0), size: CGSize())
|
||||
let tooltipController = TooltipScreen(account: self.context.account, sharedContext: self.context.sharedContext, text: .markdown(text: text), style: .wide, location: .point(location, .bottom), displayDuration: .default, inset: 16.0, shouldDismissOnTouch: { _, _ in
|
||||
return .dismiss(consume: false)
|
||||
})
|
||||
controller.present(tooltipController, in: .current)
|
||||
}
|
||||
|
||||
func openGiftResale(gift: StarGift.Gift) {
|
||||
guard let controller = self.getController() as? GiftAuctionViewScreen else {
|
||||
return
|
||||
}
|
||||
let storeController = self.context.sharedContext.makeGiftStoreController(
|
||||
context: self.context,
|
||||
peerId: self.context.account.peerId,
|
||||
gift: gift
|
||||
)
|
||||
controller.push(storeController)
|
||||
}
|
||||
|
||||
func openGiftFragmentResale(url: String) {
|
||||
guard let controller = self.getController() as? GiftAuctionViewScreen, let navigationController = controller.navigationController as? NavigationController else {
|
||||
return
|
||||
}
|
||||
let presentationData = self.context.sharedContext.currentPresentationData.with { $0 }
|
||||
self.context.sharedContext.openExternalUrl(context: self.context, urlContext: .generic, url: url, forceExternal: true, presentationData: presentationData, navigationController: navigationController, dismissInput: {})
|
||||
}
|
||||
|
||||
func dismiss(animated: Bool) {
|
||||
guard let controller = self.getController() as? GiftAuctionViewScreen else {
|
||||
return
|
||||
}
|
||||
if animated {
|
||||
controller.dismissAllTooltips()
|
||||
self.animateOut.invoke(Action { [weak controller] _ in
|
||||
controller?.dismiss(completion: nil)
|
||||
})
|
||||
} else {
|
||||
controller.dismiss(animated: false)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func makeState() -> State {
|
||||
return State(context: self.context, animateOut: self.animateOut, getController: self.getController)
|
||||
}
|
||||
|
||||
static var body: Body {
|
||||
let closeButton = Child(GlassBarButtonComponent.self)
|
||||
let animation = Child(GiftCompositionComponent.self)
|
||||
|
||||
let titleBackground = Child(RoundedRectangle.self)
|
||||
let title = Child(MultilineTextComponent.self)
|
||||
|
||||
let description = Child(MultilineTextComponent.self)
|
||||
|
||||
let table = Child(TableComponent.self)
|
||||
|
||||
// let telegramSaleButton = Child(PlainButtonComponent.self)
|
||||
// let fragmentSaleButton = Child(PlainButtonComponent.self)
|
||||
|
||||
let giftCompositionExternalState = GiftCompositionComponent.ExternalState()
|
||||
|
||||
return { context in
|
||||
let environment = context.environment[ViewControllerComponentContainer.Environment.self].value
|
||||
|
||||
let component = context.component
|
||||
let theme = environment.theme
|
||||
let strings = environment.strings
|
||||
let dateTimeFormat = environment.dateTimeFormat
|
||||
|
||||
let state = context.state
|
||||
|
||||
let sideInset: CGFloat = 16.0 + environment.safeInsets.left
|
||||
|
||||
let titleString: String = "Gift Name"
|
||||
var animationFile: TelegramMediaFile?
|
||||
var giftIconSubject: GiftItemComponent.Subject?
|
||||
var genericGift: StarGift.Gift?
|
||||
|
||||
switch component.auctionContext.gift {
|
||||
case let .generic(gift):
|
||||
animationFile = gift.file
|
||||
giftIconSubject = .starGift(gift: gift, price: "")
|
||||
genericGift = gift
|
||||
default:
|
||||
break
|
||||
}
|
||||
|
||||
let _ = giftIconSubject
|
||||
let _ = genericGift
|
||||
|
||||
var originY: CGFloat = 0.0
|
||||
|
||||
let headerHeight: CGFloat = 210.0
|
||||
let headerSubject: GiftCompositionComponent.Subject?
|
||||
if let animationFile {
|
||||
headerSubject = .generic(animationFile)
|
||||
} else {
|
||||
headerSubject = nil
|
||||
}
|
||||
if let headerSubject {
|
||||
let animation = animation.update(
|
||||
component: GiftCompositionComponent(
|
||||
context: component.context,
|
||||
theme: environment.theme,
|
||||
subject: headerSubject,
|
||||
animationOffset: nil,
|
||||
animationScale: nil,
|
||||
displayAnimationStars: false,
|
||||
externalState: giftCompositionExternalState,
|
||||
requestUpdate: { [weak state] _ in
|
||||
state?.updated()
|
||||
}
|
||||
),
|
||||
availableSize: CGSize(width: context.availableSize.width, height: headerHeight),
|
||||
transition: context.transition
|
||||
)
|
||||
context.add(animation
|
||||
.position(CGPoint(x: context.availableSize.width / 2.0, y: headerHeight / 2.0))
|
||||
)
|
||||
}
|
||||
originY += headerHeight
|
||||
|
||||
let title = title.update(
|
||||
component: MultilineTextComponent(
|
||||
text: .plain(NSAttributedString(
|
||||
string: titleString,
|
||||
font: Font.with(size: 24.0, design: .round, weight: .bold),
|
||||
textColor: theme.list.itemCheckColors.foregroundColor,
|
||||
paragraphAlignment: .center
|
||||
)),
|
||||
horizontalAlignment: .center,
|
||||
maximumNumberOfLines: 1
|
||||
),
|
||||
availableSize: CGSize(width: context.availableSize.width - sideInset * 2.0 - 60.0, height: CGFloat.greatestFiniteMagnitude),
|
||||
transition: .immediate
|
||||
)
|
||||
let titleBackground = titleBackground.update(
|
||||
component: RoundedRectangle(color: theme.actionSheet.controlAccentColor, cornerRadius: 24.0),
|
||||
environment: {},
|
||||
availableSize: CGSize(width: title.size.width + 32.0, height: 48.0),
|
||||
transition: .immediate
|
||||
)
|
||||
context.add(titleBackground
|
||||
.position(CGPoint(x: context.availableSize.width / 2.0, y: 187.0))
|
||||
)
|
||||
context.add(title
|
||||
.position(CGPoint(x: context.availableSize.width / 2.0, y: 187.0))
|
||||
)
|
||||
|
||||
let descriptionText: String = "description"
|
||||
let description = description.update(
|
||||
component: MultilineTextComponent(
|
||||
text: .plain(NSAttributedString(string: descriptionText))
|
||||
),
|
||||
availableSize: CGSize(width: context.availableSize.width - sideInset * 2.0 - 50.0, height: CGFloat.greatestFiniteMagnitude),
|
||||
transition: .immediate
|
||||
)
|
||||
context.add(description
|
||||
.position(CGPoint(x: context.availableSize.width / 2.0, y: 231.0 + description.size.height / 2.0))
|
||||
.appear(.default(alpha: true))
|
||||
.disappear(.default(alpha: true))
|
||||
)
|
||||
originY += description.size.height
|
||||
originY += 42.0
|
||||
|
||||
let tableFont = Font.regular(15.0)
|
||||
let tableTextColor = theme.list.itemPrimaryTextColor
|
||||
|
||||
var tableItems: [TableComponent.Item] = []
|
||||
tableItems.append(.init(
|
||||
id: "firstSale",
|
||||
title: "First Sale",
|
||||
component: AnyComponent(
|
||||
MultilineTextComponent(text: .plain(NSAttributedString(string: stringForMediumDate(timestamp: 0, strings: strings, dateTimeFormat: dateTimeFormat), font: tableFont, textColor: tableTextColor)))
|
||||
)
|
||||
))
|
||||
tableItems.append(.init(
|
||||
id: "lastSale",
|
||||
title: "Last Sale",
|
||||
component: AnyComponent(
|
||||
MultilineTextComponent(text: .plain(NSAttributedString(string: stringForMediumDate(timestamp: 0, strings: strings, dateTimeFormat: dateTimeFormat), font: tableFont, textColor: tableTextColor)))
|
||||
)
|
||||
))
|
||||
|
||||
let table = table.update(
|
||||
component: TableComponent(
|
||||
theme: environment.theme,
|
||||
items: tableItems
|
||||
),
|
||||
availableSize: CGSize(width: context.availableSize.width - sideInset * 2.0, height: .greatestFiniteMagnitude),
|
||||
transition: context.transition
|
||||
)
|
||||
context.add(table
|
||||
.position(CGPoint(x: context.availableSize.width / 2.0, y: originY + table.size.height / 2.0))
|
||||
.appear(.default(alpha: true))
|
||||
.disappear(.default(alpha: true))
|
||||
)
|
||||
originY += table.size.height + 23.0
|
||||
|
||||
// if component.valueInfo.listedCount != nil || component.valueInfo.fragmentListedCount != nil {
|
||||
// originY += 5.0
|
||||
// }
|
||||
//
|
||||
// if let listedCount = component.valueInfo.listedCount, let giftIconSubject {
|
||||
// let telegramSaleButton = telegramSaleButton.update(
|
||||
// component: PlainButtonComponent(
|
||||
// content: AnyComponent(
|
||||
// HStack([
|
||||
// AnyComponentWithIdentity(id: "count", component: AnyComponent(
|
||||
// MultilineTextComponent(text: .plain(NSAttributedString(string: presentationStringsFormattedNumber(listedCount, dateTimeFormat.groupingSeparator), font: Font.regular(17.0), textColor: theme.actionSheet.controlAccentColor)))
|
||||
// )),
|
||||
// AnyComponentWithIdentity(id: "spacing", component: AnyComponent(
|
||||
// Rectangle(color: .clear, width: 8.0, height: 1.0)
|
||||
// )),
|
||||
// AnyComponentWithIdentity(id: "icon", component: AnyComponent(
|
||||
// GiftItemComponent(
|
||||
// context: component.context,
|
||||
// theme: theme,
|
||||
// strings: strings,
|
||||
// peer: nil,
|
||||
// subject: giftIconSubject,
|
||||
// mode: .buttonIcon
|
||||
// )
|
||||
// )),
|
||||
// AnyComponentWithIdentity(id: "label", component: AnyComponent(
|
||||
// MultilineTextComponent(text: .plain(NSAttributedString(string: " \(strings.Gift_Value_ForSaleOnTelegram)", font: Font.regular(17.0), textColor: theme.actionSheet.controlAccentColor)))
|
||||
// )),
|
||||
// AnyComponentWithIdentity(id: "arrow", component: AnyComponent(
|
||||
// BundleIconComponent(name: "Chat/Context Menu/Arrow", tintColor: theme.actionSheet.controlAccentColor)
|
||||
// ))
|
||||
// ], spacing: 0.0)
|
||||
// ),
|
||||
// action: { [weak state] in
|
||||
// guard let state, let genericGift else {
|
||||
// return
|
||||
// }
|
||||
// state.openGiftResale(gift: genericGift)
|
||||
// },
|
||||
// animateScale: false
|
||||
// ),
|
||||
// environment: {},
|
||||
// availableSize: context.availableSize,
|
||||
// transition: .immediate
|
||||
// )
|
||||
// context.add(telegramSaleButton
|
||||
// .position(CGPoint(x: context.availableSize.width / 2.0, y: originY + telegramSaleButton.size.height / 2.0))
|
||||
// )
|
||||
// originY += telegramSaleButton.size.height
|
||||
// originY += 12.0
|
||||
// }
|
||||
//
|
||||
// if let listedCount = component.valueInfo.fragmentListedCount, let fragmentListedUrl = component.valueInfo.fragmentListedUrl, let giftIconSubject {
|
||||
// if component.valueInfo.listedCount != nil {
|
||||
// originY += 18.0
|
||||
// }
|
||||
//
|
||||
// let fragmentSaleButton = fragmentSaleButton.update(
|
||||
// component: PlainButtonComponent(
|
||||
// content: AnyComponent(
|
||||
// HStack([
|
||||
// AnyComponentWithIdentity(id: "count", component: AnyComponent(
|
||||
// MultilineTextComponent(text: .plain(NSAttributedString(string: presentationStringsFormattedNumber(listedCount, dateTimeFormat.groupingSeparator), font: Font.regular(17.0), textColor: theme.actionSheet.controlAccentColor)))
|
||||
// )),
|
||||
// AnyComponentWithIdentity(id: "spacing", component: AnyComponent(
|
||||
// Rectangle(color: .clear, width: 8.0, height: 1.0)
|
||||
// )),
|
||||
// AnyComponentWithIdentity(id: "icon", component: AnyComponent(
|
||||
// GiftItemComponent(
|
||||
// context: component.context,
|
||||
// theme: theme,
|
||||
// strings: strings,
|
||||
// peer: nil,
|
||||
// subject: giftIconSubject,
|
||||
// mode: .buttonIcon
|
||||
// )
|
||||
// )),
|
||||
// AnyComponentWithIdentity(id: "label", component: AnyComponent(
|
||||
// MultilineTextComponent(text: .plain(NSAttributedString(string: " \(strings.Gift_Value_ForSaleOnFragment)", font: Font.regular(17.0), textColor: theme.actionSheet.controlAccentColor)))
|
||||
// )),
|
||||
// AnyComponentWithIdentity(id: "arrow", component: AnyComponent(
|
||||
// BundleIconComponent(name: "Chat/Context Menu/Arrow", tintColor: theme.actionSheet.controlAccentColor)
|
||||
// ))
|
||||
// ], spacing: 0.0)
|
||||
// ),
|
||||
// action: { [weak state] in
|
||||
// state?.openGiftFragmentResale(url: fragmentListedUrl)
|
||||
// },
|
||||
// animateScale: false
|
||||
// ),
|
||||
// environment: {},
|
||||
// availableSize: context.availableSize,
|
||||
// transition: .immediate
|
||||
// )
|
||||
// context.add(fragmentSaleButton
|
||||
// .position(CGPoint(x: context.availableSize.width / 2.0, y: originY + fragmentSaleButton.size.height / 2.0))
|
||||
// )
|
||||
// originY += fragmentSaleButton.size.height
|
||||
// originY += 12.0
|
||||
// }
|
||||
|
||||
let closeButton = closeButton.update(
|
||||
component: GlassBarButtonComponent(
|
||||
size: CGSize(width: 40.0, height: 40.0),
|
||||
backgroundColor: theme.rootController.navigationBar.glassBarButtonBackgroundColor,
|
||||
isDark: theme.overallDarkAppearance,
|
||||
state: .generic,
|
||||
component: AnyComponentWithIdentity(id: "close", component: AnyComponent(
|
||||
BundleIconComponent(
|
||||
name: "Navigation/Close",
|
||||
tintColor: theme.rootController.navigationBar.glassBarButtonForegroundColor
|
||||
)
|
||||
)),
|
||||
action: { [weak state] _ in
|
||||
guard let state else {
|
||||
return
|
||||
}
|
||||
state.dismiss(animated: true)
|
||||
}
|
||||
),
|
||||
availableSize: CGSize(width: 40.0, height: 40.0),
|
||||
transition: .immediate
|
||||
)
|
||||
context.add(closeButton
|
||||
.position(CGPoint(x: 16.0 + closeButton.size.width / 2.0, y: 16.0 + closeButton.size.height / 2.0))
|
||||
)
|
||||
|
||||
let effectiveBottomInset: CGFloat = environment.metrics.isTablet ? 0.0 : environment.safeInsets.bottom
|
||||
return CGSize(width: context.availableSize.width, height: originY + 5.0 + effectiveBottomInset)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
final class GiftAuctionViewSheetComponent: CombinedComponent {
|
||||
typealias EnvironmentType = ViewControllerComponentContainer.Environment
|
||||
|
||||
let context: AccountContext
|
||||
let auctionContext: GiftAuctionContext
|
||||
|
||||
init(
|
||||
context: AccountContext,
|
||||
auctionContext: GiftAuctionContext
|
||||
) {
|
||||
self.context = context
|
||||
self.auctionContext = auctionContext
|
||||
}
|
||||
|
||||
static func ==(lhs: GiftAuctionViewSheetComponent, rhs: GiftAuctionViewSheetComponent) -> Bool {
|
||||
if lhs.context !== rhs.context {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
static var body: Body {
|
||||
let sheet = Child(SheetComponent<EnvironmentType>.self)
|
||||
let animateOut = StoredActionSlot(Action<Void>.self)
|
||||
|
||||
let sheetExternalState = SheetComponent<EnvironmentType>.ExternalState()
|
||||
|
||||
return { context in
|
||||
let environment = context.environment[EnvironmentType.self]
|
||||
let controller = environment.controller
|
||||
|
||||
let sheet = sheet.update(
|
||||
component: SheetComponent<EnvironmentType>(
|
||||
content: AnyComponent<EnvironmentType>(GiftAuctionViewSheetContent(
|
||||
context: context.component.context,
|
||||
auctionContext: context.component.auctionContext,
|
||||
animateOut: animateOut,
|
||||
getController: controller
|
||||
)),
|
||||
style: .glass,
|
||||
backgroundColor: .color(environment.theme.actionSheet.opaqueItemBackgroundColor),
|
||||
followContentSizeChanges: true,
|
||||
clipsContent: true,
|
||||
autoAnimateOut: false,
|
||||
externalState: sheetExternalState,
|
||||
animateOut: animateOut,
|
||||
onPan: {
|
||||
if let controller = controller() as? GiftAuctionViewScreen {
|
||||
controller.dismissAllTooltips()
|
||||
}
|
||||
},
|
||||
willDismiss: {
|
||||
}
|
||||
),
|
||||
environment: {
|
||||
environment
|
||||
SheetComponentEnvironment(
|
||||
isDisplaying: environment.value.isVisible,
|
||||
isCentered: environment.metrics.widthClass == .regular,
|
||||
hasInputHeight: !environment.inputHeight.isZero,
|
||||
regularMetricsSize: CGSize(width: 430.0, height: 900.0),
|
||||
dismiss: { animated in
|
||||
if animated {
|
||||
if let controller = controller() as? GiftAuctionViewScreen {
|
||||
controller.dismissAllTooltips()
|
||||
animateOut.invoke(Action { _ in
|
||||
controller.dismiss(completion: nil)
|
||||
})
|
||||
}
|
||||
} else {
|
||||
if let controller = controller() as? GiftAuctionViewScreen {
|
||||
controller.dismissAllTooltips()
|
||||
controller.dismiss(completion: nil)
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
},
|
||||
availableSize: context.availableSize,
|
||||
transition: context.transition
|
||||
)
|
||||
|
||||
context.add(sheet
|
||||
.position(CGPoint(x: context.availableSize.width / 2.0, y: context.availableSize.height / 2.0))
|
||||
)
|
||||
|
||||
if let controller = controller(), !controller.automaticallyControlPresentationContextLayout {
|
||||
var sideInset: CGFloat = 0.0
|
||||
var bottomInset: CGFloat = max(environment.safeInsets.bottom, sheetExternalState.contentHeight)
|
||||
if case .regular = environment.metrics.widthClass {
|
||||
sideInset = floor((context.availableSize.width - 430.0) / 2.0) - 12.0
|
||||
bottomInset = (context.availableSize.height - sheetExternalState.contentHeight) / 2.0 + sheetExternalState.contentHeight
|
||||
}
|
||||
|
||||
let layout = ContainerViewLayout(
|
||||
size: context.availableSize,
|
||||
metrics: environment.metrics,
|
||||
deviceMetrics: environment.deviceMetrics,
|
||||
intrinsicInsets: UIEdgeInsets(top: 0.0, left: 0.0, bottom: bottomInset, right: 0.0),
|
||||
safeInsets: UIEdgeInsets(top: 0.0, left: max(sideInset, environment.safeInsets.left), bottom: 0.0, right: max(sideInset, environment.safeInsets.right)),
|
||||
additionalInsets: .zero,
|
||||
statusBarHeight: environment.statusBarHeight,
|
||||
inputHeight: nil,
|
||||
inputHeightIsInteractivellyChanging: false,
|
||||
inVoiceOver: false
|
||||
)
|
||||
controller.presentationContext.containerLayoutUpdated(layout, transition: context.transition.containedViewLayoutTransition)
|
||||
}
|
||||
|
||||
return context.availableSize
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public final class GiftAuctionViewScreen: ViewControllerComponentContainer {
|
||||
public init(
|
||||
context: AccountContext,
|
||||
auctionContext: GiftAuctionContext
|
||||
) {
|
||||
super.init(
|
||||
context: context,
|
||||
component: GiftAuctionViewSheetComponent(
|
||||
context: context,
|
||||
auctionContext: auctionContext
|
||||
),
|
||||
navigationBarAppearance: .none,
|
||||
statusBarStyle: .ignore,
|
||||
theme: .default
|
||||
)
|
||||
|
||||
self.navigationPresentation = .flatModal
|
||||
self.automaticallyControlPresentationContextLayout = false
|
||||
}
|
||||
|
||||
required public init(coder aDecoder: NSCoder) {
|
||||
fatalError("init(coder:) has not been implemented")
|
||||
}
|
||||
|
||||
deinit {
|
||||
}
|
||||
|
||||
public override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
|
||||
self.view.disablesInteractiveModalDismiss = true
|
||||
}
|
||||
|
||||
public override func viewWillDisappear(_ animated: Bool) {
|
||||
super.viewWillDisappear(animated)
|
||||
self.dismissAllTooltips()
|
||||
}
|
||||
|
||||
public func dismissAnimated() {
|
||||
self.dismissAllTooltips()
|
||||
|
||||
if let view = self.node.hostView.findTaggedView(tag: SheetComponent<ViewControllerComponentContainer.Environment>.View.Tag()) as? SheetComponent<ViewControllerComponentContainer.Environment>.View {
|
||||
view.dismissAnimated()
|
||||
}
|
||||
}
|
||||
|
||||
fileprivate func dismissAllTooltips() {
|
||||
self.window?.forEachController({ controller in
|
||||
if let controller = controller as? TooltipScreen {
|
||||
controller.dismiss(inPlace: false)
|
||||
}
|
||||
})
|
||||
self.forEachController({ controller in
|
||||
if let controller = controller as? TooltipScreen {
|
||||
controller.dismiss(inPlace: false)
|
||||
}
|
||||
return true
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
@ -348,7 +348,10 @@ private final class StarsPurchaseScreenContentComponent: CombinedComponent {
|
|||
let backgroundComponent: AnyComponent<Empty>?
|
||||
if product.storeProduct.id == context.component.selectedProductId {
|
||||
backgroundComponent = AnyComponent(
|
||||
ItemShimmeringLoadingComponent(color: environment.theme.list.itemAccentColor)
|
||||
ItemShimmeringLoadingComponent(
|
||||
color: environment.theme.list.itemAccentColor,
|
||||
cornerRadius: 26.0
|
||||
)
|
||||
)
|
||||
} else {
|
||||
backgroundComponent = nil
|
||||
|
|
|
|||
|
|
@ -3846,8 +3846,12 @@ public final class SharedAccountContextImpl: SharedAccountContext {
|
|||
return GiftAuctionInfoScreen(context: context, gift: gift, completion: completion)
|
||||
}
|
||||
|
||||
public func makeGiftAuctionScreen(context: AccountContext, gift: StarGift, auctionContext: GiftAuctionContext) -> ViewController {
|
||||
return GiftAuctionScreen(context: context, gift: gift, auctionContext: auctionContext)
|
||||
public func makeGiftAuctionBidScreen(context: AccountContext, auctionContext: GiftAuctionContext) -> ViewController {
|
||||
return GiftAuctionBidScreen(context: context, auctionContext: auctionContext)
|
||||
}
|
||||
|
||||
public func makeGiftAuctionViewScreen(context: AccountContext, auctionContext: GiftAuctionContext) -> ViewController {
|
||||
return GiftAuctionViewScreen(context: context, auctionContext: auctionContext)
|
||||
}
|
||||
|
||||
public func makeStorySharingScreen(context: AccountContext, subject: StorySharingSubject, parentController: ViewController) -> ViewController {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue