Merge branch 'master' of gitlab.com:peter-iakovlev/telegram-ios

This commit is contained in:
Ilya Laktyushin 2021-09-08 00:42:01 +03:00
commit e1e4ae0949
20 changed files with 475 additions and 99 deletions

View File

@ -6766,9 +6766,16 @@ Sorry for the inconvenience.";
"Channel.AdminLog.MessageChangedThemeRemove" = "%1$@ disabled chat theme";
"SponsoredMessageMenu.Info" = "What are sponsored\nmessages?";
"SponsoredMessageInfo.Text" = "See https://telegram.org";
"SponsoredMessageInfoScreen.Title" = "What are sponsored messages?";
"SponsoredMessageInfoScreen.Text" = "Unlike other apps, Telegram never uses your private data to target ads. You are seeing this message only because someone chose this public one-to many channel as a space to promote their messages. This means that no user data is mined or analyzed to display ads, and every user viewing a channel on Telegram sees the same sponsored message.
Unline other apps, Telegram doesn't track whether you tapped on a sponsored message and doesn't profile you based on your activity. We also prevent external links in sponsored messages to ensure that third parties can't spy on our users. We believe that everyone has the right to privacy, and technological platforms should respect that.
Telegram offers free and unlimited service to hundreds of millions of users, which involves significant server and traffic costs. In order to remain independent and stay true to its values, Telegram developed a paid tool to promote messages with user privacy in mind. We welcome responsible adverticers at:
[url]
Ads should no longer be synonymous with abuse of user privacy. Let us redefine how a tech compony should operate — together.";
"SponsoredMessageInfo.Action" = "Learn More";
"SponsoredMessageInfo.ActionUrl" = "https://telegram.org";
"SponsoredMessageInfo.ActionUrl" = "https://telegram.org/ads";
"Chat.NavigationNoChannels" = "You have no unread channels";
@ -6797,5 +6804,9 @@ Sorry for the inconvenience.";
"Conversation.ContextMenuSeen_1" = "1 Seen";
"Conversation.ContextMenuSeen_any" = "%@ Seen";
"Conversation.ContextMenuNoViews" = "Nobody Viewed";
"Conversation.ContextMenuNobodyListened" = "Nobody Listened";
"Conversation.ContextMenuNobodyWatched" = "Nobody Watched";
"VideoChat.RecordingSaved" = "Video chat recording saved to **Saved Messages**.";
"LiveStream.RecordingSaved" = "Live stream recording saved to **Saved Messages**.";

25
submodules/AdUI/BUILD Normal file
View File

@ -0,0 +1,25 @@
load("@build_bazel_rules_swift//swift:swift.bzl", "swift_library")
swift_library(
name = "AdUI",
module_name = "AdUI",
srcs = glob([
"Sources/**/*.swift",
]),
copts = [
"-warnings-as-errors",
],
deps = [
"//submodules/SSignalKit/SwiftSignalKit:SwiftSignalKit",
"//submodules/AsyncDisplayKit:AsyncDisplayKit",
"//submodules/Display:Display",
"//submodules/Postbox:Postbox",
"//submodules/TelegramCore:TelegramCore",
"//submodules/TelegramPresentationData:TelegramPresentationData",
"//submodules/TelegramUIPreferences:TelegramUIPreferences",
"//submodules/AccountContext:AccountContext",
],
visibility = [
"//visibility:public",
],
)

View File

