mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-12-23 06:35:51 +00:00
Stars giveaways [skip ci]
This commit is contained in:
@@ -33,8 +33,9 @@ private final class CreateGiveawayControllerArguments {
|
||||
let scrollToDescription: () -> Void
|
||||
let setItemIdWithRevealedOptions: (EnginePeer.Id?, EnginePeer.Id?) -> Void
|
||||
let removeChannel: (EnginePeer.Id) -> Void
|
||||
let expandStars: () -> Void
|
||||
|
||||
init(context: AccountContext, updateState: @escaping ((CreateGiveawayControllerState) -> CreateGiveawayControllerState) -> Void, dismissInput: @escaping () -> Void, openPeersSelection: @escaping () -> Void, openChannelsSelection: @escaping () -> Void, openCountriesSelection: @escaping () -> Void, openPremiumIntro: @escaping () -> Void, scrollToDate: @escaping () -> Void, scrollToDescription: @escaping () -> Void, setItemIdWithRevealedOptions: @escaping (EnginePeer.Id?, EnginePeer.Id?) -> Void, removeChannel: @escaping (EnginePeer.Id) -> Void) {
|
||||
init(context: AccountContext, updateState: @escaping ((CreateGiveawayControllerState) -> CreateGiveawayControllerState) -> Void, dismissInput: @escaping () -> Void, openPeersSelection: @escaping () -> Void, openChannelsSelection: @escaping () -> Void, openCountriesSelection: @escaping () -> Void, openPremiumIntro: @escaping () -> Void, scrollToDate: @escaping () -> Void, scrollToDescription: @escaping () -> Void, setItemIdWithRevealedOptions: @escaping (EnginePeer.Id?, EnginePeer.Id?) -> Void, removeChannel: @escaping (EnginePeer.Id) -> Void, expandStars: @escaping () -> Void) {
|
||||
self.context = context
|
||||
self.updateState = updateState
|
||||
self.dismissInput = dismissInput
|
||||
@@ -46,12 +47,14 @@ private final class CreateGiveawayControllerArguments {
|
||||
self.scrollToDescription = scrollToDescription
|
||||
self.setItemIdWithRevealedOptions = setItemIdWithRevealedOptions
|
||||
self.removeChannel = removeChannel
|
||||
self.expandStars = expandStars
|
||||
}
|
||||
}
|
||||
|
||||
private enum CreateGiveawaySection: Int32 {
|
||||
case header
|
||||
case mode
|
||||
case stars
|
||||
case subscriptions
|
||||
case channels
|
||||
case users
|
||||
@@ -77,14 +80,20 @@ private enum CreateGiveawayEntryTag: ItemListItemTag {
|
||||
private enum CreateGiveawayEntry: ItemListNodeEntry {
|
||||
case header(PresentationTheme, String, String)
|
||||
|
||||
case createGiveaway(PresentationTheme, String, String, Bool)
|
||||
case awardUsers(PresentationTheme, String, String, Bool)
|
||||
case modeHeader(PresentationTheme, String)
|
||||
case giftPremium(PresentationTheme, String, String, Bool)
|
||||
case giftStars(PresentationTheme, String, String, Bool)
|
||||
|
||||
case prepaidHeader(PresentationTheme, String)
|
||||
case prepaid(PresentationTheme, String, String, PrepaidGiveaway)
|
||||
|
||||
case starsHeader(PresentationTheme, String, String)
|
||||
case stars(Int32, PresentationTheme, Int32, String, String, String, Bool)
|
||||
case starsMore(PresentationTheme, String)
|
||||
case starsInfo(PresentationTheme, String)
|
||||
|
||||
case subscriptionsHeader(PresentationTheme, String, String)
|
||||
case subscriptions(PresentationTheme, Int32)
|
||||
case subscriptions(PresentationTheme, Int32, [Int32])
|
||||
case subscriptionsInfo(PresentationTheme, String)
|
||||
|
||||
case channelsHeader(PresentationTheme, String)
|
||||
@@ -117,8 +126,10 @@ private enum CreateGiveawayEntry: ItemListNodeEntry {
|
||||
switch self {
|
||||
case .header:
|
||||
return CreateGiveawaySection.header.rawValue
|
||||
case .createGiveaway, .awardUsers, .prepaidHeader, .prepaid:
|
||||
case .modeHeader, .giftPremium, .giftStars, .prepaidHeader, .prepaid:
|
||||
return CreateGiveawaySection.mode.rawValue
|
||||
case .starsHeader, .stars, .starsMore, .starsInfo:
|
||||
return CreateGiveawaySection.stars.rawValue
|
||||
case .subscriptionsHeader, .subscriptions, .subscriptionsInfo:
|
||||
return CreateGiveawaySection.subscriptions.rawValue
|
||||
case .channelsHeader, .channel, .channelAdd, .channelsInfo:
|
||||
@@ -139,61 +150,71 @@ private enum CreateGiveawayEntry: ItemListNodeEntry {
|
||||
var stableId: Int32 {
|
||||
switch self {
|
||||
case .header:
|
||||
return -2
|
||||
case .modeHeader:
|
||||
return -1
|
||||
case .createGiveaway:
|
||||
case .giftPremium:
|
||||
return 0
|
||||
case .awardUsers:
|
||||
case .giftStars:
|
||||
return 1
|
||||
case .prepaidHeader:
|
||||
return 2
|
||||
case .prepaid:
|
||||
return 3
|
||||
case .subscriptionsHeader:
|
||||
case .starsHeader:
|
||||
return 4
|
||||
case let .stars(_, _, stars, _, _, _, _):
|
||||
return 5 + stars
|
||||
case .starsMore:
|
||||
return 100000
|
||||
case .starsInfo:
|
||||
return 100001
|
||||
case .subscriptionsHeader:
|
||||
return 100002
|
||||
case .subscriptions:
|
||||
return 5
|
||||
return 100003
|
||||
case .subscriptionsInfo:
|
||||
return 6
|
||||
return 100004
|
||||
case .channelsHeader:
|
||||
return 7
|
||||
return 100005
|
||||
case let .channel(index, _, _, _, _):
|
||||
return 8 + index
|
||||
return 100006 + index
|
||||
case .channelAdd:
|
||||
return 100
|
||||
return 100200
|
||||
case .channelsInfo:
|
||||
return 101
|
||||
return 100201
|
||||
case .usersHeader:
|
||||
return 102
|
||||
return 100202
|
||||
case .usersAll:
|
||||
return 103
|
||||
return 100203
|
||||
case .usersNew:
|
||||
return 104
|
||||
return 100204
|
||||
case .usersInfo:
|
||||
return 105
|
||||
return 100205
|
||||
case .durationHeader:
|
||||
return 106
|
||||
return 100206
|
||||
case let .duration(index, _, _, _, _, _, _, _):
|
||||
return 107 + index
|
||||
return 100207 + index
|
||||
case .durationInfo:
|
||||
return 200
|
||||
return 100300
|
||||
case .prizeDescription:
|
||||
return 201
|
||||
return 100301
|
||||
case .prizeDescriptionText:
|
||||
return 202
|
||||
return 100302
|
||||
case .prizeDescriptionInfo:
|
||||
return 203
|
||||
case .winners:
|
||||
return 204
|
||||
case .winnersInfo:
|
||||
return 205
|
||||
return 100303
|
||||
case .timeHeader:
|
||||
return 206
|
||||
return 100304
|
||||
case .timeExpiryDate:
|
||||
return 207
|
||||
return 100305
|
||||
case .timeCustomPicker:
|
||||
return 208
|
||||
return 100306
|
||||
case .timeInfo:
|
||||
return 209
|
||||
return 100307
|
||||
case .winners:
|
||||
return 100308
|
||||
case .winnersInfo:
|
||||
return 100309
|
||||
}
|
||||
}
|
||||
|
||||
@@ -205,14 +226,20 @@ private enum CreateGiveawayEntry: ItemListNodeEntry {
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
case let .createGiveaway(lhsTheme, lhsText, lhsSubtext, lhsSelected):
|
||||
if case let .createGiveaway(rhsTheme, rhsText, rhsSubtext, rhsSelected) = rhs, lhsTheme === rhsTheme, lhsText == rhsText, lhsSubtext == rhsSubtext, lhsSelected == rhsSelected {
|
||||
case let .modeHeader(lhsTheme, lhsText):
|
||||
if case let .modeHeader(rhsTheme, rhsText) = rhs, lhsTheme === rhsTheme, lhsText == rhsText {
|
||||
return true
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
case let .awardUsers(lhsTheme, lhsText, lhsSubtext, lhsSelected):
|
||||
if case let .awardUsers(rhsTheme, rhsText, rhsSubtext, rhsSelected) = rhs, lhsTheme === rhsTheme, lhsText == rhsText, lhsSubtext == rhsSubtext, lhsSelected == rhsSelected {
|
||||
case let .giftPremium(lhsTheme, lhsText, lhsSubtext, lhsSelected):
|
||||
if case let .giftPremium(rhsTheme, rhsText, rhsSubtext, rhsSelected) = rhs, lhsTheme === rhsTheme, lhsText == rhsText, lhsSubtext == rhsSubtext, lhsSelected == rhsSelected {
|
||||
return true
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
case let .giftStars(lhsTheme, lhsText, lhsSubtext, lhsSelected):
|
||||
if case let .giftStars(rhsTheme, rhsText, rhsSubtext, rhsSelected) = rhs, lhsTheme === rhsTheme, lhsText == rhsText, lhsSubtext == rhsSubtext, lhsSelected == rhsSelected {
|
||||
return true
|
||||
} else {
|
||||
return false
|
||||
@@ -229,14 +256,38 @@ private enum CreateGiveawayEntry: ItemListNodeEntry {
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
case let .starsHeader(lhsTheme, lhsText, lhsAdditionalText):
|
||||
if case let .starsHeader(rhsTheme, rhsText, rhsAdditionalText) = rhs, lhsTheme === rhsTheme, lhsText == rhsText, lhsAdditionalText == rhsAdditionalText {
|
||||
return true
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
case let .stars(lhsIndex, lhsTheme, lhsStars, lhsTitle, lhsSubtitle, lhsLabel, lhsIsSelected):
|
||||
if case let .stars(rhsIndex, rhsTheme, rhsStars, rhsTitle, rhsSubtitle, rhsLabel, rhsIsSelected) = rhs, lhsIndex == rhsIndex, lhsTheme === rhsTheme, lhsStars == rhsStars, lhsTitle == rhsTitle, lhsSubtitle == rhsSubtitle, lhsLabel == rhsLabel, lhsIsSelected == rhsIsSelected {
|
||||
return true
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
case let .starsMore(lhsTheme, lhsText):
|
||||
if case let .starsMore(rhsTheme, rhsText) = rhs, lhsTheme === rhsTheme, lhsText == rhsText {
|
||||
return true
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
case let .starsInfo(lhsTheme, lhsText):
|
||||
if case let .starsInfo(rhsTheme, rhsText) = rhs, lhsTheme === rhsTheme, lhsText == rhsText {
|
||||
return true
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
case let .subscriptionsHeader(lhsTheme, lhsText, lhsAdditionalText):
|
||||
if case let .subscriptionsHeader(rhsTheme, rhsText, rhsAdditionalText) = rhs, lhsTheme === rhsTheme, lhsText == rhsText, lhsAdditionalText == rhsAdditionalText {
|
||||
return true
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
case let .subscriptions(lhsTheme, lhsValue):
|
||||
if case let .subscriptions(rhsTheme, rhsValue) = rhs, lhsTheme === rhsTheme, lhsValue == rhsValue {
|
||||
case let .subscriptions(lhsTheme, lhsValue, lhsValues):
|
||||
if case let .subscriptions(rhsTheme, rhsValue, rhsValues) = rhs, lhsTheme === rhsTheme, lhsValue == rhsValue, lhsValues == rhsValues {
|
||||
return true
|
||||
} else {
|
||||
return false
|
||||
@@ -379,29 +430,31 @@ private enum CreateGiveawayEntry: ItemListNodeEntry {
|
||||
switch self {
|
||||
case let .header(_, title, text):
|
||||
return ItemListTextItem(presentationData: presentationData, text: .plain(title + text), sectionId: self.section)
|
||||
case let .createGiveaway(_, title, subtitle, isSelected):
|
||||
return GiftOptionItem(presentationData: presentationData, context: arguments.context, icon: .image(color: .blue, name: "Premium/Giveaway"), title: title, subtitle: subtitle, isSelected: isSelected, sectionId: self.section, action: {
|
||||
arguments.updateState { state in
|
||||
var updatedState = state
|
||||
updatedState.mode = .giveaway
|
||||
return updatedState
|
||||
}
|
||||
})
|
||||
case let .awardUsers(_, title, subtitle, isSelected):
|
||||
return GiftOptionItem(presentationData: presentationData, context: arguments.context, icon: .image(color: .violet, name: "Media Editor/Privacy/SelectedUsers"), title: title, subtitle: subtitle, subtitleActive: true, isSelected: isSelected, sectionId: self.section, action: {
|
||||
case let .modeHeader(_, text):
|
||||
return ItemListSectionHeaderItem(presentationData: presentationData, text: text, sectionId: self.section)
|
||||
case let .giftPremium(_, title, subtitle, isSelected):
|
||||
return GiftOptionItem(presentationData: presentationData, context: arguments.context, icon: .image(color: .premium, name: "Peer Info/PremiumIcon"), title: title, subtitle: subtitle, subtitleActive: true, isSelected: isSelected, sectionId: self.section, action: {
|
||||
var openSelection = false
|
||||
arguments.updateState { state in
|
||||
var updatedState = state
|
||||
if state.mode == .gift || state.peers.isEmpty {
|
||||
if (state.mode == .giveaway && state.peers.isEmpty) {
|
||||
openSelection = true
|
||||
}
|
||||
updatedState.mode = .gift
|
||||
updatedState.mode = .giveaway
|
||||
return updatedState
|
||||
}
|
||||
if openSelection {
|
||||
arguments.openPeersSelection()
|
||||
}
|
||||
})
|
||||
case let .giftStars(_, title, subtitle, isSelected):
|
||||
return GiftOptionItem(presentationData: presentationData, context: arguments.context, icon: .image(color: .stars, name: "Peer Info/PremiumIcon"), title: title, subtitle: subtitle, subtitleActive: false, isSelected: isSelected, sectionId: self.section, action: {
|
||||
arguments.updateState { state in
|
||||
var updatedState = state
|
||||
updatedState.mode = .starsGiveaway
|
||||
return updatedState
|
||||
}
|
||||
})
|
||||
case let .prepaidHeader(_, text):
|
||||
return ItemListSectionHeaderItem(presentationData: presentationData, text: text, sectionId: self.section)
|
||||
case let .prepaid(_, title, subtitle, prepaidGiveaway):
|
||||
@@ -417,13 +470,33 @@ private enum CreateGiveawayEntry: ItemListNodeEntry {
|
||||
color = .blue
|
||||
}
|
||||
return GiftOptionItem(presentationData: presentationData, context: arguments.context, icon: .image(color: color, name: "Premium/Giveaway"), title: title, titleFont: .bold, titleBadge: "\(prepaidGiveaway.quantity * 4)", subtitle: subtitle, sectionId: self.section, action: nil)
|
||||
case let .subscriptionsHeader(_, text, additionalText):
|
||||
case let .starsHeader(_, text, additionalText):
|
||||
return ItemListSectionHeaderItem(presentationData: presentationData, text: text, accessoryText: ItemListSectionHeaderAccessoryText(value: additionalText, color: .generic), sectionId: self.section)
|
||||
case let .subscriptions(_, value):
|
||||
return SubscriptionsCountItem(theme: presentationData.theme, strings: presentationData.strings, value: value, sectionId: self.section, updated: { value in
|
||||
case let .stars(_, _, stars, title, subtitle, label, isSelected):
|
||||
return GiftOptionItem(presentationData: presentationData, context: arguments.context, title: title, subtitle: subtitle, subtitleFont: .small, label: .generic(label), badge: nil, isSelected: isSelected, stars: Int64(stars), sectionId: self.section, action: {
|
||||
arguments.updateState { state in
|
||||
var updatedState = state
|
||||
updatedState.subscriptions = value
|
||||
updatedState.stars = Int64(stars)
|
||||
return updatedState
|
||||
}
|
||||
})
|
||||
case let .starsMore(theme, title):
|
||||
return ItemListPeerActionItem(presentationData: presentationData, icon: PresentationResourcesItemList.downArrowImage(theme), title: title, sectionId: self.section, editing: false, action: {
|
||||
arguments.expandStars()
|
||||
})
|
||||
case let .starsInfo(_, text):
|
||||
return ItemListTextItem(presentationData: presentationData, text: .plain(text), sectionId: self.section)
|
||||
case let .subscriptionsHeader(_, text, additionalText):
|
||||
return ItemListSectionHeaderItem(presentationData: presentationData, text: text, accessoryText: ItemListSectionHeaderAccessoryText(value: additionalText, color: .generic), sectionId: self.section)
|
||||
case let .subscriptions(_, value, values):
|
||||
return SubscriptionsCountItem(theme: presentationData.theme, strings: presentationData.strings, value: value, values: values, sectionId: self.section, updated: { value in
|
||||
arguments.updateState { state in
|
||||
var updatedState = state
|
||||
if state.mode == .giveaway {
|
||||
updatedState.subscriptions = value
|
||||
} else if state.mode == .starsGiveaway {
|
||||
updatedState.winners = value
|
||||
}
|
||||
return updatedState
|
||||
}
|
||||
})
|
||||
@@ -626,6 +699,19 @@ private struct PremiumGiftProduct: Equatable {
|
||||
}
|
||||
}
|
||||
|
||||
private struct StarsGiveawayProduct: Equatable {
|
||||
let giveawayOption: StarsGiveawayOption
|
||||
let storeProduct: InAppPurchaseManager.Product
|
||||
|
||||
var id: String {
|
||||
return self.storeProduct.id
|
||||
}
|
||||
|
||||
var price: String {
|
||||
return self.storeProduct.price
|
||||
}
|
||||
}
|
||||
|
||||
private func createGiveawayControllerEntries(
|
||||
peerId: EnginePeer.Id,
|
||||
subject: CreateGiveawaySubject,
|
||||
@@ -635,6 +721,7 @@ private func createGiveawayControllerEntries(
|
||||
peers: [EnginePeer.Id: EnginePeer],
|
||||
products: [PremiumGiftProduct],
|
||||
defaultPrice: (Int64, NSDecimalNumber),
|
||||
starsGiveawayOptions: [StarsGiveawayProduct],
|
||||
minDate: Int32,
|
||||
maxDate: Int32
|
||||
) -> [CreateGiveawayEntry] {
|
||||
@@ -647,10 +734,8 @@ private func createGiveawayControllerEntries(
|
||||
|
||||
switch subject {
|
||||
case .generic:
|
||||
entries.append(.createGiveaway(presentationData.theme, presentationData.strings.BoostGift_CreateGiveaway, presentationData.strings.BoostGift_CreateGiveawayInfo, state.mode == .giveaway))
|
||||
|
||||
let recipientsText: String
|
||||
if !state.peers.isEmpty {
|
||||
if !state.peers.isEmpty && state.mode == .gift {
|
||||
var peerNamesArray: [String] = []
|
||||
let peersCount = state.peers.count
|
||||
for peerId in state.peers.prefix(2) {
|
||||
@@ -665,14 +750,47 @@ private func createGiveawayControllerEntries(
|
||||
recipientsText = presentationData.strings.PremiumGift_LabelRecipients(Int32(peersCount))
|
||||
}
|
||||
} else {
|
||||
recipientsText = presentationData.strings.BoostGift_SelectRecipients
|
||||
recipientsText = presentationData.strings.BoostGift_CreateGiveawayInfo //presentationData.strings.BoostGift_SelectRecipients
|
||||
}
|
||||
entries.append(.awardUsers(presentationData.theme, presentationData.strings.BoostGift_AwardSpecificUsers, recipientsText, state.mode == .gift))
|
||||
|
||||
//TODO:localize
|
||||
entries.append(.modeHeader(presentationData.theme, "PRIZE"))
|
||||
entries.append(.giftPremium(presentationData.theme, "Telegram Premium", recipientsText, state.mode == .giveaway || state.mode == .gift))
|
||||
|
||||
entries.append(.giftStars(presentationData.theme, "Telegram Stars", presentationData.strings.BoostGift_CreateGiveawayInfo, state.mode == .starsGiveaway))
|
||||
case let .prepaid(prepaidGiveaway):
|
||||
entries.append(.prepaidHeader(presentationData.theme, presentationData.strings.BoostGift_PrepaidGiveawayTitle))
|
||||
entries.append(.prepaid(presentationData.theme, presentationData.strings.BoostGift_PrepaidGiveawayCount(prepaidGiveaway.quantity), presentationData.strings.BoostGift_PrepaidGiveawayMonths("\(prepaidGiveaway.months)").string, prepaidGiveaway))
|
||||
}
|
||||
|
||||
if case .starsGiveaway = state.mode, !starsGiveawayOptions.isEmpty {
|
||||
let selectedOption = starsGiveawayOptions.first(where: { $0.giveawayOption.count == state.stars })!
|
||||
entries.append(.starsHeader(presentationData.theme, "STARS TO DISTRIBUTE".uppercased(), "\(selectedOption.giveawayOption.yearlyBoosts) BOOSTS"))
|
||||
|
||||
var i: Int32 = 0
|
||||
for product in starsGiveawayOptions {
|
||||
if !state.starsExpanded && product.giveawayOption.isExtended {
|
||||
continue
|
||||
}
|
||||
let giftTitle: String = "\(product.giveawayOption.count) Stars"
|
||||
let winners = product.giveawayOption.winners.first(where: { $0.users == state.winners }) ?? product.giveawayOption.winners.first!
|
||||
|
||||
let subtitle = "\(winners.starsPerUser) per user"
|
||||
let label = product.storeProduct.price
|
||||
|
||||
let isSelected = product.giveawayOption.count == state.stars
|
||||
entries.append(.stars(i, presentationData.theme, Int32(product.giveawayOption.count), giftTitle, subtitle, label, isSelected))
|
||||
|
||||
i += 1
|
||||
}
|
||||
|
||||
if !state.starsExpanded {
|
||||
entries.append(.starsMore(presentationData.theme, "Show More Options"))
|
||||
}
|
||||
|
||||
entries.append(.starsInfo(presentationData.theme, "Choose how many stars to give away and how many boosts to receive for 1 year."))
|
||||
}
|
||||
|
||||
let appendDurationEntries = {
|
||||
entries.append(.durationHeader(presentationData.theme, presentationData.strings.BoostGift_DurationTitle.uppercased()))
|
||||
|
||||
@@ -682,6 +800,8 @@ private func createGiveawayControllerEntries(
|
||||
recipientCount = Int(state.subscriptions)
|
||||
case .gift:
|
||||
recipientCount = state.peers.count
|
||||
case .starsGiveaway:
|
||||
recipientCount = Int(state.subscriptions)
|
||||
}
|
||||
|
||||
var i: Int32 = 0
|
||||
@@ -721,11 +841,21 @@ private func createGiveawayControllerEntries(
|
||||
}
|
||||
|
||||
switch state.mode {
|
||||
case .giveaway:
|
||||
if case .generic = subject {
|
||||
entries.append(.subscriptionsHeader(presentationData.theme, presentationData.strings.BoostGift_QuantityTitle.uppercased(), presentationData.strings.BoostGift_QuantityBoosts(state.subscriptions * 4)))
|
||||
entries.append(.subscriptions(presentationData.theme, state.subscriptions))
|
||||
entries.append(.subscriptionsInfo(presentationData.theme, presentationData.strings.BoostGift_QuantityInfo))
|
||||
case .giveaway, .starsGiveaway:
|
||||
if case .starsGiveaway = state.mode {
|
||||
var values: [Int32] = [1]
|
||||
if let selectedOption = starsGiveawayOptions.first(where: { $0.giveawayOption.count == state.stars }) {
|
||||
values = selectedOption.giveawayOption.winners.map { $0.users }
|
||||
}
|
||||
entries.append(.subscriptionsHeader(presentationData.theme, "NUMBER OF WINNERS", ""))
|
||||
entries.append(.subscriptions(presentationData.theme, state.winners, values))
|
||||
entries.append(.subscriptionsInfo(presentationData.theme, "Choose how many winners you want to distribute stars among."))
|
||||
} else {
|
||||
if case .generic = subject {
|
||||
entries.append(.subscriptionsHeader(presentationData.theme, presentationData.strings.BoostGift_QuantityTitle.uppercased(), presentationData.strings.BoostGift_QuantityBoosts(state.subscriptions * 4)))
|
||||
entries.append(.subscriptions(presentationData.theme, state.subscriptions, [1, 3, 5, 7, 10, 25, 50]))
|
||||
entries.append(.subscriptionsInfo(presentationData.theme, presentationData.strings.BoostGift_QuantityInfo))
|
||||
}
|
||||
}
|
||||
|
||||
entries.append(.channelsHeader(presentationData.theme, isGroup ? presentationData.strings.BoostGift_GroupsAndChannelsTitle.uppercased() : presentationData.strings.BoostGift_ChannelsAndGroupsTitle.uppercased()))
|
||||
@@ -765,12 +895,16 @@ private func createGiveawayControllerEntries(
|
||||
entries.append(.usersNew(presentationData.theme, isGroup ? presentationData.strings.BoostGift_Group_OnlyNewMembers : presentationData.strings.BoostGift_OnlyNewSubscribers, countriesText, state.onlyNewEligible))
|
||||
entries.append(.usersInfo(presentationData.theme, isGroup ? presentationData.strings.BoostGift_Group_LimitMembersInfo : presentationData.strings.BoostGift_LimitSubscribersInfo))
|
||||
|
||||
if case .generic = subject {
|
||||
appendDurationEntries()
|
||||
if case .starsGiveaway = state.mode {
|
||||
|
||||
} else {
|
||||
if case .generic = subject {
|
||||
appendDurationEntries()
|
||||
}
|
||||
}
|
||||
|
||||
entries.append(.prizeDescription(presentationData.theme, presentationData.strings.BoostGift_AdditionalPrizes, state.showPrizeDescription))
|
||||
var prizeDescriptionInfoText = presentationData.strings.BoostGift_AdditionalPrizesInfoOff
|
||||
var prizeDescriptionInfoText = state.mode == .starsGiveaway ? "Turn this on if you want to give the winners your own prizes in addition to Stars." : presentationData.strings.BoostGift_AdditionalPrizesInfoOff
|
||||
if state.showPrizeDescription {
|
||||
entries.append(.prizeDescriptionText(presentationData.theme, presentationData.strings.BoostGift_AdditionalPrizesPlaceholder, state.prizeDescription, state.subscriptions))
|
||||
|
||||
@@ -785,18 +919,28 @@ private func createGiveawayControllerEntries(
|
||||
}
|
||||
}
|
||||
entries.append(.prizeDescriptionInfo(presentationData.theme, prizeDescriptionInfoText))
|
||||
|
||||
entries.append(.winners(presentationData.theme, presentationData.strings.BoostGift_Winners, state.showWinners))
|
||||
entries.append(.winnersInfo(presentationData.theme, presentationData.strings.BoostGift_WinnersInfo))
|
||||
|
||||
|
||||
entries.append(.timeHeader(presentationData.theme, presentationData.strings.BoostGift_DateTitle.uppercased()))
|
||||
entries.append(.timeCustomPicker(presentationData.theme, presentationData.dateTimeFormat, state.time, minDate, maxDate, state.pickingExpiryDate, state.pickingExpiryTime))
|
||||
|
||||
let timeInfoText: String
|
||||
if isGroup {
|
||||
entries.append(.timeInfo(presentationData.theme, presentationData.strings.BoostGift_Group_DateInfo(presentationData.strings.BoostGift_Group_DateInfoMembers(Int32(state.subscriptions))).string))
|
||||
if case .starsGiveaway = state.mode {
|
||||
timeInfoText = "Choose when \(presentationData.strings.BoostGift_Group_DateInfoMembers(Int32(state.winners))) of your group will be randomly selected to receive Stars."
|
||||
} else {
|
||||
timeInfoText = presentationData.strings.BoostGift_Group_DateInfo(presentationData.strings.BoostGift_Group_DateInfoMembers(Int32(state.subscriptions))).string
|
||||
}
|
||||
} else {
|
||||
entries.append(.timeInfo(presentationData.theme, presentationData.strings.BoostGift_DateInfo(presentationData.strings.BoostGift_DateInfoSubscribers(Int32(state.subscriptions))).string))
|
||||
if case .starsGiveaway = state.mode {
|
||||
timeInfoText = "Choose when \(presentationData.strings.BoostGift_DateInfoSubscribers(Int32(state.winners))) of your channel will be randomly selected to receive Stars."
|
||||
} else {
|
||||
timeInfoText = presentationData.strings.BoostGift_DateInfo(presentationData.strings.BoostGift_DateInfoSubscribers(Int32(state.subscriptions))).string
|
||||
}
|
||||
}
|
||||
entries.append(.timeInfo(presentationData.theme, timeInfoText))
|
||||
|
||||
entries.append(.winners(presentationData.theme, presentationData.strings.BoostGift_Winners, state.showWinners))
|
||||
entries.append(.winnersInfo(presentationData.theme, presentationData.strings.BoostGift_WinnersInfo))
|
||||
case .gift:
|
||||
appendDurationEntries()
|
||||
}
|
||||
@@ -808,10 +952,13 @@ private struct CreateGiveawayControllerState: Equatable {
|
||||
enum Mode {
|
||||
case giveaway
|
||||
case gift
|
||||
case starsGiveaway
|
||||
}
|
||||
|
||||
var mode: Mode
|
||||
var subscriptions: Int32
|
||||
var stars: Int64
|
||||
var winners: Int32
|
||||
var channels: [EnginePeer.Id] = []
|
||||
var peers: [EnginePeer.Id] = []
|
||||
var selectedMonths: Int32?
|
||||
@@ -825,6 +972,7 @@ private struct CreateGiveawayControllerState: Equatable {
|
||||
var pickingExpiryDate = false
|
||||
var revealedItemId: EnginePeer.Id? = nil
|
||||
var updating = false
|
||||
var starsExpanded = false
|
||||
}
|
||||
|
||||
public enum CreateGiveawaySubject {
|
||||
@@ -857,7 +1005,7 @@ public func createGiveawayController(context: AccountContext, updatedPresentatio
|
||||
let minDate = currentTime + 60 * 1
|
||||
let maxDate = currentTime + context.userLimits.maxGiveawayPeriodSeconds
|
||||
|
||||
let initialState: CreateGiveawayControllerState = CreateGiveawayControllerState(mode: .giveaway, subscriptions: initialSubscriptions, time: expiryTime)
|
||||
let initialState: CreateGiveawayControllerState = CreateGiveawayControllerState(mode: .giveaway, subscriptions: initialSubscriptions, stars: 500, winners: 5, time: expiryTime)
|
||||
|
||||
let statePromise = ValuePromise(initialState, ignoreRepeated: true)
|
||||
let stateValue = Atomic(value: initialState)
|
||||
@@ -868,6 +1016,7 @@ public func createGiveawayController(context: AccountContext, updatedPresentatio
|
||||
let isGroupValue = Atomic<Bool>(value: false)
|
||||
|
||||
let productsValue = Atomic<[PremiumGiftProduct]?>(value: nil)
|
||||
let starsValue = Atomic<[StarsGiveawayProduct]?>(value: nil)
|
||||
|
||||
var buyActionImpl: (() -> Void)?
|
||||
var openPeersSelectionImpl: (() -> Void)?
|
||||
@@ -912,6 +1061,13 @@ public func createGiveawayController(context: AccountContext, updatedPresentatio
|
||||
updatedState.channels = updatedState.channels.filter { $0 != id }
|
||||
return updatedState
|
||||
}
|
||||
},
|
||||
expandStars: {
|
||||
updateState { state in
|
||||
var updatedState = state
|
||||
updatedState.starsExpanded = true
|
||||
return updatedState
|
||||
}
|
||||
})
|
||||
|
||||
let presentationData = updatedPresentationData?.signal ?? context.sharedContext.presentationData
|
||||
@@ -938,6 +1094,20 @@ public func createGiveawayController(context: AccountContext, updatedPresentatio
|
||||
return (gifts, defaultPrice)
|
||||
}
|
||||
|
||||
let starsGiveawayOptions: Signal<[StarsGiveawayProduct], NoError> = combineLatest(
|
||||
.single([]) |> then(context.engine.payments.starsGiveawayOptions()),
|
||||
context.inAppPurchaseManager?.availableProducts ?? .single([])
|
||||
)
|
||||
|> map { options, products in
|
||||
var result: [StarsGiveawayProduct] = []
|
||||
for option in options {
|
||||
if let product = products.first(where: { $0.id == option.storeProductId }), !product.isSubscription {
|
||||
result.append(StarsGiveawayProduct(giveawayOption: option, storeProduct: product))
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
let previousState = Atomic<CreateGiveawayControllerState?>(value: nil)
|
||||
let signal = combineLatest(
|
||||
presentationData,
|
||||
@@ -952,10 +1122,11 @@ public func createGiveawayController(context: AccountContext, updatedPresentatio
|
||||
return (state, peers)
|
||||
}
|
||||
},
|
||||
productsAndDefaultPrice
|
||||
productsAndDefaultPrice,
|
||||
starsGiveawayOptions
|
||||
)
|
||||
|> deliverOnMainQueue
|
||||
|> map { presentationData, stateAndPeersMap, productsAndDefaultPrice -> (ItemListControllerState, (ItemListNodeState, Any)) in
|
||||
|> map { presentationData, stateAndPeersMap, productsAndDefaultPrice, starsGiveawayOptions -> (ItemListControllerState, (ItemListNodeState, Any)) in
|
||||
var presentationData = presentationData
|
||||
|
||||
let (products, defaultPrice) = productsAndDefaultPrice
|
||||
@@ -971,7 +1142,9 @@ public func createGiveawayController(context: AccountContext, updatedPresentatio
|
||||
}
|
||||
let _ = isGroupValue.swap(isGroup)
|
||||
|
||||
let headerItem = CreateGiveawayHeaderItem(theme: presentationData.theme, strings: presentationData.strings, title: presentationData.strings.BoostGift_Title, text: isGroup ? presentationData.strings.BoostGift_Group_Description : presentationData.strings.BoostGift_Description, cancel: {
|
||||
//TODO:localize
|
||||
let headerText = isGroup ? "Get more boosts and members for\nyour group by giving away prizes." : "Get more boosts and subscribers for\nyour channel by giving away prizes."
|
||||
let headerItem = CreateGiveawayHeaderItem(theme: presentationData.theme, strings: presentationData.strings, title: presentationData.strings.BoostGift_Title, text: headerText, cancel: {
|
||||
dismissImpl?()
|
||||
})
|
||||
|
||||
@@ -981,6 +1154,8 @@ public func createGiveawayController(context: AccountContext, updatedPresentatio
|
||||
badgeCount = state.subscriptions * 4
|
||||
case .gift:
|
||||
badgeCount = Int32(state.peers.count) * 4
|
||||
case .starsGiveaway:
|
||||
badgeCount = Int32(state.stars) / 500
|
||||
}
|
||||
let footerItem = CreateGiveawayFooterItem(theme: presentationData.theme, title: state.mode == .gift ? presentationData.strings.BoostGift_GiftPremium : presentationData.strings.BoostGift_StartGiveaway, badgeCount: badgeCount, isLoading: state.updating, action: {
|
||||
if case .prepaid = subject {
|
||||
@@ -995,6 +1170,10 @@ public func createGiveawayController(context: AccountContext, updatedPresentatio
|
||||
let leftNavigationButton = ItemListNavigationButton(content: .none, style: .regular, enabled: false, action: {})
|
||||
|
||||
let _ = productsValue.swap(products)
|
||||
let previousStars = starsValue.swap(starsGiveawayOptions)
|
||||
if (previousStars ?? []).isEmpty && !starsGiveawayOptions.isEmpty {
|
||||
|
||||
}
|
||||
|
||||
let previousState = previousState.swap(state)
|
||||
var animateChanges = false
|
||||
@@ -1014,6 +1193,9 @@ public func createGiveawayController(context: AccountContext, updatedPresentatio
|
||||
if previousState.showPrizeDescription != state.showPrizeDescription {
|
||||
animateChanges = true
|
||||
}
|
||||
if previousState.starsExpanded != state.starsExpanded {
|
||||
animateChanges = true
|
||||
}
|
||||
}
|
||||
|
||||
var peers: [EnginePeer.Id: EnginePeer] = [:]
|
||||
@@ -1024,7 +1206,7 @@ public func createGiveawayController(context: AccountContext, updatedPresentatio
|
||||
}
|
||||
|
||||
let controllerState = ItemListControllerState(presentationData: ItemListPresentationData(presentationData), title: .text(""), leftNavigationButton: leftNavigationButton, rightNavigationButton: nil, backNavigationButton: ItemListBackButton(title: presentationData.strings.Common_Back), animateChanges: true)
|
||||
let listState = ItemListNodeState(presentationData: ItemListPresentationData(presentationData), entries: createGiveawayControllerEntries(peerId: peerId, subject: subject, state: state, presentationData: presentationData, locale: locale, peers: peers, products: products, defaultPrice: defaultPrice, minDate: minDate, maxDate: maxDate), style: .blocks, emptyStateItem: nil, headerItem: headerItem, footerItem: footerItem, crossfadeState: false, animateChanges: animateChanges)
|
||||
let listState = ItemListNodeState(presentationData: ItemListPresentationData(presentationData), entries: createGiveawayControllerEntries(peerId: peerId, subject: subject, state: state, presentationData: presentationData, locale: locale, peers: peers, products: products, defaultPrice: defaultPrice, starsGiveawayOptions: starsGiveawayOptions, minDate: minDate, maxDate: maxDate), style: .blocks, emptyStateItem: nil, headerItem: headerItem, footerItem: footerItem, crossfadeState: false, animateChanges: animateChanges)
|
||||
|
||||
return (controllerState, (listState, arguments))
|
||||
}
|
||||
@@ -1063,7 +1245,9 @@ public func createGiveawayController(context: AccountContext, updatedPresentatio
|
||||
return
|
||||
}
|
||||
var selectedProduct: PremiumGiftProduct?
|
||||
var selectedStarsProduct: StarsGiveawayProduct?
|
||||
let selectedMonths = state.selectedMonths ?? 12
|
||||
let selectedStars = state.stars
|
||||
switch state.mode {
|
||||
case .giveaway:
|
||||
if let product = products.first(where: { $0.months == selectedMonths && $0.giftOption.users == state.subscriptions }) {
|
||||
@@ -1073,18 +1257,27 @@ public func createGiveawayController(context: AccountContext, updatedPresentatio
|
||||
if let product = products.first(where: { $0.months == selectedMonths && $0.giftOption.users == 1 }) {
|
||||
selectedProduct = product
|
||||
}
|
||||
case .starsGiveaway:
|
||||
guard let starsOptions = starsValue.with({ $0 }), !starsOptions.isEmpty else {
|
||||
return
|
||||
}
|
||||
if let product = starsOptions.first(where: { $0.giveawayOption.count == selectedStars }) {
|
||||
selectedStarsProduct = product
|
||||
}
|
||||
}
|
||||
|
||||
guard let selectedProduct else {
|
||||
let alertController = textAlertController(context: context, title: presentationData.strings.BoostGift_ReduceQuantity_Title, text: presentationData.strings.BoostGift_ReduceQuantity_Text("\(state.subscriptions)", "\(selectedMonths)", "\(25)").string, actions: [TextAlertAction(type: .genericAction, title: presentationData.strings.Common_Cancel, action: {}), TextAlertAction(type: .defaultAction, title: presentationData.strings.BoostGift_ReduceQuantity_Reduce, action: {
|
||||
updateState { state in
|
||||
var updatedState = state
|
||||
updatedState.subscriptions = 25
|
||||
return updatedState
|
||||
}
|
||||
})], parseMarkdown: true)
|
||||
presentControllerImpl?(alertController)
|
||||
return
|
||||
if [.gift, .giveaway].contains(state.mode) {
|
||||
guard let _ = selectedProduct else {
|
||||
let alertController = textAlertController(context: context, title: presentationData.strings.BoostGift_ReduceQuantity_Title, text: presentationData.strings.BoostGift_ReduceQuantity_Text("\(state.subscriptions)", "\(selectedMonths)", "\(25)").string, actions: [TextAlertAction(type: .genericAction, title: presentationData.strings.Common_Cancel, action: {}), TextAlertAction(type: .defaultAction, title: presentationData.strings.BoostGift_ReduceQuantity_Reduce, action: {
|
||||
updateState { state in
|
||||
var updatedState = state
|
||||
updatedState.subscriptions = 25
|
||||
return updatedState
|
||||
}
|
||||
})], parseMarkdown: true)
|
||||
presentControllerImpl?(alertController)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
updateState { state in
|
||||
@@ -1093,25 +1286,48 @@ public func createGiveawayController(context: AccountContext, updatedPresentatio
|
||||
return updatedState
|
||||
}
|
||||
|
||||
let (currency, amount) = selectedProduct.storeProduct.priceCurrencyAndAmount
|
||||
|
||||
let purpose: AppStoreTransactionPurpose
|
||||
let quantity: Int32
|
||||
var storeProduct: InAppPurchaseManager.Product?
|
||||
switch state.mode {
|
||||
case .giveaway:
|
||||
guard let selectedProduct else {
|
||||
return
|
||||
}
|
||||
let (currency, amount) = selectedProduct.storeProduct.priceCurrencyAndAmount
|
||||
let currentTime = Int32(CFAbsoluteTimeGetCurrent() + kCFAbsoluteTimeIntervalSince1970)
|
||||
let untilDate = max(state.time, currentTime + 60)
|
||||
purpose = .giveaway(boostPeer: peerId, additionalPeerIds: state.channels.filter { $0 != peerId }, countries: state.countries, onlyNewSubscribers: state.onlyNewEligible, showWinners: state.showWinners, prizeDescription: state.prizeDescription.isEmpty ? nil : state.prizeDescription, randomId: Int64.random(in: .min ..< .max), untilDate: untilDate, currency: currency, amount: amount)
|
||||
quantity = selectedProduct.giftOption.storeQuantity
|
||||
storeProduct = selectedProduct.storeProduct
|
||||
case .gift:
|
||||
guard let selectedProduct else {
|
||||
return
|
||||
}
|
||||
let (currency, amount) = selectedProduct.storeProduct.priceCurrencyAndAmount
|
||||
purpose = .giftCode(peerIds: state.peers, boostPeer: peerId, currency: currency, amount: amount)
|
||||
quantity = Int32(state.peers.count)
|
||||
storeProduct = selectedProduct.storeProduct
|
||||
case .starsGiveaway:
|
||||
guard let selectedStarsProduct else {
|
||||
return
|
||||
}
|
||||
let (currency, amount) = selectedStarsProduct.storeProduct.priceCurrencyAndAmount
|
||||
let currentTime = Int32(CFAbsoluteTimeGetCurrent() + kCFAbsoluteTimeIntervalSince1970)
|
||||
let untilDate = max(state.time, currentTime + 60)
|
||||
purpose = .starsGiveaway(stars: selectedStarsProduct.giveawayOption.count, boostPeer: peerId, additionalPeerIds: state.channels.filter { $0 != peerId }, countries: state.countries, onlyNewSubscribers: state.onlyNewEligible, showWinners: state.showWinners, prizeDescription: state.prizeDescription.isEmpty ? nil : state.prizeDescription, randomId: Int64.random(in: .min ..< .max), untilDate: untilDate, currency: currency, amount: amount, users: state.winners)
|
||||
quantity = 1
|
||||
storeProduct = selectedStarsProduct.storeProduct
|
||||
}
|
||||
|
||||
guard let storeProduct else {
|
||||
return
|
||||
}
|
||||
|
||||
let _ = (context.engine.payments.canPurchasePremium(purpose: purpose)
|
||||
|> deliverOnMainQueue).startStandalone(next: { [weak controller] available in
|
||||
if available, let inAppPurchaseManager = context.inAppPurchaseManager {
|
||||
let _ = (inAppPurchaseManager.buyProduct(selectedProduct.storeProduct, quantity: quantity, purpose: purpose)
|
||||
let _ = (inAppPurchaseManager.buyProduct(storeProduct, quantity: quantity, purpose: purpose)
|
||||
|> deliverOnMainQueue).startStandalone(next: { [weak controller] status in
|
||||
if case .purchased = status {
|
||||
if let controller, let navigationController = controller.navigationController as? NavigationController {
|
||||
@@ -1133,7 +1349,7 @@ public func createGiveawayController(context: AccountContext, updatedPresentatio
|
||||
let title: String
|
||||
let text: String
|
||||
switch state.mode {
|
||||
case .giveaway:
|
||||
case .giveaway, .starsGiveaway:
|
||||
title = presentationData.strings.BoostGift_GiveawayCreated_Title
|
||||
text = isGroup ? presentationData.strings.BoostGift_Group_GiveawayCreated_Text : presentationData.strings.BoostGift_GiveawayCreated_Text
|
||||
case .gift:
|
||||
@@ -1248,6 +1464,8 @@ public func createGiveawayController(context: AccountContext, updatedPresentatio
|
||||
updatedState.peers = privacy.additionallyIncludePeers
|
||||
if updatedState.peers.isEmpty {
|
||||
updatedState.mode = .giveaway
|
||||
} else {
|
||||
updatedState.mode = .gift
|
||||
}
|
||||
return updatedState
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user