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

This commit is contained in:
Ilya Laktyushin 2019-02-15 18:23:52 +04:00
commit a1da20afe0
60 changed files with 3586 additions and 3135 deletions

Binary file not shown.

View File

@ -0,0 +1,12 @@
{
"images" : [
{
"idiom" : "universal",
"filename" : "AddAcc.pdf"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}

View File

@ -0,0 +1,12 @@
{
"images" : [
{
"idiom" : "universal",
"filename" : "Sim.pdf"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}

Binary file not shown.

View File

@ -0,0 +1,12 @@
{
"images" : [
{
"idiom" : "universal",
"filename" : "Cache.pdf"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}

View File

@ -0,0 +1,12 @@
{
"images" : [
{
"idiom" : "universal",
"filename" : "Passcode.pdf"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}

View File

@ -436,6 +436,8 @@
D0B21B13220D6E8C003F741D /* ActionSheetPeerItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0B21B12220D6E8C003F741D /* ActionSheetPeerItem.swift */; };
D0B21B15220D85DD003F741D /* TabBarAccountSwitchController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0B21B14220D85DD003F741D /* TabBarAccountSwitchController.swift */; };
D0B21B17220D85E7003F741D /* TabBarAccountSwitchControllerNode.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0B21B16220D85E7003F741D /* TabBarAccountSwitchControllerNode.swift */; };
D0B21B1F22156D92003F741D /* LegacyCache.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0B21B1E22156D92003F741D /* LegacyCache.swift */; };
D0B21B212215B539003F741D /* LogoutOptionsController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0B21B202215B539003F741D /* LogoutOptionsController.swift */; };
D0B2F76220506E2A00D3BFB9 /* MediaInputSettings.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0B2F76120506E2A00D3BFB9 /* MediaInputSettings.swift */; };
D0B2F76820528E3D00D3BFB9 /* UserInfoEditingPhoneActionItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0B2F76720528E3D00D3BFB9 /* UserInfoEditingPhoneActionItem.swift */; };
D0B2F76A2052920D00D3BFB9 /* UserInfoEditingPhoneItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0B2F7692052920D00D3BFB9 /* UserInfoEditingPhoneItem.swift */; };
@ -1868,6 +1870,8 @@
D0B21B12220D6E8C003F741D /* ActionSheetPeerItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ActionSheetPeerItem.swift; sourceTree = "<group>"; };
D0B21B14220D85DD003F741D /* TabBarAccountSwitchController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TabBarAccountSwitchController.swift; sourceTree = "<group>"; };
D0B21B16220D85E7003F741D /* TabBarAccountSwitchControllerNode.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TabBarAccountSwitchControllerNode.swift; sourceTree = "<group>"; };
D0B21B1E22156D92003F741D /* LegacyCache.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LegacyCache.swift; sourceTree = "<group>"; };
D0B21B202215B539003F741D /* LogoutOptionsController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LogoutOptionsController.swift; sourceTree = "<group>"; };
D0B2F76120506E2A00D3BFB9 /* MediaInputSettings.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MediaInputSettings.swift; sourceTree = "<group>"; };
D0B2F76720528E3D00D3BFB9 /* UserInfoEditingPhoneActionItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserInfoEditingPhoneActionItem.swift; sourceTree = "<group>"; };
D0B2F7692052920D00D3BFB9 /* UserInfoEditingPhoneItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserInfoEditingPhoneItem.swift; sourceTree = "<group>"; };
@ -3302,6 +3306,7 @@
D097C26B20DD1EA5007BB4B8 /* OverlayStatusController.swift */,
09F799F921C3542D00820234 /* LegacyWebSearchGallery.swift */,
09F79A0C21C88E8900820234 /* LegacyWebSearchEditor.swift */,
D0B21B1E22156D92003F741D /* LegacyCache.swift */,
);
name = "Legacy Components";
sourceTree = "<group>";
@ -4652,6 +4657,7 @@
D0F53BEB1E784DA900117362 /* ChangePhoneNumberCodeController.swift */,
D0B21B14220D85DD003F741D /* TabBarAccountSwitchController.swift */,
D0B21B16220D85E7003F741D /* TabBarAccountSwitchControllerNode.swift */,
D0B21B202215B539003F741D /* LogoutOptionsController.swift */,
);
name = Settings;
sourceTree = "<group>";
@ -5638,6 +5644,7 @@
D0EC6DA31EB9F58900EBF1C3 /* ChatMessageDateHeader.swift in Sources */,
D0EC6DA41EB9F58900EBF1C3 /* ChatMessageActionButtonsNode.swift in Sources */,
D0EC6DA51EB9F58900EBF1C3 /* ChatBotInfoItem.swift in Sources */,
D0B21B212215B539003F741D /* LogoutOptionsController.swift in Sources */,
D0E9BAE41F0574D800F079A4 /* STPBankAccountParams.m in Sources */,
D0E412D3206A7DC100BEE4A2 /* DateSelectionActionSheetController.swift in Sources */,
D06887F01F72DEE6000AB936 /* ShareInputFieldNode.swift in Sources */,
@ -5784,6 +5791,7 @@
D0EC6DE81EB9F58900EBF1C3 /* ChatPinnedMessageTitlePanelNode.swift in Sources */,
D0EC6DE91EB9F58900EBF1C3 /* ChatInfoTitlePanelNode.swift in Sources */,
D0EC6DEA1EB9F58900EBF1C3 /* ChatReportPeerTitlePanelNode.swift in Sources */,
D0B21B1F22156D92003F741D /* LegacyCache.swift in Sources */,
D0EC6DEB1EB9F58900EBF1C3 /* ChatRequestInProgressTitlePanelNode.swift in Sources */,
D0EC6DEC1EB9F58900EBF1C3 /* ChatToastAlertPanelNode.swift in Sources */,
D0EC6DED1EB9F58900EBF1C3 /* ChatHistoryNavigationButtonNode.swift in Sources */,

View File

@ -382,7 +382,7 @@ class AvatarGalleryController: ViewController {
self.galleryNode.setControlsHidden(true, animated: false)
if let centralItemNode = self.galleryNode.pager.centralItemNode(), let itemSize = centralItemNode.contentSize() {
self.preferredContentSize = itemSize.aspectFitted(self.view.bounds.size)
self.containerLayoutUpdated(ContainerViewLayout(size: self.preferredContentSize, metrics: LayoutMetrics(), intrinsicInsets: UIEdgeInsets(), safeInsets: UIEdgeInsets(), statusBarHeight: nil, inputHeight: nil, standardInputHeight: 216.0, inputHeightIsInteractivellyChanging: false), transition: .immediate)
self.containerLayoutUpdated(ContainerViewLayout(size: self.preferredContentSize, metrics: LayoutMetrics(), intrinsicInsets: UIEdgeInsets(), safeInsets: UIEdgeInsets(), statusBarHeight: nil, inputHeight: nil, standardInputHeight: 216.0, inputHeightIsInteractivellyChanging: false, inVoiceOver: false), transition: .immediate)
centralItemNode.activateAsInitial()
}
}

View File

