Various Fixes

This commit is contained in:
Ilya Laktyushin 2021-03-02 22:10:23 +04:00
parent 5f0a33e414
commit fed6d34f53
10 changed files with 367 additions and 335 deletions

View File

@ -600,7 +600,7 @@ public class ChatListControllerImpl: TelegramBaseController, ChatListController
|> take(1) |> take(1)
|> deliverOnMainQueue).start(next: { [weak self] greetingSticker in |> deliverOnMainQueue).start(next: { [weak self] greetingSticker in
if let strongSelf = self { if let strongSelf = self {
strongSelf.context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: strongSelf.context, chatLocation: .peer(peer.id), activateInput: activateInput, scrollToEndIfExists: scrollToEndIfExists, greetingData: greetingSticker.flatMap({ ChatGreetingData(sticker: $0) }), animated: !scrollToEndIfExists, options: strongSelf.groupId == PeerGroupId.root ? [.removeOnMasterDetails] : [], parentGroupId: strongSelf.groupId, completion: { [weak self] controller in strongSelf.context.sharedContext.navigateToChatController(NavigateToChatControllerParams(navigationController: navigationController, context: strongSelf.context, chatLocation: .peer(peer.id), activateInput: activateInput && !peer.isDeleted, scrollToEndIfExists: scrollToEndIfExists, greetingData: greetingSticker.flatMap({ ChatGreetingData(sticker: $0) }), animated: !scrollToEndIfExists, options: strongSelf.groupId == PeerGroupId.root ? [.removeOnMasterDetails] : [], parentGroupId: strongSelf.groupId, completion: { [weak self] controller in
self?.chatListDisplayNode.containerNode.currentItemNode.clearHighlightAnimated(true) self?.chatListDisplayNode.containerNode.currentItemNode.clearHighlightAnimated(true)
if let promoInfo = promoInfo { if let promoInfo = promoInfo {
switch promoInfo { switch promoInfo {

View File

@ -217,7 +217,6 @@ private final class NavigationButtonItemNode: ImmediateTextNode {
override func updateLayout(_ constrainedSize: CGSize) -> CGSize { override func updateLayout(_ constrainedSize: CGSize) -> CGSize {
var superSize = super.updateLayout(constrainedSize) var superSize = super.updateLayout(constrainedSize)
superSize.height = max(44.0, superSize.height)
if let node = self.node { if let node = self.node {
let nodeSize = node.measure(constrainedSize) let nodeSize = node.measure(constrainedSize)
@ -231,6 +230,8 @@ private final class NavigationButtonItemNode: ImmediateTextNode {
imageNode.frame = imageFrame imageNode.frame = imageFrame
self.imageRippleNode.frame = imageFrame self.imageRippleNode.frame = imageFrame
return size return size
} else {
superSize.height = max(44.0, superSize.height)
} }
return superSize return superSize
} }

View File

@ -128,6 +128,8 @@ final class PasscodeEntryControllerNode: ASDisplayNode {
override func didLoad() { override func didLoad() {
super.didLoad() super.didLoad()
self.view.disablesInteractiveKeyboardGestureRecognizer = true
self.view.insertSubview(self.effectView, at: 0) self.view.insertSubview(self.effectView, at: 0)
if self.arguments.cancel != nil { if self.arguments.cancel != nil {

View File

@ -161,6 +161,11 @@ final class PasscodeSetupControllerNode: ASDisplayNode {
transition.updateFrame(node: self.modeButtonNode, frame: CGRect(origin: CGPoint(x: 0.0, y: layout.size.height - insets.bottom - 53.0), size: CGSize(width: layout.size.width, height: 44.0))) transition.updateFrame(node: self.modeButtonNode, frame: CGRect(origin: CGPoint(x: 0.0, y: layout.size.height - insets.bottom - 53.0), size: CGSize(width: layout.size.width, height: 44.0)))
} }
override func didLoad() {
super.didLoad()
self.view.disablesInteractiveKeyboardGestureRecognizer = true
}
func updateMode(_ mode: PasscodeSetupControllerMode) { func updateMode(_ mode: PasscodeSetupControllerMode) {
self.mode = mode self.mode = mode
self.inputFieldNode.reset() self.inputFieldNode.reset()

View File

@ -1039,6 +1039,10 @@ public func channelAdminController(context: AccountContext, peerId: PeerId, admi
return current.withUpdatedUpdating(true) return current.withUpdatedUpdating(true)
} }
updateRightsDisposable.set((context.peerChannelMemberCategoriesContextsManager.updateMemberAdminRights(account: context.account, peerId: peerId, memberId: adminId, adminRights: TelegramChatAdminRights(rights: updateFlags ?? []), rank: effectiveRank) |> deliverOnMainQueue).start(error: { error in updateRightsDisposable.set((context.peerChannelMemberCategoriesContextsManager.updateMemberAdminRights(account: context.account, peerId: peerId, memberId: adminId, adminRights: TelegramChatAdminRights(rights: updateFlags ?? []), rank: effectiveRank) |> deliverOnMainQueue).start(error: { error in
updateState { current in
return current.withUpdatedUpdating(false)
}
let presentationData = context.sharedContext.currentPresentationData.with { $0 } let presentationData = context.sharedContext.currentPresentationData.with { $0 }
var text = presentationData.strings.Login_UnknownError var text = presentationData.strings.Login_UnknownError
switch error { switch error {

View File

@ -1382,6 +1382,7 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
} }
}, openInstantPage: { [weak self] message, associatedData in }, openInstantPage: { [weak self] message, associatedData in
if let strongSelf = self, strongSelf.isNodeLoaded, let navigationController = strongSelf.effectiveNavigationController, let message = strongSelf.chatDisplayNode.historyNode.messageInCurrentHistoryView(message.id) { if let strongSelf = self, strongSelf.isNodeLoaded, let navigationController = strongSelf.effectiveNavigationController, let message = strongSelf.chatDisplayNode.historyNode.messageInCurrentHistoryView(message.id) {
strongSelf.chatDisplayNode.dismissInput()
openChatInstantPage(context: strongSelf.context, message: message, sourcePeerType: associatedData?.automaticDownloadPeerType, navigationController: navigationController) openChatInstantPage(context: strongSelf.context, message: message, sourcePeerType: associatedData?.automaticDownloadPeerType, navigationController: navigationController)
if case .overlay = strongSelf.presentationInterfaceState.mode { if case .overlay = strongSelf.presentationInterfaceState.mode {
@ -11642,12 +11643,14 @@ public final class ChatControllerImpl: TelegramBaseController, ChatController, G
var latestNode: (Int32, ASDisplayNode)? var latestNode: (Int32, ASDisplayNode)?
self.chatDisplayNode.historyNode.forEachVisibleItemNode { itemNode in self.chatDisplayNode.historyNode.forEachVisibleItemNode { itemNode in
if let itemNode = itemNode as? ChatMessageItemView, let item = itemNode.item, let statusNode = itemNode.getStatusNode() { if let itemNode = itemNode as? ChatMessageItemView, let item = itemNode.item, let statusNode = itemNode.getStatusNode() {
if let (latestTimestamp, _) = latestNode { if !item.content.effectivelyIncoming(self.context.account.peerId) {
if item.message.timestamp > latestTimestamp { if let (latestTimestamp, _) = latestNode {
if item.message.timestamp > latestTimestamp {
latestNode = (item.message.timestamp, statusNode)
}
} else {
latestNode = (item.message.timestamp, statusNode) latestNode = (item.message.timestamp, statusNode)
} }
} else {
latestNode = (item.message.timestamp, statusNode)
} }
} }
} }

View File

@ -184,8 +184,6 @@ final class ChatMessageAccessibilityData {
let singleUrl: String? let singleUrl: String?
init(item: ChatMessageItem, isSelected: Bool?) { init(item: ChatMessageItem, isSelected: Bool?) {
var label: String = ""
let value: String
var hint: String? var hint: String?
var traits: UIAccessibilityTraits = [] var traits: UIAccessibilityTraits = []
var singleUrl: String? var singleUrl: String?
@ -202,368 +200,377 @@ final class ChatMessageAccessibilityData {
} }
} }
let authorName = item.message.author?.displayTitle(strings: item.presentationData.strings, displayOrder: item.presentationData.nameDisplayOrder) let dataForMessage: (Message, Bool) -> (String, String) = { message, isReply -> (String, String) in
var label: String = ""
if let chatPeer = item.message.peers[item.message.id.peerId] { var value: String = ""
let (_, _, messageText) = chatListItemStrings(strings: item.presentationData.strings, nameDisplayOrder: item.presentationData.nameDisplayOrder, messages: [item.message], chatPeer: RenderedPeer(peer: chatPeer), accountPeerId: item.context.account.peerId)
var text = messageText if let chatPeer = message.peers[item.message.id.peerId] {
let authorName = message.author?.displayTitle(strings: item.presentationData.strings, displayOrder: item.presentationData.nameDisplayOrder)
loop: for media in item.message.media {
if let _ = media as? TelegramMediaImage { let (_, _, messageText) = chatListItemStrings(strings: item.presentationData.strings, nameDisplayOrder: item.presentationData.nameDisplayOrder, messages: [message], chatPeer: RenderedPeer(peer: chatPeer), accountPeerId: item.context.account.peerId)
if isIncoming {
if announceIncomingAuthors, let authorName = authorName { var text = messageText
label = item.presentationData.strings.VoiceOver_Chat_PhotoFrom(authorName).0
} else { loop: for media in message.media {
label = item.presentationData.strings.VoiceOver_Chat_Photo if let _ = media as? TelegramMediaImage {
}
} else {
label = item.presentationData.strings.VoiceOver_Chat_YourPhoto
}
text = ""
if !item.message.text.isEmpty {
text.append("\n")
text.append(item.presentationData.strings.VoiceOver_Chat_Caption(item.message.text).0)
}
} else if let file = media as? TelegramMediaFile {
var isSpecialFile = false
for attribute in file.attributes {
switch attribute {
case let .Sticker(displayText, packReference, _):
isSpecialFile = true
text = displayText
if file.mimeType == "application/x-tgsticker" {
if isIncoming {
if announceIncomingAuthors, let authorName = authorName {
label = item.presentationData.strings.VoiceOver_Chat_AnimatedStickerFrom(authorName).0
} else {
label = item.presentationData.strings.VoiceOver_Chat_AnimatedSticker
}
} else {
label = item.presentationData.strings.VoiceOver_Chat_YourAnimatedSticker
}
} else {
if isIncoming {
if announceIncomingAuthors, let authorName = authorName {
label = item.presentationData.strings.VoiceOver_Chat_StickerFrom(authorName).0
} else {
label = item.presentationData.strings.VoiceOver_Chat_Sticker
}
} else {
label = item.presentationData.strings.VoiceOver_Chat_YourSticker
}
}
case let .Audio(audio):
isSpecialFile = true
if isSelected == nil {
hint = item.presentationData.strings.VoiceOver_Chat_PlayHint
}
traits.insert(.startsMediaSession)
if audio.isVoice {
let durationString = voiceMessageDurationFormatter.string(from: Double(audio.duration)) ?? ""
if isIncoming {
if announceIncomingAuthors, let authorName = authorName {
label = item.presentationData.strings.VoiceOver_Chat_VoiceMessageFrom(authorName).0
} else {
label = item.presentationData.strings.VoiceOver_Chat_VoiceMessage
}
} else {
label = item.presentationData.strings.VoiceOver_Chat_YourVoiceMessage
}
text = item.presentationData.strings.VoiceOver_Chat_Duration(durationString).0
} else {
let durationString = musicDurationFormatter.string(from: Double(audio.duration)) ?? ""
if isIncoming {
if announceIncomingAuthors, let authorName = authorName {
label = item.presentationData.strings.VoiceOver_Chat_MusicFrom(authorName).0
} else {
label = item.presentationData.strings.VoiceOver_Chat_Music
}
} else {
label = item.presentationData.strings.VoiceOver_Chat_YourMusic
}
let performer = audio.performer ?? "Unknown"
let title = audio.title ?? "Unknown"
text = item.presentationData.strings.VoiceOver_Chat_MusicTitle(title, performer).0
text.append(item.presentationData.strings.VoiceOver_Chat_Duration(durationString).0)
}
case let .Video(video):
isSpecialFile = true
if isSelected == nil {
hint = item.presentationData.strings.VoiceOver_Chat_PlayHint
}
traits.insert(.startsMediaSession)
let durationString = voiceMessageDurationFormatter.string(from: Double(video.duration)) ?? ""
if video.flags.contains(.instantRoundVideo) {
if isIncoming {
if announceIncomingAuthors, let authorName = authorName {
label = item.presentationData.strings.VoiceOver_Chat_VideoMessageFrom(authorName).0
} else {
label = item.presentationData.strings.VoiceOver_Chat_VideoMessage
}
} else {
label = item.presentationData.strings.VoiceOver_Chat_YourVideoMessage
}
} else {
if isIncoming {
if announceIncomingAuthors, let authorName = authorName {
label = item.presentationData.strings.VoiceOver_Chat_VideoFrom(authorName).0
} else {
label = item.presentationData.strings.VoiceOver_Chat_Video
}
} else {
label = item.presentationData.strings.VoiceOver_Chat_YourVideo
}
}
text = item.presentationData.strings.VoiceOver_Chat_Duration(durationString).0
default:
break
}
}
if !isSpecialFile {
if isSelected == nil {
hint = item.presentationData.strings.VoiceOver_Chat_OpenHint
}
let sizeString = fileSizeFormatter.string(fromByteCount: Int64(file.size ?? 0))
if isIncoming { if isIncoming {
if announceIncomingAuthors, let authorName = authorName { if announceIncomingAuthors, let authorName = authorName {
label = item.presentationData.strings.VoiceOver_Chat_FileFrom(authorName).0 label = item.presentationData.strings.VoiceOver_Chat_PhotoFrom(authorName).0
} else { } else {
label = item.presentationData.strings.VoiceOver_Chat_File label = item.presentationData.strings.VoiceOver_Chat_Photo
} }
} else { } else {
label = item.presentationData.strings.VoiceOver_Chat_YourFile label = item.presentationData.strings.VoiceOver_Chat_YourPhoto
} }
text = "\(file.fileName ?? ""). " text = ""
text.append(item.presentationData.strings.VoiceOver_Chat_Size(sizeString).0) if !message.text.isEmpty {
} text.append("\n")
if !item.message.text.isEmpty {
text.append("\n") text.append(item.presentationData.strings.VoiceOver_Chat_Caption(message.text).0)
text.append(item.presentationData.strings.VoiceOver_Chat_Caption(item.message.text).0)
}
break loop
} else if let webpage = media as? TelegramMediaWebpage, case let .Loaded(content) = webpage.content {
var contentText = item.presentationData.strings.VoiceOver_Chat_PagePreview + ". "
if let title = content.title, !title.isEmpty {
contentText.append(item.presentationData.strings.VoiceOver_Chat_Title(title).0)
contentText.append(". ")
}
if let text = content.text, !text.isEmpty {
contentText.append(text)
}
text = "\(item.message.text)\n\(contentText)"
} else if let contact = media as? TelegramMediaContact {
if isIncoming {
if announceIncomingAuthors, let authorName = authorName {
label = item.presentationData.strings.VoiceOver_Chat_ContactFrom(authorName).0
} else {
label = item.presentationData.strings.VoiceOver_Chat_Contact
} }
} else { } else if let file = media as? TelegramMediaFile {
label = item.presentationData.strings.VoiceOver_Chat_YourContact var isSpecialFile = false
} for attribute in file.attributes {
var displayName = "" switch attribute {
if !contact.firstName.isEmpty { case let .Sticker(displayText, packReference, _):
displayName.append(contact.firstName) isSpecialFile = true
} text = displayText
if !contact.lastName.isEmpty { if file.mimeType == "application/x-tgsticker" {
if !displayName.isEmpty { if isIncoming {
displayName.append(" ") if announceIncomingAuthors, let authorName = authorName {
label = item.presentationData.strings.VoiceOver_Chat_AnimatedStickerFrom(authorName).0
} else {
label = item.presentationData.strings.VoiceOver_Chat_AnimatedSticker
}
} else {
label = item.presentationData.strings.VoiceOver_Chat_YourAnimatedSticker
}
} else {
if isIncoming {
if announceIncomingAuthors, let authorName = authorName {
label = item.presentationData.strings.VoiceOver_Chat_StickerFrom(authorName).0
} else {
label = item.presentationData.strings.VoiceOver_Chat_Sticker
}
} else {
label = item.presentationData.strings.VoiceOver_Chat_YourSticker
}
}
case let .Audio(audio):
isSpecialFile = true
if isSelected == nil {
hint = item.presentationData.strings.VoiceOver_Chat_PlayHint
}
traits.insert(.startsMediaSession)
if audio.isVoice {
let durationString = voiceMessageDurationFormatter.string(from: Double(audio.duration)) ?? ""
if isIncoming {
if announceIncomingAuthors, let authorName = authorName {
label = item.presentationData.strings.VoiceOver_Chat_VoiceMessageFrom(authorName).0
} else {
label = item.presentationData.strings.VoiceOver_Chat_VoiceMessage
}
} else {
label = item.presentationData.strings.VoiceOver_Chat_YourVoiceMessage
}
text = item.presentationData.strings.VoiceOver_Chat_Duration(durationString).0
} else {
let durationString = musicDurationFormatter.string(from: Double(audio.duration)) ?? ""
if isIncoming {
if announceIncomingAuthors, let authorName = authorName {
label = item.presentationData.strings.VoiceOver_Chat_MusicFrom(authorName).0
} else {
label = item.presentationData.strings.VoiceOver_Chat_Music
}
} else {
label = item.presentationData.strings.VoiceOver_Chat_YourMusic
}
let performer = audio.performer ?? "Unknown"
let title = audio.title ?? "Unknown"
text = item.presentationData.strings.VoiceOver_Chat_MusicTitle(title, performer).0
text.append(item.presentationData.strings.VoiceOver_Chat_Duration(durationString).0)
}
case let .Video(video):
isSpecialFile = true
if isSelected == nil {
hint = item.presentationData.strings.VoiceOver_Chat_PlayHint
}
traits.insert(.startsMediaSession)
let durationString = voiceMessageDurationFormatter.string(from: Double(video.duration)) ?? ""
if video.flags.contains(.instantRoundVideo) {
if isIncoming {
if announceIncomingAuthors, let authorName = authorName {
label = item.presentationData.strings.VoiceOver_Chat_VideoMessageFrom(authorName).0
} else {
label = item.presentationData.strings.VoiceOver_Chat_VideoMessage
}
} else {
label = item.presentationData.strings.VoiceOver_Chat_YourVideoMessage
}
} else {
if isIncoming {
if announceIncomingAuthors, let authorName = authorName {
label = item.presentationData.strings.VoiceOver_Chat_VideoFrom(authorName).0
} else {
label = item.presentationData.strings.VoiceOver_Chat_Video
}
} else {
label = item.presentationData.strings.VoiceOver_Chat_YourVideo
}
}
text = item.presentationData.strings.VoiceOver_Chat_Duration(durationString).0
default:
break
}
} }
displayName.append(contact.lastName) if !isSpecialFile {
} if isSelected == nil {
var phoneNumbersString = "" hint = item.presentationData.strings.VoiceOver_Chat_OpenHint
var phoneNumberCount = 0 }
var emailAddressesString = "" let sizeString = fileSizeFormatter.string(fromByteCount: Int64(file.size ?? 0))
var emailAddressCount = 0 if isIncoming {
var organizationString = "" if announceIncomingAuthors, let authorName = authorName {
if let vCard = contact.vCardData, let vCardData = vCard.data(using: .utf8), let contactData = DeviceContactExtendedData(vcard: vCardData) { label = item.presentationData.strings.VoiceOver_Chat_FileFrom(authorName).0
if displayName.isEmpty && !contactData.organization.isEmpty { } else {
displayName = contactData.organization label = item.presentationData.strings.VoiceOver_Chat_File
}
if !contactData.basicData.phoneNumbers.isEmpty {
for phone in contactData.basicData.phoneNumbers {
if !phoneNumbersString.isEmpty {
phoneNumbersString.append(", ")
} }
for c in phone.value { } else {
label = item.presentationData.strings.VoiceOver_Chat_YourFile
}
text = "\(file.fileName ?? ""). "
text.append(item.presentationData.strings.VoiceOver_Chat_Size(sizeString).0)
}
if !message.text.isEmpty {
text.append("\n")
text.append(item.presentationData.strings.VoiceOver_Chat_Caption(message.text).0)
}
break loop
} else if let webpage = media as? TelegramMediaWebpage, case let .Loaded(content) = webpage.content {
var contentText = item.presentationData.strings.VoiceOver_Chat_PagePreview + ". "
if let title = content.title, !title.isEmpty {
contentText.append(item.presentationData.strings.VoiceOver_Chat_Title(title).0)
contentText.append(". ")
}
if let text = content.text, !text.isEmpty {
contentText.append(text)
}
text = "\(message.text)\n\(contentText)"
} else if let contact = media as? TelegramMediaContact {
if isIncoming {
if announceIncomingAuthors, let authorName = authorName {
label = item.presentationData.strings.VoiceOver_Chat_ContactFrom(authorName).0
} else {
label = item.presentationData.strings.VoiceOver_Chat_Contact
}
} else {
label = item.presentationData.strings.VoiceOver_Chat_YourContact
}
var displayName = ""
if !contact.firstName.isEmpty {
displayName.append(contact.firstName)
}
if !contact.lastName.isEmpty {
if !displayName.isEmpty {
displayName.append(" ")
}
displayName.append(contact.lastName)
}
var phoneNumbersString = ""
var phoneNumberCount = 0
var emailAddressesString = ""
var emailAddressCount = 0
var organizationString = ""
if let vCard = contact.vCardData, let vCardData = vCard.data(using: .utf8), let contactData = DeviceContactExtendedData(vcard: vCardData) {
if displayName.isEmpty && !contactData.organization.isEmpty {
displayName = contactData.organization
}
if !contactData.basicData.phoneNumbers.isEmpty {
for phone in contactData.basicData.phoneNumbers {
if !phoneNumbersString.isEmpty {
phoneNumbersString.append(", ")
}
for c in phone.value {
phoneNumbersString.append(c)
phoneNumbersString.append(" ")
}
phoneNumberCount += 1
}
} else {
for c in contact.phoneNumber {
phoneNumbersString.append(c) phoneNumbersString.append(c)
phoneNumbersString.append(" ") phoneNumbersString.append(" ")
} }
phoneNumberCount += 1 phoneNumberCount += 1
} }
} else {
for c in contact.phoneNumber { for email in contactData.emailAddresses {
phoneNumbersString.append(c) if !emailAddressesString.isEmpty {
phoneNumbersString.append(" ") emailAddressesString.append(", ")
}
emailAddressesString.append("\(email.value)")
emailAddressCount += 1
} }
phoneNumberCount += 1 if !contactData.organization.isEmpty && displayName != contactData.organization {
organizationString = contactData.organization
}
} else {
phoneNumbersString.append("\(contact.phoneNumber)")
}
text = "\(displayName)."
if !phoneNumbersString.isEmpty {
if phoneNumberCount > 1 {
text.append(item.presentationData.strings.VoiceOver_Chat_ContactPhoneNumberCount(Int32(phoneNumberCount)))
text.append(": ")
} else {
text.append(item.presentationData.strings.VoiceOver_Chat_ContactPhoneNumber)
}
text.append("\(phoneNumbersString). ")
}
if !emailAddressesString.isEmpty {
if emailAddressCount > 1 {
text.append(item.presentationData.strings.VoiceOver_Chat_ContactEmailCount(Int32(emailAddressCount)))
text.append(": ")
} else {
text.append(item.presentationData.strings.VoiceOver_Chat_ContactEmail)
text.append(": ")
}
text.append("\(emailAddressesString). ")
}
if !organizationString.isEmpty {
text.append(item.presentationData.strings.VoiceOver_Chat_ContactOrganization(organizationString).0)
text.append(".")
}
} else if let poll = media as? TelegramMediaPoll {
if isIncoming {
if announceIncomingAuthors, let authorName = authorName {
label = item.presentationData.strings.VoiceOver_Chat_AnonymousPollFrom(authorName).0
} else {
label = item.presentationData.strings.VoiceOver_Chat_AnonymousPoll
}
} else {
label = item.presentationData.strings.VoiceOver_Chat_YourAnonymousPoll
} }
for email in contactData.emailAddresses { var optionVoterCount: [Int: Int32] = [:]
if !emailAddressesString.isEmpty { var maxOptionVoterCount: Int32 = 0
emailAddressesString.append(", ") var totalVoterCount: Int32 = 0
let voters: [TelegramMediaPollOptionVoters]?
if poll.isClosed {
voters = poll.results.voters ?? []
} else {
voters = poll.results.voters
}
var selectedOptionId: Data?
if let voters = voters, let totalVoters = poll.results.totalVoters {
var didVote = false
for voter in voters {
if voter.selected {
didVote = true
selectedOptionId = voter.opaqueIdentifier
}
} }
emailAddressesString.append("\(email.value)") totalVoterCount = totalVoters
emailAddressCount += 1 if didVote || poll.isClosed {
} for i in 0 ..< poll.options.count {
if !contactData.organization.isEmpty && displayName != contactData.organization { inner: for optionVoters in voters {
organizationString = contactData.organization if optionVoters.opaqueIdentifier == poll.options[i].opaqueIdentifier {
} optionVoterCount[i] = optionVoters.count
} else { maxOptionVoterCount = max(maxOptionVoterCount, optionVoters.count)
phoneNumbersString.append("\(contact.phoneNumber)") break inner
} }
text = "\(displayName)."
if !phoneNumbersString.isEmpty {
if phoneNumberCount > 1 {
text.append(item.presentationData.strings.VoiceOver_Chat_ContactPhoneNumberCount(Int32(phoneNumberCount)))
text.append(": ")
} else {
text.append(item.presentationData.strings.VoiceOver_Chat_ContactPhoneNumber)
}
text.append("\(phoneNumbersString). ")
}
if !emailAddressesString.isEmpty {
if emailAddressCount > 1 {
text.append(item.presentationData.strings.VoiceOver_Chat_ContactEmailCount(Int32(emailAddressCount)))
text.append(": ")
} else {
text.append(item.presentationData.strings.VoiceOver_Chat_ContactEmail)
text.append(": ")
}
text.append("\(emailAddressesString). ")
}
if !organizationString.isEmpty {
text.append(item.presentationData.strings.VoiceOver_Chat_ContactOrganization(organizationString).0)
text.append(".")
}
} else if let poll = media as? TelegramMediaPoll {
if isIncoming {
if announceIncomingAuthors, let authorName = authorName {
label = item.presentationData.strings.VoiceOver_Chat_AnonymousPollFrom(authorName).0
} else {
label = item.presentationData.strings.VoiceOver_Chat_AnonymousPoll
}
} else {
label = item.presentationData.strings.VoiceOver_Chat_YourAnonymousPoll
}
var optionVoterCount: [Int: Int32] = [:]
var maxOptionVoterCount: Int32 = 0
var totalVoterCount: Int32 = 0
let voters: [TelegramMediaPollOptionVoters]?
if poll.isClosed {
voters = poll.results.voters ?? []
} else {
voters = poll.results.voters
}
var selectedOptionId: Data?
if let voters = voters, let totalVoters = poll.results.totalVoters {
var didVote = false
for voter in voters {
if voter.selected {
didVote = true
selectedOptionId = voter.opaqueIdentifier
}
}
totalVoterCount = totalVoters
if didVote || poll.isClosed {
for i in 0 ..< poll.options.count {
inner: for optionVoters in voters {
if optionVoters.opaqueIdentifier == poll.options[i].opaqueIdentifier {
optionVoterCount[i] = optionVoters.count
maxOptionVoterCount = max(maxOptionVoterCount, optionVoters.count)
break inner
} }
} }
} }
} }
}
var optionVoterCounts: [Int]
if totalVoterCount != 0 {
optionVoterCounts = countNicePercent(votes: (0 ..< poll.options.count).map({ Int(optionVoterCount[$0] ?? 0) }), total: Int(totalVoterCount))
} else {
optionVoterCounts = Array(repeating: 0, count: poll.options.count)
}
text = item.presentationData.strings.VoiceOver_Chat_Title(poll.text).0
text.append(". ")
text.append(item.presentationData.strings.VoiceOver_Chat_PollOptionCount(Int32(poll.options.count)))
text.append(": ")
var optionsText = ""
for i in 0 ..< poll.options.count {
let option = poll.options[i]
if !optionsText.isEmpty { var optionVoterCounts: [Int]
optionsText.append(", ") if totalVoterCount != 0 {
} optionVoterCounts = countNicePercent(votes: (0 ..< poll.options.count).map({ Int(optionVoterCount[$0] ?? 0) }), total: Int(totalVoterCount))
optionsText.append(option.text) } else {
if let selectedOptionId = selectedOptionId, selectedOptionId == option.opaqueIdentifier { optionVoterCounts = Array(repeating: 0, count: poll.options.count)
optionsText.append(", ")
optionsText.append(item.presentationData.strings.VoiceOver_Chat_OptionSelected)
} }
if let _ = optionVoterCount[i] { text = item.presentationData.strings.VoiceOver_Chat_Title(poll.text).0
if maxOptionVoterCount != 0 && totalVoterCount != 0 { text.append(". ")
optionsText.append(", \(optionVoterCounts[i])%")
text.append(item.presentationData.strings.VoiceOver_Chat_PollOptionCount(Int32(poll.options.count)))
text.append(": ")
var optionsText = ""
for i in 0 ..< poll.options.count {
let option = poll.options[i]
if !optionsText.isEmpty {
optionsText.append(", ")
}
optionsText.append(option.text)
if let selectedOptionId = selectedOptionId, selectedOptionId == option.opaqueIdentifier {
optionsText.append(", ")
optionsText.append(item.presentationData.strings.VoiceOver_Chat_OptionSelected)
}
if let _ = optionVoterCount[i] {
if maxOptionVoterCount != 0 && totalVoterCount != 0 {
optionsText.append(", \(optionVoterCounts[i])%")
}
} }
} }
} text.append("\(optionsText). ")
text.append("\(optionsText). ") if totalVoterCount != 0 {
if totalVoterCount != 0 { text.append(item.presentationData.strings.VoiceOver_Chat_PollVotes(Int32(totalVoterCount)))
text.append(item.presentationData.strings.VoiceOver_Chat_PollVotes(Int32(totalVoterCount))) } else {
} else { text.append(item.presentationData.strings.VoiceOver_Chat_PollNoVotes)
text.append(item.presentationData.strings.VoiceOver_Chat_PollNoVotes) }
} if poll.isClosed {
if poll.isClosed { text.append(item.presentationData.strings.VoiceOver_Chat_PollFinalResults)
text.append(item.presentationData.strings.VoiceOver_Chat_PollFinalResults) }
} }
} }
}
var result = ""
var result = ""
if let isSelected = isSelected {
if let isSelected = isSelected { if isSelected {
if isSelected { result += item.presentationData.strings.VoiceOver_Chat_Selected
result += item.presentationData.strings.VoiceOver_Chat_Selected result += "\n"
}
traits.insert(.startsMediaSession)
}
result += "\(text)"
let dateString = DateFormatter.localizedString(from: Date(timeIntervalSince1970: Double(message.timestamp)), dateStyle: .medium, timeStyle: .short)
result += "\n\(dateString)"
if !isIncoming && item.read && !isReply {
result += "\n" result += "\n"
if announceIncomingAuthors {
result += item.presentationData.strings.VoiceOver_Chat_SeenByRecipients
} else {
result += item.presentationData.strings.VoiceOver_Chat_SeenByRecipient
}
} }
traits.insert(.startsMediaSession) value = result
} else {
value = ""
} }
result += "\(text)" if label.isEmpty {
if let author = message.author {
let dateString = DateFormatter.localizedString(from: Date(timeIntervalSince1970: Double(item.message.timestamp)), dateStyle: .medium, timeStyle: .short) if isIncoming {
label = author.displayTitle(strings: item.presentationData.strings, displayOrder: item.presentationData.nameDisplayOrder)
result += "\n\(dateString)" } else {
if !isIncoming && item.read { label = item.presentationData.strings.VoiceOver_Chat_YourMessage
result += "\n" }
if announceIncomingAuthors {
result += item.presentationData.strings.VoiceOver_Chat_SeenByRecipients
} else { } else {
result += item.presentationData.strings.VoiceOver_Chat_SeenByRecipient label = item.presentationData.strings.VoiceOver_Chat_Message
} }
} }
value = result
} else { return (label, value)
value = ""
} }
if label.isEmpty { var (label, value) = dataForMessage(item.message, false)
if let author = item.message.author {
if isIncoming {
label = author.displayTitle(strings: item.presentationData.strings, displayOrder: item.presentationData.nameDisplayOrder)
} else {
label = item.presentationData.strings.VoiceOver_Chat_YourMessage
}
} else {
label = item.presentationData.strings.VoiceOver_Chat_Message
}
}
for attribute in item.message.attributes { for attribute in item.message.attributes {
if let attribute = attribute as? TextEntitiesMessageAttribute { if let attribute = attribute as? TextEntitiesMessageAttribute {
@ -593,7 +600,7 @@ final class ChatMessageAccessibilityData {
} }
} }
} else if let attribute = attribute as? ReplyMessageAttribute, let replyMessage = item.message.associatedMessages[attribute.messageId] { } else if let attribute = attribute as? ReplyMessageAttribute, let replyMessage = item.message.associatedMessages[attribute.messageId] {
let replyLabel: String var replyLabel: String
if replyMessage.flags.contains(.Incoming) { if replyMessage.flags.contains(.Incoming) {
if let author = replyMessage.author { if let author = replyMessage.author {
replyLabel = item.presentationData.strings.VoiceOver_Chat_ReplyFrom(author.displayTitle(strings: item.presentationData.strings, displayOrder: item.presentationData.nameDisplayOrder)).0 replyLabel = item.presentationData.strings.VoiceOver_Chat_ReplyFrom(author.displayTitle(strings: item.presentationData.strings, displayOrder: item.presentationData.nameDisplayOrder)).0
@ -603,6 +610,10 @@ final class ChatMessageAccessibilityData {
} else { } else {
replyLabel = item.presentationData.strings.VoiceOver_Chat_ReplyToYourMessage replyLabel = item.presentationData.strings.VoiceOver_Chat_ReplyToYourMessage
} }
let (replyMessageLabel, replyMessageValue) = dataForMessage(replyMessage, true)
replyLabel += "\(replyLabel): \(replyMessageLabel), \(replyMessageValue)"
label = "\(replyLabel) . \(label)" label = "\(replyLabel) . \(label)"
} }
} }

View File

@ -378,7 +378,9 @@ final class ChatTitleView: UIView, NavigationBarTitleView {
let string = NSAttributedString(string: "", font: Font.regular(13.0), textColor: titleTheme.rootController.navigationBar.secondaryTextColor) let string = NSAttributedString(string: "", font: Font.regular(13.0), textColor: titleTheme.rootController.navigationBar.secondaryTextColor)
state = .info(string, .generic) state = .info(string, .generic)
} else if let user = peer as? TelegramUser { } else if let user = peer as? TelegramUser {
if servicePeer { if user.isDeleted {
state = .none
} else if servicePeer {
let string = NSAttributedString(string: "", font: Font.regular(13.0), textColor: titleTheme.rootController.navigationBar.secondaryTextColor) let string = NSAttributedString(string: "", font: Font.regular(13.0), textColor: titleTheme.rootController.navigationBar.secondaryTextColor)
state = .info(string, .generic) state = .info(string, .generic)
} else if user.flags.contains(.isSupport) { } else if user.flags.contains(.isSupport) {

View File

@ -826,7 +826,7 @@ final class PeerInfoVisualMediaPaneNode: ASDisplayNode, PeerInfoPaneNode, UIScro
self.scrollNode.view.delaysContentTouches = false self.scrollNode.view.delaysContentTouches = false
self.scrollNode.view.canCancelContentTouches = true self.scrollNode.view.canCancelContentTouches = true
self.scrollNode.view.showsVerticalScrollIndicator = true self.scrollNode.view.showsVerticalScrollIndicator = false
if #available(iOS 11.0, *) { if #available(iOS 11.0, *) {
self.scrollNode.view.contentInsetAdjustmentBehavior = .never self.scrollNode.view.contentInsetAdjustmentBehavior = .never
} }

View File

@ -993,6 +993,7 @@ func peerInfoHeaderButtons(peer: Peer?, cachedData: CachedPeerData?, isOpenedFro
var canViewStats = false var canViewStats = false
var hasDiscussion = false var hasDiscussion = false
var hasVoiceChat = false var hasVoiceChat = false
var canStartVoiceChat = false
if let cachedChannelData = cachedData as? CachedChannelData { if let cachedChannelData = cachedData as? CachedChannelData {
canViewStats = cachedChannelData.flags.contains(.canViewStats) canViewStats = cachedChannelData.flags.contains(.canViewStats)
} }
@ -1012,6 +1013,9 @@ func peerInfoHeaderButtons(peer: Peer?, cachedData: CachedPeerData?, isOpenedFro
if channel.flags.contains(.hasVoiceChat) { if channel.flags.contains(.hasVoiceChat) {
hasVoiceChat = true hasVoiceChat = true
} }
if !hasVoiceChat && (channel.flags.contains(.isCreator) || channel.hasPermission(.manageCalls)) {
canStartVoiceChat = true
}
} }
switch channel.participationStatus { switch channel.participationStatus {
case .member: case .member:
@ -1043,7 +1047,7 @@ func peerInfoHeaderButtons(peer: Peer?, cachedData: CachedPeerData?, isOpenedFro
if channel.isVerified || channel.adminRights != nil || channel.flags.contains(.isCreator) { if channel.isVerified || channel.adminRights != nil || channel.flags.contains(.isCreator) {
canReport = false canReport = false
} }
if !canReport && !canViewStats { if !canReport && !canViewStats && !canStartVoiceChat {
displayMore = false displayMore = false
} }
if displayMore { if displayMore {