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
@@ -40,6 +40,10 @@ import ChatThemeScreen
import ProfileLevelRatingBarComponent
import AnimatedTextComponent
import InfoParagraphComponent
import ChatMessagePaymentAlertController
import TableComponent
import PeerTableCellComponent
import AvatarComponent
private final class GiftViewSheetContent: CombinedComponent {
typealias EnvironmentType = ViewControllerComponentContainer.Environment
@@ -120,6 +124,8 @@ private final class GiftViewSheetContent: CombinedComponent {
let levelsDisposable = MetaDisposable()
var nextGiftToUpgrade: ProfileGiftsContext.State.StarGift?
var giftVariantsDisposable = MetaDisposable()
var buyForm: BotPaymentForm?
var buyFormDisposable: Disposable?
var buyDisposable: Disposable?
@@ -374,6 +380,7 @@ private final class GiftViewSheetContent: CombinedComponent {
self.buyDisposable?.dispose()
self.levelsDisposable.dispose()
self.starsTopUpOptionsDisposable?.dispose()
self.giftVariantsDisposable.dispose()
}
func openPeer(_ peer: EnginePeer, gifts: Bool = false, dismiss: Bool = true) {
@@ -625,7 +632,7 @@ private final class GiftViewSheetContent: CombinedComponent {
controller?.dismissAnimated()
if let navigationController {
Queue.mainQueue().after(0.5) {
Queue.mainQueue().after(2.5) {
starsContext.load(force: true)
let text: String
@@ -730,7 +737,7 @@ private final class GiftViewSheetContent: CombinedComponent {
guard let self else {
return
}
Queue.mainQueue().after(0.5) {
Queue.mainQueue().after(2.5) {
starsContext?.load(force: true)
}
switch self.subject {
@@ -1134,7 +1141,7 @@ private final class GiftViewSheetContent: CombinedComponent {
guard let peerId = peerIds.first else {
return .complete()
}
Queue.mainQueue().after(1.5, {
Queue.mainQueue().after(2.5, {
if transferStars > 0 {
context.starsContext?.load(force: true)
}
@@ -1350,6 +1357,33 @@ private final class GiftViewSheetContent: CombinedComponent {
})
}
func openUpgradeVariants(attribute: StarGift.UniqueGift.Attribute? = nil) {
guard let controller = self.getController() as? GiftViewScreen, let arguments = self.subject.arguments else {
return
}
var selectedAttributes: [StarGift.UniqueGift.Attribute]?
if case let .unique(uniqueGift) = arguments.gift {
selectedAttributes = uniqueGift.attributes
}
self.giftVariantsDisposable.set((self.context.engine.payments.getStarGiftUpgradeAttributes(giftId: arguments.gift.giftId)
|> take(1)
|> deliverOnMainQueue).start(next: { [weak self] attributes in
guard let self, let attributes else {
return
}
let variantsController = self.context.sharedContext.makeGiftUpgradeVariantsScreen(
context: self.context,
gift: arguments.gift,
attributes: attributes,
selectedAttributes: selectedAttributes,
focusedAttribute: attribute
)
controller.push(variantsController)
}))
}
func showAttributeInfo(tag: Any, text: String) {
guard let controller = self.getController() as? GiftViewScreen else {
return
@@ -1821,7 +1855,7 @@ private final class GiftViewSheetContent: CombinedComponent {
self.updated(transition: .spring(duration: 0.4))
Queue.mainQueue().after(0.5) {
Queue.mainQueue().after(2.5) {
switch finalPrice.currency {
case .stars:
context.starsContext?.load(force: true)
@@ -2114,7 +2148,7 @@ private final class GiftViewSheetContent: CombinedComponent {
self.subject = .profileGift(peerId, result)
self.updated(transition: .spring(duration: 0.4))
Queue.mainQueue().after(0.5) {
Queue.mainQueue().after(2.5) {
starsContext?.load(force: true)
}
})
@@ -2233,7 +2267,7 @@ private final class GiftViewSheetContent: CombinedComponent {
guard let self else {
return
}
Queue.mainQueue().after(0.5) {
Queue.mainQueue().after(2.5) {
starsContext?.load(force: true)
}
@@ -2337,6 +2371,7 @@ private final class GiftViewSheetContent: CombinedComponent {
guard let gift = self.subject.arguments?.gift, case let .unique(uniqueGift) = gift, case let .peerId(ownerPeerId) = uniqueGift.owner, let controller = self.getController() else {
return
}
let presentationData = self.context.sharedContext.currentPresentationData.with { $0 }
let _ = (self.context.engine.data.get(TelegramEngine.EngineData.Item.Peer.Peer(id: ownerPeerId))
|> deliverOnMainQueue).start(next: { [weak self] peer in
guard let self, let peer else {
@@ -2346,13 +2381,41 @@ private final class GiftViewSheetContent: CombinedComponent {
guard let self else {
return
}
self.commitGiftBuyOffer(peer: peer, price: amount, duration: duration)
let _ = (self.context.engine.data.get(TelegramEngine.EngineData.Item.Peer.SendPaidMessageStars(id: peer.id))
|> deliverOnMainQueue).start(next: { [weak self, weak controller] sendPaidMessageStars in
guard let self else {
return
}
let action: (Int64?) -> Void = { allowPaidStars in
self.commitGiftBuyOffer(peer: peer, price: amount, duration: duration, allowPaidStars: allowPaidStars)
}
if let sendPaidMessageStars, sendPaidMessageStars.value > 0 {
let alertController = chatMessagePaymentAlertController(
context: nil,
presentationData: presentationData,
updatedPresentationData: nil,
peers: [EngineRenderedPeer(peer: peer)],
count: 1,
amount: sendPaidMessageStars,
totalAmount: nil,
hasCheck: false,
navigationController: controller?.navigationController as? NavigationController,
completion: { _ in
action(sendPaidMessageStars.value)
}
)
controller?.present(alertController, in: .window(.root))
} else {
action(nil)
}
})
}))
controller.push(buyController)
})
}
func commitGiftBuyOffer(peer: EnginePeer, price: CurrencyAmount, duration: Int32) {
func commitGiftBuyOffer(peer: EnginePeer, price: CurrencyAmount, duration: Int32, allowPaidStars: Int64?) {
guard let gift = self.subject.arguments?.gift, case let .unique(uniqueGift) = gift, let starsContext = self.context.starsContext, let starsState = starsContext.currentState else {
return
}
@@ -2362,13 +2425,13 @@ private final class GiftViewSheetContent: CombinedComponent {
guard let self else {
return
}
self.upgradeDisposable = (context.engine.payments.sendStarGiftOffer(peerId: peer.id, slug: uniqueGift.slug, amount: price, duration: duration, allowPaidStars: nil)
self.upgradeDisposable = (context.engine.payments.sendStarGiftOffer(peerId: peer.id, slug: uniqueGift.slug, amount: price, duration: duration, allowPaidStars: allowPaidStars)
|> deliverOnMainQueue).start(error: { _ in
}, completed: { [weak self, weak starsContext] in
guard let self else {
return
}
Queue.mainQueue().after(0.5) {
Queue.mainQueue().after(2.5) {
starsContext?.load(force: true)
}
self.openPeer(peer, dismiss: true)
@@ -2383,11 +2446,15 @@ private final class GiftViewSheetContent: CombinedComponent {
guard let self, let controller = self.getController() else {
return
}
var finalStars = price.amount.value
if let allowPaidStars {
finalStars += allowPaidStars
}
let purchaseController = context.sharedContext.makeStarsPurchaseScreen(
context: context,
starsContext: starsContext,
options: options ?? [],
purpose: .starGiftOffer(requiredStars: price.amount.value),
purpose: .starGiftOffer(requiredStars: finalStars),
targetPeerId: nil,
customTheme: nil,
completion: { [weak self, weak starsContext] stars in
@@ -2411,7 +2478,7 @@ private final class GiftViewSheetContent: CombinedComponent {
self.inProgress = false
self.updated()
self.commitGiftBuyOffer(peer: peer, price: price, duration: duration)
self.commitGiftBuyOffer(peer: peer, price: price, duration: duration, allowPaidStars: allowPaidStars)
} else {
proceed()
}
@@ -2480,10 +2547,11 @@ private final class GiftViewSheetContent: CombinedComponent {
let upgradeNextButton = Child(PlainButtonComponent.self)
let upgradeTitle = Child(MultilineTextComponent.self)
let upgradeDescription = Child(BalancedTextComponent.self)
let upgradeDescription = Child(PlainButtonComponent.self)
let upgradePerks = Child(List<Empty>.self)
let upgradeKeepName = Child(PlainButtonComponent.self)
let upgradePriceButton = Child(PlainButtonComponent.self)
let variantsMeasureDescription = Child(MultilineTextComponent.self)
let spaceRegex = try? NSRegularExpression(pattern: "\\[(.*?)\\]", options: [])
@@ -2687,10 +2755,10 @@ private final class GiftViewSheetContent: CombinedComponent {
}
headerSubject = .unique(state.justUpgraded ? state.upgradePreview?.attributes : nil, uniqueGift)
} else if state.inUpgradePreview, let attributes = state.upgradePreview?.attributes {
headerHeight = 258.0
headerHeight = 246.0
headerSubject = .preview(attributes)
} else if case let .upgradePreview(attributes, _) = component.subject {
headerHeight = 258.0
headerHeight = 246.0
headerSubject = .preview(attributes)
} else if case let .wearPreview(_, attributes) = component.subject, let attributes {
headerHeight = 200.0
@@ -2944,9 +3012,7 @@ private final class GiftViewSheetContent: CombinedComponent {
originY += 16.0
} else if showUpgradePreview {
let title: String
let description: String
let uniqueText: String
let transferableText: String
let tradableText: String
if !incoming, case let .profileGift(peerId, _) = subject, let peer = state.peerMap[peerId] {
var peerName = peer.compactDisplayTitle
@@ -2954,9 +3020,7 @@ private final class GiftViewSheetContent: CombinedComponent {
peerName = "\(peerName.prefix(22))"
}
title = environment.strings.Gift_Upgrade_GiftTitle
description = environment.strings.Gift_Upgrade_GiftDescription(peerName).string
uniqueText = strings.Gift_Upgrade_Unique_GiftDescription(peerName).string
transferableText = strings.Gift_Upgrade_Transferable_GiftDescription(peerName).string
tradableText = strings.Gift_Upgrade_Tradable_GiftDescription(peerName).string
} else if case let .upgradePreview(_, peerName) = component.subject {
var peerName = peerName
@@ -2964,15 +3028,11 @@ private final class GiftViewSheetContent: CombinedComponent {
peerName = "\(peerName.prefix(22))"
}
title = environment.strings.Gift_Upgrade_IncludeTitle
description = environment.strings.Gift_Upgrade_IncludeDescription(peerName).string
uniqueText = strings.Gift_Upgrade_Unique_IncludeDescription
transferableText = strings.Gift_Upgrade_Transferable_IncludeDescription
tradableText = strings.Gift_Upgrade_Tradable_IncludeDescription
} else {
title = environment.strings.Gift_Upgrade_Title
description = environment.strings.Gift_Upgrade_Description
uniqueText = strings.Gift_Upgrade_Unique_Description
transferableText = strings.Gift_Upgrade_Transferable_Description
tradableText = strings.Gift_Upgrade_Tradable_Description
}
@@ -2990,39 +3050,119 @@ private final class GiftViewSheetContent: CombinedComponent {
availableSize: CGSize(width: context.availableSize.width - sideInset * 2.0 - 60.0, height: CGFloat.greatestFiniteMagnitude),
transition: .immediate
)
let upgradeDescription = upgradeDescription.update(
component: BalancedTextComponent(
text: .plain(NSAttributedString(
string: description,
font: Font.regular(13.0),
textColor: .white,
paragraphAlignment: .center
)),
horizontalAlignment: .center,
maximumNumberOfLines: 5,
lineSpacing: 0.2,
tintColor: vibrantColor
),
availableSize: CGSize(width: context.availableSize.width - sideInset * 2.0 - 50.0, height: CGFloat.greatestFiniteMagnitude),
transition: context.transition
)
let spacing: CGFloat = 6.0
let totalHeight: CGFloat = upgradeTitle.size.height + spacing + upgradeDescription.size.height
headerComponents.append({
context.add(upgradeTitle
.position(CGPoint(x: context.availableSize.width / 2.0, y: floor(212.0 - totalHeight / 2.0 + upgradeTitle.size.height / 2.0)))
.appear(.default(alpha: true))
.disappear(.default(alpha: true))
if case let .generic(gift) = component.subject.arguments?.gift, let upgradePreview = state.upgradePreview {
var variant1: GiftItemComponent.Subject = .starGift(gift: gift, price: "")
var variant2: GiftItemComponent.Subject = .starGift(gift: gift, price: "")
var variant3: GiftItemComponent.Subject = .starGift(gift: gift, price: "")
var i = 0
for attribute in upgradePreview.attributes {
if case .model = attribute {
switch i {
case 0:
variant1 = .preview(attributes: [attribute], rarity: 0)
case 1:
variant2 = .preview(attributes: [attribute], rarity: 0)
case 2:
variant3 = .preview(attributes: [attribute], rarity: 0)
default:
break
}
i += 1
}
}
var buttonColor: UIColor = UIColor.white.withAlphaComponent(0.16)
if let previewPatternColor = giftCompositionExternalState.previewPatternColor {
buttonColor = previewPatternColor
}
let variantsMeasureDescription = variantsMeasureDescription.update(
component: MultilineTextComponent(text: .plain(NSAttributedString(string: strings.Gift_Upgrade_ViewAllVariants, font: Font.semibold(13.0), textColor: .clear))),
availableSize: context.availableSize,
transition: .immediate
)
context.add(variantsMeasureDescription
.position(CGPoint(x: -10000.0, y: -10000.0))
)
context.add(upgradeDescription
.position(CGPoint(x: context.availableSize.width / 2.0, y: floor(212.0 + totalHeight / 2.0 - upgradeDescription.size.height / 2.0)))
.appear(.default(alpha: true))
.disappear(.default(alpha: true))
let upgradeDescription = upgradeDescription.update(
component: PlainButtonComponent(
content: AnyComponent(
ZStack([
AnyComponentWithIdentity(id: "background", component: AnyComponent(
FilledRoundedRectangleComponent(color: buttonColor, cornerRadius: .minEdge, smoothCorners: false)
)),
AnyComponentWithIdentity(id: "label", component: AnyComponent(HStack([
AnyComponentWithIdentity(id: "icon1", component: AnyComponent(
GiftItemComponent(
context: component.context,
theme: theme,
strings: strings,
peer: nil,
subject: variant1,
isPlaceholder: false,
mode: .tableIcon
)
)),
AnyComponentWithIdentity(id: "icon2", component: AnyComponent(
GiftItemComponent(
context: component.context,
theme: theme,
strings: strings,
peer: nil,
subject: variant2,
isPlaceholder: false,
mode: .tableIcon
)
)),
AnyComponentWithIdentity(id: "icon3", component: AnyComponent(
GiftItemComponent(
context: component.context,
theme: theme,
strings: strings,
peer: nil,
subject: variant3,
isPlaceholder: false,
mode: .tableIcon
)
)),
AnyComponentWithIdentity(id: "text", component: AnyComponent(
MultilineTextComponent(text: .plain(NSAttributedString(string: strings.Gift_Upgrade_ViewAllVariants, font: Font.semibold(13.0), textColor: .white)))
)),
AnyComponentWithIdentity(id: "arrow", component: AnyComponent(
BundleIconComponent(name: "Item List/InlineTextRightArrow", tintColor: .white)
))
], spacing: 3.0)))
])
),
action: { [weak state] in
state?.openUpgradeVariants()
},
animateScale: false
),
availableSize: CGSize(width: variantsMeasureDescription.size.width + 87.0, height: 24.0),
transition: context.transition
)
})
let spacing: CGFloat = 6.0
let totalHeight: CGFloat = upgradeTitle.size.height + spacing + upgradeDescription.size.height
headerComponents.append({
context.add(upgradeTitle
.position(CGPoint(x: context.availableSize.width / 2.0, y: floor(194.0 - totalHeight / 2.0 + upgradeTitle.size.height / 2.0)))
.appear(.default(alpha: true))
.disappear(.default(alpha: true))
)
context.add(upgradeDescription
.position(CGPoint(x: context.availableSize.width / 2.0, y: floor(198.0 + totalHeight / 2.0 - upgradeDescription.size.height / 2.0)))
.appear(.default(alpha: true))
.disappear(.default(alpha: true))
)
})
}
originY += 24.0
let textColor = theme.actionSheet.primaryTextColor
@@ -3044,20 +3184,6 @@ private final class GiftViewSheetContent: CombinedComponent {
))
)
)
items.append(
AnyComponentWithIdentity(
id: "transferable",
component: AnyComponent(InfoParagraphComponent(
title: strings.Gift_Upgrade_Transferable_Title,
titleColor: textColor,
text: transferableText,
textColor: secondaryTextColor,
accentColor: linkColor,
iconName: "Premium/Collectible/Transferable",
iconColor: linkColor
))
)
)
items.append(
AnyComponentWithIdentity(
id: "tradable",
@@ -3072,6 +3198,20 @@ private final class GiftViewSheetContent: CombinedComponent {
))
)
)
items.append(
AnyComponentWithIdentity(
id: "wearable",
component: AnyComponent(InfoParagraphComponent(
title: strings.Gift_Upgrade_Wearable_Title,
titleColor: textColor,
text: strings.Gift_Upgrade_Wearable_Text,
textColor: secondaryTextColor,
accentColor: linkColor,
iconName: "Premium/Collectible/Wearable",
iconColor: linkColor
))
)
)
let perksSideInset = sideInset + 16.0
let upgradePerks = upgradePerks.update(
@@ -3564,7 +3704,7 @@ private final class GiftViewSheetContent: CombinedComponent {
id: AnyHashable(0),
component: AnyComponent(Button(
content: AnyComponent(
PeerCellComponent(
PeerTableCellComponent(
context: component.context,
theme: theme,
strings: strings,
@@ -3597,7 +3737,7 @@ private final class GiftViewSheetContent: CombinedComponent {
} else {
ownerComponent = AnyComponent(Button(
content: AnyComponent(
PeerCellComponent(
PeerTableCellComponent(
context: component.context,
theme: theme,
strings: strings,
@@ -3648,7 +3788,7 @@ private final class GiftViewSheetContent: CombinedComponent {
title: strings.Gift_Unique_Telegram,
component: AnyComponent(Button(
content: AnyComponent(
PeerCellComponent(
PeerTableCellComponent(
context: component.context,
theme: theme,
strings: strings,
@@ -3678,7 +3818,7 @@ private final class GiftViewSheetContent: CombinedComponent {
id: AnyHashable(0),
component: AnyComponent(Button(
content: AnyComponent(
PeerCellComponent(
PeerTableCellComponent(
context: component.context,
theme: theme,
strings: strings,
@@ -3708,7 +3848,7 @@ private final class GiftViewSheetContent: CombinedComponent {
} else {
fromComponent = AnyComponent(Button(
content: AnyComponent(
PeerCellComponent(
PeerTableCellComponent(
context: component.context,
theme: theme,
strings: strings,
@@ -3733,7 +3873,7 @@ private final class GiftViewSheetContent: CombinedComponent {
id: "from_anon",
title: strings.Gift_View_From,
component: AnyComponent(
PeerCellComponent(
PeerTableCellComponent(
context: component.context,
theme: theme,
strings: strings,
@@ -4117,7 +4257,7 @@ private final class GiftViewSheetContent: CombinedComponent {
color: theme.list.itemAccentColor
)),
action: { [weak state] in
state?.showAttributeInfo(tag: tag, text: strings.Gift_Unique_AttributeDescription(formatPercentage(percentage)).string)
state?.openUpgradeVariants(attribute: attribute)
}
).tagged(tag))
))
@@ -5164,42 +5304,50 @@ final class GiftViewSheetComponent: CombinedComponent {
var headerContent: AnyComponent<Empty>?
if let arguments = context.component.subject.arguments, case .unique = arguments.gift, let fromPeerId = arguments.fromPeerId, var fromPeerName = arguments.fromPeerName, arguments.fromPeerId != context.component.context.account.peerId && !(arguments.fromPeerId?.isTelegramNotifications ?? false) {
let dateString = stringForMediumDate(timestamp: arguments.date, strings: environment.strings, dateTimeFormat: environment.dateTimeFormat, withTime: false)
if fromPeerName.count > 25 {
fromPeerName = "\(fromPeerName.prefix(25))"
var showSenderInfo = false
if arguments.incoming {
showSenderInfo = true
} else if arguments.peerId == context.component.context.account.peerId {
showSenderInfo = true
}
if showSenderInfo {
let dateString = stringForMediumDate(timestamp: arguments.date, strings: environment.strings, dateTimeFormat: environment.dateTimeFormat, withTime: false)
if fromPeerName.count > 25 {
fromPeerName = "\(fromPeerName.prefix(25))"
}
let rawString = environment.strings.Gift_View_SenderInfo(fromPeerName, dateString).string
let attributedString = parseMarkdownIntoAttributedString(rawString, attributes: MarkdownAttributes(body: MarkdownAttributeSet(font: Font.regular(13.0), textColor: .white), bold: MarkdownAttributeSet(font: Font.semibold(13.0), textColor: .white), link: MarkdownAttributeSet(font: Font.regular(13.0), textColor: .white), linkAttribute: { _ in return nil }))
let context = context.component.context
headerContent = AnyComponent(
PlainButtonComponent(content: AnyComponent(HeaderContentComponent(attributedText: attributedString)), action: {
if let controller = controller(), let navigationController = controller.navigationController as? NavigationController {
let _ = (context.engine.data.get(TelegramEngine.EngineData.Item.Peer.Peer(id: fromPeerId))
|> deliverOnMainQueue).start(next: { [weak navigationController] peer in
guard let peer, let navigationController else {
return
}
context.sharedContext.navigateToChatController(NavigateToChatControllerParams(
navigationController: navigationController,
chatController: nil,
context: context,
chatLocation: .peer(peer),
subject: nil,
botStart: nil,
updateTextInputState: nil,
keepStack: .always,
useExisting: true,
purposefulAction: nil,
scrollToEndIfExists: false,
activateMessageSearch: nil,
animated: true
))
})
}
})
)
}
let rawString = environment.strings.Gift_View_SenderInfo(fromPeerName, dateString).string
let attributedString = parseMarkdownIntoAttributedString(rawString, attributes: MarkdownAttributes(body: MarkdownAttributeSet(font: Font.regular(13.0), textColor: .white), bold: MarkdownAttributeSet(font: Font.semibold(13.0), textColor: .white), link: MarkdownAttributeSet(font: Font.regular(13.0), textColor: .white), linkAttribute: { _ in return nil }))
let context = context.component.context
headerContent = AnyComponent(
PlainButtonComponent(content: AnyComponent(HeaderContentComponent(attributedText: attributedString)), action: {
if let controller = controller(), let navigationController = controller.navigationController as? NavigationController {
let _ = (context.engine.data.get(TelegramEngine.EngineData.Item.Peer.Peer(id: fromPeerId))
|> deliverOnMainQueue).start(next: { [weak navigationController] peer in
guard let peer, let navigationController else {
return
}
context.sharedContext.navigateToChatController(NavigateToChatControllerParams(
navigationController: navigationController,
chatController: nil,
context: context,
chatLocation: .peer(peer),
subject: nil,
botStart: nil,
updateTextInputState: nil,
keepStack: .always,
useExisting: true,
purposefulAction: nil,
scrollToEndIfExists: false,
activateMessageSearch: nil,
animated: true
))
})
}
})
)
}
let sheet = sheet.update(
@@ -5742,115 +5890,6 @@ func formatPercentage(_ value: Float) -> String {
return String(format: "%0.1f", value).replacingOccurrences(of: ".0", with: "").replacingOccurrences(of: ",0", with: "") + "%"
}
final class PeerCellComponent: Component {
let context: AccountContext
let theme: PresentationTheme
let strings: PresentationStrings
let peer: EnginePeer?
init(context: AccountContext, theme: PresentationTheme, strings: PresentationStrings, peer: EnginePeer?) {
self.context = context
self.theme = theme
self.strings = strings
self.peer = peer
}
static func ==(lhs: PeerCellComponent, rhs: PeerCellComponent) -> Bool {
if lhs.context !== rhs.context {
return false
}
if lhs.theme !== rhs.theme {
return false
}
if lhs.strings !== rhs.strings {
return false
}
if lhs.peer != rhs.peer {
return false
}
return true
}
final class View: UIView {
private let avatarNode: AvatarNode
private let text = ComponentView<Empty>()
private var component: PeerCellComponent?
private weak var state: EmptyComponentState?
override init(frame: CGRect) {
self.avatarNode = AvatarNode(font: avatarPlaceholderFont(size: 8.0))
super.init(frame: frame)
self.addSubnode(self.avatarNode)
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
func update(component: PeerCellComponent, availableSize: CGSize, state: EmptyComponentState, environment: Environment<Empty>, transition: ComponentTransition) -> CGSize {
self.component = component
self.state = state
let avatarSize = CGSize(width: 22.0, height: 22.0)
let spacing: CGFloat = 6.0
var peerName: String
let avatarOverride: AvatarNodeImageOverride?
if let peerValue = component.peer {
peerName = peerValue.compactDisplayTitle
if peerName.count > 40 {
peerName = "\(peerName.prefix(40))"
}
avatarOverride = nil
} else {
peerName = component.strings.Gift_View_HiddenName
avatarOverride = .anonymousSavedMessagesIcon(isColored: true)
}
let avatarNaturalSize = CGSize(width: 40.0, height: 40.0)
self.avatarNode.setPeer(context: component.context, theme: component.theme, peer: component.peer, overrideImage: avatarOverride)
self.avatarNode.bounds = CGRect(origin: .zero, size: avatarNaturalSize)
let textSize = self.text.update(
transition: .immediate,
component: AnyComponent(
MultilineTextComponent(
text: .plain(NSAttributedString(string: peerName, font: Font.regular(15.0), textColor: component.peer != nil ? component.theme.list.itemAccentColor : component.theme.list.itemPrimaryTextColor, paragraphAlignment: .left))
)
),
environment: {},
containerSize: CGSize(width: availableSize.width - avatarSize.width - spacing, height: availableSize.height)
)
let size = CGSize(width: avatarSize.width + textSize.width + spacing, height: textSize.height)
let avatarFrame = CGRect(origin: CGPoint(x: 0.0, y: floorToScreenPixels((size.height - avatarSize.height) / 2.0)), size: avatarSize)
self.avatarNode.frame = avatarFrame
if let view = self.text.view {
if view.superview == nil {
self.addSubview(view)
}
let textFrame = CGRect(origin: CGPoint(x: avatarSize.width + spacing, y: floorToScreenPixels((size.height - textSize.height) / 2.0)), size: textSize)
transition.setFrame(view: view, frame: textFrame)
}
return size
}
}
func makeView() -> View {
return View(frame: CGRect())
}
func update(view: View, availableSize: CGSize, state: EmptyComponentState, environment: Environment<Empty>, transition: ComponentTransition) -> CGSize {
return view.update(component: self, availableSize: availableSize, state: state, environment: environment, transition: transition)
}
}
final class HeaderContentComponent: Component {
let attributedText: NSAttributedString
@@ -6165,73 +6204,6 @@ private final class HeaderButtonComponent: CombinedComponent {
}
}
final class AvatarComponent: Component {
let context: AccountContext
let theme: PresentationTheme
let peer: EnginePeer
init(context: AccountContext, theme: PresentationTheme, peer: EnginePeer) {
self.context = context
self.theme = theme
self.peer = peer
}
static func ==(lhs: AvatarComponent, rhs: AvatarComponent) -> Bool {
if lhs.context !== rhs.context {
return false
}
if lhs.theme !== rhs.theme {
return false
}
if lhs.peer != rhs.peer {
return false
}
return true
}
final class View: UIView {
private let avatarNode: AvatarNode
private var component: AvatarComponent?
private weak var state: EmptyComponentState?
override init(frame: CGRect) {
self.avatarNode = AvatarNode(font: avatarPlaceholderFont(size: 42.0))
super.init(frame: frame)
self.addSubnode(self.avatarNode)
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
func update(component: AvatarComponent, availableSize: CGSize, state: EmptyComponentState, environment: Environment<Empty>, transition: ComponentTransition) -> CGSize {
self.component = component
self.state = state
self.avatarNode.frame = CGRect(origin: .zero, size: availableSize)
self.avatarNode.setPeer(
context: component.context,
theme: component.theme,
peer: component.peer,
synchronousLoad: true
)
return availableSize
}
}
func makeView() -> View {
return View(frame: CGRect())
}
func update(view: View, availableSize: CGSize, state: EmptyComponentState, environment: Environment<Empty>, transition: ComponentTransition) -> CGSize {
return view.update(component: self, availableSize: availableSize, state: state, environment: environment, transition: transition)
}
}
private struct GiftViewConfiguration {
public static var defaultValue: GiftViewConfiguration {
return GiftViewConfiguration(explorerUrl: "https://tonviewer.com")