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

View File

@ -382,7 +382,7 @@ class AvatarGalleryController: ViewController {
self.galleryNode.setControlsHidden(true, animated: false) self.galleryNode.setControlsHidden(true, animated: false)
if let centralItemNode = self.galleryNode.pager.centralItemNode(), let itemSize = centralItemNode.contentSize() { if let centralItemNode = self.galleryNode.pager.centralItemNode(), let itemSize = centralItemNode.contentSize() {
self.preferredContentSize = itemSize.aspectFitted(self.view.bounds.size) 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() 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 let hasApplePaySupport: Bool = PKPaymentAuthorizationViewController.canMakePayments(usingNetworks: [.visa, .masterCard, .amex])
private func formSupportApplePay(_ paymentForm: BotPaymentForm) -> Bool { private func formSupportApplePay(_ paymentForm: BotPaymentForm) -> Bool {
if !hasApplePaySupport {
return false
}
guard let nativeProvider = paymentForm.nativeProvider else { guard let nativeProvider = paymentForm.nativeProvider else {
return false return false
} }
@ -342,10 +345,10 @@ private func formSupportApplePay(_ paymentForm: BotPaymentForm) -> Bool {
return merchantId != nil return merchantId != nil
} }
private func availablePaymentMethods(current: BotCheckoutPaymentMethod?, supportsApplePay: Bool) -> [BotCheckoutPaymentMethod] { private func availablePaymentMethods(form: BotPaymentForm, current: BotCheckoutPaymentMethod?) -> [BotCheckoutPaymentMethod] {
var methods: [BotCheckoutPaymentMethod] = [] var methods: [BotCheckoutPaymentMethod] = []
if hasApplePaySupport { if formSupportApplePay(form) && hasApplePaySupport {
methods.append(.applePayStripe) methods.append(.applePay)
} }
if let current = current { if let current = current {
if !methods.contains(current) { if !methods.contains(current) {
@ -595,13 +598,7 @@ final class BotCheckoutControllerNode: ItemListControllerNode<BotCheckoutEntry>,
openPaymentMethodImpl = { [weak self] in openPaymentMethodImpl = { [weak self] in
if let strongSelf = self, let paymentForm = strongSelf.paymentFormValue { if let strongSelf = self, let paymentForm = strongSelf.paymentFormValue {
let supportsApplePay: Bool let methods = availablePaymentMethods(form: paymentForm, current: strongSelf.currentPaymentMethod)
if formSupportApplePay(paymentForm) {
supportsApplePay = true
} else {
supportsApplePay = false
}
let methods = availablePaymentMethods(current: strongSelf.currentPaymentMethod, supportsApplePay: supportsApplePay)
if methods.isEmpty { if methods.isEmpty {
openNewCard() openNewCard()
} else { } else {
@ -699,7 +696,7 @@ final class BotCheckoutControllerNode: ItemListControllerNode<BotCheckoutEntry>,
override func containerLayoutUpdated(_ layout: ContainerViewLayout, navigationBarHeight: CGFloat, transition: ContainedViewLayoutTransition) { override func containerLayoutUpdated(_ layout: ContainerViewLayout, navigationBarHeight: CGFloat, transition: ContainedViewLayoutTransition) {
var updatedInsets = layout.intrinsicInsets var updatedInsets = layout.intrinsicInsets
updatedInsets.bottom += BotCheckoutActionButton.diameter + 20.0 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)) 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) transition.updateFrame(node: self.actionButton, frame: actionButtonFrame)
@ -789,11 +786,10 @@ final class BotCheckoutControllerNode: ItemListControllerNode<BotCheckoutEntry>,
} }
case let .webToken(token): case let .webToken(token):
credentials = .generic(data: token.data, saveOnServer: token.saveOnServer) credentials = .generic(data: token.data, saveOnServer: token.saveOnServer)
case .applePayStripe: case .applePay:
guard let paymentForm = self.paymentFormValue, let nativeProvider = paymentForm.nativeProvider else { guard let paymentForm = self.paymentFormValue, let nativeProvider = paymentForm.nativeProvider else {
return return
} }
//NSDictionary *dict = [NSJSONSerialization JSONObjectWithData:[strongSelf->_paymentForm.nativeParams dataUsingEncoding:NSUTF8StringEncoding] options:0 error:nil];
guard let nativeParamsData = nativeProvider.params.data(using: .utf8) else { guard let nativeParamsData = nativeProvider.params.data(using: .utf8) else {
return return
} }

View File

@ -13,7 +13,7 @@ struct BotCheckoutPaymentWebToken: Equatable {
enum BotCheckoutPaymentMethod: Equatable { enum BotCheckoutPaymentMethod: Equatable {
case savedCredentials(BotPaymentSavedCredentials) case savedCredentials(BotPaymentSavedCredentials)
case webToken(BotCheckoutPaymentWebToken) case webToken(BotCheckoutPaymentWebToken)
case applePayStripe case applePay
var title: String { var title: String {
switch self { switch self {
@ -24,7 +24,7 @@ enum BotCheckoutPaymentMethod: Equatable {
} }
case let .webToken(token): case let .webToken(token):
return token.title return token.title
case .applePayStripe: case .applePay:
return "Apple Pay" return "Apple Pay"
} }
} }
@ -63,7 +63,7 @@ final class BotCheckoutPaymentMethodSheetController: ActionSheetController {
case let .webToken(token): case let .webToken(token):
title = token.title title = token.title
icon = nil icon = nil
case .applePayStripe: case .applePay:
title = "Apple Pay" title = "Apple Pay"
icon = UIImage(bundleImageName: "Bot Payments/ApplePayLogo")?.precomposed() 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) { override func containerLayoutUpdated(_ layout: ContainerViewLayout, navigationBarHeight: CGFloat, transition: ContainedViewLayoutTransition) {
var updatedInsets = layout.intrinsicInsets var updatedInsets = layout.intrinsicInsets
updatedInsets.bottom += BotCheckoutActionButton.diameter + 20.0 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)) 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) transition.updateFrame(node: self.actionButton, frame: actionButtonFrame)

View File

@ -2454,13 +2454,17 @@ public final class ChatController: TelegramController, KeyShortcutResponder, Gal
self?.enqueueChatContextResult(results, result) self?.enqueueChatContextResult(results, result)
}, sendBotCommand: { [weak self] botPeer, command in }, sendBotCommand: { [weak self] botPeer, command in
if let strongSelf = self, canSendMessagesToChat(strongSelf.presentationInterfaceState) { 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 let messageText: String
if let addressName = botPeer.addressName {
if peer is TelegramUser { if peer is TelegramUser {
messageText = command messageText = command
} else { } else {
messageText = command + "@" + addressName messageText = command + "@" + addressName
} }
} else {
messageText = command
}
let replyMessageId = strongSelf.presentationInterfaceState.interfaceState.replyMessageId let replyMessageId = strongSelf.presentationInterfaceState.interfaceState.replyMessageId
strongSelf.chatDisplayNode.setupSendActionOnViewUpdate({ strongSelf.chatDisplayNode.setupSendActionOnViewUpdate({
if let strongSelf = self { if let strongSelf = self {
@ -4815,7 +4819,7 @@ public final class ChatController: TelegramController, KeyShortcutResponder, Gal
return .single((nil, true)) return .single((nil, true))
case let .HistoryView(view, _, _, _, _): case let .HistoryView(view, _, _, _, _):
for entry in view.entries { for entry in view.entries {
if case let .MessageEntry(message, _, _, _) = entry { if case let .MessageEntry(message, _, _, _, _) = entry {
if message.id == messageLocation.messageId { if message.id == messageLocation.messageId {
return .single((MessageIndex(message), false)) return .single((MessageIndex(message), false))
} }
@ -4902,7 +4906,7 @@ public final class ChatController: TelegramController, KeyShortcutResponder, Gal
return .complete() return .complete()
case let .HistoryView(view, _, _, _, _): case let .HistoryView(view, _, _, _, _):
for entry in view.entries { for entry in view.entries {
if case let .MessageEntry(message, _, _, _) = entry { if case let .MessageEntry(message, _, _, _, _) = entry {
if message.id == messageLocation.messageId { if message.id == messageLocation.messageId {
return .single(MessageIndex(message)) 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 let galleryController = AvatarGalleryController(context: self.context, peer: peer, remoteEntries: nil, replaceRootController: { controller, ready in
}, synchronousLoad: true) }, synchronousLoad: true)
galleryController.setHintWillBePresentedInPreviewingContext(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 (galleryController, buttonView.convert(buttonView.bounds, to: sourceView))
} }
return nil return nil
@ -5478,7 +5482,7 @@ public final class ChatController: TelegramController, KeyShortcutResponder, Gal
gallery.setHintWillBePresentedInPreviewingContext(true) gallery.setHintWillBePresentedInPreviewingContext(true)
let rect = selectedTransitionNode.0.view.convert(selectedTransitionNode.0.bounds, to: sourceView) let rect = selectedTransitionNode.0.view.convert(selectedTransitionNode.0.bounds, to: sourceView)
let sourceRect = rect.insetBy(dx: -2.0, dy: -2.0) 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) return (gallery, sourceRect)
case let .instantPage(gallery, centralIndex, galleryMedia): case let .instantPage(gallery, centralIndex, galleryMedia):
break break

View File

@ -1361,10 +1361,10 @@ class ChatControllerNode: ASDisplayNode, UIScrollViewDelegate {
} }
var restrictionText: String? 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 restrictionText = chatPresentationInterfaceState.strings.Channel_ErrorAccessDenied
} else if let peer = chatPresentationInterfaceState.renderedPeer?.peer {
restrictionText = peer.restrictionText
} }
if let restrictionText = restrictionText { if let restrictionText = restrictionText {
@ -1557,6 +1557,8 @@ class ChatControllerNode: ASDisplayNode, UIScrollViewDelegate {
if let (validLayout, _) = self.validLayout { 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) 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 { loop: for entry in view.entries {
switch entry { switch entry {
case let .HoleEntry(hole, _): case let .HoleEntry(hole, _):
@ -30,7 +30,7 @@ func chatHistoryEntriesForView(location: ChatLocation, view: MessageHistoryView,
if view.tagMask == nil { if view.tagMask == nil {
entries.append(.HoleEntry(hole, presentationData)) 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 { if message.id.peerId.namespace == Namespaces.Peer.CloudChannel {
for media in message.media { for media in message.media {
if let action = media as? TelegramMediaAction { if let action = media as? TelegramMediaAction {
@ -61,7 +61,7 @@ func chatHistoryEntriesForView(location: ChatLocation, view: MessageHistoryView,
} else { } else {
selection = .none selection = .none
} }
groupBucket.append((message, read, selection, isAdmin)) groupBucket.append((message, read, selection, ChatMessageEntryAttributes(isAdmin: isAdmin, isContact: attributes.authorIsContact)))
} else { } else {
let selection: ChatHistoryMessageSelection let selection: ChatHistoryMessageSelection
if let selectedMessages = selectedMessages { if let selectedMessages = selectedMessages {
@ -69,7 +69,7 @@ func chatHistoryEntriesForView(location: ChatLocation, view: MessageHistoryView,
} else { } else {
selection = .none 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 { } else {
let selection: ChatHistoryMessageSelection let selection: ChatHistoryMessageSelection
@ -78,7 +78,7 @@ func chatHistoryEntriesForView(location: ChatLocation, view: MessageHistoryView,
} else { } else {
selection = .none 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 { enum ChatHistoryEntry: Identifiable, Comparable {
case HoleEntry(MessageHistoryHole, ChatPresentationData) case HoleEntry(MessageHistoryHole, ChatPresentationData)
case MessageEntry(Message, ChatPresentationData, Bool, MessageHistoryEntryMonthLocation?, ChatHistoryMessageSelection, Bool) case MessageEntry(Message, ChatPresentationData, Bool, MessageHistoryEntryMonthLocation?, ChatHistoryMessageSelection, ChatMessageEntryAttributes)
case MessageGroupEntry(MessageGroupInfo, [(Message, Bool, ChatHistoryMessageSelection, Bool)], ChatPresentationData) case MessageGroupEntry(MessageGroupInfo, [(Message, Bool, ChatHistoryMessageSelection, ChatMessageEntryAttributes)], ChatPresentationData)
case UnreadEntry(MessageIndex, ChatPresentationData) case UnreadEntry(MessageIndex, ChatPresentationData)
case ChatInfoEntry(String, ChatPresentationData) case ChatInfoEntry(String, ChatPresentationData)
case SearchEntry(PresentationTheme, PresentationStrings) case SearchEntry(PresentationTheme, PresentationStrings)
@ -73,9 +78,9 @@ enum ChatHistoryEntry: Identifiable, Comparable {
} else { } else {
return false return false
} }
case let .MessageEntry(lhsMessage, lhsPresentationData, lhsRead, _, lhsSelection, lhsIsAdmin): case let .MessageEntry(lhsMessage, lhsPresentationData, lhsRead, _, lhsSelection, lhsAttributes):
switch rhs { 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 { if lhsPresentationData !== rhsPresentationData {
return false return false
} }
@ -105,7 +110,7 @@ enum ChatHistoryEntry: Identifiable, Comparable {
if lhsSelection != rhsSelection { if lhsSelection != rhsSelection {
return false return false
} }
if lhsIsAdmin != rhsIsAdmin { if lhsAttributes != rhsAttributes {
return false return false
} }
return true return true
@ -115,8 +120,8 @@ enum ChatHistoryEntry: Identifiable, Comparable {
case let .MessageGroupEntry(lhsGroupInfo, lhsMessages, lhsPresentationData): case let .MessageGroupEntry(lhsGroupInfo, lhsMessages, lhsPresentationData):
if case let .MessageGroupEntry(rhsGroupInfo, rhsMessages, rhsPresentationData) = rhs, lhsGroupInfo == rhsGroupInfo, lhsPresentationData === rhsPresentationData, lhsMessages.count == rhsMessages.count { if case let .MessageGroupEntry(rhsGroupInfo, rhsMessages, rhsPresentationData) = rhs, lhsGroupInfo == rhsGroupInfo, lhsPresentationData === rhsPresentationData, lhsMessages.count == rhsMessages.count {
for i in 0 ..< lhsMessages.count { for i in 0 ..< lhsMessages.count {
let (lhsMessage, lhsRead, lhsSelection, lhsIsAdmin) = lhsMessages[i] let (lhsMessage, lhsRead, lhsSelection, lhsAttributes) = lhsMessages[i]
let (rhsMessage, rhsRead, rhsSelection, rhsIsAdmin) = rhsMessages[i] let (rhsMessage, rhsRead, rhsSelection, rhsAttributes) = rhsMessages[i]
if lhsMessage.id != rhsMessage.id { if lhsMessage.id != rhsMessage.id {
return false return false
@ -159,7 +164,7 @@ enum ChatHistoryEntry: Identifiable, Comparable {
} }
} }
} }
if lhsIsAdmin != rhsIsAdmin { if lhsAttributes != rhsAttributes {
return false 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] { private func mappedInsertEntries(context: AccountContext, chatLocation: ChatLocation, associatedData: ChatMessageItemAssociatedData, controllerInteraction: ChatControllerInteraction, mode: ChatHistoryListMode, entries: [ChatHistoryViewTransitionInsertEntry]) -> [ListViewInsertItem] {
return entries.map { entry -> ListViewInsertItem in return entries.map { entry -> ListViewInsertItem in
switch entry.entry { switch entry.entry {
case let .MessageEntry(message, presentationData, read, _, selection, isAdmin): case let .MessageEntry(message, presentationData, read, _, selection, attributes):
let item: ListViewItem let item: ListViewItem
switch mode { switch mode {
case .bubbles: 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, _): 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) 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] { private func mappedUpdateEntries(context: AccountContext, chatLocation: ChatLocation, associatedData: ChatMessageItemAssociatedData, controllerInteraction: ChatControllerInteraction, mode: ChatHistoryListMode, entries: [ChatHistoryViewTransitionUpdateEntry]) -> [ListViewUpdateItem] {
return entries.map { entry -> ListViewUpdateItem in return entries.map { entry -> ListViewUpdateItem in
switch entry.entry { switch entry.entry {
case let .MessageEntry(message, presentationData, read, _, selection, isAdmin): case let .MessageEntry(message, presentationData, read, _, selection, attributes):
let item: ListViewItem let item: ListViewItem
switch mode { switch mode {
case .bubbles: 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, _): 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) 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 { loop: for i in 0 ..< historyView.filteredEntries.count {
switch historyView.filteredEntries[i] { switch historyView.filteredEntries[i] {
case let .MessageEntry(message, presentationData, read, _, selection, isAdmin): case let .MessageEntry(message, presentationData, read, _, selection, attributes):
if message.id == id { if message.id == id {
let index = historyView.filteredEntries.count - 1 - i let index = historyView.filteredEntries.count - 1 - i
let item: ListViewItem let item: ListViewItem
switch self.mode { switch self.mode {
case .bubbles: 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, _): 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) 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 { switch entry {
case .HoleEntry: case .HoleEntry:
break inner break inner
case let .MessageEntry(message, _, _, _): case let .MessageEntry(message, _, _, _, _):
if message.flags.contains(.Incoming) { if message.flags.contains(.Incoming) {
incomingCount += 1 incomingCount += 1
} }

View File

@ -662,6 +662,17 @@ public class ChatListController: TelegramController, KeyShortcutResponder, UIVie
self.displayNodeDidLoad() 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) { override public func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated) super.viewDidAppear(animated)
@ -677,12 +688,6 @@ public class ChatListController: TelegramController, KeyShortcutResponder, UIVie
}) })
#endif #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 { 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 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)) let chatController = ChatController(context: self.context, chatLocation: .peer(peerId), mode: .standard(previewing: true))
chatController.canReadHistory.set(false) 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) return (chatController, sourceRect)
} else if let messageId = action as? MessageId, messageId.peerId.namespace != Namespaces.Peer.SecretChat { } else if let messageId = action as? MessageId, messageId.peerId.namespace != Namespaces.Peer.SecretChat {
var sourceRect = view.superview!.convert(view.frame, to: sourceView) 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)) let chatController = ChatController(context: self.context, chatLocation: .peer(messageId.peerId), messageId: messageId, mode: .standard(previewing: true))
chatController.canReadHistory.set(false) 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) return (chatController, sourceRect)
} }
} }
@ -941,14 +946,14 @@ public class ChatListController: TelegramController, KeyShortcutResponder, UIVie
if peer.peerId.namespace != Namespaces.Peer.SecretChat { if peer.peerId.namespace != Namespaces.Peer.SecretChat {
let chatController = ChatController(context: self.context, chatLocation: .peer(peer.peerId), mode: .standard(previewing: true)) let chatController = ChatController(context: self.context, chatLocation: .peer(peer.peerId), mode: .standard(previewing: true))
chatController.canReadHistory.set(false) 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) return (chatController, sourceRect)
} else { } else {
return nil return nil
} }
case let .groupReference(groupId, _, _, _): case let .groupReference(groupId, _, _, _):
let chatListController = ChatListController(context: self.context, groupId: groupId, controlsHistoryPreload: false) 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) return (chatListController, sourceRect)
} }
} else { } else {

View File

@ -256,6 +256,19 @@ class ChatListItemNode: ItemListRevealOptionsItemNode {
} set(value) { } 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? { override var accessibilityLabel: String? {
get { get {
guard let item = self.item else { guard let item = self.item else {
@ -366,7 +379,6 @@ class ChatListItemNode: ItemListRevealOptionsItemNode {
super.init(layerBacked: false, dynamicBounce: false, rotated: false, seeThrough: false) super.init(layerBacked: false, dynamicBounce: false, rotated: false, seeThrough: false)
self.isAccessibilityElement = true self.isAccessibilityElement = true
self.isAccessibilityContainer = true
self.addSubnode(self.backgroundNode) self.addSubnode(self.backgroundNode)
self.addSubnode(self.separatorNode) self.addSubnode(self.separatorNode)
@ -1112,6 +1124,9 @@ class ChatListItemNode: ItemListRevealOptionsItemNode {
strongSelf.setRevealOptions((left: peerLeftRevealOptions, right: peerRevealOptions)) strongSelf.setRevealOptions((left: peerLeftRevealOptions, right: peerRevealOptions))
} }
strongSelf.setRevealOptionsOpened(item.hasActiveRevealControls, animated: true) 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 let status: ContactsPeerItemStatus
if let user = primaryPeer as? TelegramUser { if let user = primaryPeer as? TelegramUser {
if let _ = user.botInfo { if let _ = user.botInfo {
if let phoneNumber = user.phone, phoneNumber.hasPrefix("424") {
status = .custom(strings.Bot_GenericSupportStatus)
} else {
status = .custom(strings.Bot_GenericBotStatus) status = .custom(strings.Bot_GenericBotStatus)
}
} else if user.id != context.account.peerId { } else if user.id != context.account.peerId {
let presence = peer.presence ?? TelegramUserPresence(status: .none, lastActivity: 0) let presence = peer.presence ?? TelegramUserPresence(status: .none, lastActivity: 0)
status = .presence(presence, timeFormat) status = .presence(presence, timeFormat)

View File

@ -13,6 +13,8 @@ final class ChatMessageAvatarAccessoryItem: ListViewAccessoryItem {
private let messageTimestamp: Int32 private let messageTimestamp: Int32
private let emptyColor: UIColor private let emptyColor: UIColor
private let day: Int32
init(context: AccountContext, peerId: PeerId, peer: Peer?, messageReference: MessageReference?, messageTimestamp: Int32, emptyColor: UIColor) { init(context: AccountContext, peerId: PeerId, peer: Peer?, messageReference: MessageReference?, messageTimestamp: Int32, emptyColor: UIColor) {
self.context = context self.context = context
self.peerId = peerId self.peerId = peerId
@ -20,11 +22,17 @@ final class ChatMessageAvatarAccessoryItem: ListViewAccessoryItem {
self.messageReference = messageReference self.messageReference = messageReference
self.messageTimestamp = messageTimestamp self.messageTimestamp = messageTimestamp
self.emptyColor = emptyColor 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 { func isEqualToItem(_ other: ListViewAccessoryItem) -> Bool {
if case let other as ChatMessageAvatarAccessoryItem = other { 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 return false

View File

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

View File

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

View File

@ -91,46 +91,43 @@ enum ChatMessagePeekPreviewContent {
case url(ASDisplayNode, CGRect, String) 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 { public class ChatMessageItemView: ListViewItemNode {
let layoutConstants = defaultChatMessageItemLayoutConstants let layoutConstants = defaultChatMessageItemLayoutConstants
var item: ChatMessageItem? 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() { public required convenience init() {
self.init(layerBacked: false) self.init(layerBacked: false)
} }

View File

@ -114,7 +114,7 @@ struct ChatRecentActionsEntry: Comparable, Identifiable {
let action = TelegramMediaActionType.titleUpdated(title: new) 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: []) 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): case let .changeAbout(prev, new):
var peers = SimpleDictionary<PeerId, Peer>() var peers = SimpleDictionary<PeerId, Peer>()
var author: Peer? var author: Peer?
@ -145,14 +145,14 @@ struct ChatRecentActionsEntry: Comparable, Identifiable {
} }
let action = TelegramMediaActionType.customText(text: text, entities: entities) 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: []) 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: case .content:
let peers = SimpleDictionary<PeerId, Peer>() let peers = SimpleDictionary<PeerId, Peer>()
let attributes: [MessageAttribute] = [] 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 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: []) 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): case let .changeUsername(prev, new):
var peers = SimpleDictionary<PeerId, Peer>() var peers = SimpleDictionary<PeerId, Peer>()
@ -183,7 +183,7 @@ struct ChatRecentActionsEntry: Comparable, Identifiable {
} }
let action: TelegramMediaActionType = TelegramMediaActionType.customText(text: text, entities: entities) 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: []) 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: case .content:
var previousAttributes: [MessageAttribute] = [] var previousAttributes: [MessageAttribute] = []
var attributes: [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 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: []) 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): case let .changePhoto(_, new):
var peers = SimpleDictionary<PeerId, Peer>() var peers = SimpleDictionary<PeerId, Peer>()
@ -220,7 +220,7 @@ struct ChatRecentActionsEntry: Comparable, Identifiable {
let action = TelegramMediaActionType.photoUpdated(image: photo) 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: []) 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): case let .toggleInvites(value):
var peers = SimpleDictionary<PeerId, Peer>() var peers = SimpleDictionary<PeerId, Peer>()
var author: Peer? var author: Peer?
@ -247,7 +247,7 @@ struct ChatRecentActionsEntry: Comparable, Identifiable {
} }
let action = TelegramMediaActionType.customText(text: text, entities: entities) 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: []) 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): case let .toggleSignatures(value):
var peers = SimpleDictionary<PeerId, Peer>() var peers = SimpleDictionary<PeerId, Peer>()
var author: Peer? var author: Peer?
@ -274,7 +274,7 @@ struct ChatRecentActionsEntry: Comparable, Identifiable {
} }
let action = TelegramMediaActionType.customText(text: text, entities: entities) 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: []) 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): case let .updatePinned(message):
switch self.id.contentIndex { switch self.id.contentIndex {
case .header: case .header:
@ -296,7 +296,7 @@ struct ChatRecentActionsEntry: Comparable, Identifiable {
let action = TelegramMediaActionType.customText(text: text, entities: entities) 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: []) 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: case .content:
if let message = message { if let message = message {
var peers = SimpleDictionary<PeerId, Peer>() 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: []) 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 { } else {
var peers = SimpleDictionary<PeerId, Peer>() var peers = SimpleDictionary<PeerId, Peer>()
var author: Peer? var author: Peer?
@ -336,7 +336,7 @@ struct ChatRecentActionsEntry: Comparable, Identifiable {
let action = TelegramMediaActionType.customText(text: text, entities: entities) 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: []) 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): case let .editMessage(prev, message):
@ -381,7 +381,7 @@ struct ChatRecentActionsEntry: Comparable, Identifiable {
let action = TelegramMediaActionType.customText(text: text, entities: entities) 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: []) 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: case .content:
var peers = SimpleDictionary<PeerId, Peer>() var peers = SimpleDictionary<PeerId, Peer>()
var attributes: [MessageAttribute] = [] 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: []) 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): case let .deleteMessage(message):
switch self.id.contentIndex { switch self.id.contentIndex {
@ -424,7 +424,7 @@ struct ChatRecentActionsEntry: Comparable, Identifiable {
let action = TelegramMediaActionType.customText(text: text, entities: entities) 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: []) 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: case .content:
var peers = SimpleDictionary<PeerId, Peer>() var peers = SimpleDictionary<PeerId, Peer>()
var attributes: [MessageAttribute] = [] 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: []) 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: case .participantJoin, .participantLeave:
var peers = SimpleDictionary<PeerId, Peer>() var peers = SimpleDictionary<PeerId, Peer>()
@ -466,7 +466,7 @@ struct ChatRecentActionsEntry: Comparable, Identifiable {
action = TelegramMediaActionType.removedMembers(peerIds: [self.entry.event.peerId]) 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: []) 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): case let .participantInvite(participant):
var peers = SimpleDictionary<PeerId, Peer>() var peers = SimpleDictionary<PeerId, Peer>()
var author: Peer? var author: Peer?
@ -483,7 +483,7 @@ struct ChatRecentActionsEntry: Comparable, Identifiable {
let action: TelegramMediaActionType let action: TelegramMediaActionType
action = TelegramMediaActionType.addedMembers(peerIds: [participant.peer.id]) 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: []) 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): case let .participantToggleBan(prev, new):
var peers = SimpleDictionary<PeerId, Peer>() var peers = SimpleDictionary<PeerId, Peer>()
var attributes: [MessageAttribute] = [] 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: []) 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): case let .participantToggleAdmin(prev, new):
var peers = SimpleDictionary<PeerId, Peer>() var peers = SimpleDictionary<PeerId, Peer>()
var attributes: [MessageAttribute] = [] 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: []) 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): case let .changeStickerPack(_, new):
var peers = SimpleDictionary<PeerId, Peer>() var peers = SimpleDictionary<PeerId, Peer>()
var author: Peer? var author: Peer?
@ -722,7 +722,7 @@ struct ChatRecentActionsEntry: Comparable, Identifiable {
let action = TelegramMediaActionType.customText(text: text, entities: entities) 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: []) 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): case let .togglePreHistoryHidden(value):
var peers = SimpleDictionary<PeerId, Peer>() var peers = SimpleDictionary<PeerId, Peer>()
var author: Peer? var author: Peer?
@ -752,7 +752,7 @@ struct ChatRecentActionsEntry: Comparable, Identifiable {
let action = TelegramMediaActionType.customText(text: text, entities: entities) 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: []) 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): case let .updateDefaultBannedRights(prev, new):
var peers = SimpleDictionary<PeerId, Peer>() var peers = SimpleDictionary<PeerId, Peer>()
var attributes: [MessageAttribute] = [] 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: []) 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): case let .pollStopped(message):
switch self.id.contentIndex { switch self.id.contentIndex {
case .header: case .header:
@ -838,7 +838,7 @@ struct ChatRecentActionsEntry: Comparable, Identifiable {
let action = TelegramMediaActionType.customText(text: text, entities: entities) 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: []) 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: case .content:
var peers = SimpleDictionary<PeerId, Peer>() var peers = SimpleDictionary<PeerId, Peer>()
var attributes: [MessageAttribute] = [] 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: []) 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() super.init()
self.isAccessibilityElement = true
self.accessibilityTraits = UIAccessibilityTraitButton | UIAccessibilityTraitNotEnabled
self.view.addSubview(self.micButton) self.view.addSubview(self.micButton)
self.view.addSubview(self.sendButton) self.view.addSubview(self.sendButton)
self.addSubnode(self.expandMediaInputButton) 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)) 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.addTarget(self, action: #selector(self.sendButtonPressed), for: .touchUpInside)
self.actionButtons.sendButton.alpha = 0.0 self.actionButtons.sendButton.alpha = 0.0
self.actionButtons.updateAccessibility()
self.actionButtons.expandMediaInputButton.addTarget(self, action: #selector(self.expandButtonPressed), forControlEvents: .touchUpInside) self.actionButtons.expandMediaInputButton.addTarget(self, action: #selector(self.expandButtonPressed), forControlEvents: .touchUpInside)
self.actionButtons.expandMediaInputButton.alpha = 0.0 self.actionButtons.expandMediaInputButton.alpha = 0.0
@ -422,6 +423,12 @@ class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDelegate {
fatalError("init(coder:) has not been implemented") fatalError("init(coder:) has not been implemented")
} }
func loadTextInputNodeIfNeeded() {
if self.textInputNode == nil {
self.loadTextInputNode()
}
}
private func loadTextInputNode() { private func loadTextInputNode() {
let textInputNode = EditableTextNode() let textInputNode = EditableTextNode()
textInputNode.initialPrimaryLanguage = self.presentationInterfaceState?.interfaceState.inputLanguage textInputNode.initialPrimaryLanguage = self.presentationInterfaceState?.interfaceState.inputLanguage
@ -1109,6 +1116,7 @@ class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDelegate {
if !self.actionButtons.sendButton.alpha.isZero { if !self.actionButtons.sendButton.alpha.isZero {
self.actionButtons.sendButton.alpha = 0.0 self.actionButtons.sendButton.alpha = 0.0
self.actionButtons.updateAccessibility()
if animated { if animated {
self.actionButtons.animatingSendButton = true self.actionButtons.animatingSendButton = true
self.actionButtons.sendButton.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.2, completion: { [weak self] _ in 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 hideMicButton = true
if self.actionButtons.sendButton.alpha.isZero { if self.actionButtons.sendButton.alpha.isZero {
self.actionButtons.sendButton.alpha = 1.0 self.actionButtons.sendButton.alpha = 1.0
self.actionButtons.updateAccessibility()
if animated { if animated {
self.actionButtons.sendButton.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.1) self.actionButtons.sendButton.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.1)
if animateWithBounce { if animateWithBounce {
@ -1154,6 +1163,7 @@ class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDelegate {
} else { } else {
if !self.actionButtons.sendButton.alpha.isZero { if !self.actionButtons.sendButton.alpha.isZero {
self.actionButtons.sendButton.alpha = 0.0 self.actionButtons.sendButton.alpha = 0.0
self.actionButtons.updateAccessibility()
if animated { if animated {
self.actionButtons.animatingSendButton = true self.actionButtons.animatingSendButton = true
self.actionButtons.sendButton.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.2, completion: { [weak self] _ in 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 shouldUpdateLayout = true
} }
} else if let _ = user.botInfo { } 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) { if self.infoNode.attributedText == nil || !self.infoNode.attributedText!.isEqual(to: string) {
self.infoNode.attributedText = string self.infoNode.attributedText = string
shouldUpdateLayout = true shouldUpdateLayout = true
@ -455,9 +461,14 @@ final class ChatTitleView: UIView, NavigationBarTitleView {
break break
} }
self.accessibilityLabel = self.titleNode.attributedText?.string
self.accessibilityValue = self.infoNode.attributedText?.string
if shouldUpdateLayout { if shouldUpdateLayout {
self.setNeedsLayout() self.setNeedsLayout()
} }
} else {
self.accessibilityLabel = nil
} }
} }
@ -499,6 +510,9 @@ final class ChatTitleView: UIView, NavigationBarTitleView {
super.init(frame: CGRect()) super.init(frame: CGRect())
self.isAccessibilityElement = true
self.accessibilityTraits = UIAccessibilityTraitHeader
self.addSubnode(self.contentContainer) self.addSubnode(self.contentContainer)
self.contentContainer.addSubnode(self.titleNode) self.contentContainer.addSubnode(self.titleNode)
self.contentContainer.addSubnode(self.infoNode) self.contentContainer.addSubnode(self.infoNode)

View File

@ -101,7 +101,7 @@ final class ComposeControllerNode: ASDisplayNode {
searchDisplayController.containerLayoutUpdated(layout, navigationBarHeight: navigationBarHeight, transition: transition) 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) 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]) var headerInsets = layout.insets(options: [.input])
headerInsets.top += actualNavigationBarHeight headerInsets.top += actualNavigationBarHeight
headerInsets.top += strongSelf.tokenListNode.bounds.size.height 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) searchResultsNode.frame = CGRect(origin: CGPoint(), size: layout.size)
} }
@ -168,11 +168,11 @@ final class ContactMultiselectionControllerNode: ASDisplayNode {
insets.top += tokenListHeight insets.top += tokenListHeight
headerInsets.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) self.contactListNode.frame = CGRect(origin: CGPoint(), size: layout.size)
if let searchResultsNode = self.searchResultsNode { 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) 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) 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) 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) 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) self.contactListNode.frame = CGRect(origin: CGPoint(), size: layout.size)
} }

View File

@ -315,6 +315,8 @@ func editSettingsController(context: AccountContext, currentName: ItemListAvatar
var updateHiddenAvatarImpl: (() -> Void)? var updateHiddenAvatarImpl: (() -> Void)?
var changeProfilePhotoImpl: (() -> Void)? var changeProfilePhotoImpl: (() -> Void)?
var getNavigationController: (() -> NavigationController?)?
let arguments = EditSettingsItemArguments(context: context, accountManager: accountManager, avatarAndNameInfoContext: avatarAndNameInfoContext, avatarTapAction: { let arguments = EditSettingsItemArguments(context: context, accountManager: accountManager, avatarAndNameInfoContext: avatarAndNameInfoContext, avatarTapAction: {
var updating = false var updating = false
updateState { updateState {
@ -373,15 +375,14 @@ func editSettingsController(context: AccountContext, currentName: ItemListAvatar
let isTestingEnvironment = context.account.testingEnvironment let isTestingEnvironment = context.account.testingEnvironment
context.sharedContext.beginNewAuth(testingEnvironment: isTestingEnvironment) context.sharedContext.beginNewAuth(testingEnvironment: isTestingEnvironment)
}, logout: { }, logout: {
let presentationData = context.sharedContext.currentPresentationData.with { $0 } let _ = (context.account.postbox.transaction { transaction -> String in
let alertController = standardTextAlertController(theme: AlertControllerTheme(presentationTheme: presentationData.theme), title: presentationData.strings.Settings_LogoutConfirmationTitle, text: presentationData.strings.Settings_LogoutConfirmationText, actions: [ return (transaction.getPeer(context.account.peerId) as? TelegramUser)?.phone ?? ""
TextAlertAction(type: .genericAction, title: presentationData.strings.Common_Cancel, action: { }
}), |> deliverOnMainQueue).start(next: { phoneNumber in
TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_OK, action: { if let navigationController = getNavigationController?() {
let _ = logoutFromAccount(id: context.account.id, accountManager: accountManager).start() presentControllerImpl?(logoutOptionsController(context: context, navigationController: navigationController, canAddAccounts: canAddAccounts, phoneNumber: phoneNumber), ViewControllerPresentationArguments(presentationAnimation: .modalSheet))
}
}) })
])
presentControllerImpl?(alertController, nil)
}) })
let peerView = context.account.viewTracker.peerView(context.account.peerId) 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 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? { 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 { switch entry {
case let .MessageEntry(message, _, location, _): case let .MessageEntry(message, _, location, _, _):
if let (media, mediaImage) = mediaForMessage(message: message) { if let (media, mediaImage) = mediaForMessage(message: message) {
if let _ = media as? TelegramMediaImage { if let _ = media as? TelegramMediaImage {
return ChatImageGalleryItem(context: context, presentationData: presentationData, message: message, location: location, performAction: performAction, openActionOptions: openActionOptions) return ChatImageGalleryItem(context: context, presentationData: presentationData, message: message, location: location, performAction: performAction, openActionOptions: openActionOptions)
@ -359,10 +359,10 @@ class GalleryController: ViewController {
return .single(mapped) return .single(mapped)
} }
} else { } 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: 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) |> take(1)
@ -389,7 +389,7 @@ class GalleryController: ViewController {
var centralEntryStableId: UInt32? var centralEntryStableId: UInt32?
loop: for i in 0 ..< entries.count { loop: for i in 0 ..< entries.count {
switch entries[i] { switch entries[i] {
case let .MessageEntry(message, _, _, _): case let .MessageEntry(message, _, _, _, _):
switch source { switch source {
case let .peerMessagesAtId(messageId): case let .peerMessagesAtId(messageId):
if message.id == messageId { if message.id == messageId {
@ -420,7 +420,7 @@ class GalleryController: ViewController {
var centralItemIndex: Int? var centralItemIndex: Int?
for entry in strongSelf.entries { for entry in strongSelf.entries {
var isCentral = false 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 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) { 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 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 { if let (media, _) = mediaForMessage(message: message), let transitionArguments = presentationArguments.transitionArguments(message.id, media), !forceAway {
animatedOutNode = false animatedOutNode = false
centralItemNode.animateOut(to: transitionArguments.transitionNode, addToTransitionSurface: transitionArguments.addToTransitionSurface, completion: { centralItemNode.animateOut(to: transitionArguments.transitionNode, addToTransitionSurface: transitionArguments.addToTransitionSurface, completion: {
@ -755,7 +755,7 @@ class GalleryController: ViewController {
self.galleryNode.transitionDataForCentralItem = { [weak self] in self.galleryNode.transitionDataForCentralItem = { [weak self] in
if let strongSelf = self { if let strongSelf = self {
if let centralItemNode = strongSelf.galleryNode.pager.centralItemNode(), let presentationArguments = strongSelf.presentationArguments as? GalleryControllerPresentationArguments { 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) { if let (media, _) = mediaForMessage(message: message), let transitionArguments = presentationArguments.transitionArguments(message.id, media) {
return (transitionArguments.transitionNode, transitionArguments.addToTransitionSurface) return (transitionArguments.transitionNode, transitionArguments.addToTransitionSurface)
} }
@ -803,7 +803,7 @@ class GalleryController: ViewController {
var centralItemIndex: Int? var centralItemIndex: Int?
for entry in self.entries { 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 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 centralItemIndex = items.count
} }
items.append(item) items.append(item)
@ -816,7 +816,7 @@ class GalleryController: ViewController {
if let strongSelf = self { if let strongSelf = self {
var hiddenItem: (MessageId, Media)? var hiddenItem: (MessageId, Media)?
if let index = index { 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) hiddenItem = (message.id, media)
} }
@ -857,7 +857,7 @@ class GalleryController: ViewController {
var nodeAnimatesItself = false var nodeAnimatesItself = false
if let centralItemNode = self.galleryNode.pager.centralItemNode() { 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.centralItemTitle.set(centralItemNode.title())
self.centralItemTitleView.set(centralItemNode.titleView()) self.centralItemTitleView.set(centralItemNode.titleView())
self.centralItemRightBarButtonItem.set(centralItemNode.rightBarButtonItem()) self.centralItemRightBarButtonItem.set(centralItemNode.rightBarButtonItem())
@ -910,7 +910,7 @@ class GalleryController: ViewController {
self.galleryNode.setControlsHidden(true, animated: false) self.galleryNode.setControlsHidden(true, animated: false)
if let centralItemNode = self.galleryNode.pager.centralItemNode(), let itemSize = centralItemNode.contentSize() { if let centralItemNode = self.galleryNode.pager.centralItemNode(), let itemSize = centralItemNode.contentSize() {
self.preferredContentSize = itemSize.aspectFitted(self.view.bounds.size) 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) { func animateOut(animateContent: Bool, completion: @escaping () -> Void) {
self.isDismissed = true self.isDismissed = true
self.pager.isScrollEnabled = false
var contentAnimationCompleted = true var contentAnimationCompleted = true
var interfaceAnimationCompleted = false var interfaceAnimationCompleted = false

View File

@ -103,7 +103,7 @@ final class HashtagSearchControllerNode: ASDisplayNode {
insets.top += toolbarHeight - 4.0 insets.top += toolbarHeight - 4.0
let chatSize = CGSize(width: layout.size.width, height: layout.size.height) 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)) 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 { if chatController.displayNode.supernode == nil {
chatController.viewWillAppear(false) chatController.viewWillAppear(false)

View File

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

View File

@ -81,6 +81,10 @@ final class InstantPageImageNode: ASDisplayNode, InstantPageNode {
} else { } else {
self.imageNode.setSignal(chatMessageVideo(postbox: context.account.postbox, videoReference: fileReference)) 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 { } else if let map = media.media as? TelegramMediaMap {
self.addSubnode(self.pinNode) self.addSubnode(self.pinNode)

View File

@ -404,7 +404,7 @@ final class InstantPageSlideshowNode: ASDisplayNode, InstantPageNode {
super.layout() super.layout()
self.pagerNode.frame = self.bounds 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.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)) 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 statusText = label
statusColor = item.theme.list.itemSecondaryTextColor statusColor = item.theme.list.itemSecondaryTextColor
} else if let _ = peer.botInfo { } else if let _ = peer.botInfo {
if let phoneNumber = peer.phone, phoneNumber.hasPrefix("424") {
statusText = item.strings.Bot_GenericSupportStatus
} else {
statusText = item.strings.Bot_GenericBotStatus statusText = item.strings.Bot_GenericBotStatus
}
statusColor = item.theme.list.itemSecondaryTextColor 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)) { } 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) 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 = self.previewItemWithTag?(tag) {
if let controller = controller as? ContainableController { 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) return (controller, sourceRect)
} else { } else {

View File

@ -16,6 +16,7 @@ enum ItemListDisclosureStyle {
enum ItemListDisclosureLabelStyle { enum ItemListDisclosureLabelStyle {
case text case text
case detailText case detailText
case multilineDetailText
case badge(UIColor) case badge(UIColor)
case color(UIColor) case color(UIColor)
} }
@ -221,27 +222,6 @@ class ItemListDisclosureItemNode: ListViewItemNode {
let itemSeparatorColor: UIColor let itemSeparatorColor: UIColor
var leftInset = 16.0 + params.leftInset 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 { if let _ = item.icon {
leftInset += 43.0 leftInset += 43.0
} }
@ -262,7 +242,7 @@ class ItemListDisclosureItemNode: ListViewItemNode {
case .badge: case .badge:
labelBadgeColor = item.theme.rootController.tabBar.badgeTextColor labelBadgeColor = item.theme.rootController.tabBar.badgeTextColor
labelFont = badgeFont labelFont = badgeFont
case .detailText: case .detailText, .multilineDetailText:
labelBadgeColor = item.theme.list.itemSecondaryTextColor labelBadgeColor = item.theme.list.itemSecondaryTextColor
labelFont = detailFont labelFont = detailFont
labelConstrain = params.width - params.rightInset - 40.0 - leftInset labelConstrain = params.width - params.rightInset - 40.0 - leftInset
@ -270,8 +250,35 @@ class ItemListDisclosureItemNode: ListViewItemNode {
labelBadgeColor = item.theme.list.itemSecondaryTextColor labelBadgeColor = item.theme.list.itemSecondaryTextColor
labelFont = titleFont 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) let layout = ListViewItemNodeLayout(contentSize: contentSize, insets: insets)
@ -286,7 +293,13 @@ class ItemListDisclosureItemNode: ListViewItemNode {
if updateIcon { if updateIcon {
strongSelf.iconNode.image = icon 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 { } else if strongSelf.iconNode.supernode != nil {
strongSelf.iconNode.image = nil strongSelf.iconNode.image = nil
strongSelf.iconNode.removeFromSupernode() strongSelf.iconNode.removeFromSupernode()
@ -368,7 +381,7 @@ class ItemListDisclosureItemNode: ListViewItemNode {
switch item.labelStyle { switch item.labelStyle {
case .badge: case .badge:
labelFrame = CGRect(origin: CGPoint(x: params.width - rightInset - badgeWidth + (badgeWidth - labelLayout.size.width) / 2.0, y: 13.0), size: labelLayout.size) 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) labelFrame = CGRect(origin: CGPoint(x: leftInset, y: 36.0), size: labelLayout.size)
default: default:
labelFrame = CGRect(origin: CGPoint(x: params.width - rightInset - labelLayout.size.width, y: 11.0), size: labelLayout.size) 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 var finised = false
loop: while true { loop: while true {
let isReady = layer.isReadyForMoreMediaData let isReady = layer.isReadyForMoreMediaData
#if DEBUG
if let error = layer.error {
print("MediaPlayerNode error: \(error)")
}
#endif
if isReady { if isReady {
switch takeFrame() { switch takeFrame() {

View File

@ -35,7 +35,7 @@ public final class OverlayMediaController: ViewController {
override public func containerLayoutUpdated(_ layout: ContainerViewLayout, transition: ContainedViewLayoutTransition) { override public func containerLayoutUpdated(_ layout: ContainerViewLayout, transition: ContainedViewLayoutTransition) {
super.containerLayoutUpdated(layout, transition: transition) 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) self.controllerNode.containerLayoutUpdated(updatedLayout, transition: transition)
} }
} }

View File

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

View File

@ -202,7 +202,7 @@ final class PeerSelectionControllerNode: ASDisplayNode {
let contactsInsets = insets 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 { if let searchDisplayController = self.searchDisplayController {

View File

@ -690,7 +690,7 @@ public func chatMessagePhotoInternal(photoData: Signal<(Data?, Data?, Bool), NoE
if let thumbnailImage = thumbnailImage { if let thumbnailImage = thumbnailImage {
let thumbnailSize = CGSize(width: thumbnailImage.width, height: thumbnailImage.height) 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) blurredThumbnailImage = UIImage(cgImage: thumbnailImage)
} else { } else {
let initialThumbnailContextFittingSize = fittedSize.fitted(CGSize(width: 90.0, height: 90.0)) 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) self.containerLayout = (layout, navigationBarFrame.maxY)
transition.updateFrame(node: self.contentNode, frame: CGRect(origin: CGPoint(), size: layout.size)) 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) { func activate(insertSubnode: (ASDisplayNode, Bool) -> Void, placeholder: SearchBarPlaceholderNode) {
@ -104,7 +104,7 @@ final class SearchDisplayController {
insertSubnode(self.contentNode, false) insertSubnode(self.contentNode, false)
self.contentNode.frame = CGRect(origin: CGPoint(), size: layout.size) 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) 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) self?.dismiss(forceAway: false)
}) else { }) else {
self._ready.set(.single(true)) 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 { private struct AccountAttributes: Equatable {
let sortIndex: Int32 let sortIndex: Int32
let isTestingEnvironment: Bool let isTestingEnvironment: Bool
@ -125,7 +145,7 @@ public final class SharedAccountContext {
public var presentGlobalController: (ViewController, Any?) -> Void = { _, _ in } public var presentGlobalController: (ViewController, Any?) -> Void = { _, _ in }
public var presentCrossfadeController: () -> Void = {} 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()) assert(Queue.mainQueue().isCurrent())
self.mainWindow = mainWindow self.mainWindow = mainWindow
self.applicationBindings = applicationBindings self.applicationBindings = applicationBindings
@ -300,6 +320,13 @@ public final class SharedAccountContext {
|> map { result -> (AccountRecordId, Account?, Int32) in |> map { result -> (AccountRecordId, Account?, Int32) in
switch result { switch result {
case let .authorized(account): 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) return (id, account, attributes.sortIndex)
default: default:
return (id, nil, attributes.sortIndex) return (id, nil, attributes.sortIndex)

View File

@ -511,7 +511,7 @@ public class TelegramController: ViewController {
return .single((nil, true)) return .single((nil, true))
case let .HistoryView(view, _, _, _, _): case let .HistoryView(view, _, _, _, _):
for entry in view.entries { for entry in view.entries {
if case let .MessageEntry(message, _, _, _) = entry { if case let .MessageEntry(message, _, _, _, _) = entry {
if message.id == id.messageId { if message.id == id.messageId {
return .single((MessageIndex(message), false)) 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 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 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, 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, attributes: ChatMessageEntryAttributes(isAdmin: false, isContact: false)), disableDate: true)
var node1: ListViewItemNode? var node1: ListViewItemNode?
if let current = currentNode1 { if let current = currentNode1 {

View File

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

View File

@ -588,9 +588,9 @@ class WallpaperGalleryController: ViewController {
bottomMessageText = presentationData.strings.WallpaperPreview_CustomColorBottomText 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) let params = ListViewItemLayoutParams(width: layout.size.width, leftInset: layout.safeInsets.left, rightInset: layout.safeInsets.right)
if let messageNodes = self.messageNodes { if let messageNodes = self.messageNodes {