@ -0,0 +1,223 @@
import Foundation
import UIKit
import Display
import AsyncDisplayKit
import SwiftSignalKit
import Postbox
import TelegramCore
import TelegramPresentationData
import TelegramUIPreferences
import AccountContext
public final class AdInfoScreen: ViewController {
private final class Node: ViewControllerTracingNode {
private weak var controller: AdInfoScreen?
private let context: AccountContext
private var presentationData: PresentationData
private let titleNode: ImmediateTextNode
private final class LinkNode: HighlightableButtonNode {
private let backgroundNode: ASImageNode
private let textNode: ImmediateTextNode
private let action: () -> Void
init(text: String, color: UIColor, action: @escaping () -> Void) {
self.action = action
self.backgroundNode = ASImageNode()
self.backgroundNode.image = generateStretchableFilledCircleImage(diameter: 10.0, color: nil, strokeColor: color, strokeWidth: 1.0, backgroundColor: nil)
self.textNode = ImmediateTextNode()
self.textNode.maximumNumberOfLines = 1
self.textNode.attributedText = NSAttributedString(string: text, font: Font.regular(16.0), textColor: color)
super.init()
self.addSubnode(self.backgroundNode)
self.addSubnode(self.textNode)
self.addTarget(self, action:#selector(self.pressed), forControlEvents: .touchUpInside)
}
@objc private func pressed() {
self.action()
}
func update(width: CGFloat, transition: ContainedViewLayoutTransition) -> CGFloat {
let size = CGSize(width: width, height: 44.0)
transition.updateFrame(node: self.backgroundNode, frame: CGRect(origin: CGPoint(), size: size))
let textSize = self.textNode.updateLayout(CGSize(width: width - 8.0 * 2.0, height: 44.0))
transition.updateFrameAdditiveToCenter(node: self.textNode, frame: CGRect(origin: CGPoint(x: floor((size.width - textSize.width) / 2.0), y: floor((size.height - textSize.height) / 2.0)), size: textSize))
return size.height
}
}
private enum Item {
case text(ImmediateTextNode)
case link(LinkNode)
}
private let items: [Item]
private let scrollNode: ASScrollNode
init(controller: AdInfoScreen, context: AccountContext) {
self.controller = controller
self.context = context
self.presentationData = context.sharedContext.currentPresentationData.with { $0 }
self.titleNode = ImmediateTextNode()
self.titleNode.maximumNumberOfLines = 1
self.titleNode.attributedText = NSAttributedString(string: self.presentationData.strings.SponsoredMessageInfoScreen_Title, font: NavigationBar.titleFont, textColor: self.presentationData.theme.rootController.navigationBar.primaryTextColor)
self.scrollNode = ASScrollNode()
self.scrollNode.view.showsVerticalScrollIndicator = true
self.scrollNode.view.showsHorizontalScrollIndicator = false
self.scrollNode.view.scrollsToTop = true
self.scrollNode.view.delaysContentTouches = false
self.scrollNode.view.canCancelContentTouches = true
if #available(iOS 11.0, *) {
self.scrollNode.view.contentInsetAdjustmentBehavior = .never
}
var openUrl: (() -> Void)?
let rawText = self.presentationData.strings.SponsoredMessageInfoScreen_Text
var items: [Item] = []
var didAddUrl = false
for component in rawText.components(separatedBy: "[url]") {
var itemText = component
if itemText.hasPrefix("\n") {
itemText = String(itemText[itemText.index(itemText.startIndex, offsetBy: 1)...])
}
if itemText.hasSuffix("\n") {
itemText = String(itemText[..<itemText.index(itemText.endIndex, offsetBy: -1)])
}
let textNode = ImmediateTextNode()
textNode.maximumNumberOfLines = 0
textNode.attributedText = NSAttributedString(string: itemText, font: Font.regular(16.0), textColor: self.presentationData.theme.list.itemPrimaryTextColor)
items.append(.text(textNode))
if !didAddUrl {
didAddUrl = true
items.append(.link(LinkNode(text: self.presentationData.strings.SponsoredMessageInfo_ActionUrl, color: self.presentationData.theme.list.itemAccentColor, action: {
openUrl?()
})))
}
}
if !didAddUrl {
didAddUrl = true
items.append(.link(LinkNode(text: self.presentationData.strings.SponsoredMessageInfo_ActionUrl, color: self.presentationData.theme.list.itemAccentColor, action: {
openUrl?()
})))
}
self.items = items
super.init()
self.backgroundColor = self.presentationData.theme.list.plainBackgroundColor
self.addSubnode(self.scrollNode)
for item in self.items {
switch item {
case let .text(text):
self.scrollNode.addSubnode(text)
case let .link(link):
self.scrollNode.addSubnode(link)
}
}
openUrl = { [weak self] in
guard let strongSelf = self else {
return
}
strongSelf.context.sharedContext.applicationBindings.openUrl(strongSelf.presentationData.strings.SponsoredMessageInfo_ActionUrl)
}
}
func containerLayoutUpdated(layout: ContainerViewLayout, navigationHeight: CGFloat, transition: ContainedViewLayoutTransition) {
if self.titleNode.supernode == nil {
self.addSubnode(self.titleNode)
}
let titleSize = self.titleNode.updateLayout(CGSize(width: layout.size.width - layout.safeInsets.left * 2.0 - 80.0 - 16.0 * 2.0, height: 100.0))
transition.updateFrameAdditive(node: self.titleNode, frame: CGRect(origin: CGPoint(x: layout.safeInsets.left + 16.0, y: floor((navigationHeight - titleSize.height) / 2.0)), size: titleSize))
transition.updateFrame(node: self.scrollNode, frame: CGRect(origin: CGPoint(), size: layout.size))
self.scrollNode.view.scrollIndicatorInsets = UIEdgeInsets(top: navigationHeight, left: 0.0, bottom: 0.0, right: 0.0)
let sideInset: CGFloat = layout.safeInsets.left + 16.0
let maxWidth: CGFloat = layout.size.width - sideInset * 2.0
var contentHeight: CGFloat = navigationHeight + 16.0
for item in self.items {
switch item {
case let .text(text):
let textSize = text.updateLayout(CGSize(width: maxWidth, height: .greatestFiniteMagnitude))
transition.updateFrameAdditive(node: text, frame: CGRect(origin: CGPoint(x: sideInset, y: contentHeight), size: textSize))
contentHeight += textSize.height
case let .link(link):
let linkHeight = link.update(width: maxWidth, transition: transition)
let linkSize = CGSize(width: maxWidth, height: linkHeight)
contentHeight += 16.0
transition.updateFrame(node: link, frame: CGRect(origin: CGPoint(x: sideInset, y: contentHeight), size: linkSize))
contentHeight += linkSize.height
contentHeight += 16.0
}
}
contentHeight += 16.0
contentHeight += layout.intrinsicInsets.bottom
self.scrollNode.view.contentSize = CGSize(width: layout.size.width, height: contentHeight)
}
}
private var node: Node {
return self.displayNode as! Node
}
private let context: AccountContext
private var presentationData: PresentationData
public init(context: AccountContext) {
self.context = context
self.presentationData = context.sharedContext.currentPresentationData.with { $0 }
super.init(navigationBarPresentationData: NavigationBarPresentationData(presentationData: self.presentationData))
self.navigationPresentation = .modal
self.navigationItem.setLeftBarButton(UIBarButtonItem(title: "", style: .plain, target: self, action: #selector(self.noAction)), animated: false)
self.navigationItem.setRightBarButton(UIBarButtonItem(title: self.presentationData.strings.Common_Done, style: .done, target: self, action: #selector(self.donePressed)), animated: false)
}
required init(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
@objc private func noAction() {
}
@objc private func donePressed() {
self.dismiss()
}
override public func loadDisplayNode() {
self.displayNode = Node(controller: self, context: self.context)
super.displayNodeDidLoad()
}
override public func containerLayoutUpdated(_ layout: ContainerViewLayout, transition: ContainedViewLayoutTransition) {
super.containerLayoutUpdated(layout, transition: transition)
self.node.containerLayoutUpdated(layout: layout, navigationHeight: self.navigationLayout(layout: layout).navigationFrame.maxY, transition: transition)
}
}

View File

@ -1122,6 +1122,7 @@ final class BotCheckoutControllerNode: ItemListControllerNode, PKPaymentAuthoriz
}
let merchantId: String
var countryCode: String = "US"
if nativeProvider.name == "stripe" {
merchantId = "merchant.ph.telegra.Telegraph"
} else if let paramsId = nativeParams["apple_pay_merchant_id"] as? String {
@ -1129,6 +1130,9 @@ final class BotCheckoutControllerNode: ItemListControllerNode, PKPaymentAuthoriz
} else {
return
}
if let paramsCountryCode = nativeParams["acquirer_bank_country"] as? String {
countryCode = paramsCountryCode
}
let botPeerId = self.messageId.peerId
let _ = (context.engine.data.get(
@ -1141,9 +1145,9 @@ final class BotCheckoutControllerNode: ItemListControllerNode, PKPaymentAuthoriz
request.merchantIdentifier = merchantId
request.supportedNetworks = [.visa, .amex, .masterCard]
request.merchantCapabilities = [.capability3DS]
request.countryCode = "US"
request.countryCode = countryCode
request.currencyCode = paymentForm.invoice.currency.uppercased()
var items: [PKPaymentSummaryItem] = []
var totalAmount: Int64 = 0

View File

@ -250,10 +250,10 @@ func chatContextMenuItems(context: AccountContext, peerId: PeerId, promoInfo: Ch
updatedItems.append(.action(ContextMenuActionItem(text: strings.ChatList_Context_Back, icon: { theme in
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Back"), color: theme.contextMenu.primaryColor)
}, action: { c, _ in
c.setItems(chatContextMenuItems(context: context, peerId: peerId, promoInfo: promoInfo, source: source, chatListController: chatListController, joined: joined))
c.setItems(chatContextMenuItems(context: context, peerId: peerId, promoInfo: promoInfo, source: source, chatListController: chatListController, joined: joined), minHeight: nil)
})))
c.setItems(.single(updatedItems))
c.setItems(.single(updatedItems), minHeight: nil)
})))
}
}

View File

@ -13,8 +13,9 @@ private let animationDurationFactor: Double = 1.0
public protocol ContextControllerProtocol {
var useComplexItemsTransitionAnimation: Bool { get set }
var immediateItemsTransitionAnimation: Bool { get set }
func setItems(_ items: Signal<[ContextMenuItem], NoError>)
func getActionsMinHeight() -> CGFloat?
func setItems(_ items: Signal<[ContextMenuItem], NoError>, minHeight: CGFloat?)
func dismiss(completion: (() -> Void)?)
}
@ -130,6 +131,7 @@ private final class ContextControllerNode: ViewControllerTracingNode, UIScrollVi
let contentReady = Promise<Bool>()
private var currentItems: [ContextMenuItem]?
private var currentActionsMinHeight: CGFloat?
private var validLayout: ContainerViewLayout?
@ -448,7 +450,7 @@ private final class ContextControllerNode: ViewControllerTracingNode, UIScrollVi
self.itemsDisposable.set((items
|> deliverOnMainQueue).start(next: { [weak self] items in
self?.setItems(items: items)
self?.setItems(items: items, minHeight: nil)
}))
switch source {
@ -1167,24 +1169,33 @@ private final class ContextControllerNode: ViewControllerTracingNode, UIScrollVi
intermediateCompletion()
})
}
func getActionsMinHeight() -> CGFloat? {
if !self.actionsContainerNode.bounds.height.isZero {
return self.actionsContainerNode.bounds.height
} else {
return nil
}
}
func setItemsSignal(items: Signal<[ContextMenuItem], NoError>) {
func setItemsSignal(items: Signal<[ContextMenuItem], NoError>, minHeight: CGFloat?) {
self.items = items
self.itemsDisposable.set((items
|> deliverOnMainQueue).start(next: { [weak self] items in
guard let strongSelf = self else {
return
}
strongSelf.setItems(items: items)
strongSelf.setItems(items: items, minHeight: minHeight)
}))
}
private func setItems(items: [ContextMenuItem]) {
private func setItems(items: [ContextMenuItem], minHeight: CGFloat?) {
if let _ = self.currentItems, !self.didCompleteAnimationIn && self.getController()?.immediateItemsTransitionAnimation == true {
return
}
self.currentItems = items
self.currentActionsMinHeight = minHeight
let previousActionsContainerNode = self.actionsContainerNode
self.actionsContainerNode = ContextActionsContainerNode(presentationData: self.presentationData, items: items, getController: { [weak self] in
@ -1282,17 +1293,19 @@ private final class ContextControllerNode: ViewControllerTracingNode, UIScrollVi
let isInitialLayout = self.actionsContainerNode.frame.size.width.isZero
let previousContainerFrame = self.view.convert(self.contentContainerNode.frame, from: self.scrollNode.view)
let actionsSize = self.actionsContainerNode.updateLayout(widthClass: layout.metrics.widthClass, constrainedWidth: layout.size.width - actionsSideInset * 2.0, transition: actionsContainerTransition)
self.actionsContainerNode.updateSize(containerSize: actionsSize, contentSize: actionsSize)
let realActionsSize = self.actionsContainerNode.updateLayout(widthClass: layout.metrics.widthClass, constrainedWidth: layout.size.width - actionsSideInset * 2.0, transition: actionsContainerTransition)
let adjustedActionsSize = CGSize(width: realActionsSize.width, height: max(realActionsSize.height, self.currentActionsMinHeight ?? 0.0))
self.actionsContainerNode.updateSize(containerSize: realActionsSize, contentSize: realActionsSize)
let contentSize = originalProjectedContentViewFrame.1.size
self.contentContainerNode.updateLayout(size: contentSize, scaledSize: contentSize, transition: transition)
let maximumActionsFrameOrigin = max(60.0, layout.size.height - layout.intrinsicInsets.bottom - actionsBottomInset - actionsSize.height)
let maximumActionsFrameOrigin = max(60.0, layout.size.height - layout.intrinsicInsets.bottom - actionsBottomInset - adjustedActionsSize.height)
let originalActionsY = min(originalProjectedContentViewFrame.1.maxY + contentActionsSpacing, maximumActionsFrameOrigin)
let preferredActionsX = originalProjectedContentViewFrame.1.minX
var originalActionsFrame = CGRect(origin: CGPoint(x: max(actionsSideInset, min(layout.size.width - actionsSize.width - actionsSideInset, preferredActionsX)), y: originalActionsY), size: actionsSize)
var originalActionsFrame = CGRect(origin: CGPoint(x: max(actionsSideInset, min(layout.size.width - adjustedActionsSize.width - actionsSideInset, preferredActionsX)), y: originalActionsY), size: realActionsSize)
let originalContentX: CGFloat = originalProjectedContentViewFrame.1.minX
let originalContentY = originalProjectedContentViewFrame.1.minY
@ -1307,7 +1320,7 @@ private final class ContextControllerNode: ViewControllerTracingNode, UIScrollVi
}
var contentHeight = max(layout.size.height, max(layout.size.height, originalActionsFrame.maxY + actionsBottomInset) - originalContentFrame.minY + contentTopInset)
contentHeight = max(contentHeight, actionsSize.height + originalActionsFrame.minY + actionsBottomInset)
contentHeight = max(contentHeight, adjustedActionsSize.height + originalActionsFrame.minY + actionsBottomInset)
var overflowOffset: CGFloat
var contentContainerFrame: CGRect
@ -1360,26 +1373,28 @@ private final class ContextControllerNode: ViewControllerTracingNode, UIScrollVi
let isInitialLayout = self.actionsContainerNode.frame.size.width.isZero
let previousContainerFrame = self.view.convert(self.contentContainerNode.frame, from: self.scrollNode.view)
let actionsSize = self.actionsContainerNode.updateLayout(widthClass: layout.metrics.widthClass, constrainedWidth: layout.size.width - actionsSideInset * 2.0, transition: actionsContainerTransition)
self.actionsContainerNode.updateSize(containerSize: actionsSize, contentSize: actionsSize)
let realActionsSize = self.actionsContainerNode.updateLayout(widthClass: layout.metrics.widthClass, constrainedWidth: layout.size.width - actionsSideInset * 2.0, transition: actionsContainerTransition)
let adjustedActionsSize = CGSize(width: realActionsSize.width, height: max(realActionsSize.height, self.currentActionsMinHeight ?? 0.0))
self.actionsContainerNode.updateSize(containerSize: realActionsSize, contentSize: realActionsSize)
let contentSize = originalProjectedContentViewFrame.1.size
self.contentContainerNode.updateLayout(size: contentSize, scaledSize: contentSize, transition: transition)
let maximumActionsFrameOrigin = max(60.0, layout.size.height - layout.intrinsicInsets.bottom - actionsBottomInset - actionsSize.height)
let maximumActionsFrameOrigin = max(60.0, layout.size.height - layout.intrinsicInsets.bottom - actionsBottomInset - adjustedActionsSize.height)
let preferredActionsX: CGFloat
let originalActionsY: CGFloat
if centerVertically {
originalActionsY = min(originalProjectedContentViewFrame.1.maxY + contentActionsSpacing, maximumActionsFrameOrigin)
preferredActionsX = originalProjectedContentViewFrame.1.maxX - actionsSize.width
preferredActionsX = originalProjectedContentViewFrame.1.maxX - adjustedActionsSize.width
} else if keepInPlace {
originalActionsY = originalProjectedContentViewFrame.1.minY - contentActionsSpacing - actionsSize.height
preferredActionsX = max(actionsSideInset, originalProjectedContentViewFrame.1.maxX - actionsSize.width)
originalActionsY = originalProjectedContentViewFrame.1.minY - contentActionsSpacing - adjustedActionsSize.height
preferredActionsX = max(actionsSideInset, originalProjectedContentViewFrame.1.maxX - adjustedActionsSize.width)
} else {
originalActionsY = min(originalProjectedContentViewFrame.1.maxY + contentActionsSpacing, maximumActionsFrameOrigin)
preferredActionsX = originalProjectedContentViewFrame.1.minX
}
var originalActionsFrame = CGRect(origin: CGPoint(x: max(actionsSideInset, min(layout.size.width - actionsSize.width - actionsSideInset, preferredActionsX)), y: originalActionsY), size: actionsSize)
var originalActionsFrame = CGRect(origin: CGPoint(x: max(actionsSideInset, min(layout.size.width - adjustedActionsSize.width - actionsSideInset, preferredActionsX)), y: originalActionsY), size: realActionsSize)
let originalContentX: CGFloat = originalProjectedContentViewFrame.1.minX
let originalContentY: CGFloat
if keepInPlace {
@ -1957,11 +1972,18 @@ public final class ContextController: ViewController, StandalonePresentableContr
self.controllerNode.animateIn()
}
}
public func getActionsMinHeight() -> CGFloat? {
if self.isNodeLoaded {
return self.controllerNode.getActionsMinHeight()
}
return nil
}
public func setItems(_ items: Signal<[ContextMenuItem], NoError>) {
public func setItems(_ items: Signal<[ContextMenuItem], NoError>, minHeight: CGFloat? = nil) {
self.items = items
if self.isNodeLoaded {
self.controllerNode.setItemsSignal(items: items)
self.controllerNode.setItemsSignal(items: items, minHeight: minHeight)
}
}

View File

@ -33,9 +33,12 @@ extension PeekControllerTheme {
public final class PeekController: ViewController, ContextControllerProtocol {
public var useComplexItemsTransitionAnimation: Bool = false
public var immediateItemsTransitionAnimation = false
public func getActionsMinHeight() -> CGFloat? {
return nil
}
public func setItems(_ items: Signal<[ContextMenuItem], NoError>) {
public func setItems(_ items: Signal<[ContextMenuItem], NoError>, minHeight: CGFloat?) {
}
private var controllerNode: PeekControllerNode {

View File

@ -151,7 +151,7 @@ private func cancelContextGestures(view: UIView) {
open class ListView: ASDisplayNode, UIScrollViewAccessibilityDelegate, UIGestureRecognizerDelegate {
public final let scroller: ListViewScroller
private final var visibleSize: CGSize = CGSize()
public private(set) final var visibleSize: CGSize = CGSize()
public private(set) final var insets = UIEdgeInsets()
public final var visualInsets: UIEdgeInsets?
public private(set) final var headerInsets = UIEdgeInsets()

View File

@ -1,8 +1,6 @@
import UIKit
import AsyncDisplayKit
private let titleFont = Font.with(size: 17.0, design: .regular, weight: .semibold, traits: [.monospacedNumbers])
private var backArrowImageCache: [Int32: UIImage] = [:]
public final class SparseNode: ASDisplayNode {
@ -236,6 +234,8 @@ open class NavigationBar: ASDisplayNode {
public static var defaultSecondaryContentHeight: CGFloat {
return 38.0
}
public static let titleFont = Font.with(size: 17.0, design: .regular, weight: .semibold, traits: [.monospacedNumbers])
var presentationData: NavigationBarPresentationData
@ -388,7 +388,7 @@ open class NavigationBar: ASDisplayNode {
private var title: String? {
didSet {
if let title = self.title {
self.titleNode.attributedText = NSAttributedString(string: title, font: titleFont, textColor: self.presentationData.theme.primaryTextColor)
self.titleNode.attributedText = NSAttributedString(string: title, font: NavigationBar.titleFont, textColor: self.presentationData.theme.primaryTextColor)
self.titleNode.accessibilityLabel = title
if self.titleNode.supernode == nil {
self.buttonsContainerNode.addSubnode(self.titleNode)
@ -837,7 +837,7 @@ open class NavigationBar: ASDisplayNode {
self.rightButtonNode.rippleColor = self.presentationData.theme.primaryTextColor.withAlphaComponent(0.05)
self.backButtonArrow.image = backArrowImage(color: self.presentationData.theme.buttonColor)
if let title = self.title {
self.titleNode.attributedText = NSAttributedString(string: title, font: titleFont, textColor: self.presentationData.theme.primaryTextColor)
self.titleNode.attributedText = NSAttributedString(string: title, font: NavigationBar.titleFont, textColor: self.presentationData.theme.primaryTextColor)
self.titleNode.accessibilityLabel = title
}
self.stripeNode.backgroundColor = self.presentationData.theme.separatorColor
@ -919,7 +919,7 @@ open class NavigationBar: ASDisplayNode {
self.rightButtonNode.rippleColor = self.presentationData.theme.primaryTextColor.withAlphaComponent(0.05)
self.backButtonArrow.image = backArrowImage(color: self.presentationData.theme.buttonColor)
if let title = self.title {
self.titleNode.attributedText = NSAttributedString(string: title, font: titleFont, textColor: self.presentationData.theme.primaryTextColor)
self.titleNode.attributedText = NSAttributedString(string: title, font: NavigationBar.titleFont, textColor: self.presentationData.theme.primaryTextColor)
self.titleNode.accessibilityLabel = title
}
self.stripeNode.backgroundColor = self.presentationData.theme.separatorColor
@ -1191,7 +1191,7 @@ open class NavigationBar: ASDisplayNode {
}
} else if let title = self.title {
let node = ImmediateTextNode()
node.attributedText = NSAttributedString(string: title, font: titleFont, textColor: foregroundColor)
node.attributedText = NSAttributedString(string: title, font: NavigationBar.titleFont, textColor: foregroundColor)
return node
} else {
return nil

View File

@ -2087,7 +2087,7 @@ final class UniversalVideoGalleryItemNode: ZoomableContentGalleryItemNode {
return
}
c.setItems(strongSelf.contextMenuSpeedItems())
c.setItems(strongSelf.contextMenuSpeedItems(), minHeight: nil)
})))
if let (message, _, _) = strongSelf.contentInfo() {
@ -2206,7 +2206,7 @@ final class UniversalVideoGalleryItemNode: ZoomableContentGalleryItemNode {
c.dismiss(completion: nil)
return
}
c.setItems(strongSelf.contextMenuMainItems())
c.setItems(strongSelf.contextMenuMainItems(), minHeight: nil)
})))
return items

View File

@ -158,7 +158,7 @@ public func presentPeerReportOptions(context: AccountContext, parent: ViewContro
backAction(c)
})))
}
contextController.setItems(.single(items))
contextController.setItems(.single(items), minHeight: nil)
} else {
contextController?.dismiss(completion: nil)
parent.view.endEditing(true)

View File

@ -2473,7 +2473,7 @@ public final class VoiceChatController: ViewController {
guard let strongSelf = self else {
return
}
c.setItems(strongSelf.contextMenuDisplayAsItems())
c.setItems(strongSelf.contextMenuDisplayAsItems(), minHeight: nil)
})))
items.append(.separator)
break
@ -2506,7 +2506,7 @@ public final class VoiceChatController: ViewController {
guard let strongSelf = self else {
return
}
c.setItems(strongSelf.contextMenuAudioItems())
c.setItems(strongSelf.contextMenuAudioItems(), minHeight: nil)
})))
}
@ -2543,7 +2543,7 @@ public final class VoiceChatController: ViewController {
guard let strongSelf = self else {
return
}
c.setItems(strongSelf.contextMenuPermissionItems())
c.setItems(strongSelf.contextMenuPermissionItems(), minHeight: nil)
})))
}
}
@ -2803,7 +2803,7 @@ public final class VoiceChatController: ViewController {
guard let strongSelf = self else {
return
}
c.setItems(strongSelf.contextMenuMainItems())
c.setItems(strongSelf.contextMenuMainItems(), minHeight: nil)
})))
return .single(items)
}
@ -2898,7 +2898,7 @@ public final class VoiceChatController: ViewController {
guard let strongSelf = self else {
return
}
c.setItems(strongSelf.contextMenuMainItems())
c.setItems(strongSelf.contextMenuMainItems(), minHeight: nil)
})))
return items
}
@ -2944,7 +2944,7 @@ public final class VoiceChatController: ViewController {
guard let strongSelf = self else {
return
}
c.setItems(strongSelf.contextMenuMainItems())
c.setItems(strongSelf.contextMenuMainItems(), minHeight: nil)
})))
}
return .single(items)

