Limit min stars

This commit is contained in:
Isaac 2025-06-29 14:23:52 +02:00
parent ea9f53acb8
commit b2909a3241
2 changed files with 47 additions and 9 deletions

View File

@ -1511,7 +1511,8 @@ public struct StarsSubscriptionConfiguration {
channelMessageSuggestionStarsCommissionPermille: 850, channelMessageSuggestionStarsCommissionPermille: 850,
channelMessageSuggestionTonCommissionPermille: 850, channelMessageSuggestionTonCommissionPermille: 850,
channelMessageSuggestionMaxStarsAmount: 10000, channelMessageSuggestionMaxStarsAmount: 10000,
channelMessageSuggestionMaxTonAmount: 10000000000000 channelMessageSuggestionMaxTonAmount: 10000000000000,
channelMessageSuggestionMinStarsAmount: 5
) )
} }
@ -1528,6 +1529,7 @@ public struct StarsSubscriptionConfiguration {
public let channelMessageSuggestionTonCommissionPermille: Int32 public let channelMessageSuggestionTonCommissionPermille: Int32
public let channelMessageSuggestionMaxStarsAmount: Int64 public let channelMessageSuggestionMaxStarsAmount: Int64
public let channelMessageSuggestionMaxTonAmount: Int64 public let channelMessageSuggestionMaxTonAmount: Int64
public let channelMessageSuggestionMinStarsAmount: Int64
fileprivate init( fileprivate init(
maxFee: Int64, maxFee: Int64,
@ -1542,7 +1544,8 @@ public struct StarsSubscriptionConfiguration {
channelMessageSuggestionStarsCommissionPermille: Int32, channelMessageSuggestionStarsCommissionPermille: Int32,
channelMessageSuggestionTonCommissionPermille: Int32, channelMessageSuggestionTonCommissionPermille: Int32,
channelMessageSuggestionMaxStarsAmount: Int64, channelMessageSuggestionMaxStarsAmount: Int64,
channelMessageSuggestionMaxTonAmount: Int64 channelMessageSuggestionMaxTonAmount: Int64,
channelMessageSuggestionMinStarsAmount: Int64
) { ) {
self.maxFee = maxFee self.maxFee = maxFee
self.usdWithdrawRate = usdWithdrawRate self.usdWithdrawRate = usdWithdrawRate
@ -1557,6 +1560,7 @@ public struct StarsSubscriptionConfiguration {
self.channelMessageSuggestionTonCommissionPermille = channelMessageSuggestionTonCommissionPermille self.channelMessageSuggestionTonCommissionPermille = channelMessageSuggestionTonCommissionPermille
self.channelMessageSuggestionMaxStarsAmount = channelMessageSuggestionMaxStarsAmount self.channelMessageSuggestionMaxStarsAmount = channelMessageSuggestionMaxStarsAmount
self.channelMessageSuggestionMaxTonAmount = channelMessageSuggestionMaxTonAmount self.channelMessageSuggestionMaxTonAmount = channelMessageSuggestionMaxTonAmount
self.channelMessageSuggestionMinStarsAmount = channelMessageSuggestionMinStarsAmount
} }
public static func with(appConfiguration: AppConfiguration) -> StarsSubscriptionConfiguration { public static func with(appConfiguration: AppConfiguration) -> StarsSubscriptionConfiguration {
@ -1576,6 +1580,8 @@ public struct StarsSubscriptionConfiguration {
let channelMessageSuggestionMaxStarsAmount = (data["stars_suggested_post_amount_max"] as? Double).flatMap(Int64.init) ?? StarsSubscriptionConfiguration.defaultValue.channelMessageSuggestionMaxStarsAmount let channelMessageSuggestionMaxStarsAmount = (data["stars_suggested_post_amount_max"] as? Double).flatMap(Int64.init) ?? StarsSubscriptionConfiguration.defaultValue.channelMessageSuggestionMaxStarsAmount
let channelMessageSuggestionMaxTonAmount = (data["ton_suggested_post_amount_max"] as? Double).flatMap(Int64.init) ?? StarsSubscriptionConfiguration.defaultValue.channelMessageSuggestionMaxTonAmount let channelMessageSuggestionMaxTonAmount = (data["ton_suggested_post_amount_max"] as? Double).flatMap(Int64.init) ?? StarsSubscriptionConfiguration.defaultValue.channelMessageSuggestionMaxTonAmount
let channelMessageSuggestionMinStarsAmount = (data["stars_suggested_post_amount_min"] as? Double).flatMap(Int64.init) ?? StarsSubscriptionConfiguration.defaultValue.channelMessageSuggestionMinStarsAmount
return StarsSubscriptionConfiguration( return StarsSubscriptionConfiguration(
maxFee: maxFee, maxFee: maxFee,
usdWithdrawRate: usdWithdrawRate, usdWithdrawRate: usdWithdrawRate,
@ -1589,7 +1595,8 @@ public struct StarsSubscriptionConfiguration {
channelMessageSuggestionStarsCommissionPermille: channelMessageSuggestionStarsCommissionPermille, channelMessageSuggestionStarsCommissionPermille: channelMessageSuggestionStarsCommissionPermille,
channelMessageSuggestionTonCommissionPermille: channelMessageSuggestionTonCommissionPermille, channelMessageSuggestionTonCommissionPermille: channelMessageSuggestionTonCommissionPermille,
channelMessageSuggestionMaxStarsAmount: channelMessageSuggestionMaxStarsAmount, channelMessageSuggestionMaxStarsAmount: channelMessageSuggestionMaxStarsAmount,
channelMessageSuggestionMaxTonAmount: channelMessageSuggestionMaxTonAmount channelMessageSuggestionMaxTonAmount: channelMessageSuggestionMaxTonAmount,
channelMessageSuggestionMinStarsAmount: channelMessageSuggestionMinStarsAmount
) )
} else { } else {
return .defaultValue return .defaultValue

View File

@ -157,6 +157,7 @@ private final class SheetContent: CombinedComponent {
var amountRightLabel: String? var amountRightLabel: String?
let minAmount: StarsAmount? let minAmount: StarsAmount?
var allowZero = false
let maxAmount: StarsAmount? let maxAmount: StarsAmount?
let withdrawConfiguration = StarsWithdrawConfiguration.with(appConfiguration: component.context.currentAppConfiguration.with { $0 }) let withdrawConfiguration = StarsWithdrawConfiguration.with(appConfiguration: component.context.currentAppConfiguration.with { $0 })
@ -222,13 +223,14 @@ private final class SheetContent: CombinedComponent {
case .stars: case .stars:
amountTitle = "ENTER A PRICE IN STARS" amountTitle = "ENTER A PRICE IN STARS"
maxAmount = StarsAmount(value: resaleConfiguration.channelMessageSuggestionMaxStarsAmount, nanos: 0) maxAmount = StarsAmount(value: resaleConfiguration.channelMessageSuggestionMaxStarsAmount, nanos: 0)
minAmount = StarsAmount(value: resaleConfiguration.channelMessageSuggestionMinStarsAmount, nanos: 0)
case .ton: case .ton:
amountTitle = "ENTER A PRICE IN TON" amountTitle = "ENTER A PRICE IN TON"
maxAmount = StarsAmount(value: resaleConfiguration.channelMessageSuggestionMaxTonAmount, nanos: 0) maxAmount = StarsAmount(value: resaleConfiguration.channelMessageSuggestionMaxTonAmount, nanos: 0)
minAmount = StarsAmount(value: 0, nanos: 0)
} }
amountPlaceholder = "Price" amountPlaceholder = "Price"
allowZero = true
minAmount = StarsAmount(value: 0, nanos: 0)
if let usdWithdrawRate = withdrawConfiguration.usdWithdrawRate, let tonUsdRate = withdrawConfiguration.tonUsdRate, let amount = state.amount, amount > StarsAmount.zero { if let usdWithdrawRate = withdrawConfiguration.usdWithdrawRate, let tonUsdRate = withdrawConfiguration.tonUsdRate, let amount = state.amount, amount > StarsAmount.zero {
switch state.currency { switch state.currency {
@ -535,6 +537,7 @@ private final class SheetContent: CombinedComponent {
accentColor: theme.list.itemAccentColor, accentColor: theme.list.itemAccentColor,
value: state.amount?.value, value: state.amount?.value,
minValue: minAmount?.value, minValue: minAmount?.value,
allowZero: allowZero,
maxValue: maxAmount?.value, maxValue: maxAmount?.value,
placeholderText: amountPlaceholder, placeholderText: amountPlaceholder,
labelText: amountLabel, labelText: amountLabel,
@ -762,8 +765,8 @@ private final class SheetContent: CombinedComponent {
if let controller = controller() as? StarsWithdrawScreen, let state { if let controller = controller() as? StarsWithdrawScreen, let state {
let amount = state.amount ?? StarsAmount.zero let amount = state.amount ?? StarsAmount.zero
if let minAmount, amount < minAmount { if let minAmount, amount < minAmount, (!allowZero || amount != .zero) {
controller.presentMinAmountTooltip(minAmount.value) controller.presentMinAmountTooltip(minAmount.value, currency: state.currency)
} else { } else {
switch state.mode { switch state.mode {
case let .withdraw(_, completion): case let .withdraw(_, completion):
@ -1113,12 +1116,30 @@ public final class StarsWithdrawScreen: ViewControllerComponentContainer {
} }
} }
func presentMinAmountTooltip(_ minAmount: Int64) { func presentMinAmountTooltip(_ minAmount: Int64, currency: CurrencyAmount.Currency) {
let presentationData = self.context.sharedContext.currentPresentationData.with { $0 } let presentationData = self.context.sharedContext.currentPresentationData.with { $0 }
var text = presentationData.strings.Stars_Withdraw_Withdraw_ErrorMinimum(presentationData.strings.Stars_Withdraw_Withdraw_ErrorMinimum_Stars(Int32(minAmount))).string var text = presentationData.strings.Stars_Withdraw_Withdraw_ErrorMinimum(presentationData.strings.Stars_Withdraw_Withdraw_ErrorMinimum_Stars(Int32(minAmount))).string
if case .starGiftResell = self.mode { if case .starGiftResell = self.mode {
//TODO:localize //TODO:localize
text = "You cannot sell gift for less than \(presentationData.strings.Stars_Withdraw_Withdraw_ErrorMinimum_Stars(Int32(minAmount)))." text = "You cannot sell gift for less than \(presentationData.strings.Stars_Withdraw_Withdraw_ErrorMinimum_Stars(Int32(minAmount)))."
} else if case let .suggestedPost(mode, _, _, _) = self.mode {
let resaleConfiguration = StarsSubscriptionConfiguration.with(appConfiguration: self.context.currentAppConfiguration.with { $0 })
switch currency {
case .stars:
//TODO:localize
switch mode {
case .admin:
text = "You cannot request less than \(resaleConfiguration.channelMessageSuggestionMinStarsAmount) Stars."
case let .sender(_, isFromAdmin):
if isFromAdmin {
text = "You cannot request less than \(resaleConfiguration.channelMessageSuggestionMinStarsAmount) Stars."
} else {
text = "You cannot offer less than \(resaleConfiguration.channelMessageSuggestionMinStarsAmount) Stars."
}
}
case .ton:
break
}
} }
let resultController = UndoOverlayController( let resultController = UndoOverlayController(
@ -1153,17 +1174,19 @@ private final class AmountFieldStarsFormatter: NSObject, UITextFieldDelegate {
private let textField: UITextField private let textField: UITextField
private let minValue: Int64 private let minValue: Int64
private let allowZero: Bool
private let maxValue: Int64 private let maxValue: Int64
private let updated: (Int64) -> Void private let updated: (Int64) -> Void
private let isEmptyUpdated: (Bool) -> Void private let isEmptyUpdated: (Bool) -> Void
private let animateError: () -> Void private let animateError: () -> Void
private let focusUpdated: (Bool) -> Void private let focusUpdated: (Bool) -> Void
init?(textField: UITextField, currency: CurrencyAmount.Currency, dateTimeFormat: PresentationDateTimeFormat, minValue: Int64, maxValue: Int64, updated: @escaping (Int64) -> Void, isEmptyUpdated: @escaping (Bool) -> Void, animateError: @escaping () -> Void, focusUpdated: @escaping (Bool) -> Void) { init?(textField: UITextField, currency: CurrencyAmount.Currency, dateTimeFormat: PresentationDateTimeFormat, minValue: Int64, allowZero: Bool, maxValue: Int64, updated: @escaping (Int64) -> Void, isEmptyUpdated: @escaping (Bool) -> Void, animateError: @escaping () -> Void, focusUpdated: @escaping (Bool) -> Void) {
self.textField = textField self.textField = textField
self.currency = currency self.currency = currency
self.dateTimeFormat = dateTimeFormat self.dateTimeFormat = dateTimeFormat
self.minValue = minValue self.minValue = minValue
self.allowZero = allowZero
self.maxValue = maxValue self.maxValue = maxValue
self.updated = updated self.updated = updated
self.isEmptyUpdated = isEmptyUpdated self.isEmptyUpdated = isEmptyUpdated
@ -1307,6 +1330,7 @@ private final class AmountFieldComponent: Component {
let accentColor: UIColor let accentColor: UIColor
let value: Int64? let value: Int64?
let minValue: Int64? let minValue: Int64?
let allowZero: Bool
let maxValue: Int64? let maxValue: Int64?
let placeholderText: String let placeholderText: String
let labelText: String? let labelText: String?
@ -1322,6 +1346,7 @@ private final class AmountFieldComponent: Component {
accentColor: UIColor, accentColor: UIColor,
value: Int64?, value: Int64?,
minValue: Int64?, minValue: Int64?,
allowZero: Bool,
maxValue: Int64?, maxValue: Int64?,
placeholderText: String, placeholderText: String,
labelText: String?, labelText: String?,
@ -1336,6 +1361,7 @@ private final class AmountFieldComponent: Component {
self.accentColor = accentColor self.accentColor = accentColor
self.value = value self.value = value
self.minValue = minValue self.minValue = minValue
self.allowZero = allowZero
self.maxValue = maxValue self.maxValue = maxValue
self.placeholderText = placeholderText self.placeholderText = placeholderText
self.labelText = labelText self.labelText = labelText
@ -1364,6 +1390,9 @@ private final class AmountFieldComponent: Component {
if lhs.minValue != rhs.minValue { if lhs.minValue != rhs.minValue {
return false return false
} }
if lhs.allowZero != rhs.allowZero {
return false
}
if lhs.maxValue != rhs.maxValue { if lhs.maxValue != rhs.maxValue {
return false return false
} }
@ -1470,6 +1499,7 @@ private final class AmountFieldComponent: Component {
currency: component.currency, currency: component.currency,
dateTimeFormat: component.dateTimeFormat, dateTimeFormat: component.dateTimeFormat,
minValue: component.minValue ?? 0, minValue: component.minValue ?? 0,
allowZero: component.allowZero,
maxValue: component.maxValue ?? Int64.max, maxValue: component.maxValue ?? Int64.max,
updated: { [weak self] value in updated: { [weak self] value in
guard let self, let component = self.component else { guard let self, let component = self.component else {
@ -1505,6 +1535,7 @@ private final class AmountFieldComponent: Component {
currency: component.currency, currency: component.currency,
dateTimeFormat: component.dateTimeFormat, dateTimeFormat: component.dateTimeFormat,
minValue: component.minValue ?? 0, minValue: component.minValue ?? 0,
allowZero: component.allowZero,
maxValue: component.maxValue ?? 10000000, maxValue: component.maxValue ?? 10000000,
updated: { [weak self] value in updated: { [weak self] value in
guard let self, let component = self.component else { guard let self, let component = self.component else {