@ -313,6 +313,9 @@ private func botCheckoutControllerEntries(presentationData: PresentationData, st
private let hasApplePaySupport: Bool = PKPaymentAuthorizationViewController.canMakePayments(usingNetworks: [.visa, .masterCard, .amex])
private func formSupportApplePay(_ paymentForm: BotPaymentForm) -> Bool {
if !hasApplePaySupport {
return false
}
guard let nativeProvider = paymentForm.nativeProvider else {
return false
}
@ -342,10 +345,10 @@ private func formSupportApplePay(_ paymentForm: BotPaymentForm) -> Bool {
return merchantId != nil
}
private func availablePaymentMethods(current: BotCheckoutPaymentMethod?, supportsApplePay: Bool) -> [BotCheckoutPaymentMethod] {
private func availablePaymentMethods(form: BotPaymentForm, current: BotCheckoutPaymentMethod?) -> [BotCheckoutPaymentMethod] {
var methods: [BotCheckoutPaymentMethod] = []
if hasApplePaySupport {
methods.append(.applePayStripe)
if formSupportApplePay(form) && hasApplePaySupport {
methods.append(.applePay)
}
if let current = current {
if !methods.contains(current) {
@ -595,13 +598,7 @@ final class BotCheckoutControllerNode: ItemListControllerNode<BotCheckoutEntry>,
openPaymentMethodImpl = { [weak self] in
if let strongSelf = self, let paymentForm = strongSelf.paymentFormValue {
let supportsApplePay: Bool
if formSupportApplePay(paymentForm) {
supportsApplePay = true
} else {
supportsApplePay = false
}
let methods = availablePaymentMethods(current: strongSelf.currentPaymentMethod, supportsApplePay: supportsApplePay)
let methods = availablePaymentMethods(form: paymentForm, current: strongSelf.currentPaymentMethod)
if methods.isEmpty {
openNewCard()
} else {
@ -699,7 +696,7 @@ final class BotCheckoutControllerNode: ItemListControllerNode<BotCheckoutEntry>,
override func containerLayoutUpdated(_ layout: ContainerViewLayout, navigationBarHeight: CGFloat, transition: ContainedViewLayoutTransition) {
var updatedInsets = layout.intrinsicInsets
updatedInsets.bottom += BotCheckoutActionButton.diameter + 20.0
super.containerLayoutUpdated(ContainerViewLayout(size: layout.size, metrics: layout.metrics, intrinsicInsets: updatedInsets, safeInsets: layout.safeInsets, statusBarHeight: layout.statusBarHeight, inputHeight: layout.inputHeight, standardInputHeight: layout.standardInputHeight, inputHeightIsInteractivellyChanging: layout.inputHeightIsInteractivellyChanging), navigationBarHeight: navigationBarHeight, transition: transition)
super.containerLayoutUpdated(ContainerViewLayout(size: layout.size, metrics: layout.metrics, intrinsicInsets: updatedInsets, safeInsets: layout.safeInsets, statusBarHeight: layout.statusBarHeight, inputHeight: layout.inputHeight, standardInputHeight: layout.standardInputHeight, inputHeightIsInteractivellyChanging: layout.inputHeightIsInteractivellyChanging, inVoiceOver: layout.inVoiceOver), navigationBarHeight: navigationBarHeight, transition: transition)
let actionButtonFrame = CGRect(origin: CGPoint(x: 10.0, y: layout.size.height - 10.0 - BotCheckoutActionButton.diameter - layout.intrinsicInsets.bottom), size: CGSize(width: layout.size.width - 20.0, height: BotCheckoutActionButton.diameter))
transition.updateFrame(node: self.actionButton, frame: actionButtonFrame)
@ -789,11 +786,10 @@ final class BotCheckoutControllerNode: ItemListControllerNode<BotCheckoutEntry>,
}
case let .webToken(token):
credentials = .generic(data: token.data, saveOnServer: token.saveOnServer)
case .applePayStripe:
case .applePay:
guard let paymentForm = self.paymentFormValue, let nativeProvider = paymentForm.nativeProvider else {
return
}
//NSDictionary *dict = [NSJSONSerialization JSONObjectWithData:[strongSelf->_paymentForm.nativeParams dataUsingEncoding:NSUTF8StringEncoding] options:0 error:nil];
guard let nativeParamsData = nativeProvider.params.data(using: .utf8) else {
return
}

View File

@ -13,7 +13,7 @@ struct BotCheckoutPaymentWebToken: Equatable {
enum BotCheckoutPaymentMethod: Equatable {
case savedCredentials(BotPaymentSavedCredentials)
case webToken(BotCheckoutPaymentWebToken)
case applePayStripe
case applePay
var title: String {
switch self {
@ -24,7 +24,7 @@ enum BotCheckoutPaymentMethod: Equatable {
}
case let .webToken(token):
return token.title
case .applePayStripe:
case .applePay:
return "Apple Pay"
}
}
@ -63,7 +63,7 @@ final class BotCheckoutPaymentMethodSheetController: ActionSheetController {
case let .webToken(token):
title = token.title
icon = nil
case .applePayStripe:
case .applePay:
title = "Apple Pay"
icon = UIImage(bundleImageName: "Bot Payments/ApplePayLogo")?.precomposed()
}

View File

@ -296,7 +296,7 @@ final class BotReceiptControllerNode: ItemListControllerNode<BotReceiptEntry> {
override func containerLayoutUpdated(_ layout: ContainerViewLayout, navigationBarHeight: CGFloat, transition: ContainedViewLayoutTransition) {
var updatedInsets = layout.intrinsicInsets
updatedInsets.bottom += BotCheckoutActionButton.diameter + 20.0
super.containerLayoutUpdated(ContainerViewLayout(size: layout.size, metrics: layout.metrics, intrinsicInsets: updatedInsets, safeInsets: layout.safeInsets, statusBarHeight: layout.statusBarHeight, inputHeight: layout.inputHeight, standardInputHeight: layout.standardInputHeight, inputHeightIsInteractivellyChanging: layout.inputHeightIsInteractivellyChanging), navigationBarHeight: navigationBarHeight, transition: transition)
super.containerLayoutUpdated(ContainerViewLayout(size: layout.size, metrics: layout.metrics, intrinsicInsets: updatedInsets, safeInsets: layout.safeInsets, statusBarHeight: layout.statusBarHeight, inputHeight: layout.inputHeight, standardInputHeight: layout.standardInputHeight, inputHeightIsInteractivellyChanging: layout.inputHeightIsInteractivellyChanging, inVoiceOver: layout.inVoiceOver), navigationBarHeight: navigationBarHeight, transition: transition)
let actionButtonFrame = CGRect(origin: CGPoint(x: 10.0, y: layout.size.height - 10.0 - BotCheckoutActionButton.diameter - layout.intrinsicInsets.bottom), size: CGSize(width: layout.size.width - 20.0, height: BotCheckoutActionButton.diameter))
transition.updateFrame(node: self.actionButton, frame: actionButtonFrame)

View File

@ -2454,12 +2454,16 @@ public final class ChatController: TelegramController, KeyShortcutResponder, Gal
self?.enqueueChatContextResult(results, result)
}, sendBotCommand: { [weak self] botPeer, command in
if let strongSelf = self, canSendMessagesToChat(strongSelf.presentationInterfaceState) {
if let peer = strongSelf.presentationInterfaceState.renderedPeer?.peer, let addressName = botPeer.addressName {
if let peer = strongSelf.presentationInterfaceState.renderedPeer?.peer {
let messageText: String
if peer is TelegramUser {
messageText = command
if let addressName = botPeer.addressName {
if peer is TelegramUser {
messageText = command
} else {
messageText = command + "@" + addressName
}
} else {
messageText = command + "@" + addressName
messageText = command
}
let replyMessageId = strongSelf.presentationInterfaceState.interfaceState.replyMessageId
strongSelf.chatDisplayNode.setupSendActionOnViewUpdate({
@ -4815,7 +4819,7 @@ public final class ChatController: TelegramController, KeyShortcutResponder, Gal
return .single((nil, true))
case let .HistoryView(view, _, _, _, _):
for entry in view.entries {
if case let .MessageEntry(message, _, _, _) = entry {
if case let .MessageEntry(message, _, _, _, _) = entry {
if message.id == messageLocation.messageId {
return .single((MessageIndex(message), false))
}
@ -4902,7 +4906,7 @@ public final class ChatController: TelegramController, KeyShortcutResponder, Gal
return .complete()
case let .HistoryView(view, _, _, _, _):
for entry in view.entries {
if case let .MessageEntry(message, _, _, _) = entry {
if case let .MessageEntry(message, _, _, _, _) = entry {
if message.id == messageLocation.messageId {
return .single(MessageIndex(message))
}
@ -5441,7 +5445,7 @@ public final class ChatController: TelegramController, KeyShortcutResponder, Gal
let galleryController = AvatarGalleryController(context: self.context, peer: peer, remoteEntries: nil, replaceRootController: { controller, ready in
}, synchronousLoad: true)
galleryController.setHintWillBePresentedInPreviewingContext(true)
galleryController.containerLayoutUpdated(ContainerViewLayout(size: CGSize(width: self.view.bounds.size.width, height: self.view.bounds.size.height), metrics: LayoutMetrics(), intrinsicInsets: UIEdgeInsets(), safeInsets: UIEdgeInsets(), statusBarHeight: nil, inputHeight: nil, standardInputHeight: 216.0, inputHeightIsInteractivellyChanging: false), transition: .immediate)
galleryController.containerLayoutUpdated(ContainerViewLayout(size: CGSize(width: self.view.bounds.size.width, height: self.view.bounds.size.height), metrics: LayoutMetrics(), intrinsicInsets: UIEdgeInsets(), safeInsets: UIEdgeInsets(), statusBarHeight: nil, inputHeight: nil, standardInputHeight: 216.0, inputHeightIsInteractivellyChanging: false, inVoiceOver: false), transition: .immediate)
return (galleryController, buttonView.convert(buttonView.bounds, to: sourceView))
}
return nil
@ -5478,7 +5482,7 @@ public final class ChatController: TelegramController, KeyShortcutResponder, Gal
gallery.setHintWillBePresentedInPreviewingContext(true)
let rect = selectedTransitionNode.0.view.convert(selectedTransitionNode.0.bounds, to: sourceView)
let sourceRect = rect.insetBy(dx: -2.0, dy: -2.0)
gallery.containerLayoutUpdated(ContainerViewLayout(size: CGSize(width: self.view.bounds.size.width, height: self.view.bounds.size.height), metrics: LayoutMetrics(), intrinsicInsets: UIEdgeInsets(), safeInsets: UIEdgeInsets(), statusBarHeight: nil, inputHeight: nil, standardInputHeight: 216.0, inputHeightIsInteractivellyChanging: false), transition: .immediate)
gallery.containerLayoutUpdated(ContainerViewLayout(size: CGSize(width: self.view.bounds.size.width, height: self.view.bounds.size.height), metrics: LayoutMetrics(), intrinsicInsets: UIEdgeInsets(), safeInsets: UIEdgeInsets(), statusBarHeight: nil, inputHeight: nil, standardInputHeight: 216.0, inputHeightIsInteractivellyChanging: false, inVoiceOver: false), transition: .immediate)
return (gallery, sourceRect)
case let .instantPage(gallery, centralIndex, galleryMedia):
break

View File

@ -1361,10 +1361,10 @@ class ChatControllerNode: ASDisplayNode, UIScrollViewDelegate {
}
var restrictionText: String?
if chatPresentationInterfaceState.isNotAccessible {
if let peer = chatPresentationInterfaceState.renderedPeer?.peer, let restrictionTextValue = peer.restrictionText, !restrictionTextValue.isEmpty {
restrictionText = restrictionTextValue
} else if chatPresentationInterfaceState.isNotAccessible {
restrictionText = chatPresentationInterfaceState.strings.Channel_ErrorAccessDenied
} else if let peer = chatPresentationInterfaceState.renderedPeer?.peer {
restrictionText = peer.restrictionText
}
if let restrictionText = restrictionText {
@ -1557,6 +1557,8 @@ class ChatControllerNode: ASDisplayNode, UIScrollViewDelegate {
if let (validLayout, _) = self.validLayout {
let _ = inputNode.updateLayout(width: validLayout.size.width, leftInset: validLayout.safeInsets.left, rightInset: validLayout.safeInsets.right, bottomInset: validLayout.intrinsicInsets.bottom, standardInputHeight: validLayout.standardInputHeight, inputHeight: validLayout.inputHeight ?? 0.0, maximumHeight: validLayout.standardInputHeight, inputPanelHeight: 44.0, transition: .immediate, interfaceState: self.chatPresentationInterfaceState, isVisible: false)
}
self.textInputPanelNode?.loadTextInputNodeIfNeeded()
}
}

View File

@ -19,7 +19,7 @@ func chatHistoryEntriesForView(location: ChatLocation, view: MessageHistoryView,
}
}
var groupBucket: [(Message, Bool, ChatHistoryMessageSelection, Bool)] = []
var groupBucket: [(Message, Bool, ChatHistoryMessageSelection, ChatMessageEntryAttributes)] = []
loop: for entry in view.entries {
switch entry {
case let .HoleEntry(hole, _):
@ -30,7 +30,7 @@ func chatHistoryEntriesForView(location: ChatLocation, view: MessageHistoryView,
if view.tagMask == nil {
entries.append(.HoleEntry(hole, presentationData))
}
case let .MessageEntry(message, read, _, monthLocation):
case let .MessageEntry(message, read, _, monthLocation, attributes):
if message.id.peerId.namespace == Namespaces.Peer.CloudChannel {
for media in message.media {
if let action = media as? TelegramMediaAction {
@ -61,7 +61,7 @@ func chatHistoryEntriesForView(location: ChatLocation, view: MessageHistoryView,
} else {
selection = .none
}
groupBucket.append((message, read, selection, isAdmin))
groupBucket.append((message, read, selection, ChatMessageEntryAttributes(isAdmin: isAdmin, isContact: attributes.authorIsContact)))
} else {
let selection: ChatHistoryMessageSelection
if let selectedMessages = selectedMessages {
@ -69,7 +69,7 @@ func chatHistoryEntriesForView(location: ChatLocation, view: MessageHistoryView,
} else {
selection = .none
}
entries.append(.MessageEntry(message, presentationData, read, monthLocation, selection, isAdmin))
entries.append(.MessageEntry(message, presentationData, read, monthLocation, selection, ChatMessageEntryAttributes(isAdmin: isAdmin, isContact: attributes.authorIsContact)))
}
} else {
let selection: ChatHistoryMessageSelection
@ -78,7 +78,7 @@ func chatHistoryEntriesForView(location: ChatLocation, view: MessageHistoryView,
} else {
selection = .none
}
entries.append(.MessageEntry(message, presentationData, read, monthLocation, selection, isAdmin))
entries.append(.MessageEntry(message, presentationData, read, monthLocation, selection, ChatMessageEntryAttributes(isAdmin: isAdmin, isContact: attributes.authorIsContact)))
}
}
}

View File

@ -23,10 +23,15 @@ public enum ChatHistoryMessageSelection: Equatable {
}
}
public struct ChatMessageEntryAttributes: Equatable {
let isAdmin: Bool
let isContact: Bool
}
enum ChatHistoryEntry: Identifiable, Comparable {
case HoleEntry(MessageHistoryHole, ChatPresentationData)
case MessageEntry(Message, ChatPresentationData, Bool, MessageHistoryEntryMonthLocation?, ChatHistoryMessageSelection, Bool)
case MessageGroupEntry(MessageGroupInfo, [(Message, Bool, ChatHistoryMessageSelection, Bool)], ChatPresentationData)
case MessageEntry(Message, ChatPresentationData, Bool, MessageHistoryEntryMonthLocation?, ChatHistoryMessageSelection, ChatMessageEntryAttributes)
case MessageGroupEntry(MessageGroupInfo, [(Message, Bool, ChatHistoryMessageSelection, ChatMessageEntryAttributes)], ChatPresentationData)
case UnreadEntry(MessageIndex, ChatPresentationData)
case ChatInfoEntry(String, ChatPresentationData)
case SearchEntry(PresentationTheme, PresentationStrings)
@ -73,9 +78,9 @@ enum ChatHistoryEntry: Identifiable, Comparable {
} else {
return false
}
case let .MessageEntry(lhsMessage, lhsPresentationData, lhsRead, _, lhsSelection, lhsIsAdmin):
case let .MessageEntry(lhsMessage, lhsPresentationData, lhsRead, _, lhsSelection, lhsAttributes):
switch rhs {
case let .MessageEntry(rhsMessage, rhsPresentationData, rhsRead, _, rhsSelection, rhsIsAdmin) where MessageIndex(lhsMessage) == MessageIndex(rhsMessage) && lhsMessage.flags == rhsMessage.flags && lhsRead == rhsRead:
case let .MessageEntry(rhsMessage, rhsPresentationData, rhsRead, _, rhsSelection, rhsAttributes) where MessageIndex(lhsMessage) == MessageIndex(rhsMessage) && lhsMessage.flags == rhsMessage.flags && lhsRead == rhsRead:
if lhsPresentationData !== rhsPresentationData {
return false
}
@ -105,7 +110,7 @@ enum ChatHistoryEntry: Identifiable, Comparable {
if lhsSelection != rhsSelection {
return false
}
if lhsIsAdmin != rhsIsAdmin {
if lhsAttributes != rhsAttributes {
return false
}
return true
@ -115,8 +120,8 @@ enum ChatHistoryEntry: Identifiable, Comparable {
case let .MessageGroupEntry(lhsGroupInfo, lhsMessages, lhsPresentationData):
if case let .MessageGroupEntry(rhsGroupInfo, rhsMessages, rhsPresentationData) = rhs, lhsGroupInfo == rhsGroupInfo, lhsPresentationData === rhsPresentationData, lhsMessages.count == rhsMessages.count {
for i in 0 ..< lhsMessages.count {
let (lhsMessage, lhsRead, lhsSelection, lhsIsAdmin) = lhsMessages[i]
let (rhsMessage, rhsRead, rhsSelection, rhsIsAdmin) = rhsMessages[i]
let (lhsMessage, lhsRead, lhsSelection, lhsAttributes) = lhsMessages[i]
let (rhsMessage, rhsRead, rhsSelection, rhsAttributes) = rhsMessages[i]
if lhsMessage.id != rhsMessage.id {
return false
@ -159,7 +164,7 @@ enum ChatHistoryEntry: Identifiable, Comparable {
}
}
}
if lhsIsAdmin != rhsIsAdmin {
if lhsAttributes != rhsAttributes {
return false
}
}

View File

@ -167,11 +167,11 @@ private func maxMessageIndexForEntries(_ view: ChatHistoryView, indexRange: (Int
private func mappedInsertEntries(context: AccountContext, chatLocation: ChatLocation, associatedData: ChatMessageItemAssociatedData, controllerInteraction: ChatControllerInteraction, mode: ChatHistoryListMode, entries: [ChatHistoryViewTransitionInsertEntry]) -> [ListViewInsertItem] {
return entries.map { entry -> ListViewInsertItem in
switch entry.entry {
case let .MessageEntry(message, presentationData, read, _, selection, isAdmin):
case let .MessageEntry(message, presentationData, read, _, selection, attributes):
let item: ListViewItem
switch mode {
case .bubbles:
item = ChatMessageItem(presentationData: presentationData, context: context, chatLocation: chatLocation, associatedData: associatedData, controllerInteraction: controllerInteraction, content: .message(message: message, read: read, selection: selection, isAdmin: isAdmin))
item = ChatMessageItem(presentationData: presentationData, context: context, chatLocation: chatLocation, associatedData: associatedData, controllerInteraction: controllerInteraction, content: .message(message: message, read: read, selection: selection, attributes: attributes))
case let .list(search, _):
item = ListMessageItem(theme: presentationData.theme.theme, strings: presentationData.strings, dateTimeFormat: presentationData.dateTimeFormat, context: context, chatLocation: chatLocation, controllerInteraction: controllerInteraction, message: message, selection: selection, displayHeader: search)
}
@ -210,11 +210,11 @@ private func mappedInsertEntries(context: AccountContext, chatLocation: ChatLoca
private func mappedUpdateEntries(context: AccountContext, chatLocation: ChatLocation, associatedData: ChatMessageItemAssociatedData, controllerInteraction: ChatControllerInteraction, mode: ChatHistoryListMode, entries: [ChatHistoryViewTransitionUpdateEntry]) -> [ListViewUpdateItem] {
return entries.map { entry -> ListViewUpdateItem in
switch entry.entry {
case let .MessageEntry(message, presentationData, read, _, selection, isAdmin):
case let .MessageEntry(message, presentationData, read, _, selection, attributes):
let item: ListViewItem
switch mode {
case .bubbles:
item = ChatMessageItem(presentationData: presentationData, context: context, chatLocation: chatLocation, associatedData: associatedData, controllerInteraction: controllerInteraction, content: .message(message: message, read: read, selection: selection, isAdmin: isAdmin))
item = ChatMessageItem(presentationData: presentationData, context: context, chatLocation: chatLocation, associatedData: associatedData, controllerInteraction: controllerInteraction, content: .message(message: message, read: read, selection: selection, attributes: attributes))
case let .list(search, _):
item = ListMessageItem(theme: presentationData.theme.theme, strings: presentationData.strings, dateTimeFormat: presentationData.dateTimeFormat, context: context, chatLocation: chatLocation, controllerInteraction: controllerInteraction, message: message, selection: selection, displayHeader: search)
}
@ -1207,13 +1207,13 @@ public final class ChatHistoryListNode: ListView, ChatHistoryNode {
loop: for i in 0 ..< historyView.filteredEntries.count {
switch historyView.filteredEntries[i] {
case let .MessageEntry(message, presentationData, read, _, selection, isAdmin):
case let .MessageEntry(message, presentationData, read, _, selection, attributes):
if message.id == id {
let index = historyView.filteredEntries.count - 1 - i
let item: ListViewItem
switch self.mode {
case .bubbles:
item = ChatMessageItem(presentationData: presentationData, context: self.context, chatLocation: self.chatLocation, associatedData: associatedData, controllerInteraction: self.controllerInteraction, content: .message(message: message, read: read, selection: selection, isAdmin: isAdmin))
item = ChatMessageItem(presentationData: presentationData, context: self.context, chatLocation: self.chatLocation, associatedData: associatedData, controllerInteraction: self.controllerInteraction, content: .message(message: message, read: read, selection: selection, attributes: attributes))
case let .list(search, _):
item = ListMessageItem(theme: presentationData.theme.theme, strings: presentationData.strings, dateTimeFormat: presentationData.dateTimeFormat, context: self.context, chatLocation: self.chatLocation, controllerInteraction: self.controllerInteraction, message: message, selection: selection, displayHeader: search)
}

View File

@ -50,7 +50,7 @@ func chatHistoryViewForLocation(_ location: ChatHistoryLocation, account: Accoun
switch entry {
case .HoleEntry:
break inner
case let .MessageEntry(message, _, _, _):
case let .MessageEntry(message, _, _, _, _):
if message.flags.contains(.Incoming) {
incomingCount += 1
}

View File

@ -662,6 +662,17 @@ public class ChatListController: TelegramController, KeyShortcutResponder, UIVie
self.displayNodeDidLoad()
}
override public func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) {
super.traitCollectionDidChange(previousTraitCollection)
if #available(iOSApplicationExtension 9.0, *) {
if !self.didSetup3dTouch && self.traitCollection.forceTouchCapability != .unknown {
self.didSetup3dTouch = true
self.registerForPreviewingNonNative(with: self, sourceView: self.view, theme: PeekControllerTheme(presentationTheme: self.presentationData.theme))
}
}
}
override public func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
@ -676,13 +687,7 @@ public class ChatListController: TelegramController, KeyShortcutResponder, UIVie
}
})
#endif
if !self.didSetup3dTouch {
self.didSetup3dTouch = true
if #available(iOSApplicationExtension 9.0, *) {
self.registerForPreviewingNonNative(with: self, sourceView: self.view, theme: PeekControllerTheme(presentationTheme: self.presentationData.theme))
}
}
if let lockViewFrame = self.titleView.lockViewFrame, !self.didShowPasscodeLockTooltipController {
self.passcodeLockTooltipDisposable.set(combineLatest(queue: .mainQueue(), ApplicationSpecificNotice.getPasscodeLockTips(accountManager: self.context.sharedContext.accountManager), self.context.sharedContext.accountManager.accessChallengeData() |> take(1)).start(next: { [weak self] tooltipValue, passcodeView in
@ -899,7 +904,7 @@ public class ChatListController: TelegramController, KeyShortcutResponder, UIVie
let chatController = ChatController(context: self.context, chatLocation: .peer(peerId), mode: .standard(previewing: true))
chatController.canReadHistory.set(false)
chatController.containerLayoutUpdated(ContainerViewLayout(size: contentSize, metrics: LayoutMetrics(), intrinsicInsets: UIEdgeInsets(), safeInsets: UIEdgeInsets(), statusBarHeight: nil, inputHeight: nil, standardInputHeight: 216.0, inputHeightIsInteractivellyChanging: false), transition: .immediate)
chatController.containerLayoutUpdated(ContainerViewLayout(size: contentSize, metrics: LayoutMetrics(), intrinsicInsets: UIEdgeInsets(), safeInsets: UIEdgeInsets(), statusBarHeight: nil, inputHeight: nil, standardInputHeight: 216.0, inputHeightIsInteractivellyChanging: false, inVoiceOver: false), transition: .immediate)
return (chatController, sourceRect)
} else if let messageId = action as? MessageId, messageId.peerId.namespace != Namespaces.Peer.SecretChat {
var sourceRect = view.superview!.convert(view.frame, to: sourceView)
@ -908,7 +913,7 @@ public class ChatListController: TelegramController, KeyShortcutResponder, UIVie
let chatController = ChatController(context: self.context, chatLocation: .peer(messageId.peerId), messageId: messageId, mode: .standard(previewing: true))
chatController.canReadHistory.set(false)
chatController.containerLayoutUpdated(ContainerViewLayout(size: contentSize, metrics: LayoutMetrics(), intrinsicInsets: UIEdgeInsets(), safeInsets: UIEdgeInsets(), statusBarHeight: nil, inputHeight: nil, standardInputHeight: 216.0, inputHeightIsInteractivellyChanging: false), transition: .immediate)
chatController.containerLayoutUpdated(ContainerViewLayout(size: contentSize, metrics: LayoutMetrics(), intrinsicInsets: UIEdgeInsets(), safeInsets: UIEdgeInsets(), statusBarHeight: nil, inputHeight: nil, standardInputHeight: 216.0, inputHeightIsInteractivellyChanging: false, inVoiceOver: false), transition: .immediate)
return (chatController, sourceRect)
}
}
@ -941,14 +946,14 @@ public class ChatListController: TelegramController, KeyShortcutResponder, UIVie
if peer.peerId.namespace != Namespaces.Peer.SecretChat {
let chatController = ChatController(context: self.context, chatLocation: .peer(peer.peerId), mode: .standard(previewing: true))
chatController.canReadHistory.set(false)
chatController.containerLayoutUpdated(ContainerViewLayout(size: contentSize, metrics: LayoutMetrics(), intrinsicInsets: UIEdgeInsets(), safeInsets: UIEdgeInsets(), statusBarHeight: nil, inputHeight: nil, standardInputHeight: 216.0, inputHeightIsInteractivellyChanging: false), transition: .immediate)
chatController.containerLayoutUpdated(ContainerViewLayout(size: contentSize, metrics: LayoutMetrics(), intrinsicInsets: UIEdgeInsets(), safeInsets: UIEdgeInsets(), statusBarHeight: nil, inputHeight: nil, standardInputHeight: 216.0, inputHeightIsInteractivellyChanging: false, inVoiceOver: false), transition: .immediate)
return (chatController, sourceRect)
} else {
return nil
}
case let .groupReference(groupId, _, _, _):
let chatListController = ChatListController(context: self.context, groupId: groupId, controlsHistoryPreload: false)
chatListController.containerLayoutUpdated(ContainerViewLayout(size: contentSize, metrics: LayoutMetrics(), intrinsicInsets: UIEdgeInsets(), safeInsets: UIEdgeInsets(), statusBarHeight: nil, inputHeight: nil, standardInputHeight: 216.0, inputHeightIsInteractivellyChanging: false), transition: .immediate)
chatListController.containerLayoutUpdated(ContainerViewLayout(size: contentSize, metrics: LayoutMetrics(), intrinsicInsets: UIEdgeInsets(), safeInsets: UIEdgeInsets(), statusBarHeight: nil, inputHeight: nil, standardInputHeight: 216.0, inputHeightIsInteractivellyChanging: false, inVoiceOver: false), transition: .immediate)
return (chatListController, sourceRect)
}
} else {

View File

@ -256,6 +256,19 @@ class ChatListItemNode: ItemListRevealOptionsItemNode {
} set(value) {
}
}
override var accessibilityAttributedLabel: NSAttributedString? {
get {
return self.accessibilityLabel.flatMap(NSAttributedString.init(string:))
} set(value) {
}
}
override var accessibilityAttributedValue: NSAttributedString? {
get {
return self.accessibilityValue.flatMap(NSAttributedString.init(string:))
} set(value) {
}
}
override var accessibilityLabel: String? {
get {
guard let item = self.item else {
@ -366,7 +379,6 @@ class ChatListItemNode: ItemListRevealOptionsItemNode {
super.init(layerBacked: false, dynamicBounce: false, rotated: false, seeThrough: false)
self.isAccessibilityElement = true
self.isAccessibilityContainer = true
self.addSubnode(self.backgroundNode)
self.addSubnode(self.separatorNode)
@ -1112,6 +1124,9 @@ class ChatListItemNode: ItemListRevealOptionsItemNode {
strongSelf.setRevealOptions((left: peerLeftRevealOptions, right: peerRevealOptions))
}
strongSelf.setRevealOptionsOpened(item.hasActiveRevealControls, animated: true)
strongSelf.view.accessibilityLabel = strongSelf.accessibilityLabel
strongSelf.view.accessibilityValue = strongSelf.accessibilityValue
}
})
}

View File

@ -145,7 +145,11 @@ private enum ChatListRecentEntry: Comparable, Identifiable {
let status: ContactsPeerItemStatus
if let user = primaryPeer as? TelegramUser {
if let _ = user.botInfo {
status = .custom(strings.Bot_GenericBotStatus)
if let phoneNumber = user.phone, phoneNumber.hasPrefix("424") {
status = .custom(strings.Bot_GenericSupportStatus)
} else {
status = .custom(strings.Bot_GenericBotStatus)
}
} else if user.id != context.account.peerId {
let presence = peer.presence ?? TelegramUserPresence(status: .none, lastActivity: 0)
status = .presence(presence, timeFormat)

View File

@ -13,6 +13,8 @@ final class ChatMessageAvatarAccessoryItem: ListViewAccessoryItem {
private let messageTimestamp: Int32
private let emptyColor: UIColor
private let day: Int32
init(context: AccountContext, peerId: PeerId, peer: Peer?, messageReference: MessageReference?, messageTimestamp: Int32, emptyColor: UIColor) {
self.context = context
self.peerId = peerId
@ -20,11 +22,17 @@ final class ChatMessageAvatarAccessoryItem: ListViewAccessoryItem {
self.messageReference = messageReference
self.messageTimestamp = messageTimestamp
self.emptyColor = emptyColor
var t: time_t = time_t(messageTimestamp)
var timeinfo: tm = tm()
gmtime_r(&t, &timeinfo)
self.day = timeinfo.tm_mday
}
func isEqualToItem(_ other: ListViewAccessoryItem) -> Bool {
if case let other as ChatMessageAvatarAccessoryItem = other {
return other.peerId == self.peerId && abs(other.messageTimestamp - self.messageTimestamp) < 10 * 60
return other.peerId == self.peerId && self.day == other.day && abs(other.messageTimestamp - self.messageTimestamp) < 10 * 60
}
return false

View File

@ -316,6 +316,8 @@ class ChatMessageBubbleItemNode: ChatMessageItemView {
let currentItem = self.appliedItem
return { item, params, mergedTop, mergedBottom, dateHeaderAtBottom in
let accessibilityData = ChatMessageAccessibilityData(item: item)
let baseWidth = params.width - params.leftInset - params.rightInset
let content = item.content
@ -484,11 +486,11 @@ class ChatMessageBubbleItemNode: ChatMessageItemView {
var authorNameString: String?
let authorIsAdmin: Bool
switch content {
case let .message(message, _, _, isAdmin):
case let .message(message, _, _, attributes):
if let peer = message.peers[message.id.peerId] as? TelegramChannel, case .broadcast = peer.info {
authorIsAdmin = false
} else {
authorIsAdmin = isAdmin
authorIsAdmin = attributes.isAdmin
}
case .group:
authorIsAdmin = false
@ -1153,6 +1155,8 @@ class ChatMessageBubbleItemNode: ChatMessageItemView {
return (layout, { [weak self] animation, synchronousLoads in
if let strongSelf = self {
strongSelf.appliedItem = item
strongSelf.accessibilityLabel = accessibilityData.label
strongSelf.accessibilityValue = accessibilityData.value
var transition: ContainedViewLayoutTransition = .immediate
if case let .System(duration) = animation {

View File

@ -7,8 +7,8 @@ import SwiftSignalKit
import TelegramCore
public enum ChatMessageItemContent: Sequence {
case message(message: Message, read: Bool, selection: ChatHistoryMessageSelection, isAdmin: Bool)
case group(messages: [(Message, Bool, ChatHistoryMessageSelection, Bool)])
case message(message: Message, read: Bool, selection: ChatHistoryMessageSelection, attributes: ChatMessageEntryAttributes)
case group(messages: [(Message, Bool, ChatHistoryMessageSelection, ChatMessageEntryAttributes)])
func effectivelyIncoming(_ accountPeerId: PeerId) -> Bool {
switch self {

View File

@ -91,46 +91,43 @@ enum ChatMessagePeekPreviewContent {
case url(ASDisplayNode, CGRect, String)
}
final class ChatMessageAccessibilityData {
let label: String?
let value: String?
init(item: ChatMessageItem) {
let label: String
let value: String
if let author = item.message.author {
if item.message.effectivelyIncoming(item.context.account.peerId) {
label = author.displayTitle
} else {
label = "Outgoing message"
}
} else {
label = "Post"
}
if let chatPeer = item.message.peers[item.message.id.peerId] {
let (_, _, messageText) = chatListItemStrings(strings: item.presentationData.strings, nameDisplayOrder: item.presentationData.nameDisplayOrder, message: item.message, chatPeer: RenderedPeer(peer: chatPeer), accountPeerId: item.context.account.peerId)
var result = ""
result += "\(messageText)"
value = result
} else {
value = "Empty"
}
self.label = label
self.value = value
}
}
public class ChatMessageItemView: ListViewItemNode {
let layoutConstants = defaultChatMessageItemLayoutConstants
var item: ChatMessageItem?
override public var accessibilityLabel: String? {
get {
guard let item = self.item else {
return nil
}
if let author = item.message.author {
if item.message.effectivelyIncoming(item.context.account.peerId) {
return author.displayTitle
} else {
return "Outgoing message"
}
} else {
return "Message"
}
} set(value) {
}
}
override public var accessibilityValue: String? {
get {
guard let item = self.item else {
return nil
}
if let chatPeer = item.message.peers[item.message.id.peerId] {
let (_, initialHideAuthor, messageText) = chatListItemStrings(strings: item.presentationData.strings, nameDisplayOrder: item.presentationData.nameDisplayOrder, message: item.message, chatPeer: RenderedPeer(peer: chatPeer), accountPeerId: item.context.account.peerId)
var result = ""
result += "\(messageText)"
return result
} else {
return "Empty"
}
} set(value) {
}
}
public required convenience init() {
self.init(layerBacked: false)
}

View File

@ -114,7 +114,7 @@ struct ChatRecentActionsEntry: Comparable, Identifiable {
let action = TelegramMediaActionType.titleUpdated(title: new)
let message = Message(stableId: self.entry.stableId, stableVersion: 0, id: MessageId(peerId: peer.id, namespace: Namespaces.Message.Cloud, id: Int32(bitPattern: self.entry.stableId)), globallyUniqueId: self.entry.event.id, groupingKey: nil, groupInfo: nil, timestamp: self.entry.event.date, flags: [.Incoming], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: author, text: "", attributes: [], media: [TelegramMediaAction(action: action)], peers: peers, associatedMessages: SimpleDictionary(), associatedMessageIds: [])
return ChatMessageItem(presentationData: self.presentationData, context: context, chatLocation: .peer(peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadNetworkType: .cellular, isRecentActions: true), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, isAdmin: false))
return ChatMessageItem(presentationData: self.presentationData, context: context, chatLocation: .peer(peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadNetworkType: .cellular, isRecentActions: true), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, attributes: ChatMessageEntryAttributes(isAdmin: false, isContact: false)))
case let .changeAbout(prev, new):
var peers = SimpleDictionary<PeerId, Peer>()
var author: Peer?
@ -145,14 +145,14 @@ struct ChatRecentActionsEntry: Comparable, Identifiable {
}
let action = TelegramMediaActionType.customText(text: text, entities: entities)
let message = Message(stableId: 0, stableVersion: 0, id: MessageId(peerId: peer.id, namespace: Namespaces.Message.Cloud, id: 1), globallyUniqueId: self.entry.event.id, groupingKey: nil, groupInfo: nil, timestamp: self.entry.event.date, flags: [.Incoming], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: author, text: "", attributes: [], media: [TelegramMediaAction(action: action)], peers: peers, associatedMessages: SimpleDictionary(), associatedMessageIds: [])
return ChatMessageItem(presentationData: self.presentationData, context: context, chatLocation: .peer(peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadNetworkType: .cellular, isRecentActions: true), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, isAdmin: false))
return ChatMessageItem(presentationData: self.presentationData, context: context, chatLocation: .peer(peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadNetworkType: .cellular, isRecentActions: true), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, attributes: ChatMessageEntryAttributes(isAdmin: false, isContact: false)))
case .content:
let peers = SimpleDictionary<PeerId, Peer>()
let attributes: [MessageAttribute] = []
let prevMessage = Message(stableId: self.entry.stableId, stableVersion: 0, id: MessageId(peerId: peer.id, namespace: Namespaces.Message.Cloud, id: Int32(bitPattern: self.entry.stableId)), globallyUniqueId: self.entry.event.id, groupingKey: nil, groupInfo: nil, timestamp: self.entry.event.date, flags: [.Incoming], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: author, text: prev, attributes: [], media: [], peers: peers, associatedMessages: SimpleDictionary(), associatedMessageIds: [])
let message = Message(stableId: self.entry.stableId, stableVersion: 0, id: MessageId(peerId: peer.id, namespace: Namespaces.Message.Cloud, id: Int32(bitPattern: self.entry.stableId)), globallyUniqueId: self.entry.event.id, groupingKey: nil, groupInfo: nil, timestamp: self.entry.event.date, flags: [.Incoming], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: author, text: new, attributes: attributes, media: [], peers: peers, associatedMessages: SimpleDictionary(), associatedMessageIds: [])
return ChatMessageItem(presentationData: self.presentationData, context: context, chatLocation: .peer(peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadNetworkType: .cellular, isRecentActions: true), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, isAdmin: false), additionalContent: !prev.isEmpty ? .eventLogPreviousDescription(prevMessage) : nil)
return ChatMessageItem(presentationData: self.presentationData, context: context, chatLocation: .peer(peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadNetworkType: .cellular, isRecentActions: true), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, attributes: ChatMessageEntryAttributes(isAdmin: false, isContact: false)), additionalContent: !prev.isEmpty ? .eventLogPreviousDescription(prevMessage) : nil)
}
case let .changeUsername(prev, new):
var peers = SimpleDictionary<PeerId, Peer>()
@ -183,7 +183,7 @@ struct ChatRecentActionsEntry: Comparable, Identifiable {
}
let action: TelegramMediaActionType = TelegramMediaActionType.customText(text: text, entities: entities)
let message = Message(stableId: 0, stableVersion: 0, id: MessageId(peerId: peer.id, namespace: Namespaces.Message.Cloud, id: 1), globallyUniqueId: self.entry.event.id, groupingKey: nil, groupInfo: nil, timestamp: self.entry.event.date, flags: [.Incoming], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: author, text: "", attributes: [], media: [TelegramMediaAction(action: action)], peers: peers, associatedMessages: SimpleDictionary(), associatedMessageIds: [])
return ChatMessageItem(presentationData: self.presentationData, context: context, chatLocation: .peer(peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadNetworkType: .cellular, isRecentActions: true), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, isAdmin: false))
return ChatMessageItem(presentationData: self.presentationData, context: context, chatLocation: .peer(peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadNetworkType: .cellular, isRecentActions: true), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, attributes: ChatMessageEntryAttributes(isAdmin: false, isContact: false)))
case .content:
var previousAttributes: [MessageAttribute] = []
var attributes: [MessageAttribute] = []
@ -202,7 +202,7 @@ struct ChatRecentActionsEntry: Comparable, Identifiable {
let prevMessage = Message(stableId: 0, stableVersion: 0, id: MessageId(peerId: peer.id, namespace: Namespaces.Message.Cloud, id: 1), globallyUniqueId: self.entry.event.id, groupingKey: nil, groupInfo: nil, timestamp: self.entry.event.date, flags: [.Incoming], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: author, text: prevText, attributes: previousAttributes, media: [], peers: peers, associatedMessages: SimpleDictionary(), associatedMessageIds: [])
let message = Message(stableId: self.entry.stableId, stableVersion: 0, id: MessageId(peerId: peer.id, namespace: Namespaces.Message.Cloud, id: Int32(bitPattern: self.entry.stableId)), globallyUniqueId: self.entry.event.id, groupingKey: nil, groupInfo: nil, timestamp: self.entry.event.date, flags: [.Incoming], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: author, text: text, attributes: attributes, media: [], peers: peers, associatedMessages: SimpleDictionary(), associatedMessageIds: [])
return ChatMessageItem(presentationData: self.presentationData, context: context, chatLocation: .peer(peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadNetworkType: .cellular, isRecentActions: true), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, isAdmin: false), additionalContent: !prev.isEmpty ? .eventLogPreviousLink(prevMessage) : nil)
return ChatMessageItem(presentationData: self.presentationData, context: context, chatLocation: .peer(peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadNetworkType: .cellular, isRecentActions: true), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, attributes: ChatMessageEntryAttributes(isAdmin: false, isContact: false)), additionalContent: !prev.isEmpty ? .eventLogPreviousLink(prevMessage) : nil)
}
case let .changePhoto(_, new):
var peers = SimpleDictionary<PeerId, Peer>()
@ -220,7 +220,7 @@ struct ChatRecentActionsEntry: Comparable, Identifiable {
let action = TelegramMediaActionType.photoUpdated(image: photo)
let message = Message(stableId: self.entry.stableId, stableVersion: 0, id: MessageId(peerId: peer.id, namespace: Namespaces.Message.Cloud, id: Int32(bitPattern: self.entry.stableId)), globallyUniqueId: self.entry.event.id, groupingKey: nil, groupInfo: nil, timestamp: self.entry.event.date, flags: [.Incoming], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: author, text: "", attributes: [], media: [TelegramMediaAction(action: action)], peers: peers, associatedMessages: SimpleDictionary(), associatedMessageIds: [])
return ChatMessageItem(presentationData: self.presentationData, context: context, chatLocation: .peer(peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadNetworkType: .cellular, isRecentActions: true), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, isAdmin: false))
return ChatMessageItem(presentationData: self.presentationData, context: context, chatLocation: .peer(peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadNetworkType: .cellular, isRecentActions: true), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, attributes: ChatMessageEntryAttributes(isAdmin: false, isContact: false)))
case let .toggleInvites(value):
var peers = SimpleDictionary<PeerId, Peer>()
var author: Peer?
@ -247,7 +247,7 @@ struct ChatRecentActionsEntry: Comparable, Identifiable {
}
let action = TelegramMediaActionType.customText(text: text, entities: entities)
let message = Message(stableId: self.entry.stableId, stableVersion: 0, id: MessageId(peerId: peer.id, namespace: Namespaces.Message.Cloud, id: Int32(bitPattern: self.entry.stableId)), globallyUniqueId: self.entry.event.id, groupingKey: nil, groupInfo: nil, timestamp: self.entry.event.date, flags: [.Incoming], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: author, text: "", attributes: [], media: [TelegramMediaAction(action: action)], peers: peers, associatedMessages: SimpleDictionary(), associatedMessageIds: [])
return ChatMessageItem(presentationData: self.presentationData, context: context, chatLocation: .peer(peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadNetworkType: .cellular, isRecentActions: true), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, isAdmin: false))
return ChatMessageItem(presentationData: self.presentationData, context: context, chatLocation: .peer(peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadNetworkType: .cellular, isRecentActions: true), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, attributes: ChatMessageEntryAttributes(isAdmin: false, isContact: false)))
case let .toggleSignatures(value):
var peers = SimpleDictionary<PeerId, Peer>()
var author: Peer?
@ -274,7 +274,7 @@ struct ChatRecentActionsEntry: Comparable, Identifiable {
}
let action = TelegramMediaActionType.customText(text: text, entities: entities)
let message = Message(stableId: self.entry.stableId, stableVersion: 0, id: MessageId(peerId: peer.id, namespace: Namespaces.Message.Cloud, id: Int32(bitPattern: self.entry.stableId)), globallyUniqueId: self.entry.event.id, groupingKey: nil, groupInfo: nil, timestamp: self.entry.event.date, flags: [.Incoming], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: author, text: "", attributes: [], media: [TelegramMediaAction(action: action)], peers: peers, associatedMessages: SimpleDictionary(), associatedMessageIds: [])
return ChatMessageItem(presentationData: self.presentationData, context: context, chatLocation: .peer(peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadNetworkType: .cellular, isRecentActions: true), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, isAdmin: false))
return ChatMessageItem(presentationData: self.presentationData, context: context, chatLocation: .peer(peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadNetworkType: .cellular, isRecentActions: true), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, attributes: ChatMessageEntryAttributes(isAdmin: false, isContact: false)))
case let .updatePinned(message):
switch self.id.contentIndex {
case .header:
@ -296,7 +296,7 @@ struct ChatRecentActionsEntry: Comparable, Identifiable {
let action = TelegramMediaActionType.customText(text: text, entities: entities)
let message = Message(stableId: 0, stableVersion: 0, id: MessageId(peerId: peer.id, namespace: Namespaces.Message.Cloud, id: 1), globallyUniqueId: self.entry.event.id, groupingKey: nil, groupInfo: nil, timestamp: self.entry.event.date, flags: [.Incoming], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: author, text: "", attributes: [], media: [TelegramMediaAction(action: action)], peers: peers, associatedMessages: SimpleDictionary(), associatedMessageIds: [])
return ChatMessageItem(presentationData: self.presentationData, context: context, chatLocation: .peer(peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadNetworkType: .cellular, isRecentActions: true), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, isAdmin: false))
return ChatMessageItem(presentationData: self.presentationData, context: context, chatLocation: .peer(peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadNetworkType: .cellular, isRecentActions: true), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, attributes: ChatMessageEntryAttributes(isAdmin: false, isContact: false)))
case .content:
if let message = message {
var peers = SimpleDictionary<PeerId, Peer>()
@ -314,7 +314,7 @@ struct ChatRecentActionsEntry: Comparable, Identifiable {
}
}
let message = Message(stableId: self.entry.stableId, stableVersion: 0, id: MessageId(peerId: peer.id, namespace: Namespaces.Message.Cloud, id: Int32(bitPattern: self.entry.stableId)), globallyUniqueId: self.entry.event.id, groupingKey: nil, groupInfo: nil, timestamp: self.entry.event.date, flags: [.Incoming], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: message.author, text: message.text, attributes: attributes, media: message.media, peers: peers, associatedMessages: SimpleDictionary(), associatedMessageIds: [])
return ChatMessageItem(presentationData: self.presentationData, context: context, chatLocation: .peer(peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadNetworkType: .cellular, isRecentActions: true), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, isAdmin: false))
return ChatMessageItem(presentationData: self.presentationData, context: context, chatLocation: .peer(peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadNetworkType: .cellular, isRecentActions: true), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, attributes: ChatMessageEntryAttributes(isAdmin: false, isContact: false)))
} else {
var peers = SimpleDictionary<PeerId, Peer>()
var author: Peer?
@ -336,7 +336,7 @@ struct ChatRecentActionsEntry: Comparable, Identifiable {
let action = TelegramMediaActionType.customText(text: text, entities: entities)
let message = Message(stableId: self.entry.stableId, stableVersion: 0, id: MessageId(peerId: peer.id, namespace: Namespaces.Message.Cloud, id: 0), globallyUniqueId: self.entry.event.id, groupingKey: nil, groupInfo: nil, timestamp: self.entry.event.date, flags: [.Incoming], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: author, text: "", attributes: [], media: [TelegramMediaAction(action: action)], peers: peers, associatedMessages: SimpleDictionary(), associatedMessageIds: [])
return ChatMessageItem(presentationData: self.presentationData, context: context, chatLocation: .peer(peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadNetworkType: .cellular, isRecentActions: true), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, isAdmin: false))
return ChatMessageItem(presentationData: self.presentationData, context: context, chatLocation: .peer(peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadNetworkType: .cellular, isRecentActions: true), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, attributes: ChatMessageEntryAttributes(isAdmin: false, isContact: false)))
}
}
case let .editMessage(prev, message):
@ -381,7 +381,7 @@ struct ChatRecentActionsEntry: Comparable, Identifiable {
let action = TelegramMediaActionType.customText(text: text, entities: entities)
let message = Message(stableId: 0, stableVersion: 0, id: MessageId(peerId: peer.id, namespace: Namespaces.Message.Cloud, id: 1), globallyUniqueId: self.entry.event.id, groupingKey: nil, groupInfo: nil, timestamp: self.entry.event.date, flags: [.Incoming], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: author, text: "", attributes: [], media: [TelegramMediaAction(action: action)], peers: peers, associatedMessages: SimpleDictionary(), associatedMessageIds: [])
return ChatMessageItem(presentationData: self.presentationData, context: context, chatLocation: .peer(peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadNetworkType: .cellular, isRecentActions: true), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, isAdmin: false))
return ChatMessageItem(presentationData: self.presentationData, context: context, chatLocation: .peer(peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadNetworkType: .cellular, isRecentActions: true), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, attributes: ChatMessageEntryAttributes(isAdmin: false, isContact: false)))
case .content:
var peers = SimpleDictionary<PeerId, Peer>()
var attributes: [MessageAttribute] = []
@ -398,7 +398,7 @@ struct ChatRecentActionsEntry: Comparable, Identifiable {
}
}
let message = Message(stableId: self.entry.stableId, stableVersion: 0, id: MessageId(peerId: peer.id, namespace: Namespaces.Message.Cloud, id: Int32(bitPattern: self.entry.stableId)), globallyUniqueId: self.entry.event.id, groupingKey: nil, groupInfo: nil, timestamp: self.entry.event.date, flags: [.Incoming], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: message.author, text: message.text, attributes: attributes, media: message.media, peers: peers, associatedMessages: SimpleDictionary(), associatedMessageIds: [])
return ChatMessageItem(presentationData: self.presentationData, context: context, chatLocation: .peer(peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadNetworkType: .cellular, isRecentActions: true), controllerInteraction: controllerInteraction, content: .message(message: filterOriginalMessageFlags(message), read: true, selection: .none, isAdmin: false), additionalContent: !prev.text.isEmpty || !message.text.isEmpty ? .eventLogPreviousMessage(filterOriginalMessageFlags(prev)) : nil)
return ChatMessageItem(presentationData: self.presentationData, context: context, chatLocation: .peer(peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadNetworkType: .cellular, isRecentActions: true), controllerInteraction: controllerInteraction, content: .message(message: filterOriginalMessageFlags(message), read: true, selection: .none, attributes: ChatMessageEntryAttributes(isAdmin: false, isContact: false)), additionalContent: !prev.text.isEmpty || !message.text.isEmpty ? .eventLogPreviousMessage(filterOriginalMessageFlags(prev)) : nil)
}
case let .deleteMessage(message):
switch self.id.contentIndex {
@ -424,7 +424,7 @@ struct ChatRecentActionsEntry: Comparable, Identifiable {
let action = TelegramMediaActionType.customText(text: text, entities: entities)
let message = Message(stableId: 0, stableVersion: 0, id: MessageId(peerId: peer.id, namespace: Namespaces.Message.Cloud, id: 1), globallyUniqueId: self.entry.event.id, groupingKey: nil, groupInfo: nil, timestamp: self.entry.event.date, flags: [.Incoming], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: author, text: "", attributes: [], media: [TelegramMediaAction(action: action)], peers: peers, associatedMessages: SimpleDictionary(), associatedMessageIds: [])
return ChatMessageItem(presentationData: self.presentationData, context: context, chatLocation: .peer(peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadNetworkType: .cellular, isRecentActions: true), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, isAdmin: false))
return ChatMessageItem(presentationData: self.presentationData, context: context, chatLocation: .peer(peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadNetworkType: .cellular, isRecentActions: true), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, attributes: ChatMessageEntryAttributes(isAdmin: false, isContact: false)))
case .content:
var peers = SimpleDictionary<PeerId, Peer>()
var attributes: [MessageAttribute] = []
@ -448,7 +448,7 @@ struct ChatRecentActionsEntry: Comparable, Identifiable {
}
}
let message = Message(stableId: self.entry.stableId, stableVersion: 0, id: MessageId(peerId: peer.id, namespace: Namespaces.Message.Cloud, id: Int32(bitPattern: self.entry.stableId)), globallyUniqueId: self.entry.event.id, groupingKey: nil, groupInfo: nil, timestamp: self.entry.event.date, flags: [.Incoming], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: message.author, text: message.text, attributes: attributes, media: message.media, peers: peers, associatedMessages: SimpleDictionary(), associatedMessageIds: [])
return ChatMessageItem(presentationData: self.presentationData, context: context, chatLocation: .peer(peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadNetworkType: .cellular, isRecentActions: true), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, isAdmin: false))
return ChatMessageItem(presentationData: self.presentationData, context: context, chatLocation: .peer(peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadNetworkType: .cellular, isRecentActions: true), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, attributes: ChatMessageEntryAttributes(isAdmin: false, isContact: false)))
}
case .participantJoin, .participantLeave:
var peers = SimpleDictionary<PeerId, Peer>()
@ -466,7 +466,7 @@ struct ChatRecentActionsEntry: Comparable, Identifiable {
action = TelegramMediaActionType.removedMembers(peerIds: [self.entry.event.peerId])
}
let message = Message(stableId: self.entry.stableId, stableVersion: 0, id: MessageId(peerId: peer.id, namespace: Namespaces.Message.Cloud, id: Int32(bitPattern: self.entry.stableId)), globallyUniqueId: self.entry.event.id, groupingKey: nil, groupInfo: nil, timestamp: self.entry.event.date, flags: [.Incoming], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: author, text: "", attributes: [], media: [TelegramMediaAction(action: action)], peers: peers, associatedMessages: SimpleDictionary(), associatedMessageIds: [])
return ChatMessageItem(presentationData: self.presentationData, context: context, chatLocation: .peer(peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadNetworkType: .cellular, isRecentActions: true), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, isAdmin: false))
return ChatMessageItem(presentationData: self.presentationData, context: context, chatLocation: .peer(peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadNetworkType: .cellular, isRecentActions: true), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, attributes: ChatMessageEntryAttributes(isAdmin: false, isContact: false)))
case let .participantInvite(participant):
var peers = SimpleDictionary<PeerId, Peer>()
var author: Peer?
@ -483,7 +483,7 @@ struct ChatRecentActionsEntry: Comparable, Identifiable {
let action: TelegramMediaActionType
action = TelegramMediaActionType.addedMembers(peerIds: [participant.peer.id])
let message = Message(stableId: self.entry.stableId, stableVersion: 0, id: MessageId(peerId: peer.id, namespace: Namespaces.Message.Cloud, id: Int32(bitPattern: self.entry.stableId)), globallyUniqueId: self.entry.event.id, groupingKey: nil, groupInfo: nil, timestamp: self.entry.event.date, flags: [.Incoming], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: author, text: "", attributes: [], media: [TelegramMediaAction(action: action)], peers: peers, associatedMessages: SimpleDictionary(), associatedMessageIds: [])
return ChatMessageItem(presentationData: self.presentationData, context: context, chatLocation: .peer(peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadNetworkType: .cellular, isRecentActions: true), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, isAdmin: false))
return ChatMessageItem(presentationData: self.presentationData, context: context, chatLocation: .peer(peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadNetworkType: .cellular, isRecentActions: true), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, attributes: ChatMessageEntryAttributes(isAdmin: false, isContact: false)))
case let .participantToggleBan(prev, new):
var peers = SimpleDictionary<PeerId, Peer>()
var attributes: [MessageAttribute] = []
@ -613,7 +613,7 @@ struct ChatRecentActionsEntry: Comparable, Identifiable {
}
}
let message = Message(stableId: self.entry.stableId, stableVersion: 0, id: MessageId(peerId: peer.id, namespace: Namespaces.Message.Cloud, id: Int32(bitPattern: self.entry.stableId)), globallyUniqueId: self.entry.event.id, groupingKey: nil, groupInfo: nil, timestamp: self.entry.event.date, flags: [.Incoming], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: author, text: text, attributes: attributes, media: [], peers: peers, associatedMessages: SimpleDictionary(), associatedMessageIds: [])
return ChatMessageItem(presentationData: self.presentationData, context: context, chatLocation: .peer(peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadNetworkType: .cellular, isRecentActions: true), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, isAdmin: false))
return ChatMessageItem(presentationData: self.presentationData, context: context, chatLocation: .peer(peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadNetworkType: .cellular, isRecentActions: true), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, attributes: ChatMessageEntryAttributes(isAdmin: false, isContact: false)))
case let .participantToggleAdmin(prev, new):
var peers = SimpleDictionary<PeerId, Peer>()
var attributes: [MessageAttribute] = []
@ -693,7 +693,7 @@ struct ChatRecentActionsEntry: Comparable, Identifiable {
}
}
let message = Message(stableId: self.entry.stableId, stableVersion: 0, id: MessageId(peerId: peer.id, namespace: Namespaces.Message.Cloud, id: Int32(bitPattern: self.entry.stableId)), globallyUniqueId: self.entry.event.id, groupingKey: nil, groupInfo: nil, timestamp: self.entry.event.date, flags: [.Incoming], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: author, text: text, attributes: attributes, media: [], peers: peers, associatedMessages: SimpleDictionary(), associatedMessageIds: [])
return ChatMessageItem(presentationData: self.presentationData, context: context, chatLocation: .peer(peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadNetworkType: .cellular, isRecentActions: true), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, isAdmin: false))
return ChatMessageItem(presentationData: self.presentationData, context: context, chatLocation: .peer(peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadNetworkType: .cellular, isRecentActions: true), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, attributes: ChatMessageEntryAttributes(isAdmin: false, isContact: false)))
case let .changeStickerPack(_, new):
var peers = SimpleDictionary<PeerId, Peer>()
var author: Peer?
@ -722,7 +722,7 @@ struct ChatRecentActionsEntry: Comparable, Identifiable {
let action = TelegramMediaActionType.customText(text: text, entities: entities)
let message = Message(stableId: self.entry.stableId, stableVersion: 0, id: MessageId(peerId: peer.id, namespace: Namespaces.Message.Cloud, id: Int32(bitPattern: self.entry.stableId)), globallyUniqueId: self.entry.event.id, groupingKey: nil, groupInfo: nil, timestamp: self.entry.event.date, flags: [.Incoming], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: author, text: "", attributes: [], media: [TelegramMediaAction(action: action)], peers: peers, associatedMessages: SimpleDictionary(), associatedMessageIds: [])
return ChatMessageItem(presentationData: self.presentationData, context: context, chatLocation: .peer(peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadNetworkType: .cellular, isRecentActions: true), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, isAdmin: false))
return ChatMessageItem(presentationData: self.presentationData, context: context, chatLocation: .peer(peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadNetworkType: .cellular, isRecentActions: true), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, attributes: ChatMessageEntryAttributes(isAdmin: false, isContact: false)))
case let .togglePreHistoryHidden(value):
var peers = SimpleDictionary<PeerId, Peer>()
var author: Peer?
@ -752,7 +752,7 @@ struct ChatRecentActionsEntry: Comparable, Identifiable {
let action = TelegramMediaActionType.customText(text: text, entities: entities)
let message = Message(stableId: self.entry.stableId, stableVersion: 0, id: MessageId(peerId: peer.id, namespace: Namespaces.Message.Cloud, id: Int32(bitPattern: self.entry.stableId)), globallyUniqueId: self.entry.event.id, groupingKey: nil, groupInfo: nil, timestamp: self.entry.event.date, flags: [.Incoming], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: author, text: "", attributes: [], media: [TelegramMediaAction(action: action)], peers: peers, associatedMessages: SimpleDictionary(), associatedMessageIds: [])
return ChatMessageItem(presentationData: self.presentationData, context: context, chatLocation: .peer(peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadNetworkType: .cellular, isRecentActions: true), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, isAdmin: false))
return ChatMessageItem(presentationData: self.presentationData, context: context, chatLocation: .peer(peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadNetworkType: .cellular, isRecentActions: true), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, attributes: ChatMessageEntryAttributes(isAdmin: false, isContact: false)))
case let .updateDefaultBannedRights(prev, new):
var peers = SimpleDictionary<PeerId, Peer>()
var attributes: [MessageAttribute] = []
@ -810,7 +810,7 @@ struct ChatRecentActionsEntry: Comparable, Identifiable {
}
}
let message = Message(stableId: self.entry.stableId, stableVersion: 0, id: MessageId(peerId: peer.id, namespace: Namespaces.Message.Cloud, id: Int32(bitPattern: self.entry.stableId)), globallyUniqueId: self.entry.event.id, groupingKey: nil, groupInfo: nil, timestamp: self.entry.event.date, flags: [.Incoming], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: author, text: text, attributes: attributes, media: [], peers: peers, associatedMessages: SimpleDictionary(), associatedMessageIds: [])
return ChatMessageItem(presentationData: self.presentationData, context: context, chatLocation: .peer(peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadNetworkType: .cellular, isRecentActions: true), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, isAdmin: false))
return ChatMessageItem(presentationData: self.presentationData, context: context, chatLocation: .peer(peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadNetworkType: .cellular, isRecentActions: true), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, attributes: ChatMessageEntryAttributes(isAdmin: false, isContact: false)))
case let .pollStopped(message):
switch self.id.contentIndex {
case .header:
@ -838,7 +838,7 @@ struct ChatRecentActionsEntry: Comparable, Identifiable {
let action = TelegramMediaActionType.customText(text: text, entities: entities)
let message = Message(stableId: 0, stableVersion: 0, id: MessageId(peerId: peer.id, namespace: Namespaces.Message.Cloud, id: 1), globallyUniqueId: self.entry.event.id, groupingKey: nil, groupInfo: nil, timestamp: self.entry.event.date, flags: [.Incoming], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: author, text: "", attributes: [], media: [TelegramMediaAction(action: action)], peers: peers, associatedMessages: SimpleDictionary(), associatedMessageIds: [])
return ChatMessageItem(presentationData: self.presentationData, context: context, chatLocation: .peer(peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadNetworkType: .cellular, isRecentActions: true), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, isAdmin: false))
return ChatMessageItem(presentationData: self.presentationData, context: context, chatLocation: .peer(peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadNetworkType: .cellular, isRecentActions: true), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, attributes: ChatMessageEntryAttributes(isAdmin: false, isContact: false)))
case .content:
var peers = SimpleDictionary<PeerId, Peer>()
var attributes: [MessageAttribute] = []
@ -855,7 +855,7 @@ struct ChatRecentActionsEntry: Comparable, Identifiable {
}
}
let message = Message(stableId: self.entry.stableId, stableVersion: 0, id: MessageId(peerId: peer.id, namespace: Namespaces.Message.Cloud, id: Int32(bitPattern: self.entry.stableId)), globallyUniqueId: self.entry.event.id, groupingKey: nil, groupInfo: nil, timestamp: self.entry.event.date, flags: [.Incoming], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: message.author, text: message.text, attributes: attributes, media: message.media, peers: peers, associatedMessages: SimpleDictionary(), associatedMessageIds: [])
return ChatMessageItem(presentationData: self.presentationData, context: context, chatLocation: .peer(peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadNetworkType: .cellular, isRecentActions: true), controllerInteraction: controllerInteraction, content: .message(message: filterOriginalMessageFlags(message), read: true, selection: .none, isAdmin: false), additionalContent: nil)
return ChatMessageItem(presentationData: self.presentationData, context: context, chatLocation: .peer(peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadNetworkType: .cellular, isRecentActions: true), controllerInteraction: controllerInteraction, content: .message(message: filterOriginalMessageFlags(message), read: true, selection: .none, attributes: ChatMessageEntryAttributes(isAdmin: false, isContact: false)), additionalContent: nil)
}
}
}

View File

@ -16,6 +16,9 @@ final class ChatTextInputActionButtonsNode: ASDisplayNode {
super.init()
self.isAccessibilityElement = true
self.accessibilityTraits = UIAccessibilityTraitButton | UIAccessibilityTraitNotEnabled
self.view.addSubview(self.micButton)
self.view.addSubview(self.sendButton)
self.addSubnode(self.expandMediaInputButton)
@ -37,4 +40,14 @@ final class ChatTextInputActionButtonsNode: ASDisplayNode {
}
transition.updateSublayerTransformScale(node: self.expandMediaInputButton, scale: CGPoint(x: 1.0, y: expanded ? 1.0 : -1.0))
}
func updateAccessibility() {
if self.sendButton.alpha.isZero {
self.accessibilityTraits = UIAccessibilityTraitButton | UIAccessibilityTraitNotEnabled
self.accessibilityLabel = "Send"
} else {
self.accessibilityTraits = UIAccessibilityTraitButton
self.accessibilityLabel = "Send"
}
}
}

View File

@ -391,6 +391,7 @@ class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDelegate {
self.actionButtons.sendButton.addTarget(self, action: #selector(self.sendButtonPressed), for: .touchUpInside)
self.actionButtons.sendButton.alpha = 0.0
self.actionButtons.updateAccessibility()
self.actionButtons.expandMediaInputButton.addTarget(self, action: #selector(self.expandButtonPressed), forControlEvents: .touchUpInside)
self.actionButtons.expandMediaInputButton.alpha = 0.0
@ -422,6 +423,12 @@ class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDelegate {
fatalError("init(coder:) has not been implemented")
}
func loadTextInputNodeIfNeeded() {
if self.textInputNode == nil {
self.loadTextInputNode()
}
}
private func loadTextInputNode() {
let textInputNode = EditableTextNode()
textInputNode.initialPrimaryLanguage = self.presentationInterfaceState?.interfaceState.inputLanguage
@ -1109,6 +1116,7 @@ class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDelegate {
if !self.actionButtons.sendButton.alpha.isZero {
self.actionButtons.sendButton.alpha = 0.0
self.actionButtons.updateAccessibility()
if animated {
self.actionButtons.animatingSendButton = true
self.actionButtons.sendButton.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.2, completion: { [weak self] _ in
@ -1142,6 +1150,7 @@ class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDelegate {
hideMicButton = true
if self.actionButtons.sendButton.alpha.isZero {
self.actionButtons.sendButton.alpha = 1.0
self.actionButtons.updateAccessibility()
if animated {
self.actionButtons.sendButton.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.1)
if animateWithBounce {
@ -1154,6 +1163,7 @@ class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDelegate {
} else {
if !self.actionButtons.sendButton.alpha.isZero {
self.actionButtons.sendButton.alpha = 0.0
self.actionButtons.updateAccessibility()
if animated {
self.actionButtons.animatingSendButton = true
self.actionButtons.sendButton.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.2, completion: { [weak self] _ in

View File

@ -337,7 +337,13 @@ final class ChatTitleView: UIView, NavigationBarTitleView {
shouldUpdateLayout = true
}
} else if let _ = user.botInfo {
let string = NSAttributedString(string: self.strings.Bot_GenericBotStatus, font: Font.regular(13.0), textColor: self.theme.rootController.navigationBar.secondaryTextColor)
let statusText: String
if let phoneNumber = user.phone, phoneNumber.hasPrefix("424") {
statusText = self.strings.Bot_GenericSupportStatus
} else {
statusText = self.strings.Bot_GenericBotStatus
}
let string = NSAttributedString(string: statusText, font: Font.regular(13.0), textColor: self.theme.rootController.navigationBar.secondaryTextColor)
if self.infoNode.attributedText == nil || !self.infoNode.attributedText!.isEqual(to: string) {
self.infoNode.attributedText = string
shouldUpdateLayout = true
@ -455,9 +461,14 @@ final class ChatTitleView: UIView, NavigationBarTitleView {
break
}
self.accessibilityLabel = self.titleNode.attributedText?.string
self.accessibilityValue = self.infoNode.attributedText?.string
if shouldUpdateLayout {
self.setNeedsLayout()
}
} else {
self.accessibilityLabel = nil
}
}
@ -499,6 +510,9 @@ final class ChatTitleView: UIView, NavigationBarTitleView {
super.init(frame: CGRect())
self.isAccessibilityElement = true
self.accessibilityTraits = UIAccessibilityTraitHeader
self.addSubnode(self.contentContainer)
self.contentContainer.addSubnode(self.titleNode)
self.contentContainer.addSubnode(self.infoNode)

View File

@ -101,7 +101,7 @@ final class ComposeControllerNode: ASDisplayNode {
searchDisplayController.containerLayoutUpdated(layout, navigationBarHeight: navigationBarHeight, transition: transition)
}
self.contactListNode.containerLayoutUpdated(ContainerViewLayout(size: layout.size, metrics: layout.metrics, intrinsicInsets: insets, safeInsets: layout.safeInsets, statusBarHeight: layout.statusBarHeight, inputHeight: layout.inputHeight, standardInputHeight: layout.standardInputHeight, inputHeightIsInteractivellyChanging: layout.inputHeightIsInteractivellyChanging), headerInsets: headerInsets, transition: transition)
self.contactListNode.containerLayoutUpdated(ContainerViewLayout(size: layout.size, metrics: layout.metrics, intrinsicInsets: insets, safeInsets: layout.safeInsets, statusBarHeight: layout.statusBarHeight, inputHeight: layout.inputHeight, standardInputHeight: layout.standardInputHeight, inputHeightIsInteractivellyChanging: layout.inputHeightIsInteractivellyChanging, inVoiceOver: layout.inVoiceOver), headerInsets: headerInsets, transition: transition)
self.contactListNode.frame = CGRect(origin: CGPoint(), size: layout.size)
}

View File

@ -115,7 +115,7 @@ final class ContactMultiselectionControllerNode: ASDisplayNode {
var headerInsets = layout.insets(options: [.input])
headerInsets.top += actualNavigationBarHeight
headerInsets.top += strongSelf.tokenListNode.bounds.size.height
searchResultsNode.containerLayoutUpdated(ContainerViewLayout(size: layout.size, metrics: layout.metrics, intrinsicInsets: insets, safeInsets: layout.safeInsets, statusBarHeight: layout.statusBarHeight, inputHeight: layout.inputHeight, standardInputHeight: layout.standardInputHeight, inputHeightIsInteractivellyChanging: layout.inputHeightIsInteractivellyChanging), headerInsets: headerInsets, transition: .immediate)
searchResultsNode.containerLayoutUpdated(ContainerViewLayout(size: layout.size, metrics: layout.metrics, intrinsicInsets: insets, safeInsets: layout.safeInsets, statusBarHeight: layout.statusBarHeight, inputHeight: layout.inputHeight, standardInputHeight: layout.standardInputHeight, inputHeightIsInteractivellyChanging: layout.inputHeightIsInteractivellyChanging, inVoiceOver: layout.inVoiceOver), headerInsets: headerInsets, transition: .immediate)
searchResultsNode.frame = CGRect(origin: CGPoint(), size: layout.size)
}
@ -168,11 +168,11 @@ final class ContactMultiselectionControllerNode: ASDisplayNode {
insets.top += tokenListHeight
headerInsets.top += tokenListHeight
self.contactListNode.containerLayoutUpdated(ContainerViewLayout(size: layout.size, metrics: layout.metrics, intrinsicInsets: insets, safeInsets: layout.safeInsets, statusBarHeight: layout.statusBarHeight, inputHeight: layout.inputHeight, standardInputHeight: layout.standardInputHeight, inputHeightIsInteractivellyChanging: layout.inputHeightIsInteractivellyChanging), headerInsets: headerInsets, transition: transition)
self.contactListNode.containerLayoutUpdated(ContainerViewLayout(size: layout.size, metrics: layout.metrics, intrinsicInsets: insets, safeInsets: layout.safeInsets, statusBarHeight: layout.statusBarHeight, inputHeight: layout.inputHeight, standardInputHeight: layout.standardInputHeight, inputHeightIsInteractivellyChanging: layout.inputHeightIsInteractivellyChanging, inVoiceOver: layout.inVoiceOver), headerInsets: headerInsets, transition: transition)
self.contactListNode.frame = CGRect(origin: CGPoint(), size: layout.size)
if let searchResultsNode = self.searchResultsNode {
searchResultsNode.containerLayoutUpdated(ContainerViewLayout(size: layout.size, metrics: layout.metrics, intrinsicInsets: insets, safeInsets: layout.safeInsets, statusBarHeight: layout.statusBarHeight, inputHeight: layout.inputHeight, standardInputHeight: layout.standardInputHeight, inputHeightIsInteractivellyChanging: layout.inputHeightIsInteractivellyChanging), headerInsets: headerInsets, transition: transition)
searchResultsNode.containerLayoutUpdated(ContainerViewLayout(size: layout.size, metrics: layout.metrics, intrinsicInsets: insets, safeInsets: layout.safeInsets, statusBarHeight: layout.statusBarHeight, inputHeight: layout.inputHeight, standardInputHeight: layout.standardInputHeight, inputHeightIsInteractivellyChanging: layout.inputHeightIsInteractivellyChanging, inVoiceOver: layout.inVoiceOver), headerInsets: headerInsets, transition: transition)
searchResultsNode.frame = CGRect(origin: CGPoint(), size: layout.size)
}
}

View File

@ -95,7 +95,7 @@ final class ContactSelectionControllerNode: ASDisplayNode {
searchDisplayController.containerLayoutUpdated(layout, navigationBarHeight: navigationBarHeight, transition: transition)
}
self.contactListNode.containerLayoutUpdated(ContainerViewLayout(size: layout.size, metrics: layout.metrics, intrinsicInsets: insets, safeInsets: layout.safeInsets, statusBarHeight: layout.statusBarHeight, inputHeight: layout.inputHeight, standardInputHeight: layout.standardInputHeight, inputHeightIsInteractivellyChanging: layout.inputHeightIsInteractivellyChanging), headerInsets: headerInsets, transition: transition)
self.contactListNode.containerLayoutUpdated(ContainerViewLayout(size: layout.size, metrics: layout.metrics, intrinsicInsets: insets, safeInsets: layout.safeInsets, statusBarHeight: layout.statusBarHeight, inputHeight: layout.inputHeight, standardInputHeight: layout.standardInputHeight, inputHeightIsInteractivellyChanging: layout.inputHeightIsInteractivellyChanging, inVoiceOver: layout.inVoiceOver), headerInsets: headerInsets, transition: transition)
self.contactListNode.frame = CGRect(origin: CGPoint(), size: layout.size)

View File

@ -113,7 +113,7 @@ final class ContactsControllerNode: ASDisplayNode {
searchDisplayController.containerLayoutUpdated(layout, navigationBarHeight: navigationBarHeight, transition: transition)
}
self.contactListNode.containerLayoutUpdated(ContainerViewLayout(size: layout.size, metrics: layout.metrics, intrinsicInsets: insets, safeInsets: layout.safeInsets, statusBarHeight: layout.statusBarHeight, inputHeight: layout.inputHeight, standardInputHeight: layout.standardInputHeight, inputHeightIsInteractivellyChanging: layout.inputHeightIsInteractivellyChanging), headerInsets: headerInsets, transition: transition)
self.contactListNode.containerLayoutUpdated(ContainerViewLayout(size: layout.size, metrics: layout.metrics, intrinsicInsets: insets, safeInsets: layout.safeInsets, statusBarHeight: layout.statusBarHeight, inputHeight: layout.inputHeight, standardInputHeight: layout.standardInputHeight, inputHeightIsInteractivellyChanging: layout.inputHeightIsInteractivellyChanging, inVoiceOver: layout.inVoiceOver), headerInsets: headerInsets, transition: transition)
self.contactListNode.frame = CGRect(origin: CGPoint(), size: layout.size)
}

View File

@ -314,6 +314,8 @@ func editSettingsController(context: AccountContext, currentName: ItemListAvatar
let avatarAndNameInfoContext = ItemListAvatarAndNameInfoItemContext()
var updateHiddenAvatarImpl: (() -> Void)?
var changeProfilePhotoImpl: (() -> Void)?
var getNavigationController: (() -> NavigationController?)?
let arguments = EditSettingsItemArguments(context: context, accountManager: accountManager, avatarAndNameInfoContext: avatarAndNameInfoContext, avatarTapAction: {
var updating = false
@ -373,15 +375,14 @@ func editSettingsController(context: AccountContext, currentName: ItemListAvatar
let isTestingEnvironment = context.account.testingEnvironment
context.sharedContext.beginNewAuth(testingEnvironment: isTestingEnvironment)
}, logout: {
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
let alertController = standardTextAlertController(theme: AlertControllerTheme(presentationTheme: presentationData.theme), title: presentationData.strings.Settings_LogoutConfirmationTitle, text: presentationData.strings.Settings_LogoutConfirmationText, actions: [
TextAlertAction(type: .genericAction, title: presentationData.strings.Common_Cancel, action: {
}),
TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_OK, action: {
let _ = logoutFromAccount(id: context.account.id, accountManager: accountManager).start()
})
])
presentControllerImpl?(alertController, nil)
let _ = (context.account.postbox.transaction { transaction -> String in
return (transaction.getPeer(context.account.peerId) as? TelegramUser)?.phone ?? ""
}
|> deliverOnMainQueue).start(next: { phoneNumber in
if let navigationController = getNavigationController?() {
presentControllerImpl?(logoutOptionsController(context: context, navigationController: navigationController, canAddAccounts: canAddAccounts, phoneNumber: phoneNumber), ViewControllerPresentationArguments(presentationAnimation: .modalSheet))
}
})
})
let peerView = context.account.viewTracker.peerView(context.account.peerId)
@ -557,6 +558,10 @@ func editSettingsController(context: AccountContext, currentName: ItemListAvatar
})
}
getNavigationController = { [weak controller] in
return controller?.navigationController as? NavigationController
}
return controller
}

View File

@ -133,7 +133,7 @@ private func galleryMessageCaptionText(_ message: Message) -> String {
func galleryItemForEntry(context: AccountContext, presentationData: PresentationData, entry: MessageHistoryEntry, isCentral: Bool = false, streamVideos: Bool, loopVideos: Bool = false, hideControls: Bool = false, fromPlayingVideo: Bool = false, tempFilePath: String? = nil, playbackCompleted: @escaping () -> Void = {}, performAction: @escaping (GalleryControllerInteractionTapAction) -> Void = { _ in }, openActionOptions: @escaping (GalleryControllerInteractionTapAction) -> Void = { _ in }) -> GalleryItem? {
switch entry {
case let .MessageEntry(message, _, location, _):
case let .MessageEntry(message, _, location, _, _):
if let (media, mediaImage) = mediaForMessage(message: message) {
if let _ = media as? TelegramMediaImage {
return ChatImageGalleryItem(context: context, presentationData: presentationData, message: message, location: location, performAction: performAction, openActionOptions: openActionOptions)
@ -359,10 +359,10 @@ class GalleryController: ViewController {
return .single(mapped)
}
} else {
return .single(GalleryMessageHistoryView.single(MessageHistoryEntry.MessageEntry(message!, false, nil, nil)))
return .single(GalleryMessageHistoryView.single(MessageHistoryEntry.MessageEntry(message!, false, nil, nil, MutableMessageHistoryEntryAttributes(authorIsContact: false))))
}
case .standaloneMessage:
return .single(GalleryMessageHistoryView.single(MessageHistoryEntry.MessageEntry(message!, false, nil, nil)))
return .single(GalleryMessageHistoryView.single(MessageHistoryEntry.MessageEntry(message!, false, nil, nil, MutableMessageHistoryEntryAttributes(authorIsContact: false))))
}
}
|> take(1)
@ -389,7 +389,7 @@ class GalleryController: ViewController {
var centralEntryStableId: UInt32?
loop: for i in 0 ..< entries.count {
switch entries[i] {
case let .MessageEntry(message, _, _, _):
case let .MessageEntry(message, _, _, _, _):
switch source {
case let .peerMessagesAtId(messageId):
if message.id == messageId {
@ -420,7 +420,7 @@ class GalleryController: ViewController {
var centralItemIndex: Int?
for entry in strongSelf.entries {
var isCentral = false
if case let .MessageEntry(message, _, _, _) = entry, message.stableId == strongSelf.centralEntryStableId {
if case let .MessageEntry(message, _, _, _, _) = entry, message.stableId == strongSelf.centralEntryStableId {
isCentral = true
}
if let item = galleryItemForEntry(context: context, presentationData: strongSelf.presentationData, entry: entry, isCentral: isCentral, streamVideos: streamSingleVideo, fromPlayingVideo: isCentral && fromPlayingVideo, performAction: strongSelf.performAction, openActionOptions: strongSelf.openActionOptions) {
@ -717,7 +717,7 @@ class GalleryController: ViewController {
}
if let centralItemNode = self.galleryNode.pager.centralItemNode(), let presentationArguments = self.presentationArguments as? GalleryControllerPresentationArguments {
if case let .MessageEntry(message, _, _, _) = self.entries[centralItemNode.index] {
if case let .MessageEntry(message, _, _, _, _) = self.entries[centralItemNode.index] {
if let (media, _) = mediaForMessage(message: message), let transitionArguments = presentationArguments.transitionArguments(message.id, media), !forceAway {
animatedOutNode = false
centralItemNode.animateOut(to: transitionArguments.transitionNode, addToTransitionSurface: transitionArguments.addToTransitionSurface, completion: {
@ -755,7 +755,7 @@ class GalleryController: ViewController {
self.galleryNode.transitionDataForCentralItem = { [weak self] in
if let strongSelf = self {
if let centralItemNode = strongSelf.galleryNode.pager.centralItemNode(), let presentationArguments = strongSelf.presentationArguments as? GalleryControllerPresentationArguments {
if case let .MessageEntry(message, _, _, _) = strongSelf.entries[centralItemNode.index] {
if case let .MessageEntry(message, _, _, _, _) = strongSelf.entries[centralItemNode.index] {
if let (media, _) = mediaForMessage(message: message), let transitionArguments = presentationArguments.transitionArguments(message.id, media) {
return (transitionArguments.transitionNode, transitionArguments.addToTransitionSurface)
}
@ -803,7 +803,7 @@ class GalleryController: ViewController {
var centralItemIndex: Int?
for entry in self.entries {
if let item = galleryItemForEntry(context: context, presentationData: self.presentationData, entry: entry, streamVideos: self.streamVideos, fromPlayingVideo: self.fromPlayingVideo, performAction: self.performAction, openActionOptions: self.openActionOptions) {
if case let .MessageEntry(message, _, _, _) = entry, message.stableId == self.centralEntryStableId {
if case let .MessageEntry(message, _, _, _, _) = entry, message.stableId == self.centralEntryStableId {
centralItemIndex = items.count
}
items.append(item)
@ -816,7 +816,7 @@ class GalleryController: ViewController {
if let strongSelf = self {
var hiddenItem: (MessageId, Media)?
if let index = index {
if case let .MessageEntry(message, _, _, _) = strongSelf.entries[index], let (media, _) = mediaForMessage(message: message) {
if case let .MessageEntry(message, _, _, _, _) = strongSelf.entries[index], let (media, _) = mediaForMessage(message: message) {
hiddenItem = (message.id, media)
}
@ -857,7 +857,7 @@ class GalleryController: ViewController {
var nodeAnimatesItself = false
if let centralItemNode = self.galleryNode.pager.centralItemNode() {
if case let .MessageEntry(message, _, _, _) = self.entries[centralItemNode.index] {
if case let .MessageEntry(message, _, _, _, _) = self.entries[centralItemNode.index] {
self.centralItemTitle.set(centralItemNode.title())
self.centralItemTitleView.set(centralItemNode.titleView())
self.centralItemRightBarButtonItem.set(centralItemNode.rightBarButtonItem())
@ -910,7 +910,7 @@ class GalleryController: ViewController {
self.galleryNode.setControlsHidden(true, animated: false)
if let centralItemNode = self.galleryNode.pager.centralItemNode(), let itemSize = centralItemNode.contentSize() {
self.preferredContentSize = itemSize.aspectFitted(self.view.bounds.size)
self.containerLayoutUpdated(ContainerViewLayout(size: self.preferredContentSize, metrics: LayoutMetrics(), intrinsicInsets: UIEdgeInsets(), safeInsets: UIEdgeInsets(), statusBarHeight: nil, inputHeight: nil, standardInputHeight: 216.0, inputHeightIsInteractivellyChanging: false), transition: .immediate)
self.containerLayoutUpdated(ContainerViewLayout(size: self.preferredContentSize, metrics: LayoutMetrics(), intrinsicInsets: UIEdgeInsets(), safeInsets: UIEdgeInsets(), statusBarHeight: nil, inputHeight: nil, standardInputHeight: 216.0, inputHeightIsInteractivellyChanging: false, inVoiceOver: false), transition: .immediate)
}
}
}

View File

@ -263,6 +263,8 @@ class GalleryControllerNode: ASDisplayNode, UIScrollViewDelegate, UIGestureRecog
func animateOut(animateContent: Bool, completion: @escaping () -> Void) {
self.isDismissed = true
self.pager.isScrollEnabled = false
var contentAnimationCompleted = true
var interfaceAnimationCompleted = false

View File

@ -103,7 +103,7 @@ final class HashtagSearchControllerNode: ASDisplayNode {
insets.top += toolbarHeight - 4.0
let chatSize = CGSize(width: layout.size.width, height: layout.size.height)
transition.updateFrame(node: chatController.displayNode, frame: CGRect(origin: CGPoint(x: 0.0, y: 0.0), size: chatSize))
chatController.containerLayoutUpdated(ContainerViewLayout(size: chatSize, metrics: layout.metrics, intrinsicInsets: UIEdgeInsets(top: insets.top, left: 0.0, bottom: layout.intrinsicInsets.bottom, right: 0.0), safeInsets: layout.safeInsets, statusBarHeight: nil, inputHeight: nil, standardInputHeight: 216.0, inputHeightIsInteractivellyChanging: false), transition: .immediate)
chatController.containerLayoutUpdated(ContainerViewLayout(size: chatSize, metrics: layout.metrics, intrinsicInsets: UIEdgeInsets(top: insets.top, left: 0.0, bottom: layout.intrinsicInsets.bottom, right: 0.0), safeInsets: layout.safeInsets, statusBarHeight: nil, inputHeight: nil, standardInputHeight: 216.0, inputHeightIsInteractivellyChanging: false, inVoiceOver: false), transition: .immediate)
if chatController.displayNode.supernode == nil {
chatController.viewWillAppear(false)

View File

@ -1227,7 +1227,7 @@ final class InstantPageControllerNode: ASDisplayNode, UIScrollViewDelegate {
} else {
var medias: [InstantPageMedia] = mediasFromItems(items)
medias = medias.filter {
$0.media is TelegramMediaImage
return $0.media is TelegramMediaImage || $0.media is TelegramMediaFile
}
for media in medias {

View File

@ -81,6 +81,10 @@ final class InstantPageImageNode: ASDisplayNode, InstantPageNode {
} else {
self.imageNode.setSignal(chatMessageVideo(postbox: context.account.postbox, videoReference: fileReference))
}
if file.isVideo {
self.statusNode.transitionToState(.play(.white), animated: false, completion: {})
self.addSubnode(self.statusNode)
}
} else if let map = media.media as? TelegramMediaMap {
self.addSubnode(self.pinNode)

View File

@ -404,7 +404,7 @@ final class InstantPageSlideshowNode: ASDisplayNode, InstantPageNode {
super.layout()
self.pagerNode.frame = self.bounds
self.pagerNode.containerLayoutUpdated(ContainerViewLayout(size: self.bounds.size, metrics: LayoutMetrics(), intrinsicInsets: UIEdgeInsets(), safeInsets: UIEdgeInsets(), statusBarHeight: nil, inputHeight: nil, standardInputHeight: 216.0, inputHeightIsInteractivellyChanging: false), transition: .immediate)
self.pagerNode.containerLayoutUpdated(ContainerViewLayout(size: self.bounds.size, metrics: LayoutMetrics(), intrinsicInsets: UIEdgeInsets(), safeInsets: UIEdgeInsets(), statusBarHeight: nil, inputHeight: nil, standardInputHeight: 216.0, inputHeightIsInteractivellyChanging: false, inVoiceOver: false), transition: .immediate)
self.pageControlNode.layer.transform = CATransform3DIdentity
self.pageControlNode.frame = CGRect(origin: CGPoint(x: 0.0, y: self.bounds.size.height - 20.0), size: CGSize(width: self.bounds.size.width, height: 20.0))

View File

@ -421,7 +421,11 @@ class ItemListAvatarAndNameInfoItemNode: ListViewItemNode, ItemListItemNode, Ite
statusText = label
statusColor = item.theme.list.itemSecondaryTextColor
} else if let _ = peer.botInfo {
statusText = item.strings.Bot_GenericBotStatus
if let phoneNumber = peer.phone, phoneNumber.hasPrefix("424") {
statusText = item.strings.Bot_GenericSupportStatus
} else {
statusText = item.strings.Bot_GenericBotStatus
}
statusColor = item.theme.list.itemSecondaryTextColor
} else if case .generic = item.mode, !(peer.id.namespace == Namespaces.Peer.CloudUser && (peer.id.id == 777000 || peer.id.id == 333000)) {
let presence = (item.presence as? TelegramUserPresence) ?? TelegramUserPresence(status: .none, lastActivity: 0)

View File

@ -518,7 +518,7 @@ class ItemListController<Entry: ItemListNodeEntry>: ViewController {
if let controller = self.previewItemWithTag?(tag) {
if let controller = controller as? ContainableController {
controller.containerLayoutUpdated(ContainerViewLayout(size: contentSize, metrics: LayoutMetrics(), intrinsicInsets: UIEdgeInsets(), safeInsets: UIEdgeInsets(), statusBarHeight: nil, inputHeight: nil, standardInputHeight: 216.0, inputHeightIsInteractivellyChanging: false), transition: .immediate)
controller.containerLayoutUpdated(ContainerViewLayout(size: contentSize, metrics: LayoutMetrics(), intrinsicInsets: UIEdgeInsets(), safeInsets: UIEdgeInsets(), statusBarHeight: nil, inputHeight: nil, standardInputHeight: 216.0, inputHeightIsInteractivellyChanging: false, inVoiceOver: false), transition: .immediate)
}
return (controller, sourceRect)
} else {

View File

@ -16,6 +16,7 @@ enum ItemListDisclosureStyle {
enum ItemListDisclosureLabelStyle {
case text
case detailText
case multilineDetailText
case badge(UIColor)
case color(UIColor)
}
@ -221,27 +222,6 @@ class ItemListDisclosureItemNode: ListViewItemNode {
let itemSeparatorColor: UIColor
var leftInset = 16.0 + params.leftInset
let height: CGFloat
switch item.labelStyle {
case .detailText:
height = 64.0
default:
height = 44.0
}
switch item.style {
case .plain:
itemBackgroundColor = item.theme.list.plainBackgroundColor
itemSeparatorColor = item.theme.list.itemPlainSeparatorColor
contentSize = CGSize(width: params.width, height: height)
insets = itemListNeighborsPlainInsets(neighbors)
case .blocks:
itemBackgroundColor = item.theme.list.itemBlocksBackgroundColor
itemSeparatorColor = item.theme.list.itemBlocksSeparatorColor
contentSize = CGSize(width: params.width, height: height)
insets = itemListNeighborsGroupedInsets(neighbors)
}
if let _ = item.icon {
leftInset += 43.0
}
@ -262,7 +242,7 @@ class ItemListDisclosureItemNode: ListViewItemNode {
case .badge:
labelBadgeColor = item.theme.rootController.tabBar.badgeTextColor
labelFont = badgeFont
case .detailText:
case .detailText, .multilineDetailText:
labelBadgeColor = item.theme.list.itemSecondaryTextColor
labelFont = detailFont
labelConstrain = params.width - params.rightInset - 40.0 - leftInset
@ -270,8 +250,35 @@ class ItemListDisclosureItemNode: ListViewItemNode {
labelBadgeColor = item.theme.list.itemSecondaryTextColor
labelFont = titleFont
}
var multilineLabel = false
if case .multilineDetailText = item.labelStyle {
multilineLabel = true
}
let (labelLayout, labelApply) = makeLabelLayout(TextNodeLayoutArguments(attributedString: NSAttributedString(string: item.label, font: labelFont, textColor:labelBadgeColor), backgroundColor: nil, maximumNumberOfLines: 1, truncationType: .end, constrainedSize: CGSize(width: labelConstrain, height: CGFloat.greatestFiniteMagnitude), alignment: .natural, cutout: nil, insets: UIEdgeInsets()))
let (labelLayout, labelApply) = makeLabelLayout(TextNodeLayoutArguments(attributedString: NSAttributedString(string: item.label, font: labelFont, textColor:labelBadgeColor), backgroundColor: nil, maximumNumberOfLines: multilineLabel ? 0 : 1, truncationType: .end, constrainedSize: CGSize(width: labelConstrain, height: CGFloat.greatestFiniteMagnitude), alignment: .natural, cutout: nil, insets: UIEdgeInsets()))
let height: CGFloat
switch item.labelStyle {
case .detailText:
height = 64.0
case .multilineDetailText:
height = 44.0 + labelLayout.size.height
default:
height = 44.0
}
switch item.style {
case .plain:
itemBackgroundColor = item.theme.list.plainBackgroundColor
itemSeparatorColor = item.theme.list.itemPlainSeparatorColor
contentSize = CGSize(width: params.width, height: height)
insets = itemListNeighborsPlainInsets(neighbors)
case .blocks:
itemBackgroundColor = item.theme.list.itemBlocksBackgroundColor
itemSeparatorColor = item.theme.list.itemBlocksSeparatorColor
contentSize = CGSize(width: params.width, height: height)
insets = itemListNeighborsGroupedInsets(neighbors)
}
let layout = ListViewItemNodeLayout(contentSize: contentSize, insets: insets)
@ -286,7 +293,13 @@ class ItemListDisclosureItemNode: ListViewItemNode {
if updateIcon {
strongSelf.iconNode.image = icon
}
strongSelf.iconNode.frame = CGRect(origin: CGPoint(x: params.leftInset + floor((leftInset - params.leftInset - icon.size.width) / 2.0), y: floor((layout.contentSize.height - icon.size.height) / 2.0)), size: icon.size)
let iconY: CGFloat
if case .multilineDetailText = item.labelStyle {
iconY = 14.0
} else {
iconY = floor((layout.contentSize.height - icon.size.height) / 2.0)
}
strongSelf.iconNode.frame = CGRect(origin: CGPoint(x: params.leftInset + floor((leftInset - params.leftInset - icon.size.width) / 2.0), y: iconY), size: icon.size)
} else if strongSelf.iconNode.supernode != nil {
strongSelf.iconNode.image = nil
strongSelf.iconNode.removeFromSupernode()
@ -368,7 +381,7 @@ class ItemListDisclosureItemNode: ListViewItemNode {
switch item.labelStyle {
case .badge:
labelFrame = CGRect(origin: CGPoint(x: params.width - rightInset - badgeWidth + (badgeWidth - labelLayout.size.width) / 2.0, y: 13.0), size: labelLayout.size)
case .detailText:
case .detailText, .multilineDetailText:
labelFrame = CGRect(origin: CGPoint(x: leftInset, y: 36.0), size: labelLayout.size)
default:
labelFrame = CGRect(origin: CGPoint(x: params.width - rightInset - labelLayout.size.width, y: 11.0), size: labelLayout.size)

View File

@ -0,0 +1,14 @@
import Foundation
import LegacyComponents
public final class LegacyCache {
private let impl: TGCache
public init(path: String) {
self.impl = TGCache(cachesPath: path)
}
public func path(forCachedData id: String) -> String? {
return self.impl.path(forCachedData: id)
}
}

View File

@ -0,0 +1,226 @@
import Foundation
import Display
import SwiftSignalKit
import Postbox
import TelegramCore
import LegacyComponents
private final class LogoutOptionsItemIcons {
static let addAccount = UIImage(bundleImageName: "Settings/MenuIcons/AddAccount")?.precomposed()
static let setPasscode = UIImage(bundleImageName: "Settings/MenuIcons/SetPasscode")?.precomposed()
static let clearCache = UIImage(bundleImageName: "Settings/MenuIcons/ClearCache")?.precomposed()
static let changePhoneNumber = UIImage(bundleImageName: "Settings/MenuIcons/ChangePhoneNumber")?.precomposed()
static let contactSupport = UIImage(bundleImageName: "Settings/MenuIcons/Faq")?.precomposed()
}
private struct LogoutOptionsItemArguments {
let addAccount: () -> Void
let setPasscode: () -> Void
let clearCache: () -> Void
let changePhoneNumber: () -> Void
let contactSupport: () -> Void
let logout: () -> Void
}
private enum LogoutOptionsSection: Int32 {
case options
case logOut
}
private enum LogoutOptionsEntry: ItemListNodeEntry, Equatable {
case alternativeHeader(PresentationTheme, String)
case addAccount(PresentationTheme, String, String)
case setPasscode(PresentationTheme, String, String)
case clearCache(PresentationTheme, String, String)
case changePhoneNumber(PresentationTheme, String, String)
case contactSupport(PresentationTheme, String, String)
case logout(PresentationTheme, String)
case logoutInfo(PresentationTheme, String)
var section: ItemListSectionId {
switch self {
case .alternativeHeader, .addAccount, .setPasscode, .clearCache, .changePhoneNumber, .contactSupport:
return LogoutOptionsSection.options.rawValue
case .logout, .logoutInfo:
return LogoutOptionsSection.logOut.rawValue
}
}
var stableId: Int32 {
switch self {
case .alternativeHeader:
return 0
case .addAccount:
return 1
case .setPasscode:
return 2
case .clearCache:
return 3
case .changePhoneNumber:
return 4
case .contactSupport:
return 5
case .logout:
return 6
case .logoutInfo:
return 7
}
}
static func <(lhs: LogoutOptionsEntry, rhs: LogoutOptionsEntry) -> Bool {
return lhs.stableId < rhs.stableId
}
func item(_ arguments: LogoutOptionsItemArguments) -> ListViewItem {
switch self {
case let .alternativeHeader(theme, title):
return ItemListSectionHeaderItem(theme: theme, text: title, sectionId: self.section)
case let .addAccount(theme, title, text):
return ItemListDisclosureItem(theme: theme, icon: LogoutOptionsItemIcons.addAccount, title: title, label: text, labelStyle: .multilineDetailText, sectionId: self.section, style: .blocks, disclosureStyle: .arrow, action: {
arguments.addAccount()
})
case let .setPasscode(theme, title, text):
return ItemListDisclosureItem(theme: theme, icon: LogoutOptionsItemIcons.setPasscode, title: title, label: text, labelStyle: .multilineDetailText, sectionId: self.section, style: .blocks, disclosureStyle: .arrow, action: {
arguments.setPasscode()
})
case let .clearCache(theme, title, text):
return ItemListDisclosureItem(theme: theme, icon: LogoutOptionsItemIcons.clearCache, title: title, label: text, labelStyle: .multilineDetailText, sectionId: self.section, style: .blocks, disclosureStyle: .arrow, action: {
arguments.clearCache()
})
case let .changePhoneNumber(theme, title, text):
return ItemListDisclosureItem(theme: theme, icon: LogoutOptionsItemIcons.changePhoneNumber, title: title, label: text, labelStyle: .multilineDetailText, sectionId: self.section, style: .blocks, disclosureStyle: .arrow, action: {
arguments.changePhoneNumber()
})
case let .contactSupport(theme, title, text):
return ItemListDisclosureItem(theme: theme, icon: LogoutOptionsItemIcons.contactSupport, title: title, label: text, labelStyle: .multilineDetailText, sectionId: self.section, style: .blocks, disclosureStyle: .arrow, action: {
arguments.contactSupport()
})
case let .logout(theme, title):
return ItemListActionItem(theme: theme, title: title, kind: .destructive, alignment: .natural, sectionId: self.section, style: .blocks, action: {
arguments.logout()
})
case let .logoutInfo(theme, title):
return ItemListTextItem(theme: theme, text: .plain(title), sectionId: self.section)
}
}
}
private func logoutOptionsEntries(presentationData: PresentationData, canAddAccounts: Bool) -> [LogoutOptionsEntry] {
var entries: [LogoutOptionsEntry] = []
entries.append(.alternativeHeader(presentationData.theme, presentationData.strings.LogoutOptions_AlternativeOptionsSection))
entries.append(.addAccount(presentationData.theme, presentationData.strings.LogoutOptions_AddAccountTitle, presentationData.strings.LogoutOptions_AddAccountText))
entries.append(.setPasscode(presentationData.theme, presentationData.strings.LogoutOptions_SetPasscodeTitle, presentationData.strings.LogoutOptions_SetPasscodeText))
entries.append(.clearCache(presentationData.theme, presentationData.strings.LogoutOptions_ClearCacheTitle, presentationData.strings.LogoutOptions_ClearCacheText))
entries.append(.changePhoneNumber(presentationData.theme, presentationData.strings.LogoutOptions_ChangePhoneNumberTitle, presentationData.strings.LogoutOptions_ChangePhoneNumberText))
entries.append(.contactSupport(presentationData.theme, presentationData.strings.LogoutOptions_ContactSupportTitle, presentationData.strings.LogoutOptions_ContactSupportText))
entries.append(.logout(presentationData.theme, presentationData.strings.LogoutOptions_LogOut))
entries.append(.logoutInfo(presentationData.theme, presentationData.strings.LogoutOptions_LogOutInfo))
return entries
}
func logoutOptionsController(context: AccountContext, navigationController: NavigationController, canAddAccounts: Bool, phoneNumber: String) -> ViewController {
var pushControllerImpl: ((ViewController) -> Void)?
var presentControllerImpl: ((ViewController, Any?) -> Void)?
var dismissImpl: (() -> Void)?
let supportPeerDisposable = MetaDisposable()
let arguments = LogoutOptionsItemArguments(addAccount: {
let isTestingEnvironment = context.account.testingEnvironment
context.sharedContext.beginNewAuth(testingEnvironment: isTestingEnvironment)
dismissImpl?()
}, setPasscode: {
pushControllerImpl?(passcodeOptionsController(context: context))
dismissImpl?()
}, clearCache: {
pushControllerImpl?(storageUsageController(context: context))
dismissImpl?()
}, changePhoneNumber: {
pushControllerImpl?(ChangePhoneNumberIntroController(context: context, phoneNumber: phoneNumber))
dismissImpl?()
}, contactSupport: { [weak navigationController] in
let supportPeer = Promise<PeerId?>()
supportPeer.set(supportPeerId(account: context.account))
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
var faqUrl = context.sharedContext.currentPresentationData.with { $0 }.strings.Settings_FAQ_URL
if faqUrl == "Settings.FAQ_URL" || faqUrl.isEmpty {
faqUrl = "https://telegram.org/faq#general"
}
let resolvedUrl = resolveInstantViewUrl(account: context.account, url: faqUrl)
let resolvedUrlPromise = Promise<ResolvedUrl>()
resolvedUrlPromise.set(resolvedUrl)
let openFaq: (Promise<ResolvedUrl>) -> Void = { resolvedUrl in
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
let controller = OverlayStatusController(theme: presentationData.theme, strings: presentationData.strings, type: .loading(cancelled: nil))
presentControllerImpl?(controller, nil)
let _ = (resolvedUrl.get()
|> take(1)
|> deliverOnMainQueue).start(next: { [weak controller] resolvedUrl in
controller?.dismiss()
dismissImpl?()
openResolvedUrl(resolvedUrl, context: context, navigationController: navigationController, openPeer: { peer, navigation in
}, present: { controller, arguments in
pushControllerImpl?(controller)
}, dismissInput: {})
})
}
presentControllerImpl?(standardTextAlertController(theme: AlertControllerTheme(presentationTheme: presentationData.theme), title: nil, text: presentationData.strings.Settings_FAQ_Intro, actions: [
TextAlertAction(type: .genericAction, title: presentationData.strings.Settings_FAQ_Button, action: {
openFaq(resolvedUrlPromise)
dismissImpl?()
}),
TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_OK, action: {
supportPeerDisposable.set((supportPeer.get()
|> take(1)
|> deliverOnMainQueue).start(next: { peerId in
if let peerId = peerId {
dismissImpl?()
pushControllerImpl?(ChatController(context: context, chatLocation: .peer(peerId)))
}
}))
})
]), nil)
}, logout: {
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
let alertController = standardTextAlertController(theme: AlertControllerTheme(presentationTheme: presentationData.theme), title: presentationData.strings.Settings_LogoutConfirmationTitle, text: presentationData.strings.Settings_LogoutConfirmationText, actions: [
TextAlertAction(type: .genericAction, title: presentationData.strings.Common_Cancel, action: {
}),
TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_OK, action: {
let _ = logoutFromAccount(id: context.account.id, accountManager: context.sharedContext.accountManager).start()
})
])
presentControllerImpl?(alertController, nil)
})
let signal = context.sharedContext.presentationData
|> map { presentationData -> (ItemListControllerState, (ItemListNodeState<LogoutOptionsEntry>, LogoutOptionsEntry.ItemGenerationArguments)) in
let leftNavigationButton = ItemListNavigationButton(content: .text(presentationData.strings.Common_Cancel), style: .regular, enabled: true, action: {
dismissImpl?()
})
let controllerState = ItemListControllerState(theme: presentationData.theme, title: .text(presentationData.strings.LogoutOptions_Title), leftNavigationButton: leftNavigationButton, rightNavigationButton: nil, backNavigationButton: ItemListBackButton(title: presentationData.strings.Common_Back))
let listState = ItemListNodeState(entries: logoutOptionsEntries(presentationData: presentationData, canAddAccounts: canAddAccounts), style: .blocks)
return (controllerState, (listState, arguments))
}
let controller = ItemListController(context: context, state: signal, tabBarItem: nil)
pushControllerImpl = { [weak navigationController] value in
navigationController?.pushViewController(value, animated: false)
}
presentControllerImpl = { [weak controller] value, arguments in
controller?.present(value, in: .window(.root), with: arguments ?? ViewControllerPresentationArguments(presentationAnimation: .modalSheet))
}
dismissImpl = { [weak controller] in
let _ = controller?.dismiss()
}
return controller
}

View File

@ -157,6 +157,11 @@ final class MediaPlayerNode: ASDisplayNode {
var finised = false
loop: while true {
let isReady = layer.isReadyForMoreMediaData
#if DEBUG
if let error = layer.error {
print("MediaPlayerNode error: \(error)")
}
#endif
if isReady {
switch takeFrame() {

View File

@ -35,7 +35,7 @@ public final class OverlayMediaController: ViewController {
override public func containerLayoutUpdated(_ layout: ContainerViewLayout, transition: ContainedViewLayoutTransition) {
super.containerLayoutUpdated(layout, transition: transition)
let updatedLayout = ContainerViewLayout(size: layout.size, metrics: layout.metrics, intrinsicInsets: UIEdgeInsets(top: (layout.statusBarHeight ?? 0.0) + 44.0, left: layout.intrinsicInsets.left, bottom: layout.intrinsicInsets.bottom, right: layout.intrinsicInsets.right), safeInsets: layout.safeInsets, statusBarHeight: layout.statusBarHeight, inputHeight: layout.inputHeight, standardInputHeight: layout.standardInputHeight, inputHeightIsInteractivellyChanging: layout.inputHeightIsInteractivellyChanging)
let updatedLayout = ContainerViewLayout(size: layout.size, metrics: layout.metrics, intrinsicInsets: UIEdgeInsets(top: (layout.statusBarHeight ?? 0.0) + 44.0, left: layout.intrinsicInsets.left, bottom: layout.intrinsicInsets.bottom, right: layout.intrinsicInsets.right), safeInsets: layout.safeInsets, statusBarHeight: layout.statusBarHeight, inputHeight: layout.inputHeight, standardInputHeight: layout.standardInputHeight, inputHeightIsInteractivellyChanging: layout.inputHeightIsInteractivellyChanging, inVoiceOver: layout.inVoiceOver)
self.controllerNode.containerLayoutUpdated(updatedLayout, transition: transition)
}
}

View File

@ -147,7 +147,7 @@ private func aroundMessagesFromView(view: MessageHistoryView, centralIndex: Mess
var result: [Message] = []
if index != 0 {
for i in (0 ..< index).reversed() {
if case let .MessageEntry(message, _, _, _) = view.entries[i] {
if case let .MessageEntry(message, _, _, _, _) = view.entries[i] {
result.append(message)
break
}
@ -155,7 +155,7 @@ private func aroundMessagesFromView(view: MessageHistoryView, centralIndex: Mess
}
if index != view.entries.count - 1 {
for i in index + 1 ..< view.entries.count {
if case let .MessageEntry(message, _, _, _) = view.entries[i] {
if case let .MessageEntry(message, _, _, _, _) = view.entries[i] {
result.append(message)
break
}
@ -171,7 +171,7 @@ private func navigatedMessageFromView(_ view: MessageHistoryView, anchorIndex: M
switch position {
case .exact:
switch entry {
case let .MessageEntry(message, _, _, _):
case let .MessageEntry(message, _, _, _, _):
return (message, aroundMessagesFromView(view: view, centralIndex: entry.index), true)
default:
return nil
@ -179,7 +179,7 @@ private func navigatedMessageFromView(_ view: MessageHistoryView, anchorIndex: M
case .later:
if index + 1 < view.entries.count {
switch view.entries[index + 1] {
case let .MessageEntry(message, _, _, _):
case let .MessageEntry(message, _, _, _, _):
return (message, aroundMessagesFromView(view: view, centralIndex: view.entries[index + 1].index), true)
default:
return nil
@ -190,7 +190,7 @@ private func navigatedMessageFromView(_ view: MessageHistoryView, anchorIndex: M
case .earlier:
if index != 0 {
switch view.entries[index - 1] {
case let .MessageEntry(message, _, _, _):
case let .MessageEntry(message, _, _, _, _):
return (message, aroundMessagesFromView(view: view, centralIndex: view.entries[index - 1].index), true)
default:
return nil
@ -206,14 +206,14 @@ private func navigatedMessageFromView(_ view: MessageHistoryView, anchorIndex: M
switch position {
case .later, .exact:
switch view.entries[view.entries.count - 1] {
case let .MessageEntry(message, _, _, _):
case let .MessageEntry(message, _, _, _, _):
return (message, aroundMessagesFromView(view: view, centralIndex: view.entries[view.entries.count - 1].index), false)
default:
return nil
}
case .earlier:
switch view.entries[0] {
case let .MessageEntry(message, _, _, _):
case let .MessageEntry(message, _, _, _, _):
return (message, aroundMessagesFromView(view: view, centralIndex: view.entries[0].index), false)
default:
return nil

View File

@ -202,7 +202,7 @@ final class PeerSelectionControllerNode: ASDisplayNode {
let contactsInsets = insets
contactListNode.containerLayoutUpdated(ContainerViewLayout(size: layout.size, metrics: layout.metrics, intrinsicInsets: contactsInsets, safeInsets: layout.safeInsets, statusBarHeight: layout.statusBarHeight, inputHeight: layout.inputHeight, standardInputHeight: layout.standardInputHeight, inputHeightIsInteractivellyChanging: layout.inputHeightIsInteractivellyChanging), headerInsets: headerInsets, transition: transition)
contactListNode.containerLayoutUpdated(ContainerViewLayout(size: layout.size, metrics: layout.metrics, intrinsicInsets: contactsInsets, safeInsets: layout.safeInsets, statusBarHeight: layout.statusBarHeight, inputHeight: layout.inputHeight, standardInputHeight: layout.standardInputHeight, inputHeightIsInteractivellyChanging: layout.inputHeightIsInteractivellyChanging, inVoiceOver: layout.inVoiceOver), headerInsets: headerInsets, transition: transition)
}
if let searchDisplayController = self.searchDisplayController {

View File

@ -690,7 +690,7 @@ public func chatMessagePhotoInternal(photoData: Signal<(Data?, Data?, Bool), NoE
if let thumbnailImage = thumbnailImage {
let thumbnailSize = CGSize(width: thumbnailImage.width, height: thumbnailImage.height)
if thumbnailSize.width > arguments.drawingSize.width * 0.7 && thumbnailSize.height > arguments.drawingSize.height * 0.7 {
if thumbnailSize.width > 200.0 && thumbnailSize.height > 200.0 {
blurredThumbnailImage = UIImage(cgImage: thumbnailImage)
} else {
let initialThumbnailContextFittingSize = fittedSize.fitted(CGSize(width: 90.0, height: 90.0))

File diff suppressed because it is too large Load Diff

View File

@ -93,7 +93,7 @@ final class SearchDisplayController {
self.containerLayout = (layout, navigationBarFrame.maxY)
transition.updateFrame(node: self.contentNode, frame: CGRect(origin: CGPoint(), size: layout.size))
self.contentNode.containerLayoutUpdated(ContainerViewLayout(size: layout.size, metrics: LayoutMetrics(), intrinsicInsets: layout.intrinsicInsets, safeInsets: layout.safeInsets, statusBarHeight: nil, inputHeight: layout.inputHeight, standardInputHeight: layout.standardInputHeight, inputHeightIsInteractivellyChanging: layout.inputHeightIsInteractivellyChanging), navigationBarHeight: navigationBarFrame.maxY, transition: transition)
self.contentNode.containerLayoutUpdated(ContainerViewLayout(size: layout.size, metrics: LayoutMetrics(), intrinsicInsets: layout.intrinsicInsets, safeInsets: layout.safeInsets, statusBarHeight: nil, inputHeight: layout.inputHeight, standardInputHeight: layout.standardInputHeight, inputHeightIsInteractivellyChanging: layout.inputHeightIsInteractivellyChanging, inVoiceOver: layout.inVoiceOver), navigationBarHeight: navigationBarFrame.maxY, transition: transition)
}
func activate(insertSubnode: (ASDisplayNode, Bool) -> Void, placeholder: SearchBarPlaceholderNode) {
@ -104,7 +104,7 @@ final class SearchDisplayController {
insertSubnode(self.contentNode, false)
self.contentNode.frame = CGRect(origin: CGPoint(), size: layout.size)
self.contentNode.containerLayoutUpdated(ContainerViewLayout(size: layout.size, metrics: LayoutMetrics(), intrinsicInsets: UIEdgeInsets(), safeInsets: layout.safeInsets, statusBarHeight: nil, inputHeight: nil, standardInputHeight: layout.standardInputHeight, inputHeightIsInteractivellyChanging: false), navigationBarHeight: navigationBarHeight, transition: .immediate)
self.contentNode.containerLayoutUpdated(ContainerViewLayout(size: layout.size, metrics: LayoutMetrics(), intrinsicInsets: UIEdgeInsets(), safeInsets: layout.safeInsets, statusBarHeight: nil, inputHeight: nil, standardInputHeight: layout.standardInputHeight, inputHeightIsInteractivellyChanging: false, inVoiceOver: false), navigationBarHeight: navigationBarHeight, transition: .immediate)
let initialTextBackgroundFrame = placeholder.convert(placeholder.backgroundNode.frame, to: nil)

View File

@ -421,7 +421,7 @@ public final class SecretMediaPreviewController: ViewController {
}
}
guard let item = galleryItemForEntry(context: self.context, presentationData: self.presentationData, entry: .MessageEntry(message, false, nil, nil), streamVideos: false, hideControls: true, tempFilePath: tempFilePath, playbackCompleted: { [weak self] in
guard let item = galleryItemForEntry(context: self.context, presentationData: self.presentationData, entry: .MessageEntry(message, false, nil, nil, MutableMessageHistoryEntryAttributes(authorIsContact: false)), streamVideos: false, hideControls: true, tempFilePath: tempFilePath, playbackCompleted: { [weak self] in
self?.dismiss(forceAway: false)
}) else {
self._ready.set(.single(true))

View File

@ -38,6 +38,26 @@ public final class AccountWithInfo: Equatable {
}
}
private func pathFromLegacyFile(basePath: String, fileId: Int64, isLocal: Bool, fileName: String) -> String {
let documentsPath = basePath + "/Documents"
let filePath = documentsPath + "/files/" + (isLocal ? "local" : "") + "\(String(fileId, radix: 16))/\(fileName)"
return filePath
}
private func preFetchedLegacyResourcePath(basePath: String, resource: MediaResource, cache: LegacyCache) -> String? {
if let resource = resource as? CloudDocumentMediaResource {
let videoPath = "\(basePath)/Documents/video/remote\(String(resource.fileId, radix: 16)).mov"
if FileManager.default.fileExists(atPath: videoPath) {
return videoPath
}
let fileName = resource.fileName?.replacingOccurrences(of: "/", with: "_") ?? "file"
return pathFromLegacyFile(basePath: basePath, fileId: resource.fileId, isLocal: false, fileName: fileName)
} else if let resource = resource as? CloudFileMediaResource {
return cache.path(forCachedData: "\(resource.datacenterId)_\(resource.volumeId)_\(resource.localId)_\(resource.secret)")
}
return nil
}
private struct AccountAttributes: Equatable {
let sortIndex: Int32
let isTestingEnvironment: Bool
@ -125,7 +145,7 @@ public final class SharedAccountContext {
public var presentGlobalController: (ViewController, Any?) -> Void = { _, _ in }
public var presentCrossfadeController: () -> Void = {}
public init(mainWindow: Window1?, accountManager: AccountManager, applicationBindings: TelegramApplicationBindings, initialPresentationDataAndSettings: InitialPresentationDataAndSettings, networkArguments: NetworkInitializationArguments, rootPath: String, apsNotificationToken: Signal<Data?, NoError>, voipNotificationToken: Signal<Data?, NoError>, setNotificationCall: @escaping (PresentationCall?) -> Void, navigateToChat: @escaping (AccountRecordId, PeerId, MessageId?) -> Void) {
public init(mainWindow: Window1?, accountManager: AccountManager, applicationBindings: TelegramApplicationBindings, initialPresentationDataAndSettings: InitialPresentationDataAndSettings, networkArguments: NetworkInitializationArguments, rootPath: String, legacyBasePath: String?, legacyCache: LegacyCache?, apsNotificationToken: Signal<Data?, NoError>, voipNotificationToken: Signal<Data?, NoError>, setNotificationCall: @escaping (PresentationCall?) -> Void, navigateToChat: @escaping (AccountRecordId, PeerId, MessageId?) -> Void) {
assert(Queue.mainQueue().isCurrent())
self.mainWindow = mainWindow
self.applicationBindings = applicationBindings
@ -300,6 +320,13 @@ public final class SharedAccountContext {
|> map { result -> (AccountRecordId, Account?, Int32) in
switch result {
case let .authorized(account):
setupAccount(account, fetchCachedResourceRepresentation: fetchCachedResourceRepresentation, transformOutgoingMessageMedia: transformOutgoingMessageMedia, preFetchedResourcePath: { resource in
if let legacyBasePath = legacyBasePath, let legacyCache = legacyCache {
return preFetchedLegacyResourcePath(basePath: legacyBasePath, resource: resource, cache: legacyCache)
} else {
return nil
}
})
return (id, account, attributes.sortIndex)
default:
return (id, nil, attributes.sortIndex)

View File

@ -511,7 +511,7 @@ public class TelegramController: ViewController {
return .single((nil, true))
case let .HistoryView(view, _, _, _, _):
for entry in view.entries {
if case let .MessageEntry(message, _, _, _) = entry {
if case let .MessageEntry(message, _, _, _, _) = entry {
if message.id == id.messageId {
return .single((MessageIndex(message), false))
}

View File

@ -126,8 +126,8 @@ class ThemeSettingsChatPreviewItemNode: ListViewItemNode {
let chatPresentationData = ChatPresentationData(theme: ChatPresentationThemeData(theme: item.componentTheme, wallpaper: item.wallpaper), fontSize: item.fontSize, strings: item.strings, dateTimeFormat: item.dateTimeFormat, nameDisplayOrder: item.nameDisplayOrder, disableAnimations: false)
let item2: ChatMessageItem = ChatMessageItem(presentationData: chatPresentationData, context: item.context, chatLocation: .peer(peerId), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .contact, automaticDownloadNetworkType: .cellular, isRecentActions: false), controllerInteraction: controllerInteraction, content: .message(message: Message(stableId: 1, stableVersion: 0, id: MessageId(peerId: peerId, namespace: 0, id: 1), globallyUniqueId: nil, groupingKey: nil, groupInfo: nil, timestamp: 66000, flags: [.Incoming], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: nil, text: item.strings.Appearance_PreviewIncomingText, attributes: [ReplyMessageAttribute(messageId: replyMessageId)], media: [], peers: peers, associatedMessages: messages, associatedMessageIds: []), read: true, selection: .none, isAdmin: false), disableDate: true)
let item1: ChatMessageItem = ChatMessageItem(presentationData: chatPresentationData, context: item.context, chatLocation: .peer(peerId), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .contact, automaticDownloadNetworkType: .cellular, isRecentActions: false), controllerInteraction: controllerInteraction, content: .message(message: Message(stableId: 2, stableVersion: 0, id: MessageId(peerId: peerId, namespace: 0, id: 2), globallyUniqueId: nil, groupingKey: nil, groupInfo: nil, timestamp: 66001, flags: [], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: TelegramUser(id: item.context.account.peerId, accessHash: nil, firstName: "", lastName: "", username: nil, phone: nil, photo: [], botInfo: nil, restrictionInfo: nil, flags: []), text: item.strings.Appearance_PreviewOutgoingText, attributes: [], media: [], peers: peers, associatedMessages: messages, associatedMessageIds: []), read: true, selection: .none, isAdmin: false), disableDate: true)
let item2: ChatMessageItem = ChatMessageItem(presentationData: chatPresentationData, context: item.context, chatLocation: .peer(peerId), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .contact, automaticDownloadNetworkType: .cellular, isRecentActions: false), controllerInteraction: controllerInteraction, content: .message(message: Message(stableId: 1, stableVersion: 0, id: MessageId(peerId: peerId, namespace: 0, id: 1), globallyUniqueId: nil, groupingKey: nil, groupInfo: nil, timestamp: 66000, flags: [.Incoming], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: nil, text: item.strings.Appearance_PreviewIncomingText, attributes: [ReplyMessageAttribute(messageId: replyMessageId)], media: [], peers: peers, associatedMessages: messages, associatedMessageIds: []), read: true, selection: .none, attributes: ChatMessageEntryAttributes(isAdmin: false, isContact: false)), disableDate: true)
let item1: ChatMessageItem = ChatMessageItem(presentationData: chatPresentationData, context: item.context, chatLocation: .peer(peerId), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .contact, automaticDownloadNetworkType: .cellular, isRecentActions: false), controllerInteraction: controllerInteraction, content: .message(message: Message(stableId: 2, stableVersion: 0, id: MessageId(peerId: peerId, namespace: 0, id: 2), globallyUniqueId: nil, groupingKey: nil, groupInfo: nil, timestamp: 66001, flags: [], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: TelegramUser(id: item.context.account.peerId, accessHash: nil, firstName: "", lastName: "", username: nil, phone: nil, photo: [], botInfo: nil, restrictionInfo: nil, flags: []), text: item.strings.Appearance_PreviewOutgoingText, attributes: [], media: [], peers: peers, associatedMessages: messages, associatedMessageIds: []), read: true, selection: .none, attributes: ChatMessageEntryAttributes(isAdmin: false, isContact: false)), disableDate: true)
var node1: ListViewItemNode?
if let current = currentNode1 {

View File

@ -693,7 +693,10 @@ private func userInfoEntries(account: Account, presentationData: PresentationDat
if cachedData.isBlocked {
entries.append(UserInfoEntry.block(presentationData.theme, stringForBlockAction(strings: presentationData.strings, action: .unblock, peer: user), .unblock))
} else {
entries.append(UserInfoEntry.block(presentationData.theme, stringForBlockAction(strings: presentationData.strings, action: .block, peer: user), .block))
if let peer = peer as? TelegramUser, let phone = peer.phone, phone.hasPrefix("424") {
} else {
entries.append(UserInfoEntry.block(presentationData.theme, stringForBlockAction(strings: presentationData.strings, action: .block, peer: user), .block))
}
}
}
}

View File

@ -588,9 +588,9 @@ class WallpaperGalleryController: ViewController {
bottomMessageText = presentationData.strings.WallpaperPreview_CustomColorBottomText
}
items.append(ChatMessageItem(presentationData: chatPresentationData, context: self.context, chatLocation: .peer(peerId), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .contact, automaticDownloadNetworkType: .cellular, isRecentActions: false), controllerInteraction: controllerInteraction, content: .message(message: Message(stableId: 2, stableVersion: 0, id: MessageId(peerId: peerId, namespace: 0, id: 2), globallyUniqueId: nil, groupingKey: nil, groupInfo: nil, timestamp: 66001, flags: [], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: peers[otherPeerId], text: bottomMessageText, attributes: [], media: [], peers: peers, associatedMessages: messages, associatedMessageIds: []), read: true, selection: .none, isAdmin: false), disableDate: false))
items.append(ChatMessageItem(presentationData: chatPresentationData, context: self.context, chatLocation: .peer(peerId), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .contact, automaticDownloadNetworkType: .cellular, isRecentActions: false), controllerInteraction: controllerInteraction, content: .message(message: Message(stableId: 2, stableVersion: 0, id: MessageId(peerId: peerId, namespace: 0, id: 2), globallyUniqueId: nil, groupingKey: nil, groupInfo: nil, timestamp: 66001, flags: [], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: peers[otherPeerId], text: bottomMessageText, attributes: [], media: [], peers: peers, associatedMessages: messages, associatedMessageIds: []), read: true, selection: .none, attributes: ChatMessageEntryAttributes(isAdmin: false, isContact: false)), disableDate: false))
items.append(ChatMessageItem(presentationData: chatPresentationData, context: self.context, chatLocation: .peer(peerId), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .contact, automaticDownloadNetworkType: .cellular, isRecentActions: false), controllerInteraction: controllerInteraction, content: .message(message: Message(stableId: 1, stableVersion: 0, id: MessageId(peerId: peerId, namespace: 0, id: 1), globallyUniqueId: nil, groupingKey: nil, groupInfo: nil, timestamp: 66000, flags: [.Incoming], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: peers[peerId], text: topMessageText, attributes: [], media: [], peers: peers, associatedMessages: messages, associatedMessageIds: []), read: true, selection: .none, isAdmin: false), disableDate: false))
items.append(ChatMessageItem(presentationData: chatPresentationData, context: self.context, chatLocation: .peer(peerId), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .contact, automaticDownloadNetworkType: .cellular, isRecentActions: false), controllerInteraction: controllerInteraction, content: .message(message: Message(stableId: 1, stableVersion: 0, id: MessageId(peerId: peerId, namespace: 0, id: 1), globallyUniqueId: nil, groupingKey: nil, groupInfo: nil, timestamp: 66000, flags: [.Incoming], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: peers[peerId], text: topMessageText, attributes: [], media: [], peers: peers, associatedMessages: messages, associatedMessageIds: []), read: true, selection: .none, attributes: ChatMessageEntryAttributes(isAdmin: false, isContact: false)), disableDate: false))
let params = ListViewItemLayoutParams(width: layout.size.width, leftInset: layout.safeInsets.left, rightInset: layout.safeInsets.right)
if let messageNodes = self.messageNodes {