View File

@ -260,7 +260,7 @@ private class AdMessagesHistoryContextImpl {
self.state.set(CachedState.getCached(postbox: account.postbox, peerId: peerId)
|> mapToSignal { cachedState -> Signal<State, NoError> in
if let cachedState = cachedState, cachedState.timestamp >= Int32(Date().timeIntervalSince1970) - 5 * 60 {
if false, let cachedState = cachedState, cachedState.timestamp >= Int32(Date().timeIntervalSince1970) - 5 * 60 {
return account.postbox.transaction { transaction -> State in
return State(messages: cachedState.messages.map { message in
return message.toMessage(peerId: peerId, transaction: transaction)

View File

@ -239,6 +239,7 @@ swift_library(
"//submodules/GradientBackground:GradientBackground",
"//submodules/WallpaperBackgroundNode:WallpaperBackgroundNode",
"//submodules/ComponentFlow:ComponentFlow",
"//submodules/AdUI:AdUI",
] + select({
"@build_bazel_rules_apple//apple:ios_armv7": [],
"@build_bazel_rules_apple//apple:ios_arm64": appcenter_targets,

View File

@ -3440,7 +3440,15 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
})
if case .standard(previewing: false) = mode, let channel = renderedPeer?.chatMainPeer as? TelegramChannel, case .broadcast = channel.info {
if strongSelf.nextChannelToReadDisposable == nil {
var isRegularChat = false
if let subject = subject {
if case .message = subject {
isRegularChat = true
}
} else {
isRegularChat = true
}
if isRegularChat, strongSelf.nextChannelToReadDisposable == nil {
strongSelf.nextChannelToReadDisposable = (combineLatest(queue: .mainQueue(),
strongSelf.context.engine.peers.getNextUnreadChannel(peerId: channel.id, chatListFilterId: strongSelf.currentChatListFilter, getFilterPredicate: chatListFilterPredicate),
ApplicationSpecificNotice.getNextChatSuggestionTip(accountManager: strongSelf.context.sharedContext.accountManager)
@ -6493,7 +6501,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
})
})))
contextController.setItems(.single(contextItems))
contextController.setItems(.single(contextItems), minHeight: nil)
}
return
} else {
@ -6512,7 +6520,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
})
})))
contextController.setItems(.single(contextItems))
contextController.setItems(.single(contextItems), minHeight: nil)
return
} else {
@ -12625,7 +12633,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
}
if canDisplayContextMenu, let contextController = contextController {
contextController.setItems(.single(contextItems))
contextController.setItems(.single(contextItems), minHeight: nil)
} else {
actionSheet.setItemGroups([ActionSheetItemGroup(items: items), ActionSheetItemGroup(items: [
ActionSheetButtonItem(title: self.presentationData.strings.Common_Cancel, color: .accent, font: .bold, action: { [weak actionSheet] in

View File

@ -2613,6 +2613,8 @@ class ChatControllerNode: ASDisplayNode, UIScrollViewDelegate {
let navigationButtonsSnapshotState: ChatHistoryNavigationButtons.SnapshotState
let titleAccessoryPanelSnapshot: UIView?
let navigationBarHeight: CGFloat
let inputPanelNodeSnapshot: UIView?
let inputPanelOverscrollNodeSnapshot: UIView?
fileprivate init(
historySnapshotState: ChatHistoryListNode.SnapshotState,
@ -2620,7 +2622,9 @@ class ChatControllerNode: ASDisplayNode, UIScrollViewDelegate {
avatarSnapshotState: ChatAvatarNavigationNode.SnapshotState?,
navigationButtonsSnapshotState: ChatHistoryNavigationButtons.SnapshotState,
titleAccessoryPanelSnapshot: UIView?,
navigationBarHeight: CGFloat
navigationBarHeight: CGFloat,
inputPanelNodeSnapshot: UIView?,
inputPanelOverscrollNodeSnapshot: UIView?
) {
self.historySnapshotState = historySnapshotState
self.titleViewSnapshotState = titleViewSnapshotState
@ -2628,6 +2632,8 @@ class ChatControllerNode: ASDisplayNode, UIScrollViewDelegate {
self.navigationButtonsSnapshotState = navigationButtonsSnapshotState
self.titleAccessoryPanelSnapshot = titleAccessoryPanelSnapshot
self.navigationBarHeight = navigationBarHeight
self.inputPanelNodeSnapshot = inputPanelNodeSnapshot
self.inputPanelOverscrollNodeSnapshot = inputPanelOverscrollNodeSnapshot
}
}
@ -2640,13 +2646,25 @@ class ChatControllerNode: ASDisplayNode, UIScrollViewDelegate {
snapshot.frame = titleAccessoryPanelNode.frame
titleAccessoryPanelSnapshot = snapshot
}
var inputPanelNodeSnapshot: UIView?
if let inputPanelNode = self.inputPanelNode, let snapshot = inputPanelNode.view.snapshotView(afterScreenUpdates: false) {
snapshot.frame = inputPanelNode.frame
inputPanelNodeSnapshot = snapshot
}
var inputPanelOverscrollNodeSnapshot: UIView?
if let inputPanelOverscrollNode = self.inputPanelOverscrollNode, let snapshot = inputPanelOverscrollNode.view.snapshotView(afterScreenUpdates: false) {
snapshot.frame = inputPanelOverscrollNode.frame
inputPanelOverscrollNodeSnapshot = snapshot
}
return SnapshotState(
historySnapshotState: self.historyNode.prepareSnapshotState(),
titleViewSnapshotState: titleViewSnapshotState,
avatarSnapshotState: avatarSnapshotState,
navigationButtonsSnapshotState: self.navigateButtons.prepareSnapshotState(),
titleAccessoryPanelSnapshot: titleAccessoryPanelSnapshot,
navigationBarHeight: self.navigationBar?.backgroundNode.bounds.height ?? 0.0
navigationBarHeight: self.navigationBar?.backgroundNode.bounds.height ?? 0.0,
inputPanelNodeSnapshot: inputPanelNodeSnapshot,
inputPanelOverscrollNodeSnapshot: inputPanelOverscrollNodeSnapshot
)
}
@ -2686,6 +2704,27 @@ class ChatControllerNode: ASDisplayNode, UIScrollViewDelegate {
navigationBar.backgroundNode.update(size: currentFrame.size, transition: .animated(duration: 0.5, curve: .spring))
}
}
if let inputPanelNode = self.inputPanelNode, let inputPanelNodeSnapshot = snapshotState.inputPanelNodeSnapshot {
inputPanelNode.view.superview?.insertSubview(inputPanelNodeSnapshot, belowSubview: inputPanelNode.view)
inputPanelNodeSnapshot.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.3, removeOnCompletion: false, completion: { [weak inputPanelNodeSnapshot] _ in
inputPanelNodeSnapshot?.removeFromSuperview()
})
inputPanelNodeSnapshot.layer.animatePosition(from: CGPoint(), to: CGPoint(x: 0.0, y: -5.0), duration: 0.5, timingFunction: kCAMediaTimingFunctionSpring, removeOnCompletion: false, additive: true)
if let inputPanelOverscrollNodeSnapshot = snapshotState.inputPanelOverscrollNodeSnapshot {
inputPanelNode.view.superview?.insertSubview(inputPanelOverscrollNodeSnapshot, belowSubview: inputPanelNode.view)
inputPanelOverscrollNodeSnapshot.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.3, removeOnCompletion: false, completion: { [weak inputPanelOverscrollNodeSnapshot] _ in
inputPanelOverscrollNodeSnapshot?.removeFromSuperview()
})
inputPanelOverscrollNodeSnapshot.layer.animatePosition(from: CGPoint(), to: CGPoint(x: 0.0, y: -5.0), duration: 0.5, timingFunction: kCAMediaTimingFunctionSpring, removeOnCompletion: false, additive: true)
}
inputPanelNode.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.3)
inputPanelNode.layer.animatePosition(from: CGPoint(x: 0.0, y: 5.0), to: CGPoint(), duration: 0.5, timingFunction: kCAMediaTimingFunctionSpring, additive: true)
}
}
private var preivousChatInputPanelOverscrollNodeTimestamp: Double = 0.0

View File

@ -1039,6 +1039,16 @@ public final class ChatHistoryListNode: ListView, ChatHistoryNode {
var disableAnimations = false
if let strongSelf = self, updatedScrollPosition == nil, case .InteractiveChanges = reason, case let .known(offset) = strongSelf.visibleContentOffset(), abs(offset) <= 0.9, let previous = previous {
var fillsScreen = true
switch strongSelf.visibleBottomContentOffset() {
case let .known(bottomOffset):
if bottomOffset <= strongSelf.visibleSize.height - strongSelf.insets.bottom {
fillsScreen = false
}
default:
break
}
var previousNumAds = 0
for entry in previous.filteredEntries {
if case let .MessageEntry(message, _, _, _, _, _) = entry {
@ -1062,7 +1072,7 @@ public final class ChatHistoryListNode: ListView, ChatHistoryNode {
}
}
if let firstNonAdIndex = firstNonAdIndex, previousNumAds == 0, updatedNumAds != 0 {
if fillsScreen, let firstNonAdIndex = firstNonAdIndex, previousNumAds == 0, updatedNumAds != 0 {
updatedScrollPosition = .index(index: .message(firstNonAdIndex), position: .top(0.0), directionHint: .Up, animated: false, highlight: false)
disableAnimations = true
}

View File

@ -21,6 +21,7 @@ import UndoUI
import ShimmerEffect
import AnimatedAvatarSetNode
import AvatarNode
import AdUI
private struct MessageContextMenuData {
let starStatus: Bool?
@ -139,7 +140,10 @@ private func canEditMessage(accountPeerId: PeerId, limitsConfiguration: LimitsCo
return false
}
private func canViewReadStats(message: Message, appConfig: AppConfiguration) -> Bool {
private func canViewReadStats(message: Message, isMessageRead: Bool, appConfig: AppConfiguration) -> Bool {
if !isMessageRead {
return false
}
if message.flags.contains(.Incoming) {
return false
}
@ -149,6 +153,21 @@ private func canViewReadStats(message: Message, appConfig: AppConfiguration) ->
for media in message.media {
if let _ = media as? TelegramMediaAction {
return false
} else if let file = media as? TelegramMediaFile {
if file.isVoice || file.isInstantVideo {
var hasRead = false
for attribute in message.attributes {
if let attribute = attribute as? ConsumableContentMessageAttribute {
if attribute.consumed {
hasRead = true
break
}
}
}
if !hasRead {
return false
}
}
}
}
@ -345,18 +364,10 @@ func contextMenuForChatPresentationInterfaceState(chatPresentationInterfaceState
var actions: [ContextMenuItem] = []
actions.append(.action(ContextMenuActionItem(text: presentationData.strings.SponsoredMessageMenu_Info, textColor: .primary, textLayout: .twoLinesMax, textFont: .custom(Font.regular(presentationData.listsFontSize.baseDisplaySize - 1.0)), badge: nil, icon: { theme in
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Info"), color: theme.actionSheet.primaryTextColor)
}, iconSource: nil, action: { _, f in
f(.default)
controllerInteraction.presentController(textAlertController(context: context, title: nil, text: presentationData.strings.SponsoredMessageInfo_Text, actions: [
TextAlertAction(type: .genericAction, title: presentationData.strings.Common_Cancel, action: {
}),
TextAlertAction(type: .defaultAction, title: presentationData.strings.SponsoredMessageInfo_Action, action: {
context.sharedContext.openExternalUrl(context: context, urlContext: .generic, url: presentationData.strings.SponsoredMessageInfo_ActionUrl, forceExternal: true, presentationData: presentationData, navigationController: controllerInteraction.navigationController(), dismissInput: {
controllerInteraction.navigationController()?.view.endEditing(true)
})
}),
]), nil)
}, iconSource: nil, action: { c, _ in
c.dismiss(completion: {
controllerInteraction.navigationController()?.pushViewController(AdInfoScreen(context: context))
})
})))
actions.append(.separator)
@ -518,30 +529,40 @@ func contextMenuForChatPresentationInterfaceState(chatPresentationInterfaceState
let cachedData = context.account.postbox.transaction { transaction -> CachedPeerData? in
return transaction.getPeerCachedData(peerId: messages[0].id.peerId)
}
let readState = context.account.postbox.transaction { transaction -> CombinedPeerReadState? in
return transaction.getCombinedPeerReadState(messages[0].id.peerId)
}
let dataSignal: Signal<(MessageContextMenuData, [MessageId: ChatUpdatingMessageMedia], CachedPeerData?, AppConfiguration), NoError> = combineLatest(
let dataSignal: Signal<(MessageContextMenuData, [MessageId: ChatUpdatingMessageMedia], CachedPeerData?, AppConfiguration, Bool), NoError> = combineLatest(
loadLimits,
loadStickerSaveStatusSignal,
loadResourceStatusSignal,
context.sharedContext.chatAvailableMessageActions(postbox: context.account.postbox, accountPeerId: context.account.peerId, messageIds: Set(messages.map { $0.id })),
context.account.pendingUpdateMessageManager.updatingMessageMedia
|> take(1),
cachedData
cachedData,
readState
)
|> map { limitsAndAppConfig, stickerSaveStatus, resourceStatus, messageActions, updatingMessageMedia, cachedData -> (MessageContextMenuData, [MessageId: ChatUpdatingMessageMedia], CachedPeerData?, AppConfiguration) in
|> map { limitsAndAppConfig, stickerSaveStatus, resourceStatus, messageActions, updatingMessageMedia, cachedData, readState -> (MessageContextMenuData, [MessageId: ChatUpdatingMessageMedia], CachedPeerData?, AppConfiguration, Bool) in
let (limitsConfiguration, appConfig) = limitsAndAppConfig
var canEdit = false
if !isAction {
let message = messages[0]
canEdit = canEditMessage(context: context, limitsConfiguration: limitsConfiguration, message: message)
}
var isMessageRead = false
if let readState = readState {
isMessageRead = readState.isOutgoingMessageIndexRead(message.index)
}
return (MessageContextMenuData(starStatus: stickerSaveStatus, canReply: canReply, canPin: canPin, canEdit: canEdit, canSelect: canSelect, resourceStatus: resourceStatus, messageActions: messageActions), updatingMessageMedia, cachedData, appConfig)
return (MessageContextMenuData(starStatus: stickerSaveStatus, canReply: canReply, canPin: canPin, canEdit: canEdit, canSelect: canSelect, resourceStatus: resourceStatus, messageActions: messageActions), updatingMessageMedia, cachedData, appConfig, isMessageRead)
}
return dataSignal
|> deliverOnMainQueue
|> map { data, updatingMessageMedia, cachedData, appConfig -> [ContextMenuItem] in
|> map { data, updatingMessageMedia, cachedData, appConfig, isMessageRead -> [ContextMenuItem] in
var actions: [ContextMenuItem] = []
var isPinnedMessages = false
@ -1103,8 +1124,10 @@ func contextMenuForChatPresentationInterfaceState(chatPresentationInterfaceState
}
if !isPinnedMessages, !isReplyThreadHead, data.canSelect {
var didAddSeparator = false
if !selectAll || messages.count == 1 {
if !actions.isEmpty {
if !actions.isEmpty && !didAddSeparator {
didAddSeparator = true
actions.append(.separator)
}
@ -1118,6 +1141,11 @@ func contextMenuForChatPresentationInterfaceState(chatPresentationInterfaceState
}
if messages.count > 1 {
if !actions.isEmpty && !didAddSeparator {
didAddSeparator = true
actions.append(.separator)
}
actions.append(.action(ContextMenuActionItem(text: chatPresentationInterfaceState.strings.Conversation_ContextMenuSelectAll(Int32(messages.count)), icon: { theme in
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/SelectAll"), color: theme.actionSheet.primaryTextColor)
}, action: { _, f in
@ -1128,7 +1156,7 @@ func contextMenuForChatPresentationInterfaceState(chatPresentationInterfaceState
}
}
if let peer = message.peers[message.id.peerId], canViewReadStats(message: message, appConfig: appConfig) {
if let peer = message.peers[message.id.peerId], canViewReadStats(message: message, isMessageRead: isMessageRead, appConfig: appConfig) {
var hasReadReports = false
if let channel = peer as? TelegramChannel {
if case .group = channel.info {
@ -1160,29 +1188,21 @@ func contextMenuForChatPresentationInterfaceState(chatPresentationInterfaceState
subActions.append(.action(ContextMenuActionItem(text: presentationData.strings.Common_Back, textColor: .primary, icon: { theme in
return generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/Back"), color: theme.actionSheet.primaryTextColor)
}, action: { controller, _ in
controller.setItems(contextMenuForChatPresentationInterfaceState(chatPresentationInterfaceState: chatPresentationInterfaceState, context: context, messages: messages, controllerInteraction: controllerInteraction, selectAll: selectAll, interfaceInteraction: interfaceInteraction, readStats: stats))
controller.setItems(contextMenuForChatPresentationInterfaceState(chatPresentationInterfaceState: chatPresentationInterfaceState, context: context, messages: messages, controllerInteraction: controllerInteraction, selectAll: selectAll, interfaceInteraction: interfaceInteraction, readStats: stats), minHeight: nil)
})))
let debugRepeatCount: Int
#if DEBUG
debugRepeatCount = stats.peers.count == 1 ? 1 : 50
#else
debugRepeatCount = 1
#endif
for peer in stats.peers {
let avatarSignal = peerAvatarCompleteImage(account: context.account, peer: peer._asPeer(), size: CGSize(width: 30.0, height: 30.0))
for _ in 0 ..< debugRepeatCount {
for peer in stats.peers {
let avatarSignal = peerAvatarCompleteImage(account: context.account, peer: peer._asPeer(), size: CGSize(width: 30.0, height: 30.0))
subActions.append(.action(ContextMenuActionItem(text: peer.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder), textLayout: .singleLine, icon: { _ in nil }, iconSource: ContextMenuActionItemIconSource(size: CGSize(width: 30.0, height: 30.0), signal: avatarSignal), action: { _, f in
c.dismiss(completion: {
controllerInteraction.openPeer(peer.id, .default, nil)
})
})))
}
subActions.append(.action(ContextMenuActionItem(text: peer.displayTitle(strings: presentationData.strings, displayOrder: presentationData.nameDisplayOrder), textLayout: .singleLine, icon: { _ in nil }, iconSource: ContextMenuActionItemIconSource(size: CGSize(width: 30.0, height: 30.0), signal: avatarSignal), action: { _, f in
c.dismiss(completion: {
controllerInteraction.openPeer(peer.id, .default, nil)
})
})))
}
c.setItems(.single(subActions))
let minHeight = c.getActionsMinHeight()
c.setItems(.single(subActions), minHeight: minHeight)
} else {
f(.default)
}
@ -1845,14 +1865,24 @@ private final class ChatReadReportContextItemNode: ASDisplayNode, ContextMenuCus
let rightTextInset: CGFloat = sideInset + 36.0
let calculatedWidth = min(constrainedWidth, 260.0)
let calculatedWidth = min(constrainedWidth, 250.0)
let textFont = Font.regular(self.presentationData.listsFontSize.baseDisplaySize)
if let currentStats = self.currentStats {
if currentStats.peers.isEmpty {
//TODO:localize
self.textNode.attributedText = NSAttributedString(string: "No Views", font: textFont, textColor: self.presentationData.theme.contextMenu.secondaryColor)
var text = self.presentationData.strings.Conversation_ContextMenuNoViews
for media in self.item.message.media {
if let file = media as? TelegramMediaFile {
if file.isVoice {
text = self.presentationData.strings.Conversation_ContextMenuNobodyListened
} else if file.isInstantVideo {
text = self.presentationData.strings.Conversation_ContextMenuNobodyWatched
}
}
}
self.textNode.attributedText = NSAttributedString(string: text, font: textFont, textColor: self.presentationData.theme.contextMenu.secondaryColor)
} else if currentStats.peers.count == 1 {
self.textNode.attributedText = NSAttributedString(string: currentStats.peers[0].displayTitle(strings: self.presentationData.strings, displayOrder: self.presentationData.nameDisplayOrder), font: textFont, textColor: self.presentationData.theme.contextMenu.primaryColor)
} else {

View File

@ -1850,7 +1850,7 @@ private final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewD
}
return items
})
}, minHeight: nil)
})))
}
if strongSelf.searchDisplayController == nil {
@ -1984,7 +1984,7 @@ private final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewD
}
return items
})
}, minHeight: nil)
})))
}
@ -3700,7 +3700,7 @@ private final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewD
}, action: { [weak self] c, f in
self?.openReport(user: false, contextController: c, backAction: { c in
if let mainItemsImpl = mainItemsImpl {
c.setItems(mainItemsImpl())
c.setItems(mainItemsImpl(), minHeight: nil)
}
})
})))
@ -4442,7 +4442,7 @@ private final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewD
})))
if let contextController = contextController {
contextController.setItems(.single(items))
contextController.setItems(.single(items), minHeight: nil)
} else {
strongSelf.state = strongSelf.state.withHighlightedButton(.voiceChat)
if let (layout, navigationHeight) = strongSelf.validLayout {
@ -4538,7 +4538,7 @@ private final class PeerInfoScreenNode: ViewControllerTracingNode, UIScrollViewD
}
if let contextController = contextController {
contextController.setItems(.single(items))
contextController.setItems(.single(items), minHeight: nil)
} else {
strongSelf.state = strongSelf.state.withHighlightedButton(.voiceChat)
if let (layout, navigationHeight) = strongSelf.validLayout {

@ -1 +1 @@
Subproject commit aaede253be4dbfdfcb2258cdb6faa843785192e6
Subproject commit f76a9290fa502a8df473dd872aedf9a553b089cc