Giveaway improvements

This commit is contained in:
Ilya Laktyushin 2023-10-22 16:48:19 +04:00
parent b167771b5f
commit e990abd718
6 changed files with 53 additions and 55 deletions

View File

@ -1062,17 +1062,19 @@ public protocol AccountContext: AnyObject {
public struct PremiumConfiguration { public struct PremiumConfiguration {
public static var defaultValue: PremiumConfiguration { public static var defaultValue: PremiumConfiguration {
return PremiumConfiguration(isPremiumDisabled: false, showPremiumGiftInAttachMenu: false, showPremiumGiftInTextField: false) return PremiumConfiguration(isPremiumDisabled: false, showPremiumGiftInAttachMenu: false, showPremiumGiftInTextField: false, giveawayGiftsPurchaseAvailable: false)
} }
public let isPremiumDisabled: Bool public let isPremiumDisabled: Bool
public let showPremiumGiftInAttachMenu: Bool public let showPremiumGiftInAttachMenu: Bool
public let showPremiumGiftInTextField: Bool public let showPremiumGiftInTextField: Bool
public let giveawayGiftsPurchaseAvailable: Bool
fileprivate init(isPremiumDisabled: Bool, showPremiumGiftInAttachMenu: Bool, showPremiumGiftInTextField: Bool) { fileprivate init(isPremiumDisabled: Bool, showPremiumGiftInAttachMenu: Bool, showPremiumGiftInTextField: Bool, giveawayGiftsPurchaseAvailable: Bool) {
self.isPremiumDisabled = isPremiumDisabled self.isPremiumDisabled = isPremiumDisabled
self.showPremiumGiftInAttachMenu = showPremiumGiftInAttachMenu self.showPremiumGiftInAttachMenu = showPremiumGiftInAttachMenu
self.showPremiumGiftInTextField = showPremiumGiftInTextField self.showPremiumGiftInTextField = showPremiumGiftInTextField
self.giveawayGiftsPurchaseAvailable = giveawayGiftsPurchaseAvailable
} }
public static func with(appConfiguration: AppConfiguration) -> PremiumConfiguration { public static func with(appConfiguration: AppConfiguration) -> PremiumConfiguration {
@ -1080,7 +1082,8 @@ public struct PremiumConfiguration {
return PremiumConfiguration( return PremiumConfiguration(
isPremiumDisabled: data["premium_purchase_blocked"] as? Bool ?? false, isPremiumDisabled: data["premium_purchase_blocked"] as? Bool ?? false,
showPremiumGiftInAttachMenu: data["premium_gift_attach_menu_icon"] as? Bool ?? false, showPremiumGiftInAttachMenu: data["premium_gift_attach_menu_icon"] as? Bool ?? false,
showPremiumGiftInTextField: data["premium_gift_text_field_icon"] as? Bool ?? false showPremiumGiftInTextField: data["premium_gift_text_field_icon"] as? Bool ?? false,
giveawayGiftsPurchaseAvailable: data["giveaway_gifts_purchase_available"] as? Bool ?? false
) )
} else { } else {
return .defaultValue return .defaultValue

View File

@ -1439,7 +1439,7 @@ private final class LimitSheetContent: CombinedComponent {
) )
var additionalContentHeight: CGFloat = 0.0 var additionalContentHeight: CGFloat = 0.0
if case let .storiesChannelBoost(_, _, _, _, _, link, _) = component.subject, link != nil { if case let .storiesChannelBoost(_, _, _, _, _, link, _) = component.subject, link != nil, let openGift = component.openGift {
let orText = orText.update( let orText = orText.update(
component: MultilineTextComponent(text: .plain(NSAttributedString(string: "or", font: Font.regular(15.0), textColor: textColor.withAlphaComponent(0.8), paragraphAlignment: .center))), component: MultilineTextComponent(text: .plain(NSAttributedString(string: "or", font: Font.regular(15.0), textColor: textColor.withAlphaComponent(0.8), paragraphAlignment: .center))),
availableSize: CGSize(width: context.availableSize.width - sideInset * 2.0, height: context.availableSize.height), availableSize: CGSize(width: context.availableSize.width - sideInset * 2.0, height: context.availableSize.height),
@ -1477,7 +1477,6 @@ private final class LimitSheetContent: CombinedComponent {
if let range = giftAttributedString.string.range(of: ">"), let chevronImage = state.cachedChevronImage?.0 { if let range = giftAttributedString.string.range(of: ">"), let chevronImage = state.cachedChevronImage?.0 {
giftAttributedString.addAttribute(.attachment, value: chevronImage, range: NSRange(range, in: giftAttributedString.string)) giftAttributedString.addAttribute(.attachment, value: chevronImage, range: NSRange(range, in: giftAttributedString.string))
} }
let openGift = component.openGift
let giftText = giftText.update( let giftText = giftText.update(
component: BalancedTextComponent( component: BalancedTextComponent(
text: .plain(giftAttributedString), text: .plain(giftAttributedString),
@ -1485,15 +1484,11 @@ private final class LimitSheetContent: CombinedComponent {
maximumNumberOfLines: 0, maximumNumberOfLines: 0,
lineSpacing: 0.1, lineSpacing: 0.1,
highlightColor: linkColor.withAlphaComponent(0.2), highlightColor: linkColor.withAlphaComponent(0.2),
highlightAction: { attributes in highlightAction: { _ in
if let _ = attributes[NSAttributedString.Key(rawValue: TelegramTextAttributes.URL)] { return nil
return NSAttributedString.Key(rawValue: TelegramTextAttributes.URL)
} else {
return nil
}
}, },
tapAction: { _, _ in tapAction: { _, _ in
openGift?() openGift()
} }
), ),
availableSize: CGSize(width: context.availableSize.width - textSideInset * 2.0, height: context.availableSize.height), availableSize: CGSize(width: context.availableSize.width - textSideInset * 2.0, height: context.availableSize.height),
@ -1517,7 +1512,9 @@ private final class LimitSheetContent: CombinedComponent {
if link != nil { if link != nil {
height += 66.0 height += 66.0
height += 100.0 if let _ = component.openGift {
height += 100.0
}
} else { } else {
if isCurrent { if isCurrent {
height -= 53.0 height -= 53.0

View File

@ -663,7 +663,7 @@ private struct ChannelStatsControllerState: Equatable {
} }
private func channelStatsControllerEntries(state: ChannelStatsControllerState, peer: EnginePeer?, data: ChannelStats?, messages: [Message]?, interactions: [MessageId: ChannelStatsMessageInteractions]?, boostData: ChannelBoostStatus?, boostersState: ChannelBoostersContext.State?, giftsState: ChannelBoostersContext.State?, presentationData: PresentationData) -> [StatsEntry] { private func channelStatsControllerEntries(state: ChannelStatsControllerState, peer: EnginePeer?, data: ChannelStats?, messages: [Message]?, interactions: [MessageId: ChannelStatsMessageInteractions]?, boostData: ChannelBoostStatus?, boostersState: ChannelBoostersContext.State?, giftsState: ChannelBoostersContext.State?, presentationData: PresentationData, giveawayAvailable: Bool) -> [StatsEntry] {
var entries: [StatsEntry] = [] var entries: [StatsEntry] = []
switch state.section { switch state.section {
@ -822,8 +822,10 @@ private func channelStatsControllerEntries(state: ChannelStatsControllerState, p
entries.append(.boostLink(presentationData.theme, boostData.url)) entries.append(.boostLink(presentationData.theme, boostData.url))
entries.append(.boostLinkInfo(presentationData.theme, presentationData.strings.Stats_Boosts_LinkInfo)) entries.append(.boostLinkInfo(presentationData.theme, presentationData.strings.Stats_Boosts_LinkInfo))
entries.append(.gifts(presentationData.theme, "Get Boosts via Gifts")) if giveawayAvailable {
entries.append(.giftsInfo(presentationData.theme, "Get more boosts for your channel by gifting Premium to your subscribers.")) entries.append(.gifts(presentationData.theme, "Get Boosts via Gifts"))
entries.append(.giftsInfo(presentationData.theme, "Get more boosts for your channel by gifting Premium to your subscribers."))
}
} }
} }
@ -837,6 +839,8 @@ public func channelStatsController(context: AccountContext, updatedPresentationD
statePromise.set(stateValue.modify { f($0) }) statePromise.set(stateValue.modify { f($0) })
} }
let premiumConfiguration = PremiumConfiguration.with(appConfiguration: context.currentAppConfiguration.with { $0 })
var openMessageStatsImpl: ((MessageId) -> Void)? var openMessageStatsImpl: ((MessageId) -> Void)?
var contextActionImpl: ((MessageId, ASDisplayNode, ContextGesture?) -> Void)? var contextActionImpl: ((MessageId, ASDisplayNode, ContextGesture?) -> Void)?
@ -998,11 +1002,9 @@ public func channelStatsController(context: AccountContext, updatedPresentationD
map[interactions.messageId] = interactions map[interactions.messageId] = interactions
return map return map
} }
let controllerState = ItemListControllerState(presentationData: ItemListPresentationData(presentationData), title: .sectionControl([presentationData.strings.Stats_Statistics, presentationData.strings.Stats_Boosts], state.section == .boosts ? 1 : 0), leftNavigationButton: nil, rightNavigationButton: nil, backNavigationButton: ItemListBackButton(title: presentationData.strings.Common_Back), animateChanges: true) let controllerState = ItemListControllerState(presentationData: ItemListPresentationData(presentationData), title: .sectionControl([presentationData.strings.Stats_Statistics, presentationData.strings.Stats_Boosts], state.section == .boosts ? 1 : 0), leftNavigationButton: nil, rightNavigationButton: nil, backNavigationButton: ItemListBackButton(title: presentationData.strings.Common_Back), animateChanges: true)
let listState = ItemListNodeState(presentationData: ItemListPresentationData(presentationData), entries: channelStatsControllerEntries(state: state, peer: peer, data: data, messages: messages, interactions: interactions, boostData: boostData, boostersState: boostersState, giftsState: giftsState, presentationData: presentationData), style: .blocks, emptyStateItem: emptyStateItem, crossfadeState: previous == nil, animateChanges: false) let listState = ItemListNodeState(presentationData: ItemListPresentationData(presentationData), entries: channelStatsControllerEntries(state: state, peer: peer, data: data, messages: messages, interactions: interactions, boostData: boostData, boostersState: boostersState, giftsState: giftsState, presentationData: presentationData, giveawayAvailable: premiumConfiguration.giveawayGiftsPurchaseAvailable), style: .blocks, emptyStateItem: emptyStateItem, crossfadeState: previous == nil, animateChanges: false)
return (controllerState, (listState, arguments)) return (controllerState, (listState, arguments))
} }

View File

@ -95,41 +95,35 @@ public enum UpdatePeerNameColorAndEmojiError {
} }
func _internal_updatePeerNameColorAndEmoji(account: Account, peerId: EnginePeer.Id, nameColor: PeerNameColor, backgroundEmojiId: Int64?) -> Signal<Void, UpdatePeerNameColorAndEmojiError> { func _internal_updatePeerNameColorAndEmoji(account: Account, peerId: EnginePeer.Id, nameColor: PeerNameColor, backgroundEmojiId: Int64?) -> Signal<Void, UpdatePeerNameColorAndEmojiError> {
let accountPeerId = account.peerId return account.postbox.transaction { transaction -> Signal<Void, UpdatePeerNameColorAndEmojiError> in
if let peer = transaction.getPeer(peerId) {
return account.postbox.transaction { transaction -> Signal<Peer, NoError> in if let peer = peer as? TelegramChannel, let inputChannel = apiInputChannel(peer) {
guard let peer = transaction.getPeer(peerId) as? TelegramChannel else { let flags: Int32 = (1 << 0)
return .complete() return account.network.request(Api.functions.channels.updateColor(flags: flags, channel: inputChannel, color: nameColor.rawValue, backgroundEmojiId: backgroundEmojiId ?? 0))
} |> mapError { error -> UpdatePeerNameColorAndEmojiError in
updatePeersCustom(transaction: transaction, peers: [peer.withUpdatedNameColor(nameColor).withUpdatedBackgroundEmojiId(backgroundEmojiId)], update: { _, updated in if error.errorDescription.hasPrefix("BOOSTS_REQUIRED") {
return updated return .channelBoostRequired
}) }
return .single(peer) return .generic
}
|> switchToLatest
|> castError(UpdatePeerNameColorAndEmojiError.self)
|> mapToSignal { peer -> Signal<Void, UpdatePeerNameColorAndEmojiError> in
if let peer = peer as? TelegramChannel, let inputChannel = apiInputChannel(peer) {
let flags: Int32 = (1 << 0)
return account.network.request(Api.functions.channels.updateColor(flags: flags, channel: inputChannel, color: nameColor.rawValue, backgroundEmojiId: backgroundEmojiId ?? 0))
|> mapError { error -> UpdatePeerNameColorAndEmojiError in
if error.errorDescription.hasPrefix("BOOSTS_REQUIRED") {
return .channelBoostRequired
}
return .generic
}
|> mapToSignal { result -> Signal<Void, UpdatePeerNameColorAndEmojiError> in
account.stateManager.addUpdates(result)
return account.postbox.transaction { transaction -> Void in
if let apiChat = apiUpdatesGroups(result).first {
let parsedPeers = AccumulatedPeers(transaction: transaction, chats: [apiChat], users: [])
updatePeers(transaction: transaction, accountPeerId: accountPeerId, peers: parsedPeers)
} }
} |> mapError { _ -> UpdatePeerNameColorAndEmojiError in } |> mapToSignal { result -> Signal<Void, UpdatePeerNameColorAndEmojiError> in
account.stateManager.addUpdates(result)
return account.postbox.transaction { transaction -> Void in
if let apiChat = apiUpdatesGroups(result).first {
let parsedPeers = AccumulatedPeers(transaction: transaction, chats: [apiChat], users: [])
updatePeers(transaction: transaction, accountPeerId: account.peerId, peers: parsedPeers)
}
}
|> mapError { _ -> UpdatePeerNameColorAndEmojiError in }
}
} else {
return .fail(.generic)
} }
} else { } else {
return .fail(.generic) return .fail(.generic)
} }
} }
|> castError(UpdatePeerNameColorAndEmojiError.self)
|> switchToLatest
} }

View File

@ -442,7 +442,7 @@ public func PeerNameColorScreen(
} }
updateState { state in updateState { state in
var updatedState = state var updatedState = state
updatedState.inProgress = true updatedState.inProgress = false
return updatedState return updatedState
} }
}, completed: { }, completed: {

View File

@ -8362,6 +8362,8 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, PeerInfoScreenNodePro
case .channelBoostRequired: case .channelBoostRequired:
self.postingAvailabilityDisposable?.dispose() self.postingAvailabilityDisposable?.dispose()
let premiumConfiguration = PremiumConfiguration.with(appConfiguration: self.context.currentAppConfiguration.with { $0 })
self.postingAvailabilityDisposable = combineLatest( self.postingAvailabilityDisposable = combineLatest(
queue: Queue.mainQueue(), queue: Queue.mainQueue(),
self.context.engine.data.get(TelegramEngine.EngineData.Item.Peer.Peer(id: self.peerId)), self.context.engine.data.get(TelegramEngine.EngineData.Item.Peer.Peer(id: self.peerId)),
@ -8387,12 +8389,12 @@ final class PeerInfoScreenNode: ViewControllerTracingNode, PeerInfoScreenNodePro
if let self { if let self {
self.openStats(boosts: true, boostStatus: status) self.openStats(boosts: true, boostStatus: status)
} }
}, openGift: { [weak self] in }, openGift: premiumConfiguration.giveawayGiftsPurchaseAvailable ? { [weak self] in
if let self { if let self {
let controller = createGiveawayController(context: self.context, peerId: self.peerId, subject: .generic) let controller = createGiveawayController(context: self.context, peerId: self.peerId, subject: .generic)
self.controller?.push(controller) self.controller?.push(controller)
} }
}) } : nil)
navigationController.pushViewController(controller) navigationController.pushViewController(controller)
} }