chore: migrate to new version + fixed several critical bugs

- Migrated project to latest Telegram iOS base (v12.3.2+)
- Fixed circular dependency between GhostModeManager and MiscSettingsManager
- Fixed multiple Bazel build configuration errors (select() default conditions)
- Fixed duplicate type definitions in PeerInfoScreen
- Fixed swiftmodule directory resolution in build scripts
- Added Ghostgram Settings tab in main Settings menu with all 5 features
- Cleared sensitive credentials from config.json (template-only now)
- Excluded bazel-cache from version control
This commit is contained in:
ichmagmaus 812
2026-02-23 23:04:32 +01:00
parent 703e291bcb
commit db53826061
1017 changed files with 62323 additions and 40545 deletions
@@ -23,6 +23,8 @@ swift_library(
"//submodules/TelegramUI/Components/ButtonComponent",
"//submodules/TelegramUI/Components/LottieComponent",
"//submodules/TelegramCore",
"//submodules/TelegramUI/Components/GlassBarButtonComponent",
],
visibility = [
"//visibility:public",
@@ -14,6 +14,7 @@ import TelegramStringFormatting
import BundleIconComponent
import TelegramCore
import TelegramPresentationData
import GlassBarButtonComponent
private final class BalanceNeededSheetContentComponent: Component {
typealias EnvironmentType = ViewControllerComponentContainer.Environment
@@ -49,9 +50,7 @@ private final class BalanceNeededSheetContentComponent: Component {
private var component: BalanceNeededSheetContentComponent?
private weak var state: EmptyComponentState?
private var cachedCloseImage: (UIImage, PresentationTheme)?
override init(frame: CGRect) {
super.init(frame: frame)
}
@@ -71,28 +70,27 @@ private final class BalanceNeededSheetContentComponent: Component {
let sideInset: CGFloat = 16.0
let closeImage: UIImage
if let (image, theme) = self.cachedCloseImage, theme === environment.theme {
closeImage = image
} else {
closeImage = generateCloseButtonImage(backgroundColor: UIColor(rgb: 0x808084, alpha: 0.1), foregroundColor: environment.theme.actionSheet.inputClearButtonColor)!
self.cachedCloseImage = (closeImage, environment.theme)
}
let closeButtonSize = self.closeButton.update(
transition: .immediate,
component: AnyComponent(Button(
content: AnyComponent(Image(image: closeImage)),
action: { [weak self] in
guard let self, let component = self.component else {
return
}
component: AnyComponent(GlassBarButtonComponent(
size: CGSize(width: 40.0, height: 40.0),
backgroundColor: environment.theme.rootController.navigationBar.glassBarButtonBackgroundColor,
isDark: environment.theme.overallDarkAppearance,
state: .generic,
component: AnyComponentWithIdentity(id: "close", component: AnyComponent(
BundleIconComponent(
name: "Navigation/Close",
tintColor: environment.theme.chat.inputPanel.panelControlColor
)
)),
action: { _ in
component.dismiss()
}
)),
environment: {},
containerSize: CGSize(width: 30.0, height: 30.0)
containerSize: CGSize(width: 40.0, height: 40.0)
)
let closeButtonFrame = CGRect(origin: CGPoint(x: availableSize.width - closeButtonSize.width - 16.0, y: 12.0), size: closeButtonSize)
let closeButtonFrame = CGRect(origin: CGPoint(x: 16.0, y: 16.0), size: closeButtonSize)
if let closeButtonView = self.closeButton.view {
if closeButtonView.superview == nil {
self.addSubview(closeButtonView)
@@ -164,10 +162,12 @@ private final class BalanceNeededSheetContentComponent: Component {
contentHeight += textSize.height
contentHeight += 24.0
let buttonInsets = ContainerViewLayout.concentricInsets(bottomInset: environment.safeInsets.bottom, innerDiameter: 52.0, sideInset: 30.0)
let buttonSize = self.button.update(
transition: transition,
component: AnyComponent(ButtonComponent(
background: ButtonComponent.Background(
style: .glass,
color: environment.theme.list.itemCheckColors.fillColor,
foreground: environment.theme.list.itemCheckColors.foregroundColor,
pressedColor: environment.theme.list.itemCheckColors.fillColor.withMultipliedAlpha(0.8)
@@ -187,9 +187,9 @@ private final class BalanceNeededSheetContentComponent: Component {
}
)),
environment: {},
containerSize: CGSize(width: availableSize.width - sideInset * 2.0, height: 50.0)
containerSize: CGSize(width: availableSize.width - buttonInsets.left - buttonInsets.right, height: 52.0)
)
let buttonFrame = CGRect(origin: CGPoint(x: sideInset, y: contentHeight), size: buttonSize)
let buttonFrame = CGRect(origin: CGPoint(x: buttonInsets.left, y: contentHeight), size: buttonSize)
if let buttonView = self.button.view {
if buttonView.superview == nil {
self.addSubview(buttonView)
@@ -197,13 +197,8 @@ private final class BalanceNeededSheetContentComponent: Component {
transition.setFrame(view: buttonView, frame: buttonFrame)
}
contentHeight += buttonSize.height
if environment.safeInsets.bottom.isZero {
contentHeight += 16.0
} else {
contentHeight += environment.safeInsets.bottom + 8.0
}
contentHeight += buttonInsets.bottom
return CGSize(width: availableSize.width, height: contentHeight)
}
}
@@ -307,6 +302,7 @@ private final class BalanceNeededScreenComponent: Component {
})
}
)),
style: .glass,
backgroundColor: .color(environment.theme.actionSheet.opaqueItemBackgroundColor),
animateOut: self.sheetAnimateOut
)),
@@ -504,6 +504,7 @@ private final class StarsPurchaseScreenComponent: CombinedComponent {
typealias EnvironmentType = ViewControllerComponentContainer.Environment
let context: AccountContext
let overNavigationContainer: UIView
let starsContext: StarsContext
let options: [Any]
let purpose: StarsPurchasePurpose
@@ -515,6 +516,7 @@ private final class StarsPurchaseScreenComponent: CombinedComponent {
init(
context: AccountContext,
overNavigationContainer: UIView,
starsContext: StarsContext,
options: [Any],
purpose: StarsPurchasePurpose,
@@ -525,6 +527,7 @@ private final class StarsPurchaseScreenComponent: CombinedComponent {
completion: @escaping (Int64) -> Void
) {
self.context = context
self.overNavigationContainer = overNavigationContainer
self.starsContext = starsContext
self.options = options
self.purpose = purpose
@@ -759,8 +762,6 @@ private final class StarsPurchaseScreenComponent: CombinedComponent {
let scrollContent = Child(ScrollComponent<EnvironmentType>.self)
let star = Child(PremiumStarComponent.self)
let avatar = Child(GiftAvatarComponent.self)
let topPanel = Child(BlurredBackgroundComponent.self)
let topSeparator = Child(Rectangle.self)
let title = Child(MultilineTextComponent.self)
let balanceTitle = Child(MultilineTextComponent.self)
let balanceValue = Child(MultilineTextComponent.self)
@@ -816,29 +817,13 @@ private final class StarsPurchaseScreenComponent: CombinedComponent {
UIColor(rgb: 0xfdd219)
],
particleColor: UIColor(rgb: 0xf9b004),
backgroundColor: environment.theme.list.blocksBackgroundColor
backgroundColor: nil
),
availableSize: CGSize(width: min(414.0, context.availableSize.width), height: 220.0),
transition: context.transition
)
}
let topPanel = topPanel.update(
component: BlurredBackgroundComponent(
color: environment.theme.rootController.navigationBar.blurredBackgroundColor
),
availableSize: CGSize(width: context.availableSize.width, height: environment.navigationHeight),
transition: context.transition
)
let topSeparator = topSeparator.update(
component: Rectangle(
color: environment.theme.rootController.navigationBar.separatorColor
),
availableSize: CGSize(width: context.availableSize.width, height: UIScreenPixel),
transition: context.transition
)
let titleText: String
switch context.component.purpose {
case .generic:
@@ -948,14 +933,12 @@ private final class StarsPurchaseScreenComponent: CombinedComponent {
.position(CGPoint(x: context.availableSize.width / 2.0, y: context.availableSize.height / 2.0))
)
let topPanelAlpha: CGFloat
let titleOffset: CGFloat
let titleScale: CGFloat
let titleOffsetDelta = (topInset + 160.0) - (environment.statusBarHeight + (environment.navigationHeight - environment.statusBarHeight) / 2.0)
let titleAlpha: CGFloat
if let topContentOffset = state.topContentOffset {
topPanelAlpha = min(20.0, max(0.0, topContentOffset - 95.0)) / 20.0
let topContentOffset = topContentOffset + max(0.0, min(1.0, topContentOffset / titleOffsetDelta)) * 10.0
titleOffset = topContentOffset
let fraction = max(0.0, min(1.0, titleOffset / titleOffsetDelta))
@@ -963,42 +946,37 @@ private final class StarsPurchaseScreenComponent: CombinedComponent {
titleAlpha = 1.0
} else {
topPanelAlpha = 0.0
titleScale = 1.0
titleOffset = 0.0
titleAlpha = 1.0
}
context.add(header
context.addWithExternalContainer(header
.position(CGPoint(x: context.availableSize.width / 2.0, y: topInset + header.size.height / 2.0 - 30.0 - titleOffset * titleScale))
.scale(titleScale)
.scale(titleScale),
container: context.component.overNavigationContainer
)
context.add(topPanel
.position(CGPoint(x: context.availableSize.width / 2.0, y: topPanel.size.height / 2.0))
.opacity(topPanelAlpha)
)
context.add(topSeparator
.position(CGPoint(x: context.availableSize.width / 2.0, y: topPanel.size.height))
.opacity(topPanelAlpha)
)
context.add(title
context.addWithExternalContainer(title
.position(CGPoint(x: context.availableSize.width / 2.0, y: max(topInset + 160.0 - titleOffset, environment.statusBarHeight + (environment.navigationHeight - environment.statusBarHeight) / 2.0)))
.scale(titleScale)
.opacity(titleAlpha)
.opacity(titleAlpha),
container: context.component.overNavigationContainer
)
let navigationHeight = environment.navigationHeight - environment.statusBarHeight
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.addWithExternalContainer(balanceTitle
.position(CGPoint(x: context.availableSize.width - 16.0 - environment.safeInsets.right - balanceTitle.size.width / 2.0, y: topBalanceOriginY + balanceTitle.size.height / 2.0)),
container: context.component.overNavigationContainer
)
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.addWithExternalContainer(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)),
container: context.component.overNavigationContainer
)
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))
context.addWithExternalContainer(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)),
container: context.component.overNavigationContainer
)
return context.availableSize
@@ -1010,6 +988,8 @@ public final class StarsPurchaseScreen: ViewControllerComponentContainer {
fileprivate let context: AccountContext
fileprivate let starsContext: StarsContext
private let overNavigationContainer: UIView
private var didSetReady = false
private let _ready = Promise<Bool>()
public override var ready: Promise<Bool> {
@@ -1027,6 +1007,8 @@ public final class StarsPurchaseScreen: ViewControllerComponentContainer {
) {
self.context = context
self.starsContext = starsContext
self.overNavigationContainer = SparseContainerView()
var openAppExamplesImpl: (() -> Void)?
var updateInProgressImpl: ((Bool) -> Void)?
@@ -1034,6 +1016,7 @@ public final class StarsPurchaseScreen: ViewControllerComponentContainer {
var completionImpl: ((Int64) -> Void)?
super.init(context: context, component: StarsPurchaseScreenComponent(
context: context,
overNavigationContainer: self.overNavigationContainer,
starsContext: starsContext,
options: options,
purpose: purpose,
@@ -1050,7 +1033,7 @@ public final class StarsPurchaseScreen: ViewControllerComponentContainer {
completion: { stars in
completionImpl?(stars)
}
), navigationBarAppearance: .transparent, presentationMode: .modal, theme: customTheme.flatMap { .custom($0) } ?? .default)
), navigationBarAppearance: .default, presentationMode: .modal, theme: customTheme.flatMap { .custom($0) } ?? .default)
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
@@ -1090,6 +1073,10 @@ public final class StarsPurchaseScreen: ViewControllerComponentContainer {
completion(stars)
}
}
if let navigationBar = self.navigationBar {
navigationBar.customOverBackgroundContentView.insertSubview(self.overNavigationContainer, at: 0)
}
}
required public init(coder aDecoder: NSCoder) {
@@ -1129,10 +1116,10 @@ public final class StarsPurchaseScreen: ViewControllerComponentContainer {
super.containerLayoutUpdated(layout, transition: transition)
if !self.didSetReady {
if let view = self.node.hostView.findTaggedView(tag: PremiumStarComponent.View.Tag()) as? PremiumStarComponent.View {
if let view = findTaggedComponentViewImpl(view: self.node.view, tag: PremiumStarComponent.View.Tag()) as? PremiumStarComponent.View {
self.didSetReady = true
self._ready.set(view.ready)
} else if let view = self.node.hostView.findTaggedView(tag: GiftAvatarComponent.View.Tag()) as? GiftAvatarComponent.View {
} else if let view = findTaggedComponentViewImpl(view: self.node.view, tag: GiftAvatarComponent.View.Tag()) as? GiftAvatarComponent.View {
self.didSetReady = true
self._ready.set(view.ready)
}
@@ -39,6 +39,8 @@ swift_library(
"//submodules/TelegramUI/Components/Premium/PremiumStarComponent",
"//submodules/TelegramUI/Components/Gifts/GiftAnimationComponent",
"//submodules/TelegramUI/Components/GlassBarButtonComponent",
"//submodules/TelegramUI/Components/Gifts/TableComponent",
"//submodules/TelegramUI/Components/Gifts/PeerTableCellComponent",
],
visibility = [
"//visibility:public",
@@ -28,6 +28,8 @@ import MiniAppListScreen
import PremiumStarComponent
import GiftAnimationComponent
import GlassBarButtonComponent
import TableComponent
import PeerTableCellComponent
private final class StarsTransactionSheetContent: CombinedComponent {
typealias EnvironmentType = ViewControllerComponentContainer.Environment
@@ -677,7 +679,7 @@ private final class StarsTransactionSheetContent: CombinedComponent {
component: AnyComponentWithIdentity(id: "close", component: AnyComponent(
BundleIconComponent(
name: "Navigation/Close",
tintColor: theme.rootController.navigationBar.glassBarButtonForegroundColor
tintColor: theme.chat.inputPanel.panelControlColor
)
)),
action: { _ in
@@ -936,9 +938,10 @@ private final class StarsTransactionSheetContent: CombinedComponent {
component: AnyComponent(
Button(
content: AnyComponent(
PeerCellComponent(
PeerTableCellComponent(
context: component.context,
theme: theme,
strings: strings,
peer: nil
)
),
@@ -983,9 +986,10 @@ private final class StarsTransactionSheetContent: CombinedComponent {
id: AnyHashable(0),
component: AnyComponent(Button(
content: AnyComponent(
PeerCellComponent(
PeerTableCellComponent(
context: component.context,
theme: theme,
strings: strings,
peer: toPeer
)
),
@@ -1026,9 +1030,10 @@ private final class StarsTransactionSheetContent: CombinedComponent {
toComponent = AnyComponent(
Button(
content: AnyComponent(
PeerCellComponent(
PeerTableCellComponent(
context: component.context,
theme: theme,
strings: strings,
peer: toPeer
)
),
@@ -1164,9 +1169,10 @@ private final class StarsTransactionSheetContent: CombinedComponent {
component: AnyComponent(
Button(
content: AnyComponent(
PeerCellComponent(
PeerTableCellComponent(
context: component.context,
theme: theme,
strings: strings,
peer: toPeer
)
),
@@ -1196,9 +1202,10 @@ private final class StarsTransactionSheetContent: CombinedComponent {
component: AnyComponent(
Button(
content: AnyComponent(
PeerCellComponent(
PeerTableCellComponent(
context: component.context,
theme: theme,
strings: strings,
peer: starRefPeer
)
),
@@ -1227,9 +1234,10 @@ private final class StarsTransactionSheetContent: CombinedComponent {
component: AnyComponent(
Button(
content: AnyComponent(
PeerCellComponent(
PeerTableCellComponent(
context: component.context,
theme: theme,
strings: strings,
peer: toPeer
)
),
@@ -1638,7 +1646,7 @@ private final class StarsTransactionSheetContent: CombinedComponent {
style: .glass,
color: theme.list.itemCheckColors.fillColor.withMultipliedAlpha(0.1),
foreground: theme.list.itemCheckColors.fillColor,
pressedColor: theme.list.itemCheckColors.fillColor.withMultipliedAlpha(0.8),
pressedColor: theme.list.itemCheckColors.fillColor.withMultipliedAlpha(0.8)
),
content: AnyComponentWithIdentity(
id: AnyHashable(0),
@@ -2146,241 +2154,6 @@ public class StarsTransactionScreen: ViewControllerComponentContainer {
}
}
private final class TableComponent: CombinedComponent {
class Item: Equatable {
public let id: AnyHashable
public let title: String
public let component: AnyComponent<Empty>
public let insets: UIEdgeInsets?
public init<IdType: Hashable>(id: IdType, title: String, component: AnyComponent<Empty>, insets: UIEdgeInsets? = nil) {
self.id = AnyHashable(id)
self.title = title
self.component = component
self.insets = insets
}
public static func == (lhs: Item, rhs: Item) -> Bool {
if lhs.id != rhs.id {
return false
}
if lhs.title != rhs.title {
return false
}
if lhs.component != rhs.component {
return false
}
if lhs.insets != rhs.insets {
return false
}
return true
}
}
private let theme: PresentationTheme
private let items: [Item]
public init(theme: PresentationTheme, items: [Item]) {
self.theme = theme
self.items = items
}
public static func ==(lhs: TableComponent, rhs: TableComponent) -> Bool {
if lhs.theme !== rhs.theme {
return false
}
if lhs.items != rhs.items {
return false
}
return true
}
final class State: ComponentState {
var cachedLeftColumnImage: (UIImage, PresentationTheme)?
var cachedBorderImage: (UIImage, PresentationTheme)?
}
func makeState() -> State {
return State()
}
public static var body: Body {
let leftColumnBackground = Child(Image.self)
let verticalBorder = Child(Rectangle.self)
let titleChildren = ChildMap(environment: Empty.self, keyedBy: AnyHashable.self)
let valueChildren = ChildMap(environment: Empty.self, keyedBy: AnyHashable.self)
let borderChildren = ChildMap(environment: Empty.self, keyedBy: AnyHashable.self)
let outerBorder = Child(Image.self)
return { context in
let verticalPadding: CGFloat = 11.0
let horizontalPadding: CGFloat = 12.0
let borderWidth: CGFloat = 1.0
let borderRadius: CGFloat = 14.0
let backgroundColor = context.component.theme.actionSheet.opaqueItemBackgroundColor
let borderColor = backgroundColor.mixedWith(context.component.theme.list.itemBlocksSeparatorColor, alpha: 0.6)
let secondaryBackgroundColor = context.component.theme.overallDarkAppearance ? context.component.theme.list.itemModalBlocksBackgroundColor : context.component.theme.list.itemInputField.backgroundColor
var leftColumnWidth: CGFloat = 0.0
var updatedTitleChildren: [_UpdatedChildComponent] = []
var updatedValueChildren: [(_UpdatedChildComponent, UIEdgeInsets)] = []
var updatedBorderChildren: [_UpdatedChildComponent] = []
for item in context.component.items {
let titleChild = titleChildren[item.id].update(
component: AnyComponent(MultilineTextComponent(
text: .plain(NSAttributedString(string: item.title, font: Font.regular(15.0), textColor: context.component.theme.list.itemPrimaryTextColor))
)),
availableSize: context.availableSize,
transition: context.transition
)
updatedTitleChildren.append(titleChild)
if titleChild.size.width > leftColumnWidth {
leftColumnWidth = titleChild.size.width
}
}
leftColumnWidth = max(100.0, leftColumnWidth + horizontalPadding * 2.0)
let rightColumnWidth = context.availableSize.width - leftColumnWidth
var i = 0
var rowHeights: [Int: CGFloat] = [:]
var totalHeight: CGFloat = 0.0
for item in context.component.items {
let titleChild = updatedTitleChildren[i]
let insets: UIEdgeInsets
if let customInsets = item.insets {
insets = customInsets
} else {
insets = UIEdgeInsets(top: 0.0, left: horizontalPadding, bottom: 0.0, right: horizontalPadding)
}
let valueChild = valueChildren[item.id].update(
component: item.component,
availableSize: CGSize(width: rightColumnWidth - insets.left - insets.right, height: context.availableSize.height),
transition: context.transition
)
updatedValueChildren.append((valueChild, insets))
let rowHeight = max(40.0, max(titleChild.size.height, valueChild.size.height) + verticalPadding * 2.0)
rowHeights[i] = rowHeight
totalHeight += rowHeight
if i < context.component.items.count - 1 {
let borderChild = borderChildren[item.id].update(
component: AnyComponent(Rectangle(color: borderColor)),
availableSize: CGSize(width: context.availableSize.width, height: borderWidth),
transition: context.transition
)
updatedBorderChildren.append(borderChild)
}
i += 1
}
let leftColumnImage: UIImage
if let (currentImage, theme) = context.state.cachedLeftColumnImage, theme === context.component.theme {
leftColumnImage = currentImage
} else {
leftColumnImage = generateImage(CGSize(width: borderRadius * 2.0 + 4.0, height: borderRadius * 2.0 + 4.0), rotatedContext: { size, context in
let bounds = CGRect(origin: .zero, size: CGSize(width: size.width + borderRadius, height: size.height))
context.clear(bounds)
let path = CGPath(roundedRect: bounds.insetBy(dx: borderWidth / 2.0, dy: borderWidth / 2.0), cornerWidth: borderRadius, cornerHeight: borderRadius, transform: nil)
context.setFillColor(secondaryBackgroundColor.cgColor)
context.addPath(path)
context.fillPath()
})!.stretchableImage(withLeftCapWidth: Int(borderRadius), topCapHeight: Int(borderRadius))
context.state.cachedLeftColumnImage = (leftColumnImage, context.component.theme)
}
let leftColumnBackground = leftColumnBackground.update(
component: Image(image: leftColumnImage),
availableSize: CGSize(width: leftColumnWidth, height: totalHeight),
transition: context.transition
)
context.add(
leftColumnBackground
.position(CGPoint(x: leftColumnWidth / 2.0, y: totalHeight / 2.0))
)
let borderImage: UIImage
if let (currentImage, theme) = context.state.cachedBorderImage, theme === context.component.theme {
borderImage = currentImage
} else {
borderImage = generateImage(CGSize(width: borderRadius * 2.0 + 4.0, height: borderRadius * 2.0 + 4.0), rotatedContext: { size, context in
let bounds = CGRect(origin: .zero, size: size)
context.clear(bounds)
let path = CGPath(roundedRect: bounds.insetBy(dx: borderWidth / 2.0, dy: borderWidth / 2.0), cornerWidth: borderRadius, cornerHeight: borderRadius, transform: nil)
context.setBlendMode(.clear)
context.addPath(path)
context.fillPath()
context.setBlendMode(.normal)
context.setStrokeColor(borderColor.cgColor)
context.setLineWidth(borderWidth)
context.addPath(path)
context.strokePath()
})!.stretchableImage(withLeftCapWidth: Int(borderRadius), topCapHeight: Int(borderRadius))
context.state.cachedBorderImage = (borderImage, context.component.theme)
}
let outerBorder = outerBorder.update(
component: Image(image: borderImage),
availableSize: CGSize(width: context.availableSize.width, height: totalHeight),
transition: context.transition
)
context.add(outerBorder
.position(CGPoint(x: context.availableSize.width / 2.0, y: totalHeight / 2.0))
)
let verticalBorder = verticalBorder.update(
component: Rectangle(color: borderColor),
availableSize: CGSize(width: borderWidth, height: totalHeight),
transition: context.transition
)
context.add(
verticalBorder
.position(CGPoint(x: leftColumnWidth - borderWidth / 2.0, y: totalHeight / 2.0))
)
i = 0
var originY: CGFloat = 0.0
for (titleChild, (valueChild, valueInsets)) in zip(updatedTitleChildren, updatedValueChildren) {
let rowHeight = rowHeights[i] ?? 0.0
let titleFrame = CGRect(origin: CGPoint(x: horizontalPadding, y: originY + verticalPadding), size: titleChild.size)
let valueFrame = CGRect(origin: CGPoint(x: leftColumnWidth + valueInsets.left, y: originY + verticalPadding), size: valueChild.size)
context.add(titleChild
.position(titleFrame.center)
)
context.add(valueChild
.position(valueFrame.center)
)
if i < updatedBorderChildren.count {
let borderChild = updatedBorderChildren[i]
context.add(borderChild
.position(CGPoint(x: context.availableSize.width / 2.0, y: originY + rowHeight - borderWidth / 2.0))
)
}
originY += rowHeight
i += 1
}
return CGSize(width: context.availableSize.width, height: totalHeight)
}
}
}
private final class PeerCellComponent: Component {
let context: AccountContext
let theme: PresentationTheme
@@ -26,6 +26,7 @@ final class StarsStatisticsScreenComponent: Component {
typealias EnvironmentType = ViewControllerComponentContainer.Environment
let context: AccountContext
let overNavigationContainer: UIView
let peerId: EnginePeer.Id
let revenueContext: StarsRevenueStatsContext
let openTransaction: (StarsContext.State.Transaction) -> Void
@@ -36,6 +37,7 @@ final class StarsStatisticsScreenComponent: Component {
init(
context: AccountContext,
overNavigationContainer: UIView,
peerId: EnginePeer.Id,
revenueContext: StarsRevenueStatsContext,
openTransaction: @escaping (StarsContext.State.Transaction) -> Void,
@@ -45,6 +47,7 @@ final class StarsStatisticsScreenComponent: Component {
buyAds: @escaping () -> Void
) {
self.context = context
self.overNavigationContainer = overNavigationContainer
self.peerId = peerId
self.revenueContext = revenueContext
self.openTransaction = openTransaction
@@ -125,10 +128,6 @@ final class StarsStatisticsScreenComponent: Component {
private let scrollView: ScrollViewImpl
private var currentSelectedPanelId: AnyHashable?
private let navigationBackgroundView: BlurredBackgroundView
private let navigationSeparatorLayer: SimpleLayer
private let navigationSeparatorLayerContainer: SimpleLayer
private let headerView = ComponentView<Empty>()
private let headerOffsetContainer: UIView
@@ -175,14 +174,6 @@ final class StarsStatisticsScreenComponent: Component {
self.headerOffsetContainer = UIView()
self.headerOffsetContainer.isUserInteractionEnabled = false
self.navigationBackgroundView = BlurredBackgroundView(color: nil, enableBlur: true)
self.navigationBackgroundView.alpha = 0.0
self.navigationSeparatorLayer = SimpleLayer()
self.navigationSeparatorLayer.opacity = 0.0
self.navigationSeparatorLayerContainer = SimpleLayer()
self.navigationSeparatorLayerContainer.opacity = 0.0
self.scrollContainerView = UIView()
self.scrollView = ScrollViewImpl()
@@ -208,11 +199,6 @@ final class StarsStatisticsScreenComponent: Component {
self.scrollView.addSubview(self.scrollContainerView)
self.scrollContainerView.addSubview(self.transactionsBackground)
self.addSubview(self.navigationBackgroundView)
self.navigationSeparatorLayerContainer.addSublayer(self.navigationSeparatorLayer)
self.layer.addSublayer(self.navigationSeparatorLayerContainer)
self.addSubview(self.headerOffsetContainer)
}
@@ -307,18 +293,10 @@ final class StarsStatisticsScreenComponent: Component {
let isLockedAtPanels = scrollBounds.maxY == self.scrollView.contentSize.height
if let _ = self.navigationMetrics {
let topContentOffset = self.scrollView.contentOffset.y
let navigationBackgroundAlpha = min(20.0, max(0.0, topContentOffset)) / 20.0
let animatedTransition = ComponentTransition(animation: .curve(duration: 0.18, curve: .easeInOut))
animatedTransition.setAlpha(view: self.navigationBackgroundView, alpha: navigationBackgroundAlpha)
animatedTransition.setAlpha(layer: self.navigationSeparatorLayerContainer, alpha: navigationBackgroundAlpha)
let expansionDistance: CGFloat = 32.0
var expansionDistanceFactor: CGFloat = abs(scrollBounds.maxY - self.scrollView.contentSize.height) / expansionDistance
expansionDistanceFactor = max(0.0, min(1.0, expansionDistanceFactor))
transition.setAlpha(layer: self.navigationSeparatorLayer, alpha: expansionDistanceFactor)
if let panelContainerView = self.panelContainer.view as? StarsTransactionsPanelContainerComponent.View {
panelContainerView.updateNavigationMergeFactor(value: 1.0 - expansionDistanceFactor, transition: transition)
}
@@ -417,19 +395,7 @@ final class StarsStatisticsScreenComponent: Component {
self.controller = environment.controller
self.navigationMetrics = (environment.navigationHeight, environment.statusBarHeight)
self.navigationSeparatorLayer.backgroundColor = environment.theme.rootController.navigationBar.separatorColor.cgColor
let navigationFrame = CGRect(origin: CGPoint(), size: CGSize(width: availableSize.width, height: environment.navigationHeight))
self.navigationBackgroundView.updateColor(color: environment.theme.rootController.navigationBar.blurredBackgroundColor, transition: .immediate)
self.navigationBackgroundView.update(size: navigationFrame.size, transition: transition.containedViewLayoutTransition)
transition.setFrame(view: self.navigationBackgroundView, frame: navigationFrame)
let navigationSeparatorFrame = CGRect(origin: CGPoint(x: 0.0, y: navigationFrame.maxY), size: CGSize(width: availableSize.width, height: UIScreenPixel))
transition.setFrame(layer: self.navigationSeparatorLayerContainer, frame: navigationSeparatorFrame)
transition.setFrame(layer: self.navigationSeparatorLayer, frame: CGRect(origin: CGPoint(), size: navigationSeparatorFrame.size))
self.backgroundColor = environment.theme.list.blocksBackgroundColor
var contentHeight: CGFloat = 0.0
@@ -454,7 +420,7 @@ final class StarsStatisticsScreenComponent: Component {
)
if let titleView = self.titleView.view {
if titleView.superview == nil {
self.addSubview(titleView)
component.overNavigationContainer.addSubview(titleView)
}
let titlePosition = CGPoint(x: availableSize.width / 2.0, y: environment.statusBarHeight + (environment.navigationHeight - environment.statusBarHeight) / 2.0)
transition.setPosition(view: titleView, position: titlePosition)
@@ -847,6 +813,8 @@ public final class StarsStatisticsScreen: ViewControllerComponentContainer {
private let peerId: EnginePeer.Id
private let revenueContext: StarsRevenueStatsContext
private let overNavigationContainer: UIView
private weak var tooltipScreen: UndoOverlayController?
private var timer: Foundation.Timer?
@@ -857,6 +825,8 @@ public final class StarsStatisticsScreen: ViewControllerComponentContainer {
self.peerId = peerId
self.revenueContext = revenueContext
self.overNavigationContainer = SparseContainerView()
var buyImpl: (() -> Void)?
var withdrawImpl: (() -> Void)?
var buyAdsImpl: (() -> Void)?
@@ -864,6 +834,7 @@ public final class StarsStatisticsScreen: ViewControllerComponentContainer {
var openTransactionImpl: ((StarsContext.State.Transaction) -> Void)?
super.init(context: context, component: StarsStatisticsScreenComponent(
context: context,
overNavigationContainer: self.overNavigationContainer,
peerId: peerId,
revenueContext: revenueContext,
openTransaction: { transaction in
@@ -881,7 +852,7 @@ public final class StarsStatisticsScreen: ViewControllerComponentContainer {
buyAds: {
buyAdsImpl?()
}
), navigationBarAppearance: .transparent)
), navigationBarAppearance: .default)
self.navigationPresentation = .modalInLargeLayout
@@ -1060,6 +1031,10 @@ public final class StarsStatisticsScreen: ViewControllerComponentContainer {
}
componentView.scrollToTop()
}
if let navigationBar = self.navigationBar {
navigationBar.customOverBackgroundContentView.insertSubview(self.overNavigationContainer, at: 0)
}
}
required public init(coder aDecoder: NSCoder) {
@@ -102,10 +102,6 @@ final class StarsTransactionsScreenComponent: Component {
private let scrollView: ScrollViewImpl
private var currentSelectedPanelId: AnyHashable?
private let navigationBackgroundView: BlurredBackgroundView
private let navigationSeparatorLayer: SimpleLayer
private let navigationSeparatorLayerContainer: SimpleLayer
private let scrollContainerView: UIView
@@ -160,14 +156,6 @@ final class StarsTransactionsScreenComponent: Component {
private var cachedChevronImage: (UIImage, PresentationTheme)?
override init(frame: CGRect) {
self.navigationBackgroundView = BlurredBackgroundView(color: nil, enableBlur: true)
self.navigationBackgroundView.alpha = 0.0
self.navigationSeparatorLayer = SimpleLayer()
self.navigationSeparatorLayer.opacity = 0.0
self.navigationSeparatorLayerContainer = SimpleLayer()
self.navigationSeparatorLayerContainer.opacity = 0.0
self.scrollContainerView = UIView()
self.scrollView = ScrollViewImpl()
@@ -191,11 +179,6 @@ final class StarsTransactionsScreenComponent: Component {
self.addSubview(self.scrollView)
self.scrollView.addSubview(self.scrollContainerView)
self.addSubview(self.navigationBackgroundView)
self.navigationSeparatorLayerContainer.addSublayer(self.navigationSeparatorLayer)
self.layer.addSublayer(self.navigationSeparatorLayerContainer)
}
required init?(coder: NSCoder) {
@@ -296,7 +279,6 @@ final class StarsTransactionsScreenComponent: Component {
var topContentOffset = self.scrollView.contentOffset.y
let navigationBackgroundAlpha = min(20.0, max(0.0, topContentOffset - 95.0)) / 20.0
topContentOffset = topContentOffset + max(0.0, min(1.0, topContentOffset / titleOffsetDelta)) * 10.0
titleOffset = topContentOffset
let fraction = max(0.0, min(1.0, titleOffset / titleOffsetDelta))
@@ -317,15 +299,10 @@ final class StarsTransactionsScreenComponent: Component {
headerTransition.setScale(view: titleView, scale: titleScale)
}
let animatedTransition = ComponentTransition(animation: .curve(duration: 0.18, curve: .easeInOut))
animatedTransition.setAlpha(view: self.navigationBackgroundView, alpha: navigationBackgroundAlpha)
animatedTransition.setAlpha(layer: self.navigationSeparatorLayerContainer, alpha: navigationBackgroundAlpha)
let expansionDistance: CGFloat = 32.0
var expansionDistanceFactor: CGFloat = abs(scrollBounds.maxY - self.scrollView.contentSize.height) / expansionDistance
expansionDistanceFactor = max(0.0, min(1.0, expansionDistanceFactor))
transition.setAlpha(layer: self.navigationSeparatorLayer, alpha: expansionDistanceFactor)
if let panelContainerView = self.panelContainer.view as? StarsTransactionsPanelContainerComponent.View {
panelContainerView.updateNavigationMergeFactor(value: 1.0 - expansionDistanceFactor, transition: transition)
}
@@ -435,18 +412,6 @@ final class StarsTransactionsScreenComponent: Component {
self.navigationMetrics = (environment.navigationHeight, environment.statusBarHeight)
self.navigationSeparatorLayer.backgroundColor = environment.theme.rootController.navigationBar.separatorColor.cgColor
let navigationFrame = CGRect(origin: CGPoint(), size: CGSize(width: availableSize.width, height: environment.navigationHeight))
self.navigationBackgroundView.updateColor(color: environment.theme.rootController.navigationBar.blurredBackgroundColor, transition: .immediate)
self.navigationBackgroundView.update(size: navigationFrame.size, transition: transition.containedViewLayoutTransition)
transition.setFrame(view: self.navigationBackgroundView, frame: navigationFrame)
let navigationSeparatorFrame = CGRect(origin: CGPoint(x: 0.0, y: navigationFrame.maxY), size: CGSize(width: availableSize.width, height: UIScreenPixel))
transition.setFrame(layer: self.navigationSeparatorLayerContainer, frame: navigationSeparatorFrame)
transition.setFrame(layer: self.navigationSeparatorLayer, frame: CGRect(origin: CGPoint(), size: navigationSeparatorFrame.size))
self.backgroundColor = environment.theme.list.blocksBackgroundColor
var contentHeight: CGFloat = 0.0
@@ -519,7 +484,7 @@ final class StarsTransactionsScreenComponent: Component {
UIColor(rgb: 0xfdd219)
],
particleColor: UIColor(rgb: 0xf9b004),
backgroundColor: environment.theme.list.blocksBackgroundColor
backgroundColor: nil
))
}
@@ -532,7 +497,13 @@ final class StarsTransactionsScreenComponent: Component {
let starFrame = CGRect(origin: .zero, size: starSize)
if let starView = self.starView.view {
if starView.superview == nil {
self.insertSubview(starView, aboveSubview: self.scrollView)
if let navigationBar = environment.controller()?.navigationBar {
if let titleView = self.titleView.view, titleView.superview != nil {
navigationBar.view.insertSubview(starView, belowSubview: titleView)
} else {
navigationBar.view.insertSubview(starView, aboveSubview: navigationBar.backgroundView)
}
}
}
starTransition.setBounds(view: starView, bounds: starFrame)
}
@@ -562,7 +533,9 @@ final class StarsTransactionsScreenComponent: Component {
)
if let titleView = self.titleView.view {
if titleView.superview == nil {
self.addSubview(titleView)
if let navigationBar = environment.controller()?.navigationBar {
navigationBar.view.insertSubview(titleView, aboveSubview: navigationBar.backgroundView)
}
}
starTransition.setBounds(view: titleView, bounds: CGRect(origin: .zero, size: titleSize))
}
@@ -617,7 +590,13 @@ final class StarsTransactionsScreenComponent: Component {
if let topBalanceTitleView = self.topBalanceTitleView.view {
if topBalanceTitleView.superview == nil {
topBalanceTitleView.alpha = 0.0
self.addSubview(topBalanceTitleView)
if let navigationBar = environment.controller()?.navigationBar {
if let titleView = self.titleView.view, titleView.superview != nil {
navigationBar.view.insertSubview(topBalanceTitleView, aboveSubview: titleView)
} else {
navigationBar.view.insertSubview(topBalanceTitleView, aboveSubview: navigationBar.backgroundView)
}
}
}
starTransition.setFrame(view: topBalanceTitleView, frame: topBalanceTitleFrame)
}
@@ -626,7 +605,13 @@ final class StarsTransactionsScreenComponent: Component {
if let topBalanceValueView = self.topBalanceValueView.view {
if topBalanceValueView.superview == nil {
topBalanceValueView.alpha = 0.0
self.addSubview(topBalanceValueView)
if let navigationBar = environment.controller()?.navigationBar {
if let titleView = self.titleView.view, titleView.superview != nil {
navigationBar.view.insertSubview(topBalanceValueView, aboveSubview: titleView)
} else {
navigationBar.view.insertSubview(topBalanceValueView, aboveSubview: navigationBar.backgroundView)
}
}
}
starTransition.setFrame(view: topBalanceValueView, frame: topBalanceValueFrame)
}
@@ -638,7 +623,13 @@ final class StarsTransactionsScreenComponent: Component {
if let topBalanceIconView = self.topBalanceIconView.view {
if topBalanceIconView.superview == nil {
topBalanceIconView.alpha = 0.0
self.addSubview(topBalanceIconView)
if let navigationBar = environment.controller()?.navigationBar {
if let titleView = self.titleView.view, titleView.superview != nil {
navigationBar.view.insertSubview(topBalanceIconView, aboveSubview: titleView)
} else {
navigationBar.view.insertSubview(topBalanceIconView, aboveSubview: navigationBar.backgroundView)
}
}
}
starTransition.setFrame(view: topBalanceIconView, frame: topBalanceIconFrame)
}
@@ -844,7 +835,7 @@ final class StarsTransactionsScreenComponent: Component {
footer: nil,
items: [
AnyComponentWithIdentity(id: 0, component: AnyComponent(ListItemComponentAdaptor(
itemGenerator: ItemListDisclosureItem(presentationData: ItemListPresentationData(presentationData), icon: PresentationResourcesSettings.earnStars, title: environment.strings.Monetization_EarnStarsInfo_Title, titleBadge: presentationData.strings.Settings_New, label: environment.strings.Monetization_EarnStarsInfo_Text, labelStyle: .multilineDetailText, sectionId: 0, style: .blocks, action: {
itemGenerator: ItemListDisclosureItem(presentationData: ItemListPresentationData(presentationData), icon: PresentationResourcesSettings.earnStars, title: environment.strings.Monetization_EarnStarsInfo_Title, titleBadge: nil, label: environment.strings.Monetization_EarnStarsInfo_Text, labelStyle: .multilineDetailText, sectionId: 0, style: .blocks, action: {
}),
params: ListViewItemLayoutParams(width: availableSize.width, leftInset: 0.0, rightInset: 0.0, availableHeight: 10000.0, isStandalone: true),
action: { [weak self] in
@@ -1261,7 +1252,7 @@ public final class StarsTransactionsScreen: ViewControllerComponentContainer {
gift: {
giftImpl?()
}
), navigationBarAppearance: .transparent)
), navigationBarAppearance: .default)
self.navigationPresentation = .modalInLargeLayout
@@ -348,7 +348,7 @@ private final class SheetContent: CombinedComponent {
component: AnyComponentWithIdentity(id: "close", component: AnyComponent(
BundleIconComponent(
name: "Navigation/Close",
tintColor: theme.rootController.navigationBar.glassBarButtonForegroundColor
tintColor: theme.chat.inputPanel.panelControlColor
)
)),
action: { _ in
@@ -655,7 +655,9 @@ private final class SheetContent: CombinedComponent {
controller?.complete(paid: success)
controller?.dismissAnimated()
starsContext.load(force: true)
Queue.mainQueue().after(2.5) {
starsContext.load(force: true)
}
})
}
),
@@ -42,6 +42,8 @@ swift_library(
"//submodules/TelegramUI/Components/Stars/BalanceNeededScreen",
"//submodules/TelegramUI/Components/GlassBarButtonComponent",
"//submodules/TelegramUI/Components/GlassBackgroundComponent",
"//submodules/TelegramUI/Components/AlertComponent",
"//submodules/TelegramUI/Components/AlertComponent/AlertInputFieldComponent",
],
visibility = [
"//visibility:public",
@@ -6,106 +6,141 @@ import TelegramPresentationData
import PresentationDataUtils
import AccountContext
import PasswordSetupUI
import Markdown
import OwnershipTransferController
import ComponentFlow
import AlertComponent
import AlertInputFieldComponent
public func confirmStarsRevenueWithdrawalController(context: AccountContext, updatedPresentationData: (initial: PresentationData, signal: Signal<PresentationData, NoError>)? = nil, peerId: EnginePeer.Id, amount: Int64, present: @escaping (ViewController, Any?) -> Void, completion: @escaping (String) -> Void) -> ViewController {
let presentationData = updatedPresentationData?.initial ?? context.sharedContext.currentPresentationData.with { $0 }
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
let strings = presentationData.strings
let inputState = AlertInputFieldComponent.ExternalState()
let doneIsEnabled: Signal<Bool, NoError> = inputState.valueSignal
|> map { value in
return !value.isEmpty
}
let doneInProgressPromise = ValuePromise<Bool>(false)
var content: [AnyComponentWithIdentity<AlertComponentEnvironment>] = []
content.append(AnyComponentWithIdentity(
id: "title",
component: AnyComponent(
AlertTitleComponent(title: strings.Monetization_Withdraw_EnterPassword_Title)
)
))
content.append(AnyComponentWithIdentity(
id: "text",
component: AnyComponent(
AlertTextComponent(content: .plain(strings.Monetization_Withdraw_EnterPassword_Text))
)
))
var applyImpl: (() -> Void)?
content.append(AnyComponentWithIdentity(
id: "input",
component: AnyComponent(
AlertInputFieldComponent(
context: context,
placeholder: strings.Channel_OwnershipTransfer_PasswordPlaceholder,
isSecureTextEntry: true,
isInitiallyFocused: true,
externalState: inputState,
returnKeyAction: {
applyImpl?()
}
)
)
))
var effectiveUpdatedPresentationData: (PresentationData, Signal<PresentationData, NoError>)
if let updatedPresentationData {
effectiveUpdatedPresentationData = updatedPresentationData
} else {
effectiveUpdatedPresentationData = (presentationData, context.sharedContext.presentationData)
}
var dismissImpl: (() -> Void)?
var proceedImpl: (() -> Void)?
let disposable = MetaDisposable()
let contentNode = ChannelOwnershipTransferAlertContentNode(theme: AlertControllerTheme(presentationData: presentationData), ptheme: presentationData.theme, strings: presentationData.strings, title: presentationData.strings.Monetization_Withdraw_EnterPassword_Title, text: presentationData.strings.Monetization_Withdraw_EnterPassword_Text, actions: [TextAlertAction(type: .genericAction, title: presentationData.strings.Common_Cancel, action: {
dismissImpl?()
}), TextAlertAction(type: .defaultAction, title: presentationData.strings.Monetization_Withdraw_EnterPassword_Done, action: {
proceedImpl?()
})])
contentNode.complete = {
proceedImpl?()
}
let controller = AlertController(theme: AlertControllerTheme(presentationData: presentationData), contentNode: contentNode)
let presentationDataDisposable = (updatedPresentationData?.signal ?? context.sharedContext.presentationData).start(next: { [weak controller, weak contentNode] presentationData in
controller?.theme = AlertControllerTheme(presentationData: presentationData)
contentNode?.theme = presentationData.theme
})
controller.dismissed = { _ in
presentationDataDisposable.dispose()
disposable.dispose()
}
dismissImpl = { [weak controller, weak contentNode] in
contentNode?.dismissInput()
controller?.dismissAnimated()
}
proceedImpl = { [weak contentNode] in
guard let contentNode = contentNode else {
return
}
contentNode.updateIsChecking(true)
let signal = context.engine.peers.requestStarsRevenueWithdrawalUrl(peerId: peerId, ton: false, amount: amount, password: contentNode.password)
disposable.set((signal |> deliverOnMainQueue).start(next: { url in
let alertController = AlertScreen(
configuration: AlertScreen.Configuration(allowInputInset: true),
content: content,
actions: [
.init(title: strings.Common_Cancel),
.init(title: strings.Monetization_Withdraw_EnterPassword_Done, type: .default, action: {
applyImpl?()
}, autoDismiss: false, isEnabled: doneIsEnabled, progress: doneInProgressPromise.get())
],
updatedPresentationData: effectiveUpdatedPresentationData
)
applyImpl = {
doneInProgressPromise.set(true)
let _ = (context.engine.peers.requestStarsRevenueWithdrawalUrl(peerId: peerId, ton: false, amount: amount, password: inputState.value)
|> deliverOnMainQueue).start(next: { url in
dismissImpl?()
completion(url)
}, error: { [weak contentNode] error in
}, error: { error in
var errorTextAndActions: (String, [TextAlertAction])?
switch error {
case .invalidPassword:
contentNode?.animateError()
case .limitExceeded:
errorTextAndActions = (presentationData.strings.TwoStepAuth_FloodError, [TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_OK, action: {})])
default:
errorTextAndActions = (presentationData.strings.Login_UnknownError, [TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_OK, action: {})])
case .invalidPassword:
inputState.animateError()
case .limitExceeded:
errorTextAndActions = (strings.TwoStepAuth_FloodError, [TextAlertAction(type: .defaultAction, title: strings.Common_OK, action: {})])
default:
errorTextAndActions = (strings.Login_UnknownError, [TextAlertAction(type: .defaultAction, title: strings.Common_OK, action: {})])
}
contentNode?.updateIsChecking(false)
doneInProgressPromise.set(false)
if let (text, actions) = errorTextAndActions {
dismissImpl?()
present(textAlertController(context: context, title: nil, text: text, actions: actions), nil)
}
}))
})
}
return controller
dismissImpl = { [weak alertController] in
alertController?.dismiss(completion: nil)
}
return alertController
}
public func starsRevenueWithdrawalController(context: AccountContext, updatedPresentationData: (initial: PresentationData, signal: Signal<PresentationData, NoError>)? = nil, peerId: EnginePeer.Id, amount: Int64, initialError: RequestStarsRevenueWithdrawalError, present: @escaping (ViewController, Any?) -> Void, completion: @escaping (String) -> Void) -> ViewController {
let presentationData = updatedPresentationData?.initial ?? context.sharedContext.currentPresentationData.with { $0 }
let theme = AlertControllerTheme(presentationData: presentationData)
let strings = presentationData.strings
var title: NSAttributedString? = NSAttributedString(string: presentationData.strings.OwnershipTransfer_SecurityCheck, font: Font.semibold(presentationData.listsFontSize.itemListBaseFontSize), textColor: theme.primaryColor, paragraphAlignment: .center)
var text = presentationData.strings.Monetization_Withdraw_SecurityRequirements
let textFontSize = presentationData.listsFontSize.baseDisplaySize * 13.0 / 17.0
var actions: [TextAlertAction] = []
var title: String? = strings.OwnershipTransfer_SecurityCheck
var text = strings.Monetization_Withdraw_SecurityRequirements
var actions: [AlertScreen.Action] = [
.init(title: strings.Common_OK, type: .default)
]
switch initialError {
case .requestPassword:
case .requestPassword:
return confirmStarsRevenueWithdrawalController(context: context, updatedPresentationData: updatedPresentationData, peerId: peerId, amount: amount, present: present, completion: completion)
case .twoStepAuthTooFresh, .authSessionTooFresh:
text = text + presentationData.strings.Monetization_Withdraw_ComeBackLater
actions = [TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_OK, action: {})]
case .twoStepAuthMissing:
actions = [TextAlertAction(type: .genericAction, title: presentationData.strings.OwnershipTransfer_SetupTwoStepAuth, action: {
case .twoStepAuthTooFresh, .authSessionTooFresh:
text = text + strings.Monetization_Withdraw_ComeBackLater
case .twoStepAuthMissing:
actions = [
.init(title: strings.OwnershipTransfer_SetupTwoStepAuth, type: .default, action: {
let controller = SetupTwoStepVerificationController(context: context, initialState: .automatic, stateUpdated: { update, shouldDismiss, controller in
if shouldDismiss {
controller.dismiss()
}
})
present(controller, ViewControllerPresentationArguments(presentationAnimation: .modalSheet))
}), TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_Cancel, action: {})]
default:
title = nil
text = presentationData.strings.Login_UnknownError
actions = [TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_OK, action: {})]
}),
.init(title: strings.Common_Cancel)
]
default:
title = nil
text = strings.Login_UnknownError
}
let body = MarkdownAttributeSet(font: Font.regular(textFontSize), textColor: theme.primaryColor)
let bold = MarkdownAttributeSet(font: Font.semibold(textFontSize), textColor: theme.primaryColor)
let attributedText = parseMarkdownIntoAttributedString(text, attributes: MarkdownAttributes(body: body, bold: bold, link: body, linkAttribute: { _ in return nil }), textAlignment: .center)
return richTextAlertController(context: context, title: title, text: attributedText, actions: actions)
return AlertScreen(
context: context,
configuration: AlertScreen.Configuration(actionAlignment: .vertical),
title: title,
text: text,
actions: actions
)
}
@@ -95,7 +95,7 @@ private final class SheetContent: CombinedComponent {
component: AnyComponentWithIdentity(id: "close", component: AnyComponent(
BundleIconComponent(
name: "Navigation/Close",
tintColor: theme.rootController.navigationBar.glassBarButtonForegroundColor
tintColor: theme.chat.inputPanel.panelControlColor
)
)),
action: { _ in
@@ -167,7 +167,11 @@ private final class SheetContent: CombinedComponent {
maxAmount = StarsAmount(value: resaleConfiguration.starGiftResaleMaxStarsAmount, nanos: 0)
case .ton:
amountTitle = environment.strings.Stars_SellGift_TonAmountTitle
#if DEBUG
minAmount = StarsAmount(value: 48000000000, nanos: 0)
#else
minAmount = StarsAmount(value: resaleConfiguration.starGiftResaleMinTonAmount, nanos: 0)
#endif
maxAmount = StarsAmount(value: resaleConfiguration.starGiftResaleMaxTonAmount, nanos: 0)
}
case let .paidMessages(_, minAmountValue, _, _, _):
@@ -618,7 +622,14 @@ private final class SheetContent: CombinedComponent {
}
if state.currency == .stars {
if let amount = state.amount, let tonUsdRate = withdrawConfiguration.tonUsdRate, let usdWithdrawRate = withdrawConfiguration.usdWithdrawRate {
state.amount = StarsAmount(value: max(min(convertStarsToTon(amount, tonUsdRate: tonUsdRate, starsUsdRate: usdWithdrawRate), resaleConfiguration.starGiftResaleMaxTonAmount), resaleConfiguration.starGiftResaleMinTonAmount), nanos: 0)
var convertedValue = min(convertStarsToTon(amount, tonUsdRate: tonUsdRate, starsUsdRate: usdWithdrawRate), resaleConfiguration.starGiftResaleMaxTonAmount)
if convertedValue < resaleConfiguration.starGiftResaleMinTonAmount {
convertedValue = resaleConfiguration.starGiftResaleMinTonAmount
if case .starGiftResell = component.mode, let controller = controller() as? StarsWithdrawScreen {
controller.presentMinAmountTooltip(convertedValue, currency: .ton)
}
}
state.amount = StarsAmount(value: convertedValue, nanos: 0)
} else {
state.amount = StarsAmount(value: 0, nanos: 0)
}
@@ -1255,6 +1266,8 @@ private final class StarsWithdrawSheetComponent: CombinedComponent {
let sheet = Child(SheetComponent<(EnvironmentType)>.self)
let animateOut = StoredActionSlot(Action<Void>.self)
let sheetExternalState = SheetComponent<EnvironmentType>.ExternalState()
return { context in
let environment = context.environment[EnvironmentType.self]
@@ -1281,6 +1294,7 @@ private final class StarsWithdrawSheetComponent: CombinedComponent {
followContentSizeChanges: false,
clipsContent: true,
isScrollEnabled: false,
externalState: sheetExternalState,
animateOut: animateOut
),
environment: {
@@ -1313,6 +1327,29 @@ private final class StarsWithdrawSheetComponent: CombinedComponent {
.position(CGPoint(x: context.availableSize.width / 2.0, y: context.availableSize.height / 2.0))
)
if let controller = controller(), !controller.automaticallyControlPresentationContextLayout {
var sideInset: CGFloat = 0.0
var bottomInset: CGFloat = max(environment.safeInsets.bottom, sheetExternalState.contentHeight)
if case .regular = environment.metrics.widthClass {
sideInset = floor((context.availableSize.width - 430.0) / 2.0) - 12.0
bottomInset = (context.availableSize.height - sheetExternalState.contentHeight) / 2.0 + sheetExternalState.contentHeight
}
let layout = ContainerViewLayout(
size: context.availableSize,
metrics: environment.metrics,
deviceMetrics: environment.deviceMetrics,
intrinsicInsets: UIEdgeInsets(top: 0.0, left: 0.0, bottom: bottomInset, right: 0.0),
safeInsets: UIEdgeInsets(top: 0.0, left: max(sideInset, environment.safeInsets.left), bottom: 0.0, right: max(sideInset, environment.safeInsets.right)),
additionalInsets: .zero,
statusBarHeight: environment.statusBarHeight,
inputHeight: nil,
inputHeightIsInteractivellyChanging: false,
inVoiceOver: false
)
controller.presentationContext.containerLayoutUpdated(layout, transition: context.transition.containedViewLayoutTransition)
}
return context.availableSize
}
}
@@ -1357,6 +1394,7 @@ public final class StarsWithdrawScreen: ViewControllerComponentContainer {
)
self.navigationPresentation = .flatModal
self.automaticallyControlPresentationContextLayout = false
}
required public init(coder aDecoder: NSCoder) {
@@ -1422,10 +1460,8 @@ public final class StarsWithdrawScreen: ViewControllerComponentContainer {
round: false,
undoText: nil
),
elevatedLayout: false,
position: .top,
action: { _ in return true})
self.present(resultController, in: .window(.root))
self.present(resultController, in: .current)
if let view = self.node.hostView.findTaggedView(tag: amountTag) as? AmountFieldComponent.View {
view.animateError()
@@ -1769,8 +1805,15 @@ public final class AmountFieldComponent: Component {
guard let component = self.component, let value = component.value else {
return
}
self.textField.text = "\(value)"
self.placeholderView.view?.isHidden = self.textField.text?.isEmpty ?? false
var text = ""
switch component.currency {
case .stars:
text = "\(value)"
case .ton:
text = "\(formatTonAmountText(value, dateTimeFormat: PresentationDateTimeFormat(timeFormat: component.dateTimeFormat.timeFormat, dateFormat: component.dateTimeFormat.dateFormat, dateSeparator: "", dateSuffix: "", requiresFullYear: false, decimalSeparator: ".", groupingSeparator: ""), maxDecimalPositions: nil))"
}
self.textField.text = text
self.placeholderView.view?.isHidden = !(self.textField.text ?? "").isEmpty
}
func update(component: AmountFieldComponent, availableSize: CGSize, state: EmptyComponentState, environment: Environment<EnvironmentType>, transition: ComponentTransition) -> CGSize {
@@ -1790,7 +1833,7 @@ public final class AmountFieldComponent: Component {
text = "\(formatTonAmountText(value, dateTimeFormat: PresentationDateTimeFormat(timeFormat: component.dateTimeFormat.timeFormat, dateFormat: component.dateTimeFormat.dateFormat, dateSeparator: "", dateSuffix: "", requiresFullYear: false, decimalSeparator: ".", groupingSeparator: ""), maxDecimalPositions: nil))"
}
self.textField.text = text
self.placeholderView.view?.isHidden = text.isEmpty
self.placeholderView.view?.isHidden = !text.isEmpty
} else {
self.textField.text = ""
}