Various fixes

This commit is contained in:
Ilya Laktyushin 2025-05-03 05:54:09 +04:00
parent 60aef02fa5
commit c04e8f3c11
5 changed files with 100 additions and 83 deletions

View File

@ -2438,6 +2438,7 @@ private final class ResaleGiftsContextImpl {
private var gifts: [StarGift] = [] private var gifts: [StarGift] = []
private var attributes: [StarGift.UniqueGift.Attribute] = [] private var attributes: [StarGift.UniqueGift.Attribute] = []
private var attributeCount: [ResaleGiftsContext.Attribute: Int32] = [:] private var attributeCount: [ResaleGiftsContext.Attribute: Int32] = [:]
private var attributesHash: Int64?
private var count: Int32? private var count: Int32?
private var dataState: ResaleGiftsContext.State.DataState = .ready(canLoadMore: true, nextOffset: nil) private var dataState: ResaleGiftsContext.State.DataState = .ready(canLoadMore: true, nextOffset: nil)
@ -2477,6 +2478,7 @@ private final class ResaleGiftsContextImpl {
let postbox = self.account.postbox let postbox = self.account.postbox
let sorting = self.sorting let sorting = self.sorting
let filterAttributes = self.filterAttributes let filterAttributes = self.filterAttributes
let currentAttributesHash = self.attributesHash
let dataState = self.dataState let dataState = self.dataState
@ -2511,46 +2513,45 @@ private final class ResaleGiftsContextImpl {
} }
} }
var attributesHash: Int64? let attributesHash = currentAttributesHash ?? 0
if "".isEmpty { flags |= (1 << 0)
flags |= (1 << 0)
attributesHash = 0
}
let signal = network.request(Api.functions.payments.getResaleStarGifts(flags: flags, attributesHash: attributesHash, giftId: giftId, attributes: apiAttributes, offset: initialNextOffset ?? "", limit: 36)) let signal = network.request(Api.functions.payments.getResaleStarGifts(flags: flags, attributesHash: attributesHash, giftId: giftId, attributes: apiAttributes, offset: initialNextOffset ?? "", limit: 36))
|> map(Optional.init) |> map(Optional.init)
|> `catch` { _ -> Signal<Api.payments.ResaleStarGifts?, NoError> in |> `catch` { _ -> Signal<Api.payments.ResaleStarGifts?, NoError> in
return .single(nil) return .single(nil)
} }
|> mapToSignal { result -> Signal<([StarGift], [StarGift.UniqueGift.Attribute], [ResaleGiftsContext.Attribute: Int32], Int32, String?), NoError> in |> mapToSignal { result -> Signal<([StarGift], [StarGift.UniqueGift.Attribute]?, [ResaleGiftsContext.Attribute: Int32]?, Int64?, Int32, String?), NoError> in
guard let result else { guard let result else {
return .single(([], [], [:], 0, nil)) return .single(([], nil, nil, nil, 0, nil))
} }
return postbox.transaction { transaction -> ([StarGift], [StarGift.UniqueGift.Attribute], [ResaleGiftsContext.Attribute: Int32], Int32, String?) in return postbox.transaction { transaction -> ([StarGift], [StarGift.UniqueGift.Attribute]?, [ResaleGiftsContext.Attribute: Int32]?, Int64?, Int32, String?) in
switch result { switch result {
case let .resaleStarGifts(_, count, gifts, nextOffset, attributes, attributesHash, chats, counters, users): case let .resaleStarGifts(_, count, gifts, nextOffset, attributes, attributesHash, chats, counters, users):
let _ = attributesHash let _ = attributesHash
var resultAttributes: [StarGift.UniqueGift.Attribute] = [] var resultAttributes: [StarGift.UniqueGift.Attribute]?
if let attributes { if let attributes {
resultAttributes = attributes.compactMap { StarGift.UniqueGift.Attribute(apiAttribute: $0) } resultAttributes = attributes.compactMap { StarGift.UniqueGift.Attribute(apiAttribute: $0) }
} }
var attributeCount: [ResaleGiftsContext.Attribute: Int32] = [:] var attributeCount: [ResaleGiftsContext.Attribute: Int32]?
if let counters { if let counters {
var attributeCountValue: [ResaleGiftsContext.Attribute: Int32] = [:]
for counter in counters { for counter in counters {
switch counter { switch counter {
case let .starGiftAttributeCounter(attribute, count): case let .starGiftAttributeCounter(attribute, count):
switch attribute { switch attribute {
case let .starGiftAttributeIdModel(documentId): case let .starGiftAttributeIdModel(documentId):
attributeCount[.model(documentId)] = count attributeCountValue[.model(documentId)] = count
case let .starGiftAttributeIdPattern(documentId): case let .starGiftAttributeIdPattern(documentId):
attributeCount[.pattern(documentId)] = count attributeCountValue[.pattern(documentId)] = count
case let .starGiftAttributeIdBackdrop(backdropId): case let .starGiftAttributeIdBackdrop(backdropId):
attributeCount[.backdrop(backdropId)] = count attributeCountValue[.backdrop(backdropId)] = count
} }
} }
} }
attributeCount = attributeCountValue
} }
let parsedPeers = AccumulatedPeers(transaction: transaction, chats: chats, users: users) let parsedPeers = AccumulatedPeers(transaction: transaction, chats: chats, users: users)
@ -2563,13 +2564,13 @@ private final class ResaleGiftsContextImpl {
} }
} }
return (mappedGifts, resultAttributes, attributeCount, count, nextOffset) return (mappedGifts, resultAttributes, attributeCount, attributesHash, count, nextOffset)
} }
} }
} }
self.disposable.set((signal self.disposable.set((signal
|> deliverOn(self.queue)).start(next: { [weak self] (gifts, attributes, attributeCount, count, nextOffset) in |> deliverOn(self.queue)).start(next: { [weak self] (gifts, attributes, attributeCount, attributesHash, count, nextOffset) in
guard let self else { guard let self else {
return return
} }
@ -2581,10 +2582,13 @@ private final class ResaleGiftsContextImpl {
let updatedCount = max(Int32(self.gifts.count), count) let updatedCount = max(Int32(self.gifts.count), count)
self.count = updatedCount self.count = updatedCount
self.attributes = attributes
if !attributeCount.isEmpty { if let attributes, let attributeCount, let attributesHash {
self.attributes = attributes
self.attributeCount = attributeCount self.attributeCount = attributeCount
self.attributesHash = attributesHash
} }
self.dataState = .ready(canLoadMore: count != 0 && updatedCount > self.gifts.count && nextOffset != nil, nextOffset: nextOffset) self.dataState = .ready(canLoadMore: count != 0 && updatedCount > self.gifts.count && nextOffset != nil, nextOffset: nextOffset)
self.pushState() self.pushState()

View File

@ -458,9 +458,13 @@ final class GiftOptionsScreenComponent: Component {
mainController.push(giftController) mainController.push(giftController)
} }
} else { } else {
var forceUnique = false var forceUnique: Bool?
if let disallowedGifts = self.state?.disallowedGifts, disallowedGifts.contains(.limited) && !disallowedGifts.contains(.unique) { if let disallowedGifts = self.state?.disallowedGifts {
forceUnique = true if disallowedGifts.contains(.limited) && !disallowedGifts.contains(.unique) {
forceUnique = true
} else if !disallowedGifts.contains(.limited) && disallowedGifts.contains(.unique) {
forceUnique = false
}
} }
let giftController = GiftSetupScreen( let giftController = GiftSetupScreen(

View File

@ -788,57 +788,60 @@ final class GiftSetupScreenComponent: Component {
contentHeight += sectionSpacing contentHeight += sectionSpacing
} }
if case let .starGift(starGift, _) = component.subject, let availability = starGift.availability, availability.resale > 0 { if case let .starGift(starGift, forceUnique) = component.subject, let availability = starGift.availability, availability.resale > 0 {
let resaleSectionSize = self.resaleSection.update( if let forceUnique, !forceUnique {
transition: transition, } else {
component: AnyComponent(ListSectionComponent( let resaleSectionSize = self.resaleSection.update(
theme: environment.theme, transition: transition,
header: nil, component: AnyComponent(ListSectionComponent(
footer: nil, theme: environment.theme,
items: [ header: nil,
AnyComponentWithIdentity(id: 0, component: AnyComponent(ListActionItemComponent( footer: nil,
theme: environment.theme, items: [
title: AnyComponent(VStack([ AnyComponentWithIdentity(id: 0, component: AnyComponent(ListActionItemComponent(
AnyComponentWithIdentity(id: AnyHashable(0), component: AnyComponent( theme: environment.theme,
MultilineTextComponent( title: AnyComponent(VStack([
text: .plain(NSAttributedString(string: environment.strings.Gift_Send_AvailableForResale, font: Font.regular(presentationData.listsFontSize.baseDisplaySize), textColor: environment.theme.list.itemPrimaryTextColor)) AnyComponentWithIdentity(id: AnyHashable(0), component: AnyComponent(
MultilineTextComponent(
text: .plain(NSAttributedString(string: environment.strings.Gift_Send_AvailableForResale, font: Font.regular(presentationData.listsFontSize.baseDisplaySize), textColor: environment.theme.list.itemPrimaryTextColor))
)
)),
], alignment: .left, spacing: 2.0)),
accessory: .custom(ListActionItemComponent.CustomAccessory(component: AnyComponentWithIdentity(id: 0, component: AnyComponent(MultilineTextComponent(
text: .plain(NSAttributedString(
string: presentationStringsFormattedNumber(Int32(availability.resale), environment.dateTimeFormat.groupingSeparator),
font: Font.regular(presentationData.listsFontSize.baseDisplaySize),
textColor: environment.theme.list.itemSecondaryTextColor
)),
maximumNumberOfLines: 0
))), insets: UIEdgeInsets(top: 0.0, left: 0.0, bottom: 0.0, right: 16.0))),
action: { [weak self] _ in
guard let self, let component = self.component, let controller = environment.controller() else {
return
}
let storeController = component.context.sharedContext.makeGiftStoreController(
context: component.context,
peerId: component.peerId,
gift: starGift
) )
)), controller.push(storeController)
], alignment: .left, spacing: 2.0)),
accessory: .custom(ListActionItemComponent.CustomAccessory(component: AnyComponentWithIdentity(id: 0, component: AnyComponent(MultilineTextComponent(
text: .plain(NSAttributedString(
string: presentationStringsFormattedNumber(Int32(availability.resale), environment.dateTimeFormat.groupingSeparator),
font: Font.regular(presentationData.listsFontSize.baseDisplaySize),
textColor: environment.theme.list.itemSecondaryTextColor
)),
maximumNumberOfLines: 0
))), insets: UIEdgeInsets(top: 0.0, left: 0.0, bottom: 0.0, right: 16.0))),
action: { [weak self] _ in
guard let self, let component = self.component, let controller = environment.controller() else {
return
} }
let storeController = component.context.sharedContext.makeGiftStoreController( )))
context: component.context, ]
peerId: component.peerId, )),
gift: starGift environment: {},
) containerSize: CGSize(width: availableSize.width - sideInset * 2.0, height: 10000.0)
controller.push(storeController) )
} let resaleSectionFrame = CGRect(origin: CGPoint(x: sideInset, y: contentHeight), size: resaleSectionSize)
))) if let resaleSectionView = self.resaleSection.view {
] if resaleSectionView.superview == nil {
)), self.scrollView.addSubview(resaleSectionView)
environment: {}, }
containerSize: CGSize(width: availableSize.width - sideInset * 2.0, height: 10000.0) transition.setFrame(view: resaleSectionView, frame: resaleSectionFrame)
)
let resaleSectionFrame = CGRect(origin: CGPoint(x: sideInset, y: contentHeight), size: resaleSectionSize)
if let resaleSectionView = self.resaleSection.view {
if resaleSectionView.superview == nil {
self.scrollView.addSubview(resaleSectionView)
} }
transition.setFrame(view: resaleSectionView, frame: resaleSectionFrame) contentHeight += resaleSectionSize.height
contentHeight += sectionSpacing
} }
contentHeight += resaleSectionSize.height
contentHeight += sectionSpacing
} }
let giftConfiguration = GiftConfiguration.with(appConfiguration: component.context.currentAppConfiguration.with { $0 }) let giftConfiguration = GiftConfiguration.with(appConfiguration: component.context.currentAppConfiguration.with { $0 })
@ -1128,7 +1131,7 @@ final class GiftSetupScreenComponent: Component {
if isChannelGift { if isChannelGift {
upgradeFooterRawString = environment.strings.Gift_SendChannel_Upgrade_Info(peerName).string upgradeFooterRawString = environment.strings.Gift_SendChannel_Upgrade_Info(peerName).string
} else { } else {
if forceUnique { if forceUnique == true {
upgradeFooterRawString = environment.strings.Gift_Send_Upgrade_ForcedInfo(peerName).string upgradeFooterRawString = environment.strings.Gift_Send_Upgrade_ForcedInfo(peerName).string
} else { } else {
upgradeFooterRawString = environment.strings.Gift_Send_Upgrade_Info(peerName).string upgradeFooterRawString = environment.strings.Gift_Send_Upgrade_Info(peerName).string
@ -1201,8 +1204,8 @@ final class GiftSetupScreenComponent: Component {
) )
)), )),
], alignment: .left, spacing: 2.0)), ], alignment: .left, spacing: 2.0)),
accessory: .toggle(ListActionItemComponent.Toggle(style: .regular, isOn: self.includeUpgrade, isEnabled: !forceUnique, action: { [weak self] _ in accessory: .toggle(ListActionItemComponent.Toggle(style: .regular, isOn: self.includeUpgrade, isEnabled: forceUnique != true, action: { [weak self] _ in
guard let self, !forceUnique else { guard let self, forceUnique != true else {
return return
} }
self.includeUpgrade = !self.includeUpgrade self.includeUpgrade = !self.includeUpgrade
@ -1748,7 +1751,7 @@ final class GiftSetupScreenComponent: Component {
public final class GiftSetupScreen: ViewControllerComponentContainer { public final class GiftSetupScreen: ViewControllerComponentContainer {
public enum Subject: Equatable { public enum Subject: Equatable {
case premium(PremiumGiftProduct) case premium(PremiumGiftProduct)
case starGift(StarGift.Gift, Bool) case starGift(StarGift.Gift, Bool?)
} }
private let context: AccountContext private let context: AccountContext

View File

@ -789,6 +789,11 @@ final class GiftStoreScreenComponent: Component {
} }
self.component = component self.component = component
var isLoading = false
if self.state?.starGiftsState?.gifts == nil || self.state?.starGiftsState?.dataState == .loading {
isLoading = true
}
let theme = environment.theme let theme = environment.theme
let strings = environment.strings let strings = environment.strings
@ -887,6 +892,10 @@ final class GiftStoreScreenComponent: Component {
balanceIconView.bounds = CGRect(origin: .zero, size: balanceIconSize) balanceIconView.bounds = CGRect(origin: .zero, size: balanceIconSize)
} }
var topInset: CGFloat = 0.0
if environment.statusBarHeight > 0.0 {
topInset = environment.statusBarHeight - 6.0
}
let titleSize = self.title.update( let titleSize = self.title.update(
transition: transition, transition: transition,
component: AnyComponent(MultilineTextComponent( component: AnyComponent(MultilineTextComponent(
@ -900,7 +909,7 @@ final class GiftStoreScreenComponent: Component {
if titleView.superview == nil { if titleView.superview == nil {
self.addSubview(titleView) self.addSubview(titleView)
} }
transition.setFrame(view: titleView, frame: CGRect(origin: CGPoint(x: floor((availableSize.width - titleSize.width) / 2.0), y: 10.0), size: titleSize)) transition.setFrame(view: titleView, frame: CGRect(origin: CGPoint(x: floor((availableSize.width - titleSize.width) / 2.0), y: topInset + 10.0), size: titleSize))
} }
let effectiveCount: Int32 let effectiveCount: Int32
@ -922,7 +931,7 @@ final class GiftStoreScreenComponent: Component {
environment: {}, environment: {},
containerSize: CGSize(width: availableSize.width - headerSideInset * 2.0, height: 100.0) containerSize: CGSize(width: availableSize.width - headerSideInset * 2.0, height: 100.0)
) )
let subtitleFrame = CGRect(origin: CGPoint(x: floor((availableSize.width - subtitleSize.width) / 2.0), y: 31.0), size: subtitleSize) let subtitleFrame = CGRect(origin: CGPoint(x: floor((availableSize.width - subtitleSize.width) / 2.0), y: topInset + 31.0), size: subtitleSize)
if let subtitleView = self.subtitle.view { if let subtitleView = self.subtitle.view {
if subtitleView.superview == nil { if subtitleView.superview == nil {
self.addSubview(subtitleView) self.addSubview(subtitleView)
@ -984,10 +993,10 @@ final class GiftStoreScreenComponent: Component {
modelTitle = environment.strings.Gift_Store_Filter_Selected_Model(modelCount) modelTitle = environment.strings.Gift_Store_Filter_Selected_Model(modelCount)
} }
if backdropCount > 0 { if backdropCount > 0 {
backdropTitle = environment.strings.Gift_Store_Filter_Selected_Backdrop(modelCount) backdropTitle = environment.strings.Gift_Store_Filter_Selected_Backdrop(backdropCount)
} }
if symbolCount > 0 { if symbolCount > 0 {
symbolTitle = environment.strings.Gift_Store_Filter_Selected_Symbol(modelCount) symbolTitle = environment.strings.Gift_Store_Filter_Selected_Symbol(symbolCount)
} }
} }
@ -1036,7 +1045,7 @@ final class GiftStoreScreenComponent: Component {
if filterSelectorView.superview == nil { if filterSelectorView.superview == nil {
self.addSubview(filterSelectorView) self.addSubview(filterSelectorView)
} }
transition.setFrame(view: filterSelectorView, frame: CGRect(origin: CGPoint(x: floor((availableSize.width - filterSize.width) / 2.0), y: 56.0), size: filterSize)) transition.setFrame(view: filterSelectorView, frame: CGRect(origin: CGPoint(x: floor((availableSize.width - filterSize.width) / 2.0), y: topInset + 56.0), size: filterSize))
} }
if let starGifts = self.state?.starGiftsState?.gifts { if let starGifts = self.state?.starGiftsState?.gifts {
@ -1078,12 +1087,7 @@ final class GiftStoreScreenComponent: Component {
self.topOverscrollLayer.frame = CGRect(origin: CGPoint(x: 0.0, y: -3000.0), size: CGSize(width: availableSize.width, height: 3000.0)) self.topOverscrollLayer.frame = CGRect(origin: CGPoint(x: 0.0, y: -3000.0), size: CGSize(width: availableSize.width, height: 3000.0))
self.updateScrolling(transition: transition) self.updateScrolling(transition: transition)
var isLoading = false
if self.state?.starGiftsState?.gifts == nil || self.state?.starGiftsState?.dataState == .loading {
isLoading = true
}
let loadingTransition: ComponentTransition = .easeInOut(duration: 0.25) let loadingTransition: ComponentTransition = .easeInOut(duration: 0.25)
if isLoading { if isLoading {
self.loadingNode.update(size: availableSize, theme: environment.theme, transition: .immediate) self.loadingNode.update(size: availableSize, theme: environment.theme, transition: .immediate)

View File

@ -805,6 +805,7 @@ private final class GiftViewSheetContent: CombinedComponent {
default: default:
break break
} }
self.updated(transition: .easeInOut(duration: 0.2))
let text = presentationData.strings.Gift_View_Resale_Unlist_Success(giftTitle).string let text = presentationData.strings.Gift_View_Resale_Unlist_Success(giftTitle).string
let tooltipController = UndoOverlayController( let tooltipController = UndoOverlayController(
@ -880,7 +881,8 @@ private final class GiftViewSheetContent: CombinedComponent {
default: default:
break break
} }
self.updated(transition: .easeInOut(duration: 0.2))
var text = presentationData.strings.Gift_View_Resale_List_Success(giftTitle).string var text = presentationData.strings.Gift_View_Resale_List_Success(giftTitle).string
if update { if update {
let starsString = presentationData.strings.Gift_View_Resale_Relist_Success_Stars(Int32(price)) let starsString = presentationData.strings.Gift_View_Resale_Relist_Success_Stars(Int32(price))