Various improvements

This commit is contained in:
Ilya Laktyushin 2024-05-25 03:45:32 +04:00
parent edd869c702
commit bb5789234c
5 changed files with 126 additions and 118 deletions

View File

@ -35,9 +35,8 @@ private final class DataAndStorageControllerArguments {
let openBrowserSelection: () -> Void let openBrowserSelection: () -> Void
let openIntents: () -> Void let openIntents: () -> Void
let toggleEnableSensitiveContent: (Bool) -> Void let toggleEnableSensitiveContent: (Bool) -> Void
let presentSensitiveContentConfirmation: () -> Void
init(openStorageUsage: @escaping () -> Void, openNetworkUsage: @escaping () -> Void, openProxy: @escaping () -> Void, openAutomaticDownloadConnectionType: @escaping (AutomaticDownloadConnectionType) -> Void, resetAutomaticDownload: @escaping () -> Void, toggleVoiceUseLessData: @escaping (Bool) -> Void, openSaveIncoming: @escaping (AutomaticSaveIncomingPeerType) -> Void, toggleSaveEditedPhotos: @escaping (Bool) -> Void, togglePauseMusicOnRecording: @escaping (Bool) -> Void, toggleRaiseToListen: @escaping (Bool) -> Void, toggleDownloadInBackground: @escaping (Bool) -> Void, openBrowserSelection: @escaping () -> Void, openIntents: @escaping () -> Void, toggleEnableSensitiveContent: @escaping (Bool) -> Void, presentSensitiveContentConfirmation: @escaping () -> Void) { init(openStorageUsage: @escaping () -> Void, openNetworkUsage: @escaping () -> Void, openProxy: @escaping () -> Void, openAutomaticDownloadConnectionType: @escaping (AutomaticDownloadConnectionType) -> Void, resetAutomaticDownload: @escaping () -> Void, toggleVoiceUseLessData: @escaping (Bool) -> Void, openSaveIncoming: @escaping (AutomaticSaveIncomingPeerType) -> Void, toggleSaveEditedPhotos: @escaping (Bool) -> Void, togglePauseMusicOnRecording: @escaping (Bool) -> Void, toggleRaiseToListen: @escaping (Bool) -> Void, toggleDownloadInBackground: @escaping (Bool) -> Void, openBrowserSelection: @escaping () -> Void, openIntents: @escaping () -> Void, toggleEnableSensitiveContent: @escaping (Bool) -> Void) {
self.openStorageUsage = openStorageUsage self.openStorageUsage = openStorageUsage
self.openNetworkUsage = openNetworkUsage self.openNetworkUsage = openNetworkUsage
self.openProxy = openProxy self.openProxy = openProxy
@ -52,7 +51,6 @@ private final class DataAndStorageControllerArguments {
self.openBrowserSelection = openBrowserSelection self.openBrowserSelection = openBrowserSelection
self.openIntents = openIntents self.openIntents = openIntents
self.toggleEnableSensitiveContent = toggleEnableSensitiveContent self.toggleEnableSensitiveContent = toggleEnableSensitiveContent
self.presentSensitiveContentConfirmation = presentSensitiveContentConfirmation
} }
} }
@ -112,7 +110,6 @@ private enum DataAndStorageEntry: ItemListNodeEntry {
case connectionHeader(PresentationTheme, String) case connectionHeader(PresentationTheme, String)
case connectionProxy(PresentationTheme, String, String) case connectionProxy(PresentationTheme, String, String)
case enableSensitiveContent(String, Bool) case enableSensitiveContent(String, Bool)
case enableSensitiveContentInfo(String)
var section: ItemListSectionId { var section: ItemListSectionId {
switch self { switch self {
@ -130,7 +127,7 @@ private enum DataAndStorageEntry: ItemListNodeEntry {
return DataAndStorageSection.other.rawValue return DataAndStorageSection.other.rawValue
case .connectionHeader, .connectionProxy: case .connectionHeader, .connectionProxy:
return DataAndStorageSection.connection.rawValue return DataAndStorageSection.connection.rawValue
case .enableSensitiveContent, .enableSensitiveContentInfo: case .enableSensitiveContent:
return DataAndStorageSection.enableSensitiveContent.rawValue return DataAndStorageSection.enableSensitiveContent.rawValue
} }
} }
@ -177,14 +174,12 @@ private enum DataAndStorageEntry: ItemListNodeEntry {
return 34 return 34
case .raiseToListenInfo: case .raiseToListenInfo:
return 35 return 35
case .enableSensitiveContent:
return 36
case .enableSensitiveContentInfo:
return 37
case .connectionHeader: case .connectionHeader:
return 38 return 36
case .connectionProxy: case .connectionProxy:
return 39 return 37
case .enableSensitiveContent:
return 38
} }
} }
@ -328,12 +323,6 @@ private enum DataAndStorageEntry: ItemListNodeEntry {
} else { } else {
return false return false
} }
case let .enableSensitiveContentInfo(text):
if case .enableSensitiveContentInfo(text) = rhs {
return true
} else {
return false
}
} }
} }
@ -432,15 +421,9 @@ private enum DataAndStorageEntry: ItemListNodeEntry {
arguments.openProxy() arguments.openProxy()
}) })
case let .enableSensitiveContent(text, value): case let .enableSensitiveContent(text, value):
return ItemListSwitchItem(presentationData: presentationData, title: text, value: value, enableInteractiveChanges: value, sectionId: self.section, style: .blocks, updated: { updatedValue in return ItemListSwitchItem(presentationData: presentationData, title: text, value: value, sectionId: self.section, style: .blocks, updated: { value in
if value { arguments.toggleEnableSensitiveContent(value)
arguments.toggleEnableSensitiveContent(updatedValue)
} else {
arguments.presentSensitiveContentConfirmation()
}
}, tag: nil) }, tag: nil)
case let .enableSensitiveContentInfo(text):
return ItemListTextItem(presentationData: presentationData, text: .markdown(text), sectionId: self.section)
} }
} }
} }
@ -644,14 +627,6 @@ private func dataAndStorageControllerEntries(state: DataAndStorageControllerStat
entries.append(.raiseToListen(presentationData.theme, presentationData.strings.Settings_RaiseToListen, data.mediaInputSettings.enableRaiseToSpeak)) entries.append(.raiseToListen(presentationData.theme, presentationData.strings.Settings_RaiseToListen, data.mediaInputSettings.enableRaiseToSpeak))
entries.append(.raiseToListenInfo(presentationData.theme, presentationData.strings.Settings_RaiseToListenInfo)) entries.append(.raiseToListenInfo(presentationData.theme, presentationData.strings.Settings_RaiseToListenInfo))
#if DEBUG
if let contentSettingsConfiguration = contentSettingsConfiguration { //, contentSettingsConfiguration.canAdjustSensitiveContent {
entries.append(.enableSensitiveContent("Show 18+ Content", contentSettingsConfiguration.sensitiveContentEnabled))
entries.append(.enableSensitiveContentInfo("Do not hide media that contain content suitable only for adults."))
}
#endif
let proxyValue: String let proxyValue: String
if let proxySettings = data.proxySettings, let activeServer = proxySettings.activeServer, proxySettings.enabled { if let proxySettings = data.proxySettings, let activeServer = proxySettings.activeServer, proxySettings.enabled {
switch activeServer.connection { switch activeServer.connection {
@ -666,6 +641,12 @@ private func dataAndStorageControllerEntries(state: DataAndStorageControllerStat
entries.append(.connectionHeader(presentationData.theme, presentationData.strings.ChatSettings_ConnectionType_Title.uppercased())) entries.append(.connectionHeader(presentationData.theme, presentationData.strings.ChatSettings_ConnectionType_Title.uppercased()))
entries.append(.connectionProxy(presentationData.theme, presentationData.strings.SocksProxySetup_Title, proxyValue)) entries.append(.connectionProxy(presentationData.theme, presentationData.strings.SocksProxySetup_Title, proxyValue))
#if DEBUG
if let contentSettingsConfiguration = contentSettingsConfiguration, contentSettingsConfiguration.canAdjustSensitiveContent {
entries.append(.enableSensitiveContent("Display Sensitive Content", contentSettingsConfiguration.sensitiveContentEnabled))
}
#endif
return entries return entries
} }
@ -798,8 +779,6 @@ public func dataAndStorageController(context: AccountContext, focusOnItemTag: Da
return DataAndStorageData(automaticMediaDownloadSettings: automaticMediaDownloadSettings, autodownloadSettings: autodownloadSettings, generatedMediaStoreSettings: generatedMediaStoreSettings, mediaInputSettings: mediaInputSettings, voiceCallSettings: voiceCallSettings, proxySettings: proxySettings) return DataAndStorageData(automaticMediaDownloadSettings: automaticMediaDownloadSettings, autodownloadSettings: autodownloadSettings, generatedMediaStoreSettings: generatedMediaStoreSettings, mediaInputSettings: mediaInputSettings, voiceCallSettings: voiceCallSettings, proxySettings: proxySettings)
}) })
var enableSensitiveContentImpl: (() -> Void)?
let arguments = DataAndStorageControllerArguments(openStorageUsage: { let arguments = DataAndStorageControllerArguments(openStorageUsage: {
pushControllerImpl?(StorageUsageScreen(context: context, makeStorageUsageExceptionsScreen: { category in pushControllerImpl?(StorageUsageScreen(context: context, makeStorageUsageExceptionsScreen: { category in
return storageUsageExceptionsScreen(context: context, category: category) return storageUsageExceptionsScreen(context: context, category: category)
@ -903,21 +882,7 @@ public func dataAndStorageController(context: AccountContext, focusOnItemTag: Da
} }
}) })
updateSensitiveContentDisposable.set(updateRemoteContentSettingsConfiguration(postbox: context.account.postbox, network: context.account.network, sensitiveContentEnabled: value).start()) updateSensitiveContentDisposable.set(updateRemoteContentSettingsConfiguration(postbox: context.account.postbox, network: context.account.network, sensitiveContentEnabled: value).start())
}, presentSensitiveContentConfirmation: {
let controller = textAlertController(context: context, title: "18+ Content", text: "Confirm that you are over 18 years old and update your settings to see potentially explicit and sensitive content.", actions: [
TextAlertAction(type: .genericAction, title: "Cancel", action: {
}),
TextAlertAction(type: .defaultAction, title: "Confirm", action: {
enableSensitiveContentImpl?()
}) })
])
presentControllerImpl?(controller, nil)
})
enableSensitiveContentImpl = {
arguments.toggleEnableSensitiveContent(true)
}
let preferencesKey: PostboxViewKey = .preferences(keys: Set([ApplicationSpecificPreferencesKeys.mediaAutoSaveSettings])) let preferencesKey: PostboxViewKey = .preferences(keys: Set([ApplicationSpecificPreferencesKeys.mediaAutoSaveSettings]))
let preferences = context.account.postbox.combinedView(keys: [preferencesKey]) let preferences = context.account.postbox.combinedView(keys: [preferencesKey])

View File

@ -130,8 +130,6 @@ private final class StarsPurchaseScreenContentComponent: CombinedComponent {
private var disposable: Disposable? private var disposable: Disposable?
var cachedChevronImage: (UIImage, PresentationTheme)?
init( init(
context: AccountContext, context: AccountContext,
peerId: EnginePeer.Id? peerId: EnginePeer.Id?
@ -553,8 +551,6 @@ private final class StarsPurchaseScreenComponent: CombinedComponent {
private var disposable: Disposable? private var disposable: Disposable?
private var paymentDisposable = MetaDisposable() private var paymentDisposable = MetaDisposable()
var cachedChevronImage: (UIImage, PresentationTheme)?
init( init(
context: AccountContext, context: AccountContext,
starsContext: StarsContext, starsContext: StarsContext,
@ -696,7 +692,9 @@ private final class StarsPurchaseScreenComponent: CombinedComponent {
let topPanel = Child(BlurredBackgroundComponent.self) let topPanel = Child(BlurredBackgroundComponent.self)
let topSeparator = Child(Rectangle.self) let topSeparator = Child(Rectangle.self)
let title = Child(MultilineTextComponent.self) let title = Child(MultilineTextComponent.self)
let balanceText = Child(MultilineTextComponent.self) let balanceTitle = Child(MultilineTextComponent.self)
let balanceValue = Child(MultilineTextComponent.self)
let balanceIcon = Child(BundleIconComponent.self)
let scrollAction = ActionSlot<CGPoint?>() let scrollAction = ActionSlot<CGPoint?>()
@ -765,32 +763,33 @@ private final class StarsPurchaseScreenComponent: CombinedComponent {
transition: context.transition transition: context.transition
) )
let textColor = environment.theme.list.itemPrimaryTextColor let balanceTitle = balanceTitle.update(
let accentColor = UIColor(rgb: 0x597cf5)
let textFont = Font.regular(14.0)
let boldTextFont = Font.bold(14.0)
let markdownAttributes = MarkdownAttributes(body: MarkdownAttributeSet(font: textFont, textColor: textColor), bold: MarkdownAttributeSet(font: boldTextFont, textColor: textColor), link: MarkdownAttributeSet(font: textFont, textColor: accentColor), linkAttribute: { _ in
return nil
})
if state.cachedChevronImage == nil || state.cachedChevronImage?.1 !== environment.theme {
state.cachedChevronImage = (generateTintedImage(image: UIImage(bundleImageName: "Item List/PremiumIcon"), color: UIColor(rgb: 0xf09903))!, environment.theme)
}
let balanceAttributedString = parseMarkdownIntoAttributedString(" \(strings.Stars_Purchase_Balance)\n # **\(state.starsState?.balance ?? 0)**", attributes: markdownAttributes, textAlignment: .right).mutableCopy() as! NSMutableAttributedString
if let range = balanceAttributedString.string.range(of: "#"), let chevronImage = state.cachedChevronImage?.0 {
balanceAttributedString.addAttribute(.attachment, value: chevronImage, range: NSRange(range, in: balanceAttributedString.string))
balanceAttributedString.addAttribute(.foregroundColor, value: UIColor(rgb: 0xf09903), range: NSRange(range, in: balanceAttributedString.string))
balanceAttributedString.addAttribute(.baselineOffset, value: 2.0, range: NSRange(range, in: balanceAttributedString.string))
}
let balanceText = balanceText.update(
component: MultilineTextComponent( component: MultilineTextComponent(
text: .plain(balanceAttributedString), text: .plain(NSAttributedString(
horizontalAlignment: .left, string: environment.strings.Stars_Purchase_Balance,
maximumNumberOfLines: 0 font: Font.regular(14.0),
textColor: environment.theme.actionSheet.primaryTextColor
)),
maximumNumberOfLines: 1
), ),
availableSize: CGSize(width: 200, height: context.availableSize.height), availableSize: context.availableSize,
transition: .immediate
)
let balanceValue = balanceValue.update(
component: MultilineTextComponent(
text: .plain(NSAttributedString(
string: presentationStringsFormattedNumber(Int32(state.starsState?.balance ?? 0), environment.dateTimeFormat.decimalSeparator),
font: Font.semibold(14.0),
textColor: environment.theme.actionSheet.primaryTextColor
)),
maximumNumberOfLines: 1
),
availableSize: context.availableSize,
transition: .immediate
)
let balanceIcon = balanceIcon.update(
component: BundleIconComponent(name: "Premium/Stars/StarSmall", tintColor: nil),
availableSize: context.availableSize,
transition: .immediate transition: .immediate
) )
@ -890,8 +889,16 @@ private final class StarsPurchaseScreenComponent: CombinedComponent {
.opacity(titleAlpha) .opacity(titleAlpha)
) )
context.add(balanceText let navigationHeight = environment.navigationHeight - environment.statusBarHeight
.position(CGPoint(x: context.availableSize.width - 16.0 - balanceText.size.width / 2.0, y: 28.0)) let topBalanceOriginY = environment.statusBarHeight + (navigationHeight - balanceTitle.size.height - balanceValue.size.height) / 2.0
context.add(balanceTitle
.position(CGPoint(x: context.availableSize.width - 16.0 - environment.safeInsets.right - balanceTitle.size.width / 2.0, y: topBalanceOriginY + balanceTitle.size.height / 2.0))
)
context.add(balanceValue
.position(CGPoint(x: context.availableSize.width - 16.0 - environment.safeInsets.right - balanceValue.size.width / 2.0, y: topBalanceOriginY + balanceTitle.size.height + balanceValue.size.height / 2.0))
)
context.add(balanceIcon
.position(CGPoint(x: context.availableSize.width - 16.0 - environment.safeInsets.right - balanceValue.size.width - balanceIcon.size.width / 2.0 - 2.0, y: topBalanceOriginY + balanceTitle.size.height + balanceValue.size.height / 2.0 - UIScreenPixel))
) )
return context.availableSize return context.availableSize

View File

@ -285,7 +285,7 @@ final class StarsTransactionsListPanelComponent: Component {
component: AnyComponent(ListActionItemComponent( component: AnyComponent(ListActionItemComponent(
theme: environment.theme, theme: environment.theme,
title: AnyComponent(VStack(titleComponents, alignment: .left, spacing: 2.0)), title: AnyComponent(VStack(titleComponents, alignment: .left, spacing: 2.0)),
contentInsets: UIEdgeInsets(top: 9.0, left: 0.0, bottom: 8.0, right: 0.0), contentInsets: UIEdgeInsets(top: 9.0, left: environment.containerInsets.left, bottom: 8.0, right: environment.containerInsets.right),
leftIcon: .custom(AnyComponentWithIdentity(id: "avatar", component: AnyComponent(AvatarComponent(context: component.context, theme: environment.theme, peer: item.transaction.peer))), false), leftIcon: .custom(AnyComponentWithIdentity(id: "avatar", component: AnyComponent(AvatarComponent(context: component.context, theme: environment.theme, peer: item.transaction.peer))), false),
icon: nil, icon: nil,
accessory: .custom(ListActionItemComponent.CustomAccessory(component: AnyComponentWithIdentity(id: "label", component: AnyComponent(LabelComponent(text: itemLabel))), insets: UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 16.0))), accessory: .custom(ListActionItemComponent.CustomAccessory(component: AnyComponentWithIdentity(id: "label", component: AnyComponent(LabelComponent(text: itemLabel))), insets: UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 16.0))),
@ -306,7 +306,7 @@ final class StarsTransactionsListPanelComponent: Component {
} }
itemTransition.setFrame(view: itemComponentView, frame: itemFrame) itemTransition.setFrame(view: itemComponentView, frame: itemFrame)
} }
let sideInset: CGFloat = 60.0 let sideInset: CGFloat = 60.0 + environment.containerInsets.left
itemTransition.setFrame(view: separatorView, frame: CGRect(x: sideInset, y: itemFrame.maxY, width: itemFrame.width - sideInset, height: UIScreenPixel)) itemTransition.setFrame(view: separatorView, frame: CGRect(x: sideInset, y: itemFrame.maxY, width: itemFrame.width - sideInset, height: UIScreenPixel))
} }
} }

View File

@ -426,7 +426,6 @@ final class StarsTransactionsScreenComponent: Component {
font: Font.regular(14.0), font: Font.regular(14.0),
textColor: environment.theme.actionSheet.primaryTextColor textColor: environment.theme.actionSheet.primaryTextColor
)), )),
horizontalAlignment: .right,
maximumNumberOfLines: 1 maximumNumberOfLines: 1
)), )),
environment: {}, environment: {},
@ -441,7 +440,6 @@ final class StarsTransactionsScreenComponent: Component {
font: Font.semibold(14.0), font: Font.semibold(14.0),
textColor: environment.theme.actionSheet.primaryTextColor textColor: environment.theme.actionSheet.primaryTextColor
)), )),
horizontalAlignment: .right,
maximumNumberOfLines: 1 maximumNumberOfLines: 1
)), )),
environment: {}, environment: {},
@ -456,7 +454,7 @@ final class StarsTransactionsScreenComponent: Component {
let navigationHeight = environment.navigationHeight - environment.statusBarHeight let navigationHeight = environment.navigationHeight - environment.statusBarHeight
let topBalanceOriginY = environment.statusBarHeight + (navigationHeight - topBalanceTitleSize.height - topBalanceValueSize.height) / 2.0 let topBalanceOriginY = environment.statusBarHeight + (navigationHeight - topBalanceTitleSize.height - topBalanceValueSize.height) / 2.0
let topBalanceTitleFrame = CGRect(origin: CGPoint(x: availableSize.width - topBalanceTitleSize.width - 16.0, y: topBalanceOriginY), size: topBalanceTitleSize) let topBalanceTitleFrame = CGRect(origin: CGPoint(x: availableSize.width - topBalanceTitleSize.width - 16.0 - environment.safeInsets.right, y: topBalanceOriginY), size: topBalanceTitleSize)
if let topBalanceTitleView = self.topBalanceTitleView.view { if let topBalanceTitleView = self.topBalanceTitleView.view {
if topBalanceTitleView.superview == nil { if topBalanceTitleView.superview == nil {
topBalanceTitleView.alpha = 0.0 topBalanceTitleView.alpha = 0.0
@ -465,7 +463,7 @@ final class StarsTransactionsScreenComponent: Component {
starTransition.setFrame(view: topBalanceTitleView, frame: topBalanceTitleFrame) starTransition.setFrame(view: topBalanceTitleView, frame: topBalanceTitleFrame)
} }
let topBalanceValueFrame = CGRect(origin: CGPoint(x: availableSize.width - topBalanceValueSize.width - 16.0, y: topBalanceTitleFrame.maxY), size: topBalanceValueSize) let topBalanceValueFrame = CGRect(origin: CGPoint(x: availableSize.width - topBalanceValueSize.width - 16.0 - environment.safeInsets.right, y: topBalanceTitleFrame.maxY), size: topBalanceValueSize)
if let topBalanceValueView = self.topBalanceValueView.view { if let topBalanceValueView = self.topBalanceValueView.view {
if topBalanceValueView.superview == nil { if topBalanceValueView.superview == nil {
topBalanceValueView.alpha = 0.0 topBalanceValueView.alpha = 0.0

View File

@ -11,11 +11,12 @@ import ViewControllerComponent
import SheetComponent import SheetComponent
import BalancedTextComponent import BalancedTextComponent
import MultilineTextComponent import MultilineTextComponent
import BundleIconComponent
import ButtonComponent
import PremiumStarComponent
import ItemListUI import ItemListUI
import UndoUI import UndoUI
import AccountContext import AccountContext
import PremiumStarComponent
import ButtonComponent
private final class SheetContent: CombinedComponent { private final class SheetContent: CombinedComponent {
typealias EnvironmentType = ViewControllerComponentContainer.Environment typealias EnvironmentType = ViewControllerComponentContainer.Environment
@ -55,7 +56,6 @@ private final class SheetContent: CombinedComponent {
final class State: ComponentState { final class State: ComponentState {
var cachedCloseImage: (UIImage, PresentationTheme)? var cachedCloseImage: (UIImage, PresentationTheme)?
var cachedChevronImage: (UIImage, PresentationTheme)?
var cachedStarImage: (UIImage, PresentationTheme)? var cachedStarImage: (UIImage, PresentationTheme)?
private let context: AccountContext private let context: AccountContext
@ -68,7 +68,12 @@ private final class SheetContent: CombinedComponent {
private(set) var form: BotPaymentForm? private(set) var form: BotPaymentForm?
private var optionsDisposable: Disposable? private var optionsDisposable: Disposable?
private(set) var options: [StarsTopUpOption] = [] private(set) var options: [StarsTopUpOption] = [] {
didSet {
self.optionsPromise.set(self.options)
}
}
private let optionsPromise = ValuePromise<[StarsTopUpOption]?>(nil)
var inProgress = false var inProgress = false
@ -94,7 +99,7 @@ private final class SheetContent: CombinedComponent {
self.peer = inputData?.2 self.peer = inputData?.2
self.updated(transition: .immediate) self.updated(transition: .immediate)
if self.optionsDisposable != nil { if self.optionsDisposable == nil, let balance = self.balance, balance < self.invoice.totalAmount {
self.optionsDisposable = (context.engine.payments.starsTopUpOptions() self.optionsDisposable = (context.engine.payments.starsTopUpOptions()
|> deliverOnMainQueue).start(next: { [weak self] options in |> deliverOnMainQueue).start(next: { [weak self] options in
guard let self else { guard let self else {
@ -111,12 +116,15 @@ private final class SheetContent: CombinedComponent {
self.optionsDisposable?.dispose() self.optionsDisposable?.dispose()
} }
func buy(requestTopUp: (@escaping () -> Void) -> Void, completion: @escaping () -> Void) { func buy(requestTopUp: @escaping (@escaping () -> Void) -> Void, completion: @escaping () -> Void) {
guard let form, let balance else { guard let form, let balance else {
return return
} }
let action = { let action = { [weak self] in
guard let self else {
return
}
self.inProgress = true self.inProgress = true
self.updated() self.updated()
@ -127,9 +135,22 @@ private final class SheetContent: CombinedComponent {
} }
if balance < self.invoice.totalAmount { if balance < self.invoice.totalAmount {
if self.options.isEmpty {
self.inProgress = true
self.updated()
}
let _ = (self.optionsPromise.get()
|> filter { $0 != nil}
|> take(1)
|> deliverOnMainQueue).startStandalone(next: { [weak self] _ in
if let self {
self.inProgress = false
self.updated()
}
requestTopUp({ requestTopUp({
action() action()
}) })
})
} else { } else {
action() action()
} }
@ -146,8 +167,10 @@ private final class SheetContent: CombinedComponent {
let closeButton = Child(Button.self) let closeButton = Child(Button.self)
let title = Child(Text.self) let title = Child(Text.self)
let text = Child(BalancedTextComponent.self) let text = Child(BalancedTextComponent.self)
let balanceText = Child(MultilineTextComponent.self)
let button = Child(ButtonComponent.self) let button = Child(ButtonComponent.self)
let balanceTitle = Child(MultilineTextComponent.self)
let balanceValue = Child(MultilineTextComponent.self)
let balanceIcon = Child(BundleIconComponent.self)
return { context in return { context in
let environment = context.environment[EnvironmentType.self] let environment = context.environment[EnvironmentType.self]
@ -261,30 +284,45 @@ private final class SheetContent: CombinedComponent {
contentSize.height += text.size.height contentSize.height += text.size.height
contentSize.height += 28.0 contentSize.height += 28.0
if state.cachedChevronImage == nil || state.cachedChevronImage?.1 !== theme { let balanceTitle = balanceTitle.update(
state.cachedChevronImage = (generateTintedImage(image: UIImage(bundleImageName: "Premium/Stars/StarLarge"), color: UIColor(rgb: 0xf09903))!, theme)
}
let balanceValue = presentationStringsFormattedNumber(Int32(state.balance ?? 0), environment.dateTimeFormat.decimalSeparator)
let balanceAttributedString = NSMutableAttributedString(string: strings.Stars_Transfer_Balance, font: Font.regular(14.0), textColor: textColor)
balanceAttributedString.append(NSMutableAttributedString(string: "\n # \(balanceValue)", font: Font.semibold(16.0), textColor: textColor))
if let range = balanceAttributedString.string.range(of: "#"), let chevronImage = state.cachedChevronImage?.0 {
balanceAttributedString.addAttribute(.attachment, value: chevronImage, range: NSRange(range, in: balanceAttributedString.string))
balanceAttributedString.addAttribute(.foregroundColor, value: UIColor(rgb: 0xf09903), range: NSRange(range, in: balanceAttributedString.string))
balanceAttributedString.addAttribute(.baselineOffset, value: 2.0, range: NSRange(range, in: balanceAttributedString.string))
}
let balanceText = balanceText.update(
component: MultilineTextComponent( component: MultilineTextComponent(
text: .plain(balanceAttributedString), text: .plain(NSAttributedString(
horizontalAlignment: .left, string: environment.strings.Stars_Transfer_Balance,
maximumNumberOfLines: 0, font: Font.regular(14.0),
lineSpacing: 0.25 textColor: textColor
)),
maximumNumberOfLines: 1
), ),
availableSize: CGSize(width: constrainedTitleWidth, height: context.availableSize.height), availableSize: context.availableSize,
transition: .immediate transition: .immediate
) )
context.add(balanceText let balanceValue = balanceValue.update(
.position(CGPoint(x: 16.0 + balanceText.size.width / 2.0, y: 31.0)) component: MultilineTextComponent(
text: .plain(NSAttributedString(
string: presentationStringsFormattedNumber(Int32(state.balance ?? 0), environment.dateTimeFormat.decimalSeparator),
font: Font.semibold(16.0),
textColor: textColor
)),
maximumNumberOfLines: 1
),
availableSize: context.availableSize,
transition: .immediate
)
let balanceIcon = balanceIcon.update(
component: BundleIconComponent(name: "Premium/Stars/StarMedium", tintColor: nil),
availableSize: context.availableSize,
transition: .immediate
)
let topBalanceOriginY = 11.0
context.add(balanceTitle
.position(CGPoint(x: 16.0 + environment.safeInsets.left + balanceTitle.size.width / 2.0, y: topBalanceOriginY + balanceTitle.size.height / 2.0))
)
context.add(balanceIcon
.position(CGPoint(x: 16.0 + environment.safeInsets.left + balanceIcon.size.width / 2.0, y: topBalanceOriginY + balanceTitle.size.height + balanceValue.size.height / 2.0 - UIScreenPixel))
)
context.add(balanceValue
.position(CGPoint(x: 16.0 + environment.safeInsets.left + balanceIcon.size.width + 3.0 + balanceValue.size.width / 2.0, y: topBalanceOriginY + balanceTitle.size.height + balanceValue.size.height / 2.0))
) )
if state.cachedStarImage == nil || state.cachedStarImage?.1 !== theme { if state.cachedStarImage == nil || state.cachedStarImage?.1 !== theme {