mirror of
https://github.com/TelegramMessenger/Telegram-iOS.git
synced 2026-07-06 03:33:41 +02:00
Various improvements
This commit is contained in:
parent
3e483aad40
commit
94ee23649d
15 changed files with 387 additions and 56 deletions
|
|
@ -15017,4 +15017,4 @@ Sorry for the inconvenience.";
|
|||
|
||||
"Stars.Purchase.RemoveOriginalDetailsStarGiftInfo" = "Buy Stars to remove original details of your gift.";
|
||||
|
||||
|
||||
"Notification.StarGift.TitleTo" = "Gift for %@";
|
||||
|
|
|
|||
|
|
@ -703,6 +703,7 @@ public enum PeerInfoControllerMode {
|
|||
case recommendedChannels
|
||||
case myProfile
|
||||
case gifts
|
||||
case upgradableGifts
|
||||
case myProfileGifts
|
||||
case groupsInCommon
|
||||
case monoforum(EnginePeer.Id)
|
||||
|
|
|
|||
|
|
@ -60,6 +60,7 @@ public final class SheetComponent<ChildEnvironmentType: Sendable & Equatable>: C
|
|||
}
|
||||
|
||||
public let content: AnyComponent<ChildEnvironmentType>
|
||||
public let headerContent: AnyComponent<Empty>?
|
||||
public let backgroundColor: BackgroundColor
|
||||
public let followContentSizeChanges: Bool
|
||||
public let clipsContent: Bool
|
||||
|
|
@ -73,6 +74,7 @@ public final class SheetComponent<ChildEnvironmentType: Sendable & Equatable>: C
|
|||
|
||||
public init(
|
||||
content: AnyComponent<ChildEnvironmentType>,
|
||||
headerContent: AnyComponent<Empty>? = nil,
|
||||
backgroundColor: BackgroundColor,
|
||||
followContentSizeChanges: Bool = false,
|
||||
clipsContent: Bool = false,
|
||||
|
|
@ -85,6 +87,7 @@ public final class SheetComponent<ChildEnvironmentType: Sendable & Equatable>: C
|
|||
willDismiss: @escaping () -> Void = {}
|
||||
) {
|
||||
self.content = content
|
||||
self.headerContent = headerContent
|
||||
self.backgroundColor = backgroundColor
|
||||
self.followContentSizeChanges = followContentSizeChanges
|
||||
self.clipsContent = clipsContent
|
||||
|
|
@ -101,6 +104,9 @@ public final class SheetComponent<ChildEnvironmentType: Sendable & Equatable>: C
|
|||
if lhs.content != rhs.content {
|
||||
return false
|
||||
}
|
||||
if lhs.headerContent != rhs.headerContent {
|
||||
return false
|
||||
}
|
||||
if lhs.backgroundColor != rhs.backgroundColor {
|
||||
return false
|
||||
}
|
||||
|
|
@ -159,6 +165,7 @@ public final class SheetComponent<ChildEnvironmentType: Sendable & Equatable>: C
|
|||
private let backgroundView: UIView
|
||||
private var effectView: UIVisualEffectView?
|
||||
private let contentView: ComponentView<ChildEnvironmentType>
|
||||
private var headerView: ComponentView<Empty>?
|
||||
|
||||
private var isAnimatingOut: Bool = false
|
||||
private var previousIsDisplaying: Bool = false
|
||||
|
|
@ -272,10 +279,12 @@ public final class SheetComponent<ChildEnvironmentType: Sendable & Equatable>: C
|
|||
}
|
||||
|
||||
override public func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
|
||||
if let headerView = self.headerView?.view, headerView.bounds.contains(self.convert(point, to: headerView)) {
|
||||
return super.hitTest(point, with: event)
|
||||
}
|
||||
if !self.backgroundView.bounds.contains(self.convert(point, to: self.backgroundView)) {
|
||||
return self.dimView
|
||||
}
|
||||
|
||||
return super.hitTest(point, with: event)
|
||||
}
|
||||
|
||||
|
|
@ -288,6 +297,10 @@ public final class SheetComponent<ChildEnvironmentType: Sendable & Equatable>: C
|
|||
transition.animateView(allowUserInteraction: true, {
|
||||
self.scrollView.center = targetPosition
|
||||
})
|
||||
|
||||
if let headerContent = self.headerView {
|
||||
headerContent.view?.layer.animateAlpha(from: 0.1, to: 0.0, duration: 0.15)
|
||||
}
|
||||
}
|
||||
|
||||
private func animateOut(initialVelocity: CGFloat? = nil, completion: @escaping () -> Void) {
|
||||
|
|
@ -300,6 +313,10 @@ public final class SheetComponent<ChildEnvironmentType: Sendable & Equatable>: C
|
|||
self.isUserInteractionEnabled = false
|
||||
self.dimView.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.3, removeOnCompletion: false)
|
||||
|
||||
if let headerContent = self.headerView {
|
||||
headerContent.view?.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.15, removeOnCompletion: false)
|
||||
}
|
||||
|
||||
guard let contentView = self.contentView.view else {
|
||||
return
|
||||
}
|
||||
|
|
@ -404,6 +421,33 @@ public final class SheetComponent<ChildEnvironmentType: Sendable & Equatable>: C
|
|||
}
|
||||
transition.setFrame(view: self.scrollView, frame: CGRect(origin: CGPoint(), size: availableSize), completion: nil)
|
||||
|
||||
if let headerContent = component.headerContent {
|
||||
let headerView: ComponentView<Empty>
|
||||
if let current = self.headerView {
|
||||
headerView = current
|
||||
} else {
|
||||
headerView = ComponentView()
|
||||
self.headerView = headerView
|
||||
}
|
||||
|
||||
let headerSize = headerView.update(
|
||||
transition: transition,
|
||||
component: headerContent,
|
||||
environment: {},
|
||||
containerSize: CGSize(width: contentSize.width, height: 44.0)
|
||||
)
|
||||
let headerFrame = CGRect(origin: CGPoint(x: floorToScreenPixels((availableSize.width - headerSize.width) / 2.0), y: self.backgroundView.frame.minY - headerSize.height - 10.0), size: headerSize)
|
||||
if let headerView = headerView.view {
|
||||
if headerView.superview == nil {
|
||||
self.scrollView.addSubview(headerView)
|
||||
}
|
||||
transition.setFrame(view: headerView, frame: headerFrame)
|
||||
}
|
||||
} else if let headerView = self.headerView {
|
||||
self.headerView = nil
|
||||
headerView.view?.removeFromSuperview()
|
||||
}
|
||||
|
||||
let previousContentSize = self.scrollView.contentSize
|
||||
let updateContentSize = {
|
||||
self.scrollView.contentSize = contentSize
|
||||
|
|
|
|||
|
|
@ -558,7 +558,7 @@ public class ChatMessageGiftBubbleContentNode: ChatMessageBubbleContentNode {
|
|||
|
||||
isStarGift = true
|
||||
var authorName = item.message.author.flatMap { EnginePeer($0) }?.compactDisplayTitle ?? ""
|
||||
|
||||
|
||||
let isSelfGift = item.message.id.peerId == item.context.account.peerId
|
||||
let isChannelGift = item.message.id.peerId.namespace == Namespaces.Peer.CloudChannel || channelPeerId != nil
|
||||
if isSelfGift {
|
||||
|
|
@ -569,8 +569,12 @@ public class ChatMessageGiftBubbleContentNode: ChatMessageBubbleContentNode {
|
|||
} else {
|
||||
if let senderPeerId, let name = item.message.peers[senderPeerId].flatMap(EnginePeer.init)?.compactDisplayTitle {
|
||||
authorName = name
|
||||
title = item.presentationData.strings.Notification_StarGift_Title(authorName).string
|
||||
} else if !incoming, let name = item.message.peers[item.message.id.peerId].flatMap(EnginePeer.init)?.compactDisplayTitle {
|
||||
title = item.presentationData.strings.Notification_StarGift_TitleTo(name).string
|
||||
} else {
|
||||
title = item.presentationData.strings.Gift_View_Unknown_Title
|
||||
}
|
||||
title = item.presentationData.strings.Notification_StarGift_Title(authorName).string
|
||||
}
|
||||
}
|
||||
if let giftText, !giftText.isEmpty {
|
||||
|
|
@ -647,7 +651,11 @@ public class ChatMessageGiftBubbleContentNode: ChatMessageBubbleContentNode {
|
|||
buttonTitle = item.presentationData.strings.Notification_StarGift_Unpack
|
||||
buttonIcon = "GiftUnpack"
|
||||
} else {
|
||||
buttonTitle = item.presentationData.strings.Notification_StarGift_View
|
||||
if isPrepaidUpgrade && !incoming {
|
||||
buttonTitle = ""
|
||||
} else {
|
||||
buttonTitle = item.presentationData.strings.Notification_StarGift_View
|
||||
}
|
||||
}
|
||||
}
|
||||
case let .starGiftUnique(gift, isUpgrade, _, _, _, _, isRefunded, _, _, _, _, _, _, _, _):
|
||||
|
|
|
|||
|
|
@ -41,6 +41,7 @@ public final class EmojiStatusComponent: Component {
|
|||
public enum SizeType {
|
||||
case compact
|
||||
case large
|
||||
case smaller
|
||||
}
|
||||
|
||||
public enum Content: Equatable {
|
||||
|
|
@ -357,7 +358,7 @@ public final class EmojiStatusComponent: Component {
|
|||
case let .verified(fillColor, foregroundColor, sizeType):
|
||||
let imageNamePrefix: String
|
||||
switch sizeType {
|
||||
case .compact:
|
||||
case .compact, .smaller:
|
||||
imageNamePrefix = "Chat List/PeerVerifiedIcon"
|
||||
case .large:
|
||||
imageNamePrefix = "Peer Info/VerifiedIcon"
|
||||
|
|
|
|||
|
|
@ -506,14 +506,27 @@ final class GiftOptionsScreenComponent: Component {
|
|||
}
|
||||
isSoldOut = true
|
||||
} else if let _ = gift.availability {
|
||||
let text: String
|
||||
if let perUserLimit = gift.perUserLimit {
|
||||
text = "\(perUserLimit.remains) left"
|
||||
} else {
|
||||
text = environment.strings.Gift_Options_Gift_Limited
|
||||
}
|
||||
ribbon = GiftItemComponent.Ribbon(
|
||||
text: environment.strings.Gift_Options_Gift_Limited,
|
||||
text: text,
|
||||
color: .blue
|
||||
)
|
||||
}
|
||||
if !isSoldOut && gift.flags.contains(.requiresPremium) {
|
||||
let text: String
|
||||
if component.context.isPremium, let perUserLimit = gift.perUserLimit {
|
||||
//TODO:localize
|
||||
text = "\(perUserLimit.remains) left"
|
||||
} else {
|
||||
text = environment.strings.Gift_Options_Gift_Premium
|
||||
}
|
||||
ribbon = GiftItemComponent.Ribbon(
|
||||
text: environment.strings.Gift_Options_Gift_Premium,
|
||||
text: text,
|
||||
color: .orange
|
||||
)
|
||||
outline = .orange
|
||||
|
|
|
|||
|
|
@ -457,6 +457,35 @@ final class GiftSetupScreenComponent: Component {
|
|||
controllers.append(chatController)
|
||||
}
|
||||
navigationController.setViewControllers(controllers, animated: true)
|
||||
|
||||
|
||||
if case let .starGift(starGift, _) = component.subject, let perUserLimit = starGift.perUserLimit {
|
||||
Queue.mainQueue().after(0.5) {
|
||||
//TODO:localize
|
||||
let remains = max(0, perUserLimit.remains - 1)
|
||||
let text: String
|
||||
if remains == 0 {
|
||||
text = "You've reached your limit on this gift."
|
||||
} else {
|
||||
text = "You can send **\(remains)** more."
|
||||
}
|
||||
let tooltipController = UndoOverlayController(
|
||||
presentationData: presentationData,
|
||||
content: .sticker(
|
||||
context: context,
|
||||
file: starGift.file,
|
||||
loop: true,
|
||||
title: "Gift Sent!",
|
||||
text: text,
|
||||
undoText: nil,
|
||||
customAction: nil
|
||||
),
|
||||
position: .top,
|
||||
action: { _ in return true }
|
||||
)
|
||||
(navigationController.viewControllers.last as? ViewController)?.present(tooltipController, in: .current)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if let completion {
|
||||
|
|
|
|||
|
|
@ -138,7 +138,7 @@ private final class GiftTransferAlertContentNode: AlertContentNode {
|
|||
return ("URL", url)
|
||||
}
|
||||
), textAlignment: .center)
|
||||
self.arrowNode.image = generateTintedImage(image: UIImage(bundleImageName: "Peer Info/AlertArrow"), color: theme.secondaryColor)
|
||||
self.arrowNode.image = generateTintedImage(image: UIImage(bundleImageName: "Peer Info/AlertArrow"), color: theme.secondaryColor.withAlphaComponent(0.9))
|
||||
|
||||
self.actionNodesSeparator.backgroundColor = theme.separatorColor
|
||||
for actionNode in self.actionNodes {
|
||||
|
|
|
|||
|
|
@ -537,7 +537,7 @@ private final class GiftViewSheetContent: CombinedComponent {
|
|||
action: { [weak navigationController] action in
|
||||
if case .undo = action, let navigationController, let giftsPeerId {
|
||||
let _ = (self.context.engine.data.get(TelegramEngine.EngineData.Item.Peer.Peer(id: giftsPeerId))
|
||||
|> deliverOnMainQueue).start(next: { [weak navigationController] peer in
|
||||
|> deliverOnMainQueue).start(next: { [weak navigationController] peer in
|
||||
guard let peer, let navigationController else {
|
||||
return
|
||||
}
|
||||
|
|
@ -564,7 +564,7 @@ private final class GiftViewSheetContent: CombinedComponent {
|
|||
}
|
||||
|
||||
func convertToStars() {
|
||||
guard let controller = self.getController() as? GiftViewScreen, let starsContext = context.starsContext, let arguments = self.subject.arguments, let reference = arguments.reference, let fromPeerName = arguments.fromPeerName, let convertStars = arguments.convertStars, let navigationController = controller.navigationController as? NavigationController else {
|
||||
guard let controller = self.getController() as? GiftViewScreen, let starsContext = context.starsContext, let arguments = self.subject.arguments, let reference = arguments.reference, let fromPeerName = arguments.fromPeerCompactName, let convertStars = arguments.convertStars, let navigationController = controller.navigationController as? NavigationController else {
|
||||
return
|
||||
}
|
||||
|
||||
|
|
@ -2036,7 +2036,7 @@ private final class GiftViewSheetContent: CombinedComponent {
|
|||
}
|
||||
|
||||
func commitPrepaidUpgrade() {
|
||||
guard let arguments = self.subject.arguments, let peerId = arguments.peerId, let prepaidUpgradeHash = arguments.prepaidUpgradeHash, let starsContext = self.context.starsContext, let starsState = starsContext.currentState else {
|
||||
guard let arguments = self.subject.arguments, let controller = self.getController() as? GiftViewScreen, let peerId = arguments.peerId, let prepaidUpgradeHash = arguments.prepaidUpgradeHash, let starsContext = self.context.starsContext, let starsState = starsContext.currentState else {
|
||||
return
|
||||
}
|
||||
guard case let .generic(gift) = arguments.gift else {
|
||||
|
|
@ -2046,6 +2046,7 @@ private final class GiftViewSheetContent: CombinedComponent {
|
|||
return
|
||||
}
|
||||
let context = self.context
|
||||
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
||||
let proceed: () -> Void = { [weak self, weak starsContext] in
|
||||
guard let self else {
|
||||
return
|
||||
|
|
@ -2068,7 +2069,7 @@ private final class GiftViewSheetContent: CombinedComponent {
|
|||
}
|
||||
|
||||
self.upgradeDisposable = (signal
|
||||
|> deliverOnMainQueue).start(next: { [weak self, weak starsContext] result in
|
||||
|> deliverOnMainQueue).start(next: { [weak self, weak controller, weak starsContext] result in
|
||||
guard let self else {
|
||||
return
|
||||
}
|
||||
|
|
@ -2076,12 +2077,54 @@ private final class GiftViewSheetContent: CombinedComponent {
|
|||
starsContext?.load(force: true)
|
||||
}
|
||||
|
||||
let navigationController = controller?.navigationController as? NavigationController
|
||||
let _ = (self.context.engine.data.get(TelegramEngine.EngineData.Item.Peer.Peer(id: peerId))
|
||||
|> deliverOnMainQueue).start(next: { [weak self] peer in
|
||||
|> deliverOnMainQueue).start(next: { [weak self, weak navigationController] peer in
|
||||
guard let self, let peer else {
|
||||
return
|
||||
}
|
||||
self.openPeer(peer, gifts: false, dismiss: true)
|
||||
|
||||
Queue.mainQueue().after(0.5) {
|
||||
if let lastController = navigationController?.viewControllers.last as? ViewController {
|
||||
let resultController = UndoOverlayController(
|
||||
presentationData: presentationData,
|
||||
content: .sticker(
|
||||
context: context,
|
||||
file: gift.file,
|
||||
loop: false,
|
||||
title: nil,
|
||||
text: "Upgrade sent!",
|
||||
undoText: "Gift More",
|
||||
customAction: nil
|
||||
),
|
||||
elevatedLayout: !(lastController is ChatController),
|
||||
action: { [weak navigationController] action in
|
||||
if case .undo = action, let navigationController {
|
||||
let _ = (self.context.engine.data.get(TelegramEngine.EngineData.Item.Peer.Peer(id: peerId))
|
||||
|> deliverOnMainQueue).start(next: { [weak navigationController] peer in
|
||||
guard let peer, let navigationController else {
|
||||
return
|
||||
}
|
||||
if let controller = context.sharedContext.makePeerInfoController(
|
||||
context: context,
|
||||
updatedPresentationData: nil,
|
||||
peer: peer._asPeer(),
|
||||
mode: .upgradableGifts,
|
||||
avatarInitiallyExpanded: false,
|
||||
fromChat: false,
|
||||
requestsContext: nil
|
||||
) {
|
||||
navigationController.pushViewController(controller, animated: true)
|
||||
}
|
||||
})
|
||||
}
|
||||
return true
|
||||
}
|
||||
)
|
||||
lastController.present(resultController, in: .current)
|
||||
}
|
||||
}
|
||||
})
|
||||
}, error: { _ in
|
||||
|
||||
|
|
@ -2092,8 +2135,8 @@ private final class GiftViewSheetContent: CombinedComponent {
|
|||
let _ = (self.optionsPromise.get()
|
||||
|> filter { $0 != nil }
|
||||
|> take(1)
|
||||
|> deliverOnMainQueue).startStandalone(next: { [weak self] options in
|
||||
guard let self, let controller = self.getController() else {
|
||||
|> deliverOnMainQueue).startStandalone(next: { [weak self, weak controller] options in
|
||||
guard let self, let controller else {
|
||||
return
|
||||
}
|
||||
let purchaseController = self.context.sharedContext.makeStarsPurchaseScreen(
|
||||
|
|
@ -4322,7 +4365,8 @@ private final class GiftViewSheetContent: CombinedComponent {
|
|||
buttonTitleItems.append(AnyComponentWithIdentity(id: "timer", component: AnyComponent(AnimatedTextComponent(
|
||||
font: Font.with(size: 11.0, weight: .medium, traits: .monospacedNumbers),
|
||||
color: environment.theme.list.itemCheckColors.foregroundColor.withAlphaComponent(0.7),
|
||||
items: buttonAnimatedTitleItems
|
||||
items: buttonAnimatedTitleItems,
|
||||
noDelay: true
|
||||
))))
|
||||
} else {
|
||||
buttonTitleItems.append(AnyComponentWithIdentity(id: "static_label", component: AnyComponent(MultilineTextComponent(text: .plain(buttonAttributedString)))))
|
||||
|
|
@ -4347,7 +4391,7 @@ private final class GiftViewSheetContent: CombinedComponent {
|
|||
availableSize: buttonSize,
|
||||
transition: .spring(duration: 0.2)
|
||||
)
|
||||
} else if upgraded, let upgradeMessageIdId = subject.arguments?.upgradeMessageId, let originalMessageId = subject.arguments?.messageId {
|
||||
} else if upgraded, let arguments = subject.arguments, let upgradeMessageIdId = arguments.upgradeMessageId, let originalMessageId = arguments.messageId, !arguments.upgradeSeparate {
|
||||
let upgradeMessageId = MessageId(peerId: originalMessageId.peerId, namespace: originalMessageId.namespace, id: upgradeMessageIdId)
|
||||
let buttonTitle = strings.Gift_View_ViewUpgraded
|
||||
buttonChild = button.update(
|
||||
|
|
@ -4564,13 +4608,13 @@ private final class GiftViewSheetContent: CombinedComponent {
|
|||
originY += buttonChild.size.height
|
||||
originY += 7.0
|
||||
|
||||
if showUpgradePreview {
|
||||
if showUpgradePreview, let _ = state.nextUpgradePrice {
|
||||
originY += 20.0
|
||||
|
||||
if state.cachedSmallChevronImage == nil || state.cachedSmallChevronImage?.1 !== environment.theme {
|
||||
state.cachedSmallChevronImage = (generateTintedImage(image: UIImage(bundleImageName: "Item List/InlineTextRightArrow"), color: theme.actionSheet.controlAccentColor)!, theme)
|
||||
}
|
||||
|
||||
//TODO:localize
|
||||
let attributedString = NSMutableAttributedString(string: "See how price will decrease >", font: Font.regular(13.0), textColor: theme.actionSheet.controlAccentColor)
|
||||
if let range = attributedString.string.range(of: ">"), let chevronImage = state.cachedSmallChevronImage?.0 {
|
||||
attributedString.addAttribute(.attachment, value: chevronImage, range: NSRange(range, in: attributedString.string))
|
||||
|
|
@ -4642,6 +4686,43 @@ final class GiftViewSheetComponent: CombinedComponent {
|
|||
let environment = context.environment[EnvironmentType.self]
|
||||
let controller = environment.controller
|
||||
|
||||
var headerContent: AnyComponent<Empty>?
|
||||
if let arguments = context.component.subject.arguments, case .unique = arguments.gift, let fromPeerId = arguments.fromPeerId, let fromPeerName = arguments.fromPeerName, arguments.fromPeerId != context.component.context.account.peerId {
|
||||
let dateString = stringForMediumDate(timestamp: arguments.date, strings: environment.strings, dateTimeFormat: environment.dateTimeFormat, withTime: false)
|
||||
|
||||
let rawString = "**\(fromPeerName)** sent you this gift on **\(dateString)**."
|
||||
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(
|
||||
component: SheetComponent<EnvironmentType>(
|
||||
content: AnyComponent<EnvironmentType>(GiftViewSheetContent(
|
||||
|
|
@ -4650,10 +4731,12 @@ final class GiftViewSheetComponent: CombinedComponent {
|
|||
animateOut: animateOut,
|
||||
getController: controller
|
||||
)),
|
||||
headerContent: headerContent,
|
||||
backgroundColor: .color(environment.theme.actionSheet.opaqueItemBackgroundColor),
|
||||
followContentSizeChanges: true,
|
||||
clipsContent: true,
|
||||
hasDimView: false,
|
||||
autoAnimateOut: false,
|
||||
externalState: sheetExternalState,
|
||||
animateOut: animateOut,
|
||||
onPan: {
|
||||
|
|
@ -4740,7 +4823,7 @@ public class GiftViewScreen: ViewControllerComponentContainer {
|
|||
case upgradePreview([StarGift.UniqueGift.Attribute], String)
|
||||
case wearPreview(StarGift.UniqueGift)
|
||||
|
||||
var arguments: (peerId: EnginePeer.Id?, fromPeerId: EnginePeer.Id?, fromPeerName: String?, messageId: EngineMessage.Id?, reference: StarGiftReference?, incoming: Bool, gift: StarGift, date: Int32, convertStars: Int64?, text: String?, entities: [MessageTextEntity]?, nameHidden: Bool, savedToProfile: Bool, pinnedToTop: Bool?, converted: Bool, upgraded: Bool, refunded: Bool, canUpgrade: Bool, upgradeStars: Int64?, transferStars: Int64?, resellAmounts: [CurrencyAmount]?, canExportDate: Int32?, upgradeMessageId: Int32?, canTransferDate: Int32?, canResaleDate: Int32?, prepaidUpgradeHash: String?, upgradeSeparate: Bool, dropOriginalDetailsStars: Int64?)? {
|
||||
var arguments: (peerId: EnginePeer.Id?, fromPeerId: EnginePeer.Id?, fromPeerName: String?, fromPeerCompactName: String?, messageId: EngineMessage.Id?, reference: StarGiftReference?, incoming: Bool, gift: StarGift, date: Int32, convertStars: Int64?, text: String?, entities: [MessageTextEntity]?, nameHidden: Bool, savedToProfile: Bool, pinnedToTop: Bool?, converted: Bool, upgraded: Bool, refunded: Bool, canUpgrade: Bool, upgradeStars: Int64?, transferStars: Int64?, resellAmounts: [CurrencyAmount]?, canExportDate: Int32?, upgradeMessageId: Int32?, canTransferDate: Int32?, canResaleDate: Int32?, prepaidUpgradeHash: String?, upgradeSeparate: Bool, dropOriginalDetailsStars: Int64?)? {
|
||||
switch self {
|
||||
case let .message(message):
|
||||
if let action = message.media.first(where: { $0 is TelegramMediaAction }) as? TelegramMediaAction {
|
||||
|
|
@ -4754,7 +4837,7 @@ public class GiftViewScreen: ViewControllerComponentContainer {
|
|||
} else {
|
||||
reference = .message(messageId: message.id)
|
||||
}
|
||||
return (message.id.peerId, senderId ?? message.author?.id, message.author?.compactDisplayTitle, message.id, reference, message.flags.contains(.Incoming), gift, message.timestamp, convertStars, text, entities, nameHidden, savedToProfile, nil, converted, upgraded, isRefunded, canUpgrade, upgradeStars, nil, nil, nil, upgradeMessageId, nil, nil, prepaidUpgradeHash, upgradeSeparate, nil)
|
||||
return (message.id.peerId, senderId ?? message.author?.id, message.author?.debugDisplayTitle, message.author?.compactDisplayTitle, message.id, reference, message.flags.contains(.Incoming), gift, message.timestamp, convertStars, text, entities, nameHidden, savedToProfile, nil, converted, upgraded, isRefunded, canUpgrade, upgradeStars, nil, nil, nil, upgradeMessageId, nil, nil, prepaidUpgradeHash, upgradeSeparate, nil)
|
||||
case let .starGiftUnique(gift, isUpgrade, isTransferred, savedToProfile, canExportDate, transferStars, _, _, peerId, senderId, savedId, _, canTransferDate, canResaleDate, dropOriginalDetailsStars):
|
||||
var reference: StarGiftReference
|
||||
if let peerId, let savedId {
|
||||
|
|
@ -4779,13 +4862,13 @@ public class GiftViewScreen: ViewControllerComponentContainer {
|
|||
if case let .unique(uniqueGift) = gift {
|
||||
resellAmounts = uniqueGift.resellAmounts
|
||||
}
|
||||
return (message.id.peerId, senderId ?? message.author?.id, message.author?.compactDisplayTitle, message.id, reference, incoming, gift, message.timestamp, nil, nil, nil, false, savedToProfile, nil, false, false, false, false, nil, transferStars, resellAmounts, canExportDate, nil, canTransferDate, canResaleDate, nil, false, dropOriginalDetailsStars)
|
||||
return (message.id.peerId, senderId ?? message.author?.id, message.author?.debugDisplayTitle, message.author?.compactDisplayTitle, message.id, reference, incoming, gift, message.timestamp, nil, nil, nil, false, savedToProfile, nil, false, false, false, false, nil, transferStars, resellAmounts, canExportDate, nil, canTransferDate, canResaleDate, nil, false, dropOriginalDetailsStars)
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
case let .uniqueGift(gift, _), let .wearPreview(gift):
|
||||
return (nil, nil, nil, nil, nil, false, .unique(gift), 0, nil, nil, nil, false, false, nil, false, false, false, false, nil, nil, gift.resellAmounts, nil, nil, nil, nil, nil, false, nil)
|
||||
return (nil, nil, nil, nil, nil, nil, false, .unique(gift), 0, nil, nil, nil, false, false, nil, false, false, false, false, nil, nil, gift.resellAmounts, nil, nil, nil, nil, nil, false, nil)
|
||||
case let .profileGift(peerId, gift):
|
||||
var messageId: EngineMessage.Id?
|
||||
if case let .message(messageIdValue) = gift.reference {
|
||||
|
|
@ -4795,7 +4878,7 @@ public class GiftViewScreen: ViewControllerComponentContainer {
|
|||
if case let .unique(uniqueGift) = gift.gift {
|
||||
resellAmounts = uniqueGift.resellAmounts
|
||||
}
|
||||
return (peerId, gift.fromPeer?.id, gift.fromPeer?.compactDisplayTitle, messageId, gift.reference, false, gift.gift, gift.date, gift.convertStars, gift.text, gift.entities, gift.nameHidden, gift.savedToProfile, gift.pinnedToTop, false, false, false, gift.canUpgrade, gift.upgradeStars, gift.transferStars, resellAmounts, gift.canExportDate, nil, gift.canTransferDate, gift.canResaleDate, gift.prepaidUpgradeHash, gift.upgradeSeparate, gift.dropOriginalDetailsStars)
|
||||
return (peerId, gift.fromPeer?.id, gift.fromPeer?.debugDisplayTitle, gift.fromPeer?.compactDisplayTitle, messageId, gift.reference, false, gift.gift, gift.date, gift.convertStars, gift.text, gift.entities, gift.nameHidden, gift.savedToProfile, gift.pinnedToTop, false, false, false, gift.canUpgrade, gift.upgradeStars, gift.transferStars, resellAmounts, gift.canExportDate, nil, gift.canTransferDate, gift.canResaleDate, gift.prepaidUpgradeHash, gift.upgradeSeparate, gift.dropOriginalDetailsStars)
|
||||
case .soldOutGift:
|
||||
return nil
|
||||
case .upgradePreview:
|
||||
|
|
@ -5240,6 +5323,79 @@ private final class PeerCellComponent: Component {
|
|||
}
|
||||
}
|
||||
|
||||
final class HeaderContentComponent: Component {
|
||||
let attributedText: NSAttributedString
|
||||
|
||||
init(
|
||||
attributedText: NSAttributedString
|
||||
) {
|
||||
self.attributedText = attributedText
|
||||
}
|
||||
|
||||
static func ==(lhs: HeaderContentComponent, rhs: HeaderContentComponent) -> Bool {
|
||||
if lhs.attributedText != rhs.attributedText {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
final class View: UIView {
|
||||
private var component: HeaderContentComponent?
|
||||
|
||||
private let backgroundView: BlurredBackgroundView
|
||||
private let title = ComponentView<Empty>()
|
||||
|
||||
override init(frame: CGRect) {
|
||||
self.backgroundView = BlurredBackgroundView(color: UIColor.black.withAlphaComponent(0.2))
|
||||
|
||||
super.init(frame: frame)
|
||||
|
||||
self.addSubview(self.backgroundView)
|
||||
}
|
||||
|
||||
required init?(coder: NSCoder) {
|
||||
fatalError("init(coder:) has not been implemented")
|
||||
}
|
||||
|
||||
func update(component: HeaderContentComponent, availableSize: CGSize, state: EmptyComponentState, environment: Environment<Empty>, transition: ComponentTransition) -> CGSize {
|
||||
self.component = component
|
||||
|
||||
let titleSize = self.title.update(
|
||||
transition: transition,
|
||||
component: AnyComponent(
|
||||
MultilineTextComponent(text: .plain(component.attributedText), horizontalAlignment: .center)
|
||||
),
|
||||
environment: {},
|
||||
containerSize: availableSize
|
||||
)
|
||||
|
||||
let padding: CGFloat = 10.0
|
||||
let size = CGSize(width: titleSize.width + padding * 2.0, height: 19.0)
|
||||
|
||||
let titleFrame = CGRect(origin: CGPoint(x: floorToScreenPixels((size.width - titleSize.width) / 2.0), y: floorToScreenPixels((size.height - titleSize.height) / 2.0) - UIScreenPixel), size: titleSize)
|
||||
if let titleView = self.title.view {
|
||||
if titleView.superview == nil {
|
||||
self.addSubview(titleView)
|
||||
}
|
||||
transition.setFrame(view: titleView, frame: titleFrame)
|
||||
}
|
||||
|
||||
self.backgroundView.update(size: size, cornerRadius: size.height / 2.0, transition: transition.containedViewLayoutTransition)
|
||||
transition.setFrame(view: self.backgroundView, frame: CGRect(origin: .zero, size: size))
|
||||
|
||||
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 ButtonContentComponent: Component {
|
||||
let context: AccountContext
|
||||
let text: String
|
||||
|
|
|
|||
|
|
@ -70,6 +70,7 @@ final class TableComponent: CombinedComponent {
|
|||
}
|
||||
|
||||
final class State: ComponentState {
|
||||
var cachedLeftColumnImage: (UIImage, PresentationTheme)?
|
||||
var cachedBorderImage: (UIImage, PresentationTheme)?
|
||||
}
|
||||
|
||||
|
|
@ -78,7 +79,7 @@ final class TableComponent: CombinedComponent {
|
|||
}
|
||||
|
||||
public static var body: Body {
|
||||
let leftColumnBackground = Child(Rectangle.self)
|
||||
let leftColumnBackground = Child(Image.self)
|
||||
let lastBackground = Child(Rectangle.self)
|
||||
let verticalBorder = Child(Rectangle.self)
|
||||
let titleChildren = ChildMap(environment: Empty.self, keyedBy: AnyHashable.self)
|
||||
|
|
@ -194,25 +195,39 @@ final class TableComponent: CombinedComponent {
|
|||
)
|
||||
}
|
||||
|
||||
let borderRadius: CGFloat = 10.0
|
||||
let leftColumnImage: UIImage
|
||||
if let (currentImage, theme) = context.state.cachedLeftColumnImage, theme === context.component.theme {
|
||||
leftColumnImage = currentImage
|
||||
} else {
|
||||
leftColumnImage = generateImage(CGSize(width: 24.0, height: 24.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: 10, topCapHeight: 10)
|
||||
context.state.cachedLeftColumnImage = (leftColumnImage, context.component.theme)
|
||||
}
|
||||
|
||||
let leftColumnBackground = leftColumnBackground.update(
|
||||
component: Rectangle(color: secondaryBackgroundColor),
|
||||
component: Image(image: leftColumnImage),
|
||||
availableSize: CGSize(width: leftColumnWidth, height: innerTotalHeight),
|
||||
transition: context.transition
|
||||
)
|
||||
context.add(
|
||||
leftColumnBackground
|
||||
.position(CGPoint(x: leftColumnWidth / 2.0, y: innerTotalHeight / 2.0))
|
||||
context.add(leftColumnBackground
|
||||
.position(CGPoint(x: leftColumnWidth / 2.0, y: innerTotalHeight / 2.0))
|
||||
)
|
||||
|
||||
let borderImage: UIImage
|
||||
if let (currentImage, theme) = context.state.cachedBorderImage, theme === context.component.theme {
|
||||
borderImage = currentImage
|
||||
} else {
|
||||
let borderRadius: CGFloat = 10.0
|
||||
borderImage = generateImage(CGSize(width: 24.0, height: 24.0), rotatedContext: { size, context in
|
||||
let bounds = CGRect(origin: .zero, size: size)
|
||||
context.setFillColor(backgroundColor.cgColor)
|
||||
context.fill(bounds)
|
||||
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)
|
||||
|
|
|
|||
|
|
@ -180,7 +180,7 @@ final class StarsBalanceComponent: Component {
|
|||
let formattedLabel: String
|
||||
switch component.currency {
|
||||
case .ton:
|
||||
formattedLabel = formatTonAmountText(component.count.value, dateTimeFormat: component.dateTimeFormat)
|
||||
formattedLabel = formatTonAmountText(component.count.value, dateTimeFormat: component.dateTimeFormat, maxDecimalPositions: 3)
|
||||
case .stars:
|
||||
formattedLabel = formatStarsAmountText(component.count, dateTimeFormat: component.dateTimeFormat)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -466,7 +466,7 @@ private final class SheetContent: CombinedComponent {
|
|||
case .ton:
|
||||
if let value = state.amount?.value, value > 0 {
|
||||
let tonValue = Int64(Float(value) * Float(resaleConfiguration.starGiftCommissionTonPermille) / 1000.0)
|
||||
let tonString = formatTonAmountText(tonValue, dateTimeFormat: environment.dateTimeFormat, maxDecimalPositions: nil) + " TON"
|
||||
let tonString = formatTonAmountText(tonValue, dateTimeFormat: environment.dateTimeFormat, maxDecimalPositions: 3) + " TON"
|
||||
amountInfoString = NSAttributedString(attributedString: parseMarkdownIntoAttributedString(environment.strings.Stars_SellGift_AmountInfo(tonString).string, attributes: amountMarkdownAttributes, textAlignment: .natural))
|
||||
|
||||
if let tonUsdRate = withdrawConfiguration.tonUsdRate {
|
||||
|
|
@ -1230,7 +1230,13 @@ public final class StarsWithdrawScreen: ViewControllerComponentContainer {
|
|||
let presentationData = self.context.sharedContext.currentPresentationData.with { $0 }
|
||||
var text = presentationData.strings.Stars_Withdraw_Withdraw_ErrorMinimum(presentationData.strings.Stars_Withdraw_Withdraw_ErrorMinimum_Stars(Int32(clamping: minAmount))).string
|
||||
if case .starGiftResell = self.mode {
|
||||
text = presentationData.strings.Stars_SellGiftMinAmountToast_Text("\(presentationData.strings.Stars_Withdraw_Withdraw_ErrorMinimum_Stars(Int32(clamping: minAmount)))").string
|
||||
switch currency {
|
||||
case .stars:
|
||||
text = presentationData.strings.Stars_SellGiftMinAmountToast_Text("\(presentationData.strings.Stars_Withdraw_Withdraw_ErrorMinimum_Stars(Int32(clamping: minAmount)))").string
|
||||
case .ton:
|
||||
let amountString = formatTonAmountText(minAmount, dateTimeFormat: presentationData.dateTimeFormat) + " TON"
|
||||
text = presentationData.strings.Stars_SellGiftMinAmountToast_Text(amountString).string
|
||||
}
|
||||
} else if case let .suggestedPost(mode, _, _, _) = self.mode {
|
||||
let resaleConfiguration = StarsSubscriptionConfiguration.with(appConfiguration: self.context.currentAppConfiguration.with { $0 })
|
||||
switch currency {
|
||||
|
|
@ -1253,7 +1259,7 @@ public final class StarsWithdrawScreen: ViewControllerComponentContainer {
|
|||
let resultController = UndoOverlayController(
|
||||
presentationData: presentationData,
|
||||
content: .image(
|
||||
image: UIImage(bundleImageName: "Premium/Stars/StarLarge")!,
|
||||
image: currency == .ton ? generateTintedImage(image: UIImage(bundleImageName: "Premium/TonGift"), color: .white)! : UIImage(bundleImageName: "Premium/Stars/StarLarge")!,
|
||||
title: nil,
|
||||
text: text,
|
||||
round: false,
|
||||
|
|
@ -1314,9 +1320,9 @@ private final class AmountFieldStarsFormatter: NSObject, UITextFieldDelegate {
|
|||
}
|
||||
case .ton:
|
||||
let scale: Int64 = 1_000_000_000 // 10⁹ (one “nano”)
|
||||
if let dot = text.firstIndex(of: ".") {
|
||||
if let decimalSeparator = self.dateTimeFormat.decimalSeparator.first, let dot = text.firstIndex(of: decimalSeparator) {
|
||||
// Slices for the parts on each side of the dot
|
||||
var wholeSlice = String(text[..<dot])
|
||||
var wholeSlice = String(text[..<dot])
|
||||
if wholeSlice.isEmpty {
|
||||
wholeSlice = "0"
|
||||
}
|
||||
|
|
@ -1356,7 +1362,7 @@ private final class AmountFieldStarsFormatter: NSObject, UITextFieldDelegate {
|
|||
|
||||
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
|
||||
var acceptZero = false
|
||||
if self.minValue <= 0 {
|
||||
if case .ton = self.currency, self.minValue < 1_000_000_000 {
|
||||
acceptZero = true
|
||||
}
|
||||
|
||||
|
|
@ -1367,7 +1373,7 @@ private final class AmountFieldStarsFormatter: NSObject, UITextFieldDelegate {
|
|||
return false
|
||||
default:
|
||||
if case .ton = self.currency {
|
||||
if c == "." {
|
||||
if let decimalSeparator = self.dateTimeFormat.decimalSeparator.first, c == decimalSeparator {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
|
@ -1376,7 +1382,7 @@ private final class AmountFieldStarsFormatter: NSObject, UITextFieldDelegate {
|
|||
}) {
|
||||
return false
|
||||
}
|
||||
if newText.count(where: { $0 == "." }) > 1 {
|
||||
if let decimalSeparator = self.dateTimeFormat.decimalSeparator.first, newText.count(where: { $0 == decimalSeparator }) > 1 {
|
||||
return false
|
||||
}
|
||||
|
||||
|
|
@ -1390,7 +1396,7 @@ private final class AmountFieldStarsFormatter: NSObject, UITextFieldDelegate {
|
|||
}
|
||||
case .ton:
|
||||
var fixedText = false
|
||||
if let index = newText.firstIndex(of: ".") {
|
||||
if let decimalSeparator = self.dateTimeFormat.decimalSeparator.first, let index = newText.firstIndex(of: decimalSeparator) {
|
||||
let fractionalString = newText[newText.index(after: index)...]
|
||||
if fractionalString.count > 2 {
|
||||
newText = String(newText[newText.startIndex ..< newText.index(index, offsetBy: 3)])
|
||||
|
|
@ -1398,7 +1404,16 @@ private final class AmountFieldStarsFormatter: NSObject, UITextFieldDelegate {
|
|||
}
|
||||
}
|
||||
|
||||
if (newText == "0" && !acceptZero) || (newText.count > 1 && newText.hasPrefix("0") && !newText.hasPrefix("0.")) {
|
||||
if newText == self.dateTimeFormat.decimalSeparator {
|
||||
if !acceptZero {
|
||||
newText.removeFirst()
|
||||
} else {
|
||||
newText = "0\(newText)"
|
||||
}
|
||||
fixedText = true
|
||||
}
|
||||
|
||||
if (newText == "0" && !acceptZero) || (newText.count > 1 && newText.hasPrefix("0") && !newText.hasPrefix("0\(self.dateTimeFormat.decimalSeparator)")) {
|
||||
newText.removeFirst()
|
||||
fixedText = true
|
||||
}
|
||||
|
|
@ -1416,7 +1431,7 @@ private final class AmountFieldStarsFormatter: NSObject, UITextFieldDelegate {
|
|||
case .stars:
|
||||
textField.text = "\(self.maxValue)"
|
||||
case .ton:
|
||||
textField.text = "\(formatTonAmountText(self.maxValue, dateTimeFormat: PresentationDateTimeFormat(timeFormat: self.dateTimeFormat.timeFormat, dateFormat: self.dateTimeFormat.dateFormat, dateSeparator: "", dateSuffix: "", requiresFullYear: false, decimalSeparator: ".", groupingSeparator: ""), maxDecimalPositions: nil))"
|
||||
textField.text = "\(formatTonAmountText(self.maxValue, dateTimeFormat: PresentationDateTimeFormat(timeFormat: self.dateTimeFormat.timeFormat, dateFormat: self.dateTimeFormat.dateFormat, dateSeparator: "", dateSuffix: "", requiresFullYear: false, decimalSeparator: self.dateTimeFormat.decimalSeparator, groupingSeparator: ""), maxDecimalPositions: nil))"
|
||||
}
|
||||
self.onTextChanged(text: self.textField.text ?? "")
|
||||
self.animateError()
|
||||
|
|
@ -1639,7 +1654,7 @@ private final class AmountFieldComponent: Component {
|
|||
self.tonFormatter = nil
|
||||
self.textField.delegate = self.starsFormatter
|
||||
case .ton:
|
||||
self.textField.keyboardType = .numbersAndPunctuation
|
||||
self.textField.keyboardType = .decimalPad
|
||||
if self.tonFormatter == nil {
|
||||
self.tonFormatter = AmountFieldStarsFormatter(
|
||||
textField: self.textField,
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ import AsyncDisplayKit
|
|||
import StoryContainerScreen
|
||||
import MultilineTextComponent
|
||||
import HierarchyTrackingLayer
|
||||
import EmojiStatusComponent
|
||||
|
||||
private func calculateCircleIntersection(center: CGPoint, otherCenter: CGPoint, radius: CGFloat) -> (point1Angle: CGFloat, point2Angle: CGFloat)? {
|
||||
let distanceVector = CGPoint(x: otherCenter.x - center.x, y: otherCenter.y - center.y)
|
||||
|
|
@ -501,6 +502,7 @@ public final class StoryPeerListItemComponent: Component {
|
|||
private let indicatorShapeSeenLayer: SimpleShapeLayer
|
||||
private let indicatorShapeUnseenLayer: SimpleShapeLayer
|
||||
private let title = ComponentView<Empty>()
|
||||
private var verifiedIconView: ComponentHostView<Empty>?
|
||||
private let composeTitle = ComponentView<Empty>()
|
||||
|
||||
private var component: StoryPeerListItemComponent?
|
||||
|
|
@ -885,7 +887,59 @@ public final class StoryPeerListItemComponent: Component {
|
|||
environment: {},
|
||||
containerSize: CGSize(width: availableSize.width + 12.0, height: 100.0)
|
||||
)
|
||||
let titleFrame = CGRect(origin: CGPoint(x: floor((availableSize.width - titleSize.width) * 0.5) + (effectiveWidth - availableSize.width) * 0.5, y: indicatorFrame.midY + (indicatorFrame.height * 0.5 + 2.0) * effectiveScale), size: titleSize)
|
||||
|
||||
var totalTitleWidth = titleSize.width
|
||||
|
||||
var currentVerifiedIconContent: EmojiStatusComponent.Content?
|
||||
if component.peer.isVerified {
|
||||
currentVerifiedIconContent = .verified(fillColor: component.theme.list.itemCheckColors.fillColor, foregroundColor: component.theme.list.itemCheckColors.foregroundColor, sizeType: .smaller)
|
||||
}
|
||||
if let currentVerifiedIconContent {
|
||||
let verifiedIconView: ComponentHostView<Empty>
|
||||
if let current = self.verifiedIconView {
|
||||
verifiedIconView = current
|
||||
} else {
|
||||
verifiedIconView = ComponentHostView<Empty>()
|
||||
verifiedIconView.isUserInteractionEnabled = false
|
||||
self.verifiedIconView = verifiedIconView
|
||||
self.button.addSubview(verifiedIconView)
|
||||
}
|
||||
|
||||
let containerSize = CGSize(width: 12.0, height: 12.0)
|
||||
let verifiedIconComponent = EmojiStatusComponent(
|
||||
context: component.context,
|
||||
animationCache: component.context.animationCache,
|
||||
animationRenderer: component.context.animationRenderer,
|
||||
content: currentVerifiedIconContent,
|
||||
size: containerSize,
|
||||
isVisibleForAnimations: component.context.sharedContext.energyUsageSettings.loopEmoji,
|
||||
action: nil
|
||||
)
|
||||
|
||||
let iconSize = verifiedIconView.update(
|
||||
transition: .immediate,
|
||||
component: AnyComponent(verifiedIconComponent),
|
||||
environment: {},
|
||||
containerSize: containerSize
|
||||
)
|
||||
totalTitleWidth += iconSize.width + 1.0
|
||||
var titleScale = effectiveScale
|
||||
if titleScale < 1.0 {
|
||||
titleScale = min(1.0, titleScale + 0.02)
|
||||
} else if titleScale > 1.01 {
|
||||
titleScale = max(1.0, titleScale * 0.96)
|
||||
}
|
||||
let verifiedIconFrame = CGRect(origin: CGPoint(x: floor((availableSize.width - totalTitleWidth) * 0.5) + (titleSize.width + 1.0) * titleScale + (effectiveWidth - availableSize.width) * 0.5, y: indicatorFrame.midY + (indicatorFrame.height * 0.5 + 2.0 + UIScreenPixel) * effectiveScale), size: iconSize)
|
||||
titleTransition.setPosition(view: verifiedIconView, position: verifiedIconFrame.center)
|
||||
verifiedIconView.bounds = CGRect(origin: CGPoint(), size: verifiedIconFrame.size)
|
||||
titleTransition.setScale(view: verifiedIconView, scale: effectiveScale)
|
||||
titleTransition.setAlpha(view: verifiedIconView, alpha: component.expandedAlphaFraction)
|
||||
} else if let verifiedIconView = self.verifiedIconView {
|
||||
self.verifiedIconView = nil
|
||||
verifiedIconView.removeFromSuperview()
|
||||
}
|
||||
|
||||
let titleFrame = CGRect(origin: CGPoint(x: floor((availableSize.width - totalTitleWidth) * 0.5) + (effectiveWidth - availableSize.width) * 0.5, y: indicatorFrame.midY + (indicatorFrame.height * 0.5 + 2.0) * effectiveScale), size: titleSize)
|
||||
if let titleView = self.title.view {
|
||||
if titleView.superview == nil {
|
||||
titleView.layer.anchorPoint = CGPoint(x: 0.5, y: 0.5)
|
||||
|
|
|
|||
|
|
@ -1137,7 +1137,7 @@ func openExternalUrlImpl(context: AccountContext, urlContext: OpenURLContext, ur
|
|||
}
|
||||
|
||||
if isInternetUrl {
|
||||
if parsedUrl.host == "t.me" || parsedUrl.host == "telegram.me" {
|
||||
if parsedUrl.host == "t.me" || parsedUrl.host == "telegram.me" || parsedUrl.host == "telegram.dog" {
|
||||
handleInternalUrl(parsedUrl.absoluteString)
|
||||
} else {
|
||||
let settings = combineLatest(context.sharedContext.accountManager.sharedData(keys: [ApplicationSpecificSharedDataKeys.webBrowserSettings, ApplicationSpecificSharedDataKeys.presentationPasscodeSettings]), context.sharedContext.accountManager.accessChallengeData())
|
||||
|
|
@ -1159,11 +1159,6 @@ func openExternalUrlImpl(context: AccountContext, urlContext: OpenURLContext, ur
|
|||
return settings
|
||||
}
|
||||
|
||||
// var isCompact = false
|
||||
// if let metrics = navigationController?.validLayout?.metrics, case .compact = metrics.widthClass {
|
||||
// isCompact = true
|
||||
// }
|
||||
|
||||
let _ = (settings
|
||||
|> deliverOnMainQueue).startStandalone(next: { settings in
|
||||
var isTonSite = false
|
||||
|
|
@ -1216,7 +1211,7 @@ func openExternalUrlImpl(context: AccountContext, urlContext: OpenURLContext, ur
|
|||
}
|
||||
|
||||
if parsedUrl.scheme == "http" || parsedUrl.scheme == "https" {
|
||||
let nativeHosts = ["t.me", "telegram.me"]
|
||||
let nativeHosts = ["t.me", "telegram.me", "telegram.dog"]
|
||||
if let host = parsedUrl.host, nativeHosts.contains(host) {
|
||||
continueHandling()
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -3948,7 +3948,7 @@ private func peerInfoControllerImpl(context: AccountContext, updatedPresentation
|
|||
forumTopicThread = thread
|
||||
case .recommendedChannels:
|
||||
switchToRecommendedChannels = true
|
||||
case .gifts:
|
||||
case .gifts, .upgradableGifts:
|
||||
switchToGifts = true
|
||||
case .groupsInCommon:
|
||||
switchToGroupsInCommon = true
|
||||
|
|
@ -3986,7 +3986,7 @@ private func peerInfoControllerImpl(context: AccountContext, updatedPresentation
|
|||
forumTopicThread = thread
|
||||
case .myProfile:
|
||||
isMyProfile = true
|
||||
case .gifts:
|
||||
case .gifts, .upgradableGifts:
|
||||
switchToGifts = true
|
||||
case .myProfileGifts:
|
||||
isMyProfile = true
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue