Various fixes

This commit is contained in:
Ilya Laktyushin 2023-02-07 21:41:49 +04:00
parent 2ef1de9a8c
commit f800936080
29 changed files with 265 additions and 371 deletions

View File

@ -8906,3 +8906,5 @@ Sorry for the inconvenience.";
"Gallery.VoiceOver.Edit" = "Edit";
"Gallery.VoiceOver.Stickers" = "Stickers";
"Gallery.VoiceOver.PictureInPicture" = "Picture-in-Picture";
"Appearance.VoiceOver.Theme" = "%@ Theme";

View File

@ -757,6 +757,8 @@ final class AttachmentPanel: ASDisplayNode, UIScrollViewDelegate {
self.scrollNode.view.delegate = self
self.scrollNode.view.showsHorizontalScrollIndicator = false
self.scrollNode.view.showsVerticalScrollIndicator = false
self.view.accessibilityTraits = .tabBar
}
@objc private func buttonPressed() {

View File

@ -76,9 +76,7 @@ private final class ItemNode: ASDisplayNode {
private var deleteButtonNode: ItemNodeDeleteButtonNode?
private let buttonNode: HighlightTrackingButtonNode
private let activateArea: AccessibilityAreaNode
private var selectionFraction: CGFloat = 0.0
private(set) var unreadCount: Int = 0
@ -140,13 +138,9 @@ private final class ItemNode: ASDisplayNode {
self.badgeBackgroundInactiveNode.displayWithoutProcessing = true
self.buttonNode = HighlightTrackingButtonNode()
self.activateArea = AccessibilityAreaNode()
super.init()
self.isAccessibilityElement = true
self.extractedContainerNode.contentNode.addSubnode(self.extractedBackgroundNode)
self.extractedContainerNode.contentNode.addSubnode(self.titleContainer)
self.titleContainer.addSubnode(self.titleNode)
@ -163,9 +157,7 @@ private final class ItemNode: ASDisplayNode {
self.containerNode.addSubnode(self.extractedContainerNode)
self.containerNode.targetNodeForActivationProgress = self.extractedContainerNode.contentNode
self.addSubnode(self.containerNode)
self.addSubnode(self.activateArea)
self.buttonNode.addTarget(self, action: #selector(self.buttonPressed), forControlEvents: .touchUpInside)
self.containerNode.activated = { [weak self] gesture, _ in
@ -212,11 +204,16 @@ private final class ItemNode: ASDisplayNode {
self.badgeBackgroundInactiveNode.image = generateStretchableFilledCircleImage(diameter: 18.0, color: presentationData.theme.chatList.unreadBadgeInactiveBackgroundColor)
}
self.activateArea.accessibilityLabel = title
self.buttonNode.accessibilityLabel = title
if unreadCount > 0 {
self.activateArea.accessibilityValue = strings.VoiceOver_Chat_UnreadMessages(Int32(unreadCount))
self.buttonNode.accessibilityValue = strings.VoiceOver_Chat_UnreadMessages(Int32(unreadCount))
} else {
self.activateArea.accessibilityValue = ""
self.buttonNode.accessibilityValue = ""
}
if selectionFraction == 1.0 {
self.buttonNode.accessibilityTraits = [.button, .selected]
} else {
self.buttonNode.accessibilityTraits = [.button]
}
self.containerNode.isGestureEnabled = !isEditing && !isReordering
@ -338,7 +335,6 @@ private final class ItemNode: ASDisplayNode {
self.extractedContainerNode.contentNode.frame = CGRect(origin: CGPoint(), size: size)
self.extractedContainerNode.contentRect = CGRect(origin: CGPoint(x: self.extractedBackgroundNode.frame.minX, y: 0.0), size: CGSize(width:self.extractedBackgroundNode.frame.width, height: size.height))
self.containerNode.frame = CGRect(origin: CGPoint(), size: size)
self.activateArea.frame = CGRect(origin: CGPoint(), size: size)
self.hitTestSlop = UIEdgeInsets(top: 0.0, left: -sideInset, bottom: 0.0, right: -sideInset)
self.extractedContainerNode.hitTestSlop = self.hitTestSlop

View File

@ -126,6 +126,13 @@ private final class ItemNode: ASDisplayNode {
transition.updateAlpha(node: self.titleNode, alpha: deselectionAlpha)
transition.updateAlpha(node: self.titleActiveNode, alpha: selectionAlpha)
self.buttonNode.accessibilityLabel = title
if selectionFraction == 1.0 {
self.buttonNode.accessibilityTraits = [.button, .selected]
} else {
self.buttonNode.accessibilityTraits = [.button]
}
if self.theme !== presentationData.theme {
self.theme = presentationData.theme
self.iconNode.image = icon

View File

@ -1861,6 +1861,9 @@ public final class ChatListNode: ListView {
return false
}
}
case .GroupReferenceEntry:
isEmpty = false
return true
default:
return true
}

View File

@ -686,9 +686,9 @@ func chatListNodeEntriesForView(_ view: EngineChatList, state: ChatListNodeState
} else if case let .peerType(type) = mode, !result.isEmpty {
switch type {
case .group:
result.append(.AdditionalCategory(index: 0, id: 0, title: "Create a New Group for This", image: PresentationResourcesItemList.createGroupIcon(state.presentationData.theme), appearance: .action, selected: false, presentationData: state.presentationData))
result.append(.AdditionalCategory(index: 0, id: 0, title: state.presentationData.strings.RequestPeer_CreateNewGroup, image: PresentationResourcesItemList.createGroupIcon(state.presentationData.theme), appearance: .action, selected: false, presentationData: state.presentationData))
case .channel:
result.append(.AdditionalCategory(index: 0, id: 0, title: "Create a New Channel for This", image: PresentationResourcesItemList.createGroupIcon(state.presentationData.theme), appearance: .action, selected: false, presentationData: state.presentationData))
result.append(.AdditionalCategory(index: 0, id: 0, title: state.presentationData.strings.RequestPeer_CreateNewChannel, image: PresentationResourcesItemList.createGroupIcon(state.presentationData.theme), appearance: .action, selected: false, presentationData: state.presentationData))
default:
break
}

View File

@ -103,7 +103,6 @@ public enum ChatInputMode: Equatable {
public enum ChatTitlePanelContext: Equatable, Comparable {
case pinnedMessage
case chatInfo
case requestInProgress
case toastAlert(String)
case inviteRequests([EnginePeer], Int32)
@ -112,8 +111,6 @@ public enum ChatTitlePanelContext: Equatable, Comparable {
switch self {
case .pinnedMessage:
return 0
case .chatInfo:
return 1
case .requestInProgress:
return 2
case .toastAlert:

View File

@ -101,6 +101,7 @@ private final class ContextControllerActionsListActionItemNode: HighlightTrackin
self.isAccessibilityElement = true
self.accessibilityLabel = item.text
self.accessibilityTraits = [.button]
self.addSubnode(self.highlightBackgroundNode)
self.addSubnode(self.titleLabelNode)

View File

@ -8,6 +8,8 @@ public protocol AccessibilityFocusableNode {
public final class AccessibilityAreaNode: ASDisplayNode {
public var activate: (() -> Bool)?
public var increment: (() -> Void)?
public var decrement: (() -> Void)?
public var focused: (() -> Void)?
override public init() {
@ -43,4 +45,12 @@ public final class AccessibilityAreaNode: ASDisplayNode {
}
}
}
override public func accessibilityIncrement() {
self.increment?()
}
override public func accessibilityDecrement() {
self.decrement?()
}
}

View File

@ -697,9 +697,16 @@ open class NavigationBar: ASDisplayNode {
if self.rightButtonNode.supernode != nil {
addAccessibilityChildren(of: self.rightButtonNode, container: self, to: &accessibilityElements)
}
if let customHeaderContentView = self.customHeaderContentView, customHeaderContentView.superview != nil {
customHeaderContentView.accessibilityFrame = UIAccessibility.convertToScreenCoordinates(customHeaderContentView.bounds, in: customHeaderContentView)
accessibilityElements.append(customHeaderContentView)
}
if let contentNode = self.contentNode {
addAccessibilityChildren(of: contentNode, container: self, to: &accessibilityElements)
}
if let secondaryContentNode = self.secondaryContentNode {
addAccessibilityChildren(of: secondaryContentNode, container: self, to: &accessibilityElements)
}
return accessibilityElements
} set(value) {
}

View File

@ -528,4 +528,12 @@ open class GalleryControllerNode: ASDisplayNode, UIScrollViewDelegate, UIGesture
break
}
}
open override func accessibilityPerformEscape() -> Bool {
if let controller = self.galleryController() {
controller.dismiss(animated: true)
return true
}
return false
}
}

View File

@ -43,6 +43,12 @@
- (void)setValue:(CGFloat)value animated:(BOOL)animated;
- (void)increase;
- (void)increaseBy:(CGFloat)delta;
- (void)decrease;
- (void)decreaseBy:(CGFloat)delta;
@end
extern const CGFloat TGPhotoEditorSliderViewMargin;

View File

@ -668,4 +668,32 @@ const CGFloat TGPhotoEditorSliderViewInternalMargin = 7.0f;
self.interactionEnded();
}
- (void)increase {
self.value = MIN(self.maximumValue, self.value + 1);
[self sendActionsForControlEvents:UIControlEventValueChanged];
[self setNeedsLayout];
}
- (void)increaseBy:(CGFloat)delta {
self.value = MIN(self.maximumValue, self.value + delta);
[self sendActionsForControlEvents:UIControlEventValueChanged];
[self setNeedsLayout];
}
- (void)decrease {
self.value = MAX(self.minimumValue, self.value - 1);
[self sendActionsForControlEvents:UIControlEventValueChanged];
[self setNeedsLayout];
}
- (void)decreaseBy:(CGFloat)delta {
self.value = MAX(self.minimumValue, self.value - delta);
[self sendActionsForControlEvents:UIControlEventValueChanged];
[self setNeedsLayout];
}
@end

View File

@ -55,7 +55,7 @@ final class HelloView: UIView, PhoneDemoDecorationView {
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
func setupAnimations() {
guard self.activePhrases.isEmpty else {
return
@ -121,11 +121,13 @@ final class HelloView: UIView, PhoneDemoDecorationView {
self.activePositions.insert(positionIndex)
let duration: Double = Double.random(in: 1.75...2.25)
view.layer.animateKeyframes(values: [0.0, 1.0, 0.0] as [NSNumber], duration: duration, keyPath: "opacity", removeOnCompletion: false, completion: { [weak view] _ in
self.activePhrases.remove(index)
self.activePositions.remove(positionIndex)
view?.removeFromSuperview()
self.spawnNextPhrase()
view.layer.animateKeyframes(values: [0.0, 1.0, 0.0] as [NSNumber], duration: duration, keyPath: "opacity", removeOnCompletion: false, completion: { [weak view, weak self] _ in
if let self {
self.activePhrases.remove(index)
self.activePositions.remove(positionIndex)
view?.removeFromSuperview()
self.spawnNextPhrase()
}
})
view.layer.animateScale(from: CGFloat.random(in: 0.4 ..< 0.6), to: CGFloat.random(in: 0.9 ..< 1.2), duration: duration, removeOnCompletion: false)

View File

@ -429,6 +429,9 @@ private final class BubbleSettingsToolbarNode: ASDisplayNode {
super.init()
self.cancelButton.accessibilityTraits = [.button]
self.doneButton.accessibilityTraits = [.button]
self.addSubnode(self.switchItemNode)
self.addSubnode(self.cornerRadiusItemNode)
self.addSubnode(self.cancelButton)
@ -482,6 +485,9 @@ private final class BubbleSettingsToolbarNode: ASDisplayNode {
self.cancelButton.setTitle(presentationData.strings.Common_Cancel, with: Font.regular(17.0), with: presentationData.theme.list.itemPrimaryTextColor, for: [])
self.doneButton.setTitle(presentationData.strings.Wallpaper_Set, with: Font.regular(17.0), with: presentationData.theme.list.itemPrimaryTextColor, for: [])
self.cancelButton.accessibilityLabel = presentationData.strings.Common_Cancel
self.doneButton.accessibilityLabel = presentationData.strings.Wallpaper_Set
}
func updatePresentationThemeSettings(presentationThemeSettings: PresentationThemeSettings) {

View File

@ -95,6 +95,8 @@ private final class AutodownloadDataUsagePickerItemNode: ListViewItemNode {
private let customTextNode: TextNode
private var sliderView: TGPhotoEditorSliderView?
private let activateArea: AccessibilityAreaNode
private var item: AutodownloadDataUsagePickerItem?
private var layoutParams: ListViewItemLayoutParams?
@ -126,12 +128,27 @@ private final class AutodownloadDataUsagePickerItemNode: ListViewItemNode {
self.customTextNode.isUserInteractionEnabled = false
self.customTextNode.displaysAsynchronously = false
self.activateArea = AccessibilityAreaNode()
super.init(layerBacked: false, dynamicBounce: false)
self.addSubnode(self.lowTextNode)
self.addSubnode(self.mediumTextNode)
self.addSubnode(self.highTextNode)
self.addSubnode(self.customTextNode)
self.addSubnode(self.activateArea)
self.activateArea.increment = { [weak self] in
if let self {
self.sliderView?.increase()
}
}
self.activateArea.decrement = { [weak self] in
if let self {
self.sliderView?.decrease()
}
}
}
func updateSliderView() {
@ -154,6 +171,8 @@ private final class AutodownloadDataUsagePickerItemNode: ListViewItemNode {
sliderView.isUserInteractionEnabled = item.enabled
sliderView.alpha = item.enabled ? 1.0 : 0.4
sliderView.layer.allowsGroupOpacity = !item.enabled
self.updateAccessibilityLabels()
}
}
@ -323,11 +342,33 @@ private final class AutodownloadDataUsagePickerItemNode: ListViewItemNode {
strongSelf.updateSliderView()
}
strongSelf.activateArea.accessibilityLabel = item.strings.AutoDownloadSettings_DataUsage
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))
}
})
}
}
private func updateAccessibilityLabels() {
guard let item = self.item else {
return
}
var textNodes: [TextNode] = [self.lowTextNode, self.mediumTextNode, self.highTextNode]
if let customPosition = item.customPosition {
textNodes.insert(self.customTextNode, at: customPosition)
}
if let value = self.sliderView?.value {
self.activateArea.accessibilityValue = textNodes[Int(value)].cachedLayout?.attributedString?.string ?? ""
}
var accessibilityTraits: UIAccessibilityTraits = [.adjustable]
if item.enabled {
} else {
accessibilityTraits.insert(.notEnabled)
}
self.activateArea.accessibilityTraits = accessibilityTraits
}
override func animateInsertion(_ currentTimestamp: Double, duration: Double, short: Bool) {
self.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.4)
}

View File

@ -135,6 +135,8 @@ class ItemListWebsiteItemNode: ItemListRevealOptionsItemNode {
return self.containerNode
}
private let activateArea: AccessibilityAreaNode
private var layoutParams: (ItemListWebsiteItem, ListViewItemLayoutParams, ItemListNeighbors)?
private var editableControlNode: ItemListEditableControlNode?
@ -184,6 +186,8 @@ class ItemListWebsiteItemNode: ItemListRevealOptionsItemNode {
self.highlightedBackgroundNode = ASDisplayNode()
self.highlightedBackgroundNode.isLayerBacked = true
self.activateArea = AccessibilityAreaNode()
super.init(layerBacked: false, dynamicBounce: false, rotated: false, seeThrough: false)
self.addSubnode(self.containerNode)
@ -191,6 +195,8 @@ class ItemListWebsiteItemNode: ItemListRevealOptionsItemNode {
self.containerNode.addSubnode(self.titleNode)
self.containerNode.addSubnode(self.appNode)
self.containerNode.addSubnode(self.locationNode)
self.addSubnode(self.activateArea)
}
func asyncLayout() -> (_ item: ItemListWebsiteItem, _ params: ListViewItemLayoutParams, _ neighbors: ItemListNeighbors) -> (ListViewItemNodeLayout, (Bool) -> Void) {
@ -288,6 +294,28 @@ class ItemListWebsiteItemNode: ItemListRevealOptionsItemNode {
if let strongSelf = self {
strongSelf.layoutParams = (item, params, neighbors)
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 = titleAttributedString?.string ?? ""
var value = ""
if let string = appAttributedString?.string {
value += string
}
if let string = locationAttributedString?.string {
if !value.isEmpty {
value += "\n"
}
value += string
}
strongSelf.activateArea.accessibilityValue = value
if item.enabled {
strongSelf.activateArea.accessibilityTraits = []
} else {
strongSelf.activateArea.accessibilityTraits = .notEnabled
}
if let _ = updatedTheme {
strongSelf.topStripeNode.backgroundColor = item.presentationData.theme.list.itemBlocksSeparatorColor
strongSelf.bottomStripeNode.backgroundColor = item.presentationData.theme.list.itemBlocksSeparatorColor

View File

@ -716,6 +716,9 @@ private final class TextSelectionToolbarNode: ASDisplayNode {
super.init()
self.cancelButton.accessibilityTraits = [.button]
self.doneButton.accessibilityTraits = [.button]
self.addSubnode(self.switchItemNode)
self.addSubnode(self.fontSizeItemNode)
self.addSubnode(self.cancelButton)
@ -769,6 +772,9 @@ private final class TextSelectionToolbarNode: ASDisplayNode {
self.cancelButton.setTitle(presentationData.strings.Common_Cancel, with: Font.regular(17.0), with: presentationData.theme.list.itemPrimaryTextColor, for: [])
self.doneButton.setTitle(presentationData.strings.Wallpaper_Set, with: Font.regular(17.0), with: presentationData.theme.list.itemPrimaryTextColor, for: [])
self.cancelButton.accessibilityLabel = presentationData.strings.Common_Cancel
self.doneButton.accessibilityLabel = presentationData.strings.Wallpaper_Set
}
func updatePresentationThemeSettings(presentationThemeSettings: PresentationThemeSettings) {

View File

@ -203,6 +203,8 @@ private final class ThemeCarouselThemeItemIconNode : ListViewItemNode {
private var placeholderNode: StickerShimmerEffectNode
var snapshotView: UIView?
private let activateAreaNode: AccessibilityAreaNode
var item: ThemeCarouselThemeIconItem?
override var visibility: ListViewItemNodeVisibility {
@ -246,6 +248,8 @@ private final class ThemeCarouselThemeItemIconNode : ListViewItemNode {
self.emojiImageNode = TransformImageNode()
self.placeholderNode = StickerShimmerEffectNode()
self.activateAreaNode = AccessibilityAreaNode()
super.init(layerBacked: false, dynamicBounce: false, rotated: false, seeThrough: false)
@ -272,6 +276,8 @@ private final class ThemeCarouselThemeItemIconNode : ListViewItemNode {
}
firstTime = false
}
self.addSubnode(self.activateAreaNode)
}
deinit {
@ -442,6 +448,16 @@ private final class ThemeCarouselThemeItemIconNode : ListViewItemNode {
animatedStickerNode.frame = emojiFrame
animatedStickerNode.updateLayout(size: emojiFrame.size)
}
let presentationData = item.context.sharedContext.currentPresentationData.with { $0 }
strongSelf.activateAreaNode.accessibilityLabel = item.themeReference.emoticon.flatMap { presentationData.strings.Appearance_VoiceOver_Theme($0).string }
if item.selected {
strongSelf.activateAreaNode.accessibilityTraits = [.button, .selected]
} else {
strongSelf.activateAreaNode.accessibilityTraits = [.button]
}
strongSelf.activateAreaNode.frame = CGRect(origin: .zero, size: itemLayout.size)
}
})
}

View File

@ -102,6 +102,8 @@ private final class ThemeSettingsAppIconNode : ASDisplayNode {
private let textNode: ImmediateTextNode
private var action: (() -> Void)?
private let activateAreaNode: AccessibilityAreaNode
private var locked = false
override init() {
@ -122,12 +124,16 @@ private final class ThemeSettingsAppIconNode : ASDisplayNode {
self.textNode.isUserInteractionEnabled = false
self.textNode.displaysAsynchronously = false
self.activateAreaNode = AccessibilityAreaNode()
self.activateAreaNode.accessibilityTraits = [.button]
super.init()
self.addSubnode(self.iconNode)
self.addSubnode(self.overlayNode)
self.addSubnode(self.textNode)
self.addSubnode(self.lockNode)
self.addSubnode(self.activateAreaNode)
}
func setup(theme: PresentationTheme, icon: UIImage, title: NSAttributedString, locked: Bool, color: UIColor, bordered: Bool, selected: Bool, action: @escaping () -> Void) {
@ -140,6 +146,13 @@ private final class ThemeSettingsAppIconNode : ASDisplayNode {
action()
}
self.activateAreaNode.accessibilityLabel = title.string
if locked {
self.activateAreaNode.accessibilityTraits = [.button, .notEnabled]
} else {
self.activateAreaNode.accessibilityTraits = [.button]
}
self.setNeedsLayout()
}
@ -171,6 +184,8 @@ private final class ThemeSettingsAppIconNode : ASDisplayNode {
self.textNode.frame = textFrame
self.lockNode.frame = CGRect(x: self.textNode.frame.minX - 10.0, y: 90.0, width: 6.0, height: 8.0)
self.activateAreaNode.frame = self.bounds
}
}
@ -186,7 +201,7 @@ class ThemeSettingsAppIconItemNode: ListViewItemNode, ItemListItemNode {
private let scrollNode: ASScrollNode
private var nodes: [ThemeSettingsAppIconNode] = []
private var item: ThemeSettingsAppIconItem?
private var layoutParams: ListViewItemLayoutParams?

View File

@ -207,6 +207,8 @@ private final class ThemeSettingsThemeItemIconNode : ListViewItemNode {
private let titleNode: TextNode
var snapshotView: UIView?
private let activateAreaNode: AccessibilityAreaNode
var item: ThemeSettingsThemeIconItem?
init() {
@ -222,13 +224,17 @@ private final class ThemeSettingsThemeItemIconNode : ListViewItemNode {
self.titleNode = TextNode()
self.titleNode.isUserInteractionEnabled = false
self.activateAreaNode = AccessibilityAreaNode()
super.init(layerBacked: false, dynamicBounce: false, rotated: false, seeThrough: false)
self.addSubnode(self.containerNode)
self.containerNode.addSubnode(self.imageNode)
self.containerNode.addSubnode(self.overlayNode)
self.containerNode.addSubnode(self.titleNode)
self.addSubnode(self.activateAreaNode)
self.containerNode.activated = { [weak self] gesture, _ in
guard let strongSelf = self, let item = strongSelf.item else {
@ -308,6 +314,15 @@ private final class ThemeSettingsThemeItemIconNode : ListViewItemNode {
strongSelf.overlayNode.frame = CGRect(origin: CGPoint(x: 9.0, y: 13.0), size: CGSize(width: 100.0, height: 64.0))
strongSelf.titleNode.frame = CGRect(origin: CGPoint(x: 0.0, y: 88.0), size: CGSize(width: itemLayout.contentSize.width, height: 16.0))
strongSelf.activateAreaNode.accessibilityLabel = item.title
if item.selected {
strongSelf.activateAreaNode.accessibilityTraits = [.button, .selected]
} else {
strongSelf.activateAreaNode.accessibilityTraits = [.button]
}
strongSelf.activateAreaNode.frame = CGRect(origin: .zero, size: itemLayout.size)
}
})
}

View File

@ -237,6 +237,9 @@ public final class ChatListHeaderComponent: Component {
self.titleView.attributedText = NSAttributedString(string: title, font: Font.regular(17.0), textColor: theme.rootController.navigationBar.accentTextColor)
let titleSize = self.titleView.updateLayout(CGSize(width: 100.0, height: 44.0))
self.accessibilityLabel = title
self.accessibilityTraits = [.button]
if self.currentColor != theme.rootController.navigationBar.accentTextColor {
self.currentColor = theme.rootController.navigationBar.accentTextColor
self.arrowView.image = NavigationBarTheme.generateBackArrowImage(color: theme.rootController.navigationBar.accentTextColor)

View File

@ -4304,36 +4304,6 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
self.chatTitleView = ChatTitleView(context: self.context, theme: self.presentationData.theme, strings: self.presentationData.strings, dateTimeFormat: self.presentationData.dateTimeFormat, nameDisplayOrder: self.presentationData.nameDisplayOrder, animationCache: controllerInteraction.presentationContext.animationCache, animationRenderer: controllerInteraction.presentationContext.animationRenderer)
self.navigationItem.titleView = self.chatTitleView
self.chatTitleView?.pressed = { [weak self] in
if let strongSelf = self {
if strongSelf.chatLocation == .peer(id: strongSelf.context.account.peerId) {
if let peer = strongSelf.presentationInterfaceState.renderedPeer?.chatMainPeer, let infoController = strongSelf.context.sharedContext.makePeerInfoController(context: strongSelf.context, updatedPresentationData: strongSelf.updatedPresentationData, peer: peer, mode: .generic, avatarInitiallyExpanded: false, fromChat: true, requestsContext: nil) {
strongSelf.effectiveNavigationController?.pushViewController(infoController)
}
} else {
strongSelf.updateChatPresentationInterfaceState(animated: true, interactive: true, {
return $0.updatedTitlePanelContext {
if let index = $0.firstIndex(where: {
switch $0 {
case .chatInfo:
return true
default:
return false
}
}) {
var updatedContexts = $0
updatedContexts.remove(at: index)
return updatedContexts
} else {
var updatedContexts = $0
updatedContexts.append(.chatInfo)
return updatedContexts.sorted()
}
}
})
}
}
}
self.chatTitleView?.longPressed = { [weak self] in
if let strongSelf = self, let peerView = strongSelf.peerView, let peer = peerView.peers[peerView.peerId], peer.restrictionText(platform: "ios", contentSettings: strongSelf.context.currentContentSettings.with { $0 }) == nil && !strongSelf.presentationInterfaceState.isNotAccessible {
strongSelf.interfaceInteraction?.beginMessageSearch(.everything, "")
@ -8317,22 +8287,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
}
strongSelf.updateChatPresentationInterfaceState(animated: true, interactive: interactive, { current in
return current.updatedTitlePanelContext {
if let index = $0.firstIndex(where: {
switch $0 {
case .chatInfo:
return true
default:
return false
}
}) {
var updatedContexts = $0
updatedContexts.remove(at: index)
return updatedContexts
} else {
return $0
}
}.updatedSearch(current.search == nil ? ChatSearchData(domain: domain).withUpdatedQuery(query) : current.search?.withUpdatedDomain(domain).withUpdatedQuery(query))
return current.updatedSearch(current.search == nil ? ChatSearchData(domain: domain).withUpdatedQuery(query) : current.search?.withUpdatedDomain(domain).withUpdatedQuery(query))
})
strongSelf.updateItemNodesSearchTextHighlightStates()
})
@ -9613,17 +9568,6 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
guard let strongSelf = self, case let .peer(peerId) = strongSelf.chatLocation else {
return
}
strongSelf.updateChatPresentationInterfaceState(interactive: true, { state in
return state.updatedTitlePanelContext({
$0.filter({ item in
if case .chatInfo = item {
return false
} else {
return true
}
})
})
})
let _ = (strongSelf.context.engine.peers.updatePeersGroupIdInteractively(peerIds: [peerId], groupId: .root)
|> deliverOnMainQueue).start()
}, openLinkEditing: { [weak self] in
@ -11070,30 +11014,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
return interfaceState
}).start()
}
override public func viewDidDisappear(_ animated: Bool) {
super.viewDidDisappear(animated)
self.updateChatPresentationInterfaceState(animated: false, interactive: false, {
$0.updatedTitlePanelContext {
if let index = $0.firstIndex(where: {
switch $0 {
case .chatInfo:
return true
default:
return false
}
}) {
var updatedContexts = $0
updatedContexts.remove(at: index)
return updatedContexts
} else {
return $0
}
}
})
}
override public func viewWillLeaveNavigation() {
self.chatDisplayNode.willNavigateAway()
}
@ -11719,7 +11640,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
private func navigationButtonAction(_ action: ChatNavigationButtonAction) {
switch action {
case .spacer:
case .spacer, .toggleInfoPanel:
break
case .cancelMessageSelection:
self.updateChatPresentationInterfaceState(animated: true, interactive: true, { $0.updatedInterfaceState { $0.withoutSelectionState() } })
@ -12204,27 +12125,6 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
case .feed:
break
}
case .toggleInfoPanel:
self.updateChatPresentationInterfaceState(animated: true, interactive: true, {
return $0.updatedTitlePanelContext {
if let index = $0.firstIndex(where: {
switch $0 {
case .chatInfo:
return true
default:
return false
}
}) {
var updatedContexts = $0
updatedContexts.remove(at: index)
return updatedContexts
} else {
var updatedContexts = $0
updatedContexts.append(.chatInfo)
return updatedContexts.sorted()
}
}
})
}
}

View File

@ -1,230 +0,0 @@
import Foundation
import UIKit
import Display
import AsyncDisplayKit
import Postbox
import TelegramCore
import TelegramPresentationData
import ChatPresentationInterfaceState
private enum ChatInfoTitleButton {
case search
case info
case mute
case unmute
case call
case report
case unarchive
func title(_ strings: PresentationStrings) -> String {
switch self {
case .search:
return strings.Common_Search
case .info:
return strings.Conversation_Info
case .mute:
return strings.Conversation_TitleMute
case .unmute:
return strings.Conversation_TitleUnmute
case .call:
return strings.Conversation_Call
case .report:
return strings.ReportPeer_Report
case .unarchive:
return strings.ChatList_UnarchiveAction
}
}
func icon(_ theme: PresentationTheme) -> UIImage? {
switch self {
case .search:
return PresentationResourcesChat.chatTitlePanelSearchImage(theme)
case .info:
return PresentationResourcesChat.chatTitlePanelInfoImage(theme)
case .mute:
return PresentationResourcesChat.chatTitlePanelMuteImage(theme)
case .unmute:
return PresentationResourcesChat.chatTitlePanelUnmuteImage(theme)
case .call:
return PresentationResourcesChat.chatTitlePanelCallImage(theme)
case .report:
return PresentationResourcesChat.chatTitlePanelReportImage(theme)
case .unarchive:
return PresentationResourcesChat.chatTitlePanelUnarchiveImage(theme)
}
}
}
private func peerButtons(_ peer: Peer, interfaceState: ChatPresentationInterfaceState) -> [ChatInfoTitleButton] {
let muteAction: ChatInfoTitleButton
if interfaceState.peerIsMuted {
muteAction = .unmute
} else {
muteAction = .mute
}
let infoButton: ChatInfoTitleButton
if interfaceState.isArchived {
infoButton = .unarchive
} else {
infoButton = .info
}
if let peer = peer as? TelegramUser {
var buttons: [ChatInfoTitleButton] = [.search, muteAction]
if peer.botInfo == nil && interfaceState.callsAvailable {
buttons.append(.call)
}
buttons.append(infoButton)
return buttons
} else if let _ = peer as? TelegramSecretChat {
var buttons: [ChatInfoTitleButton] = [.search, muteAction]
buttons.append(.call)
buttons.append(.info)
return buttons
} else if let channel = peer as? TelegramChannel {
if channel.flags.contains(.isCreator) || channel.addressName == nil {
return [.search, muteAction, infoButton]
} else {
return [.search, .report, muteAction, infoButton]
}
} else if let group = peer as? TelegramGroup {
if case .creator = group.role {
return [.search, muteAction, infoButton]
} else {
return [.search, muteAction, infoButton]
}
} else {
return [.search, muteAction, infoButton]
}
}
private let buttonFont = Font.medium(10.0)
private final class ChatInfoTitlePanelButtonNode: HighlightableButtonNode {
init() {
super.init()
self.displaysAsynchronously = false
self.imageNode.displayWithoutProcessing = true
self.imageNode.displaysAsynchronously = false
self.titleNode.displaysAsynchronously = false
self.laysOutHorizontally = false
}
func setup(text: String, color: UIColor, icon: UIImage?) {
self.setTitle(text, with: buttonFont, with: color, for: [])
self.setImage(icon, for: [])
if let icon = icon {
self.contentSpacing = max(0.0, 32.0 - icon.size.height)
}
}
}
final class ChatInfoTitlePanelNode: ChatTitleAccessoryPanelNode {
private var theme: PresentationTheme?
private let separatorNode: ASDisplayNode
private var buttons: [(ChatInfoTitleButton, ChatInfoTitlePanelButtonNode)] = []
override init() {
self.separatorNode = ASDisplayNode()
self.separatorNode.isLayerBacked = true
super.init()
self.addSubnode(self.separatorNode)
}
override func updateLayout(width: CGFloat, leftInset: CGFloat, rightInset: CGFloat, transition: ContainedViewLayoutTransition, interfaceState: ChatPresentationInterfaceState) -> LayoutResult {
let themeUpdated = self.theme !== interfaceState.theme
self.theme = interfaceState.theme
let panelHeight: CGFloat = 55.0
if themeUpdated {
self.separatorNode.backgroundColor = interfaceState.theme.rootController.navigationBar.separatorColor
}
let updatedButtons: [ChatInfoTitleButton]
switch interfaceState.chatLocation {
case .peer:
if let peer = interfaceState.renderedPeer?.peer {
updatedButtons = peerButtons(peer, interfaceState: interfaceState)
} else {
updatedButtons = []
}
case .replyThread, .feed:
updatedButtons = []
}
var buttonsUpdated = false
if self.buttons.count != updatedButtons.count {
buttonsUpdated = true
} else {
for i in 0 ..< updatedButtons.count {
if self.buttons[i].0 != updatedButtons[i] {
buttonsUpdated = true
break
}
}
}
if buttonsUpdated || themeUpdated {
for (_, buttonNode) in self.buttons {
buttonNode.removeFromSupernode()
}
self.buttons.removeAll()
for button in updatedButtons {
let buttonNode = ChatInfoTitlePanelButtonNode()
buttonNode.laysOutHorizontally = false
buttonNode.setup(text: button.title(interfaceState.strings), color: interfaceState.theme.chat.inputPanel.panelControlAccentColor, icon: button.icon(interfaceState.theme))
buttonNode.addTarget(self, action: #selector(self.buttonPressed(_:)), forControlEvents: [.touchUpInside])
self.addSubnode(buttonNode)
self.buttons.append((button, buttonNode))
}
}
if !self.buttons.isEmpty {
let buttonWidth = floor((width - leftInset - rightInset) / CGFloat(self.buttons.count))
var nextButtonOrigin: CGFloat = leftInset
for (_, buttonNode) in self.buttons {
buttonNode.frame = CGRect(origin: CGPoint(x: nextButtonOrigin, y: 0.0), size: CGSize(width: buttonWidth, height: panelHeight))
nextButtonOrigin += buttonWidth
}
}
transition.updateFrame(node: self.separatorNode, frame: CGRect(origin: CGPoint(x: 0.0, y: 0.0), size: CGSize(width: width, height: UIScreenPixel)))
return LayoutResult(backgroundHeight: panelHeight, insetHeight: panelHeight)
}
@objc func buttonPressed(_ node: HighlightableButtonNode) {
for (button, buttonNode) in self.buttons {
if buttonNode === node {
switch button {
case .info:
self.interfaceInteraction?.openPeerInfo()
case .mute:
self.interfaceInteraction?.togglePeerNotifications()
case .unmute:
self.interfaceInteraction?.togglePeerNotifications()
case .search:
self.interfaceInteraction?.beginMessageSearch(.everything, "")
case .call:
self.interfaceInteraction?.beginCall(false)
case .report:
self.interfaceInteraction?.reportPeer()
case .unarchive:
self.interfaceInteraction?.unarchiveChat()
}
break
}
}
}
}

View File

@ -42,7 +42,7 @@ func titlePanelForChatPresentationInterfaceState(_ chatPresentationInterfaceStat
break loop
}
}
case .chatInfo, .requestInProgress, .toastAlert, .inviteRequests:
case .requestInProgress, .toastAlert, .inviteRequests:
selectedContext = context
break loop
}
@ -120,14 +120,6 @@ func titlePanelForChatPresentationInterfaceState(_ chatPresentationInterfaceStat
panel.interfaceInteraction = interfaceInteraction
return panel
}
case .chatInfo:
if let currentPanel = currentPanel as? ChatInfoTitlePanelNode {
return currentPanel
} else {
let panel = ChatInfoTitlePanelNode()
panel.interfaceInteraction = interfaceInteraction
return panel
}
case .requestInProgress:
if let currentPanel = currentPanel as? ChatRequestInProgressTitlePanelNode {
return currentPanel

View File

@ -119,6 +119,8 @@ final class ChatInviteRequestsTitlePanelNode: ChatTitleAccessoryPanelNode {
private var avatarsContent: AnimatedAvatarSetContext.Content?
private let avatarsNode: AnimatedAvatarSetNode
private let activateAreaNode: AccessibilityAreaNode
private var theme: PresentationTheme?
private var peerId: PeerId?
@ -138,6 +140,9 @@ final class ChatInviteRequestsTitlePanelNode: ChatTitleAccessoryPanelNode {
self.avatarsContext = AnimatedAvatarSetContext()
self.avatarsNode = AnimatedAvatarSetNode()
self.activateAreaNode = AccessibilityAreaNode()
self.activateAreaNode.accessibilityTraits = .button
super.init()
self.addSubnode(self.separatorNode)
@ -146,6 +151,8 @@ final class ChatInviteRequestsTitlePanelNode: ChatTitleAccessoryPanelNode {
self.addSubnode(self.closeButton)
self.addSubnode(self.avatarsNode)
self.addSubnode(self.activateAreaNode)
}
@ -198,6 +205,9 @@ final class ChatInviteRequestsTitlePanelNode: ChatTitleAccessoryPanelNode {
transition.updateFrame(node: self.avatarsNode, frame: CGRect(origin: CGPoint(x: leftInset + 8.0, y: floor((panelHeight - avatarsSize.height) / 2.0)), size: avatarsSize))
}
self.activateAreaNode.frame = CGRect(origin: .zero, size: CGSize(width: width, height: panelHeight))
self.activateAreaNode.accessibilityLabel = interfaceState.strings.Conversation_RequestsToJoin(self.count)
return LayoutResult(backgroundHeight: initialPanelHeight, insetHeight: panelHeight)
}

View File

@ -9,6 +9,8 @@ final class ChatRequestInProgressTitlePanelNode: ChatTitleAccessoryPanelNode {
private let separatorNode: ASDisplayNode
private let titleNode: ImmediateTextNode
private let activateAreaNode: AccessibilityAreaNode
private var theme: PresentationTheme?
private var strings: PresentationStrings?
@ -19,10 +21,15 @@ final class ChatRequestInProgressTitlePanelNode: ChatTitleAccessoryPanelNode {
self.titleNode = ImmediateTextNode()
self.titleNode.maximumNumberOfLines = 1
self.activateAreaNode = AccessibilityAreaNode()
self.activateAreaNode.accessibilityTraits = .staticText
super.init()
self.addSubnode(self.titleNode)
self.addSubnode(self.separatorNode)
self.addSubnode(self.activateAreaNode)
}
override func updateLayout(width: CGFloat, leftInset: CGFloat, rightInset: CGFloat, transition: ContainedViewLayoutTransition, interfaceState: ChatPresentationInterfaceState) -> LayoutResult {
@ -46,6 +53,9 @@ final class ChatRequestInProgressTitlePanelNode: ChatTitleAccessoryPanelNode {
transition.updateFrame(node: self.separatorNode, frame: CGRect(origin: CGPoint(x: 0.0, y: 0.0), size: CGSize(width: width, height: UIScreenPixel)))
self.activateAreaNode.frame = CGRect(origin: .zero, size: CGSize(width: width, height: panelHeight))
self.activateAreaNode.accessibilityLabel = interfaceState.strings.Channel_NotificationLoading
return LayoutResult(backgroundHeight: panelHeight, insetHeight: panelHeight)
}
}

View File

@ -8,6 +8,8 @@ final class ChatToastAlertPanelNode: ChatTitleAccessoryPanelNode {
private let separatorNode: ASDisplayNode
private let titleNode: ImmediateTextNode
private let activateAreaNode: AccessibilityAreaNode
private var textColor: UIColor = .black {
didSet {
if !self.textColor.isEqual(oldValue) {
@ -34,6 +36,9 @@ final class ChatToastAlertPanelNode: ChatTitleAccessoryPanelNode {
self.titleNode.maximumNumberOfLines = 1
self.titleNode.insets = UIEdgeInsets(top: 2.0, left: 2.0, bottom: 2.0, right: 2.0)
self.activateAreaNode = AccessibilityAreaNode()
self.activateAreaNode.accessibilityTraits = [.staticText]
super.init()
self.addSubnode(self.titleNode)
@ -51,6 +56,9 @@ final class ChatToastAlertPanelNode: ChatTitleAccessoryPanelNode {
let titleSize = self.titleNode.updateLayout(CGSize(width: width - leftInset - rightInset - 20.0, height: 100.0))
self.titleNode.frame = CGRect(origin: CGPoint(x: floor((width - titleSize.width) / 2.0), y: floor((panelHeight - titleSize.height) / 2.0)), size: titleSize)
self.activateAreaNode.frame = CGRect(origin: .zero, size: CGSize(width: width, height: panelHeight))
self.activateAreaNode.accessibilityLabel = self.titleNode.attributedText?.string ?? ""
return LayoutResult(backgroundHeight: panelHeight, insetHeight: panelHeight)
}
}

View File

@ -155,7 +155,12 @@ public func chatTranslationState(context: AccountContext, peerId: EnginePeer.Id)
return .single(nil)
}
if #available(iOS 12.0, *) {
let baseLang = context.sharedContext.currentPresentationData.with { $0 }.strings.baseLanguageCode
var baseLang = context.sharedContext.currentPresentationData.with { $0 }.strings.baseLanguageCode
let rawSuffix = "-raw"
if baseLang.hasSuffix(rawSuffix) {
baseLang = String(baseLang.dropLast(rawSuffix.count))
}
return context.sharedContext.accountManager.sharedData(keys: [ApplicationSpecificSharedDataKeys.translationSettings])
|> mapToSignal { sharedData in
let settings = sharedData.entries[ApplicationSpecificSharedDataKeys.translationSettings]?.get(TranslationSettings.self) ?? TranslationSettings.defaultSettings