mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-12-07 23:03:35 +00:00
Merge branch 'master' of gitlab.com:peter-iakovlev/TelegramUI
This commit is contained in:
commit
a1da20afe0
BIN
Images.xcassets/Settings/MenuIcons/AddAccount.imageset/AddAcc.pdf
vendored
Normal file
BIN
Images.xcassets/Settings/MenuIcons/AddAccount.imageset/AddAcc.pdf
vendored
Normal file
Binary file not shown.
12
Images.xcassets/Settings/MenuIcons/AddAccount.imageset/Contents.json
vendored
Normal file
12
Images.xcassets/Settings/MenuIcons/AddAccount.imageset/Contents.json
vendored
Normal file
@ -0,0 +1,12 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"filename" : "AddAcc.pdf"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"version" : 1,
|
||||
"author" : "xcode"
|
||||
}
|
||||
}
|
||||
12
Images.xcassets/Settings/MenuIcons/ChangePhoneNumber.imageset/Contents.json
vendored
Normal file
12
Images.xcassets/Settings/MenuIcons/ChangePhoneNumber.imageset/Contents.json
vendored
Normal file
@ -0,0 +1,12 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"filename" : "Sim.pdf"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"version" : 1,
|
||||
"author" : "xcode"
|
||||
}
|
||||
}
|
||||
BIN
Images.xcassets/Settings/MenuIcons/ChangePhoneNumber.imageset/Sim.pdf
vendored
Normal file
BIN
Images.xcassets/Settings/MenuIcons/ChangePhoneNumber.imageset/Sim.pdf
vendored
Normal file
Binary file not shown.
BIN
Images.xcassets/Settings/MenuIcons/ClearCache.imageset/Cache.pdf
vendored
Normal file
BIN
Images.xcassets/Settings/MenuIcons/ClearCache.imageset/Cache.pdf
vendored
Normal file
Binary file not shown.
12
Images.xcassets/Settings/MenuIcons/ClearCache.imageset/Contents.json
vendored
Normal file
12
Images.xcassets/Settings/MenuIcons/ClearCache.imageset/Contents.json
vendored
Normal file
@ -0,0 +1,12 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"filename" : "Cache.pdf"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"version" : 1,
|
||||
"author" : "xcode"
|
||||
}
|
||||
}
|
||||
12
Images.xcassets/Settings/MenuIcons/SetPasscode.imageset/Contents.json
vendored
Normal file
12
Images.xcassets/Settings/MenuIcons/SetPasscode.imageset/Contents.json
vendored
Normal file
@ -0,0 +1,12 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"filename" : "Passcode.pdf"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"version" : 1,
|
||||
"author" : "xcode"
|
||||
}
|
||||
}
|
||||
BIN
Images.xcassets/Settings/MenuIcons/SetPasscode.imageset/Passcode.pdf
vendored
Normal file
BIN
Images.xcassets/Settings/MenuIcons/SetPasscode.imageset/Passcode.pdf
vendored
Normal file
Binary file not shown.
@ -436,6 +436,8 @@
|
||||
D0B21B13220D6E8C003F741D /* ActionSheetPeerItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0B21B12220D6E8C003F741D /* ActionSheetPeerItem.swift */; };
|
||||
D0B21B15220D85DD003F741D /* TabBarAccountSwitchController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0B21B14220D85DD003F741D /* TabBarAccountSwitchController.swift */; };
|
||||
D0B21B17220D85E7003F741D /* TabBarAccountSwitchControllerNode.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0B21B16220D85E7003F741D /* TabBarAccountSwitchControllerNode.swift */; };
|
||||
D0B21B1F22156D92003F741D /* LegacyCache.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0B21B1E22156D92003F741D /* LegacyCache.swift */; };
|
||||
D0B21B212215B539003F741D /* LogoutOptionsController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0B21B202215B539003F741D /* LogoutOptionsController.swift */; };
|
||||
D0B2F76220506E2A00D3BFB9 /* MediaInputSettings.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0B2F76120506E2A00D3BFB9 /* MediaInputSettings.swift */; };
|
||||
D0B2F76820528E3D00D3BFB9 /* UserInfoEditingPhoneActionItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0B2F76720528E3D00D3BFB9 /* UserInfoEditingPhoneActionItem.swift */; };
|
||||
D0B2F76A2052920D00D3BFB9 /* UserInfoEditingPhoneItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0B2F7692052920D00D3BFB9 /* UserInfoEditingPhoneItem.swift */; };
|
||||
@ -1868,6 +1870,8 @@
|
||||
D0B21B12220D6E8C003F741D /* ActionSheetPeerItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ActionSheetPeerItem.swift; sourceTree = "<group>"; };
|
||||
D0B21B14220D85DD003F741D /* TabBarAccountSwitchController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TabBarAccountSwitchController.swift; sourceTree = "<group>"; };
|
||||
D0B21B16220D85E7003F741D /* TabBarAccountSwitchControllerNode.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TabBarAccountSwitchControllerNode.swift; sourceTree = "<group>"; };
|
||||
D0B21B1E22156D92003F741D /* LegacyCache.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LegacyCache.swift; sourceTree = "<group>"; };
|
||||
D0B21B202215B539003F741D /* LogoutOptionsController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LogoutOptionsController.swift; sourceTree = "<group>"; };
|
||||
D0B2F76120506E2A00D3BFB9 /* MediaInputSettings.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MediaInputSettings.swift; sourceTree = "<group>"; };
|
||||
D0B2F76720528E3D00D3BFB9 /* UserInfoEditingPhoneActionItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserInfoEditingPhoneActionItem.swift; sourceTree = "<group>"; };
|
||||
D0B2F7692052920D00D3BFB9 /* UserInfoEditingPhoneItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserInfoEditingPhoneItem.swift; sourceTree = "<group>"; };
|
||||
@ -3302,6 +3306,7 @@
|
||||
D097C26B20DD1EA5007BB4B8 /* OverlayStatusController.swift */,
|
||||
09F799F921C3542D00820234 /* LegacyWebSearchGallery.swift */,
|
||||
09F79A0C21C88E8900820234 /* LegacyWebSearchEditor.swift */,
|
||||
D0B21B1E22156D92003F741D /* LegacyCache.swift */,
|
||||
);
|
||||
name = "Legacy Components";
|
||||
sourceTree = "<group>";
|
||||
@ -4652,6 +4657,7 @@
|
||||
D0F53BEB1E784DA900117362 /* ChangePhoneNumberCodeController.swift */,
|
||||
D0B21B14220D85DD003F741D /* TabBarAccountSwitchController.swift */,
|
||||
D0B21B16220D85E7003F741D /* TabBarAccountSwitchControllerNode.swift */,
|
||||
D0B21B202215B539003F741D /* LogoutOptionsController.swift */,
|
||||
);
|
||||
name = Settings;
|
||||
sourceTree = "<group>";
|
||||
@ -5638,6 +5644,7 @@
|
||||
D0EC6DA31EB9F58900EBF1C3 /* ChatMessageDateHeader.swift in Sources */,
|
||||
D0EC6DA41EB9F58900EBF1C3 /* ChatMessageActionButtonsNode.swift in Sources */,
|
||||
D0EC6DA51EB9F58900EBF1C3 /* ChatBotInfoItem.swift in Sources */,
|
||||
D0B21B212215B539003F741D /* LogoutOptionsController.swift in Sources */,
|
||||
D0E9BAE41F0574D800F079A4 /* STPBankAccountParams.m in Sources */,
|
||||
D0E412D3206A7DC100BEE4A2 /* DateSelectionActionSheetController.swift in Sources */,
|
||||
D06887F01F72DEE6000AB936 /* ShareInputFieldNode.swift in Sources */,
|
||||
@ -5784,6 +5791,7 @@
|
||||
D0EC6DE81EB9F58900EBF1C3 /* ChatPinnedMessageTitlePanelNode.swift in Sources */,
|
||||
D0EC6DE91EB9F58900EBF1C3 /* ChatInfoTitlePanelNode.swift in Sources */,
|
||||
D0EC6DEA1EB9F58900EBF1C3 /* ChatReportPeerTitlePanelNode.swift in Sources */,
|
||||
D0B21B1F22156D92003F741D /* LegacyCache.swift in Sources */,
|
||||
D0EC6DEB1EB9F58900EBF1C3 /* ChatRequestInProgressTitlePanelNode.swift in Sources */,
|
||||
D0EC6DEC1EB9F58900EBF1C3 /* ChatToastAlertPanelNode.swift in Sources */,
|
||||
D0EC6DED1EB9F58900EBF1C3 /* ChatHistoryNavigationButtonNode.swift in Sources */,
|
||||
|
||||
@ -382,7 +382,7 @@ class AvatarGalleryController: ViewController {
|
||||
self.galleryNode.setControlsHidden(true, animated: false)
|
||||
if let centralItemNode = self.galleryNode.pager.centralItemNode(), let itemSize = centralItemNode.contentSize() {
|
||||
self.preferredContentSize = itemSize.aspectFitted(self.view.bounds.size)
|
||||
self.containerLayoutUpdated(ContainerViewLayout(size: self.preferredContentSize, metrics: LayoutMetrics(), intrinsicInsets: UIEdgeInsets(), safeInsets: UIEdgeInsets(), statusBarHeight: nil, inputHeight: nil, standardInputHeight: 216.0, inputHeightIsInteractivellyChanging: false), transition: .immediate)
|
||||
self.containerLayoutUpdated(ContainerViewLayout(size: self.preferredContentSize, metrics: LayoutMetrics(), intrinsicInsets: UIEdgeInsets(), safeInsets: UIEdgeInsets(), statusBarHeight: nil, inputHeight: nil, standardInputHeight: 216.0, inputHeightIsInteractivellyChanging: false, inVoiceOver: false), transition: .immediate)
|
||||
centralItemNode.activateAsInitial()
|
||||
}
|
||||
}
|
||||
|
||||
@ -313,6 +313,9 @@ private func botCheckoutControllerEntries(presentationData: PresentationData, st
|
||||
private let hasApplePaySupport: Bool = PKPaymentAuthorizationViewController.canMakePayments(usingNetworks: [.visa, .masterCard, .amex])
|
||||
|
||||
private func formSupportApplePay(_ paymentForm: BotPaymentForm) -> Bool {
|
||||
if !hasApplePaySupport {
|
||||
return false
|
||||
}
|
||||
guard let nativeProvider = paymentForm.nativeProvider else {
|
||||
return false
|
||||
}
|
||||
@ -342,10 +345,10 @@ private func formSupportApplePay(_ paymentForm: BotPaymentForm) -> Bool {
|
||||
return merchantId != nil
|
||||
}
|
||||
|
||||
private func availablePaymentMethods(current: BotCheckoutPaymentMethod?, supportsApplePay: Bool) -> [BotCheckoutPaymentMethod] {
|
||||
private func availablePaymentMethods(form: BotPaymentForm, current: BotCheckoutPaymentMethod?) -> [BotCheckoutPaymentMethod] {
|
||||
var methods: [BotCheckoutPaymentMethod] = []
|
||||
if hasApplePaySupport {
|
||||
methods.append(.applePayStripe)
|
||||
if formSupportApplePay(form) && hasApplePaySupport {
|
||||
methods.append(.applePay)
|
||||
}
|
||||
if let current = current {
|
||||
if !methods.contains(current) {
|
||||
@ -595,13 +598,7 @@ final class BotCheckoutControllerNode: ItemListControllerNode<BotCheckoutEntry>,
|
||||
|
||||
openPaymentMethodImpl = { [weak self] in
|
||||
if let strongSelf = self, let paymentForm = strongSelf.paymentFormValue {
|
||||
let supportsApplePay: Bool
|
||||
if formSupportApplePay(paymentForm) {
|
||||
supportsApplePay = true
|
||||
} else {
|
||||
supportsApplePay = false
|
||||
}
|
||||
let methods = availablePaymentMethods(current: strongSelf.currentPaymentMethod, supportsApplePay: supportsApplePay)
|
||||
let methods = availablePaymentMethods(form: paymentForm, current: strongSelf.currentPaymentMethod)
|
||||
if methods.isEmpty {
|
||||
openNewCard()
|
||||
} else {
|
||||
@ -699,7 +696,7 @@ final class BotCheckoutControllerNode: ItemListControllerNode<BotCheckoutEntry>,
|
||||
override func containerLayoutUpdated(_ layout: ContainerViewLayout, navigationBarHeight: CGFloat, transition: ContainedViewLayoutTransition) {
|
||||
var updatedInsets = layout.intrinsicInsets
|
||||
updatedInsets.bottom += BotCheckoutActionButton.diameter + 20.0
|
||||
super.containerLayoutUpdated(ContainerViewLayout(size: layout.size, metrics: layout.metrics, intrinsicInsets: updatedInsets, safeInsets: layout.safeInsets, statusBarHeight: layout.statusBarHeight, inputHeight: layout.inputHeight, standardInputHeight: layout.standardInputHeight, inputHeightIsInteractivellyChanging: layout.inputHeightIsInteractivellyChanging), navigationBarHeight: navigationBarHeight, transition: transition)
|
||||
super.containerLayoutUpdated(ContainerViewLayout(size: layout.size, metrics: layout.metrics, intrinsicInsets: updatedInsets, safeInsets: layout.safeInsets, statusBarHeight: layout.statusBarHeight, inputHeight: layout.inputHeight, standardInputHeight: layout.standardInputHeight, inputHeightIsInteractivellyChanging: layout.inputHeightIsInteractivellyChanging, inVoiceOver: layout.inVoiceOver), navigationBarHeight: navigationBarHeight, transition: transition)
|
||||
|
||||
let actionButtonFrame = CGRect(origin: CGPoint(x: 10.0, y: layout.size.height - 10.0 - BotCheckoutActionButton.diameter - layout.intrinsicInsets.bottom), size: CGSize(width: layout.size.width - 20.0, height: BotCheckoutActionButton.diameter))
|
||||
transition.updateFrame(node: self.actionButton, frame: actionButtonFrame)
|
||||
@ -789,11 +786,10 @@ final class BotCheckoutControllerNode: ItemListControllerNode<BotCheckoutEntry>,
|
||||
}
|
||||
case let .webToken(token):
|
||||
credentials = .generic(data: token.data, saveOnServer: token.saveOnServer)
|
||||
case .applePayStripe:
|
||||
case .applePay:
|
||||
guard let paymentForm = self.paymentFormValue, let nativeProvider = paymentForm.nativeProvider else {
|
||||
return
|
||||
}
|
||||
//NSDictionary *dict = [NSJSONSerialization JSONObjectWithData:[strongSelf->_paymentForm.nativeParams dataUsingEncoding:NSUTF8StringEncoding] options:0 error:nil];
|
||||
guard let nativeParamsData = nativeProvider.params.data(using: .utf8) else {
|
||||
return
|
||||
}
|
||||
|
||||
@ -13,7 +13,7 @@ struct BotCheckoutPaymentWebToken: Equatable {
|
||||
enum BotCheckoutPaymentMethod: Equatable {
|
||||
case savedCredentials(BotPaymentSavedCredentials)
|
||||
case webToken(BotCheckoutPaymentWebToken)
|
||||
case applePayStripe
|
||||
case applePay
|
||||
|
||||
var title: String {
|
||||
switch self {
|
||||
@ -24,7 +24,7 @@ enum BotCheckoutPaymentMethod: Equatable {
|
||||
}
|
||||
case let .webToken(token):
|
||||
return token.title
|
||||
case .applePayStripe:
|
||||
case .applePay:
|
||||
return "Apple Pay"
|
||||
}
|
||||
}
|
||||
@ -63,7 +63,7 @@ final class BotCheckoutPaymentMethodSheetController: ActionSheetController {
|
||||
case let .webToken(token):
|
||||
title = token.title
|
||||
icon = nil
|
||||
case .applePayStripe:
|
||||
case .applePay:
|
||||
title = "Apple Pay"
|
||||
icon = UIImage(bundleImageName: "Bot Payments/ApplePayLogo")?.precomposed()
|
||||
}
|
||||
|
||||
@ -296,7 +296,7 @@ final class BotReceiptControllerNode: ItemListControllerNode<BotReceiptEntry> {
|
||||
override func containerLayoutUpdated(_ layout: ContainerViewLayout, navigationBarHeight: CGFloat, transition: ContainedViewLayoutTransition) {
|
||||
var updatedInsets = layout.intrinsicInsets
|
||||
updatedInsets.bottom += BotCheckoutActionButton.diameter + 20.0
|
||||
super.containerLayoutUpdated(ContainerViewLayout(size: layout.size, metrics: layout.metrics, intrinsicInsets: updatedInsets, safeInsets: layout.safeInsets, statusBarHeight: layout.statusBarHeight, inputHeight: layout.inputHeight, standardInputHeight: layout.standardInputHeight, inputHeightIsInteractivellyChanging: layout.inputHeightIsInteractivellyChanging), navigationBarHeight: navigationBarHeight, transition: transition)
|
||||
super.containerLayoutUpdated(ContainerViewLayout(size: layout.size, metrics: layout.metrics, intrinsicInsets: updatedInsets, safeInsets: layout.safeInsets, statusBarHeight: layout.statusBarHeight, inputHeight: layout.inputHeight, standardInputHeight: layout.standardInputHeight, inputHeightIsInteractivellyChanging: layout.inputHeightIsInteractivellyChanging, inVoiceOver: layout.inVoiceOver), navigationBarHeight: navigationBarHeight, transition: transition)
|
||||
|
||||
let actionButtonFrame = CGRect(origin: CGPoint(x: 10.0, y: layout.size.height - 10.0 - BotCheckoutActionButton.diameter - layout.intrinsicInsets.bottom), size: CGSize(width: layout.size.width - 20.0, height: BotCheckoutActionButton.diameter))
|
||||
transition.updateFrame(node: self.actionButton, frame: actionButtonFrame)
|
||||
|
||||
@ -2454,12 +2454,16 @@ public final class ChatController: TelegramController, KeyShortcutResponder, Gal
|
||||
self?.enqueueChatContextResult(results, result)
|
||||
}, sendBotCommand: { [weak self] botPeer, command in
|
||||
if let strongSelf = self, canSendMessagesToChat(strongSelf.presentationInterfaceState) {
|
||||
if let peer = strongSelf.presentationInterfaceState.renderedPeer?.peer, let addressName = botPeer.addressName {
|
||||
if let peer = strongSelf.presentationInterfaceState.renderedPeer?.peer {
|
||||
let messageText: String
|
||||
if peer is TelegramUser {
|
||||
messageText = command
|
||||
if let addressName = botPeer.addressName {
|
||||
if peer is TelegramUser {
|
||||
messageText = command
|
||||
} else {
|
||||
messageText = command + "@" + addressName
|
||||
}
|
||||
} else {
|
||||
messageText = command + "@" + addressName
|
||||
messageText = command
|
||||
}
|
||||
let replyMessageId = strongSelf.presentationInterfaceState.interfaceState.replyMessageId
|
||||
strongSelf.chatDisplayNode.setupSendActionOnViewUpdate({
|
||||
@ -4815,7 +4819,7 @@ public final class ChatController: TelegramController, KeyShortcutResponder, Gal
|
||||
return .single((nil, true))
|
||||
case let .HistoryView(view, _, _, _, _):
|
||||
for entry in view.entries {
|
||||
if case let .MessageEntry(message, _, _, _) = entry {
|
||||
if case let .MessageEntry(message, _, _, _, _) = entry {
|
||||
if message.id == messageLocation.messageId {
|
||||
return .single((MessageIndex(message), false))
|
||||
}
|
||||
@ -4902,7 +4906,7 @@ public final class ChatController: TelegramController, KeyShortcutResponder, Gal
|
||||
return .complete()
|
||||
case let .HistoryView(view, _, _, _, _):
|
||||
for entry in view.entries {
|
||||
if case let .MessageEntry(message, _, _, _) = entry {
|
||||
if case let .MessageEntry(message, _, _, _, _) = entry {
|
||||
if message.id == messageLocation.messageId {
|
||||
return .single(MessageIndex(message))
|
||||
}
|
||||
@ -5441,7 +5445,7 @@ public final class ChatController: TelegramController, KeyShortcutResponder, Gal
|
||||
let galleryController = AvatarGalleryController(context: self.context, peer: peer, remoteEntries: nil, replaceRootController: { controller, ready in
|
||||
}, synchronousLoad: true)
|
||||
galleryController.setHintWillBePresentedInPreviewingContext(true)
|
||||
galleryController.containerLayoutUpdated(ContainerViewLayout(size: CGSize(width: self.view.bounds.size.width, height: self.view.bounds.size.height), metrics: LayoutMetrics(), intrinsicInsets: UIEdgeInsets(), safeInsets: UIEdgeInsets(), statusBarHeight: nil, inputHeight: nil, standardInputHeight: 216.0, inputHeightIsInteractivellyChanging: false), transition: .immediate)
|
||||
galleryController.containerLayoutUpdated(ContainerViewLayout(size: CGSize(width: self.view.bounds.size.width, height: self.view.bounds.size.height), metrics: LayoutMetrics(), intrinsicInsets: UIEdgeInsets(), safeInsets: UIEdgeInsets(), statusBarHeight: nil, inputHeight: nil, standardInputHeight: 216.0, inputHeightIsInteractivellyChanging: false, inVoiceOver: false), transition: .immediate)
|
||||
return (galleryController, buttonView.convert(buttonView.bounds, to: sourceView))
|
||||
}
|
||||
return nil
|
||||
@ -5478,7 +5482,7 @@ public final class ChatController: TelegramController, KeyShortcutResponder, Gal
|
||||
gallery.setHintWillBePresentedInPreviewingContext(true)
|
||||
let rect = selectedTransitionNode.0.view.convert(selectedTransitionNode.0.bounds, to: sourceView)
|
||||
let sourceRect = rect.insetBy(dx: -2.0, dy: -2.0)
|
||||
gallery.containerLayoutUpdated(ContainerViewLayout(size: CGSize(width: self.view.bounds.size.width, height: self.view.bounds.size.height), metrics: LayoutMetrics(), intrinsicInsets: UIEdgeInsets(), safeInsets: UIEdgeInsets(), statusBarHeight: nil, inputHeight: nil, standardInputHeight: 216.0, inputHeightIsInteractivellyChanging: false), transition: .immediate)
|
||||
gallery.containerLayoutUpdated(ContainerViewLayout(size: CGSize(width: self.view.bounds.size.width, height: self.view.bounds.size.height), metrics: LayoutMetrics(), intrinsicInsets: UIEdgeInsets(), safeInsets: UIEdgeInsets(), statusBarHeight: nil, inputHeight: nil, standardInputHeight: 216.0, inputHeightIsInteractivellyChanging: false, inVoiceOver: false), transition: .immediate)
|
||||
return (gallery, sourceRect)
|
||||
case let .instantPage(gallery, centralIndex, galleryMedia):
|
||||
break
|
||||
|
||||
@ -1361,10 +1361,10 @@ class ChatControllerNode: ASDisplayNode, UIScrollViewDelegate {
|
||||
}
|
||||
|
||||
var restrictionText: String?
|
||||
if chatPresentationInterfaceState.isNotAccessible {
|
||||
if let peer = chatPresentationInterfaceState.renderedPeer?.peer, let restrictionTextValue = peer.restrictionText, !restrictionTextValue.isEmpty {
|
||||
restrictionText = restrictionTextValue
|
||||
} else if chatPresentationInterfaceState.isNotAccessible {
|
||||
restrictionText = chatPresentationInterfaceState.strings.Channel_ErrorAccessDenied
|
||||
} else if let peer = chatPresentationInterfaceState.renderedPeer?.peer {
|
||||
restrictionText = peer.restrictionText
|
||||
}
|
||||
|
||||
if let restrictionText = restrictionText {
|
||||
@ -1557,6 +1557,8 @@ class ChatControllerNode: ASDisplayNode, UIScrollViewDelegate {
|
||||
if let (validLayout, _) = self.validLayout {
|
||||
let _ = inputNode.updateLayout(width: validLayout.size.width, leftInset: validLayout.safeInsets.left, rightInset: validLayout.safeInsets.right, bottomInset: validLayout.intrinsicInsets.bottom, standardInputHeight: validLayout.standardInputHeight, inputHeight: validLayout.inputHeight ?? 0.0, maximumHeight: validLayout.standardInputHeight, inputPanelHeight: 44.0, transition: .immediate, interfaceState: self.chatPresentationInterfaceState, isVisible: false)
|
||||
}
|
||||
|
||||
self.textInputPanelNode?.loadTextInputNodeIfNeeded()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -19,7 +19,7 @@ func chatHistoryEntriesForView(location: ChatLocation, view: MessageHistoryView,
|
||||
}
|
||||
}
|
||||
|
||||
var groupBucket: [(Message, Bool, ChatHistoryMessageSelection, Bool)] = []
|
||||
var groupBucket: [(Message, Bool, ChatHistoryMessageSelection, ChatMessageEntryAttributes)] = []
|
||||
loop: for entry in view.entries {
|
||||
switch entry {
|
||||
case let .HoleEntry(hole, _):
|
||||
@ -30,7 +30,7 @@ func chatHistoryEntriesForView(location: ChatLocation, view: MessageHistoryView,
|
||||
if view.tagMask == nil {
|
||||
entries.append(.HoleEntry(hole, presentationData))
|
||||
}
|
||||
case let .MessageEntry(message, read, _, monthLocation):
|
||||
case let .MessageEntry(message, read, _, monthLocation, attributes):
|
||||
if message.id.peerId.namespace == Namespaces.Peer.CloudChannel {
|
||||
for media in message.media {
|
||||
if let action = media as? TelegramMediaAction {
|
||||
@ -61,7 +61,7 @@ func chatHistoryEntriesForView(location: ChatLocation, view: MessageHistoryView,
|
||||
} else {
|
||||
selection = .none
|
||||
}
|
||||
groupBucket.append((message, read, selection, isAdmin))
|
||||
groupBucket.append((message, read, selection, ChatMessageEntryAttributes(isAdmin: isAdmin, isContact: attributes.authorIsContact)))
|
||||
} else {
|
||||
let selection: ChatHistoryMessageSelection
|
||||
if let selectedMessages = selectedMessages {
|
||||
@ -69,7 +69,7 @@ func chatHistoryEntriesForView(location: ChatLocation, view: MessageHistoryView,
|
||||
} else {
|
||||
selection = .none
|
||||
}
|
||||
entries.append(.MessageEntry(message, presentationData, read, monthLocation, selection, isAdmin))
|
||||
entries.append(.MessageEntry(message, presentationData, read, monthLocation, selection, ChatMessageEntryAttributes(isAdmin: isAdmin, isContact: attributes.authorIsContact)))
|
||||
}
|
||||
} else {
|
||||
let selection: ChatHistoryMessageSelection
|
||||
@ -78,7 +78,7 @@ func chatHistoryEntriesForView(location: ChatLocation, view: MessageHistoryView,
|
||||
} else {
|
||||
selection = .none
|
||||
}
|
||||
entries.append(.MessageEntry(message, presentationData, read, monthLocation, selection, isAdmin))
|
||||
entries.append(.MessageEntry(message, presentationData, read, monthLocation, selection, ChatMessageEntryAttributes(isAdmin: isAdmin, isContact: attributes.authorIsContact)))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -23,10 +23,15 @@ public enum ChatHistoryMessageSelection: Equatable {
|
||||
}
|
||||
}
|
||||
|
||||
public struct ChatMessageEntryAttributes: Equatable {
|
||||
let isAdmin: Bool
|
||||
let isContact: Bool
|
||||
}
|
||||
|
||||
enum ChatHistoryEntry: Identifiable, Comparable {
|
||||
case HoleEntry(MessageHistoryHole, ChatPresentationData)
|
||||
case MessageEntry(Message, ChatPresentationData, Bool, MessageHistoryEntryMonthLocation?, ChatHistoryMessageSelection, Bool)
|
||||
case MessageGroupEntry(MessageGroupInfo, [(Message, Bool, ChatHistoryMessageSelection, Bool)], ChatPresentationData)
|
||||
case MessageEntry(Message, ChatPresentationData, Bool, MessageHistoryEntryMonthLocation?, ChatHistoryMessageSelection, ChatMessageEntryAttributes)
|
||||
case MessageGroupEntry(MessageGroupInfo, [(Message, Bool, ChatHistoryMessageSelection, ChatMessageEntryAttributes)], ChatPresentationData)
|
||||
case UnreadEntry(MessageIndex, ChatPresentationData)
|
||||
case ChatInfoEntry(String, ChatPresentationData)
|
||||
case SearchEntry(PresentationTheme, PresentationStrings)
|
||||
@ -73,9 +78,9 @@ enum ChatHistoryEntry: Identifiable, Comparable {
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
case let .MessageEntry(lhsMessage, lhsPresentationData, lhsRead, _, lhsSelection, lhsIsAdmin):
|
||||
case let .MessageEntry(lhsMessage, lhsPresentationData, lhsRead, _, lhsSelection, lhsAttributes):
|
||||
switch rhs {
|
||||
case let .MessageEntry(rhsMessage, rhsPresentationData, rhsRead, _, rhsSelection, rhsIsAdmin) where MessageIndex(lhsMessage) == MessageIndex(rhsMessage) && lhsMessage.flags == rhsMessage.flags && lhsRead == rhsRead:
|
||||
case let .MessageEntry(rhsMessage, rhsPresentationData, rhsRead, _, rhsSelection, rhsAttributes) where MessageIndex(lhsMessage) == MessageIndex(rhsMessage) && lhsMessage.flags == rhsMessage.flags && lhsRead == rhsRead:
|
||||
if lhsPresentationData !== rhsPresentationData {
|
||||
return false
|
||||
}
|
||||
@ -105,7 +110,7 @@ enum ChatHistoryEntry: Identifiable, Comparable {
|
||||
if lhsSelection != rhsSelection {
|
||||
return false
|
||||
}
|
||||
if lhsIsAdmin != rhsIsAdmin {
|
||||
if lhsAttributes != rhsAttributes {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
@ -115,8 +120,8 @@ enum ChatHistoryEntry: Identifiable, Comparable {
|
||||
case let .MessageGroupEntry(lhsGroupInfo, lhsMessages, lhsPresentationData):
|
||||
if case let .MessageGroupEntry(rhsGroupInfo, rhsMessages, rhsPresentationData) = rhs, lhsGroupInfo == rhsGroupInfo, lhsPresentationData === rhsPresentationData, lhsMessages.count == rhsMessages.count {
|
||||
for i in 0 ..< lhsMessages.count {
|
||||
let (lhsMessage, lhsRead, lhsSelection, lhsIsAdmin) = lhsMessages[i]
|
||||
let (rhsMessage, rhsRead, rhsSelection, rhsIsAdmin) = rhsMessages[i]
|
||||
let (lhsMessage, lhsRead, lhsSelection, lhsAttributes) = lhsMessages[i]
|
||||
let (rhsMessage, rhsRead, rhsSelection, rhsAttributes) = rhsMessages[i]
|
||||
|
||||
if lhsMessage.id != rhsMessage.id {
|
||||
return false
|
||||
@ -159,7 +164,7 @@ enum ChatHistoryEntry: Identifiable, Comparable {
|
||||
}
|
||||
}
|
||||
}
|
||||
if lhsIsAdmin != rhsIsAdmin {
|
||||
if lhsAttributes != rhsAttributes {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
@ -167,11 +167,11 @@ private func maxMessageIndexForEntries(_ view: ChatHistoryView, indexRange: (Int
|
||||
private func mappedInsertEntries(context: AccountContext, chatLocation: ChatLocation, associatedData: ChatMessageItemAssociatedData, controllerInteraction: ChatControllerInteraction, mode: ChatHistoryListMode, entries: [ChatHistoryViewTransitionInsertEntry]) -> [ListViewInsertItem] {
|
||||
return entries.map { entry -> ListViewInsertItem in
|
||||
switch entry.entry {
|
||||
case let .MessageEntry(message, presentationData, read, _, selection, isAdmin):
|
||||
case let .MessageEntry(message, presentationData, read, _, selection, attributes):
|
||||
let item: ListViewItem
|
||||
switch mode {
|
||||
case .bubbles:
|
||||
item = ChatMessageItem(presentationData: presentationData, context: context, chatLocation: chatLocation, associatedData: associatedData, controllerInteraction: controllerInteraction, content: .message(message: message, read: read, selection: selection, isAdmin: isAdmin))
|
||||
item = ChatMessageItem(presentationData: presentationData, context: context, chatLocation: chatLocation, associatedData: associatedData, controllerInteraction: controllerInteraction, content: .message(message: message, read: read, selection: selection, attributes: attributes))
|
||||
case let .list(search, _):
|
||||
item = ListMessageItem(theme: presentationData.theme.theme, strings: presentationData.strings, dateTimeFormat: presentationData.dateTimeFormat, context: context, chatLocation: chatLocation, controllerInteraction: controllerInteraction, message: message, selection: selection, displayHeader: search)
|
||||
}
|
||||
@ -210,11 +210,11 @@ private func mappedInsertEntries(context: AccountContext, chatLocation: ChatLoca
|
||||
private func mappedUpdateEntries(context: AccountContext, chatLocation: ChatLocation, associatedData: ChatMessageItemAssociatedData, controllerInteraction: ChatControllerInteraction, mode: ChatHistoryListMode, entries: [ChatHistoryViewTransitionUpdateEntry]) -> [ListViewUpdateItem] {
|
||||
return entries.map { entry -> ListViewUpdateItem in
|
||||
switch entry.entry {
|
||||
case let .MessageEntry(message, presentationData, read, _, selection, isAdmin):
|
||||
case let .MessageEntry(message, presentationData, read, _, selection, attributes):
|
||||
let item: ListViewItem
|
||||
switch mode {
|
||||
case .bubbles:
|
||||
item = ChatMessageItem(presentationData: presentationData, context: context, chatLocation: chatLocation, associatedData: associatedData, controllerInteraction: controllerInteraction, content: .message(message: message, read: read, selection: selection, isAdmin: isAdmin))
|
||||
item = ChatMessageItem(presentationData: presentationData, context: context, chatLocation: chatLocation, associatedData: associatedData, controllerInteraction: controllerInteraction, content: .message(message: message, read: read, selection: selection, attributes: attributes))
|
||||
case let .list(search, _):
|
||||
item = ListMessageItem(theme: presentationData.theme.theme, strings: presentationData.strings, dateTimeFormat: presentationData.dateTimeFormat, context: context, chatLocation: chatLocation, controllerInteraction: controllerInteraction, message: message, selection: selection, displayHeader: search)
|
||||
}
|
||||
@ -1207,13 +1207,13 @@ public final class ChatHistoryListNode: ListView, ChatHistoryNode {
|
||||
|
||||
loop: for i in 0 ..< historyView.filteredEntries.count {
|
||||
switch historyView.filteredEntries[i] {
|
||||
case let .MessageEntry(message, presentationData, read, _, selection, isAdmin):
|
||||
case let .MessageEntry(message, presentationData, read, _, selection, attributes):
|
||||
if message.id == id {
|
||||
let index = historyView.filteredEntries.count - 1 - i
|
||||
let item: ListViewItem
|
||||
switch self.mode {
|
||||
case .bubbles:
|
||||
item = ChatMessageItem(presentationData: presentationData, context: self.context, chatLocation: self.chatLocation, associatedData: associatedData, controllerInteraction: self.controllerInteraction, content: .message(message: message, read: read, selection: selection, isAdmin: isAdmin))
|
||||
item = ChatMessageItem(presentationData: presentationData, context: self.context, chatLocation: self.chatLocation, associatedData: associatedData, controllerInteraction: self.controllerInteraction, content: .message(message: message, read: read, selection: selection, attributes: attributes))
|
||||
case let .list(search, _):
|
||||
item = ListMessageItem(theme: presentationData.theme.theme, strings: presentationData.strings, dateTimeFormat: presentationData.dateTimeFormat, context: self.context, chatLocation: self.chatLocation, controllerInteraction: self.controllerInteraction, message: message, selection: selection, displayHeader: search)
|
||||
}
|
||||
|
||||
@ -50,7 +50,7 @@ func chatHistoryViewForLocation(_ location: ChatHistoryLocation, account: Accoun
|
||||
switch entry {
|
||||
case .HoleEntry:
|
||||
break inner
|
||||
case let .MessageEntry(message, _, _, _):
|
||||
case let .MessageEntry(message, _, _, _, _):
|
||||
if message.flags.contains(.Incoming) {
|
||||
incomingCount += 1
|
||||
}
|
||||
|
||||
@ -662,6 +662,17 @@ public class ChatListController: TelegramController, KeyShortcutResponder, UIVie
|
||||
self.displayNodeDidLoad()
|
||||
}
|
||||
|
||||
override public func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) {
|
||||
super.traitCollectionDidChange(previousTraitCollection)
|
||||
|
||||
if #available(iOSApplicationExtension 9.0, *) {
|
||||
if !self.didSetup3dTouch && self.traitCollection.forceTouchCapability != .unknown {
|
||||
self.didSetup3dTouch = true
|
||||
self.registerForPreviewingNonNative(with: self, sourceView: self.view, theme: PeekControllerTheme(presentationTheme: self.presentationData.theme))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override public func viewDidAppear(_ animated: Bool) {
|
||||
super.viewDidAppear(animated)
|
||||
|
||||
@ -676,13 +687,7 @@ public class ChatListController: TelegramController, KeyShortcutResponder, UIVie
|
||||
}
|
||||
})
|
||||
#endif
|
||||
|
||||
if !self.didSetup3dTouch {
|
||||
self.didSetup3dTouch = true
|
||||
if #available(iOSApplicationExtension 9.0, *) {
|
||||
self.registerForPreviewingNonNative(with: self, sourceView: self.view, theme: PeekControllerTheme(presentationTheme: self.presentationData.theme))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if let lockViewFrame = self.titleView.lockViewFrame, !self.didShowPasscodeLockTooltipController {
|
||||
self.passcodeLockTooltipDisposable.set(combineLatest(queue: .mainQueue(), ApplicationSpecificNotice.getPasscodeLockTips(accountManager: self.context.sharedContext.accountManager), self.context.sharedContext.accountManager.accessChallengeData() |> take(1)).start(next: { [weak self] tooltipValue, passcodeView in
|
||||
@ -899,7 +904,7 @@ public class ChatListController: TelegramController, KeyShortcutResponder, UIVie
|
||||
|
||||
let chatController = ChatController(context: self.context, chatLocation: .peer(peerId), mode: .standard(previewing: true))
|
||||
chatController.canReadHistory.set(false)
|
||||
chatController.containerLayoutUpdated(ContainerViewLayout(size: contentSize, metrics: LayoutMetrics(), intrinsicInsets: UIEdgeInsets(), safeInsets: UIEdgeInsets(), statusBarHeight: nil, inputHeight: nil, standardInputHeight: 216.0, inputHeightIsInteractivellyChanging: false), transition: .immediate)
|
||||
chatController.containerLayoutUpdated(ContainerViewLayout(size: contentSize, metrics: LayoutMetrics(), intrinsicInsets: UIEdgeInsets(), safeInsets: UIEdgeInsets(), statusBarHeight: nil, inputHeight: nil, standardInputHeight: 216.0, inputHeightIsInteractivellyChanging: false, inVoiceOver: false), transition: .immediate)
|
||||
return (chatController, sourceRect)
|
||||
} else if let messageId = action as? MessageId, messageId.peerId.namespace != Namespaces.Peer.SecretChat {
|
||||
var sourceRect = view.superview!.convert(view.frame, to: sourceView)
|
||||
@ -908,7 +913,7 @@ public class ChatListController: TelegramController, KeyShortcutResponder, UIVie
|
||||
|
||||
let chatController = ChatController(context: self.context, chatLocation: .peer(messageId.peerId), messageId: messageId, mode: .standard(previewing: true))
|
||||
chatController.canReadHistory.set(false)
|
||||
chatController.containerLayoutUpdated(ContainerViewLayout(size: contentSize, metrics: LayoutMetrics(), intrinsicInsets: UIEdgeInsets(), safeInsets: UIEdgeInsets(), statusBarHeight: nil, inputHeight: nil, standardInputHeight: 216.0, inputHeightIsInteractivellyChanging: false), transition: .immediate)
|
||||
chatController.containerLayoutUpdated(ContainerViewLayout(size: contentSize, metrics: LayoutMetrics(), intrinsicInsets: UIEdgeInsets(), safeInsets: UIEdgeInsets(), statusBarHeight: nil, inputHeight: nil, standardInputHeight: 216.0, inputHeightIsInteractivellyChanging: false, inVoiceOver: false), transition: .immediate)
|
||||
return (chatController, sourceRect)
|
||||
}
|
||||
}
|
||||
@ -941,14 +946,14 @@ public class ChatListController: TelegramController, KeyShortcutResponder, UIVie
|
||||
if peer.peerId.namespace != Namespaces.Peer.SecretChat {
|
||||
let chatController = ChatController(context: self.context, chatLocation: .peer(peer.peerId), mode: .standard(previewing: true))
|
||||
chatController.canReadHistory.set(false)
|
||||
chatController.containerLayoutUpdated(ContainerViewLayout(size: contentSize, metrics: LayoutMetrics(), intrinsicInsets: UIEdgeInsets(), safeInsets: UIEdgeInsets(), statusBarHeight: nil, inputHeight: nil, standardInputHeight: 216.0, inputHeightIsInteractivellyChanging: false), transition: .immediate)
|
||||
chatController.containerLayoutUpdated(ContainerViewLayout(size: contentSize, metrics: LayoutMetrics(), intrinsicInsets: UIEdgeInsets(), safeInsets: UIEdgeInsets(), statusBarHeight: nil, inputHeight: nil, standardInputHeight: 216.0, inputHeightIsInteractivellyChanging: false, inVoiceOver: false), transition: .immediate)
|
||||
return (chatController, sourceRect)
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
case let .groupReference(groupId, _, _, _):
|
||||
let chatListController = ChatListController(context: self.context, groupId: groupId, controlsHistoryPreload: false)
|
||||
chatListController.containerLayoutUpdated(ContainerViewLayout(size: contentSize, metrics: LayoutMetrics(), intrinsicInsets: UIEdgeInsets(), safeInsets: UIEdgeInsets(), statusBarHeight: nil, inputHeight: nil, standardInputHeight: 216.0, inputHeightIsInteractivellyChanging: false), transition: .immediate)
|
||||
chatListController.containerLayoutUpdated(ContainerViewLayout(size: contentSize, metrics: LayoutMetrics(), intrinsicInsets: UIEdgeInsets(), safeInsets: UIEdgeInsets(), statusBarHeight: nil, inputHeight: nil, standardInputHeight: 216.0, inputHeightIsInteractivellyChanging: false, inVoiceOver: false), transition: .immediate)
|
||||
return (chatListController, sourceRect)
|
||||
}
|
||||
} else {
|
||||
|
||||
@ -256,6 +256,19 @@ class ChatListItemNode: ItemListRevealOptionsItemNode {
|
||||
} set(value) {
|
||||
}
|
||||
}
|
||||
override var accessibilityAttributedLabel: NSAttributedString? {
|
||||
get {
|
||||
return self.accessibilityLabel.flatMap(NSAttributedString.init(string:))
|
||||
} set(value) {
|
||||
}
|
||||
}
|
||||
override var accessibilityAttributedValue: NSAttributedString? {
|
||||
get {
|
||||
return self.accessibilityValue.flatMap(NSAttributedString.init(string:))
|
||||
} set(value) {
|
||||
}
|
||||
}
|
||||
|
||||
override var accessibilityLabel: String? {
|
||||
get {
|
||||
guard let item = self.item else {
|
||||
@ -366,7 +379,6 @@ class ChatListItemNode: ItemListRevealOptionsItemNode {
|
||||
super.init(layerBacked: false, dynamicBounce: false, rotated: false, seeThrough: false)
|
||||
|
||||
self.isAccessibilityElement = true
|
||||
self.isAccessibilityContainer = true
|
||||
|
||||
self.addSubnode(self.backgroundNode)
|
||||
self.addSubnode(self.separatorNode)
|
||||
@ -1112,6 +1124,9 @@ class ChatListItemNode: ItemListRevealOptionsItemNode {
|
||||
strongSelf.setRevealOptions((left: peerLeftRevealOptions, right: peerRevealOptions))
|
||||
}
|
||||
strongSelf.setRevealOptionsOpened(item.hasActiveRevealControls, animated: true)
|
||||
|
||||
strongSelf.view.accessibilityLabel = strongSelf.accessibilityLabel
|
||||
strongSelf.view.accessibilityValue = strongSelf.accessibilityValue
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@ -145,7 +145,11 @@ private enum ChatListRecentEntry: Comparable, Identifiable {
|
||||
let status: ContactsPeerItemStatus
|
||||
if let user = primaryPeer as? TelegramUser {
|
||||
if let _ = user.botInfo {
|
||||
status = .custom(strings.Bot_GenericBotStatus)
|
||||
if let phoneNumber = user.phone, phoneNumber.hasPrefix("424") {
|
||||
status = .custom(strings.Bot_GenericSupportStatus)
|
||||
} else {
|
||||
status = .custom(strings.Bot_GenericBotStatus)
|
||||
}
|
||||
} else if user.id != context.account.peerId {
|
||||
let presence = peer.presence ?? TelegramUserPresence(status: .none, lastActivity: 0)
|
||||
status = .presence(presence, timeFormat)
|
||||
|
||||
@ -13,6 +13,8 @@ final class ChatMessageAvatarAccessoryItem: ListViewAccessoryItem {
|
||||
private let messageTimestamp: Int32
|
||||
private let emptyColor: UIColor
|
||||
|
||||
private let day: Int32
|
||||
|
||||
init(context: AccountContext, peerId: PeerId, peer: Peer?, messageReference: MessageReference?, messageTimestamp: Int32, emptyColor: UIColor) {
|
||||
self.context = context
|
||||
self.peerId = peerId
|
||||
@ -20,11 +22,17 @@ final class ChatMessageAvatarAccessoryItem: ListViewAccessoryItem {
|
||||
self.messageReference = messageReference
|
||||
self.messageTimestamp = messageTimestamp
|
||||
self.emptyColor = emptyColor
|
||||
|
||||
var t: time_t = time_t(messageTimestamp)
|
||||
var timeinfo: tm = tm()
|
||||
gmtime_r(&t, &timeinfo)
|
||||
|
||||
self.day = timeinfo.tm_mday
|
||||
}
|
||||
|
||||
func isEqualToItem(_ other: ListViewAccessoryItem) -> Bool {
|
||||
if case let other as ChatMessageAvatarAccessoryItem = other {
|
||||
return other.peerId == self.peerId && abs(other.messageTimestamp - self.messageTimestamp) < 10 * 60
|
||||
return other.peerId == self.peerId && self.day == other.day && abs(other.messageTimestamp - self.messageTimestamp) < 10 * 60
|
||||
}
|
||||
|
||||
return false
|
||||
|
||||
@ -316,6 +316,8 @@ class ChatMessageBubbleItemNode: ChatMessageItemView {
|
||||
let currentItem = self.appliedItem
|
||||
|
||||
return { item, params, mergedTop, mergedBottom, dateHeaderAtBottom in
|
||||
let accessibilityData = ChatMessageAccessibilityData(item: item)
|
||||
|
||||
let baseWidth = params.width - params.leftInset - params.rightInset
|
||||
|
||||
let content = item.content
|
||||
@ -484,11 +486,11 @@ class ChatMessageBubbleItemNode: ChatMessageItemView {
|
||||
var authorNameString: String?
|
||||
let authorIsAdmin: Bool
|
||||
switch content {
|
||||
case let .message(message, _, _, isAdmin):
|
||||
case let .message(message, _, _, attributes):
|
||||
if let peer = message.peers[message.id.peerId] as? TelegramChannel, case .broadcast = peer.info {
|
||||
authorIsAdmin = false
|
||||
} else {
|
||||
authorIsAdmin = isAdmin
|
||||
authorIsAdmin = attributes.isAdmin
|
||||
}
|
||||
case .group:
|
||||
authorIsAdmin = false
|
||||
@ -1153,6 +1155,8 @@ class ChatMessageBubbleItemNode: ChatMessageItemView {
|
||||
return (layout, { [weak self] animation, synchronousLoads in
|
||||
if let strongSelf = self {
|
||||
strongSelf.appliedItem = item
|
||||
strongSelf.accessibilityLabel = accessibilityData.label
|
||||
strongSelf.accessibilityValue = accessibilityData.value
|
||||
|
||||
var transition: ContainedViewLayoutTransition = .immediate
|
||||
if case let .System(duration) = animation {
|
||||
|
||||
@ -7,8 +7,8 @@ import SwiftSignalKit
|
||||
import TelegramCore
|
||||
|
||||
public enum ChatMessageItemContent: Sequence {
|
||||
case message(message: Message, read: Bool, selection: ChatHistoryMessageSelection, isAdmin: Bool)
|
||||
case group(messages: [(Message, Bool, ChatHistoryMessageSelection, Bool)])
|
||||
case message(message: Message, read: Bool, selection: ChatHistoryMessageSelection, attributes: ChatMessageEntryAttributes)
|
||||
case group(messages: [(Message, Bool, ChatHistoryMessageSelection, ChatMessageEntryAttributes)])
|
||||
|
||||
func effectivelyIncoming(_ accountPeerId: PeerId) -> Bool {
|
||||
switch self {
|
||||
|
||||
@ -91,46 +91,43 @@ enum ChatMessagePeekPreviewContent {
|
||||
case url(ASDisplayNode, CGRect, String)
|
||||
}
|
||||
|
||||
final class ChatMessageAccessibilityData {
|
||||
let label: String?
|
||||
let value: String?
|
||||
|
||||
init(item: ChatMessageItem) {
|
||||
let label: String
|
||||
let value: String
|
||||
|
||||
if let author = item.message.author {
|
||||
if item.message.effectivelyIncoming(item.context.account.peerId) {
|
||||
label = author.displayTitle
|
||||
} else {
|
||||
label = "Outgoing message"
|
||||
}
|
||||
} else {
|
||||
label = "Post"
|
||||
}
|
||||
|
||||
if let chatPeer = item.message.peers[item.message.id.peerId] {
|
||||
let (_, _, messageText) = chatListItemStrings(strings: item.presentationData.strings, nameDisplayOrder: item.presentationData.nameDisplayOrder, message: item.message, chatPeer: RenderedPeer(peer: chatPeer), accountPeerId: item.context.account.peerId)
|
||||
var result = ""
|
||||
result += "\(messageText)"
|
||||
value = result
|
||||
} else {
|
||||
value = "Empty"
|
||||
}
|
||||
|
||||
self.label = label
|
||||
self.value = value
|
||||
}
|
||||
}
|
||||
|
||||
public class ChatMessageItemView: ListViewItemNode {
|
||||
let layoutConstants = defaultChatMessageItemLayoutConstants
|
||||
|
||||
var item: ChatMessageItem?
|
||||
|
||||
override public var accessibilityLabel: String? {
|
||||
get {
|
||||
guard let item = self.item else {
|
||||
return nil
|
||||
}
|
||||
if let author = item.message.author {
|
||||
if item.message.effectivelyIncoming(item.context.account.peerId) {
|
||||
return author.displayTitle
|
||||
} else {
|
||||
return "Outgoing message"
|
||||
}
|
||||
} else {
|
||||
return "Message"
|
||||
}
|
||||
} set(value) {
|
||||
}
|
||||
}
|
||||
|
||||
override public var accessibilityValue: String? {
|
||||
get {
|
||||
guard let item = self.item else {
|
||||
return nil
|
||||
}
|
||||
if let chatPeer = item.message.peers[item.message.id.peerId] {
|
||||
let (_, initialHideAuthor, messageText) = chatListItemStrings(strings: item.presentationData.strings, nameDisplayOrder: item.presentationData.nameDisplayOrder, message: item.message, chatPeer: RenderedPeer(peer: chatPeer), accountPeerId: item.context.account.peerId)
|
||||
var result = ""
|
||||
result += "\(messageText)"
|
||||
return result
|
||||
} else {
|
||||
return "Empty"
|
||||
}
|
||||
} set(value) {
|
||||
}
|
||||
}
|
||||
|
||||
public required convenience init() {
|
||||
self.init(layerBacked: false)
|
||||
}
|
||||
|
||||
@ -114,7 +114,7 @@ struct ChatRecentActionsEntry: Comparable, Identifiable {
|
||||
|
||||
let action = TelegramMediaActionType.titleUpdated(title: new)
|
||||
let message = Message(stableId: self.entry.stableId, stableVersion: 0, id: MessageId(peerId: peer.id, namespace: Namespaces.Message.Cloud, id: Int32(bitPattern: self.entry.stableId)), globallyUniqueId: self.entry.event.id, groupingKey: nil, groupInfo: nil, timestamp: self.entry.event.date, flags: [.Incoming], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: author, text: "", attributes: [], media: [TelegramMediaAction(action: action)], peers: peers, associatedMessages: SimpleDictionary(), associatedMessageIds: [])
|
||||
return ChatMessageItem(presentationData: self.presentationData, context: context, chatLocation: .peer(peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadNetworkType: .cellular, isRecentActions: true), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, isAdmin: false))
|
||||
return ChatMessageItem(presentationData: self.presentationData, context: context, chatLocation: .peer(peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadNetworkType: .cellular, isRecentActions: true), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, attributes: ChatMessageEntryAttributes(isAdmin: false, isContact: false)))
|
||||
case let .changeAbout(prev, new):
|
||||
var peers = SimpleDictionary<PeerId, Peer>()
|
||||
var author: Peer?
|
||||
@ -145,14 +145,14 @@ struct ChatRecentActionsEntry: Comparable, Identifiable {
|
||||
}
|
||||
let action = TelegramMediaActionType.customText(text: text, entities: entities)
|
||||
let message = Message(stableId: 0, stableVersion: 0, id: MessageId(peerId: peer.id, namespace: Namespaces.Message.Cloud, id: 1), globallyUniqueId: self.entry.event.id, groupingKey: nil, groupInfo: nil, timestamp: self.entry.event.date, flags: [.Incoming], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: author, text: "", attributes: [], media: [TelegramMediaAction(action: action)], peers: peers, associatedMessages: SimpleDictionary(), associatedMessageIds: [])
|
||||
return ChatMessageItem(presentationData: self.presentationData, context: context, chatLocation: .peer(peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadNetworkType: .cellular, isRecentActions: true), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, isAdmin: false))
|
||||
return ChatMessageItem(presentationData: self.presentationData, context: context, chatLocation: .peer(peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadNetworkType: .cellular, isRecentActions: true), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, attributes: ChatMessageEntryAttributes(isAdmin: false, isContact: false)))
|
||||
case .content:
|
||||
let peers = SimpleDictionary<PeerId, Peer>()
|
||||
let attributes: [MessageAttribute] = []
|
||||
let prevMessage = Message(stableId: self.entry.stableId, stableVersion: 0, id: MessageId(peerId: peer.id, namespace: Namespaces.Message.Cloud, id: Int32(bitPattern: self.entry.stableId)), globallyUniqueId: self.entry.event.id, groupingKey: nil, groupInfo: nil, timestamp: self.entry.event.date, flags: [.Incoming], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: author, text: prev, attributes: [], media: [], peers: peers, associatedMessages: SimpleDictionary(), associatedMessageIds: [])
|
||||
|
||||
let message = Message(stableId: self.entry.stableId, stableVersion: 0, id: MessageId(peerId: peer.id, namespace: Namespaces.Message.Cloud, id: Int32(bitPattern: self.entry.stableId)), globallyUniqueId: self.entry.event.id, groupingKey: nil, groupInfo: nil, timestamp: self.entry.event.date, flags: [.Incoming], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: author, text: new, attributes: attributes, media: [], peers: peers, associatedMessages: SimpleDictionary(), associatedMessageIds: [])
|
||||
return ChatMessageItem(presentationData: self.presentationData, context: context, chatLocation: .peer(peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadNetworkType: .cellular, isRecentActions: true), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, isAdmin: false), additionalContent: !prev.isEmpty ? .eventLogPreviousDescription(prevMessage) : nil)
|
||||
return ChatMessageItem(presentationData: self.presentationData, context: context, chatLocation: .peer(peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadNetworkType: .cellular, isRecentActions: true), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, attributes: ChatMessageEntryAttributes(isAdmin: false, isContact: false)), additionalContent: !prev.isEmpty ? .eventLogPreviousDescription(prevMessage) : nil)
|
||||
}
|
||||
case let .changeUsername(prev, new):
|
||||
var peers = SimpleDictionary<PeerId, Peer>()
|
||||
@ -183,7 +183,7 @@ struct ChatRecentActionsEntry: Comparable, Identifiable {
|
||||
}
|
||||
let action: TelegramMediaActionType = TelegramMediaActionType.customText(text: text, entities: entities)
|
||||
let message = Message(stableId: 0, stableVersion: 0, id: MessageId(peerId: peer.id, namespace: Namespaces.Message.Cloud, id: 1), globallyUniqueId: self.entry.event.id, groupingKey: nil, groupInfo: nil, timestamp: self.entry.event.date, flags: [.Incoming], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: author, text: "", attributes: [], media: [TelegramMediaAction(action: action)], peers: peers, associatedMessages: SimpleDictionary(), associatedMessageIds: [])
|
||||
return ChatMessageItem(presentationData: self.presentationData, context: context, chatLocation: .peer(peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadNetworkType: .cellular, isRecentActions: true), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, isAdmin: false))
|
||||
return ChatMessageItem(presentationData: self.presentationData, context: context, chatLocation: .peer(peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadNetworkType: .cellular, isRecentActions: true), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, attributes: ChatMessageEntryAttributes(isAdmin: false, isContact: false)))
|
||||
case .content:
|
||||
var previousAttributes: [MessageAttribute] = []
|
||||
var attributes: [MessageAttribute] = []
|
||||
@ -202,7 +202,7 @@ struct ChatRecentActionsEntry: Comparable, Identifiable {
|
||||
|
||||
let prevMessage = Message(stableId: 0, stableVersion: 0, id: MessageId(peerId: peer.id, namespace: Namespaces.Message.Cloud, id: 1), globallyUniqueId: self.entry.event.id, groupingKey: nil, groupInfo: nil, timestamp: self.entry.event.date, flags: [.Incoming], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: author, text: prevText, attributes: previousAttributes, media: [], peers: peers, associatedMessages: SimpleDictionary(), associatedMessageIds: [])
|
||||
let message = Message(stableId: self.entry.stableId, stableVersion: 0, id: MessageId(peerId: peer.id, namespace: Namespaces.Message.Cloud, id: Int32(bitPattern: self.entry.stableId)), globallyUniqueId: self.entry.event.id, groupingKey: nil, groupInfo: nil, timestamp: self.entry.event.date, flags: [.Incoming], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: author, text: text, attributes: attributes, media: [], peers: peers, associatedMessages: SimpleDictionary(), associatedMessageIds: [])
|
||||
return ChatMessageItem(presentationData: self.presentationData, context: context, chatLocation: .peer(peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadNetworkType: .cellular, isRecentActions: true), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, isAdmin: false), additionalContent: !prev.isEmpty ? .eventLogPreviousLink(prevMessage) : nil)
|
||||
return ChatMessageItem(presentationData: self.presentationData, context: context, chatLocation: .peer(peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadNetworkType: .cellular, isRecentActions: true), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, attributes: ChatMessageEntryAttributes(isAdmin: false, isContact: false)), additionalContent: !prev.isEmpty ? .eventLogPreviousLink(prevMessage) : nil)
|
||||
}
|
||||
case let .changePhoto(_, new):
|
||||
var peers = SimpleDictionary<PeerId, Peer>()
|
||||
@ -220,7 +220,7 @@ struct ChatRecentActionsEntry: Comparable, Identifiable {
|
||||
|
||||
let action = TelegramMediaActionType.photoUpdated(image: photo)
|
||||
let message = Message(stableId: self.entry.stableId, stableVersion: 0, id: MessageId(peerId: peer.id, namespace: Namespaces.Message.Cloud, id: Int32(bitPattern: self.entry.stableId)), globallyUniqueId: self.entry.event.id, groupingKey: nil, groupInfo: nil, timestamp: self.entry.event.date, flags: [.Incoming], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: author, text: "", attributes: [], media: [TelegramMediaAction(action: action)], peers: peers, associatedMessages: SimpleDictionary(), associatedMessageIds: [])
|
||||
return ChatMessageItem(presentationData: self.presentationData, context: context, chatLocation: .peer(peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadNetworkType: .cellular, isRecentActions: true), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, isAdmin: false))
|
||||
return ChatMessageItem(presentationData: self.presentationData, context: context, chatLocation: .peer(peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadNetworkType: .cellular, isRecentActions: true), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, attributes: ChatMessageEntryAttributes(isAdmin: false, isContact: false)))
|
||||
case let .toggleInvites(value):
|
||||
var peers = SimpleDictionary<PeerId, Peer>()
|
||||
var author: Peer?
|
||||
@ -247,7 +247,7 @@ struct ChatRecentActionsEntry: Comparable, Identifiable {
|
||||
}
|
||||
let action = TelegramMediaActionType.customText(text: text, entities: entities)
|
||||
let message = Message(stableId: self.entry.stableId, stableVersion: 0, id: MessageId(peerId: peer.id, namespace: Namespaces.Message.Cloud, id: Int32(bitPattern: self.entry.stableId)), globallyUniqueId: self.entry.event.id, groupingKey: nil, groupInfo: nil, timestamp: self.entry.event.date, flags: [.Incoming], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: author, text: "", attributes: [], media: [TelegramMediaAction(action: action)], peers: peers, associatedMessages: SimpleDictionary(), associatedMessageIds: [])
|
||||
return ChatMessageItem(presentationData: self.presentationData, context: context, chatLocation: .peer(peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadNetworkType: .cellular, isRecentActions: true), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, isAdmin: false))
|
||||
return ChatMessageItem(presentationData: self.presentationData, context: context, chatLocation: .peer(peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadNetworkType: .cellular, isRecentActions: true), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, attributes: ChatMessageEntryAttributes(isAdmin: false, isContact: false)))
|
||||
case let .toggleSignatures(value):
|
||||
var peers = SimpleDictionary<PeerId, Peer>()
|
||||
var author: Peer?
|
||||
@ -274,7 +274,7 @@ struct ChatRecentActionsEntry: Comparable, Identifiable {
|
||||
}
|
||||
let action = TelegramMediaActionType.customText(text: text, entities: entities)
|
||||
let message = Message(stableId: self.entry.stableId, stableVersion: 0, id: MessageId(peerId: peer.id, namespace: Namespaces.Message.Cloud, id: Int32(bitPattern: self.entry.stableId)), globallyUniqueId: self.entry.event.id, groupingKey: nil, groupInfo: nil, timestamp: self.entry.event.date, flags: [.Incoming], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: author, text: "", attributes: [], media: [TelegramMediaAction(action: action)], peers: peers, associatedMessages: SimpleDictionary(), associatedMessageIds: [])
|
||||
return ChatMessageItem(presentationData: self.presentationData, context: context, chatLocation: .peer(peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadNetworkType: .cellular, isRecentActions: true), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, isAdmin: false))
|
||||
return ChatMessageItem(presentationData: self.presentationData, context: context, chatLocation: .peer(peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadNetworkType: .cellular, isRecentActions: true), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, attributes: ChatMessageEntryAttributes(isAdmin: false, isContact: false)))
|
||||
case let .updatePinned(message):
|
||||
switch self.id.contentIndex {
|
||||
case .header:
|
||||
@ -296,7 +296,7 @@ struct ChatRecentActionsEntry: Comparable, Identifiable {
|
||||
|
||||
let action = TelegramMediaActionType.customText(text: text, entities: entities)
|
||||
let message = Message(stableId: 0, stableVersion: 0, id: MessageId(peerId: peer.id, namespace: Namespaces.Message.Cloud, id: 1), globallyUniqueId: self.entry.event.id, groupingKey: nil, groupInfo: nil, timestamp: self.entry.event.date, flags: [.Incoming], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: author, text: "", attributes: [], media: [TelegramMediaAction(action: action)], peers: peers, associatedMessages: SimpleDictionary(), associatedMessageIds: [])
|
||||
return ChatMessageItem(presentationData: self.presentationData, context: context, chatLocation: .peer(peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadNetworkType: .cellular, isRecentActions: true), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, isAdmin: false))
|
||||
return ChatMessageItem(presentationData: self.presentationData, context: context, chatLocation: .peer(peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadNetworkType: .cellular, isRecentActions: true), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, attributes: ChatMessageEntryAttributes(isAdmin: false, isContact: false)))
|
||||
case .content:
|
||||
if let message = message {
|
||||
var peers = SimpleDictionary<PeerId, Peer>()
|
||||
@ -314,7 +314,7 @@ struct ChatRecentActionsEntry: Comparable, Identifiable {
|
||||
}
|
||||
}
|
||||
let message = Message(stableId: self.entry.stableId, stableVersion: 0, id: MessageId(peerId: peer.id, namespace: Namespaces.Message.Cloud, id: Int32(bitPattern: self.entry.stableId)), globallyUniqueId: self.entry.event.id, groupingKey: nil, groupInfo: nil, timestamp: self.entry.event.date, flags: [.Incoming], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: message.author, text: message.text, attributes: attributes, media: message.media, peers: peers, associatedMessages: SimpleDictionary(), associatedMessageIds: [])
|
||||
return ChatMessageItem(presentationData: self.presentationData, context: context, chatLocation: .peer(peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadNetworkType: .cellular, isRecentActions: true), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, isAdmin: false))
|
||||
return ChatMessageItem(presentationData: self.presentationData, context: context, chatLocation: .peer(peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadNetworkType: .cellular, isRecentActions: true), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, attributes: ChatMessageEntryAttributes(isAdmin: false, isContact: false)))
|
||||
} else {
|
||||
var peers = SimpleDictionary<PeerId, Peer>()
|
||||
var author: Peer?
|
||||
@ -336,7 +336,7 @@ struct ChatRecentActionsEntry: Comparable, Identifiable {
|
||||
let action = TelegramMediaActionType.customText(text: text, entities: entities)
|
||||
|
||||
let message = Message(stableId: self.entry.stableId, stableVersion: 0, id: MessageId(peerId: peer.id, namespace: Namespaces.Message.Cloud, id: 0), globallyUniqueId: self.entry.event.id, groupingKey: nil, groupInfo: nil, timestamp: self.entry.event.date, flags: [.Incoming], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: author, text: "", attributes: [], media: [TelegramMediaAction(action: action)], peers: peers, associatedMessages: SimpleDictionary(), associatedMessageIds: [])
|
||||
return ChatMessageItem(presentationData: self.presentationData, context: context, chatLocation: .peer(peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadNetworkType: .cellular, isRecentActions: true), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, isAdmin: false))
|
||||
return ChatMessageItem(presentationData: self.presentationData, context: context, chatLocation: .peer(peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadNetworkType: .cellular, isRecentActions: true), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, attributes: ChatMessageEntryAttributes(isAdmin: false, isContact: false)))
|
||||
}
|
||||
}
|
||||
case let .editMessage(prev, message):
|
||||
@ -381,7 +381,7 @@ struct ChatRecentActionsEntry: Comparable, Identifiable {
|
||||
let action = TelegramMediaActionType.customText(text: text, entities: entities)
|
||||
|
||||
let message = Message(stableId: 0, stableVersion: 0, id: MessageId(peerId: peer.id, namespace: Namespaces.Message.Cloud, id: 1), globallyUniqueId: self.entry.event.id, groupingKey: nil, groupInfo: nil, timestamp: self.entry.event.date, flags: [.Incoming], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: author, text: "", attributes: [], media: [TelegramMediaAction(action: action)], peers: peers, associatedMessages: SimpleDictionary(), associatedMessageIds: [])
|
||||
return ChatMessageItem(presentationData: self.presentationData, context: context, chatLocation: .peer(peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadNetworkType: .cellular, isRecentActions: true), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, isAdmin: false))
|
||||
return ChatMessageItem(presentationData: self.presentationData, context: context, chatLocation: .peer(peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadNetworkType: .cellular, isRecentActions: true), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, attributes: ChatMessageEntryAttributes(isAdmin: false, isContact: false)))
|
||||
case .content:
|
||||
var peers = SimpleDictionary<PeerId, Peer>()
|
||||
var attributes: [MessageAttribute] = []
|
||||
@ -398,7 +398,7 @@ struct ChatRecentActionsEntry: Comparable, Identifiable {
|
||||
}
|
||||
}
|
||||
let message = Message(stableId: self.entry.stableId, stableVersion: 0, id: MessageId(peerId: peer.id, namespace: Namespaces.Message.Cloud, id: Int32(bitPattern: self.entry.stableId)), globallyUniqueId: self.entry.event.id, groupingKey: nil, groupInfo: nil, timestamp: self.entry.event.date, flags: [.Incoming], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: message.author, text: message.text, attributes: attributes, media: message.media, peers: peers, associatedMessages: SimpleDictionary(), associatedMessageIds: [])
|
||||
return ChatMessageItem(presentationData: self.presentationData, context: context, chatLocation: .peer(peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadNetworkType: .cellular, isRecentActions: true), controllerInteraction: controllerInteraction, content: .message(message: filterOriginalMessageFlags(message), read: true, selection: .none, isAdmin: false), additionalContent: !prev.text.isEmpty || !message.text.isEmpty ? .eventLogPreviousMessage(filterOriginalMessageFlags(prev)) : nil)
|
||||
return ChatMessageItem(presentationData: self.presentationData, context: context, chatLocation: .peer(peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadNetworkType: .cellular, isRecentActions: true), controllerInteraction: controllerInteraction, content: .message(message: filterOriginalMessageFlags(message), read: true, selection: .none, attributes: ChatMessageEntryAttributes(isAdmin: false, isContact: false)), additionalContent: !prev.text.isEmpty || !message.text.isEmpty ? .eventLogPreviousMessage(filterOriginalMessageFlags(prev)) : nil)
|
||||
}
|
||||
case let .deleteMessage(message):
|
||||
switch self.id.contentIndex {
|
||||
@ -424,7 +424,7 @@ struct ChatRecentActionsEntry: Comparable, Identifiable {
|
||||
let action = TelegramMediaActionType.customText(text: text, entities: entities)
|
||||
|
||||
let message = Message(stableId: 0, stableVersion: 0, id: MessageId(peerId: peer.id, namespace: Namespaces.Message.Cloud, id: 1), globallyUniqueId: self.entry.event.id, groupingKey: nil, groupInfo: nil, timestamp: self.entry.event.date, flags: [.Incoming], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: author, text: "", attributes: [], media: [TelegramMediaAction(action: action)], peers: peers, associatedMessages: SimpleDictionary(), associatedMessageIds: [])
|
||||
return ChatMessageItem(presentationData: self.presentationData, context: context, chatLocation: .peer(peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadNetworkType: .cellular, isRecentActions: true), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, isAdmin: false))
|
||||
return ChatMessageItem(presentationData: self.presentationData, context: context, chatLocation: .peer(peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadNetworkType: .cellular, isRecentActions: true), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, attributes: ChatMessageEntryAttributes(isAdmin: false, isContact: false)))
|
||||
case .content:
|
||||
var peers = SimpleDictionary<PeerId, Peer>()
|
||||
var attributes: [MessageAttribute] = []
|
||||
@ -448,7 +448,7 @@ struct ChatRecentActionsEntry: Comparable, Identifiable {
|
||||
}
|
||||
}
|
||||
let message = Message(stableId: self.entry.stableId, stableVersion: 0, id: MessageId(peerId: peer.id, namespace: Namespaces.Message.Cloud, id: Int32(bitPattern: self.entry.stableId)), globallyUniqueId: self.entry.event.id, groupingKey: nil, groupInfo: nil, timestamp: self.entry.event.date, flags: [.Incoming], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: message.author, text: message.text, attributes: attributes, media: message.media, peers: peers, associatedMessages: SimpleDictionary(), associatedMessageIds: [])
|
||||
return ChatMessageItem(presentationData: self.presentationData, context: context, chatLocation: .peer(peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadNetworkType: .cellular, isRecentActions: true), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, isAdmin: false))
|
||||
return ChatMessageItem(presentationData: self.presentationData, context: context, chatLocation: .peer(peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadNetworkType: .cellular, isRecentActions: true), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, attributes: ChatMessageEntryAttributes(isAdmin: false, isContact: false)))
|
||||
}
|
||||
case .participantJoin, .participantLeave:
|
||||
var peers = SimpleDictionary<PeerId, Peer>()
|
||||
@ -466,7 +466,7 @@ struct ChatRecentActionsEntry: Comparable, Identifiable {
|
||||
action = TelegramMediaActionType.removedMembers(peerIds: [self.entry.event.peerId])
|
||||
}
|
||||
let message = Message(stableId: self.entry.stableId, stableVersion: 0, id: MessageId(peerId: peer.id, namespace: Namespaces.Message.Cloud, id: Int32(bitPattern: self.entry.stableId)), globallyUniqueId: self.entry.event.id, groupingKey: nil, groupInfo: nil, timestamp: self.entry.event.date, flags: [.Incoming], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: author, text: "", attributes: [], media: [TelegramMediaAction(action: action)], peers: peers, associatedMessages: SimpleDictionary(), associatedMessageIds: [])
|
||||
return ChatMessageItem(presentationData: self.presentationData, context: context, chatLocation: .peer(peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadNetworkType: .cellular, isRecentActions: true), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, isAdmin: false))
|
||||
return ChatMessageItem(presentationData: self.presentationData, context: context, chatLocation: .peer(peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadNetworkType: .cellular, isRecentActions: true), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, attributes: ChatMessageEntryAttributes(isAdmin: false, isContact: false)))
|
||||
case let .participantInvite(participant):
|
||||
var peers = SimpleDictionary<PeerId, Peer>()
|
||||
var author: Peer?
|
||||
@ -483,7 +483,7 @@ struct ChatRecentActionsEntry: Comparable, Identifiable {
|
||||
let action: TelegramMediaActionType
|
||||
action = TelegramMediaActionType.addedMembers(peerIds: [participant.peer.id])
|
||||
let message = Message(stableId: self.entry.stableId, stableVersion: 0, id: MessageId(peerId: peer.id, namespace: Namespaces.Message.Cloud, id: Int32(bitPattern: self.entry.stableId)), globallyUniqueId: self.entry.event.id, groupingKey: nil, groupInfo: nil, timestamp: self.entry.event.date, flags: [.Incoming], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: author, text: "", attributes: [], media: [TelegramMediaAction(action: action)], peers: peers, associatedMessages: SimpleDictionary(), associatedMessageIds: [])
|
||||
return ChatMessageItem(presentationData: self.presentationData, context: context, chatLocation: .peer(peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadNetworkType: .cellular, isRecentActions: true), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, isAdmin: false))
|
||||
return ChatMessageItem(presentationData: self.presentationData, context: context, chatLocation: .peer(peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadNetworkType: .cellular, isRecentActions: true), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, attributes: ChatMessageEntryAttributes(isAdmin: false, isContact: false)))
|
||||
case let .participantToggleBan(prev, new):
|
||||
var peers = SimpleDictionary<PeerId, Peer>()
|
||||
var attributes: [MessageAttribute] = []
|
||||
@ -613,7 +613,7 @@ struct ChatRecentActionsEntry: Comparable, Identifiable {
|
||||
}
|
||||
}
|
||||
let message = Message(stableId: self.entry.stableId, stableVersion: 0, id: MessageId(peerId: peer.id, namespace: Namespaces.Message.Cloud, id: Int32(bitPattern: self.entry.stableId)), globallyUniqueId: self.entry.event.id, groupingKey: nil, groupInfo: nil, timestamp: self.entry.event.date, flags: [.Incoming], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: author, text: text, attributes: attributes, media: [], peers: peers, associatedMessages: SimpleDictionary(), associatedMessageIds: [])
|
||||
return ChatMessageItem(presentationData: self.presentationData, context: context, chatLocation: .peer(peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadNetworkType: .cellular, isRecentActions: true), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, isAdmin: false))
|
||||
return ChatMessageItem(presentationData: self.presentationData, context: context, chatLocation: .peer(peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadNetworkType: .cellular, isRecentActions: true), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, attributes: ChatMessageEntryAttributes(isAdmin: false, isContact: false)))
|
||||
case let .participantToggleAdmin(prev, new):
|
||||
var peers = SimpleDictionary<PeerId, Peer>()
|
||||
var attributes: [MessageAttribute] = []
|
||||
@ -693,7 +693,7 @@ struct ChatRecentActionsEntry: Comparable, Identifiable {
|
||||
}
|
||||
}
|
||||
let message = Message(stableId: self.entry.stableId, stableVersion: 0, id: MessageId(peerId: peer.id, namespace: Namespaces.Message.Cloud, id: Int32(bitPattern: self.entry.stableId)), globallyUniqueId: self.entry.event.id, groupingKey: nil, groupInfo: nil, timestamp: self.entry.event.date, flags: [.Incoming], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: author, text: text, attributes: attributes, media: [], peers: peers, associatedMessages: SimpleDictionary(), associatedMessageIds: [])
|
||||
return ChatMessageItem(presentationData: self.presentationData, context: context, chatLocation: .peer(peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadNetworkType: .cellular, isRecentActions: true), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, isAdmin: false))
|
||||
return ChatMessageItem(presentationData: self.presentationData, context: context, chatLocation: .peer(peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadNetworkType: .cellular, isRecentActions: true), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, attributes: ChatMessageEntryAttributes(isAdmin: false, isContact: false)))
|
||||
case let .changeStickerPack(_, new):
|
||||
var peers = SimpleDictionary<PeerId, Peer>()
|
||||
var author: Peer?
|
||||
@ -722,7 +722,7 @@ struct ChatRecentActionsEntry: Comparable, Identifiable {
|
||||
let action = TelegramMediaActionType.customText(text: text, entities: entities)
|
||||
|
||||
let message = Message(stableId: self.entry.stableId, stableVersion: 0, id: MessageId(peerId: peer.id, namespace: Namespaces.Message.Cloud, id: Int32(bitPattern: self.entry.stableId)), globallyUniqueId: self.entry.event.id, groupingKey: nil, groupInfo: nil, timestamp: self.entry.event.date, flags: [.Incoming], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: author, text: "", attributes: [], media: [TelegramMediaAction(action: action)], peers: peers, associatedMessages: SimpleDictionary(), associatedMessageIds: [])
|
||||
return ChatMessageItem(presentationData: self.presentationData, context: context, chatLocation: .peer(peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadNetworkType: .cellular, isRecentActions: true), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, isAdmin: false))
|
||||
return ChatMessageItem(presentationData: self.presentationData, context: context, chatLocation: .peer(peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadNetworkType: .cellular, isRecentActions: true), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, attributes: ChatMessageEntryAttributes(isAdmin: false, isContact: false)))
|
||||
case let .togglePreHistoryHidden(value):
|
||||
var peers = SimpleDictionary<PeerId, Peer>()
|
||||
var author: Peer?
|
||||
@ -752,7 +752,7 @@ struct ChatRecentActionsEntry: Comparable, Identifiable {
|
||||
let action = TelegramMediaActionType.customText(text: text, entities: entities)
|
||||
|
||||
let message = Message(stableId: self.entry.stableId, stableVersion: 0, id: MessageId(peerId: peer.id, namespace: Namespaces.Message.Cloud, id: Int32(bitPattern: self.entry.stableId)), globallyUniqueId: self.entry.event.id, groupingKey: nil, groupInfo: nil, timestamp: self.entry.event.date, flags: [.Incoming], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: author, text: "", attributes: [], media: [TelegramMediaAction(action: action)], peers: peers, associatedMessages: SimpleDictionary(), associatedMessageIds: [])
|
||||
return ChatMessageItem(presentationData: self.presentationData, context: context, chatLocation: .peer(peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadNetworkType: .cellular, isRecentActions: true), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, isAdmin: false))
|
||||
return ChatMessageItem(presentationData: self.presentationData, context: context, chatLocation: .peer(peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadNetworkType: .cellular, isRecentActions: true), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, attributes: ChatMessageEntryAttributes(isAdmin: false, isContact: false)))
|
||||
case let .updateDefaultBannedRights(prev, new):
|
||||
var peers = SimpleDictionary<PeerId, Peer>()
|
||||
var attributes: [MessageAttribute] = []
|
||||
@ -810,7 +810,7 @@ struct ChatRecentActionsEntry: Comparable, Identifiable {
|
||||
}
|
||||
}
|
||||
let message = Message(stableId: self.entry.stableId, stableVersion: 0, id: MessageId(peerId: peer.id, namespace: Namespaces.Message.Cloud, id: Int32(bitPattern: self.entry.stableId)), globallyUniqueId: self.entry.event.id, groupingKey: nil, groupInfo: nil, timestamp: self.entry.event.date, flags: [.Incoming], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: author, text: text, attributes: attributes, media: [], peers: peers, associatedMessages: SimpleDictionary(), associatedMessageIds: [])
|
||||
return ChatMessageItem(presentationData: self.presentationData, context: context, chatLocation: .peer(peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadNetworkType: .cellular, isRecentActions: true), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, isAdmin: false))
|
||||
return ChatMessageItem(presentationData: self.presentationData, context: context, chatLocation: .peer(peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadNetworkType: .cellular, isRecentActions: true), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, attributes: ChatMessageEntryAttributes(isAdmin: false, isContact: false)))
|
||||
case let .pollStopped(message):
|
||||
switch self.id.contentIndex {
|
||||
case .header:
|
||||
@ -838,7 +838,7 @@ struct ChatRecentActionsEntry: Comparable, Identifiable {
|
||||
let action = TelegramMediaActionType.customText(text: text, entities: entities)
|
||||
|
||||
let message = Message(stableId: 0, stableVersion: 0, id: MessageId(peerId: peer.id, namespace: Namespaces.Message.Cloud, id: 1), globallyUniqueId: self.entry.event.id, groupingKey: nil, groupInfo: nil, timestamp: self.entry.event.date, flags: [.Incoming], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: author, text: "", attributes: [], media: [TelegramMediaAction(action: action)], peers: peers, associatedMessages: SimpleDictionary(), associatedMessageIds: [])
|
||||
return ChatMessageItem(presentationData: self.presentationData, context: context, chatLocation: .peer(peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadNetworkType: .cellular, isRecentActions: true), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, isAdmin: false))
|
||||
return ChatMessageItem(presentationData: self.presentationData, context: context, chatLocation: .peer(peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadNetworkType: .cellular, isRecentActions: true), controllerInteraction: controllerInteraction, content: .message(message: message, read: true, selection: .none, attributes: ChatMessageEntryAttributes(isAdmin: false, isContact: false)))
|
||||
case .content:
|
||||
var peers = SimpleDictionary<PeerId, Peer>()
|
||||
var attributes: [MessageAttribute] = []
|
||||
@ -855,7 +855,7 @@ struct ChatRecentActionsEntry: Comparable, Identifiable {
|
||||
}
|
||||
}
|
||||
let message = Message(stableId: self.entry.stableId, stableVersion: 0, id: MessageId(peerId: peer.id, namespace: Namespaces.Message.Cloud, id: Int32(bitPattern: self.entry.stableId)), globallyUniqueId: self.entry.event.id, groupingKey: nil, groupInfo: nil, timestamp: self.entry.event.date, flags: [.Incoming], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: message.author, text: message.text, attributes: attributes, media: message.media, peers: peers, associatedMessages: SimpleDictionary(), associatedMessageIds: [])
|
||||
return ChatMessageItem(presentationData: self.presentationData, context: context, chatLocation: .peer(peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadNetworkType: .cellular, isRecentActions: true), controllerInteraction: controllerInteraction, content: .message(message: filterOriginalMessageFlags(message), read: true, selection: .none, isAdmin: false), additionalContent: nil)
|
||||
return ChatMessageItem(presentationData: self.presentationData, context: context, chatLocation: .peer(peer.id), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .channel, automaticDownloadNetworkType: .cellular, isRecentActions: true), controllerInteraction: controllerInteraction, content: .message(message: filterOriginalMessageFlags(message), read: true, selection: .none, attributes: ChatMessageEntryAttributes(isAdmin: false, isContact: false)), additionalContent: nil)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -16,6 +16,9 @@ final class ChatTextInputActionButtonsNode: ASDisplayNode {
|
||||
|
||||
super.init()
|
||||
|
||||
self.isAccessibilityElement = true
|
||||
self.accessibilityTraits = UIAccessibilityTraitButton | UIAccessibilityTraitNotEnabled
|
||||
|
||||
self.view.addSubview(self.micButton)
|
||||
self.view.addSubview(self.sendButton)
|
||||
self.addSubnode(self.expandMediaInputButton)
|
||||
@ -37,4 +40,14 @@ final class ChatTextInputActionButtonsNode: ASDisplayNode {
|
||||
}
|
||||
transition.updateSublayerTransformScale(node: self.expandMediaInputButton, scale: CGPoint(x: 1.0, y: expanded ? 1.0 : -1.0))
|
||||
}
|
||||
|
||||
func updateAccessibility() {
|
||||
if self.sendButton.alpha.isZero {
|
||||
self.accessibilityTraits = UIAccessibilityTraitButton | UIAccessibilityTraitNotEnabled
|
||||
self.accessibilityLabel = "Send"
|
||||
} else {
|
||||
self.accessibilityTraits = UIAccessibilityTraitButton
|
||||
self.accessibilityLabel = "Send"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -391,6 +391,7 @@ class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDelegate {
|
||||
|
||||
self.actionButtons.sendButton.addTarget(self, action: #selector(self.sendButtonPressed), for: .touchUpInside)
|
||||
self.actionButtons.sendButton.alpha = 0.0
|
||||
self.actionButtons.updateAccessibility()
|
||||
|
||||
self.actionButtons.expandMediaInputButton.addTarget(self, action: #selector(self.expandButtonPressed), forControlEvents: .touchUpInside)
|
||||
self.actionButtons.expandMediaInputButton.alpha = 0.0
|
||||
@ -422,6 +423,12 @@ class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDelegate {
|
||||
fatalError("init(coder:) has not been implemented")
|
||||
}
|
||||
|
||||
func loadTextInputNodeIfNeeded() {
|
||||
if self.textInputNode == nil {
|
||||
self.loadTextInputNode()
|
||||
}
|
||||
}
|
||||
|
||||
private func loadTextInputNode() {
|
||||
let textInputNode = EditableTextNode()
|
||||
textInputNode.initialPrimaryLanguage = self.presentationInterfaceState?.interfaceState.inputLanguage
|
||||
@ -1109,6 +1116,7 @@ class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDelegate {
|
||||
|
||||
if !self.actionButtons.sendButton.alpha.isZero {
|
||||
self.actionButtons.sendButton.alpha = 0.0
|
||||
self.actionButtons.updateAccessibility()
|
||||
if animated {
|
||||
self.actionButtons.animatingSendButton = true
|
||||
self.actionButtons.sendButton.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.2, completion: { [weak self] _ in
|
||||
@ -1142,6 +1150,7 @@ class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDelegate {
|
||||
hideMicButton = true
|
||||
if self.actionButtons.sendButton.alpha.isZero {
|
||||
self.actionButtons.sendButton.alpha = 1.0
|
||||
self.actionButtons.updateAccessibility()
|
||||
if animated {
|
||||
self.actionButtons.sendButton.layer.animateAlpha(from: 0.0, to: 1.0, duration: 0.1)
|
||||
if animateWithBounce {
|
||||
@ -1154,6 +1163,7 @@ class ChatTextInputPanelNode: ChatInputPanelNode, ASEditableTextNodeDelegate {
|
||||
} else {
|
||||
if !self.actionButtons.sendButton.alpha.isZero {
|
||||
self.actionButtons.sendButton.alpha = 0.0
|
||||
self.actionButtons.updateAccessibility()
|
||||
if animated {
|
||||
self.actionButtons.animatingSendButton = true
|
||||
self.actionButtons.sendButton.layer.animateAlpha(from: 1.0, to: 0.0, duration: 0.2, completion: { [weak self] _ in
|
||||
|
||||
@ -337,7 +337,13 @@ final class ChatTitleView: UIView, NavigationBarTitleView {
|
||||
shouldUpdateLayout = true
|
||||
}
|
||||
} else if let _ = user.botInfo {
|
||||
let string = NSAttributedString(string: self.strings.Bot_GenericBotStatus, font: Font.regular(13.0), textColor: self.theme.rootController.navigationBar.secondaryTextColor)
|
||||
let statusText: String
|
||||
if let phoneNumber = user.phone, phoneNumber.hasPrefix("424") {
|
||||
statusText = self.strings.Bot_GenericSupportStatus
|
||||
} else {
|
||||
statusText = self.strings.Bot_GenericBotStatus
|
||||
}
|
||||
let string = NSAttributedString(string: statusText, font: Font.regular(13.0), textColor: self.theme.rootController.navigationBar.secondaryTextColor)
|
||||
if self.infoNode.attributedText == nil || !self.infoNode.attributedText!.isEqual(to: string) {
|
||||
self.infoNode.attributedText = string
|
||||
shouldUpdateLayout = true
|
||||
@ -455,9 +461,14 @@ final class ChatTitleView: UIView, NavigationBarTitleView {
|
||||
break
|
||||
}
|
||||
|
||||
self.accessibilityLabel = self.titleNode.attributedText?.string
|
||||
self.accessibilityValue = self.infoNode.attributedText?.string
|
||||
|
||||
if shouldUpdateLayout {
|
||||
self.setNeedsLayout()
|
||||
}
|
||||
} else {
|
||||
self.accessibilityLabel = nil
|
||||
}
|
||||
}
|
||||
|
||||
@ -499,6 +510,9 @@ final class ChatTitleView: UIView, NavigationBarTitleView {
|
||||
|
||||
super.init(frame: CGRect())
|
||||
|
||||
self.isAccessibilityElement = true
|
||||
self.accessibilityTraits = UIAccessibilityTraitHeader
|
||||
|
||||
self.addSubnode(self.contentContainer)
|
||||
self.contentContainer.addSubnode(self.titleNode)
|
||||
self.contentContainer.addSubnode(self.infoNode)
|
||||
|
||||
@ -101,7 +101,7 @@ final class ComposeControllerNode: ASDisplayNode {
|
||||
searchDisplayController.containerLayoutUpdated(layout, navigationBarHeight: navigationBarHeight, transition: transition)
|
||||
}
|
||||
|
||||
self.contactListNode.containerLayoutUpdated(ContainerViewLayout(size: layout.size, metrics: layout.metrics, intrinsicInsets: insets, safeInsets: layout.safeInsets, statusBarHeight: layout.statusBarHeight, inputHeight: layout.inputHeight, standardInputHeight: layout.standardInputHeight, inputHeightIsInteractivellyChanging: layout.inputHeightIsInteractivellyChanging), headerInsets: headerInsets, transition: transition)
|
||||
self.contactListNode.containerLayoutUpdated(ContainerViewLayout(size: layout.size, metrics: layout.metrics, intrinsicInsets: insets, safeInsets: layout.safeInsets, statusBarHeight: layout.statusBarHeight, inputHeight: layout.inputHeight, standardInputHeight: layout.standardInputHeight, inputHeightIsInteractivellyChanging: layout.inputHeightIsInteractivellyChanging, inVoiceOver: layout.inVoiceOver), headerInsets: headerInsets, transition: transition)
|
||||
|
||||
self.contactListNode.frame = CGRect(origin: CGPoint(), size: layout.size)
|
||||
}
|
||||
|
||||
@ -115,7 +115,7 @@ final class ContactMultiselectionControllerNode: ASDisplayNode {
|
||||
var headerInsets = layout.insets(options: [.input])
|
||||
headerInsets.top += actualNavigationBarHeight
|
||||
headerInsets.top += strongSelf.tokenListNode.bounds.size.height
|
||||
searchResultsNode.containerLayoutUpdated(ContainerViewLayout(size: layout.size, metrics: layout.metrics, intrinsicInsets: insets, safeInsets: layout.safeInsets, statusBarHeight: layout.statusBarHeight, inputHeight: layout.inputHeight, standardInputHeight: layout.standardInputHeight, inputHeightIsInteractivellyChanging: layout.inputHeightIsInteractivellyChanging), headerInsets: headerInsets, transition: .immediate)
|
||||
searchResultsNode.containerLayoutUpdated(ContainerViewLayout(size: layout.size, metrics: layout.metrics, intrinsicInsets: insets, safeInsets: layout.safeInsets, statusBarHeight: layout.statusBarHeight, inputHeight: layout.inputHeight, standardInputHeight: layout.standardInputHeight, inputHeightIsInteractivellyChanging: layout.inputHeightIsInteractivellyChanging, inVoiceOver: layout.inVoiceOver), headerInsets: headerInsets, transition: .immediate)
|
||||
searchResultsNode.frame = CGRect(origin: CGPoint(), size: layout.size)
|
||||
}
|
||||
|
||||
@ -168,11 +168,11 @@ final class ContactMultiselectionControllerNode: ASDisplayNode {
|
||||
insets.top += tokenListHeight
|
||||
headerInsets.top += tokenListHeight
|
||||
|
||||
self.contactListNode.containerLayoutUpdated(ContainerViewLayout(size: layout.size, metrics: layout.metrics, intrinsicInsets: insets, safeInsets: layout.safeInsets, statusBarHeight: layout.statusBarHeight, inputHeight: layout.inputHeight, standardInputHeight: layout.standardInputHeight, inputHeightIsInteractivellyChanging: layout.inputHeightIsInteractivellyChanging), headerInsets: headerInsets, transition: transition)
|
||||
self.contactListNode.containerLayoutUpdated(ContainerViewLayout(size: layout.size, metrics: layout.metrics, intrinsicInsets: insets, safeInsets: layout.safeInsets, statusBarHeight: layout.statusBarHeight, inputHeight: layout.inputHeight, standardInputHeight: layout.standardInputHeight, inputHeightIsInteractivellyChanging: layout.inputHeightIsInteractivellyChanging, inVoiceOver: layout.inVoiceOver), headerInsets: headerInsets, transition: transition)
|
||||
self.contactListNode.frame = CGRect(origin: CGPoint(), size: layout.size)
|
||||
|
||||
if let searchResultsNode = self.searchResultsNode {
|
||||
searchResultsNode.containerLayoutUpdated(ContainerViewLayout(size: layout.size, metrics: layout.metrics, intrinsicInsets: insets, safeInsets: layout.safeInsets, statusBarHeight: layout.statusBarHeight, inputHeight: layout.inputHeight, standardInputHeight: layout.standardInputHeight, inputHeightIsInteractivellyChanging: layout.inputHeightIsInteractivellyChanging), headerInsets: headerInsets, transition: transition)
|
||||
searchResultsNode.containerLayoutUpdated(ContainerViewLayout(size: layout.size, metrics: layout.metrics, intrinsicInsets: insets, safeInsets: layout.safeInsets, statusBarHeight: layout.statusBarHeight, inputHeight: layout.inputHeight, standardInputHeight: layout.standardInputHeight, inputHeightIsInteractivellyChanging: layout.inputHeightIsInteractivellyChanging, inVoiceOver: layout.inVoiceOver), headerInsets: headerInsets, transition: transition)
|
||||
searchResultsNode.frame = CGRect(origin: CGPoint(), size: layout.size)
|
||||
}
|
||||
}
|
||||
|
||||
@ -95,7 +95,7 @@ final class ContactSelectionControllerNode: ASDisplayNode {
|
||||
searchDisplayController.containerLayoutUpdated(layout, navigationBarHeight: navigationBarHeight, transition: transition)
|
||||
}
|
||||
|
||||
self.contactListNode.containerLayoutUpdated(ContainerViewLayout(size: layout.size, metrics: layout.metrics, intrinsicInsets: insets, safeInsets: layout.safeInsets, statusBarHeight: layout.statusBarHeight, inputHeight: layout.inputHeight, standardInputHeight: layout.standardInputHeight, inputHeightIsInteractivellyChanging: layout.inputHeightIsInteractivellyChanging), headerInsets: headerInsets, transition: transition)
|
||||
self.contactListNode.containerLayoutUpdated(ContainerViewLayout(size: layout.size, metrics: layout.metrics, intrinsicInsets: insets, safeInsets: layout.safeInsets, statusBarHeight: layout.statusBarHeight, inputHeight: layout.inputHeight, standardInputHeight: layout.standardInputHeight, inputHeightIsInteractivellyChanging: layout.inputHeightIsInteractivellyChanging, inVoiceOver: layout.inVoiceOver), headerInsets: headerInsets, transition: transition)
|
||||
|
||||
self.contactListNode.frame = CGRect(origin: CGPoint(), size: layout.size)
|
||||
|
||||
|
||||
@ -113,7 +113,7 @@ final class ContactsControllerNode: ASDisplayNode {
|
||||
searchDisplayController.containerLayoutUpdated(layout, navigationBarHeight: navigationBarHeight, transition: transition)
|
||||
}
|
||||
|
||||
self.contactListNode.containerLayoutUpdated(ContainerViewLayout(size: layout.size, metrics: layout.metrics, intrinsicInsets: insets, safeInsets: layout.safeInsets, statusBarHeight: layout.statusBarHeight, inputHeight: layout.inputHeight, standardInputHeight: layout.standardInputHeight, inputHeightIsInteractivellyChanging: layout.inputHeightIsInteractivellyChanging), headerInsets: headerInsets, transition: transition)
|
||||
self.contactListNode.containerLayoutUpdated(ContainerViewLayout(size: layout.size, metrics: layout.metrics, intrinsicInsets: insets, safeInsets: layout.safeInsets, statusBarHeight: layout.statusBarHeight, inputHeight: layout.inputHeight, standardInputHeight: layout.standardInputHeight, inputHeightIsInteractivellyChanging: layout.inputHeightIsInteractivellyChanging, inVoiceOver: layout.inVoiceOver), headerInsets: headerInsets, transition: transition)
|
||||
|
||||
self.contactListNode.frame = CGRect(origin: CGPoint(), size: layout.size)
|
||||
}
|
||||
|
||||
@ -314,6 +314,8 @@ func editSettingsController(context: AccountContext, currentName: ItemListAvatar
|
||||
let avatarAndNameInfoContext = ItemListAvatarAndNameInfoItemContext()
|
||||
var updateHiddenAvatarImpl: (() -> Void)?
|
||||
var changeProfilePhotoImpl: (() -> Void)?
|
||||
|
||||
var getNavigationController: (() -> NavigationController?)?
|
||||
|
||||
let arguments = EditSettingsItemArguments(context: context, accountManager: accountManager, avatarAndNameInfoContext: avatarAndNameInfoContext, avatarTapAction: {
|
||||
var updating = false
|
||||
@ -373,15 +375,14 @@ func editSettingsController(context: AccountContext, currentName: ItemListAvatar
|
||||
let isTestingEnvironment = context.account.testingEnvironment
|
||||
context.sharedContext.beginNewAuth(testingEnvironment: isTestingEnvironment)
|
||||
}, logout: {
|
||||
let presentationData = context.sharedContext.currentPresentationData.with { $0 }
|
||||
let alertController = standardTextAlertController(theme: AlertControllerTheme(presentationTheme: presentationData.theme), title: presentationData.strings.Settings_LogoutConfirmationTitle, text: presentationData.strings.Settings_LogoutConfirmationText, actions: [
|
||||
TextAlertAction(type: .genericAction, title: presentationData.strings.Common_Cancel, action: {
|
||||
}),
|
||||
TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_OK, action: {
|
||||
let _ = logoutFromAccount(id: context.account.id, accountManager: accountManager).start()
|
||||
})
|
||||
])
|
||||
presentControllerImpl?(alertController, nil)
|
||||
let _ = (context.account.postbox.transaction { transaction -> String in
|
||||
return (transaction.getPeer(context.account.peerId) as? TelegramUser)?.phone ?? ""
|
||||
}
|
||||
|> deliverOnMainQueue).start(next: { phoneNumber in
|
||||
if let navigationController = getNavigationController?() {
|
||||
presentControllerImpl?(logoutOptionsController(context: context, navigationController: navigationController, canAddAccounts: canAddAccounts, phoneNumber: phoneNumber), ViewControllerPresentationArguments(presentationAnimation: .modalSheet))
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
let peerView = context.account.viewTracker.peerView(context.account.peerId)
|
||||
@ -557,6 +558,10 @@ func editSettingsController(context: AccountContext, currentName: ItemListAvatar
|
||||
})
|
||||
}
|
||||
|
||||
getNavigationController = { [weak controller] in
|
||||
return controller?.navigationController as? NavigationController
|
||||
}
|
||||
|
||||
return controller
|
||||
}
|
||||
|
||||
|
||||
@ -133,7 +133,7 @@ private func galleryMessageCaptionText(_ message: Message) -> String {
|
||||
|
||||
func galleryItemForEntry(context: AccountContext, presentationData: PresentationData, entry: MessageHistoryEntry, isCentral: Bool = false, streamVideos: Bool, loopVideos: Bool = false, hideControls: Bool = false, fromPlayingVideo: Bool = false, tempFilePath: String? = nil, playbackCompleted: @escaping () -> Void = {}, performAction: @escaping (GalleryControllerInteractionTapAction) -> Void = { _ in }, openActionOptions: @escaping (GalleryControllerInteractionTapAction) -> Void = { _ in }) -> GalleryItem? {
|
||||
switch entry {
|
||||
case let .MessageEntry(message, _, location, _):
|
||||
case let .MessageEntry(message, _, location, _, _):
|
||||
if let (media, mediaImage) = mediaForMessage(message: message) {
|
||||
if let _ = media as? TelegramMediaImage {
|
||||
return ChatImageGalleryItem(context: context, presentationData: presentationData, message: message, location: location, performAction: performAction, openActionOptions: openActionOptions)
|
||||
@ -359,10 +359,10 @@ class GalleryController: ViewController {
|
||||
return .single(mapped)
|
||||
}
|
||||
} else {
|
||||
return .single(GalleryMessageHistoryView.single(MessageHistoryEntry.MessageEntry(message!, false, nil, nil)))
|
||||
return .single(GalleryMessageHistoryView.single(MessageHistoryEntry.MessageEntry(message!, false, nil, nil, MutableMessageHistoryEntryAttributes(authorIsContact: false))))
|
||||
}
|
||||
case .standaloneMessage:
|
||||
return .single(GalleryMessageHistoryView.single(MessageHistoryEntry.MessageEntry(message!, false, nil, nil)))
|
||||
return .single(GalleryMessageHistoryView.single(MessageHistoryEntry.MessageEntry(message!, false, nil, nil, MutableMessageHistoryEntryAttributes(authorIsContact: false))))
|
||||
}
|
||||
}
|
||||
|> take(1)
|
||||
@ -389,7 +389,7 @@ class GalleryController: ViewController {
|
||||
var centralEntryStableId: UInt32?
|
||||
loop: for i in 0 ..< entries.count {
|
||||
switch entries[i] {
|
||||
case let .MessageEntry(message, _, _, _):
|
||||
case let .MessageEntry(message, _, _, _, _):
|
||||
switch source {
|
||||
case let .peerMessagesAtId(messageId):
|
||||
if message.id == messageId {
|
||||
@ -420,7 +420,7 @@ class GalleryController: ViewController {
|
||||
var centralItemIndex: Int?
|
||||
for entry in strongSelf.entries {
|
||||
var isCentral = false
|
||||
if case let .MessageEntry(message, _, _, _) = entry, message.stableId == strongSelf.centralEntryStableId {
|
||||
if case let .MessageEntry(message, _, _, _, _) = entry, message.stableId == strongSelf.centralEntryStableId {
|
||||
isCentral = true
|
||||
}
|
||||
if let item = galleryItemForEntry(context: context, presentationData: strongSelf.presentationData, entry: entry, isCentral: isCentral, streamVideos: streamSingleVideo, fromPlayingVideo: isCentral && fromPlayingVideo, performAction: strongSelf.performAction, openActionOptions: strongSelf.openActionOptions) {
|
||||
@ -717,7 +717,7 @@ class GalleryController: ViewController {
|
||||
}
|
||||
|
||||
if let centralItemNode = self.galleryNode.pager.centralItemNode(), let presentationArguments = self.presentationArguments as? GalleryControllerPresentationArguments {
|
||||
if case let .MessageEntry(message, _, _, _) = self.entries[centralItemNode.index] {
|
||||
if case let .MessageEntry(message, _, _, _, _) = self.entries[centralItemNode.index] {
|
||||
if let (media, _) = mediaForMessage(message: message), let transitionArguments = presentationArguments.transitionArguments(message.id, media), !forceAway {
|
||||
animatedOutNode = false
|
||||
centralItemNode.animateOut(to: transitionArguments.transitionNode, addToTransitionSurface: transitionArguments.addToTransitionSurface, completion: {
|
||||
@ -755,7 +755,7 @@ class GalleryController: ViewController {
|
||||
self.galleryNode.transitionDataForCentralItem = { [weak self] in
|
||||
if let strongSelf = self {
|
||||
if let centralItemNode = strongSelf.galleryNode.pager.centralItemNode(), let presentationArguments = strongSelf.presentationArguments as? GalleryControllerPresentationArguments {
|
||||
if case let .MessageEntry(message, _, _, _) = strongSelf.entries[centralItemNode.index] {
|
||||
if case let .MessageEntry(message, _, _, _, _) = strongSelf.entries[centralItemNode.index] {
|
||||
if let (media, _) = mediaForMessage(message: message), let transitionArguments = presentationArguments.transitionArguments(message.id, media) {
|
||||
return (transitionArguments.transitionNode, transitionArguments.addToTransitionSurface)
|
||||
}
|
||||
@ -803,7 +803,7 @@ class GalleryController: ViewController {
|
||||
var centralItemIndex: Int?
|
||||
for entry in self.entries {
|
||||
if let item = galleryItemForEntry(context: context, presentationData: self.presentationData, entry: entry, streamVideos: self.streamVideos, fromPlayingVideo: self.fromPlayingVideo, performAction: self.performAction, openActionOptions: self.openActionOptions) {
|
||||
if case let .MessageEntry(message, _, _, _) = entry, message.stableId == self.centralEntryStableId {
|
||||
if case let .MessageEntry(message, _, _, _, _) = entry, message.stableId == self.centralEntryStableId {
|
||||
centralItemIndex = items.count
|
||||
}
|
||||
items.append(item)
|
||||
@ -816,7 +816,7 @@ class GalleryController: ViewController {
|
||||
if let strongSelf = self {
|
||||
var hiddenItem: (MessageId, Media)?
|
||||
if let index = index {
|
||||
if case let .MessageEntry(message, _, _, _) = strongSelf.entries[index], let (media, _) = mediaForMessage(message: message) {
|
||||
if case let .MessageEntry(message, _, _, _, _) = strongSelf.entries[index], let (media, _) = mediaForMessage(message: message) {
|
||||
hiddenItem = (message.id, media)
|
||||
}
|
||||
|
||||
@ -857,7 +857,7 @@ class GalleryController: ViewController {
|
||||
var nodeAnimatesItself = false
|
||||
|
||||
if let centralItemNode = self.galleryNode.pager.centralItemNode() {
|
||||
if case let .MessageEntry(message, _, _, _) = self.entries[centralItemNode.index] {
|
||||
if case let .MessageEntry(message, _, _, _, _) = self.entries[centralItemNode.index] {
|
||||
self.centralItemTitle.set(centralItemNode.title())
|
||||
self.centralItemTitleView.set(centralItemNode.titleView())
|
||||
self.centralItemRightBarButtonItem.set(centralItemNode.rightBarButtonItem())
|
||||
@ -910,7 +910,7 @@ class GalleryController: ViewController {
|
||||
self.galleryNode.setControlsHidden(true, animated: false)
|
||||
if let centralItemNode = self.galleryNode.pager.centralItemNode(), let itemSize = centralItemNode.contentSize() {
|
||||
self.preferredContentSize = itemSize.aspectFitted(self.view.bounds.size)
|
||||
self.containerLayoutUpdated(ContainerViewLayout(size: self.preferredContentSize, metrics: LayoutMetrics(), intrinsicInsets: UIEdgeInsets(), safeInsets: UIEdgeInsets(), statusBarHeight: nil, inputHeight: nil, standardInputHeight: 216.0, inputHeightIsInteractivellyChanging: false), transition: .immediate)
|
||||
self.containerLayoutUpdated(ContainerViewLayout(size: self.preferredContentSize, metrics: LayoutMetrics(), intrinsicInsets: UIEdgeInsets(), safeInsets: UIEdgeInsets(), statusBarHeight: nil, inputHeight: nil, standardInputHeight: 216.0, inputHeightIsInteractivellyChanging: false, inVoiceOver: false), transition: .immediate)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -263,6 +263,8 @@ class GalleryControllerNode: ASDisplayNode, UIScrollViewDelegate, UIGestureRecog
|
||||
func animateOut(animateContent: Bool, completion: @escaping () -> Void) {
|
||||
self.isDismissed = true
|
||||
|
||||
self.pager.isScrollEnabled = false
|
||||
|
||||
var contentAnimationCompleted = true
|
||||
var interfaceAnimationCompleted = false
|
||||
|
||||
|
||||
@ -103,7 +103,7 @@ final class HashtagSearchControllerNode: ASDisplayNode {
|
||||
insets.top += toolbarHeight - 4.0
|
||||
let chatSize = CGSize(width: layout.size.width, height: layout.size.height)
|
||||
transition.updateFrame(node: chatController.displayNode, frame: CGRect(origin: CGPoint(x: 0.0, y: 0.0), size: chatSize))
|
||||
chatController.containerLayoutUpdated(ContainerViewLayout(size: chatSize, metrics: layout.metrics, intrinsicInsets: UIEdgeInsets(top: insets.top, left: 0.0, bottom: layout.intrinsicInsets.bottom, right: 0.0), safeInsets: layout.safeInsets, statusBarHeight: nil, inputHeight: nil, standardInputHeight: 216.0, inputHeightIsInteractivellyChanging: false), transition: .immediate)
|
||||
chatController.containerLayoutUpdated(ContainerViewLayout(size: chatSize, metrics: layout.metrics, intrinsicInsets: UIEdgeInsets(top: insets.top, left: 0.0, bottom: layout.intrinsicInsets.bottom, right: 0.0), safeInsets: layout.safeInsets, statusBarHeight: nil, inputHeight: nil, standardInputHeight: 216.0, inputHeightIsInteractivellyChanging: false, inVoiceOver: false), transition: .immediate)
|
||||
|
||||
if chatController.displayNode.supernode == nil {
|
||||
chatController.viewWillAppear(false)
|
||||
|
||||
@ -1227,7 +1227,7 @@ final class InstantPageControllerNode: ASDisplayNode, UIScrollViewDelegate {
|
||||
} else {
|
||||
var medias: [InstantPageMedia] = mediasFromItems(items)
|
||||
medias = medias.filter {
|
||||
$0.media is TelegramMediaImage
|
||||
return $0.media is TelegramMediaImage || $0.media is TelegramMediaFile
|
||||
}
|
||||
|
||||
for media in medias {
|
||||
|
||||
@ -81,6 +81,10 @@ final class InstantPageImageNode: ASDisplayNode, InstantPageNode {
|
||||
} else {
|
||||
self.imageNode.setSignal(chatMessageVideo(postbox: context.account.postbox, videoReference: fileReference))
|
||||
}
|
||||
if file.isVideo {
|
||||
self.statusNode.transitionToState(.play(.white), animated: false, completion: {})
|
||||
self.addSubnode(self.statusNode)
|
||||
}
|
||||
} else if let map = media.media as? TelegramMediaMap {
|
||||
self.addSubnode(self.pinNode)
|
||||
|
||||
|
||||
@ -404,7 +404,7 @@ final class InstantPageSlideshowNode: ASDisplayNode, InstantPageNode {
|
||||
super.layout()
|
||||
|
||||
self.pagerNode.frame = self.bounds
|
||||
self.pagerNode.containerLayoutUpdated(ContainerViewLayout(size: self.bounds.size, metrics: LayoutMetrics(), intrinsicInsets: UIEdgeInsets(), safeInsets: UIEdgeInsets(), statusBarHeight: nil, inputHeight: nil, standardInputHeight: 216.0, inputHeightIsInteractivellyChanging: false), transition: .immediate)
|
||||
self.pagerNode.containerLayoutUpdated(ContainerViewLayout(size: self.bounds.size, metrics: LayoutMetrics(), intrinsicInsets: UIEdgeInsets(), safeInsets: UIEdgeInsets(), statusBarHeight: nil, inputHeight: nil, standardInputHeight: 216.0, inputHeightIsInteractivellyChanging: false, inVoiceOver: false), transition: .immediate)
|
||||
|
||||
self.pageControlNode.layer.transform = CATransform3DIdentity
|
||||
self.pageControlNode.frame = CGRect(origin: CGPoint(x: 0.0, y: self.bounds.size.height - 20.0), size: CGSize(width: self.bounds.size.width, height: 20.0))
|
||||
|
||||
@ -421,7 +421,11 @@ class ItemListAvatarAndNameInfoItemNode: ListViewItemNode, ItemListItemNode, Ite
|
||||
statusText = label
|
||||
statusColor = item.theme.list.itemSecondaryTextColor
|
||||
} else if let _ = peer.botInfo {
|
||||
statusText = item.strings.Bot_GenericBotStatus
|
||||
if let phoneNumber = peer.phone, phoneNumber.hasPrefix("424") {
|
||||
statusText = item.strings.Bot_GenericSupportStatus
|
||||
} else {
|
||||
statusText = item.strings.Bot_GenericBotStatus
|
||||
}
|
||||
statusColor = item.theme.list.itemSecondaryTextColor
|
||||
} else if case .generic = item.mode, !(peer.id.namespace == Namespaces.Peer.CloudUser && (peer.id.id == 777000 || peer.id.id == 333000)) {
|
||||
let presence = (item.presence as? TelegramUserPresence) ?? TelegramUserPresence(status: .none, lastActivity: 0)
|
||||
|
||||
@ -518,7 +518,7 @@ class ItemListController<Entry: ItemListNodeEntry>: ViewController {
|
||||
|
||||
if let controller = self.previewItemWithTag?(tag) {
|
||||
if let controller = controller as? ContainableController {
|
||||
controller.containerLayoutUpdated(ContainerViewLayout(size: contentSize, metrics: LayoutMetrics(), intrinsicInsets: UIEdgeInsets(), safeInsets: UIEdgeInsets(), statusBarHeight: nil, inputHeight: nil, standardInputHeight: 216.0, inputHeightIsInteractivellyChanging: false), transition: .immediate)
|
||||
controller.containerLayoutUpdated(ContainerViewLayout(size: contentSize, metrics: LayoutMetrics(), intrinsicInsets: UIEdgeInsets(), safeInsets: UIEdgeInsets(), statusBarHeight: nil, inputHeight: nil, standardInputHeight: 216.0, inputHeightIsInteractivellyChanging: false, inVoiceOver: false), transition: .immediate)
|
||||
}
|
||||
return (controller, sourceRect)
|
||||
} else {
|
||||
|
||||
@ -16,6 +16,7 @@ enum ItemListDisclosureStyle {
|
||||
enum ItemListDisclosureLabelStyle {
|
||||
case text
|
||||
case detailText
|
||||
case multilineDetailText
|
||||
case badge(UIColor)
|
||||
case color(UIColor)
|
||||
}
|
||||
@ -221,27 +222,6 @@ class ItemListDisclosureItemNode: ListViewItemNode {
|
||||
let itemSeparatorColor: UIColor
|
||||
|
||||
var leftInset = 16.0 + params.leftInset
|
||||
let height: CGFloat
|
||||
switch item.labelStyle {
|
||||
case .detailText:
|
||||
height = 64.0
|
||||
default:
|
||||
height = 44.0
|
||||
}
|
||||
|
||||
switch item.style {
|
||||
case .plain:
|
||||
itemBackgroundColor = item.theme.list.plainBackgroundColor
|
||||
itemSeparatorColor = item.theme.list.itemPlainSeparatorColor
|
||||
contentSize = CGSize(width: params.width, height: height)
|
||||
insets = itemListNeighborsPlainInsets(neighbors)
|
||||
case .blocks:
|
||||
itemBackgroundColor = item.theme.list.itemBlocksBackgroundColor
|
||||
itemSeparatorColor = item.theme.list.itemBlocksSeparatorColor
|
||||
contentSize = CGSize(width: params.width, height: height)
|
||||
insets = itemListNeighborsGroupedInsets(neighbors)
|
||||
}
|
||||
|
||||
if let _ = item.icon {
|
||||
leftInset += 43.0
|
||||
}
|
||||
@ -262,7 +242,7 @@ class ItemListDisclosureItemNode: ListViewItemNode {
|
||||
case .badge:
|
||||
labelBadgeColor = item.theme.rootController.tabBar.badgeTextColor
|
||||
labelFont = badgeFont
|
||||
case .detailText:
|
||||
case .detailText, .multilineDetailText:
|
||||
labelBadgeColor = item.theme.list.itemSecondaryTextColor
|
||||
labelFont = detailFont
|
||||
labelConstrain = params.width - params.rightInset - 40.0 - leftInset
|
||||
@ -270,8 +250,35 @@ class ItemListDisclosureItemNode: ListViewItemNode {
|
||||
labelBadgeColor = item.theme.list.itemSecondaryTextColor
|
||||
labelFont = titleFont
|
||||
}
|
||||
var multilineLabel = false
|
||||
if case .multilineDetailText = item.labelStyle {
|
||||
multilineLabel = true
|
||||
}
|
||||
|
||||
let (labelLayout, labelApply) = makeLabelLayout(TextNodeLayoutArguments(attributedString: NSAttributedString(string: item.label, font: labelFont, textColor:labelBadgeColor), backgroundColor: nil, maximumNumberOfLines: 1, truncationType: .end, constrainedSize: CGSize(width: labelConstrain, height: CGFloat.greatestFiniteMagnitude), alignment: .natural, cutout: nil, insets: UIEdgeInsets()))
|
||||
let (labelLayout, labelApply) = makeLabelLayout(TextNodeLayoutArguments(attributedString: NSAttributedString(string: item.label, font: labelFont, textColor:labelBadgeColor), backgroundColor: nil, maximumNumberOfLines: multilineLabel ? 0 : 1, truncationType: .end, constrainedSize: CGSize(width: labelConstrain, height: CGFloat.greatestFiniteMagnitude), alignment: .natural, cutout: nil, insets: UIEdgeInsets()))
|
||||
|
||||
let height: CGFloat
|
||||
switch item.labelStyle {
|
||||
case .detailText:
|
||||
height = 64.0
|
||||
case .multilineDetailText:
|
||||
height = 44.0 + labelLayout.size.height
|
||||
default:
|
||||
height = 44.0
|
||||
}
|
||||
|
||||
switch item.style {
|
||||
case .plain:
|
||||
itemBackgroundColor = item.theme.list.plainBackgroundColor
|
||||
itemSeparatorColor = item.theme.list.itemPlainSeparatorColor
|
||||
contentSize = CGSize(width: params.width, height: height)
|
||||
insets = itemListNeighborsPlainInsets(neighbors)
|
||||
case .blocks:
|
||||
itemBackgroundColor = item.theme.list.itemBlocksBackgroundColor
|
||||
itemSeparatorColor = item.theme.list.itemBlocksSeparatorColor
|
||||
contentSize = CGSize(width: params.width, height: height)
|
||||
insets = itemListNeighborsGroupedInsets(neighbors)
|
||||
}
|
||||
|
||||
let layout = ListViewItemNodeLayout(contentSize: contentSize, insets: insets)
|
||||
|
||||
@ -286,7 +293,13 @@ class ItemListDisclosureItemNode: ListViewItemNode {
|
||||
if updateIcon {
|
||||
strongSelf.iconNode.image = icon
|
||||
}
|
||||
strongSelf.iconNode.frame = CGRect(origin: CGPoint(x: params.leftInset + floor((leftInset - params.leftInset - icon.size.width) / 2.0), y: floor((layout.contentSize.height - icon.size.height) / 2.0)), size: icon.size)
|
||||
let iconY: CGFloat
|
||||
if case .multilineDetailText = item.labelStyle {
|
||||
iconY = 14.0
|
||||
} else {
|
||||
iconY = floor((layout.contentSize.height - icon.size.height) / 2.0)
|
||||
}
|
||||
strongSelf.iconNode.frame = CGRect(origin: CGPoint(x: params.leftInset + floor((leftInset - params.leftInset - icon.size.width) / 2.0), y: iconY), size: icon.size)
|
||||
} else if strongSelf.iconNode.supernode != nil {
|
||||
strongSelf.iconNode.image = nil
|
||||
strongSelf.iconNode.removeFromSupernode()
|
||||
@ -368,7 +381,7 @@ class ItemListDisclosureItemNode: ListViewItemNode {
|
||||
switch item.labelStyle {
|
||||
case .badge:
|
||||
labelFrame = CGRect(origin: CGPoint(x: params.width - rightInset - badgeWidth + (badgeWidth - labelLayout.size.width) / 2.0, y: 13.0), size: labelLayout.size)
|
||||
case .detailText:
|
||||
case .detailText, .multilineDetailText:
|
||||
labelFrame = CGRect(origin: CGPoint(x: leftInset, y: 36.0), size: labelLayout.size)
|
||||
default:
|
||||
labelFrame = CGRect(origin: CGPoint(x: params.width - rightInset - labelLayout.size.width, y: 11.0), size: labelLayout.size)
|
||||
|
||||
14
TelegramUI/LegacyCache.swift
Normal file
14
TelegramUI/LegacyCache.swift
Normal 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)
|
||||
}
|
||||
}
|
||||
226
TelegramUI/LogoutOptionsController.swift
Normal file
226
TelegramUI/LogoutOptionsController.swift
Normal 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
|
||||
}
|
||||
|
||||
@ -157,6 +157,11 @@ final class MediaPlayerNode: ASDisplayNode {
|
||||
var finised = false
|
||||
loop: while true {
|
||||
let isReady = layer.isReadyForMoreMediaData
|
||||
#if DEBUG
|
||||
if let error = layer.error {
|
||||
print("MediaPlayerNode error: \(error)")
|
||||
}
|
||||
#endif
|
||||
|
||||
if isReady {
|
||||
switch takeFrame() {
|
||||
|
||||
@ -35,7 +35,7 @@ public final class OverlayMediaController: ViewController {
|
||||
override public func containerLayoutUpdated(_ layout: ContainerViewLayout, transition: ContainedViewLayoutTransition) {
|
||||
super.containerLayoutUpdated(layout, transition: transition)
|
||||
|
||||
let updatedLayout = ContainerViewLayout(size: layout.size, metrics: layout.metrics, intrinsicInsets: UIEdgeInsets(top: (layout.statusBarHeight ?? 0.0) + 44.0, left: layout.intrinsicInsets.left, bottom: layout.intrinsicInsets.bottom, right: layout.intrinsicInsets.right), safeInsets: layout.safeInsets, statusBarHeight: layout.statusBarHeight, inputHeight: layout.inputHeight, standardInputHeight: layout.standardInputHeight, inputHeightIsInteractivellyChanging: layout.inputHeightIsInteractivellyChanging)
|
||||
let updatedLayout = ContainerViewLayout(size: layout.size, metrics: layout.metrics, intrinsicInsets: UIEdgeInsets(top: (layout.statusBarHeight ?? 0.0) + 44.0, left: layout.intrinsicInsets.left, bottom: layout.intrinsicInsets.bottom, right: layout.intrinsicInsets.right), safeInsets: layout.safeInsets, statusBarHeight: layout.statusBarHeight, inputHeight: layout.inputHeight, standardInputHeight: layout.standardInputHeight, inputHeightIsInteractivellyChanging: layout.inputHeightIsInteractivellyChanging, inVoiceOver: layout.inVoiceOver)
|
||||
self.controllerNode.containerLayoutUpdated(updatedLayout, transition: transition)
|
||||
}
|
||||
}
|
||||
|
||||
@ -147,7 +147,7 @@ private func aroundMessagesFromView(view: MessageHistoryView, centralIndex: Mess
|
||||
var result: [Message] = []
|
||||
if index != 0 {
|
||||
for i in (0 ..< index).reversed() {
|
||||
if case let .MessageEntry(message, _, _, _) = view.entries[i] {
|
||||
if case let .MessageEntry(message, _, _, _, _) = view.entries[i] {
|
||||
result.append(message)
|
||||
break
|
||||
}
|
||||
@ -155,7 +155,7 @@ private func aroundMessagesFromView(view: MessageHistoryView, centralIndex: Mess
|
||||
}
|
||||
if index != view.entries.count - 1 {
|
||||
for i in index + 1 ..< view.entries.count {
|
||||
if case let .MessageEntry(message, _, _, _) = view.entries[i] {
|
||||
if case let .MessageEntry(message, _, _, _, _) = view.entries[i] {
|
||||
result.append(message)
|
||||
break
|
||||
}
|
||||
@ -171,7 +171,7 @@ private func navigatedMessageFromView(_ view: MessageHistoryView, anchorIndex: M
|
||||
switch position {
|
||||
case .exact:
|
||||
switch entry {
|
||||
case let .MessageEntry(message, _, _, _):
|
||||
case let .MessageEntry(message, _, _, _, _):
|
||||
return (message, aroundMessagesFromView(view: view, centralIndex: entry.index), true)
|
||||
default:
|
||||
return nil
|
||||
@ -179,7 +179,7 @@ private func navigatedMessageFromView(_ view: MessageHistoryView, anchorIndex: M
|
||||
case .later:
|
||||
if index + 1 < view.entries.count {
|
||||
switch view.entries[index + 1] {
|
||||
case let .MessageEntry(message, _, _, _):
|
||||
case let .MessageEntry(message, _, _, _, _):
|
||||
return (message, aroundMessagesFromView(view: view, centralIndex: view.entries[index + 1].index), true)
|
||||
default:
|
||||
return nil
|
||||
@ -190,7 +190,7 @@ private func navigatedMessageFromView(_ view: MessageHistoryView, anchorIndex: M
|
||||
case .earlier:
|
||||
if index != 0 {
|
||||
switch view.entries[index - 1] {
|
||||
case let .MessageEntry(message, _, _, _):
|
||||
case let .MessageEntry(message, _, _, _, _):
|
||||
return (message, aroundMessagesFromView(view: view, centralIndex: view.entries[index - 1].index), true)
|
||||
default:
|
||||
return nil
|
||||
@ -206,14 +206,14 @@ private func navigatedMessageFromView(_ view: MessageHistoryView, anchorIndex: M
|
||||
switch position {
|
||||
case .later, .exact:
|
||||
switch view.entries[view.entries.count - 1] {
|
||||
case let .MessageEntry(message, _, _, _):
|
||||
case let .MessageEntry(message, _, _, _, _):
|
||||
return (message, aroundMessagesFromView(view: view, centralIndex: view.entries[view.entries.count - 1].index), false)
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
case .earlier:
|
||||
switch view.entries[0] {
|
||||
case let .MessageEntry(message, _, _, _):
|
||||
case let .MessageEntry(message, _, _, _, _):
|
||||
return (message, aroundMessagesFromView(view: view, centralIndex: view.entries[0].index), false)
|
||||
default:
|
||||
return nil
|
||||
|
||||
@ -202,7 +202,7 @@ final class PeerSelectionControllerNode: ASDisplayNode {
|
||||
|
||||
let contactsInsets = insets
|
||||
|
||||
contactListNode.containerLayoutUpdated(ContainerViewLayout(size: layout.size, metrics: layout.metrics, intrinsicInsets: contactsInsets, safeInsets: layout.safeInsets, statusBarHeight: layout.statusBarHeight, inputHeight: layout.inputHeight, standardInputHeight: layout.standardInputHeight, inputHeightIsInteractivellyChanging: layout.inputHeightIsInteractivellyChanging), headerInsets: headerInsets, transition: transition)
|
||||
contactListNode.containerLayoutUpdated(ContainerViewLayout(size: layout.size, metrics: layout.metrics, intrinsicInsets: contactsInsets, safeInsets: layout.safeInsets, statusBarHeight: layout.statusBarHeight, inputHeight: layout.inputHeight, standardInputHeight: layout.standardInputHeight, inputHeightIsInteractivellyChanging: layout.inputHeightIsInteractivellyChanging, inVoiceOver: layout.inVoiceOver), headerInsets: headerInsets, transition: transition)
|
||||
}
|
||||
|
||||
if let searchDisplayController = self.searchDisplayController {
|
||||
|
||||
@ -690,7 +690,7 @@ public func chatMessagePhotoInternal(photoData: Signal<(Data?, Data?, Bool), NoE
|
||||
if let thumbnailImage = thumbnailImage {
|
||||
let thumbnailSize = CGSize(width: thumbnailImage.width, height: thumbnailImage.height)
|
||||
|
||||
if thumbnailSize.width > arguments.drawingSize.width * 0.7 && thumbnailSize.height > arguments.drawingSize.height * 0.7 {
|
||||
if thumbnailSize.width > 200.0 && thumbnailSize.height > 200.0 {
|
||||
blurredThumbnailImage = UIImage(cgImage: thumbnailImage)
|
||||
} else {
|
||||
let initialThumbnailContextFittingSize = fittedSize.fitted(CGSize(width: 90.0, height: 90.0))
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
Binary file not shown.
@ -93,7 +93,7 @@ final class SearchDisplayController {
|
||||
self.containerLayout = (layout, navigationBarFrame.maxY)
|
||||
|
||||
transition.updateFrame(node: self.contentNode, frame: CGRect(origin: CGPoint(), size: layout.size))
|
||||
self.contentNode.containerLayoutUpdated(ContainerViewLayout(size: layout.size, metrics: LayoutMetrics(), intrinsicInsets: layout.intrinsicInsets, safeInsets: layout.safeInsets, statusBarHeight: nil, inputHeight: layout.inputHeight, standardInputHeight: layout.standardInputHeight, inputHeightIsInteractivellyChanging: layout.inputHeightIsInteractivellyChanging), navigationBarHeight: navigationBarFrame.maxY, transition: transition)
|
||||
self.contentNode.containerLayoutUpdated(ContainerViewLayout(size: layout.size, metrics: LayoutMetrics(), intrinsicInsets: layout.intrinsicInsets, safeInsets: layout.safeInsets, statusBarHeight: nil, inputHeight: layout.inputHeight, standardInputHeight: layout.standardInputHeight, inputHeightIsInteractivellyChanging: layout.inputHeightIsInteractivellyChanging, inVoiceOver: layout.inVoiceOver), navigationBarHeight: navigationBarFrame.maxY, transition: transition)
|
||||
}
|
||||
|
||||
func activate(insertSubnode: (ASDisplayNode, Bool) -> Void, placeholder: SearchBarPlaceholderNode) {
|
||||
@ -104,7 +104,7 @@ final class SearchDisplayController {
|
||||
insertSubnode(self.contentNode, false)
|
||||
|
||||
self.contentNode.frame = CGRect(origin: CGPoint(), size: layout.size)
|
||||
self.contentNode.containerLayoutUpdated(ContainerViewLayout(size: layout.size, metrics: LayoutMetrics(), intrinsicInsets: UIEdgeInsets(), safeInsets: layout.safeInsets, statusBarHeight: nil, inputHeight: nil, standardInputHeight: layout.standardInputHeight, inputHeightIsInteractivellyChanging: false), navigationBarHeight: navigationBarHeight, transition: .immediate)
|
||||
self.contentNode.containerLayoutUpdated(ContainerViewLayout(size: layout.size, metrics: LayoutMetrics(), intrinsicInsets: UIEdgeInsets(), safeInsets: layout.safeInsets, statusBarHeight: nil, inputHeight: nil, standardInputHeight: layout.standardInputHeight, inputHeightIsInteractivellyChanging: false, inVoiceOver: false), navigationBarHeight: navigationBarHeight, transition: .immediate)
|
||||
|
||||
let initialTextBackgroundFrame = placeholder.convert(placeholder.backgroundNode.frame, to: nil)
|
||||
|
||||
|
||||
@ -421,7 +421,7 @@ public final class SecretMediaPreviewController: ViewController {
|
||||
}
|
||||
}
|
||||
|
||||
guard let item = galleryItemForEntry(context: self.context, presentationData: self.presentationData, entry: .MessageEntry(message, false, nil, nil), streamVideos: false, hideControls: true, tempFilePath: tempFilePath, playbackCompleted: { [weak self] in
|
||||
guard let item = galleryItemForEntry(context: self.context, presentationData: self.presentationData, entry: .MessageEntry(message, false, nil, nil, MutableMessageHistoryEntryAttributes(authorIsContact: false)), streamVideos: false, hideControls: true, tempFilePath: tempFilePath, playbackCompleted: { [weak self] in
|
||||
self?.dismiss(forceAway: false)
|
||||
}) else {
|
||||
self._ready.set(.single(true))
|
||||
|
||||
@ -38,6 +38,26 @@ public final class AccountWithInfo: Equatable {
|
||||
}
|
||||
}
|
||||
|
||||
private func pathFromLegacyFile(basePath: String, fileId: Int64, isLocal: Bool, fileName: String) -> String {
|
||||
let documentsPath = basePath + "/Documents"
|
||||
let filePath = documentsPath + "/files/" + (isLocal ? "local" : "") + "\(String(fileId, radix: 16))/\(fileName)"
|
||||
return filePath
|
||||
}
|
||||
|
||||
private func preFetchedLegacyResourcePath(basePath: String, resource: MediaResource, cache: LegacyCache) -> String? {
|
||||
if let resource = resource as? CloudDocumentMediaResource {
|
||||
let videoPath = "\(basePath)/Documents/video/remote\(String(resource.fileId, radix: 16)).mov"
|
||||
if FileManager.default.fileExists(atPath: videoPath) {
|
||||
return videoPath
|
||||
}
|
||||
let fileName = resource.fileName?.replacingOccurrences(of: "/", with: "_") ?? "file"
|
||||
return pathFromLegacyFile(basePath: basePath, fileId: resource.fileId, isLocal: false, fileName: fileName)
|
||||
} else if let resource = resource as? CloudFileMediaResource {
|
||||
return cache.path(forCachedData: "\(resource.datacenterId)_\(resource.volumeId)_\(resource.localId)_\(resource.secret)")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
private struct AccountAttributes: Equatable {
|
||||
let sortIndex: Int32
|
||||
let isTestingEnvironment: Bool
|
||||
@ -125,7 +145,7 @@ public final class SharedAccountContext {
|
||||
public var presentGlobalController: (ViewController, Any?) -> Void = { _, _ in }
|
||||
public var presentCrossfadeController: () -> Void = {}
|
||||
|
||||
public init(mainWindow: Window1?, accountManager: AccountManager, applicationBindings: TelegramApplicationBindings, initialPresentationDataAndSettings: InitialPresentationDataAndSettings, networkArguments: NetworkInitializationArguments, rootPath: String, apsNotificationToken: Signal<Data?, NoError>, voipNotificationToken: Signal<Data?, NoError>, setNotificationCall: @escaping (PresentationCall?) -> Void, navigateToChat: @escaping (AccountRecordId, PeerId, MessageId?) -> Void) {
|
||||
public init(mainWindow: Window1?, accountManager: AccountManager, applicationBindings: TelegramApplicationBindings, initialPresentationDataAndSettings: InitialPresentationDataAndSettings, networkArguments: NetworkInitializationArguments, rootPath: String, legacyBasePath: String?, legacyCache: LegacyCache?, apsNotificationToken: Signal<Data?, NoError>, voipNotificationToken: Signal<Data?, NoError>, setNotificationCall: @escaping (PresentationCall?) -> Void, navigateToChat: @escaping (AccountRecordId, PeerId, MessageId?) -> Void) {
|
||||
assert(Queue.mainQueue().isCurrent())
|
||||
self.mainWindow = mainWindow
|
||||
self.applicationBindings = applicationBindings
|
||||
@ -300,6 +320,13 @@ public final class SharedAccountContext {
|
||||
|> map { result -> (AccountRecordId, Account?, Int32) in
|
||||
switch result {
|
||||
case let .authorized(account):
|
||||
setupAccount(account, fetchCachedResourceRepresentation: fetchCachedResourceRepresentation, transformOutgoingMessageMedia: transformOutgoingMessageMedia, preFetchedResourcePath: { resource in
|
||||
if let legacyBasePath = legacyBasePath, let legacyCache = legacyCache {
|
||||
return preFetchedLegacyResourcePath(basePath: legacyBasePath, resource: resource, cache: legacyCache)
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
})
|
||||
return (id, account, attributes.sortIndex)
|
||||
default:
|
||||
return (id, nil, attributes.sortIndex)
|
||||
|
||||
@ -511,7 +511,7 @@ public class TelegramController: ViewController {
|
||||
return .single((nil, true))
|
||||
case let .HistoryView(view, _, _, _, _):
|
||||
for entry in view.entries {
|
||||
if case let .MessageEntry(message, _, _, _) = entry {
|
||||
if case let .MessageEntry(message, _, _, _, _) = entry {
|
||||
if message.id == id.messageId {
|
||||
return .single((MessageIndex(message), false))
|
||||
}
|
||||
|
||||
@ -126,8 +126,8 @@ class ThemeSettingsChatPreviewItemNode: ListViewItemNode {
|
||||
|
||||
let chatPresentationData = ChatPresentationData(theme: ChatPresentationThemeData(theme: item.componentTheme, wallpaper: item.wallpaper), fontSize: item.fontSize, strings: item.strings, dateTimeFormat: item.dateTimeFormat, nameDisplayOrder: item.nameDisplayOrder, disableAnimations: false)
|
||||
|
||||
let item2: ChatMessageItem = ChatMessageItem(presentationData: chatPresentationData, context: item.context, chatLocation: .peer(peerId), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .contact, automaticDownloadNetworkType: .cellular, isRecentActions: false), controllerInteraction: controllerInteraction, content: .message(message: Message(stableId: 1, stableVersion: 0, id: MessageId(peerId: peerId, namespace: 0, id: 1), globallyUniqueId: nil, groupingKey: nil, groupInfo: nil, timestamp: 66000, flags: [.Incoming], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: nil, text: item.strings.Appearance_PreviewIncomingText, attributes: [ReplyMessageAttribute(messageId: replyMessageId)], media: [], peers: peers, associatedMessages: messages, associatedMessageIds: []), read: true, selection: .none, isAdmin: false), disableDate: true)
|
||||
let item1: ChatMessageItem = ChatMessageItem(presentationData: chatPresentationData, context: item.context, chatLocation: .peer(peerId), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .contact, automaticDownloadNetworkType: .cellular, isRecentActions: false), controllerInteraction: controllerInteraction, content: .message(message: Message(stableId: 2, stableVersion: 0, id: MessageId(peerId: peerId, namespace: 0, id: 2), globallyUniqueId: nil, groupingKey: nil, groupInfo: nil, timestamp: 66001, flags: [], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: TelegramUser(id: item.context.account.peerId, accessHash: nil, firstName: "", lastName: "", username: nil, phone: nil, photo: [], botInfo: nil, restrictionInfo: nil, flags: []), text: item.strings.Appearance_PreviewOutgoingText, attributes: [], media: [], peers: peers, associatedMessages: messages, associatedMessageIds: []), read: true, selection: .none, isAdmin: false), disableDate: true)
|
||||
let item2: ChatMessageItem = ChatMessageItem(presentationData: chatPresentationData, context: item.context, chatLocation: .peer(peerId), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .contact, automaticDownloadNetworkType: .cellular, isRecentActions: false), controllerInteraction: controllerInteraction, content: .message(message: Message(stableId: 1, stableVersion: 0, id: MessageId(peerId: peerId, namespace: 0, id: 1), globallyUniqueId: nil, groupingKey: nil, groupInfo: nil, timestamp: 66000, flags: [.Incoming], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: nil, text: item.strings.Appearance_PreviewIncomingText, attributes: [ReplyMessageAttribute(messageId: replyMessageId)], media: [], peers: peers, associatedMessages: messages, associatedMessageIds: []), read: true, selection: .none, attributes: ChatMessageEntryAttributes(isAdmin: false, isContact: false)), disableDate: true)
|
||||
let item1: ChatMessageItem = ChatMessageItem(presentationData: chatPresentationData, context: item.context, chatLocation: .peer(peerId), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .contact, automaticDownloadNetworkType: .cellular, isRecentActions: false), controllerInteraction: controllerInteraction, content: .message(message: Message(stableId: 2, stableVersion: 0, id: MessageId(peerId: peerId, namespace: 0, id: 2), globallyUniqueId: nil, groupingKey: nil, groupInfo: nil, timestamp: 66001, flags: [], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: TelegramUser(id: item.context.account.peerId, accessHash: nil, firstName: "", lastName: "", username: nil, phone: nil, photo: [], botInfo: nil, restrictionInfo: nil, flags: []), text: item.strings.Appearance_PreviewOutgoingText, attributes: [], media: [], peers: peers, associatedMessages: messages, associatedMessageIds: []), read: true, selection: .none, attributes: ChatMessageEntryAttributes(isAdmin: false, isContact: false)), disableDate: true)
|
||||
|
||||
var node1: ListViewItemNode?
|
||||
if let current = currentNode1 {
|
||||
|
||||
@ -693,7 +693,10 @@ private func userInfoEntries(account: Account, presentationData: PresentationDat
|
||||
if cachedData.isBlocked {
|
||||
entries.append(UserInfoEntry.block(presentationData.theme, stringForBlockAction(strings: presentationData.strings, action: .unblock, peer: user), .unblock))
|
||||
} else {
|
||||
entries.append(UserInfoEntry.block(presentationData.theme, stringForBlockAction(strings: presentationData.strings, action: .block, peer: user), .block))
|
||||
if let peer = peer as? TelegramUser, let phone = peer.phone, phone.hasPrefix("424") {
|
||||
} else {
|
||||
entries.append(UserInfoEntry.block(presentationData.theme, stringForBlockAction(strings: presentationData.strings, action: .block, peer: user), .block))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -588,9 +588,9 @@ class WallpaperGalleryController: ViewController {
|
||||
bottomMessageText = presentationData.strings.WallpaperPreview_CustomColorBottomText
|
||||
}
|
||||
|
||||
items.append(ChatMessageItem(presentationData: chatPresentationData, context: self.context, chatLocation: .peer(peerId), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .contact, automaticDownloadNetworkType: .cellular, isRecentActions: false), controllerInteraction: controllerInteraction, content: .message(message: Message(stableId: 2, stableVersion: 0, id: MessageId(peerId: peerId, namespace: 0, id: 2), globallyUniqueId: nil, groupingKey: nil, groupInfo: nil, timestamp: 66001, flags: [], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: peers[otherPeerId], text: bottomMessageText, attributes: [], media: [], peers: peers, associatedMessages: messages, associatedMessageIds: []), read: true, selection: .none, isAdmin: false), disableDate: false))
|
||||
items.append(ChatMessageItem(presentationData: chatPresentationData, context: self.context, chatLocation: .peer(peerId), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .contact, automaticDownloadNetworkType: .cellular, isRecentActions: false), controllerInteraction: controllerInteraction, content: .message(message: Message(stableId: 2, stableVersion: 0, id: MessageId(peerId: peerId, namespace: 0, id: 2), globallyUniqueId: nil, groupingKey: nil, groupInfo: nil, timestamp: 66001, flags: [], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: peers[otherPeerId], text: bottomMessageText, attributes: [], media: [], peers: peers, associatedMessages: messages, associatedMessageIds: []), read: true, selection: .none, attributes: ChatMessageEntryAttributes(isAdmin: false, isContact: false)), disableDate: false))
|
||||
|
||||
items.append(ChatMessageItem(presentationData: chatPresentationData, context: self.context, chatLocation: .peer(peerId), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .contact, automaticDownloadNetworkType: .cellular, isRecentActions: false), controllerInteraction: controllerInteraction, content: .message(message: Message(stableId: 1, stableVersion: 0, id: MessageId(peerId: peerId, namespace: 0, id: 1), globallyUniqueId: nil, groupingKey: nil, groupInfo: nil, timestamp: 66000, flags: [.Incoming], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: peers[peerId], text: topMessageText, attributes: [], media: [], peers: peers, associatedMessages: messages, associatedMessageIds: []), read: true, selection: .none, isAdmin: false), disableDate: false))
|
||||
items.append(ChatMessageItem(presentationData: chatPresentationData, context: self.context, chatLocation: .peer(peerId), associatedData: ChatMessageItemAssociatedData(automaticDownloadPeerType: .contact, automaticDownloadNetworkType: .cellular, isRecentActions: false), controllerInteraction: controllerInteraction, content: .message(message: Message(stableId: 1, stableVersion: 0, id: MessageId(peerId: peerId, namespace: 0, id: 1), globallyUniqueId: nil, groupingKey: nil, groupInfo: nil, timestamp: 66000, flags: [.Incoming], tags: [], globalTags: [], localTags: [], forwardInfo: nil, author: peers[peerId], text: topMessageText, attributes: [], media: [], peers: peers, associatedMessages: messages, associatedMessageIds: []), read: true, selection: .none, attributes: ChatMessageEntryAttributes(isAdmin: false, isContact: false)), disableDate: false))
|
||||
|
||||
let params = ListViewItemLayoutParams(width: layout.size.width, leftInset: layout.safeInsets.left, rightInset: layout.safeInsets.right)
|
||||
if let messageNodes = self.messageNodes {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user