Merge commit '8213fdaee36cf426edf15efe93ad146a09bbdc79'

This commit is contained in:
Ali 2021-02-19 22:51:08 +04:00
commit a03b3766d6
46 changed files with 2965 additions and 2656 deletions
Telegram/Telegram-iOS/en.lproj
submodules
CallListUI/Sources
ChatListSearchRecentPeersNode/Sources
ChatListUI/Sources
ContactListUI/Sources
Display/Source
HashtagSearchUI/Sources
InviteLinksUI/Sources
ItemListUI/Sources
LocationUI/Sources
MessageReactionListUI/Sources
PeerInfoUI/Sources
SettingsUI/Sources
ShareItems/Sources
StatisticsUI
TelegramCallsUI/Sources
TelegramPresentationData/Sources
TelegramUI
WebSearchUI/Sources

@ -6147,3 +6147,5 @@ Sorry for the inconvenience.";
"Channel.Setup.LinkTypePublic" = "Public";
"Channel.Setup.LinkTypePrivate" = "Private";
"VoiceOver.ScrollStatus" = "Row %1$@ of %2$@";

@ -220,6 +220,10 @@ final class CallListControllerNode: ASDisplayNode {
self.listNode = ListView()
self.listNode.verticalScrollIndicatorColor = self.presentationData.theme.list.scrollIndicatorColor
self.listNode.accessibilityPageScrolledString = { row, count in
return presentationData.strings.VoiceOver_ScrollStatus(row, count).0
}
self.leftOverlayNode = ASDisplayNode()
self.leftOverlayNode.backgroundColor = self.presentationData.theme.list.blocksBackgroundColor
self.rightOverlayNode = ASDisplayNode()

@ -140,6 +140,9 @@ public final class ChatListSearchRecentPeersNode: ASDisplayNode {
self.listView = ListView()
self.listView.transform = CATransform3DMakeRotation(-CGFloat.pi / 2.0, 0.0, 0.0, 1.0)
self.listView.accessibilityPageScrolledString = { row, count in
return strings.VoiceOver_ScrollStatus(row, count).0
}
super.init()

@ -735,7 +735,8 @@ final class ChatListSearchListPaneNode: ASDisplayNode, ChatListSearchPaneNode {
}
self.tagMask = tagMask
self.presentationData = context.sharedContext.currentPresentationData.with { $0 }
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
self.presentationData = presentationData
self.presentationDataPromise.set(.single(ChatListPresentationData(theme: self.presentationData.theme, fontSize: self.presentationData.listsFontSize, strings: self.presentationData.strings, dateTimeFormat: self.presentationData.dateTimeFormat, nameSortOrder: self.presentationData.nameSortOrder, nameDisplayOrder: self.presentationData.nameDisplayOrder, disableAnimations: self.presentationData.disableAnimations)))
self.searchStatePromise.set(self.searchStateValue)
@ -744,6 +745,9 @@ final class ChatListSearchListPaneNode: ASDisplayNode, ChatListSearchPaneNode {
self.recentListNode = ListView()
self.recentListNode.verticalScrollIndicatorColor = self.presentationData.theme.list.scrollIndicatorColor
self.recentListNode.accessibilityPageScrolledString = { row, count in
return presentationData.strings.VoiceOver_ScrollStatus(row, count).0
}
self.shimmerNode = ChatListSearchShimmerNode(key: key)
self.shimmerNode.isUserInteractionEnabled = false
@ -751,7 +755,10 @@ final class ChatListSearchListPaneNode: ASDisplayNode, ChatListSearchPaneNode {
self.listNode = ListView()
self.listNode.verticalScrollIndicatorColor = self.presentationData.theme.list.scrollIndicatorColor
self.listNode.accessibilityPageScrolledString = { row, count in
return presentationData.strings.VoiceOver_ScrollStatus(row, count).0
}
var openMediaMessageImpl: ((Message, ChatControllerInteractionOpenMessageMode) -> Void)?
var transitionNodeImpl: ((MessageId, Media) -> (ASDisplayNode, CGRect, () -> (UIView?, UIView?))?)?
var addToTransitionSurfaceImpl: ((UIView) -> Void)?

@ -805,10 +805,14 @@ public final class ContactListNode: ASDisplayNode {
self.displayPermissionPlaceholder = displayPermissionPlaceholder
self.contextAction = contextAction
self.presentationData = context.sharedContext.currentPresentationData.with { $0 }
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
self.presentationData = presentationData
self.listNode = ListView()
self.listNode.dynamicBounceEnabled = !self.presentationData.disableAnimations
self.listNode.accessibilityPageScrolledString = { row, count in
return presentationData.strings.VoiceOver_ScrollStatus(row, count).0
}
self.indexNode = CollectionIndexNode()

@ -228,7 +228,8 @@ public final class ContactsSearchContainerNode: SearchDisplayControllerContentNo
self.openPeer = openPeer
self.contextAction = contextAction
self.presentationData = context.sharedContext.currentPresentationData.with { $0 }
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
self.presentationData = presentationData
self.themeAndStringsPromise = Promise((self.presentationData.theme, self.presentationData.strings))
@ -237,6 +238,9 @@ public final class ContactsSearchContainerNode: SearchDisplayControllerContentNo
self.listNode = ListView()
self.listNode.backgroundColor = self.presentationData.theme.list.plainBackgroundColor
self.listNode.isHidden = true
self.listNode.accessibilityPageScrolledString = { row, count in
return presentationData.strings.VoiceOver_ScrollStatus(row, count).0
}
super.init()

@ -287,11 +287,15 @@ final class InviteContactsControllerNode: ASDisplayNode {
init(context: AccountContext) {
self.context = context
self.presentationData = context.sharedContext.currentPresentationData.with { $0 }
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
self.presentationData = presentationData
self.presentationDataPromise = Promise(self.presentationData)
self.listNode = ListView()
self.listNode.accessibilityPageScrolledString = { row, count in
return presentationData.strings.VoiceOver_ScrollStatus(row, count).0
}
var shareImpl: (() -> Void)?
self.countPanelNode = InviteContactsCountPanelNode(theme: self.presentationData.theme, strings: self.presentationData.strings, action: {

@ -4249,6 +4249,8 @@ open class ListView: ASDisplayNode, UIScrollViewAccessibilityDelegate, UIGesture
return false
}
public var accessibilityPageScrolledString: ((String, String) -> String)?
public func scrollWithDirection(_ direction: ListViewScrollDirection, distance: CGFloat) -> Bool {
var accessibilityFocusedNode: (ASDisplayNode, CGRect)?
for itemNode in self.itemNodes {
@ -4289,7 +4291,12 @@ open class ListView: ASDisplayNode, UIScrollViewAccessibilityDelegate, UIGesture
if frame.intersects(itemNode.frame) {
UIAccessibility.post(notification: UIAccessibility.Notification.layoutChanged, argument: itemNode.view)
if let index = itemNode.index {
let scrollStatus = "Row \(index + 1) of \(self.items.count)"
let scrollStatus: String
if let accessibilityPageScrolledString = self.accessibilityPageScrolledString {
scrollStatus = accessibilityPageScrolledString("\(index + 1)", "\(self.items.count)")
} else {
scrollStatus = "Row \(index + 1) of \(self.items.count)"
}
UIAccessibility.post(notification: UIAccessibility.Notification.pageScrolled, argument: scrollStatus)
}
break

@ -30,6 +30,9 @@ final class HashtagSearchControllerNode: ASDisplayNode {
self.context = context
self.query = query
self.listNode = ListView()
self.listNode.accessibilityPageScrolledString = { row, count in
return strings.VoiceOver_ScrollStatus(row, count).0
}
self.toolbarBackgroundNode = ASDisplayNode()
self.toolbarBackgroundNode.backgroundColor = theme.rootController.navigationBar.backgroundColor

@ -279,7 +279,9 @@ public final class InviteLinkInviteController: ViewController {
init(context: AccountContext, peerId: PeerId, controller: InviteLinkInviteController) {
self.context = context
self.peerId = peerId
self.presentationData = context.sharedContext.currentPresentationData.with { $0 }
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
self.presentationData = presentationData
self.presentationDataPromise = Promise(self.presentationData)
self.controller = controller
@ -317,6 +319,9 @@ public final class InviteLinkInviteController: ViewController {
self.listNode = ListView()
self.listNode.verticalScrollIndicatorColor = UIColor(white: 0.0, alpha: 0.3)
self.listNode.verticalScrollIndicatorFollowsOverscroll = true
self.listNode.accessibilityPageScrolledString = { row, count in
return presentationData.strings.VoiceOver_ScrollStatus(row, count).0
}
super.init()

@ -416,6 +416,9 @@ public final class InviteLinkViewController: ViewController {
self.listNode = ListView()
self.listNode.verticalScrollIndicatorColor = UIColor(white: 0.0, alpha: 0.3)
self.listNode.verticalScrollIndicatorFollowsOverscroll = true
self.listNode.accessibilityPageScrolledString = { row, count in
return presentationData.strings.VoiceOver_ScrollStatus(row, count).0
}
super.init()

@ -71,12 +71,23 @@ public enum ItemListStyle {
case blocks
}
public struct ItemListToolbarItem {
public struct Action {
public let title: String
public let isEnabled: Bool
public let action: () -> Void
}
let actions: [Action]
}
private struct ItemListNodeTransition {
let theme: PresentationTheme
let entries: ItemListNodeEntryTransition
let updateStyle: ItemListStyle?
let emptyStateItem: ItemListControllerEmptyStateItem?
let searchItem: ItemListControllerSearch?
let toolbarItem: ItemListToolbarItem?
let focusItemTag: ItemListItemTag?
let ensureVisibleItemTag: ItemListItemTag?
let scrollToItem: ListViewScrollToItem?
@ -94,6 +105,7 @@ public final class ItemListNodeState {
let style: ItemListStyle
let emptyStateItem: ItemListControllerEmptyStateItem?
let searchItem: ItemListControllerSearch?
let toolbarItem: ItemListToolbarItem?
let animateChanges: Bool
let crossfadeState: Bool
let scrollEnabled: Bool
@ -101,12 +113,13 @@ public final class ItemListNodeState {
let ensureVisibleItemTag: ItemListItemTag?
let initialScrollToItem: ListViewScrollToItem?
public init<T: ItemListNodeEntry>(presentationData: ItemListPresentationData, entries: [T], style: ItemListStyle, focusItemTag: ItemListItemTag? = nil, ensureVisibleItemTag: ItemListItemTag? = nil, emptyStateItem: ItemListControllerEmptyStateItem? = nil, searchItem: ItemListControllerSearch? = nil, initialScrollToItem: ListViewScrollToItem? = nil, crossfadeState: Bool = false, animateChanges: Bool = true, scrollEnabled: Bool = true) {
public init<T: ItemListNodeEntry>(presentationData: ItemListPresentationData, entries: [T], style: ItemListStyle, focusItemTag: ItemListItemTag? = nil, ensureVisibleItemTag: ItemListItemTag? = nil, emptyStateItem: ItemListControllerEmptyStateItem? = nil, searchItem: ItemListControllerSearch? = nil, toolbarItem: ItemListToolbarItem? = nil, initialScrollToItem: ListViewScrollToItem? = nil, crossfadeState: Bool = false, animateChanges: Bool = true, scrollEnabled: Bool = true) {
self.presentationData = presentationData
self.entries = entries.map { $0 }
self.style = style
self.emptyStateItem = emptyStateItem
self.searchItem = searchItem
self.toolbarItem = toolbarItem
self.crossfadeState = crossfadeState
self.animateChanges = animateChanges
self.focusItemTag = focusItemTag
@ -189,6 +202,8 @@ open class ItemListControllerNode: ASDisplayNode, UIScrollViewDelegate {
private var emptyStateItem: ItemListControllerEmptyStateItem?
private var emptyStateNode: ItemListControllerEmptyStateItemNode?
private var toolbarNode: ToolbarNode?
private var searchItem: ItemListControllerSearch?
private var searchNode: ItemListControllerSearchNode?
@ -333,7 +348,7 @@ open class ItemListControllerNode: ASDisplayNode, UIScrollViewDelegate {
scrollToItem = state.initialScrollToItem
}
return ItemListNodeTransition(theme: presentationData.theme, entries: transition, updateStyle: updatedStyle, emptyStateItem: state.emptyStateItem, searchItem: state.searchItem, focusItemTag: state.focusItemTag, ensureVisibleItemTag: state.ensureVisibleItemTag, scrollToItem: scrollToItem, firstTime: previous == nil, animated: previous != nil && state.animateChanges, animateAlpha: previous != nil && state.animateChanges, crossfade: state.crossfadeState, mergedEntries: state.entries, scrollEnabled: state.scrollEnabled)
return ItemListNodeTransition(theme: presentationData.theme, entries: transition, updateStyle: updatedStyle, emptyStateItem: state.emptyStateItem, searchItem: state.searchItem, toolbarItem: state.toolbarItem, focusItemTag: state.focusItemTag, ensureVisibleItemTag: state.ensureVisibleItemTag, scrollToItem: scrollToItem, firstTime: previous == nil, animated: previous != nil && state.animateChanges, animateAlpha: previous != nil && state.animateChanges, crossfade: state.crossfadeState, mergedEntries: state.entries, scrollEnabled: state.scrollEnabled)
})
|> deliverOnMainQueue).start(next: { [weak self] transition in
if let strongSelf = self {

@ -287,6 +287,9 @@ final class LocationPickerControllerNode: ViewControllerTracingNode, CLLocationM
self.listNode.backgroundColor = self.presentationData.theme.list.plainBackgroundColor
self.listNode.verticalScrollIndicatorColor = UIColor(white: 0.0, alpha: 0.3)
self.listNode.verticalScrollIndicatorFollowsOverscroll = true
self.listNode.accessibilityPageScrolledString = { row, count in
return presentationData.strings.VoiceOver_ScrollStatus(row, count).0
}
self.emptyResultsTextNode = ImmediateTextNode()
self.emptyResultsTextNode.maximumNumberOfLines = 0

@ -114,7 +114,8 @@ final class LocationSearchContainerNode: ASDisplayNode {
self.context = context
self.interaction = interaction
self.presentationData = context.sharedContext.currentPresentationData.with { $0 }
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
self.presentationData = presentationData
self.themeAndStringsPromise = Promise((self.presentationData.theme, self.presentationData.strings))
self.dimNode = ASDisplayNode()
@ -122,6 +123,9 @@ final class LocationSearchContainerNode: ASDisplayNode {
self.listNode = ListView()
self.listNode.backgroundColor = self.presentationData.theme.list.plainBackgroundColor
self.listNode.isHidden = true
self.listNode.accessibilityPageScrolledString = { row, count in
return presentationData.strings.VoiceOver_ScrollStatus(row, count).0
}
self.emptyResultsTitleNode = ImmediateTextNode()
self.emptyResultsTitleNode.attributedText = NSAttributedString(string: self.presentationData.strings.SharedMedia_SearchNoResults, font: Font.semibold(17.0), textColor: self.presentationData.theme.list.freeTextColor)

@ -234,6 +234,9 @@ final class LocationViewControllerNode: ViewControllerTracingNode, CLLocationMan
self.listNode.backgroundColor = self.presentationData.theme.list.plainBackgroundColor
self.listNode.verticalScrollIndicatorColor = UIColor(white: 0.0, alpha: 0.3)
self.listNode.verticalScrollIndicatorFollowsOverscroll = true
self.listNode.accessibilityPageScrolledString = { row, count in
return presentationData.strings.VoiceOver_ScrollStatus(row, count).0
}
var setupProximityNotificationImpl: ((Bool) -> Void)?
self.headerNode = LocationMapHeaderNode(presentationData: presentationData, toggleMapModeSelection: interaction.toggleMapModeSelection, goToUserLocation: interaction.toggleTrackingMode, setupProximityNotification: { reset in

@ -182,6 +182,9 @@ private final class MessageReactionListControllerNode: ViewControllerTracingNode
self.listNode = ListView()
self.listNode.limitHitTestToNodes = true
self.listNode.accessibilityPageScrolledString = { row, count in
return presentationData.strings.VoiceOver_ScrollStatus(row, count).0
}
self.placeholderNode = MessageReactionListLoadingPlaceholder(theme: presentationData.theme, itemHeight: itemHeight)
self.placeholderNode?.isUserInteractionEnabled = false

@ -125,11 +125,15 @@ final class ChannelDiscussionGroupSearchContainerNode: SearchDisplayControllerCo
self.context = context
self.openPeer = openPeer
self.presentationData = context.sharedContext.currentPresentationData.with { $0 }
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
self.presentationData = presentationData
self.presentationDataPromise = Promise(self.presentationData)
self.dimNode = ASDisplayNode()
self.listNode = ListView()
self.listNode.accessibilityPageScrolledString = { row, count in
return presentationData.strings.VoiceOver_ScrollStatus(row, count).0
}
super.init()

@ -321,7 +321,9 @@ public final class ChannelMembersSearchContainerNode: SearchDisplayControllerCon
self.openPeer = openPeer
self.mode = mode
self.presentationData = context.sharedContext.currentPresentationData.with { $0 }
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
self.presentationData = presentationData
self.forceTheme = forceTheme
if let forceTheme = self.forceTheme {
self.presentationData = self.presentationData.withUpdated(theme: forceTheme)
@ -329,7 +331,14 @@ public final class ChannelMembersSearchContainerNode: SearchDisplayControllerCon
self.presentationDataPromise = Promise(self.presentationData)
self.emptyQueryListNode = ListView()
self.emptyQueryListNode.accessibilityPageScrolledString = { row, count in
return presentationData.strings.VoiceOver_ScrollStatus(row, count).0
}
self.listNode = ListView()
self.listNode.accessibilityPageScrolledString = { row, count in
return presentationData.strings.VoiceOver_ScrollStatus(row, count).0
}
super.init()

@ -212,6 +212,10 @@ class ChannelMembersSearchControllerNode: ASDisplayNode {
self.presentationData = self.presentationData.withUpdated(theme: forceTheme)
}
self.listNode.accessibilityPageScrolledString = { row, count in
return presentationData.strings.VoiceOver_ScrollStatus(row, count).0
}
super.init()
self.setViewBlock({

@ -182,12 +182,16 @@ private final class OldChannelsSearchContainerNode: SearchDisplayControllerConte
private let presentationDataPromise: Promise<PresentationData>
init(context: AccountContext, peers: Signal<[InactiveChannel], NoError>, selectedPeerIds: Signal<Set<PeerId>, NoError>, togglePeer: @escaping (PeerId) -> Void) {
self.presentationData = context.sharedContext.currentPresentationData.with { $0 }
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
self.presentationData = presentationData
self.presentationDataPromise = Promise(self.presentationData)
self.listNode = ListView()
self.listNode.backgroundColor = self.presentationData.theme.chatList.backgroundColor
self.listNode.isHidden = true
self.listNode.accessibilityPageScrolledString = { row, count in
return presentationData.strings.VoiceOver_ScrollStatus(row, count).0
}
super.init()

@ -99,7 +99,8 @@ private final class LocalizationListSearchContainerNode: SearchDisplayController
}
init(context: AccountContext, listState: LocalizationListState, selectLocalization: @escaping (LocalizationInfo) -> Void, applyingCode: Signal<String?, NoError>) {
self.presentationData = context.sharedContext.currentPresentationData.with { $0 }
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
self.presentationData = presentationData
self.presentationDataPromise = Promise(self.presentationData)
@ -107,6 +108,9 @@ private final class LocalizationListSearchContainerNode: SearchDisplayController
self.dimNode.backgroundColor = UIColor.black.withAlphaComponent(0.5)
self.listNode = ListView()
self.listNode.accessibilityPageScrolledString = { row, count in
return presentationData.strings.VoiceOver_ScrollStatus(row, count).0
}
super.init()
@ -308,6 +312,9 @@ final class LocalizationListControllerNode: ViewControllerTracingNode {
self.listNode = ListView()
self.listNode.keepTopItemOverscrollBackground = ListViewKeepTopItemOverscrollBackground(color: presentationData.theme.chatList.backgroundColor, direction: true)
self.listNode.accessibilityPageScrolledString = { row, count in
return presentationData.strings.VoiceOver_ScrollStatus(row, count).0
}
super.init()

@ -716,7 +716,10 @@ final class NotificationExceptionsControllerNode: ViewControllerTracingNode {
self.stateValue = Atomic(value: NotificationExceptionState(mode: mode))
self.listNode = ListView()
self.listNode.keepTopItemOverscrollBackground = ListViewKeepTopItemOverscrollBackground(color: presentationData.theme.chatList.backgroundColor, direction: true)
//self.listNode.keepBottomItemOverscrollBackground = presentationData.theme.chatList.backgroundColor
self.listNode.accessibilityPageScrolledString = { row, count in
return presentationData.strings.VoiceOver_ScrollStatus(row, count).0
}
super.init()
let stateValue = self.stateValue
@ -1164,7 +1167,8 @@ private final class NotificationExceptionsSearchContainerNode: SearchDisplayCont
}
init(context: AccountContext, mode: NotificationExceptionMode, arguments: NotificationExceptionArguments) {
self.presentationData = context.sharedContext.currentPresentationData.with { $0 }
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
self.presentationData = presentationData
self.themeAndStringsPromise = Promise((self.presentationData.theme, self.presentationData.strings))
@ -1172,6 +1176,9 @@ private final class NotificationExceptionsSearchContainerNode: SearchDisplayCont
self.dimNode.backgroundColor = UIColor.black.withAlphaComponent(0.5)
self.listNode = ListView()
self.listNode.accessibilityPageScrolledString = { row, count in
return presentationData.strings.VoiceOver_ScrollStatus(row, count).0
}
super.init()

@ -363,16 +363,23 @@ public final class SettingsSearchContainerNode: SearchDisplayControllerContentNo
private let presentationDataPromise: Promise<PresentationData>
public init(context: AccountContext, openResult: @escaping (SettingsSearchableItem) -> Void, resolvedFaqUrl: Signal<ResolvedUrl?, NoError>, exceptionsList: Signal<NotificationExceptionsList?, NoError>, archivedStickerPacks: Signal<[ArchivedStickerPackItem]?, NoError>, privacySettings: Signal<AccountPrivacySettings?, NoError>, hasTwoStepAuth: Signal<Bool?, NoError>, activeSessionsContext: Signal<ActiveSessionsContext?, NoError>, webSessionsContext: Signal<WebSessionsContext?, NoError>) {
self.presentationData = context.sharedContext.currentPresentationData.with { $0 }
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
self.presentationData = presentationData
self.presentationDataPromise = Promise(self.presentationData)
self.listNode = ListView()
self.listNode.backgroundColor = self.presentationData.theme.chatList.backgroundColor
self.listNode.isHidden = true
self.listNode.accessibilityPageScrolledString = { row, count in
return presentationData.strings.VoiceOver_ScrollStatus(row, count).0
}
self.recentListNode = ListView()
self.recentListNode.backgroundColor = self.presentationData.theme.chatList.backgroundColor
self.recentListNode.verticalScrollIndicatorColor = self.presentationData.theme.list.scrollIndicatorColor
self.recentListNode.accessibilityPageScrolledString = { row, count in
return presentationData.strings.VoiceOver_ScrollStatus(row, count).0
}
super.init()

@ -376,12 +376,17 @@ final class ThemeGridSearchContentNode: SearchDisplayControllerContentNode {
self.context = context
self.queryPromise = Promise<WallpaperSearchQuery>(self.queryValue)
self.presentationData = context.sharedContext.currentPresentationData.with { $0 }
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
self.presentationData = presentationData
self.presentationDataPromise = Promise(self.presentationData)
self.dimNode = ASDisplayNode()
self.recentListNode = ListView()
self.recentListNode.verticalScrollIndicatorColor = self.presentationData.theme.list.scrollIndicatorColor
self.recentListNode.accessibilityPageScrolledString = { row, count in
return presentationData.strings.VoiceOver_ScrollStatus(row, count).0
}
self.gridNode = GridNode()
self.emptyResultsTitleNode = ImmediateTextNode()

@ -365,31 +365,34 @@ public func preparedShareItems(account: Account, to peerId: PeerId, dataItems: [
public func sentShareItems(account: Account, to peerIds: [PeerId], items: [PreparedShareItemContent]) -> Signal<Float, Void> {
var messages: [EnqueueMessage] = []
var groupingKey: Int64?
var mediaTypes: (photo: Bool, video: Bool, music: Bool, other: Bool) = (false, false, false, false)
var mediaTypes: (photo: Int, video: Int, music: Int, other: Int) = (0, 0, 0, 0)
if items.count > 1 {
for item in items {
if case let .media(result) = item, case let .media(media) = result {
if media.media is TelegramMediaImage {
mediaTypes.photo = true
mediaTypes.photo += 1
} else if let media = media.media as? TelegramMediaFile {
if media.isVideo {
mediaTypes.video = true
} else if let fileName = media.fileName, fileName.hasPrefix("mp3") || fileName.hasPrefix("m4a") {
mediaTypes.music = true
mediaTypes.video += 1
} else if media.isVoice || media.isAnimated || media.isSticker {
mediaTypes = (0, 0, 0, 0)
break
} else if let fileName = media.fileName?.lowercased(), fileName.hasPrefix(".mp3") || fileName.hasPrefix("m4a") {
mediaTypes.music += 1
} else {
mediaTypes.other = true
mediaTypes.other += 1
}
} else {
mediaTypes = (false, false, false, false)
mediaTypes = (0, 0, 0, 0)
break
}
}
}
}
if (mediaTypes.photo || mediaTypes.video) && !(mediaTypes.music || mediaTypes.other) {
if ((mediaTypes.photo + mediaTypes.video) > 1) && (mediaTypes.music == 0 && mediaTypes.other == 0) {
groupingKey = arc4random64()
} else if !(mediaTypes.photo || mediaTypes.video) && (mediaTypes.music != mediaTypes.other) {
} else if ((mediaTypes.photo + mediaTypes.video) == 0) && ((mediaTypes.music > 1 && mediaTypes.other == 0) || (mediaTypes.music == 0 && mediaTypes.other > 1)) {
groupingKey = arc4random64()
}

@ -28,6 +28,7 @@ swift_library(
"//submodules/AnimatedStickerNode:AnimatedStickerNode",
"//submodules/ItemListPeerItem:ItemListPeerItem",
"//submodules/ItemListPeerActionItem:ItemListPeerActionItem",
"//submodules/ContextUI:ContextUI",
],
visibility = [
"//visibility:public",

@ -1,6 +1,7 @@
import Foundation
import UIKit
import Display
import AsyncDisplayKit
import SwiftSignalKit
import Postbox
import TelegramCore
@ -14,16 +15,19 @@ import AccountContext
import PresentationDataUtils
import AppBundle
import GraphUI
import ContextUI
private final class ChannelStatsControllerArguments {
let context: AccountContext
let loadDetailedGraph: (StatsGraph, Int64) -> Signal<StatsGraph?, NoError>
let openMessageStats: (MessageId) -> Void
let contextAction: (MessageId, ASDisplayNode, ContextGesture?) -> Void
init(context: AccountContext, loadDetailedGraph: @escaping (StatsGraph, Int64) -> Signal<StatsGraph?, NoError>, openMessage: @escaping (MessageId) -> Void) {
init(context: AccountContext, loadDetailedGraph: @escaping (StatsGraph, Int64) -> Signal<StatsGraph?, NoError>, openMessage: @escaping (MessageId) -> Void, contextAction: @escaping (MessageId, ASDisplayNode, ContextGesture?) -> Void) {
self.context = context
self.loadDetailedGraph = loadDetailedGraph
self.openMessageStats = openMessage
self.contextAction = contextAction
}
}
@ -330,6 +334,8 @@ private enum StatsEntry: ItemListNodeEntry {
case let .post(_, _, _, _, message, interactions):
return StatsMessageItem(context: arguments.context, presentationData: presentationData, message: message, views: interactions.views, forwards: interactions.forwards, sectionId: self.section, style: .blocks, action: {
arguments.openMessageStats(message.id)
}, contextAction: { node, gesture in
arguments.contextAction(message.id, node, gesture)
})
}
}
@ -407,6 +413,7 @@ private func channelStatsControllerEntries(data: ChannelStats?, messages: [Messa
public func channelStatsController(context: AccountContext, peerId: PeerId, cachedPeerData: CachedPeerData) -> ViewController {
var openMessageStatsImpl: ((MessageId) -> Void)?
var contextActionImpl: ((MessageId, ASDisplayNode, ContextGesture?) -> Void)?
let actionsDisposable = DisposableSet()
let dataPromise = Promise<ChannelStats?>(nil)
@ -440,6 +447,8 @@ public func channelStatsController(context: AccountContext, peerId: PeerId, cach
return statsContext.loadDetailedGraph(graph, x: x)
}, openMessage: { messageId in
openMessageStatsImpl?(messageId)
}, contextAction: { messageId, node, gesture in
contextActionImpl?(messageId, node, gesture)
})
let messageView = context.account.viewTracker.aroundMessageHistoryViewForLocation(.peer(peerId), index: .upperBound, anchorIndex: .upperBound, count: 100, fixedCombinedReadStates: nil)
@ -496,9 +505,49 @@ public func channelStatsController(context: AccountContext, peerId: PeerId, cach
controller?.clearItemNodesHighlight(animated: true)
}
openMessageStatsImpl = { [weak controller] messageId in
if let navigationController = controller?.navigationController as? NavigationController {
controller?.push(messageStatsController(context: context, messageId: messageId, cachedPeerData: cachedPeerData))
controller?.push(messageStatsController(context: context, messageId: messageId, cachedPeerData: cachedPeerData))
}
contextActionImpl = { [weak controller] messageId, sourceNode, gesture in
guard let controller = controller, let sourceNode = sourceNode as? ContextExtractedContentContainingNode else {
return
}
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
var items: [ContextMenuItem] = []
items.append(.action(ContextMenuActionItem(text: presentationData.strings.SharedMedia_ViewInChat, icon: { theme in generateTintedImage(image: UIImage(bundleImageName: "Chat/Context Menu/GoToMessage"), color: theme.contextMenu.primaryColor) }, action: { [weak controller] c, _ in
c.dismiss(completion: {
if let navigationController = controller?.navigationController as? NavigationController {
context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: context, chatLocation: .peer(peerId), subject: .message(id: messageId, highlight: true)))
}
})
})))
let contextController = ContextController(account: context.account, presentationData: presentationData, source: .extracted(ChannelStatsContextExtractedContentSource(controller: controller, sourceNode: sourceNode, keepInPlace: false)), items: .single(items), reactionItems: [], gesture: gesture)
controller.presentInGlobalOverlay(contextController)
}
return controller
}
private final class ChannelStatsContextExtractedContentSource: ContextExtractedContentSource {
var keepInPlace: Bool
let ignoreContentTouches: Bool = true
let blurBackground: Bool = true
private let controller: ViewController
private let sourceNode: ContextExtractedContentContainingNode
init(controller: ViewController, sourceNode: ContextExtractedContentContainingNode, keepInPlace: Bool) {
self.controller = controller
self.sourceNode = sourceNode
self.keepInPlace = keepInPlace
}
func takeView() -> ContextControllerTakeViewInfo? {
return ContextControllerTakeViewInfo(contentContainingNode: self.sourceNode, contentAreaInScreenSpace: UIScreen.main.bounds)
}
func putBack() -> ContextControllerPutBackViewInfo? {
return ContextControllerPutBackViewInfo(contentAreaInScreenSpace: UIScreen.main.bounds)
}
}

@ -22,8 +22,9 @@ public class StatsMessageItem: ListViewItem, ItemListItem {
public let sectionId: ItemListSectionId
let style: ItemListStyle
let action: (() -> Void)?
let contextAction: ((ASDisplayNode, ContextGesture?) -> Void)?
init(context: AccountContext, presentationData: ItemListPresentationData, message: Message, views: Int32, forwards: Int32, sectionId: ItemListSectionId, style: ItemListStyle, action: (() -> Void)?) {
init(context: AccountContext, presentationData: ItemListPresentationData, message: Message, views: Int32, forwards: Int32, sectionId: ItemListSectionId, style: ItemListStyle, action: (() -> Void)?, contextAction: ((ASDisplayNode, ContextGesture?) -> Void)?) {
self.context = context
self.presentationData = presentationData
self.message = message
@ -32,6 +33,7 @@ public class StatsMessageItem: ListViewItem, ItemListItem {
self.sectionId = sectionId
self.style = style
self.action = action
self.contextAction = contextAction
}
public func nodeConfiguredForParams(async: @escaping (@escaping () -> Void) -> Void, params: ListViewItemLayoutParams, synchronousLoads: Bool, previousItem: ListViewItem?, nextItem: ListViewItem?, completion: @escaping (ListViewItemNode, @escaping () -> (Signal<Void, NoError>?, (ListViewItemApply) -> Void)) -> Void) {
@ -88,6 +90,8 @@ public class StatsMessageItemNode: ListViewItemNode, ItemListItemNode {
let contextSourceNode: ContextExtractedContentContainingNode
private let containerNode: ContextControllerSourceNode
private let extractedBackgroundImageNode: ASImageNode
private let offsetContainerNode: ASDisplayNode
private let countersContainerNode: ASDisplayNode
private var extractedRect: CGRect?
private var nonExtractedRect: CGRect?
@ -134,6 +138,9 @@ public class StatsMessageItemNode: ListViewItemNode, ItemListItemNode {
self.contentImageNode = TransformImageNode()
self.contentImageNode.isLayerBacked = true
self.offsetContainerNode = ASDisplayNode()
self.countersContainerNode = ASDisplayNode()
self.titleNode = TextNode()
self.titleNode.isUserInteractionEnabled = false
@ -153,13 +160,56 @@ public class StatsMessageItemNode: ListViewItemNode, ItemListItemNode {
super.init(layerBacked: false, dynamicBounce: false)
self.addSubnode(self.contentImageNode)
self.addSubnode(self.titleNode)
self.addSubnode(self.labelNode)
self.addSubnode(self.viewsNode)
self.addSubnode(self.forwardsNode)
self.containerNode.addSubnode(self.contextSourceNode)
self.containerNode.targetNodeForActivationProgress = self.contextSourceNode.contentNode
self.addSubnode(self.containerNode)
self.contextSourceNode.contentNode.addSubnode(self.extractedBackgroundImageNode)
self.contextSourceNode.contentNode.addSubnode(self.offsetContainerNode)
self.contextSourceNode.contentNode.addSubnode(self.countersContainerNode)
self.offsetContainerNode.addSubnode(self.contentImageNode)
self.offsetContainerNode.addSubnode(self.titleNode)
self.offsetContainerNode.addSubnode(self.labelNode)
self.countersContainerNode.addSubnode(self.viewsNode)
self.countersContainerNode.addSubnode(self.forwardsNode)
self.containerNode.targetNodeForActivationProgress = self.contextSourceNode.contentNode
self.addSubnode(self.activateArea)
self.containerNode.activated = { [weak self] gesture, _ in
guard let strongSelf = self, let item = strongSelf.item, let contextAction = item.contextAction else {
gesture.cancel()
return
}
contextAction(strongSelf.contextSourceNode, gesture)
}
self.contextSourceNode.willUpdateIsExtractedToContextPreview = { [weak self] isExtracted, transition in
guard let strongSelf = self, let item = strongSelf.item else {
return
}
if isExtracted {
strongSelf.extractedBackgroundImageNode.image = generateStretchableFilledCircleImage(diameter: 28.0, color: item.presentationData.theme.list.itemBlocksBackgroundColor)
}
if let extractedRect = strongSelf.extractedRect, let nonExtractedRect = strongSelf.nonExtractedRect {
let rect = isExtracted ? extractedRect : nonExtractedRect
transition.updateFrame(node: strongSelf.extractedBackgroundImageNode, frame: rect)
}
transition.updateAlpha(node: strongSelf.countersContainerNode, alpha: isExtracted ? 0.0 : 1.0)
transition.updateSublayerTransformOffset(layer: strongSelf.countersContainerNode.layer, offset: CGPoint(x: isExtracted ? -24.0 : 0.0, y: 0.0))
transition.updateSublayerTransformOffset(layer: strongSelf.offsetContainerNode.layer, offset: CGPoint(x: isExtracted ? 12.0 : 0.0, y: 0.0))
transition.updateAlpha(node: strongSelf.extractedBackgroundImageNode, alpha: isExtracted ? 1.0 : 0.0, completion: { _ in
if !isExtracted {
self?.extractedBackgroundImageNode.image = nil
}
})
}
}
public func asyncLayout() -> (_ item: StatsMessageItem, _ params: ListViewItemLayoutParams, _ insets: ItemListNeighbors) -> (ListViewItemNodeLayout, () -> Void) {
@ -271,6 +321,25 @@ public class StatsMessageItemNode: ListViewItemNode, ItemListItemNode {
if let strongSelf = self {
strongSelf.item = item
let nonExtractedRect = CGRect(origin: CGPoint(), size: CGSize(width: layout.contentSize.width - 16.0, height: layout.contentSize.height))
let extractedRect = CGRect(origin: CGPoint(), size: layout.contentSize).insetBy(dx: 16.0 + params.leftInset, dy: 0.0)
strongSelf.extractedRect = extractedRect
strongSelf.nonExtractedRect = nonExtractedRect
if strongSelf.contextSourceNode.isExtractedToContextPreview {
strongSelf.extractedBackgroundImageNode.frame = extractedRect
} else {
strongSelf.extractedBackgroundImageNode.frame = nonExtractedRect
}
strongSelf.contextSourceNode.contentRect = extractedRect
strongSelf.containerNode.frame = CGRect(origin: CGPoint(), size: layout.contentSize)
strongSelf.contextSourceNode.frame = CGRect(origin: CGPoint(), size: layout.contentSize)
strongSelf.offsetContainerNode.frame = CGRect(origin: CGPoint(), size: layout.contentSize)
strongSelf.countersContainerNode.frame = CGRect(origin: CGPoint(), size: layout.contentSize)
strongSelf.contextSourceNode.contentNode.frame = CGRect(origin: CGPoint(), size: layout.contentSize)
strongSelf.containerNode.isGestureEnabled = item.contextAction != nil
strongSelf.activateArea.frame = CGRect(origin: CGPoint(x: params.leftInset, y: 0.0), size: CGSize(width: params.width - params.leftInset - params.rightInset, height: layout.contentSize.height))
strongSelf.activateArea.accessibilityLabel = text
strongSelf.activateArea.accessibilityValue = label

@ -659,7 +659,9 @@ public final class VoiceChatController: ViewController {
self.context = call.accountContext
self.call = call
self.presentationData = sharedContext.currentPresentationData.with { $0 }
let presentationData = sharedContext.currentPresentationData.with { $0 }
self.presentationData = presentationData
self.darkTheme = defaultDarkColorPresentationTheme
self.currentSubtitle = self.presentationData.strings.SocksProxySetup_ProxyStatusConnecting
@ -681,6 +683,9 @@ public final class VoiceChatController: ViewController {
self.listNode.verticalScrollIndicatorColor = UIColor(white: 1.0, alpha: 0.3)
self.listNode.clipsToBounds = true
self.listNode.scroller.bounces = false
self.listNode.accessibilityPageScrolledString = { row, count in
return presentationData.strings.VoiceOver_ScrollStatus(row, count).0
}
self.topPanelNode = ASDisplayNode()
self.topPanelNode.clipsToBounds = false

File diff suppressed because it is too large Load Diff

@ -150,13 +150,17 @@ final class ChatHistorySearchContainerNode: SearchDisplayControllerContentNode {
init(context: AccountContext, peerId: PeerId, tagMask: MessageTags, interfaceInteraction: ChatControllerInteraction) {
self.context = context
self.presentationData = context.sharedContext.currentPresentationData.with { $0 }
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
self.presentationData = presentationData
self.themeAndStringsPromise = Promise((self.presentationData.theme, self.presentationData.strings, self.presentationData.dateTimeFormat, self.presentationData.listsFontSize))
self.dimNode = ASDisplayNode()
self.dimNode.backgroundColor = UIColor.black.withAlphaComponent(0.5)
self.listNode = ListView()
self.listNode.accessibilityPageScrolledString = { row, count in
return presentationData.strings.VoiceOver_ScrollStatus(row, count).0
}
self.emptyResultsTitleNode = ImmediateTextNode()
self.emptyResultsTitleNode.attributedText = NSAttributedString(string: self.presentationData.strings.SharedMedia_SearchNoResults, font: Font.semibold(17.0), textColor: self.presentationData.theme.list.freeTextColor)

@ -493,10 +493,16 @@ final class ChatMediaInputNode: ChatInputNode {
self.listView = ListView()
self.listView.transform = CATransform3DMakeRotation(-CGFloat(Double.pi / 2.0), 0.0, 0.0, 1.0)
self.listView.scroller.panGestureRecognizer.cancelsTouchesInView = false
self.listView.accessibilityPageScrolledString = { row, count in
return strings.VoiceOver_ScrollStatus(row, count).0
}
self.gifListView = ListView()
self.gifListView.transform = CATransform3DMakeRotation(-CGFloat(Double.pi / 2.0), 0.0, 0.0, 1.0)
self.gifListView.scroller.panGestureRecognizer.cancelsTouchesInView = false
self.gifListView.accessibilityPageScrolledString = { row, count in
return strings.VoiceOver_ScrollStatus(row, count).0
}
var paneDidScrollImpl: ((ChatMediaInputPane, ChatMediaInputPaneScrollState, ContainedViewLayoutTransition) -> Void)?
var fixPaneScrollImpl: ((ChatMediaInputPane, ChatMediaInputPaneScrollState) -> Void)?

@ -110,6 +110,10 @@ final class ChatRecentActionsControllerNode: ViewControllerTracingNode {
self.listNode = ListView()
self.listNode.dynamicBounceEnabled = !self.presentationData.disableAnimations
self.listNode.transform = CATransform3DMakeRotation(CGFloat(Double.pi), 0.0, 0.0, 1.0)
self.listNode.accessibilityPageScrolledString = { row, count in
return presentationData.strings.VoiceOver_ScrollStatus(row, count).0
}
self.loadingNode = ChatLoadingNode(theme: self.presentationData.theme, chatWallpaper: self.presentationData.chatWallpaper, bubbleCorners: self.presentationData.chatBubbleCorners)
self.emptyNode = ChatRecentActionsEmptyNode(theme: self.presentationData.theme, chatWallpaper: self.presentationData.chatWallpaper, chatBubbleCorners: self.presentationData.chatBubbleCorners)
self.emptyNode.alpha = 0.0

@ -137,11 +137,16 @@ class ChatSearchResultsControllerNode: ViewControllerTracingNode, UIScrollViewDe
self.searchQuery = searchQuery
self.searchResult = searchResult
self.searchState = searchState
self.presentationData = context.sharedContext.currentPresentationData.with { $0 }
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
self.presentationData = presentationData
self.presentationDataPromise = Promise(ChatListPresentationData(theme: self.presentationData.theme, fontSize: self.presentationData.listsFontSize, strings: self.presentationData.strings, dateTimeFormat: self.presentationData.dateTimeFormat, nameSortOrder: self.presentationData.nameSortOrder, nameDisplayOrder: self.presentationData.nameDisplayOrder, disableAnimations: self.presentationData.disableAnimations))
self.listNode = ListView()
self.listNode.verticalScrollIndicatorColor = self.presentationData.theme.list.scrollIndicatorColor
self.listNode.accessibilityPageScrolledString = { row, count in
return presentationData.strings.VoiceOver_ScrollStatus(row, count).0
}
super.init()

@ -70,6 +70,9 @@ final class CommandChatInputContextPanelNode: ChatInputContextPanelNode {
self.listView.keepBottomItemOverscrollBackground = theme.list.plainBackgroundColor
self.listView.limitHitTestToNodes = true
self.listView.view.disablesInteractiveTransitionGestureRecognizer = true
self.listView.accessibilityPageScrolledString = { row, count in
return strings.VoiceOver_ScrollStatus(row, count).0
}
super.init(context: context, theme: theme, strings: strings, fontSize: fontSize)

@ -100,7 +100,8 @@ private final class DrawingStickersScreenNode: ViewControllerTracingNode {
init(context: AccountContext, selectSticker: ((FileMediaReference, ASDisplayNode, CGRect) -> Bool)?) {
self.context = context
self.presentationData = context.sharedContext.currentPresentationData.with { $0 }
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
self.presentationData = presentationData
self.selectSticker = selectSticker
self.themeAndStringsPromise = Promise((self.presentationData.theme, self.presentationData.strings))
@ -179,9 +180,15 @@ private final class DrawingStickersScreenNode: ViewControllerTracingNode {
self.stickerListView = ListView()
self.stickerListView.transform = CATransform3DMakeRotation(-CGFloat(Double.pi / 2.0), 0.0, 0.0, 1.0)
self.stickerListView.accessibilityPageScrolledString = { row, count in
return presentationData.strings.VoiceOver_ScrollStatus(row, count).0
}
self.maskListView = ListView()
self.maskListView.transform = CATransform3DMakeRotation(-CGFloat(Double.pi / 2.0), 0.0, 0.0, 1.0)
self.maskListView.accessibilityPageScrolledString = { row, count in
return presentationData.strings.VoiceOver_ScrollStatus(row, count).0
}
self.topSeparatorNode = ASDisplayNode()
self.topSeparatorNode.backgroundColor = UIColor(rgb: 0x2c2d2d)

@ -130,6 +130,9 @@ final class EmojisChatInputContextPanelNode: ChatInputContextPanelNode {
self.listView.isOpaque = false
self.listView.view.disablesInteractiveTransitionGestureRecognizer = true
self.listView.transform = CATransform3DMakeRotation(-CGFloat.pi / 2.0, 0.0, 0.0, 1.0)
self.listView.accessibilityPageScrolledString = { row, count in
return strings.VoiceOver_ScrollStatus(row, count).0
}
super.init(context: context, theme: theme, strings: strings, fontSize: fontSize)

@ -76,6 +76,9 @@ final class HashtagChatInputContextPanelNode: ChatInputContextPanelNode {
self.listView.keepBottomItemOverscrollBackground = theme.list.plainBackgroundColor
self.listView.limitHitTestToNodes = true
self.listView.view.disablesInteractiveTransitionGestureRecognizer = true
self.listView.accessibilityPageScrolledString = { row, count in
return strings.VoiceOver_ScrollStatus(row, count).0
}
super.init(context: context, theme: theme, strings: strings, fontSize: fontSize)

@ -101,6 +101,9 @@ final class HorizontalListContextResultsChatInputContextPanelNode: ChatInputCont
self.listView.backgroundColor = theme.list.plainBackgroundColor
self.listView.transform = CATransform3DMakeRotation(-CGFloat(CGFloat.pi / 2.0), 0.0, 0.0, 1.0)
self.listView.isHidden = true
self.listView.accessibilityPageScrolledString = { row, count in
return strings.VoiceOver_ScrollStatus(row, count).0
}
super.init(context: context, theme: theme, strings: strings, fontSize: fontSize)

@ -77,6 +77,9 @@ final class MentionChatInputContextPanelNode: ChatInputContextPanelNode {
self.listView.keepBottomItemOverscrollBackground = theme.list.plainBackgroundColor
self.listView.limitHitTestToNodes = true
self.listView.view.disablesInteractiveTransitionGestureRecognizer = true
self.listView.accessibilityPageScrolledString = { row, count in
return strings.VoiceOver_ScrollStatus(row, count).0
}
super.init(context: context, theme: theme, strings: strings, fontSize: fontSize)

@ -88,7 +88,11 @@ final class PeerInfoGroupsInCommonPaneNode: ASDisplayNode, PeerInfoPaneNode {
self.openPeerContextAction = openPeerContextAction
self.groupsInCommonContext = groupsInCommonContext
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
self.listNode = ListView()
self.listNode.accessibilityPageScrolledString = { row, count in
return presentationData.strings.VoiceOver_ScrollStatus(row, count).0
}
super.init()

@ -129,7 +129,11 @@ final class PeerInfoMembersPaneNode: ASDisplayNode, PeerInfoPaneNode {
self.membersContext = membersContext
self.action = action
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
self.listNode = ListView()
self.listNode.accessibilityPageScrolledString = { row, count in
return presentationData.strings.VoiceOver_ScrollStatus(row, count).0
}
super.init()

@ -90,6 +90,9 @@ final class StickersChatInputContextPanelNode: ChatInputContextPanelNode {
self.listView.keepBottomItemOverscrollBackground = theme.list.plainBackgroundColor
self.listView.limitHitTestToNodes = true
self.listView.view.disablesInteractiveTransitionGestureRecognizer = true
self.listView.accessibilityPageScrolledString = { row, count in
return strings.VoiceOver_ScrollStatus(row, count).0
}
self.stickersInteraction = StickersChatInputContextPanelInteraction()

@ -141,6 +141,9 @@ final class VerticalListContextResultsChatInputContextPanelNode: ChatInputContex
self.listView.limitHitTestToNodes = true
self.listView.isHidden = true
self.listView.view.disablesInteractiveTransitionGestureRecognizer = true
self.listView.accessibilityPageScrolledString = { row, count in
return strings.VoiceOver_ScrollStatus(row, count).0
}
super.init(context: context, theme: theme, strings: strings, fontSize: fontSize)

@ -218,6 +218,9 @@ class WebSearchControllerNode: ASDisplayNode {
self.recentQueriesNode = ListView()
self.recentQueriesNode.backgroundColor = theme.list.plainBackgroundColor
self.recentQueriesNode.accessibilityPageScrolledString = { row, count in
return presentationData.strings.VoiceOver_ScrollStatus(row, count).0
}
super.init()